Преглед на файлове

Merge remote-tracking branch 'origin/master' into server_config

Conflicts:
	src/server/ua_server.c
Stasik0 преди 10 години
родител
ревизия
35c0b99f47

+ 6 - 0
CMakeLists.txt

@@ -66,6 +66,7 @@ set(lib_sources ${PROJECT_SOURCE_DIR}/src/ua_types.c
                 ${PROJECT_SOURCE_DIR}/src/ua_types_encoding_binary.c
                 ${PROJECT_SOURCE_DIR}/src/ua_types_encoding_binary.c
                 ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.c
                 ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.c
                 ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.c
                 ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.c
+                ${PROJECT_SOURCE_DIR}/src/ua_connection.c
                 ${PROJECT_SOURCE_DIR}/src/ua_securechannel.c
                 ${PROJECT_SOURCE_DIR}/src/ua_securechannel.c
                 ${PROJECT_SOURCE_DIR}/src/ua_session.c
                 ${PROJECT_SOURCE_DIR}/src/ua_session.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_server.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_server.c
@@ -129,6 +130,8 @@ if(EXTENSION_UDP)
 	add_definitions(-DEXTENSION_STATELESS)
 	add_definitions(-DEXTENSION_STATELESS)
 	message(STATUS "Extensions: enabling udp")
 	message(STATUS "Extensions: enabling udp")
 	add_definitions(-DEXTENSION_UDP)
 	add_definitions(-DEXTENSION_UDP)
+	add_executable(exampleServerUDP $<TARGET_OBJECTS:open62541-object> examples/networklayer_udp.c examples/server_udp.c)
+    target_link_libraries(exampleServerUDP rt)
 endif()
 endif()
 
 
 option(EXTENSION_STATELESS "Enable stateless extension" OFF)
 option(EXTENSION_STATELESS "Enable stateless extension" OFF)
@@ -240,6 +243,9 @@ if(BUILD_EXAMPLECLIENT)
     else()
     else()
         target_link_libraries(exampleClient rt)
         target_link_libraries(exampleClient rt)
     endif()
     endif()
+    if(ENABLE_MULTITHREADING)
+        target_link_libraries(exampleClient urcu-cds urcu urcu-common pthread)
+    endif()
     if(EXTENSION_STATELESS)
     if(EXTENSION_STATELESS)
         add_executable(statelessClient examples/client_stateless.c ${client_source})
         add_executable(statelessClient examples/client_stateless.c ${client_source})
         if(ENABLE_MULTITHREADING)
         if(ENABLE_MULTITHREADING)

+ 6 - 5
README.md

@@ -40,15 +40,16 @@ void signalHandler(int sign) {
     running = UA_FALSE;
     running = UA_FALSE;
 }
 }
 
 
-int main(int argc, char** argv) {
+int main(int argc, char** argv)
+{
     /* catch ctrl-c */
     /* catch ctrl-c */
     signal(SIGINT, signalHandler);
     signal(SIGINT, signalHandler);
 
 
     /* init the server */
     /* init the server */
     UA_Server *server = UA_Server_new();
     UA_Server *server = UA_Server_new();
+    UA_Server_setLogger(server, Logger_Stdout_new());
     UA_Server_addNetworkLayer(server,
     UA_Server_addNetworkLayer(server,
         ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, PORT));
         ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, PORT));
-    UA_Server_setLogger(server, Logger_Stdout_new());
     UA_UInt16 nsIndex = UA_Server_addNamespace(server, "myApplicationNamespace");
     UA_UInt16 nsIndex = UA_Server_addNamespace(server, "myApplicationNamespace");
 
 
     /* add a variable node */
     /* add a variable node */
@@ -74,10 +75,10 @@ int main(int argc, char** argv) {
 #include <stdio.h>
 #include <stdio.h>
 #include "open62541.h"
 #include "open62541.h"
 
 
-int main(int argc, char *argv[]) {
+int main(int argc, char *argv[])
+{
     UA_Client *client = UA_Client_new(UA_ClientConfig_standard);
     UA_Client *client = UA_Client_new(UA_ClientConfig_standard);
-    UA_ClientNetworkLayer nl = ClientNetworkLayerTCP_new(UA_ConnectionConfig_standard);
-    UA_StatusCode retval = UA_Client_connect(client, UA_ConnectionConfig_standard, nl,
+    UA_StatusCode retval = UA_Client_connect(client, ClientNetworkLayerTCP_connect,
                                              "opc.tcp://localhost:16664");
                                              "opc.tcp://localhost:16664");
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
         UA_Client_delete(client);
         UA_Client_delete(client);

+ 38 - 0
cmake/Toolchain-mingw64.cmake

@@ -0,0 +1,38 @@
+# the name of the target operating system
+set(CMAKE_SYSTEM_NAME Windows)
+
+#remove the runtime dependency for libgcc_s_sjlj-1.dll
+set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-libgcc")
+
+# Which compilers to use for C and C++, and location of target
+# environment.
+if(EXISTS /usr/x86_64-w64-mingw32)
+# First look in standard location as used by Debian/Ubuntu/etc.
+set(CMAKE_STRIP x86_64-w64-mingw32-strip)
+set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
+set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++)
+set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)
+set(CMAKE_AR:FILEPATH /usr/bin/x86_64-w64-mingw32-ar)
+set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32)
+elseif(EXISTS /usr/i586-mingw32msvc)
+# Else fill in local path which the user will likely adjust.
+set(CMAKE_STRIP /usr/local/cross-tools/bin/i386-mingw32-strip)
+set(CMAKE_C_COMPILER /usr/local/cross-tools/bin/i386-mingw32-gcc)
+set(CMAKE_CXX_COMPILER /usr/local/cross-tools/bin/i386-mingw32-g++)
+set(CMAKE_RC_COMPILER /usr/local/cross-tools/bin/i386-mingw32-windres)
+set(CMAKE_FIND_ROOT_PATH /usr/local/cross-tools)
+endif() 
+
+# Adjust the default behaviour of the FIND_XXX() commands:
+# search headers and libraries in the target environment, search
+# programs in the host environment
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+# Tell pkg-config not to look at the target environment's .pc files.
+# Setting PKG_CONFIG_LIBDIR sets the default search directory, but we have to
+# set PKG_CONFIG_PATH as well to prevent pkg-config falling back to the host's
+# path.
+set(ENV{PKG_CONFIG_LIBDIR} ${CMAKE_FIND_ROOT_PATH}/lib/pkgconfig)
+set(ENV{PKG_CONFIG_PATH} ${CMAKE_FIND_ROOT_PATH}/lib/pkgconfig)
+set(ENV{MINGDIR} ${CMAKE_FIND_ROOT_PATH}) 

+ 15 - 9
examples/client.c

@@ -2,6 +2,8 @@
     #include "ua_types.h"
     #include "ua_types.h"
     #include "ua_client.h"
     #include "ua_client.h"
     #include "ua_nodeids.h"
     #include "ua_nodeids.h"
+    #include "networklayer_tcp.h"
+    #include "logger_stdout.h"
 #else
 #else
     #include "open62541.h"
     #include "open62541.h"
 #endif
 #endif
@@ -10,10 +12,9 @@
 #include "networklayer_tcp.h"
 #include "networklayer_tcp.h"
 
 
 int main(int argc, char *argv[]) {
 int main(int argc, char *argv[]) {
-    UA_Client *client = UA_Client_new(UA_ClientConfig_standard);
-    UA_ClientNetworkLayer nl = ClientNetworkLayerTCP_new(UA_ConnectionConfig_standard);
-    UA_StatusCode retval = UA_Client_connect(client, UA_ConnectionConfig_standard, nl,
-            "opc.tcp://localhost:16664");
+    UA_Client *client = UA_Client_new(UA_ClientConfig_standard, Logger_Stdout_new());
+    UA_StatusCode retval = UA_Client_connect(client, ClientNetworkLayerTCP_connect,
+                                             "opc.tcp://localhost:16664");
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
         UA_Client_delete(client);
         UA_Client_delete(client);
         return retval;
         return retval;
@@ -35,10 +36,15 @@ int main(int argc, char *argv[]) {
     for (int i = 0; i < bResp.resultsSize; ++i) {
     for (int i = 0; i < bResp.resultsSize; ++i) {
         for (int j = 0; j < bResp.results[i].referencesSize; ++j) {
         for (int j = 0; j < bResp.results[i].referencesSize; ++j) {
             UA_ReferenceDescription *ref = &(bResp.results[i].references[j]);
             UA_ReferenceDescription *ref = &(bResp.results[i].references[j]);
-            if(ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_NUMERIC){
-                printf("%-9d %-16d %-16.*s %-16.*s\n", ref->browseName.namespaceIndex, ref->nodeId.nodeId.identifier.numeric, ref->browseName.name.length, ref->browseName.name.data, ref->displayName.text.length, ref->displayName.text.data);
-            }else if(ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_STRING){
-                printf("%-9d %-16.*s %-16.*s %-16.*s\n", ref->browseName.namespaceIndex, ref->nodeId.nodeId.identifier.string.length, ref->nodeId.nodeId.identifier.string.data, ref->browseName.name.length, ref->browseName.name.data, ref->displayName.text.length, ref->displayName.text.data);
+            if(ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_NUMERIC) {
+                printf("%-9d %-16d %-16.*s %-16.*s\n", ref->browseName.namespaceIndex,
+                       ref->nodeId.nodeId.identifier.numeric, ref->browseName.name.length,
+                       ref->browseName.name.data, ref->displayName.text.length, ref->displayName.text.data);
+            } else if(ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_STRING) {
+                printf("%-9d %-16.*s %-16.*s %-16.*s\n", ref->browseName.namespaceIndex,
+                       ref->nodeId.nodeId.identifier.string.length, ref->nodeId.nodeId.identifier.string.data,
+                       ref->browseName.name.length, ref->browseName.name.data, ref->displayName.text.length,
+                       ref->displayName.text.data);
             }
             }
             //TODO: distinguish further types
             //TODO: distinguish further types
         }
         }
@@ -60,7 +66,7 @@ int main(int argc, char *argv[]) {
     if(rResp.responseHeader.serviceResult == UA_STATUSCODE_GOOD &&
     if(rResp.responseHeader.serviceResult == UA_STATUSCODE_GOOD &&
        rResp.resultsSize > 0 && rResp.results[0].hasValue &&
        rResp.resultsSize > 0 && rResp.results[0].hasValue &&
        UA_Variant_isScalar(&rResp.results[0].value) &&
        UA_Variant_isScalar(&rResp.results[0].value) &&
-       rResp.results[0].value.type == &UA_TYPES[UA_TYPES_INT32]){
+       rResp.results[0].value.type == &UA_TYPES[UA_TYPES_INT32]) {
         value = *(UA_Int32*)rResp.results[0].value.data;
         value = *(UA_Int32*)rResp.results[0].value.data;
         printf("the value is: %i\n", value);
         printf("the value is: %i\n", value);
     }
     }

+ 402 - 458
examples/networklayer_tcp.c

@@ -5,20 +5,17 @@
 
 
 #ifdef NOT_AMALGATED
 #ifdef NOT_AMALGATED
 # define _XOPEN_SOURCE 500 //some users need this for some reason
 # define _XOPEN_SOURCE 500 //some users need this for some reason
-# define __USE_BSD
 # include <stdlib.h> // malloc, free
 # include <stdlib.h> // malloc, free
-# include <stdio.h>
 # include <string.h> // memset
 # include <string.h> // memset
 #endif
 #endif
 
 
 #ifdef _WIN32
 #ifdef _WIN32
 # include <malloc.h>
 # include <malloc.h>
 # include <winsock2.h>
 # include <winsock2.h>
-# include <sys/types.h>
-# include <windows.h>
 # include <ws2tcpip.h>
 # include <ws2tcpip.h>
 # define CLOSESOCKET(S) closesocket(S)
 # define CLOSESOCKET(S) closesocket(S)
 #else
 #else
+# include <fcntl.h>
 # include <sys/select.h> 
 # include <sys/select.h> 
 # include <netinet/in.h>
 # include <netinet/in.h>
 # include <netinet/tcp.h>
 # include <netinet/tcp.h>
@@ -34,355 +31,383 @@
 # include <urcu/uatomic.h>
 # include <urcu/uatomic.h>
 #endif
 #endif
 
 
-/* with a space so amalgamation does not remove the includes */
-# include <errno.h> // errno, EINTR
-# include <fcntl.h> // fcntl
+/* with a space, so the include is not removed during amalgamation */
+# include <errno.h>
 
 
-struct ServerNetworklayer_TCP;
+/****************************/
+/* Generic Socket Functions */
+/****************************/
 
 
-/* Forwarded to the server as a (UA_Connection) and used for callbacks back into
-   the networklayer */
-typedef struct {
-	UA_Connection connection;
-	UA_Int32 sockfd;
-	void *layer;
-} TCPConnection;
-
-/***************************/
-/* Server NetworkLayer TCP */
-/***************************/
-
-#define MAXBACKLOG 100
-
-/* Internal mapping of sockets to connections */
-typedef struct {
-    TCPConnection *connection;
+static UA_StatusCode socket_write(UA_Connection *connection, UA_ByteStringArray gather_buf) {
+    UA_UInt32 total_len = 0, nWritten = 0;
 #ifdef _WIN32
 #ifdef _WIN32
-	UA_UInt32 sockfd;
-#else
-	UA_Int32 sockfd;
-#endif
-} ConnectionLink;
-
-typedef struct ServerNetworkLayerTCP {
-	UA_ConnectionConfig conf;
-	fd_set fdset;
-#ifdef _WIN32
-	UA_UInt32 serversockfd;
-	UA_UInt32 highestfd;
-#else
-	UA_Int32 serversockfd;
-	UA_Int32 highestfd;
-#endif
-    UA_UInt16 conLinksSize;
-    ConnectionLink *conLinks;
-    UA_UInt32 port;
-    UA_String discoveryUrl;
-    /* We remove the connection links only in the main thread. Attach
-       to-be-deleted links with atomic operations */
-    struct deleteLink {
-#ifdef _WIN32
-		UA_UInt32 sockfd;
+    LPWSABUF buf = _alloca(gather_buf.stringsSize * sizeof(WSABUF));
+    memset(buf, 0, sizeof(gather_buf.stringsSize * sizeof(WSABUF)));
+    for(UA_UInt32 i = 0; i<gather_buf.stringsSize; i++) {
+        buf[i].buf = (char*)gather_buf.strings[i].data;
+        buf[i].len = gather_buf.strings[i].length;
+        total_len += gather_buf.strings[i].length;
+    }
+    int result = 0;
+    while(nWritten < total_len) {
+        UA_UInt32 n = 0;
+        do {
+            result = WSASend(connection->sockfd, buf, gather_buf.stringsSize, (LPDWORD)&n, 0, NULL, NULL);
+            if(result != 0 &&WSAGetLastError() != WSAEINTR)
+                return UA_STATUSCODE_BADCONNECTIONCLOSED;
+        } while(result != 0);
+        nWritten += n;
+    }
 #else
 #else
-		UA_Int32 sockfd;
+    struct iovec iov[gather_buf.stringsSize];
+    memset(iov, 0, sizeof(struct iovec)*gather_buf.stringsSize);
+    for(UA_UInt32 i=0;i<gather_buf.stringsSize;i++) {
+        iov[i].iov_base = gather_buf.strings[i].data;
+        iov[i].iov_len = gather_buf.strings[i].length;
+        total_len += gather_buf.strings[i].length;
+    }
+    struct msghdr message;
+    memset(&message, 0, sizeof(message));
+    message.msg_iov = iov;
+    message.msg_iovlen = gather_buf.stringsSize;
+    while (nWritten < total_len) {
+        UA_Int32 n = 0;
+        do {
+            n = sendmsg(connection->sockfd, &message, 0);
+            if(n == -1L && errno != EINTR)
+                return UA_STATUSCODE_BADCONNECTIONCLOSED;
+        } while (n == -1L);
+        nWritten += n;
+    }
 #endif
 #endif
-        struct deleteLink *next;
+    return UA_STATUSCODE_GOOD;
+}
 
 
-    } *deleteLinkList;
-} ServerNetworkLayerTCP;
+static UA_StatusCode socket_recv(UA_Connection *connection, UA_ByteString *response, UA_UInt32 timeout) {
+    struct timeval tmptv = {0, timeout * 1000};
+    setsockopt(connection->sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tmptv, sizeof(struct timeval));
+    int ret = recv(connection->sockfd, (char*)response->data, response->length, 0);
+    if(ret <= -1) {
+        if(errno == EAGAIN) {
+            UA_ByteString_deleteMembers(response);
+            UA_ByteString_init(response);
+            return UA_STATUSCODE_GOOD;
+        }
+        return UA_STATUSCODE_BADINTERNALERROR;
+    }
+    response->length = ret;
+    *response = UA_Connection_completeMessages(connection, *response);
+    return UA_STATUSCODE_GOOD;
+}
 
 
-typedef struct ClientNetworkLayerTCP {
-	fd_set read_fds;
-#ifdef _WIN32
-	UA_UInt32 sockfd;
-#else
-	UA_Int32 sockfd;
-#endif
-} ClientNetworkLayerTCP;
+static void socket_close(UA_Connection *connection) {
+    connection->state = UA_CONNECTION_CLOSED;
+    shutdown(connection->sockfd,2);
+    CLOSESOCKET(connection->sockfd);
+}
 
 
-static UA_StatusCode setNonBlocking(int sockid) {
+static UA_StatusCode socket_set_nonblocking(UA_Int32 sockfd) {
 #ifdef _WIN32
 #ifdef _WIN32
-	u_long iMode = 1;
-	if(ioctlsocket(sockid, FIONBIO, &iMode) != NO_ERROR)
-		return UA_STATUSCODE_BADINTERNALERROR;
+    u_long iMode = 1;
+    if(ioctlsocket(sockfd, FIONBIO, &iMode) != NO_ERROR)
+        return UA_STATUSCODE_BADINTERNALERROR;
 #else
 #else
-	int opts = fcntl(sockid,F_GETFL);
-	if(opts < 0 || fcntl(sockid,F_SETFL,opts|O_NONBLOCK) < 0)
-		return UA_STATUSCODE_BADINTERNALERROR;
+    int opts = fcntl(sockfd, F_GETFL);
+    if(opts < 0 || fcntl(sockfd, F_SETFL, opts|O_NONBLOCK) < 0)
+        return UA_STATUSCODE_BADINTERNALERROR;
 #endif
 #endif
-	return UA_STATUSCODE_GOOD;
+    return UA_STATUSCODE_GOOD;
 }
 }
 
 
-static void freeConnectionCallback(UA_Server *server, TCPConnection *connection) {
-    UA_ByteString_deleteMembers(&connection->connection.incompleteMessage);
-    free(connection);
+/*****************************/
+/* Generic Buffer Management */
+/*****************************/
+
+static UA_StatusCode GetMallocedBuffer(UA_Connection *connection, UA_ByteString *buf, size_t minSize) {
+    if(minSize > connection->remoteConf.recvBufferSize)
+        return UA_STATUSCODE_BADINTERNALERROR;
+    return UA_ByteString_newMembers(buf, minSize);
 }
 }
 
 
-// after every select, reset the set of sockets we want to listen on
-static void setFDSet(ServerNetworkLayerTCP *layer) {
-	FD_ZERO(&layer->fdset);
-	FD_SET(layer->serversockfd, &layer->fdset);
-	layer->highestfd = layer->serversockfd;
-	for(UA_Int32 i=0;i<layer->conLinksSize;i++) {
-		FD_SET(layer->conLinks[i].sockfd, &layer->fdset);
-		if(layer->conLinks[i].sockfd > layer->highestfd)
-			layer->highestfd = layer->conLinks[i].sockfd;
-	}
+static void ReleaseMallocedBuffer(UA_Connection *connection, UA_ByteString *buf) {
+    UA_ByteString_deleteMembers(buf);
 }
 }
 
 
-// the callbacks are thread-safe if UA_MULTITHREADING is defined
-void closeConnection(TCPConnection *handle);
-void writeCallback(TCPConnection *handle, UA_ByteStringArray gather_buf);
+/***************************/
+/* Server NetworkLayer TCP */
+/***************************/
 
 
-static UA_StatusCode ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_Int32 newsockfd) {
-    setNonBlocking(newsockfd);
-    TCPConnection *c = malloc(sizeof(TCPConnection));
-	if(!c)
-		return UA_STATUSCODE_BADINTERNALERROR;
-	c->sockfd = newsockfd;
-    c->layer = layer;
-    c->connection.state = UA_CONNECTION_OPENING;
-    c->connection.localConf = layer->conf;
-    c->connection.channel = (void*)0;
-    c->connection.close = (void (*)(void*))closeConnection;
-    c->connection.write = (void (*)(void*, UA_ByteStringArray))writeCallback;
-    UA_ByteString_init(&c->connection.incompleteMessage);
-
-    layer->conLinks = realloc(layer->conLinks, sizeof(ConnectionLink)*(layer->conLinksSize+1));
-	if(!layer->conLinks) {
-		free(c);
-		return UA_STATUSCODE_BADINTERNALERROR;
-	}
-    layer->conLinks[layer->conLinksSize].connection = c;
-    layer->conLinks[layer->conLinksSize].sockfd = newsockfd;
-    layer->conLinksSize++;
-	return UA_STATUSCODE_GOOD;
-}
+/**
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * - 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.
+ *
+ */
 
 
-/* Removes all connections from the network layer. Returns the work items to close them properly. */
-static UA_UInt32 removeAllConnections(ServerNetworkLayerTCP *layer, UA_WorkItem **returnWork) {
-    UA_WorkItem *work;
-	if (layer->conLinksSize <= 0 || !(work = malloc(sizeof(UA_WorkItem)*layer->conLinksSize))) {
-		*returnWork = NULL;
-		return 0;
-	}
-#ifdef UA_MULTITHREADING
-    struct deleteLink *d = uatomic_xchg(&layer->deleteLinkList, (void*)0);
+#define MAXBACKLOG 100
+
+typedef struct {
+    /* config */
+    UA_Logger *logger;
+    UA_UInt32 port;
+    UA_String discoveryUrl;
+    UA_ConnectionConfig conf; /* todo: rename to localconf. */
+
+    /* open sockets and connections */
+    fd_set fdset;
+    UA_Int32 serversockfd;
+    UA_Int32 highestfd;
+    size_t mappingsSize;
+    struct ConnectionMapping {
+        UA_Connection *connection;
+        UA_Int32 sockfd;
+    } *mappings;
+
+    /* to-be-deleted connections */
+    struct DeleteList {
+        struct DeleteList *next;
+        UA_Connection *connection;
+    } *deletes;
+} ServerNetworkLayerTCP;
+
+/* after every select, we need to reset the sockets we want to listen on */
+static void setFDSet(ServerNetworkLayerTCP *layer) {
+    FD_ZERO(&layer->fdset);
+#ifdef _WIN32
+    FD_SET((UA_UInt32)layer->serversockfd, &layer->fdset);
 #else
 #else
-    struct deleteLink *d = layer->deleteLinkList;
-    layer->deleteLinkList = (void*)0;
+    FD_SET(layer->serversockfd, &layer->fdset);
 #endif
 #endif
-    UA_UInt32 count = 0;
-    while(d) {
-        UA_Int32 i;
-        for(i = 0;i<layer->conLinksSize;i++) {
-            if(layer->conLinks[i].sockfd == d->sockfd)
-                break;
-        }
-        if(i < layer->conLinksSize) {
-            TCPConnection *c = layer->conLinks[i].connection;
-            layer->conLinksSize--;
-            layer->conLinks[i] = layer->conLinks[layer->conLinksSize];
-            work[count] = (UA_WorkItem)
-                {.type = UA_WORKITEMTYPE_DELAYEDMETHODCALL,
-                 .work.methodCall = {.data = c,
-                                     .method = (void (*)(UA_Server*,void*))freeConnectionCallback} };
-        }
-        struct deleteLink *oldd = d;
-        d = d->next;
-        free(oldd);
-        count++;
+    layer->highestfd = layer->serversockfd;
+    for(size_t i = 0; i < layer->mappingsSize; i++) {
+#ifdef _WIN32
+        FD_SET((UA_UInt32)layer->mappings[i].sockfd, &layer->fdset);
+#else
+        FD_SET(layer->mappings[i].sockfd, &layer->fdset);
+#endif
+        if(layer->mappings[i].sockfd > layer->highestfd)
+            layer->highestfd = layer->mappings[i].sockfd;
     }
     }
-    *returnWork = work;
-    return count;
 }
 }
 
 
+/* callback triggered from the server */
+static void ServerNetworkLayerTCP_closeConnection(UA_Connection *connection) {
 #ifdef UA_MULTITHREADING
 #ifdef UA_MULTITHREADING
-void closeConnection(TCPConnection *handle) {
-    if(uatomic_xchg(&handle->connection.state, UA_CONNECTION_CLOSING) == UA_CONNECTION_CLOSING)
+    if(uatomic_xchg(&connection->state, UA_CONNECTION_CLOSED) == UA_CONNECTION_CLOSED)
         return;
         return;
-    
-    UA_Connection_detachSecureChannel(&handle->connection);
-	shutdown(handle->sockfd,2);
-	CLOSESOCKET(handle->sockfd);
-
-    ServerNetworkLayerTCP *layer = (ServerNetworkLayerTCP*)handle->layer;
-
-    // Remove the link later in the main thread
-    struct deleteLink *d = malloc(sizeof(struct deleteLink));
-    d->sockfd = handle->sockfd;
+#else
+    if(connection->state == UA_CONNECTION_CLOSED)
+        return;
+    connection->state = UA_CONNECTION_CLOSED;
+#endif
+    socket_close(connection);
+    ServerNetworkLayerTCP *layer = (ServerNetworkLayerTCP*)connection->handle;
+    struct DeleteList *d = malloc(sizeof(struct DeleteList));
+    d->connection = connection;
+#ifdef UA_MULTITHREADING
     while(1) {
     while(1) {
-        d->next = layer->deleteLinkList;
-        if(uatomic_cmpxchg(&layer->deleteLinkList, d->next, d) == d->next)
+        d->next = layer->deletes;
+        if(uatomic_cmpxchg(&layer->deletes, d->next, d) == d->next)
             break;
             break;
     }
     }
-}
 #else
 #else
-void closeConnection(TCPConnection *handle) {
-    if(handle->connection.state == UA_CONNECTION_CLOSING)
-        return;
-
-	struct deleteLink *d = malloc(sizeof(struct deleteLink));
-	if(!d)
-		return;
-    handle->connection.state = UA_CONNECTION_CLOSING;
-
-    UA_Connection_detachSecureChannel(&handle->connection);
-	shutdown(handle->sockfd,2);
-	CLOSESOCKET(handle->sockfd);
-
-    // Remove the link later in the main thread
-    d->sockfd = handle->sockfd;
-    ServerNetworkLayerTCP *layer = (ServerNetworkLayerTCP*)handle->layer;
-    d->next = layer->deleteLinkList;
-    layer->deleteLinkList = d;
-}
+    d->next = layer->deletes;
+    layer->deletes = d;
 #endif
 #endif
+}
 
 
-/** Accesses only the sockfd in the handle. Can be run from parallel threads. */
-void writeCallback(TCPConnection *handle, UA_ByteStringArray gather_buf) {
-	UA_UInt32 total_len = 0, nWritten = 0;
-#ifdef _WIN32
-	LPWSABUF buf = _alloca(gather_buf.stringsSize * sizeof(WSABUF));
-	memset(buf, 0, sizeof(gather_buf.stringsSize * sizeof(WSABUF)));
-	int result = 0;
-	for(UA_UInt32 i = 0; i<gather_buf.stringsSize; i++) {
-		buf[i].buf = (char*)gather_buf.strings[i].data;
-		buf[i].len = gather_buf.strings[i].length;
-		total_len += gather_buf.strings[i].length;
-	}
-	while(nWritten < total_len) {
-		UA_UInt32 n = 0;
-		do {
-			result = WSASend(handle->sockfd, buf, gather_buf.stringsSize ,
-                             (LPDWORD)&n, 0, NULL, NULL);
-			if(result != 0)
-				printf("Error WSASend, code: %d \n", WSAGetLastError());
-		} while(errno == EINTR);
-		nWritten += n;
-	}
-#else
-	struct iovec iov[gather_buf.stringsSize];
-	memset(iov, 0, sizeof(struct iovec)*gather_buf.stringsSize);
-	for(UA_UInt32 i=0;i<gather_buf.stringsSize;i++) {
-		iov[i].iov_base = gather_buf.strings[i].data;
-		iov[i].iov_len = gather_buf.strings[i].length;
-		total_len += gather_buf.strings[i].length;
-	}
-	struct msghdr message;
-	memset(&message, 0, sizeof(message));
-	message.msg_iov = iov;
-	message.msg_iovlen = gather_buf.stringsSize;
-	while (nWritten < total_len) {
-		UA_Int32 n = 0;
-		do {
-            n = sendmsg(handle->sockfd, &message, 0);
-        } while (n == -1L && errno == EINTR);
-        nWritten += n;
-	}
-#endif
+/* call only from the single networking thread */
+static UA_StatusCode ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_Int32 newsockfd) {
+    UA_Connection *c = malloc(sizeof(UA_Connection));
+    if(!c)
+        return UA_STATUSCODE_BADINTERNALERROR;
+    UA_Connection_init(c);
+    c->sockfd = newsockfd;
+    c->handle = layer;
+    c->localConf = layer->conf;
+    c->write = socket_write;
+    c->close = ServerNetworkLayerTCP_closeConnection;
+    c->getBuffer = GetMallocedBuffer;
+    c->releaseBuffer = ReleaseMallocedBuffer;
+    struct ConnectionMapping *nm =
+        realloc(layer->mappings, sizeof(struct ConnectionMapping)*(layer->mappingsSize+1));
+    if(!nm) {
+        free(c);
+        return UA_STATUSCODE_BADINTERNALERROR;
+    }
+    layer->mappings = nm;
+    layer->mappings[layer->mappingsSize] = (struct ConnectionMapping){c, newsockfd};
+    layer->mappingsSize++;
+    return UA_STATUSCODE_GOOD;
 }
 }
 
 
 static UA_StatusCode ServerNetworkLayerTCP_start(ServerNetworkLayerTCP *layer, UA_Logger *logger) {
 static UA_StatusCode ServerNetworkLayerTCP_start(ServerNetworkLayerTCP *layer, UA_Logger *logger) {
+    layer->logger = logger;
 #ifdef _WIN32
 #ifdef _WIN32
-	if((layer->serversockfd = socket(PF_INET, SOCK_STREAM,0)) == INVALID_SOCKET) {
-		printf("ERROR opening socket, code: %d\n", WSAGetLastError());
-		return UA_STATUSCODE_BADINTERNALERROR;
-	}
+    if((layer->serversockfd = socket(PF_INET, SOCK_STREAM,0)) == (UA_Int32)INVALID_SOCKET) {
+        UA_LOG_WARNING((*layer->logger), UA_LOGGERCATEGORY_COMMUNICATION, "Error opening socket, code: %d",
+                       WSAGetLastError());
+        return UA_STATUSCODE_BADINTERNALERROR;
+    }
 #else
 #else
     if((layer->serversockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
     if((layer->serversockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
-		perror("ERROR opening socket");
-		return UA_STATUSCODE_BADINTERNALERROR;
-	} 
+        UA_LOG_WARNING((*layer->logger), UA_LOGGERCATEGORY_COMMUNICATION, "Error opening socket");
+        return UA_STATUSCODE_BADINTERNALERROR;
+    } 
 #endif
 #endif
-
-	const struct sockaddr_in serv_addr = {
-        .sin_family = AF_INET, .sin_addr.s_addr = INADDR_ANY,
-        .sin_port = htons(layer->port), .sin_zero = {0}};
-
-	int optval = 1;
-	if(setsockopt(layer->serversockfd, SOL_SOCKET,
+    const struct sockaddr_in serv_addr =
+        {.sin_family = AF_INET, .sin_addr.s_addr = INADDR_ANY,
+         .sin_port = htons(layer->port), .sin_zero = {0}};
+    int optval = 1;
+    if(setsockopt(layer->serversockfd, SOL_SOCKET,
                   SO_REUSEADDR, (const char *)&optval,
                   SO_REUSEADDR, (const char *)&optval,
                   sizeof(optval)) == -1) {
                   sizeof(optval)) == -1) {
-		perror("setsockopt");
-		CLOSESOCKET(layer->serversockfd);
-		return UA_STATUSCODE_BADINTERNALERROR;
-	}
-		
-	if(bind(layer->serversockfd, (const struct sockaddr *)&serv_addr,
+        UA_LOG_WARNING((*layer->logger), UA_LOGGERCATEGORY_COMMUNICATION, "Error during setting of socket options");
+        CLOSESOCKET(layer->serversockfd);
+        return UA_STATUSCODE_BADINTERNALERROR;
+    }
+    if(bind(layer->serversockfd, (const struct sockaddr *)&serv_addr,
             sizeof(serv_addr)) < 0) {
             sizeof(serv_addr)) < 0) {
-		perror("binding");
-		CLOSESOCKET(layer->serversockfd);
-		return UA_STATUSCODE_BADINTERNALERROR;
-	}
-
-	setNonBlocking(layer->serversockfd);
-	listen(layer->serversockfd, MAXBACKLOG);
-    UA_LOG_INFO((*logger), UA_LOGGERCATEGORY_SERVER, "Listening on %.*s",
+        UA_LOG_WARNING((*layer->logger), UA_LOGGERCATEGORY_COMMUNICATION, "Error during socket binding");
+        CLOSESOCKET(layer->serversockfd);
+        return UA_STATUSCODE_BADINTERNALERROR;
+    }
+    socket_set_nonblocking(layer->serversockfd);
+    listen(layer->serversockfd, MAXBACKLOG);
+    UA_LOG_INFO((*layer->logger), UA_LOGGERCATEGORY_COMMUNICATION, "Listening on %.*s",
                 layer->discoveryUrl.length, layer->discoveryUrl.data);
                 layer->discoveryUrl.length, layer->discoveryUrl.data);
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
+/* delayed callback that frees old connections */
+static void freeConnections(UA_Server *server, struct DeleteList *d) {
+    while(d) {
+        UA_Connection_deleteMembers(d->connection);
+        free(d->connection);
+        struct DeleteList *old = d;
+        d = d->next;
+        free(old);
+    }
+}
+
+/* remove the closed sockets from the mappings array */
+static void removeMappings(ServerNetworkLayerTCP *layer, struct DeleteList *d) {
+    while(d) {
+        size_t i = 0;
+        for(; i < layer->mappingsSize; i++) {
+            if(layer->mappings[i].sockfd == d->connection->sockfd)
+                break;
+        }
+        if(i >= layer->mappingsSize)
+            continue;
+        layer->mappingsSize--;
+        layer->mappings[i] = layer->mappings[layer->mappingsSize];
+        d = d->next;
+    }
+}
+
 static UA_Int32 ServerNetworkLayerTCP_getWork(ServerNetworkLayerTCP *layer, UA_WorkItem **workItems,
 static UA_Int32 ServerNetworkLayerTCP_getWork(ServerNetworkLayerTCP *layer, UA_WorkItem **workItems,
-                                        UA_UInt16 timeout) {
-    UA_WorkItem *items = (void*)0;
-    UA_Int32 itemsCount = removeAllConnections(layer, &items);
+                                              UA_UInt16 timeout) {
+    struct DeleteList *deletes;
+#ifdef UA_MULTITHREADING
+        deletes = uatomic_xchg(&layer->deletes, NULL);
+#else
+        deletes = layer->deletes;
+        layer->deletes = NULL;
+#endif
+    removeMappings(layer, deletes);
     setFDSet(layer);
     setFDSet(layer);
-    struct timeval tmptv = {0, timeout};
+    struct timeval tmptv = {0, timeout * 1000};
     UA_Int32 resultsize = select(layer->highestfd+1, &layer->fdset, NULL, NULL, &tmptv);
     UA_Int32 resultsize = select(layer->highestfd+1, &layer->fdset, NULL, NULL, &tmptv);
-
-    if(resultsize < 0) {
-        *workItems = items;
-        return itemsCount;
+    UA_WorkItem *items;
+    if(resultsize < 0 || !(items = malloc(sizeof(UA_WorkItem)*(resultsize+1)))) {
+        /* abort .. reattach the deletes so that they get deleted eventually.. */
+#ifdef UA_MULTITHREADING
+        struct DeleteList *last_delete = deletes;
+        while(last_delete->next != NULL)
+            last_delete = last_delete->next;
+        while(1) {
+            last_delete->next = layer->deletes;
+            if(uatomic_cmpxchg(&layer->deletes, last_delete->next, deletes) == last_delete->next)
+                break;
+        }
+#else
+        layer->deletes = deletes;
+#endif
+        *workItems = NULL;
+        return 0;
     }
     }
 
 
-	// accept new connections (can only be a single one)
-	if(FD_ISSET(layer->serversockfd,&layer->fdset)) {
-		resultsize--;
-		struct sockaddr_in cli_addr;
-		socklen_t cli_len = sizeof(cli_addr);
-		int newsockfd = accept(layer->serversockfd, (struct sockaddr *) &cli_addr, &cli_len);
-		int i = 1;
-		setsockopt(newsockfd, IPPROTO_TCP, TCP_NODELAY, (void *)&i, sizeof(i));
-		if (newsockfd >= 0)
-			ServerNetworkLayerTCP_add(layer, newsockfd);
-	}
+    /* accept new connections (can only be a single one) */
+    if(FD_ISSET(layer->serversockfd, &layer->fdset)) {
+        resultsize--;
+        struct sockaddr_in cli_addr;
+        socklen_t cli_len = sizeof(cli_addr);
+        int newsockfd = accept(layer->serversockfd, (struct sockaddr *) &cli_addr, &cli_len);
+        int i = 1;
+        setsockopt(newsockfd, IPPROTO_TCP, TCP_NODELAY, (void *)&i, sizeof(i));
+        if (newsockfd >= 0) {
+            socket_set_nonblocking(newsockfd);
+            ServerNetworkLayerTCP_add(layer, newsockfd);
+        }
+    }
     
     
-    items = realloc(items, sizeof(UA_WorkItem)*(itemsCount+resultsize));
-
-	// read from established sockets
-    UA_Int32 j = itemsCount;
-	UA_ByteString buf = { -1, NULL};
-	for(UA_Int32 i=0;i<layer->conLinksSize && j<itemsCount+resultsize;i++) {
-		if(!(FD_ISSET(layer->conLinks[i].sockfd, &layer->fdset)))
+    /* read from established sockets */
+    UA_Int32 j = 0;
+    UA_ByteString buf = UA_BYTESTRING_NULL;
+    for(size_t i = 0; i < layer->mappingsSize && j < resultsize; i++) {
+        if(!(FD_ISSET(layer->mappings[i].sockfd, &layer->fdset)))
             continue;
             continue;
-
-		if(!buf.data) {
-			buf.data = malloc(sizeof(UA_Byte) * layer->conf.recvBufferSize);
-			if(!buf.data)
-				break;
-		}
-        
-#ifdef _WIN32
-        buf.length = recv(layer->conLinks[i].sockfd, (char *)buf.data,
-                          layer->conf.recvBufferSize, 0);
-#else
-        buf.length = read(layer->conLinks[i].sockfd, buf.data, layer->conf.recvBufferSize);
-#endif
-        if (buf.length <= 0) {
-            closeConnection(layer->conLinks[i].connection); // work is returned in the next iteration
-        } else {
+        if(!buf.data) {
+            buf.data = malloc(sizeof(UA_Byte) * layer->conf.recvBufferSize);
+            buf.length = layer->conf.recvBufferSize;
+            if(!buf.data)
+                break;
+        }
+        if(socket_recv(layer->mappings[i].connection, &buf, 0) == UA_STATUSCODE_GOOD) {
             items[j].type = UA_WORKITEMTYPE_BINARYNETWORKMESSAGE;
             items[j].type = UA_WORKITEMTYPE_BINARYNETWORKMESSAGE;
             items[j].work.binaryNetworkMessage.message = buf;
             items[j].work.binaryNetworkMessage.message = buf;
-            items[j].work.binaryNetworkMessage.connection = &layer->conLinks[i].connection->connection;
+            items[j].work.binaryNetworkMessage.connection = layer->mappings[i].connection;
             buf.data = NULL;
             buf.data = NULL;
-            j++;
+        } else {
+            items[j].type = UA_WORKITEMTYPE_CLOSECONNECTION;
+            items[j].work.closeConnection = layer->mappings[i].connection;
         }
         }
+        j++;
     }
     }
 
 
-    if(buf.data)
-        free(buf.data);
+    /* add the delayed work that frees the connections */
+    if(deletes) {
+        items[j].type = UA_WORKITEMTYPE_DELAYEDMETHODCALL;
+        items[j].work.methodCall.data = deletes;
+        items[j].work.methodCall.method = (void (*)(UA_Server *server, void *data))freeConnections;
+        j++;
+    }
 
 
+    /* free the array if there is no work */
     if(j == 0) {
     if(j == 0) {
         free(items);
         free(items);
         *workItems = NULL;
         *workItems = NULL;
@@ -391,49 +416,63 @@ static UA_Int32 ServerNetworkLayerTCP_getWork(ServerNetworkLayerTCP *layer, UA_W
     return j;
     return j;
 }
 }
 
 
-static UA_Int32 ServerNetworkLayerTCP_stop(ServerNetworkLayerTCP * layer, UA_WorkItem **workItems) {
-	for(UA_Int32 index = 0;index < layer->conLinksSize;index++)
-        closeConnection(layer->conLinks[index].connection);
+static UA_Int32 ServerNetworkLayerTCP_stop(ServerNetworkLayerTCP *layer, UA_WorkItem **workItems) {
+    struct DeleteList *deletes;
+#ifdef UA_MULTITHREADING
+        deletes = uatomic_xchg(&layer->deletes, NULL);
+#else
+        deletes = layer->deletes;
+        layer->deletes = NULL;
+#endif
+    removeMappings(layer, deletes);
+    UA_WorkItem *items = malloc(sizeof(UA_WorkItem) * layer->mappingsSize);
+    if(!items)
+        return 0;
+    for(size_t i = 0; i < layer->mappingsSize; i++) {
+        items[i].type = UA_WORKITEMTYPE_CLOSECONNECTION;
+        items[i].work.closeConnection = layer->mappings[i].connection;
+    }
 #ifdef _WIN32
 #ifdef _WIN32
-	WSACleanup();
+    WSACleanup();
 #endif
 #endif
-    return removeAllConnections(layer, workItems);
+    *workItems = items;
+    return layer->mappingsSize;
 }
 }
 
 
+/* run only when the server is stopped */
 static void ServerNetworkLayerTCP_delete(ServerNetworkLayerTCP *layer) {
 static void ServerNetworkLayerTCP_delete(ServerNetworkLayerTCP *layer) {
-	UA_String_deleteMembers(&layer->discoveryUrl);
-	for(UA_Int32 i=0;i<layer->conLinksSize;++i){
-		free(layer->conLinks[i].connection);
-	}
-	free(layer->conLinks);
-	free(layer);
+    UA_String_deleteMembers(&layer->discoveryUrl);
+    for(size_t i = 0; i < layer->mappingsSize; i++)
+        free(layer->mappings[i].connection);
+    free(layer->mappings);
+    freeConnections(NULL, layer->deletes);
+    free(layer);
 }
 }
 
 
 UA_ServerNetworkLayer ServerNetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UInt32 port) {
 UA_ServerNetworkLayer ServerNetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UInt32 port) {
 #ifdef _WIN32
 #ifdef _WIN32
-	WORD wVersionRequested;
-	WSADATA wsaData;
-	wVersionRequested = MAKEWORD(2, 2);
-	WSAStartup(wVersionRequested, &wsaData);
+    WORD wVersionRequested;
+    WSADATA wsaData;
+    wVersionRequested = MAKEWORD(2, 2);
+    WSAStartup(wVersionRequested, &wsaData);
 #endif
 #endif
-    ServerNetworkLayerTCP *tcplayer = malloc(sizeof(ServerNetworkLayerTCP));
-	tcplayer->conf = conf;
-	tcplayer->conLinksSize = 0;
-	tcplayer->conLinks = NULL;
-    tcplayer->port = port;
-    tcplayer->deleteLinkList = (void*)0;
+    ServerNetworkLayerTCP *layer = malloc(sizeof(ServerNetworkLayerTCP));
+    layer->conf = conf;
+    layer->mappingsSize = 0;
+    layer->mappings = NULL;
+    layer->port = port;
+    layer->deletes = NULL;
     char hostname[256];
     char hostname[256];
     gethostname(hostname, 255);
     gethostname(hostname, 255);
-    UA_String_copyprintf("opc.tcp://%s:%d", &tcplayer->discoveryUrl, hostname, port);
+    UA_String_copyprintf("opc.tcp://%s:%d", &layer->discoveryUrl, hostname, port);
 
 
     UA_ServerNetworkLayer nl;
     UA_ServerNetworkLayer nl;
-    nl.nlHandle = tcplayer;
+    nl.nlHandle = layer;
     nl.start = (UA_StatusCode (*)(void*, UA_Logger *logger))ServerNetworkLayerTCP_start;
     nl.start = (UA_StatusCode (*)(void*, UA_Logger *logger))ServerNetworkLayerTCP_start;
     nl.getWork = (UA_Int32 (*)(void*, UA_WorkItem**, UA_UInt16))ServerNetworkLayerTCP_getWork;
     nl.getWork = (UA_Int32 (*)(void*, UA_WorkItem**, UA_UInt16))ServerNetworkLayerTCP_getWork;
     nl.stop = (UA_Int32 (*)(void*, UA_WorkItem**))ServerNetworkLayerTCP_stop;
     nl.stop = (UA_Int32 (*)(void*, UA_WorkItem**))ServerNetworkLayerTCP_stop;
     nl.free = (void (*)(void*))ServerNetworkLayerTCP_delete;
     nl.free = (void (*)(void*))ServerNetworkLayerTCP_delete;
-	nl.discoveryUrl = &tcplayer->discoveryUrl;
-
+    nl.discoveryUrl = &layer->discoveryUrl;
     return nl;
     return nl;
 }
 }
 
 
@@ -441,164 +480,69 @@ UA_ServerNetworkLayer ServerNetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UIn
 /* Client NetworkLayer TCP */
 /* Client NetworkLayer TCP */
 /***************************/
 /***************************/
 
 
-static UA_StatusCode ClientNetworkLayerTCP_connect(const UA_String endpointUrl, ClientNetworkLayerTCP *resultHandle) {
-	if(endpointUrl.length < 11 || endpointUrl.length >= 512) {
-        printf("server url size invalid\n");
-        return UA_STATUSCODE_BADINTERNALERROR;
-    }
+UA_Connection ClientNetworkLayerTCP_connect(char *endpointUrl, UA_Logger *logger) {
+    UA_Connection connection;
+    UA_Connection_init(&connection);
 
 
-    if(strncmp((char*)endpointUrl.data, "opc.tcp://", 10) != 0) {
-        printf("server url does not begin with opc.tcp://\n");
-        return UA_STATUSCODE_BADINTERNALERROR;
+    size_t urlLength = strlen(endpointUrl);
+    if(urlLength < 11 || urlLength >= 512) {
+        UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "Server url size invalid");
+        return connection;
+    }
+    if(strncmp(endpointUrl, "opc.tcp://", 10) != 0) {
+        UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "Server url does not begin with opc.tcp://");
+        return connection;
     }
     }
-
-    //this is somewhat ugly, but atoi needs a c string
-    char *cstringEndpointUrl = UA_alloca(sizeof(char) * endpointUrl.length+1);
-    memset(cstringEndpointUrl, 0, endpointUrl.length+1);
-    memcpy(cstringEndpointUrl, endpointUrl.data, endpointUrl.length);
-    cstringEndpointUrl[endpointUrl.length + 1] = '0';
 
 
     UA_UInt16 portpos = 9;
     UA_UInt16 portpos = 9;
     UA_UInt16 port = 0;
     UA_UInt16 port = 0;
-    for(;portpos < endpointUrl.length; portpos++) {
-        if(endpointUrl.data[portpos] == ':') {
-            port = atoi(&cstringEndpointUrl[portpos+1]);
+    for(;portpos < urlLength-1; portpos++) {
+        if(endpointUrl[portpos] == ':') {
+            port = atoi(&endpointUrl[portpos+1]);
             break;
             break;
         }
         }
     }
     }
     if(port == 0) {
     if(port == 0) {
-        printf("port invalid");
-        return UA_STATUSCODE_BADINTERNALERROR;
+        UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "Port invalid");
+        return connection;
     }
     }
-    
+
     char hostname[512];
     char hostname[512];
     for(int i=10; i < portpos; i++)
     for(int i=10; i < portpos; i++)
-        hostname[i-10] = endpointUrl.data[i];
+        hostname[i-10] = endpointUrl[i];
     hostname[portpos-10] = 0;
     hostname[portpos-10] = 0;
-
 #ifdef _WIN32
 #ifdef _WIN32
-    UA_UInt32 sock = 0;
+    WORD wVersionRequested;
+    WSADATA wsaData;
+    wVersionRequested = MAKEWORD(2, 2);
+    WSAStartup(wVersionRequested, &wsaData);
+    if((connection.sockfd = socket(PF_INET, SOCK_STREAM,0)) == (UA_Int32)INVALID_SOCKET) {
 #else
 #else
-    UA_Int32 sock = 0;
+    if((connection.sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
 #endif
 #endif
-#ifdef _WIN32
-	WORD wVersionRequested;
-	WSADATA wsaData;
-	wVersionRequested = MAKEWORD(2, 2);
-	WSAStartup(wVersionRequested, &wsaData);
-    if((sock = socket(PF_INET, SOCK_STREAM,0)) == INVALID_SOCKET) {
-#else
-    if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
-#endif
-		printf("Could not create socket\n");
-        return UA_STATUSCODE_BADINTERNALERROR;
+        UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "Could not create socket");
+        return connection;
     }
     }
-
-    struct hostent *server;
-    server = gethostbyname(hostname);
-    if (server == NULL) {
-        printf("DNS lookup of %s failed\n", hostname);
-        return UA_STATUSCODE_BADINTERNALERROR;
+    struct hostent *server = gethostbyname(hostname);
+    if(server == NULL) {
+        UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "DNS lookup of %s failed", hostname);
+        return connection;
     }
     }
-
-	struct sockaddr_in server_addr;
-
+    struct sockaddr_in server_addr;
     memset(&server_addr, 0, sizeof(server_addr));
     memset(&server_addr, 0, sizeof(server_addr));
-    memcpy((char *)&server_addr.sin_addr.s_addr,
-    	 (char *)server->h_addr_list[0],
-         server->h_length);
-
-	server_addr.sin_family = AF_INET;
-	server_addr.sin_port = htons(port);
-	if(connect(sock, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {
-        printf("Connect failed.\n");
-        return UA_STATUSCODE_BADINTERNALERROR;
+    memcpy((char *)&server_addr.sin_addr.s_addr, (char *)server->h_addr_list[0], server->h_length);
+    server_addr.sin_family = AF_INET;
+    server_addr.sin_port = htons(port);
+    if(connect(connection.sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {
+        UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "Connection failed");
+        return connection;
     }
     }
-    //if(setNonBlocking(*sock) != UA_STATUSCODE_GOOD) {
-    //    printf("Could not switch to nonblocking.\n");
-    //	FINALLY
-    //    return UA_STATUSCODE_BADINTERNALERROR;
-    //}
-    resultHandle->sockfd = sock;
-    return UA_STATUSCODE_GOOD;
-}
-
-static void ClientNetworkLayerTCP_disconnect(ClientNetworkLayerTCP* handle) {
-	CLOSESOCKET(handle->sockfd);
-#ifdef _WIN32
-	WSACleanup();
-#endif
-}
-
-static UA_StatusCode ClientNetworkLayerTCP_send(ClientNetworkLayerTCP *handle, UA_ByteStringArray gather_buf) {
-	UA_UInt32 total_len = 0, nWritten = 0;
-#ifdef _WIN32
-	LPWSABUF buf = _alloca(gather_buf.stringsSize * sizeof(WSABUF));
-	int result = 0;
-	for(UA_UInt32 i = 0; i<gather_buf.stringsSize; i++) {
-		buf[i].buf = (char*)gather_buf.strings[i].data;
-		buf[i].len = gather_buf.strings[i].length;
-		total_len += gather_buf.strings[i].length;
-	}
-	while(nWritten < total_len) {
-		UA_UInt32 n = 0;
-		do {
-			result = WSASend(handle->sockfd, buf, gather_buf.stringsSize ,
-                             (LPDWORD)&n, 0, NULL, NULL);
-			if(result != 0)
-				printf("Error WSASend, code: %d \n", WSAGetLastError());
-		} while(errno == EINTR);
-		nWritten += n;
-	}
-#else
-	struct iovec iov[gather_buf.stringsSize];
-	for(UA_UInt32 i=0;i<gather_buf.stringsSize;i++) {
-		iov[i] = (struct iovec) {.iov_base = gather_buf.strings[i].data,
-                                 .iov_len = gather_buf.strings[i].length};
-		total_len += gather_buf.strings[i].length;
-	}
-	struct msghdr message = {.msg_name = NULL, .msg_namelen = 0, .msg_iov = iov,
-							 .msg_iovlen = gather_buf.stringsSize, .msg_control = NULL,
-							 .msg_controllen = 0, .msg_flags = 0};
-	while (nWritten < total_len) {
-        int n = sendmsg(handle->sockfd, &message, 0);
-        if(n <= -1)
-            return UA_STATUSCODE_BADINTERNALERROR;
-        nWritten += n;
-	}
-#endif
-    return UA_STATUSCODE_GOOD;
-}
-
-static UA_StatusCode
-ClientNetworkLayerTCP_awaitResponse(ClientNetworkLayerTCP *handle, UA_ByteString *response,
-                                    UA_UInt32 timeout) {
-    struct timeval tmptv = {0, timeout};
-    setsockopt(handle->sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tmptv,sizeof(struct timeval));
-    int ret = recv(handle->sockfd, (char*)response->data, response->length, 0);
-    if(ret <= -1)
-    	return UA_STATUSCODE_BADINTERNALERROR;
-    if(ret == 0)
-        return UA_STATUSCODE_BADSERVERNOTCONNECTED;
-    response->length = ret;
-    return UA_STATUSCODE_GOOD;
-}
-
-static void ClientNetworkLayerTCP_delete(ClientNetworkLayerTCP *layer) {
-	if(layer)
-		free(layer);
-}
-
-UA_ClientNetworkLayer ClientNetworkLayerTCP_new(UA_ConnectionConfig conf) {
-	ClientNetworkLayerTCP *tcplayer = malloc(sizeof(ClientNetworkLayerTCP));
-	tcplayer->sockfd = 0;
-
-    UA_ClientNetworkLayer layer;
-    layer.nlHandle = tcplayer;
-    layer.connect = (UA_StatusCode (*)(const UA_String, void**)) ClientNetworkLayerTCP_connect;
-    layer.disconnect = (void (*)(void*)) ClientNetworkLayerTCP_disconnect;
-    layer.destroy = (void (*)(void*)) ClientNetworkLayerTCP_delete;
-    layer.send = (UA_StatusCode (*)(void*, UA_ByteStringArray)) ClientNetworkLayerTCP_send;
-    layer.awaitResponse = (UA_StatusCode (*)(void*, UA_ByteString *, UA_UInt32))ClientNetworkLayerTCP_awaitResponse;
-    return layer;
+    connection.state = UA_CONNECTION_OPENING;
+    socket_set_nonblocking(connection.sockfd);
+    connection.write = socket_write;
+    connection.recv = socket_recv;
+    connection.close = socket_close;
+    connection.getBuffer = GetMallocedBuffer;
+    connection.releaseBuffer = ReleaseMallocedBuffer;
+    return connection;
 }
 }

+ 1 - 1
examples/networklayer_tcp.h

@@ -19,7 +19,7 @@ extern "C" {
 
 
 /** @brief Create the TCP networklayer and listen to the specified port */
 /** @brief Create the TCP networklayer and listen to the specified port */
 UA_ServerNetworkLayer ServerNetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UInt32 port);
 UA_ServerNetworkLayer ServerNetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UInt32 port);
-UA_ClientNetworkLayer ClientNetworkLayerTCP_new(UA_ConnectionConfig conf);
+UA_Connection ClientNetworkLayerTCP_connect(char *endpointUrl, UA_Logger *logger);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 } // extern "C"
 } // extern "C"

+ 60 - 125
examples/networklayer_udp.c

@@ -16,15 +16,6 @@
 /* with a space so amalgamation does not remove the includes */
 /* with a space so amalgamation does not remove the includes */
 # include <errno.h> // errno, EINTR
 # include <errno.h> // errno, EINTR
 # include <fcntl.h> // fcntl
 # include <fcntl.h> // fcntl
-
-#ifdef _WIN32
-# include <malloc.h>
-# include <winsock2.h>
-# include <sys/types.h>
-# include <windows.h>
-# include <ws2tcpip.h>
-# define CLOSESOCKET(S) closesocket(S)
-#else
 # include <strings.h> //bzero
 # include <strings.h> //bzero
 # include <sys/select.h> 
 # include <sys/select.h> 
 # include <netinet/in.h>
 # include <netinet/in.h>
@@ -34,11 +25,30 @@
 # include <unistd.h> // read, write, close
 # include <unistd.h> // read, write, close
 # include <arpa/inet.h>
 # include <arpa/inet.h>
 # define CLOSESOCKET(S) close(S)
 # define CLOSESOCKET(S) close(S)
-#endif
 
 
 #define MAXBACKLOG 100
 #define MAXBACKLOG 100
 
 
-struct ServerNetworklayerUDP;
+#ifdef _WIN32
+# error fixme: udp not yet implemented for windows
+#endif
+
+/*****************************/
+/* Generic Buffer Management */
+/*****************************/
+
+static UA_StatusCode GetMallocedBuffer(UA_Connection *connection, UA_ByteString *buf, size_t minSize) {
+    if(minSize > connection->remoteConf.recvBufferSize)
+        return UA_STATUSCODE_BADINTERNALERROR;
+    return UA_ByteString_newMembers(buf, minSize);
+}
+
+static void ReleaseMallocedBuffer(UA_Connection *connection, UA_ByteString *buf) {
+    UA_ByteString_deleteMembers(buf);
+}
+
+/*********************/
+/* UDP Network Layer */
+/*********************/
 
 
 /* Forwarded to the server as a (UA_Connection) and used for callbacks back into
 /* Forwarded to the server as a (UA_Connection) and used for callbacks back into
    the networklayer */
    the networklayer */
@@ -46,84 +56,28 @@ typedef struct {
 	UA_Connection connection;
 	UA_Connection connection;
 	struct sockaddr from;
 	struct sockaddr from;
 	socklen_t fromlen;
 	socklen_t fromlen;
-	struct ServerNetworkLayerUDP *layer;
 } UDPConnection;
 } UDPConnection;
 
 
-typedef struct ServerNetworkLayerUDP {
+typedef struct {
+    UA_Server *server;
 	UA_ConnectionConfig conf;
 	UA_ConnectionConfig conf;
 	fd_set fdset;
 	fd_set fdset;
-#ifdef _WIN32
-	UA_UInt32 serversockfd;
-#else
 	UA_Int32 serversockfd;
 	UA_Int32 serversockfd;
-#endif
     UA_UInt32 port;
     UA_UInt32 port;
+    UA_Logger *logger;
 } ServerNetworkLayerUDP;
 } ServerNetworkLayerUDP;
 
 
-static UA_StatusCode setNonBlocking(int sockid) {
-#ifdef _WIN32
-	u_long iMode = 1;
-	if(ioctlsocket(sockid, FIONBIO, &iMode) != NO_ERROR)
-		return UA_STATUSCODE_BADINTERNALERROR;
-#else
-	int opts = fcntl(sockid,F_GETFL);
-	if(opts < 0 || fcntl(sockid,F_SETFL,opts|O_NONBLOCK) < 0)
-		return UA_STATUSCODE_BADINTERNALERROR;
-#endif
-	return UA_STATUSCODE_GOOD;
-}
-
-static void setFDSet(ServerNetworkLayerUDP *layer) {
-	FD_ZERO(&layer->fdset);
-	FD_SET(layer->serversockfd, &layer->fdset);
-}
-
-// the callbacks are thread-safe if UA_MULTITHREADING is defined
-static void closeConnectionUDP(UDPConnection *handle) {
-	free(handle);
-}
-
-void writeCallbackUDP(UDPConnection *handle, UA_ByteStringArray gather_buf);
-
 /** Accesses only the sockfd in the handle. Can be run from parallel threads. */
 /** Accesses only the sockfd in the handle. Can be run from parallel threads. */
-void writeCallbackUDP(UDPConnection *handle, UA_ByteStringArray gather_buf) {
+static void writeCallbackUDP(UDPConnection *handle, UA_ByteStringArray gather_buf) {
 	UA_UInt32 total_len = 0, nWritten = 0;
 	UA_UInt32 total_len = 0, nWritten = 0;
-#ifdef _WIN32
-	/*
-	LPWSABUF buf = _alloca(gather_buf.stringsSize * sizeof(WSABUF));
-	int result = 0;
-	for(UA_UInt32 i = 0; i<gather_buf.stringsSize; i++) {
-		buf[i].buf = (char*)gather_buf.strings[i].data;
-		buf[i].len = gather_buf.strings[i].length;
-		total_len += gather_buf.strings[i].length;
-	}
-	while(nWritten < total_len) {
-		UA_UInt32 n = 0;
-		do {
-			result = WSASendto(handle->layer->serversockfd, buf, gather_buf.stringsSize ,
-                             (LPDWORD)&n, 0, 
-                             handle->from, handle->fromlen,
-                             NULL, NULL);
-			//FIXME:
-			if(result != 0)
-				printf("Error WSASend, code: %d \n", WSAGetLastError());
-		} while(errno == EINTR);
-		nWritten += n;
-	}
-	*/
-	#error fixme: udp not yet implemented for windows
-#else
 	struct iovec iov[gather_buf.stringsSize];
 	struct iovec iov[gather_buf.stringsSize];
 	for(UA_UInt32 i=0;i<gather_buf.stringsSize;i++) {
 	for(UA_UInt32 i=0;i<gather_buf.stringsSize;i++) {
 		iov[i] = (struct iovec) {.iov_base = gather_buf.strings[i].data,
 		iov[i] = (struct iovec) {.iov_base = gather_buf.strings[i].data,
                                  .iov_len = gather_buf.strings[i].length};
                                  .iov_len = gather_buf.strings[i].length};
 		total_len += gather_buf.strings[i].length;
 		total_len += gather_buf.strings[i].length;
 	}
 	}
-
-
 	struct sockaddr_in *sin = NULL;
 	struct sockaddr_in *sin = NULL;
 	if (handle->from.sa_family == AF_INET) {
 	if (handle->from.sa_family == AF_INET) {
-        
 #if defined(__GNUC__) || defined(__clang__)
 #if defined(__GNUC__) || defined(__clang__)
 #pragma GCC diagnostic push
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wcast-align"
 #pragma GCC diagnostic ignored "-Wcast-align"
@@ -132,49 +86,50 @@ void writeCallbackUDP(UDPConnection *handle, UA_ByteStringArray gather_buf) {
 #if defined(__GNUC__) || defined(__clang__)
 #if defined(__GNUC__) || defined(__clang__)
 #pragma GCC diagnostic pop
 #pragma GCC diagnostic pop
 #endif
 #endif
-
 	} else {
 	} else {
 		//FIXME:
 		//FIXME:
 		return;
 		return;
 	}
 	}
-
 	struct msghdr message = {.msg_name = sin, .msg_namelen = handle->fromlen, .msg_iov = iov,
 	struct msghdr message = {.msg_name = sin, .msg_namelen = handle->fromlen, .msg_iov = iov,
 							 .msg_iovlen = gather_buf.stringsSize, .msg_control = NULL,
 							 .msg_iovlen = gather_buf.stringsSize, .msg_control = NULL,
 							 .msg_controllen = 0, .msg_flags = 0};
 							 .msg_controllen = 0, .msg_flags = 0};
 	while (nWritten < total_len) {
 	while (nWritten < total_len) {
 		UA_Int32 n = 0;
 		UA_Int32 n = 0;
 		do {
 		do {
-            n = sendmsg(handle->layer->serversockfd, &message, 0);
-            if(n==-1L){
+            n = sendmsg(((ServerNetworkLayerUDP*)handle->connection.handle)->serversockfd, &message, 0);
+            if(n == -1L) {
             	printf("ERROR:%i\n", errno);
             	printf("ERROR:%i\n", errno);
             }
             }
         } while (n == -1L && errno == EINTR);
         } while (n == -1L && errno == EINTR);
         nWritten += n;
         nWritten += n;
 	}
 	}
-#endif
+}
+
+static UA_StatusCode socket_set_nonblocking(UA_Int32 sockfd) {
+    int opts = fcntl(sockfd, F_GETFL);
+    if(opts < 0 || fcntl(sockfd, F_SETFL, opts|O_NONBLOCK) < 0)
+        return UA_STATUSCODE_BADINTERNALERROR;
+    return UA_STATUSCODE_GOOD;
+}
+
+static void setFDSet(ServerNetworkLayerUDP *layer) {
+	FD_ZERO(&layer->fdset);
+	FD_SET(layer->serversockfd, &layer->fdset);
+}
+
+static void closeConnectionUDP(UDPConnection *handle) {
+	free(handle);
 }
 }
 
 
 static UA_StatusCode ServerNetworkLayerUDP_start(ServerNetworkLayerUDP *layer, UA_Logger *logger) {
 static UA_StatusCode ServerNetworkLayerUDP_start(ServerNetworkLayerUDP *layer, UA_Logger *logger) {
-#ifdef _WIN32
-	WORD wVersionRequested;
-	WSADATA wsaData;
-	wVersionRequested = MAKEWORD(2, 2);
-	WSAStartup(wVersionRequested, &wsaData);
-	if((layer->serversockfd = socket(PF_INET, SOCK_DGRAM,0)) == INVALID_SOCKET) {
-		printf("ERROR opening socket, code: %d\n", WSAGetLastError());
-		return UA_STATUSCODE_BADINTERNALERROR;
-	}
-#else
+    layer->logger = logger;
     if((layer->serversockfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
     if((layer->serversockfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
 		perror("ERROR opening socket");
 		perror("ERROR opening socket");
 		return UA_STATUSCODE_BADINTERNALERROR;
 		return UA_STATUSCODE_BADINTERNALERROR;
 	} 
 	} 
-#endif
-
-	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}};
 	int optval = 1;
 	int optval = 1;
 	if(setsockopt(layer->serversockfd, SOL_SOCKET,
 	if(setsockopt(layer->serversockfd, SOL_SOCKET,
                   SO_REUSEADDR, (const char *)&optval,
                   SO_REUSEADDR, (const char *)&optval,
@@ -183,84 +138,64 @@ static UA_StatusCode ServerNetworkLayerUDP_start(ServerNetworkLayerUDP *layer, U
 		CLOSESOCKET(layer->serversockfd);
 		CLOSESOCKET(layer->serversockfd);
 		return UA_STATUSCODE_BADINTERNALERROR;
 		return UA_STATUSCODE_BADINTERNALERROR;
 	}
 	}
-
 	if(bind(layer->serversockfd, (const struct sockaddr *)&serv_addr,
 	if(bind(layer->serversockfd, (const struct sockaddr *)&serv_addr,
             sizeof(serv_addr)) < 0) {
             sizeof(serv_addr)) < 0) {
 		perror("binding");
 		perror("binding");
 		CLOSESOCKET(layer->serversockfd);
 		CLOSESOCKET(layer->serversockfd);
 		return UA_STATUSCODE_BADINTERNALERROR;
 		return UA_STATUSCODE_BADINTERNALERROR;
 	}
 	}
-
-	setNonBlocking(layer->serversockfd);
-    UA_LOG_INFO((*logger), UA_LOGGERCATEGORY_SERVER, "Listening for UDP connections on %s:%d",
-                inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port));
+	socket_set_nonblocking(layer->serversockfd);
+    printf("Listening for UDP connections on %s:%d", inet_ntoa(serv_addr.sin_addr),
+           ntohs(serv_addr.sin_port));
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
 static UA_Int32 ServerNetworkLayerUDP_getWork(ServerNetworkLayerUDP *layer, UA_WorkItem **workItems,
 static UA_Int32 ServerNetworkLayerUDP_getWork(ServerNetworkLayerUDP *layer, UA_WorkItem **workItems,
-                                        UA_UInt16 timeout) {
+                                              UA_UInt16 timeout) {
     UA_WorkItem *items = NULL;
     UA_WorkItem *items = NULL;
     setFDSet(layer);
     setFDSet(layer);
     struct timeval tmptv = {0, timeout};
     struct timeval tmptv = {0, timeout};
     UA_Int32 resultsize = select(layer->serversockfd+1, &layer->fdset, NULL, NULL, &tmptv);
     UA_Int32 resultsize = select(layer->serversockfd+1, &layer->fdset, NULL, NULL, &tmptv);
-
     if(resultsize <= 0 || !FD_ISSET(layer->serversockfd, &layer->fdset)) {
     if(resultsize <= 0 || !FD_ISSET(layer->serversockfd, &layer->fdset)) {
         *workItems = items;
         *workItems = items;
         return 0;
         return 0;
     }
     }
-
     items = malloc(sizeof(UA_WorkItem)*(resultsize));
     items = malloc(sizeof(UA_WorkItem)*(resultsize));
-
 	// read from established sockets
 	// read from established sockets
     UA_Int32 j = 0;
     UA_Int32 j = 0;
-	UA_ByteString buf = { -1, NULL};
+	UA_ByteString buf = {-1, NULL};
 		if(!buf.data) {
 		if(!buf.data) {
 			buf.data = malloc(sizeof(UA_Byte) * layer->conf.recvBufferSize);
 			buf.data = malloc(sizeof(UA_Byte) * layer->conf.recvBufferSize);
-			if(!buf.data){
-				//TODO:
+			if(!buf.data)
 				printf("malloc failed");
 				printf("malloc failed");
-			}
 		}
 		}
-
 		struct sockaddr sender;
 		struct sockaddr sender;
 		socklen_t sendsize = sizeof(sender);
 		socklen_t sendsize = sizeof(sender);
 		bzero(&sender, sizeof(sender));
 		bzero(&sender, sizeof(sender));
-
-#ifdef _WIN32
-        buf.length = recvfrom(layer->conLinks[i].sockfd, (char *)buf.data,
-                          layer->conf.recvBufferSize, 0);
-        //todo: fixme
-#else
         buf.length = recvfrom(layer->serversockfd, buf.data, layer->conf.recvBufferSize, 0, &sender, &sendsize);
         buf.length = recvfrom(layer->serversockfd, buf.data, layer->conf.recvBufferSize, 0, &sender, &sendsize);
-#endif
-
         if (buf.length <= 0) {
         if (buf.length <= 0) {
         } else {
         } else {
             UDPConnection *c = malloc(sizeof(UDPConnection));
             UDPConnection *c = malloc(sizeof(UDPConnection));
-
         	if(!c)
         	if(!c)
         		return UA_STATUSCODE_BADINTERNALERROR;
         		return UA_STATUSCODE_BADINTERNALERROR;
-            c->layer = layer;
             c->from = sender;
             c->from = sender;
             c->fromlen = sendsize;
             c->fromlen = sendsize;
             c->connection.state = UA_CONNECTION_OPENING;
             c->connection.state = UA_CONNECTION_OPENING;
             c->connection.localConf = layer->conf;
             c->connection.localConf = layer->conf;
             c->connection.channel = NULL;
             c->connection.channel = NULL;
-            c->connection.close = (void (*)(void*))closeConnectionUDP;
-            c->connection.write = (void (*)(void*, UA_ByteStringArray))writeCallbackUDP;
-
-
+            c->connection.close = (void (*)(UA_Connection*))closeConnectionUDP;
+            c->connection.write = (UA_StatusCode (*)(UA_Connection*, UA_ByteStringArray))writeCallbackUDP;
+            c->connection.getBuffer = GetMallocedBuffer;
+            c->connection.releaseBuffer = ReleaseMallocedBuffer;
+            c->connection.handle = layer;
             items[j].type = UA_WORKITEMTYPE_BINARYNETWORKMESSAGE;
             items[j].type = UA_WORKITEMTYPE_BINARYNETWORKMESSAGE;
             items[j].work.binaryNetworkMessage.message = buf;
             items[j].work.binaryNetworkMessage.message = buf;
             items[j].work.binaryNetworkMessage.connection = (UA_Connection*)c;
             items[j].work.binaryNetworkMessage.connection = (UA_Connection*)c;
             buf.data = NULL;
             buf.data = NULL;
             j++;
             j++;
         }
         }
-
-
     if(buf.data)
     if(buf.data)
         free(buf.data);
         free(buf.data);
-
     if(j == 0) {
     if(j == 0) {
         free(items);
         free(items);
         *workItems = NULL;
         *workItems = NULL;
@@ -278,14 +213,14 @@ static void ServerNetworkLayerUDP_delete(ServerNetworkLayerUDP *layer) {
 	free(layer);
 	free(layer);
 }
 }
 
 
-UA_ServerNetworkLayer ServerNetworkLayerUDP_new(UA_ConnectionConfig conf, UA_UInt32 port){
+UA_ServerNetworkLayer ServerNetworkLayerUDP_new(UA_ConnectionConfig conf, UA_UInt32 port) {
     ServerNetworkLayerUDP *udplayer = malloc(sizeof(ServerNetworkLayerUDP));
     ServerNetworkLayerUDP *udplayer = malloc(sizeof(ServerNetworkLayerUDP));
 	udplayer->conf = conf;
 	udplayer->conf = conf;
     udplayer->port = port;
     udplayer->port = port;
 
 
     UA_ServerNetworkLayer nl;
     UA_ServerNetworkLayer nl;
     nl.nlHandle = udplayer;
     nl.nlHandle = udplayer;
-    nl.start = (UA_StatusCode (*)(void*))ServerNetworkLayerUDP_start;
+    nl.start = (UA_StatusCode (*)(void*, UA_Logger *logger))ServerNetworkLayerUDP_start;
     nl.getWork = (UA_Int32 (*)(void*, UA_WorkItem**, UA_UInt16)) ServerNetworkLayerUDP_getWork;
     nl.getWork = (UA_Int32 (*)(void*, UA_WorkItem**, UA_UInt16)) ServerNetworkLayerUDP_getWork;
     nl.stop = (UA_Int32 (*)(void*, UA_WorkItem**)) ServerNetworkLayerUDP_stop;
     nl.stop = (UA_Int32 (*)(void*, UA_WorkItem**)) ServerNetworkLayerUDP_stop;
     nl.free = (void (*)(void*))ServerNetworkLayerUDP_delete;
     nl.free = (void (*)(void*))ServerNetworkLayerUDP_delete;

+ 2 - 1
examples/server_simple.c

@@ -68,7 +68,8 @@ int main(int argc, char** argv) {
     UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
     UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
     UA_Server_addNamespace(server, UA_ServerConfig_standard.Application_applicationURI);
     UA_Server_addNamespace(server, UA_ServerConfig_standard.Application_applicationURI);
 
 
-    UA_WorkItem work = {.type = UA_WORKITEMTYPE_METHODCALL, .work.methodCall = {.method = testCallback, .data = NULL} };
+    UA_WorkItem work = {.type = UA_WORKITEMTYPE_METHODCALL,
+                        .work.methodCall = {.method = testCallback, .data = NULL} };
     UA_Server_addRepeatedWorkItem(server, &work, 20000000, NULL); // call every 2 sec
     UA_Server_addRepeatedWorkItem(server, &work, 20000000, NULL); // call every 2 sec
 
 
 	// add a variable node to the adresspace
 	// add a variable node to the adresspace

+ 5 - 4
examples/server_udp.c

@@ -34,13 +34,14 @@ int main(int argc, char** argv) {
     UA_Variant *myIntegerVariant = UA_Variant_new();
     UA_Variant *myIntegerVariant = UA_Variant_new();
     UA_Int32 myInteger = 42;
     UA_Int32 myInteger = 42;
     UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
     UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
-    UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
-    UA_NodeId myIntegerNodeId = UA_NODEID_NULL; /* assign a random free nodeid */
-    UA_NodeId parentNodeId = UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER);
-    UA_NodeId parentReferenceNodeId = UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES);
+    const UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
+    const UA_NodeId myIntegerNodeId = UA_NODEID_STRING(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, myIntegerVariant, myIntegerName,
     UA_Server_addVariableNode(server, myIntegerVariant, myIntegerName,
                               myIntegerNodeId, parentNodeId, parentReferenceNodeId);
                               myIntegerNodeId, parentNodeId, parentReferenceNodeId);
 
 
+
     UA_StatusCode retval = UA_Server_run(server, 1, &running);
     UA_StatusCode retval = UA_Server_run(server, 1, &running);
 	UA_Server_delete(server);
 	UA_Server_delete(server);
 
 

+ 11 - 21
include/ua_client.h

@@ -8,39 +8,29 @@ extern "C" {
 #include "ua_util.h"
 #include "ua_util.h"
 #include "ua_types.h"
 #include "ua_types.h"
 #include "ua_connection.h"
 #include "ua_connection.h"
+#include "ua_log.h"
 #include "ua_types_generated.h"
 #include "ua_types_generated.h"
 
 
-/**
- * The client networklayer can handle only a single connection. The networklayer
- * is only concerned with getting messages to the client and receiving them.
- */
-typedef struct {
-    void *nlHandle;
-
-    UA_StatusCode (*connect)(const UA_String endpointUrl, void **resultHandle);
-    void (*disconnect)(void *handle);
-    void (*destroy)(void *handle);
-    UA_StatusCode (*send)(void *handle, UA_ByteStringArray gather_buf);
-    // the response buffer exists on the heap. the size shall correspond the the connection settings
-    UA_StatusCode (*awaitResponse)(void *handle, UA_ByteString *response, UA_UInt32 timeout);
-} UA_ClientNetworkLayer;
-
 struct UA_Client;
 struct UA_Client;
 typedef struct UA_Client UA_Client;
 typedef struct UA_Client UA_Client;
 
 
+/**
+ * The client networklayer is defined by a single function that fills a UA_Connection struct after
+ * successfully connecting.
+ */
+typedef UA_Connection (*UA_ConnectClientConnection)(char *endpointUrl, UA_Logger *logger);
+
 typedef struct UA_ClientConfig {
 typedef struct UA_ClientConfig {
-    UA_Int32 timeout; //sync resonse timeout
+    UA_Int32 timeout; //sync response timeout
+    UA_ConnectionConfig localConnectionConfig;
 } UA_ClientConfig;
 } UA_ClientConfig;
 
 
 extern const UA_ClientConfig UA_ClientConfig_standard;
 extern const UA_ClientConfig UA_ClientConfig_standard;
-
-UA_Client UA_EXPORT * UA_Client_new(UA_ClientConfig config);
+UA_Client UA_EXPORT * UA_Client_new(UA_ClientConfig config, UA_Logger logger);
 
 
 void UA_Client_delete(UA_Client* client);
 void UA_Client_delete(UA_Client* client);
 
 
-UA_StatusCode UA_EXPORT UA_Client_connect(UA_Client *client, UA_ConnectionConfig conf,
-                                          UA_ClientNetworkLayer networkLayer, char *endpointUrl);
-
+UA_StatusCode UA_EXPORT UA_Client_connect(UA_Client *client, UA_ConnectClientConnection connFunc, char *endpointUrl);
 UA_StatusCode UA_EXPORT UA_Client_disconnect(UA_Client *client);
 UA_StatusCode UA_EXPORT UA_Client_disconnect(UA_Client *client);
 
 
 /* Attribute Service Set */
 /* Attribute Service Set */

+ 27 - 11
include/ua_connection.h

@@ -36,9 +36,9 @@ typedef struct UA_ByteStringArray {
 } UA_ByteStringArray;
 } UA_ByteStringArray;
 
 
 typedef enum UA_ConnectionState {
 typedef enum UA_ConnectionState {
-    UA_CONNECTION_OPENING, ///< The port is open, but we haven't received a HEL
-    UA_CONNECTION_ESTABLISHED, ///< The port is open and the connection configured
-    UA_CONNECTION_CLOSING, ///< The port 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_CONNECTION_CLOSED, ///< The socket has been closed and the connection will be deleted
 } UA_ConnectionState;
 } UA_ConnectionState;
 
 
 typedef struct UA_ConnectionConfig {
 typedef struct UA_ConnectionConfig {
@@ -55,18 +55,34 @@ extern const UA_EXPORT UA_ConnectionConfig UA_ConnectionConfig_standard;
 struct UA_SecureChannel;
 struct UA_SecureChannel;
 typedef struct UA_SecureChannel UA_SecureChannel;
 typedef struct UA_SecureChannel UA_SecureChannel;
 
 
-typedef struct UA_Connection {
-    UA_ConnectionState  state;
+struct UA_Connection;
+typedef struct UA_Connection UA_Connection;
+
+/**
+ * The connection to a single client (or server). The connection is defined independent of the
+ * underlying network layer implementation. This allows a plugging-in custom implementations (e.g.
+ * an embedded TCP stack)
+ */
+struct UA_Connection {
+    UA_ConnectionState state;
     UA_ConnectionConfig localConf;
     UA_ConnectionConfig localConf;
     UA_ConnectionConfig remoteConf;
     UA_ConnectionConfig remoteConf;
-    UA_SecureChannel   *channel;
-    void (*write)(void *connection, UA_ByteStringArray buf);
-    void (*close)(void *connection);
-    UA_ByteString incompleteMessage;
-} UA_Connection;
+    UA_SecureChannel *channel; ///> The securechannel that is attached to this connection (or null)
+    UA_Int32 sockfd; ///> Most connectivity solutions run on sockets. Having the socket id here simplifies the design.
+    void *handle; ///> A pointer to the networklayer
+    UA_ByteString incompleteMessage; ///> Half-received messages (tcp is a streaming protocol) get stored here
+    UA_StatusCode (*getBuffer)(UA_Connection *connection, UA_ByteString *buf, size_t minSize); ///> Attach the data array to the buffer. Fails if minSize is larger than remoteConf allows
+    void (*releaseBuffer)(UA_Connection *connection, UA_ByteString *buf); ///> Release the buffer
+    UA_StatusCode (*write)(UA_Connection *connection, UA_ByteStringArray buf); ///> The bytestrings cannot be reused after sending!
+    UA_StatusCode (*recv)(UA_Connection *connection, UA_ByteString *response, UA_UInt32 timeout); // timeout in milliseconds
+    void (*close)(UA_Connection *connection);
+};
+
+void UA_EXPORT UA_Connection_init(UA_Connection *connection);
+void UA_EXPORT UA_Connection_deleteMembers(UA_Connection *connection);
 
 
 void UA_EXPORT UA_Connection_detachSecureChannel(UA_Connection *connection);
 void UA_EXPORT UA_Connection_detachSecureChannel(UA_Connection *connection);
-// void UA_Connection_attachSecureChannel(UA_Connection *connection);
+void UA_EXPORT UA_Connection_attachSecureChannel(UA_Connection *connection, UA_SecureChannel *channel);
 
 
 /** Returns a string of complete message (the length entry is decoded for that).
 /** Returns a string of complete message (the length entry is decoded for that).
     If the received message is incomplete, it is retained in the connection. */
     If the received message is incomplete, it is retained in the connection. */

+ 2 - 1
include/ua_log.h

@@ -35,10 +35,11 @@ extern "C" {
 typedef enum UA_LoggerCategory {
 typedef enum UA_LoggerCategory {
     UA_LOGGERCATEGORY_COMMUNICATION,
     UA_LOGGERCATEGORY_COMMUNICATION,
     UA_LOGGERCATEGORY_SERVER,
     UA_LOGGERCATEGORY_SERVER,
+    UA_LOGGERCATEGORY_CLIENT,
     UA_LOGGERCATEGORY_USERLAND
     UA_LOGGERCATEGORY_USERLAND
 } UA_LoggerCategory;
 } UA_LoggerCategory;
 
 
-extern UA_EXPORT const char *UA_LoggerCategoryNames[3];
+extern UA_EXPORT const char *UA_LoggerCategoryNames[4];
 
 
 typedef struct UA_Logger {
 typedef struct UA_Logger {
     void (*log_trace)(UA_LoggerCategory category, const char *msg, ...);
     void (*log_trace)(UA_LoggerCategory category, const char *msg, ...);

+ 3 - 0
include/ua_server.h

@@ -54,6 +54,7 @@ void UA_EXPORT UA_Server_delete(UA_Server *server);
 
 
 /** Sets the logger used by the server */
 /** Sets the logger used by the server */
 void UA_EXPORT UA_Server_setLogger(UA_Server *server, UA_Logger logger);
 void UA_EXPORT UA_Server_setLogger(UA_Server *server, UA_Logger logger);
+UA_Logger UA_EXPORT * UA_Server_getLogger(UA_Server *server);
 
 
 /**
 /**
  * Runs the main loop of the server. In each iteration, this calls into the
  * Runs the main loop of the server. In each iteration, this calls into the
@@ -109,11 +110,13 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, UA_DataSource dataSource,
 typedef struct UA_WorkItem {
 typedef struct UA_WorkItem {
     enum {
     enum {
         UA_WORKITEMTYPE_NOTHING,
         UA_WORKITEMTYPE_NOTHING,
+        UA_WORKITEMTYPE_CLOSECONNECTION,
         UA_WORKITEMTYPE_BINARYNETWORKMESSAGE,
         UA_WORKITEMTYPE_BINARYNETWORKMESSAGE,
         UA_WORKITEMTYPE_METHODCALL,
         UA_WORKITEMTYPE_METHODCALL,
         UA_WORKITEMTYPE_DELAYEDMETHODCALL,
         UA_WORKITEMTYPE_DELAYEDMETHODCALL,
     } type;
     } type;
     union {
     union {
+        UA_Connection *closeConnection;
         struct {
         struct {
             UA_Connection *connection;
             UA_Connection *connection;
             UA_ByteString message;
             UA_ByteString message;

+ 1 - 0
include/ua_types.h

@@ -371,6 +371,7 @@ UA_Boolean UA_EXPORT UA_Guid_equal(const UA_Guid *g1, const UA_Guid *g2);
 UA_Guid UA_EXPORT UA_Guid_random(UA_UInt32 *seed);
 UA_Guid UA_EXPORT UA_Guid_random(UA_UInt32 *seed);
 
 
 /* ByteString */
 /* ByteString */
+#define UA_BYTESTRING_NULL (UA_ByteString) {-1, (UA_Byte*)0 }
 #define UA_ByteString_equal(string1, string2) \
 #define UA_ByteString_equal(string1, string2) \
     UA_String_equal((const UA_String*) string1, (const UA_String*)string2)
     UA_String_equal((const UA_String*) string1, (const UA_String*)string2)
 
 

+ 32 - 33
src/client/ua_client.c

@@ -6,9 +6,8 @@
 
 
 struct UA_Client {
 struct UA_Client {
     /* Connection */
     /* Connection */
-    UA_ClientNetworkLayer networkLayer;
-    UA_String endpointUrl;
     UA_Connection connection;
     UA_Connection connection;
+    UA_String endpointUrl;
 
 
     UA_UInt32 sequenceNumber;
     UA_UInt32 sequenceNumber;
     UA_UInt32 requestId;
     UA_UInt32 requestId;
@@ -25,19 +24,22 @@ struct UA_Client {
     UA_NodeId authenticationToken;
     UA_NodeId authenticationToken;
 
 
     /* Config */
     /* Config */
+    UA_Logger logger;
     UA_ClientConfig config;
     UA_ClientConfig config;
 };
 };
 
 
-const UA_ClientConfig UA_ClientConfig_standard = { 500 };
+const UA_ClientConfig UA_ClientConfig_standard =
+    { 5 /* ms receive timout */, {.protocolVersion = 0, .sendBufferSize = 65536, .recvBufferSize  = 65536,
+                                  .maxMessageSize = 65536, .maxChunkCount = 1}};
 
 
-UA_Client * UA_Client_new(UA_ClientConfig config) {
+UA_Client * UA_Client_new(UA_ClientConfig config, UA_Logger logger) {
     UA_Client *client = UA_malloc(sizeof(UA_Client));
     UA_Client *client = UA_malloc(sizeof(UA_Client));
     if(!client)
     if(!client)
         return UA_NULL;
         return UA_NULL;
     client->config = config;
     client->config = config;
+    client->logger = logger;
     UA_String_init(&client->endpointUrl);
     UA_String_init(&client->endpointUrl);
-    client->connection.state = UA_CONNECTION_OPENING;
-    UA_ByteString_init(&client->connection.incompleteMessage);
+    UA_Connection_init(&client->connection);
 
 
     client->sequenceNumber = 0;
     client->sequenceNumber = 0;
     client->requestId = 0;
     client->requestId = 0;
@@ -53,9 +55,9 @@ UA_Client * UA_Client_new(UA_ClientConfig config) {
 }
 }
 
 
 void UA_Client_delete(UA_Client* client){
 void UA_Client_delete(UA_Client* client){
-    client->networkLayer.destroy(client->networkLayer.nlHandle);
+    UA_Connection_deleteMembers(&client->connection);
     UA_String_deleteMembers(&client->endpointUrl);
     UA_String_deleteMembers(&client->endpointUrl);
-    // client->connection
+    UA_Connection_deleteMembers(&client->connection);
 
 
     /* Secure Channel */
     /* Secure Channel */
     UA_ByteString_deleteMembers(&client->clientNonce);
     UA_ByteString_deleteMembers(&client->clientNonce);
@@ -64,7 +66,6 @@ void UA_Client_delete(UA_Client* client){
     free(client);
     free(client);
 }
 }
 
 
-// The tcp connection is established. Now do the handshake
 static UA_StatusCode HelAckHandshake(UA_Client *c) {
 static UA_StatusCode HelAckHandshake(UA_Client *c) {
     UA_TcpMessageHeader messageHeader;
     UA_TcpMessageHeader messageHeader;
     messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_HELF;
     messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_HELF;
@@ -91,15 +92,19 @@ static UA_StatusCode HelAckHandshake(UA_Client *c) {
     UA_TcpHelloMessage_deleteMembers(&hello);
     UA_TcpHelloMessage_deleteMembers(&hello);
 
 
     UA_ByteStringArray buf = {.stringsSize = 1, .strings = &message};
     UA_ByteStringArray buf = {.stringsSize = 1, .strings = &message};
-    UA_StatusCode retval = c->networkLayer.send(c->networkLayer.nlHandle, buf);
+    UA_StatusCode retval = c->connection.write(&c->connection, buf);
     if(retval)
     if(retval)
         return retval;
         return retval;
 
 
-    UA_Byte replybuf[1024];
-    UA_ByteString reply = {.data = replybuf, .length = 1024};
-    retval = c->networkLayer.awaitResponse(c->networkLayer.nlHandle, &reply, c->config.timeout * 1000);
-    if (retval)
-        return retval;
+    UA_ByteString reply;
+    do {
+        UA_ByteString_newMembers(&reply, 1024);
+        retval = c->connection.recv(&c->connection, &reply, c->config.timeout);
+        if(retval != UA_STATUSCODE_GOOD) {
+            UA_ByteString_deleteMembers(&reply);
+            return retval;
+        }
+    } while(reply.length < 0);
 
 
     offset = 0;
     offset = 0;
     UA_TcpMessageHeader_decodeBinary(&reply, &offset, &messageHeader);
     UA_TcpMessageHeader_decodeBinary(&reply, &offset, &messageHeader);
@@ -109,6 +114,7 @@ static UA_StatusCode HelAckHandshake(UA_Client *c) {
         UA_TcpAcknowledgeMessage_deleteMembers(&ackMessage);
         UA_TcpAcknowledgeMessage_deleteMembers(&ackMessage);
         return retval;
         return retval;
     }
     }
+    UA_ByteString_deleteMembers(&reply);
     conn->remoteConf.maxChunkCount = ackMessage.maxChunkCount;
     conn->remoteConf.maxChunkCount = ackMessage.maxChunkCount;
     conn->remoteConf.maxMessageSize = ackMessage.maxMessageSize;
     conn->remoteConf.maxMessageSize = ackMessage.maxMessageSize;
     conn->remoteConf.protocolVersion = ackMessage.protocolVersion;
     conn->remoteConf.protocolVersion = ackMessage.protocolVersion;
@@ -173,20 +179,19 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client) {
     UA_OpenSecureChannelRequest_deleteMembers(&opnSecRq);
     UA_OpenSecureChannelRequest_deleteMembers(&opnSecRq);
 
 
     UA_ByteStringArray buf = {.stringsSize = 1, .strings = &message};
     UA_ByteStringArray buf = {.stringsSize = 1, .strings = &message};
-    UA_StatusCode retval = client->networkLayer.send(client->networkLayer.nlHandle, buf);
+    UA_StatusCode retval = client->connection.write(&client->connection, buf);
     if(retval)
     if(retval)
         return retval;
         return retval;
 
 
     // parse the response
     // parse the response
     UA_ByteString reply;
     UA_ByteString reply;
-    UA_ByteString_newMembers(&reply, client->connection.localConf.recvBufferSize);
     do {
     do {
-        retval = client->networkLayer.awaitResponse(client->networkLayer.nlHandle, &reply, client->config.timeout * 1000);
+        UA_ByteString_newMembers(&reply, client->connection.localConf.recvBufferSize);
+        retval = client->connection.recv(&client->connection, &reply, client->config.timeout);
         if(retval != UA_STATUSCODE_GOOD) {
         if(retval != UA_STATUSCODE_GOOD) {
             UA_ByteString_deleteMembers(&reply);
             UA_ByteString_deleteMembers(&reply);
             return retval;
             return retval;
         }
         }
-        reply = UA_Connection_completeMessages(&client->connection, reply);
     } while(reply.length < 0);
     } while(reply.length < 0);
 
 
     offset = 0;
     offset = 0;
@@ -269,7 +274,7 @@ static void sendReceiveRequest(UA_RequestHeader *request, const UA_DataType *req
     retval |= UA_encodeBinary(request, requestType, &message, &offset);
     retval |= UA_encodeBinary(request, requestType, &message, &offset);
 
 
     UA_ByteStringArray buf = {.stringsSize = 1, .strings = &message};
     UA_ByteStringArray buf = {.stringsSize = 1, .strings = &message};
-    retval = client->networkLayer.send(client->networkLayer.nlHandle, buf);
+    retval = client->connection.write(&client->connection, buf);
     UA_ByteString_deleteMembers(&message);
     UA_ByteString_deleteMembers(&message);
 
 
     //TODO: rework to get return value
     //TODO: rework to get return value
@@ -286,13 +291,12 @@ static void sendReceiveRequest(UA_RequestHeader *request, const UA_DataType *req
     UA_ByteString reply;
     UA_ByteString reply;
     do {
     do {
         UA_ByteString_newMembers(&reply, client->connection.localConf.recvBufferSize);
         UA_ByteString_newMembers(&reply, client->connection.localConf.recvBufferSize);
-        retval = client->networkLayer.awaitResponse(client->networkLayer.nlHandle, &reply, client->config.timeout * 1000);
+        retval = client->connection.recv(&client->connection, &reply, client->config.timeout);
         if(retval != UA_STATUSCODE_GOOD) {
         if(retval != UA_STATUSCODE_GOOD) {
             UA_ByteString_deleteMembers(&reply);
             UA_ByteString_deleteMembers(&reply);
             respHeader->serviceResult = retval;
             respHeader->serviceResult = retval;
             return;
             return;
         }
         }
-        reply = UA_Connection_completeMessages(&client->connection, reply);
     } while(reply.length < 0);
     } while(reply.length < 0);
 
 
     offset = 0;
     offset = 0;
@@ -408,21 +412,17 @@ static UA_StatusCode CloseSecureChannel(UA_Client *client) {
 /* User-Facing Functions */
 /* User-Facing Functions */
 /*************************/
 /*************************/
 
 
+UA_StatusCode UA_Client_connect(UA_Client *client, UA_ConnectClientConnection connectFunc, char *endpointUrl) {
+    client->connection = connectFunc(endpointUrl, &client->logger);
+    if(client->connection.state != UA_CONNECTION_OPENING)
+        return UA_STATUSCODE_BADCONNECTIONCLOSED;
 
 
-UA_StatusCode UA_Client_connect(UA_Client *client, UA_ConnectionConfig conf,
-                                UA_ClientNetworkLayer networkLayer, char *endpointUrl)
-{
     client->endpointUrl = UA_STRING_ALLOC(endpointUrl);
     client->endpointUrl = UA_STRING_ALLOC(endpointUrl);
     if(client->endpointUrl.length < 0)
     if(client->endpointUrl.length < 0)
         return UA_STATUSCODE_BADOUTOFMEMORY;
         return UA_STATUSCODE_BADOUTOFMEMORY;
 
 
-    client->networkLayer = networkLayer;
-    client->connection.localConf = conf;
-    UA_StatusCode retval = networkLayer.connect(client->endpointUrl, client->networkLayer.nlHandle);
-    if(retval != UA_STATUSCODE_GOOD)
-        return retval;
-
-    retval = HelAckHandshake(client);
+    client->connection.localConf = client->config.localConnectionConfig;
+    UA_StatusCode retval = HelAckHandshake(client);
     if(retval == UA_STATUSCODE_GOOD)
     if(retval == UA_STATUSCODE_GOOD)
         retval = SecureChannelHandshake(client);
         retval = SecureChannelHandshake(client);
     if(retval == UA_STATUSCODE_GOOD)
     if(retval == UA_STATUSCODE_GOOD)
@@ -432,7 +432,6 @@ UA_StatusCode UA_Client_connect(UA_Client *client, UA_ConnectionConfig conf,
     return retval;
     return retval;
 }
 }
 
 
-
 UA_StatusCode UA_Client_disconnect(UA_Client *client) {
 UA_StatusCode UA_Client_disconnect(UA_Client *client) {
     UA_StatusCode retval;
     UA_StatusCode retval;
     retval = CloseSession(client);
     retval = CloseSession(client);

+ 53 - 7
src/server/ua_server.c

@@ -6,7 +6,6 @@
 #include "ua_services.h"
 #include "ua_services.h"
 #include "ua_nodeids.h"
 #include "ua_nodeids.h"
 
 
-const char *UA_LoggerCategoryNames[3] = {"communication", "server", "userland"};
 
 
 const UA_ServerConfig UA_ServerConfig_standard = {
 const UA_ServerConfig UA_ServerConfig_standard = {
         UA_TRUE,
         UA_TRUE,
@@ -37,6 +36,10 @@ static void UA_ExternalNamespace_deleteMembers(UA_ExternalNamespace *ens) {
 /* Configuration */
 /* Configuration */
 /*****************/
 /*****************/
 
 
+UA_Logger * UA_Server_getLogger(UA_Server *server) {
+    return &server->logger;
+}
+
 void UA_Server_addNetworkLayer(UA_Server *server, UA_ServerNetworkLayer networkLayer) {
 void UA_Server_addNetworkLayer(UA_Server *server, UA_ServerNetworkLayer networkLayer) {
     UA_ServerNetworkLayer *newlayers =
     UA_ServerNetworkLayer *newlayers =
         UA_realloc(server->nls, sizeof(UA_ServerNetworkLayer)*(server->nlsSize+1));
         UA_realloc(server->nls, sizeof(UA_ServerNetworkLayer)*(server->nlsSize+1));
@@ -117,15 +120,16 @@ static UA_StatusCode readStatus(void *handle, UA_Boolean sourceTimeStamp, UA_Dat
     status->startTime   = ((const UA_Server*)handle)->startTime;
     status->startTime   = ((const UA_Server*)handle)->startTime;
     status->currentTime = UA_DateTime_now();
     status->currentTime = UA_DateTime_now();
     status->state       = UA_SERVERSTATE_RUNNING;
     status->state       = UA_SERVERSTATE_RUNNING;
-    status->buildInfo.productUri = UA_STRING_ALLOC("http://www.open62541.org");
-    status->buildInfo.manufacturerName = UA_STRING_ALLOC("open62541");
-    status->buildInfo.productName = UA_STRING_ALLOC("open62541 OPC UA Server");
+    status->buildInfo.productUri = UA_STRING("http://www.open62541.org");
+    status->buildInfo.manufacturerName = UA_STRING("open62541");
+    status->buildInfo.productName = UA_STRING("open62541 OPC UA Server");
 #define STRINGIFY(x) #x //some magic
 #define STRINGIFY(x) #x //some magic
 #define TOSTRING(x) STRINGIFY(x) //some magic
 #define TOSTRING(x) STRINGIFY(x) //some magic
-    status->buildInfo.softwareVersion = UA_STRING_ALLOC(TOSTRING(OPEN62541_VERSION_MAJOR) "." TOSTRING(OPEN62541_VERSION_MINOR) "." TOSTRING(OPEN62541_VERSION_PATCH));
-    status->buildInfo.buildNumber = UA_STRING_ALLOC("0");
+    status->buildInfo.softwareVersion = UA_STRING(TOSTRING(OPEN62541_VERSION_MAJOR) "." TOSTRING(OPEN62541_VERSION_MINOR) "." TOSTRING(OPEN62541_VERSION_PATCH));
+    status->buildInfo.buildNumber = UA_STRING("0");
     status->buildInfo.buildDate = ((const UA_Server*)handle)->buildDate;
     status->buildInfo.buildDate = ((const UA_Server*)handle)->buildDate;
     status->secondsTillShutdown = 0;
     status->secondsTillShutdown = 0;
+
     value->value.type = &UA_TYPES[UA_TYPES_SERVERSTATUSDATATYPE];
     value->value.type = &UA_TYPES[UA_TYPES_SERVERSTATUSDATATYPE];
 	value->value.arrayLength = -1;
 	value->value.arrayLength = -1;
     value->value.data = status;
     value->value.data = status;
@@ -140,6 +144,9 @@ static UA_StatusCode readStatus(void *handle, UA_Boolean sourceTimeStamp, UA_Dat
 }
 }
 
 
 static void releaseStatus(void *handle, UA_DataValue *value) {
 static void releaseStatus(void *handle, UA_DataValue *value) {
+    UA_free(value->value.data);
+    value->value.data = UA_NULL;
+    value->hasValue = UA_FALSE;
     UA_DataValue_deleteMembers(value);
     UA_DataValue_deleteMembers(value);
 }
 }
 
 
@@ -312,7 +319,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
 
 
         server->endpointDescriptions = endpoint;
         server->endpointDescriptions = endpoint;
         server->endpointDescriptionsSize = 1;
         server->endpointDescriptionsSize = 1;
-    }
+    } 
 
 
 #define MAXCHANNELCOUNT 100
 #define MAXCHANNELCOUNT 100
 #define STARTCHANNELID 1
 #define STARTCHANNELID 1
@@ -328,6 +335,45 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
 
 
     server->nodestore = UA_NodeStore_new();
     server->nodestore = UA_NodeStore_new();
 
 
+    /**********************/
+    /* Server Information */
+    /**********************/
+
+    server->startTime = UA_DateTime_now();
+    static struct tm ct;
+    ct.tm_year = (__DATE__[7] - '0') * 1000 +  (__DATE__[8] - '0') * 100 + (__DATE__[9] - '0') * 10 + (__DATE__[10] - '0')- 1900;
+    if ((__DATE__[0]=='J') && (__DATE__[1]=='a') && (__DATE__[2]=='n')) ct.tm_mon = 1-1;
+    else if ((__DATE__[0]=='F') && (__DATE__[1]=='e') && (__DATE__[2]=='b')) ct.tm_mon = 2-1;
+    else if ((__DATE__[0]=='M') && (__DATE__[1]=='a') && (__DATE__[2]=='r')) ct.tm_mon = 3-1;
+    else if ((__DATE__[0]=='A') && (__DATE__[1]=='p') && (__DATE__[2]=='r')) ct.tm_mon = 4-1;
+    else if ((__DATE__[0]=='M') && (__DATE__[1]=='a') && (__DATE__[2]=='y')) ct.tm_mon = 5-1;
+    else if ((__DATE__[0]=='J') && (__DATE__[1]=='u') && (__DATE__[2]=='n')) ct.tm_mon = 6-1;
+    else if ((__DATE__[0]=='J') && (__DATE__[1]=='u') && (__DATE__[2]=='l')) ct.tm_mon = 7-1;
+    else if ((__DATE__[0]=='A') && (__DATE__[1]=='u') && (__DATE__[2]=='g')) ct.tm_mon = 8-1;
+    else if ((__DATE__[0]=='S') && (__DATE__[1]=='e') && (__DATE__[2]=='p')) ct.tm_mon = 9-1;
+    else if ((__DATE__[0]=='O') && (__DATE__[1]=='c') && (__DATE__[2]=='t')) ct.tm_mon = 10-1;
+    else if ((__DATE__[0]=='N') && (__DATE__[1]=='o') && (__DATE__[2]=='v')) ct.tm_mon = 11-1;
+    else if ((__DATE__[0]=='D') && (__DATE__[1]=='e') && (__DATE__[2]=='c')) ct.tm_mon = 12-1;
+
+    // special case to handle __DATE__ not inserting leading zero on day of month
+    // if Day of month is less than 10 - it inserts a blank character
+    // this results in a negative number for tm_mday
+
+    if(__DATE__[4] == ' ')
+        ct.tm_mday =  __DATE__[5]-'0';
+    else
+        ct.tm_mday = (__DATE__[4]-'0')*10 + (__DATE__[5]-'0');
+    ct.tm_hour = ((__TIME__[0] - '0') * 10 + __TIME__[1] - '0');
+    ct.tm_min = ((__TIME__[3] - '0') * 10 + __TIME__[4] - '0');
+    ct.tm_sec = ((__TIME__[6] - '0') * 10 + __TIME__[7] - '0');
+    ct.tm_isdst = -1;  // information is not available.
+
+    //FIXME: next 3 lines are copy-pasted from ua_types.c
+#define UNIX_EPOCH_BIAS_SEC 11644473600LL // Number of seconds from 1 Jan. 1601 00:00 to 1 Jan 1970 00:00 UTC
+#define HUNDRED_NANOSEC_PER_USEC 10LL
+#define HUNDRED_NANOSEC_PER_SEC (HUNDRED_NANOSEC_PER_USEC * 1000000LL)
+    server->buildDate = (mktime(&ct) + UNIX_EPOCH_BIAS_SEC) * HUNDRED_NANOSEC_PER_SEC;
+
     /**************/
     /**************/
     /* References */
     /* References */
     /**************/
     /**************/

+ 15 - 58
src/server/ua_server_binary.c

@@ -127,22 +127,10 @@ static void processOPN(UA_Connection *connection, UA_Server *server, const UA_By
 
 
 static void init_response_header(const UA_RequestHeader *p, UA_ResponseHeader *r) {
 static void init_response_header(const UA_RequestHeader *p, UA_ResponseHeader *r) {
     r->requestHandle = p->requestHandle;
     r->requestHandle = p->requestHandle;
-    r->serviceResult = UA_STATUSCODE_GOOD;
     r->stringTableSize = 0;
     r->stringTableSize = 0;
     r->timestamp = UA_DateTime_now();
     r->timestamp = UA_DateTime_now();
 }
 }
 
 
-// if the message is small enough, we allocate it on the stack and save a malloc
-#define ALLOC_MESSAGE(MESSAGE, SIZE) do {                               \
-        UA_UInt32 messageSize = SIZE;                                   \
-        if(messageSize <= MAX_STACK_MESSAGE) {                          \
-            messageOnStack = UA_TRUE;                                   \
-            *MESSAGE = (UA_ByteString){.length = messageSize,           \
-                                       .data = UA_alloca(messageSize)}; \
-                        } else                                          \
-            UA_ByteString_newMembers(MESSAGE, messageSize);             \
-    } while(0)
-
 #define INVOKE_SERVICE(TYPE) do {                                       \
 #define INVOKE_SERVICE(TYPE) do {                                       \
         UA_##TYPE##Request p;                                           \
         UA_##TYPE##Request p;                                           \
         UA_##TYPE##Response r;                                          \
         UA_##TYPE##Response r;                                          \
@@ -158,7 +146,7 @@ static void init_response_header(const UA_RequestHeader *p, UA_ResponseHeader *r
             r.responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID; \
             r.responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID; \
         else                                                            \
         else                                                            \
             Service_##TYPE(server, clientSession, &p, &r);              \
             Service_##TYPE(server, clientSession, &p, &r);              \
-        ALLOC_MESSAGE(message, UA_##TYPE##Response_calcSizeBinary(&r)); \
+        connection->getBuffer(connection, message, UA_##TYPE##Response_calcSizeBinary(&r)); \
         UA_##TYPE##Response_encodeBinary(&r, message, &sendOffset);     \
         UA_##TYPE##Response_encodeBinary(&r, message, &sendOffset);     \
         UA_##TYPE##Request_deleteMembers(&p);                           \
         UA_##TYPE##Request_deleteMembers(&p);                           \
         UA_##TYPE##Response_deleteMembers(&r);                          \
         UA_##TYPE##Response_deleteMembers(&r);                          \
@@ -173,11 +161,13 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
         return;
         return;
 
 
     UA_SecureChannel *clientChannel = connection->channel;
     UA_SecureChannel *clientChannel = connection->channel;
+#ifdef EXTENSION_STATELESS
     UA_SecureChannel anonymousChannel;
     UA_SecureChannel anonymousChannel;
     if(!clientChannel) {
     if(!clientChannel) {
         UA_SecureChannel_init(&anonymousChannel);
         UA_SecureChannel_init(&anonymousChannel);
         clientChannel = &anonymousChannel;
         clientChannel = &anonymousChannel;
     }
     }
+#endif
 
 
     // 2) Read the security header
     // 2) Read the security header
     UA_UInt32 tokenId;
     UA_UInt32 tokenId;
@@ -194,7 +184,7 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
 
 
     UA_Session *clientSession = UA_NULL;
     UA_Session *clientSession = UA_NULL;
 #ifdef EXTENSION_STATELESS
 #ifdef EXTENSION_STATELESS
-    if(clientChannel->session == UA_NULL && secureChannelId == 0)
+    if(clientChannel == &anonymousChannel)
         clientSession = &anonymousSession;
         clientSession = &anonymousSession;
 #endif
 #endif
 
 
@@ -213,21 +203,8 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
     UA_UInt32 responseType;
     UA_UInt32 responseType;
     UA_ByteString *header = &responseBufs[0];
     UA_ByteString *header = &responseBufs[0];
     UA_ByteString *message = &responseBufs[1];
     UA_ByteString *message = &responseBufs[1];
-    UA_Boolean messageOnStack = UA_FALSE;
     size_t sendOffset = 0;
     size_t sendOffset = 0;
 
 
-#ifdef EXTENSION_STATELESS
-    switch(requestType.identifier.numeric - UA_ENCODINGOFFSET_BINARY) {
-    case UA_NS0ID_READREQUEST:
-    case UA_NS0ID_WRITEREQUEST:
-    case UA_NS0ID_BROWSEREQUEST:
-        break;
-    default:
-        if(clientSession != &anonymousSession)
-            retval = UA_STATUSCODE_BADNOTCONNECTED;
-    }
-#endif
-
     //subtract UA_ENCODINGOFFSET_BINARY for binary encoding, if retval is set, this forces the default path
     //subtract UA_ENCODINGOFFSET_BINARY for binary encoding, if retval is set, this forces the default path
     switch(requestType.identifier.numeric - UA_ENCODINGOFFSET_BINARY + retval) {
     switch(requestType.identifier.numeric - UA_ENCODINGOFFSET_BINARY + retval) {
     case UA_NS0ID_GETENDPOINTSREQUEST: {
     case UA_NS0ID_GETENDPOINTSREQUEST: {
@@ -238,7 +215,7 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
         UA_GetEndpointsResponse_init(&r);
         UA_GetEndpointsResponse_init(&r);
         init_response_header(&p.requestHeader, &r.responseHeader);
         init_response_header(&p.requestHeader, &r.responseHeader);
         Service_GetEndpoints(server, &p, &r);
         Service_GetEndpoints(server, &p, &r);
-        ALLOC_MESSAGE(message, UA_GetEndpointsResponse_calcSizeBinary(&r));
+        connection->getBuffer(connection, message, UA_GetEndpointsResponse_calcSizeBinary(&r));
         UA_GetEndpointsResponse_encodeBinary(&r, message, &sendOffset);
         UA_GetEndpointsResponse_encodeBinary(&r, message, &sendOffset);
         UA_GetEndpointsRequest_deleteMembers(&p);
         UA_GetEndpointsRequest_deleteMembers(&p);
         UA_GetEndpointsResponse_deleteMembers(&r);
         UA_GetEndpointsResponse_deleteMembers(&r);
@@ -254,7 +231,7 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
         UA_FindServersResponse_init(&r);
         UA_FindServersResponse_init(&r);
         init_response_header(&p.requestHeader, &r.responseHeader);
         init_response_header(&p.requestHeader, &r.responseHeader);
         Service_FindServers(server, &p, &r);
         Service_FindServers(server, &p, &r);
-        ALLOC_MESSAGE(message, UA_FindServersResponse_calcSizeBinary(&r));
+        connection->getBuffer(connection, message, UA_FindServersResponse_calcSizeBinary(&r));
         UA_FindServersResponse_encodeBinary(&r, message, &sendOffset);
         UA_FindServersResponse_encodeBinary(&r, message, &sendOffset);
         UA_FindServersRequest_deleteMembers(&p);
         UA_FindServersRequest_deleteMembers(&p);
         UA_FindServersResponse_deleteMembers(&r);
         UA_FindServersResponse_deleteMembers(&r);
@@ -270,7 +247,7 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
         UA_CreateSessionResponse_init(&r);
         UA_CreateSessionResponse_init(&r);
         init_response_header(&p.requestHeader, &r.responseHeader);
         init_response_header(&p.requestHeader, &r.responseHeader);
         Service_CreateSession(server, clientChannel, &p, &r);
         Service_CreateSession(server, clientChannel, &p, &r);
-        ALLOC_MESSAGE(message, UA_CreateSessionResponse_calcSizeBinary(&r));
+        connection->getBuffer(connection, message, UA_CreateSessionResponse_calcSizeBinary(&r));
         UA_CreateSessionResponse_encodeBinary(&r, message, &sendOffset);
         UA_CreateSessionResponse_encodeBinary(&r, message, &sendOffset);
         UA_CreateSessionRequest_deleteMembers(&p);
         UA_CreateSessionRequest_deleteMembers(&p);
         UA_CreateSessionResponse_deleteMembers(&r);
         UA_CreateSessionResponse_deleteMembers(&r);
@@ -286,7 +263,7 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
         UA_ActivateSessionResponse_init(&r);
         UA_ActivateSessionResponse_init(&r);
         init_response_header(&p.requestHeader, &r.responseHeader);
         init_response_header(&p.requestHeader, &r.responseHeader);
         Service_ActivateSession(server, clientChannel, &p, &r);
         Service_ActivateSession(server, clientChannel, &p, &r);
-        ALLOC_MESSAGE(message, UA_ActivateSessionResponse_calcSizeBinary(&r));
+        connection->getBuffer(connection, message, UA_ActivateSessionResponse_calcSizeBinary(&r));
         UA_ActivateSessionResponse_encodeBinary(&r, message, &sendOffset);
         UA_ActivateSessionResponse_encodeBinary(&r, message, &sendOffset);
         UA_ActivateSessionRequest_deleteMembers(&p);
         UA_ActivateSessionRequest_deleteMembers(&p);
         UA_ActivateSessionResponse_deleteMembers(&r);
         UA_ActivateSessionResponse_deleteMembers(&r);
@@ -297,46 +274,36 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
     case UA_NS0ID_CLOSESESSIONREQUEST:
     case UA_NS0ID_CLOSESESSIONREQUEST:
         INVOKE_SERVICE(CloseSession);
         INVOKE_SERVICE(CloseSession);
         break;
         break;
-
     case UA_NS0ID_READREQUEST:
     case UA_NS0ID_READREQUEST:
         INVOKE_SERVICE(Read);
         INVOKE_SERVICE(Read);
         break;
         break;
-
     case UA_NS0ID_WRITEREQUEST:
     case UA_NS0ID_WRITEREQUEST:
         INVOKE_SERVICE(Write);
         INVOKE_SERVICE(Write);
         break;
         break;
-
     case UA_NS0ID_BROWSEREQUEST:
     case UA_NS0ID_BROWSEREQUEST:
         INVOKE_SERVICE(Browse);
         INVOKE_SERVICE(Browse);
         break;
         break;
-
     case UA_NS0ID_BROWSENEXTREQUEST:
     case UA_NS0ID_BROWSENEXTREQUEST:
         INVOKE_SERVICE(BrowseNext);
         INVOKE_SERVICE(BrowseNext);
         break;
         break;
-
     case UA_NS0ID_ADDREFERENCESREQUEST:
     case UA_NS0ID_ADDREFERENCESREQUEST:
         INVOKE_SERVICE(AddReferences);
         INVOKE_SERVICE(AddReferences);
         break;
         break;
-
     case UA_NS0ID_REGISTERNODESREQUEST:
     case UA_NS0ID_REGISTERNODESREQUEST:
         INVOKE_SERVICE(RegisterNodes);
         INVOKE_SERVICE(RegisterNodes);
         break;
         break;
-
     case UA_NS0ID_UNREGISTERNODESREQUEST:
     case UA_NS0ID_UNREGISTERNODESREQUEST:
         INVOKE_SERVICE(UnregisterNodes);
         INVOKE_SERVICE(UnregisterNodes);
         break;
         break;
-
     case UA_NS0ID_TRANSLATEBROWSEPATHSTONODEIDSREQUEST:
     case UA_NS0ID_TRANSLATEBROWSEPATHSTONODEIDSREQUEST:
         INVOKE_SERVICE(TranslateBrowsePathsToNodeIds);
         INVOKE_SERVICE(TranslateBrowsePathsToNodeIds);
         break;
         break;
-
     default: {
     default: {
         UA_LOG_INFO(server->logger, UA_LOGGERCATEGORY_COMMUNICATION, "Unknown request: NodeId(ns=%d, i=%d)",
         UA_LOG_INFO(server->logger, UA_LOGGERCATEGORY_COMMUNICATION, "Unknown request: NodeId(ns=%d, i=%d)",
                     requestType.namespaceIndex, requestType.identifier.numeric);
                     requestType.namespaceIndex, requestType.identifier.numeric);
-
         UA_RequestHeader  p;
         UA_RequestHeader  p;
         UA_ResponseHeader r;
         UA_ResponseHeader r;
-        if(UA_RequestHeader_decodeBinary(msg, pos, &p))
+        if(UA_RequestHeader_decodeBinary(msg, pos, &p) != UA_STATUSCODE_GOOD)
             return;
             return;
         UA_ResponseHeader_init(&r);
         UA_ResponseHeader_init(&r);
         init_response_header(&p, &r);
         init_response_header(&p, &r);
@@ -345,7 +312,7 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
         if(retval != UA_STATUSCODE_GOOD)
         if(retval != UA_STATUSCODE_GOOD)
             r.serviceResult = retval;
             r.serviceResult = retval;
 #endif
 #endif
-        ALLOC_MESSAGE(message, UA_ResponseHeader_calcSizeBinary(&r));
+        connection->getBuffer(connection, message, UA_ResponseHeader_calcSizeBinary(&r));
         UA_ResponseHeader_encodeBinary(&r, message, &sendOffset);
         UA_ResponseHeader_encodeBinary(&r, message, &sendOffset);
         UA_RequestHeader_deleteMembers(&p);
         UA_RequestHeader_deleteMembers(&p);
         UA_ResponseHeader_deleteMembers(&r);
         UA_ResponseHeader_deleteMembers(&r);
@@ -375,11 +342,10 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
         + UA_SymmetricAlgorithmSecurityHeader_calcSizeBinary(&symSecHeader)
         + UA_SymmetricAlgorithmSecurityHeader_calcSizeBinary(&symSecHeader)
         + UA_SequenceHeader_calcSizeBinary(&seqHeader)
         + UA_SequenceHeader_calcSizeBinary(&seqHeader)
         + UA_NodeId_calcSizeBinary(&response_nodeid);
         + UA_NodeId_calcSizeBinary(&response_nodeid);
-
-    *header = (UA_ByteString){ .length = headerSize, .data = UA_alloca(headerSize) };
-    respHeader.messageHeader.messageSize = header->length + message->length;
+    respHeader.messageHeader.messageSize = headerSize + message->length;
 
 
     size_t rpos = 0;
     size_t rpos = 0;
+    connection->getBuffer(connection, header, headerSize);
     UA_SecureConversationMessageHeader_encodeBinary(&respHeader, header, &rpos);
     UA_SecureConversationMessageHeader_encodeBinary(&respHeader, header, &rpos);
     UA_SymmetricAlgorithmSecurityHeader_encodeBinary(&symSecHeader, header, &rpos);
     UA_SymmetricAlgorithmSecurityHeader_encodeBinary(&symSecHeader, header, &rpos);
     UA_SequenceHeader_encodeBinary(&seqHeader, header, &rpos);
     UA_SequenceHeader_encodeBinary(&seqHeader, header, &rpos);
@@ -392,28 +358,22 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
     responseBufArray.strings = responseBufs;
     responseBufArray.strings = responseBufs;
     responseBufArray.stringsSize = 2;
     responseBufArray.stringsSize = 2;
     connection->write(connection, responseBufArray);
     connection->write(connection, responseBufArray);
-
-    if(!messageOnStack)
-        UA_free(message->data);
+    connection->releaseBuffer(connection, header);
+    connection->releaseBuffer(connection, message);
 }
 }
 
 
-static void processCLO(UA_Connection *connection, UA_Server *server, const UA_ByteString *msg,
-                       size_t *pos) {
+static void processCLO(UA_Connection *connection, UA_Server *server, const UA_ByteString *msg, size_t *pos) {
     UA_UInt32 secureChannelId;
     UA_UInt32 secureChannelId;
     UA_StatusCode retval = UA_UInt32_decodeBinary(msg, pos, &secureChannelId);
     UA_StatusCode retval = UA_UInt32_decodeBinary(msg, pos, &secureChannelId);
-
     if(retval != UA_STATUSCODE_GOOD || !connection->channel ||
     if(retval != UA_STATUSCODE_GOOD || !connection->channel ||
        connection->channel->securityToken.channelId != secureChannelId)
        connection->channel->securityToken.channelId != secureChannelId)
         return;
         return;
-
     Service_CloseSecureChannel(server, secureChannelId);
     Service_CloseSecureChannel(server, secureChannelId);
 }
 }
 
 
 void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection, UA_ByteString *msg) {
 void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection, UA_ByteString *msg) {
-    *msg = UA_Connection_completeMessages(connection, *msg);
     if(msg->length <= 0)
     if(msg->length <= 0)
         return;
         return;
-
     size_t pos = 0;
     size_t pos = 0;
     UA_TcpMessageHeader tcpMessageHeader;
     UA_TcpMessageHeader tcpMessageHeader;
     do {
     do {
@@ -423,9 +383,6 @@ void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection
             break;
             break;
         }
         }
 
 
-        if(tcpMessageHeader.messageSize < 32)
-            break; // there is no usefull message of that size
-
         size_t targetpos = pos - 8 + tcpMessageHeader.messageSize;
         size_t targetpos = pos - 8 + tcpMessageHeader.messageSize;
 
 
         switch(tcpMessageHeader.messageTypeAndFinal & 0xffffff) {
         switch(tcpMessageHeader.messageTypeAndFinal & 0xffffff) {

+ 1 - 51
src/server/ua_server_worker.c

@@ -440,60 +440,10 @@ UA_StatusCode UA_Server_run(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *r
     UA_Server_addRepeatedWorkItem(server, &processDelayed, 10000000, UA_NULL);
     UA_Server_addRepeatedWorkItem(server, &processDelayed, 10000000, UA_NULL);
 #endif
 #endif
 
 
-    // 2a) Start the networklayers
+    // 2) Start the networklayers
     for(UA_Int32 i=0;i<server->nlsSize;i++)
     for(UA_Int32 i=0;i<server->nlsSize;i++)
         server->nls[i].start(server->nls[i].nlHandle, &server->logger);
         server->nls[i].start(server->nls[i].nlHandle, &server->logger);
 
 
-    // 2b) Init server's meta-information
-    //fill startTime
-    server->startTime = UA_DateTime_now();
-
-    //fill build date
-    {
-		static struct tm ct;
-
-		ct.tm_year = (__DATE__[7] - '0') * 1000 +  (__DATE__[8] - '0') * 100 + (__DATE__[9] - '0') * 10 + (__DATE__[10] - '0')- 1900;
-
-		if (0) ;
-		else if ((__DATE__[0]=='J') && (__DATE__[1]=='a') && (__DATE__[2]=='n')) ct.tm_mon = 1-1;
-		else if ((__DATE__[0]=='F') && (__DATE__[1]=='e') && (__DATE__[2]=='b')) ct.tm_mon = 2-1;
-		else if ((__DATE__[0]=='M') && (__DATE__[1]=='a') && (__DATE__[2]=='r')) ct.tm_mon = 3-1;
-		else if ((__DATE__[0]=='A') && (__DATE__[1]=='p') && (__DATE__[2]=='r')) ct.tm_mon = 4-1;
-		else if ((__DATE__[0]=='M') && (__DATE__[1]=='a') && (__DATE__[2]=='y')) ct.tm_mon = 5-1;
-		else if ((__DATE__[0]=='J') && (__DATE__[1]=='u') && (__DATE__[2]=='n')) ct.tm_mon = 6-1;
-		else if ((__DATE__[0]=='J') && (__DATE__[1]=='u') && (__DATE__[2]=='l')) ct.tm_mon = 7-1;
-		else if ((__DATE__[0]=='A') && (__DATE__[1]=='u') && (__DATE__[2]=='g')) ct.tm_mon = 8-1;
-		else if ((__DATE__[0]=='S') && (__DATE__[1]=='e') && (__DATE__[2]=='p')) ct.tm_mon = 9-1;
-		else if ((__DATE__[0]=='O') && (__DATE__[1]=='c') && (__DATE__[2]=='t')) ct.tm_mon = 10-1;
-		else if ((__DATE__[0]=='N') && (__DATE__[1]=='o') && (__DATE__[2]=='v')) ct.tm_mon = 11-1;
-		else if ((__DATE__[0]=='D') && (__DATE__[1]=='e') && (__DATE__[2]=='c')) ct.tm_mon = 12-1;
-
-		// special case to handle __DATE__ not inserting leading zero on day of month
-		// if Day of month is less than 10 - it inserts a blank character
-		// this results in a negative number for tm_mday
-
-		if(__DATE__[4] == ' ')
-		{
-			ct.tm_mday =  __DATE__[5]-'0';
-		}
-		else
-		{
-			ct.tm_mday = (__DATE__[4]-'0')*10 + (__DATE__[5]-'0');
-		}
-
-		ct.tm_hour = ((__TIME__[0] - '0') * 10 + __TIME__[1] - '0');
-		ct.tm_min = ((__TIME__[3] - '0') * 10 + __TIME__[4] - '0');
-		ct.tm_sec = ((__TIME__[6] - '0') * 10 + __TIME__[7] - '0');
-
-		ct.tm_isdst = -1;  // information is not available.
-
-		//FIXME: next 3 lines are copy-pasted from ua_types.c
-		#define UNIX_EPOCH_BIAS_SEC 11644473600LL // Number of seconds from 1 Jan. 1601 00:00 to 1 Jan 1970 00:00 UTC
-		#define HUNDRED_NANOSEC_PER_USEC 10LL
-		#define HUNDRED_NANOSEC_PER_SEC (HUNDRED_NANOSEC_PER_USEC * 1000000LL)
-		server->buildDate = (mktime(&ct) + UNIX_EPOCH_BIAS_SEC) * HUNDRED_NANOSEC_PER_SEC;
-    }
-
     //3) The loop
     //3) The loop
     while(1) {
     while(1) {
         // 3.1) Process timed work
         // 3.1) Process timed work

+ 100 - 0
src/ua_connection.c

@@ -0,0 +1,100 @@
+#include "ua_util.h"
+#include "ua_connection.h"
+#include "ua_types_encoding_binary.h"
+
+const char *UA_LoggerCategoryNames[4] = {"communication", "server", "client", "userland"};
+
+// max message size is 64k
+const UA_ConnectionConfig UA_ConnectionConfig_standard =
+    {.protocolVersion = 0, .sendBufferSize = 65536, .recvBufferSize  = 65536,
+     .maxMessageSize = 65536, .maxChunkCount   = 1};
+
+void UA_Connection_init(UA_Connection *connection) {
+    connection->state = UA_CONNECTION_CLOSED;
+    connection->localConf = (UA_ConnectionConfig){0,0,0,0,0};
+    connection->remoteConf = (UA_ConnectionConfig){0,0,0,0,0};
+    connection->channel = UA_NULL;
+    connection->sockfd = 0;
+    connection->handle = UA_NULL;
+    UA_ByteString_init(&connection->incompleteMessage);
+    connection->write = UA_NULL;
+    connection->close = UA_NULL;
+    connection->recv = UA_NULL;
+}
+
+void UA_Connection_deleteMembers(UA_Connection *connection) {
+    UA_ByteString_deleteMembers(&connection->incompleteMessage);
+}
+
+UA_ByteString UA_Connection_completeMessages(UA_Connection *connection, UA_ByteString received)
+{
+    if(received.length == -1)
+        return received;
+
+    /* concat the existing incomplete message with the new message */
+    UA_ByteString current;
+    if(connection->incompleteMessage.length < 0)
+        current = received;
+    else {
+        current.data = UA_realloc(connection->incompleteMessage.data,
+                                  connection->incompleteMessage.length + received.length);
+        if(!current.data) {
+            /* not enough memory */
+            UA_ByteString_deleteMembers(&connection->incompleteMessage);
+            connection->incompleteMessage.length = -1;
+            UA_ByteString_deleteMembers(&received);
+            received.length = -1;
+            return received;
+        }
+        UA_memcpy(current.data + connection->incompleteMessage.length, received.data, received.length);
+        current.length = connection->incompleteMessage.length + received.length;
+        UA_ByteString_deleteMembers(&received);
+        UA_ByteString_init(&connection->incompleteMessage);
+    }
+
+    /* find the first non-complete message */
+    size_t end_pos = 0; // the end of the last complete message
+    while(current.length - end_pos >= 16) {
+        if(!(current.data[0] == 'M' && current.data[1] == 'S' && current.data[2] == 'G') &&
+           !(current.data[0] == 'O' && current.data[1] == 'P' && current.data[2] == 'N') &&
+           !(current.data[0] == 'H' && current.data[1] == 'E' && current.data[2] == 'L') &&
+           !(current.data[0] == 'A' && current.data[1] == 'C' && current.data[2] == 'K') &&
+           !(current.data[0] == 'C' && current.data[1] == 'L' && current.data[2] == 'O')) {
+            current.length = end_pos; // throw the remaining bytestring away
+            break;
+        }
+        UA_Int32 length = 0;
+        size_t pos = end_pos + 4;
+        UA_StatusCode retval = UA_Int32_decodeBinary(&current, &pos, &length);
+        if(retval != UA_STATUSCODE_GOOD || length < 16 ||
+           length > (UA_Int32)connection->localConf.maxMessageSize) {
+            current.length = end_pos; // throw the remaining bytestring away
+            break;
+        }
+        if(length + (UA_Int32)end_pos > current.length)
+            break; // the message is incomplete
+        end_pos += length;
+    }
+
+    if(current.length == 0) {
+        /* throw everything away */
+        UA_ByteString_deleteMembers(&current);
+        current.length = -1;
+        return current;
+    }
+
+    if(end_pos == 0) {
+        /* no complete message in current */
+        connection->incompleteMessage = current;
+        UA_ByteString_init(&current);
+    } else if(current.length != (UA_Int32)end_pos) {
+        /* there is an incomplete message at the end of current */
+        connection->incompleteMessage.data = UA_malloc(current.length - end_pos);
+        if(connection->incompleteMessage.data) {
+            UA_memcpy(connection->incompleteMessage.data, &current.data[end_pos], current.length - end_pos);
+            connection->incompleteMessage.length = current.length - end_pos;
+        }
+        current.length = end_pos;
+    }
+    return current;
+}

+ 1 - 88
src/ua_securechannel.c

@@ -1,85 +1,6 @@
 #include "ua_util.h"
 #include "ua_util.h"
 #include "ua_securechannel.h"
 #include "ua_securechannel.h"
 #include "ua_statuscodes.h"
 #include "ua_statuscodes.h"
-#include "ua_types_encoding_binary.h"
-
-// max message size is 64k
-const UA_ConnectionConfig UA_ConnectionConfig_standard =
-    {.protocolVersion = 0, .sendBufferSize = 65536, .recvBufferSize  = 65536,
-     .maxMessageSize = 65536, .maxChunkCount   = 1};
-
-UA_ByteString UA_Connection_completeMessages(UA_Connection *connection, UA_ByteString received)
-{
-    if(received.length == -1)
-        return received;
-
-    /* concat the existing incomplete message with the new message */
-    UA_ByteString current;
-    if(connection->incompleteMessage.length < 0)
-        current = received;
-    else {
-        current.data = UA_realloc(connection->incompleteMessage.data,
-                                  connection->incompleteMessage.length + received.length);
-        if(!current.data) {
-            /* not enough memory */
-            UA_ByteString_deleteMembers(&connection->incompleteMessage);
-            connection->incompleteMessage.length = -1;
-            UA_ByteString_deleteMembers(&received);
-            received.length = -1;
-            return received;
-        }
-        UA_memcpy(current.data + connection->incompleteMessage.length, received.data, received.length);
-        current.length = connection->incompleteMessage.length + received.length;
-        UA_ByteString_deleteMembers(&received);
-        UA_ByteString_init(&connection->incompleteMessage);
-    }
-
-    /* find the first non-complete message */
-    size_t end_pos = 0; // the end of the last complete message
-    while(current.length - end_pos >= 32) {
-        if(!(current.data[0] == 'M' && current.data[1] == 'S' && current.data[2] == 'G') &&
-           !(current.data[0] == 'O' && current.data[1] == 'P' && current.data[2] == 'N') &&
-           !(current.data[0] == 'H' && current.data[1] == 'E' && current.data[2] == 'L') &&
-           !(current.data[0] == 'A' && current.data[1] == 'C' && current.data[2] == 'K') &&
-           !(current.data[0] == 'C' && current.data[1] == 'L' && current.data[2] == 'O')) {
-            current.length = end_pos; // throw the remaining bytestring away
-            break;
-        }
-        UA_Int32 length = 0;
-        size_t pos = end_pos + 4;
-        UA_StatusCode retval = UA_Int32_decodeBinary(&current, &pos, &length);
-        if(retval != UA_STATUSCODE_GOOD || length < 32 ||
-           length > (UA_Int32)connection->localConf.maxMessageSize) {
-            current.length = end_pos; // throw the remaining bytestring away
-            break;
-        }
-        if(length + (UA_Int32)end_pos > current.length)
-            break; // the message is incomplete
-        end_pos += length;
-    }
-
-    if(current.length == 0) {
-        /* throw everything away */
-        UA_ByteString_deleteMembers(&current);
-        current.length = -1;
-        return current;
-    }
-
-    if(end_pos == 0) {
-        /* no complete message in current */
-        connection->incompleteMessage = current;
-        UA_ByteString_init(&current);
-    } else if(current.length != (UA_Int32)end_pos) {
-        /* there is an incomplete message at the end of current */
-        connection->incompleteMessage.data = UA_malloc(current.length - end_pos);
-        if(connection->incompleteMessage.data) {
-            UA_memcpy(connection->incompleteMessage.data, &current.data[end_pos], current.length - end_pos);
-            connection->incompleteMessage.length = current.length - end_pos;
-        }
-        current.length = end_pos;
-    }
-    return current;
-}
 
 
 void UA_SecureChannel_init(UA_SecureChannel *channel) {
 void UA_SecureChannel_init(UA_SecureChannel *channel) {
     UA_MessageSecurityMode_init(&channel->securityMode);
     UA_MessageSecurityMode_init(&channel->securityMode);
@@ -102,15 +23,6 @@ void UA_SecureChannel_deleteMembers(UA_SecureChannel *channel) {
     UA_ChannelSecurityToken_deleteMembers(&channel->securityToken);
     UA_ChannelSecurityToken_deleteMembers(&channel->securityToken);
 }
 }
 
 
-void UA_SecureChannel_delete(UA_SecureChannel *channel) {
-    UA_SecureChannel_deleteMembers(channel);
-    UA_free(channel);
-}
-
-UA_Boolean UA_SecureChannel_compare(UA_SecureChannel *sc1, UA_SecureChannel *sc2) {
-    return (sc1->securityToken.channelId == sc2->securityToken.channelId);
-}
-
 //TODO implement real nonce generator - DUMMY function
 //TODO implement real nonce generator - DUMMY function
 UA_StatusCode UA_SecureChannel_generateNonce(UA_ByteString *nonce) {
 UA_StatusCode UA_SecureChannel_generateNonce(UA_ByteString *nonce) {
     if(!(nonce->data = UA_malloc(1)))
     if(!(nonce->data = UA_malloc(1)))
@@ -136,6 +48,7 @@ UA_StatusCode UA_SecureChannel_updateSequenceNumber(UA_SecureChannel *channel, U
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
+/* these need ua_securechannel.h */
 void UA_Connection_detachSecureChannel(UA_Connection *connection) {
 void UA_Connection_detachSecureChannel(UA_Connection *connection) {
 #ifdef UA_MULTITHREADING
 #ifdef UA_MULTITHREADING
     UA_SecureChannel *channel = connection->channel;
     UA_SecureChannel *channel = connection->channel;

+ 1 - 4
src/ua_securechannel.h

@@ -23,20 +23,17 @@ struct UA_SecureChannel {
     UA_ByteString  serverNonce;
     UA_ByteString  serverNonce;
     UA_UInt32      requestId;
     UA_UInt32      requestId;
     UA_UInt32      sequenceNumber;
     UA_UInt32      sequenceNumber;
-    UA_Connection *connection; // make this more generic when http connections exist
+    UA_Connection *connection;
     UA_Session    *session;
     UA_Session    *session;
 };
 };
 
 
 void UA_SecureChannel_init(UA_SecureChannel *channel);
 void UA_SecureChannel_init(UA_SecureChannel *channel);
 void UA_SecureChannel_deleteMembers(UA_SecureChannel *channel);
 void UA_SecureChannel_deleteMembers(UA_SecureChannel *channel);
-void UA_SecureChannel_delete(UA_SecureChannel *channel);
-UA_Boolean UA_SecureChannel_compare(UA_SecureChannel *sc1, UA_SecureChannel *sc2);
 
 
 UA_StatusCode UA_SecureChannel_generateNonce(UA_ByteString *nonce);
 UA_StatusCode UA_SecureChannel_generateNonce(UA_ByteString *nonce);
 UA_StatusCode UA_SecureChannel_updateRequestId(UA_SecureChannel *channel, UA_UInt32 requestId);
 UA_StatusCode UA_SecureChannel_updateRequestId(UA_SecureChannel *channel, UA_UInt32 requestId);
 UA_StatusCode UA_SecureChannel_updateSequenceNumber(UA_SecureChannel *channel, UA_UInt32 sequenceNumber);
 UA_StatusCode UA_SecureChannel_updateSequenceNumber(UA_SecureChannel *channel, UA_UInt32 sequenceNumber);
 
 
-void UA_Connection_attachSecureChannel(UA_Connection *connection, UA_SecureChannel *channel);
 void UA_SecureChannel_attachSession(UA_SecureChannel *channel, UA_Session *session);
 void UA_SecureChannel_attachSession(UA_SecureChannel *channel, UA_Session *session);
 void UA_SecureChannel_detachSession(UA_SecureChannel *channel);
 void UA_SecureChannel_detachSession(UA_SecureChannel *channel);
 
 

+ 17 - 34
src/ua_session.c

@@ -30,12 +30,6 @@ UA_Session adminSession = {
     .timeout = UA_INT64_MAX, .validTill = UA_INT64_MAX, .channel = UA_NULL,
     .timeout = UA_INT64_MAX, .validTill = UA_INT64_MAX, .channel = UA_NULL,
     .continuationPoints = {UA_NULL}};
     .continuationPoints = {UA_NULL}};
 
 
-UA_Session * UA_Session_new(void) {
-    UA_Session *s = UA_malloc(sizeof(UA_Session));
-    if(s) UA_Session_init(s);
-    return s;
-}
-
 /* TODO: Nobody seems to call this function right now */
 /* TODO: Nobody seems to call this function right now */
 static UA_StatusCode UA_Session_generateToken(UA_NodeId *newToken, UA_UInt32 *seed) {
 static UA_StatusCode UA_Session_generateToken(UA_NodeId *newToken, UA_UInt32 *seed) {
     newToken->namespaceIndex = 0; // where else?
     newToken->namespaceIndex = 0; // where else?
@@ -45,7 +39,6 @@ static UA_StatusCode UA_Session_generateToken(UA_NodeId *newToken, UA_UInt32 *se
 }
 }
 
 
 void UA_Session_init(UA_Session *session) {
 void UA_Session_init(UA_Session *session) {
-    if(!session) return;
     UA_ApplicationDescription_init(&session->clientDescription);
     UA_ApplicationDescription_init(&session->clientDescription);
     UA_NodeId_init(&session->authenticationToken);
     UA_NodeId_init(&session->authenticationToken);
     UA_NodeId_init(&session->sessionId);
     UA_NodeId_init(&session->sessionId);
@@ -73,17 +66,6 @@ void UA_Session_deleteMembers(UA_Session *session) {
     }
     }
 }
 }
 
 
-void UA_Session_delete(UA_Session *session) {
-    UA_Session_deleteMembers(session);
-    UA_free(session);
-}
-
-UA_Boolean UA_Session_compare(UA_Session *session1, UA_Session *session2) {
-    if(session1 && session2 && UA_NodeId_equal(&session1->sessionId, &session2->sessionId))
-        return UA_TRUE;
-    return UA_FALSE;
-}
-
 UA_StatusCode UA_Session_setExpirationDate(UA_Session *session) {
 UA_StatusCode UA_Session_setExpirationDate(UA_Session *session) {
     if(!session)
     if(!session)
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
@@ -100,19 +82,20 @@ UA_StatusCode UA_Session_getPendingLifetime(UA_Session *session, UA_Double *pend
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-void UA_SecureChannel_detachSession(UA_SecureChannel *channel) {
+void UA_Session_detachSecureChannel(UA_Session *session) {
 #ifdef UA_MULTITHREADING
 #ifdef UA_MULTITHREADING
-    UA_Session *session = channel->session;
-    if(session)
-        uatomic_cmpxchg(&session->channel, channel, UA_NULL);
-    uatomic_set(&channel->session, UA_NULL);
+    UA_SecureChannel *channel = session->channel;
+    if(channel)
+        uatomic_cmpxchg(&channel->session, session, UA_NULL);
+    uatomic_set(&session->channel, UA_NULL);
 #else
 #else
-    if(channel->session)
-        channel->session->channel = UA_NULL;
-    channel->session = UA_NULL;
+    if(session->channel)
+        session->channel->session = UA_NULL;
+    session->channel = UA_NULL;
 #endif
 #endif
 }
 }
 
 
+/* these functions are here, since they need to include ua_session.h */
 void UA_SecureChannel_attachSession(UA_SecureChannel *channel, UA_Session *session) {
 void UA_SecureChannel_attachSession(UA_SecureChannel *channel, UA_Session *session) {
 #ifdef UA_MULTITHREADING
 #ifdef UA_MULTITHREADING
     if(uatomic_cmpxchg(&session->channel, UA_NULL, channel) == UA_NULL)
     if(uatomic_cmpxchg(&session->channel, UA_NULL, channel) == UA_NULL)
@@ -125,15 +108,15 @@ void UA_SecureChannel_attachSession(UA_SecureChannel *channel, UA_Session *sessi
 #endif
 #endif
 }
 }
 
 
-void UA_Session_detachSecureChannel(UA_Session *session) {
+void UA_SecureChannel_detachSession(UA_SecureChannel *channel) {
 #ifdef UA_MULTITHREADING
 #ifdef UA_MULTITHREADING
-    UA_SecureChannel *channel = session->channel;
-    if(channel)
-        uatomic_cmpxchg(&channel->session, session, UA_NULL);
-    uatomic_set(&session->channel, UA_NULL);
+    UA_Session *session = channel->session;
+    if(session)
+        uatomic_cmpxchg(&session->channel, channel, UA_NULL);
+    uatomic_set(&channel->session, UA_NULL);
 #else
 #else
-    if(session->channel)
-        session->channel->session = UA_NULL;
-    session->channel = UA_NULL;
+    if(channel->session)
+        channel->session->channel = UA_NULL;
+    channel->session = UA_NULL;
 #endif
 #endif
 }
 }

+ 0 - 5
src/ua_session.h

@@ -35,14 +35,9 @@ struct UA_Session {
 extern UA_Session anonymousSession; ///< If anonymous access is allowed, this session is used internally (Session ID: 0)
 extern UA_Session anonymousSession; ///< If anonymous access is allowed, this session is used internally (Session ID: 0)
 extern UA_Session adminSession; ///< Local access to the services (for startup and maintenance) uses this Session with all possible access rights (Session ID: 1)
 extern UA_Session adminSession; ///< Local access to the services (for startup and maintenance) uses this Session with all possible access rights (Session ID: 1)
 
 
-UA_Session * UA_Session_new(void);
 void UA_Session_init(UA_Session *session);
 void UA_Session_init(UA_Session *session);
-void UA_Session_delete(UA_Session *session);
 void UA_Session_deleteMembers(UA_Session *session);
 void UA_Session_deleteMembers(UA_Session *session);
 
 
-/** Compares two session objects */
-UA_Boolean UA_Session_compare(UA_Session *session1, UA_Session *session2);
-
 /** If any activity on a session happens, the timeout must be extended */
 /** If any activity on a session happens, the timeout must be extended */
 UA_StatusCode UA_Session_updateLifetime(UA_Session *session);
 UA_StatusCode UA_Session_updateLifetime(UA_Session *session);
 /** Set up the point in time till the session is valid */
 /** Set up the point in time till the session is valid */

+ 17 - 17
src/ua_types_encoding_binary.c

@@ -20,7 +20,7 @@
 /* Boolean */
 /* Boolean */
 UA_TYPE_CALCSIZEBINARY_MEMSIZE(UA_Boolean)
 UA_TYPE_CALCSIZEBINARY_MEMSIZE(UA_Boolean)
 UA_StatusCode UA_Boolean_encodeBinary(const UA_Boolean *src, UA_ByteString *dst, size_t *offset) {
 UA_StatusCode UA_Boolean_encodeBinary(const UA_Boolean *src, UA_ByteString *dst, size_t *offset) {
-    if(*offset + sizeof(UA_Boolean) > (size_t)dst->length)
+    if((UA_Int32)(*offset + sizeof(UA_Boolean)) > dst->length)
         return UA_STATUSCODE_BADENCODINGERROR;
         return UA_STATUSCODE_BADENCODINGERROR;
     dst->data[*offset] = (UA_Byte)*src;
     dst->data[*offset] = (UA_Byte)*src;
     ++(*offset);
     ++(*offset);
@@ -28,7 +28,7 @@ UA_StatusCode UA_Boolean_encodeBinary(const UA_Boolean *src, UA_ByteString *dst,
 }
 }
 
 
 UA_StatusCode UA_Boolean_decodeBinary(UA_ByteString const *src, size_t *offset, UA_Boolean *dst) {
 UA_StatusCode UA_Boolean_decodeBinary(UA_ByteString const *src, size_t *offset, UA_Boolean *dst) {
-    if(*offset + sizeof(UA_Boolean) > (size_t)src->length )
+    if((UA_Int32)(*offset + sizeof(UA_Boolean)) > src->length )
         return UA_STATUSCODE_BADDECODINGERROR;
         return UA_STATUSCODE_BADDECODINGERROR;
     *dst = (src->data[*offset] > 0) ? UA_TRUE : UA_FALSE;
     *dst = (src->data[*offset] > 0) ? UA_TRUE : UA_FALSE;
     ++(*offset);
     ++(*offset);
@@ -41,7 +41,7 @@ UA_TYPE_BINARY_ENCODING_AS(UA_SByte, UA_Byte)
 /* Byte */
 /* Byte */
 UA_TYPE_CALCSIZEBINARY_MEMSIZE(UA_Byte)
 UA_TYPE_CALCSIZEBINARY_MEMSIZE(UA_Byte)
 UA_StatusCode UA_Byte_encodeBinary(const UA_Byte *src, UA_ByteString *dst, size_t *offset) {
 UA_StatusCode UA_Byte_encodeBinary(const UA_Byte *src, UA_ByteString *dst, size_t *offset) {
-    if(*offset + sizeof(UA_Byte) > (size_t)dst->length)
+    if((UA_Int32)(*offset + sizeof(UA_Byte)) > dst->length)
         return UA_STATUSCODE_BADENCODINGERROR;
         return UA_STATUSCODE_BADENCODINGERROR;
     dst->data[*offset] = (UA_Byte)*src;
     dst->data[*offset] = (UA_Byte)*src;
     ++(*offset);
     ++(*offset);
@@ -49,7 +49,7 @@ UA_StatusCode UA_Byte_encodeBinary(const UA_Byte *src, UA_ByteString *dst, size_
 }
 }
 
 
 UA_StatusCode UA_Byte_decodeBinary(UA_ByteString const *src, size_t *offset, UA_Byte *dst) {
 UA_StatusCode UA_Byte_decodeBinary(UA_ByteString const *src, size_t *offset, UA_Byte *dst) {
-    if(*offset + sizeof(UA_Byte) > (size_t)src->length )
+    if((UA_Int32)(*offset + sizeof(UA_Byte)) > src->length )
         return UA_STATUSCODE_BADDECODINGERROR;
         return UA_STATUSCODE_BADDECODINGERROR;
     *dst = src->data[*offset];
     *dst = src->data[*offset];
     ++(*offset);
     ++(*offset);
@@ -62,7 +62,7 @@ UA_TYPE_BINARY_ENCODING_AS(UA_Int16, UA_UInt16)
 /* UInt16 */
 /* UInt16 */
 UA_TYPE_CALCSIZEBINARY_MEMSIZE(UA_UInt16)
 UA_TYPE_CALCSIZEBINARY_MEMSIZE(UA_UInt16)
 UA_StatusCode UA_UInt16_encodeBinary(UA_UInt16 const *src, UA_ByteString * dst, size_t *offset) {
 UA_StatusCode UA_UInt16_encodeBinary(UA_UInt16 const *src, UA_ByteString * dst, size_t *offset) {
-    if(*offset + sizeof(UA_UInt16) > (size_t)dst->length )
+    if((UA_Int32)(*offset + sizeof(UA_UInt16)) > dst->length )
         return UA_STATUSCODE_BADENCODINGERROR;
         return UA_STATUSCODE_BADENCODINGERROR;
     UA_UInt16 *dst_ptr = (UA_UInt16*)&dst->data[*offset];
     UA_UInt16 *dst_ptr = (UA_UInt16*)&dst->data[*offset];
 #ifndef _WIN32
 #ifndef _WIN32
@@ -75,7 +75,7 @@ UA_StatusCode UA_UInt16_encodeBinary(UA_UInt16 const *src, UA_ByteString * dst,
 }
 }
 
 
 UA_StatusCode UA_UInt16_decodeBinary(UA_ByteString const *src, size_t *offset, UA_UInt16 *dst) {
 UA_StatusCode UA_UInt16_decodeBinary(UA_ByteString const *src, size_t *offset, UA_UInt16 *dst) {
-    if(*offset + sizeof(UA_UInt16) > (size_t)src->length)
+    if((UA_Int32)(*offset + sizeof(UA_UInt16)) > src->length)
         return UA_STATUSCODE_BADDECODINGERROR;
         return UA_STATUSCODE_BADDECODINGERROR;
     UA_UInt16 value = *((UA_UInt16*)&src->data[*offset]);
     UA_UInt16 value = *((UA_UInt16*)&src->data[*offset]);
 #ifndef _WIN32
 #ifndef _WIN32
@@ -92,7 +92,7 @@ UA_TYPE_BINARY_ENCODING_AS(UA_Int32, UA_UInt32)
 /* UInt32 */
 /* UInt32 */
 UA_TYPE_CALCSIZEBINARY_MEMSIZE(UA_UInt32)
 UA_TYPE_CALCSIZEBINARY_MEMSIZE(UA_UInt32)
 UA_StatusCode UA_UInt32_encodeBinary(UA_UInt32 const *src, UA_ByteString * dst, size_t *offset) {
 UA_StatusCode UA_UInt32_encodeBinary(UA_UInt32 const *src, UA_ByteString * dst, size_t *offset) {
-    if(*offset + sizeof(UA_UInt32) > (size_t)dst->length )
+    if((UA_Int32)(*offset + sizeof(UA_UInt32)) > dst->length )
         return UA_STATUSCODE_BADENCODINGERROR;
         return UA_STATUSCODE_BADENCODINGERROR;
     UA_UInt32 *dst_ptr = (UA_UInt32*)&dst->data[*offset];
     UA_UInt32 *dst_ptr = (UA_UInt32*)&dst->data[*offset];
 #ifndef _WIN32
 #ifndef _WIN32
@@ -105,7 +105,7 @@ UA_StatusCode UA_UInt32_encodeBinary(UA_UInt32 const *src, UA_ByteString * dst,
 }
 }
 
 
 UA_StatusCode UA_UInt32_decodeBinary(UA_ByteString const *src, size_t *offset, UA_UInt32 * dst) {
 UA_StatusCode UA_UInt32_decodeBinary(UA_ByteString const *src, size_t *offset, UA_UInt32 * dst) {
-    if(*offset + sizeof(UA_UInt32) > (size_t)src->length)
+    if((UA_Int32)(*offset + sizeof(UA_UInt32)) > src->length)
         return UA_STATUSCODE_BADDECODINGERROR;
         return UA_STATUSCODE_BADDECODINGERROR;
     UA_UInt32 value = *((UA_UInt32*)&src->data[*offset]);
     UA_UInt32 value = *((UA_UInt32*)&src->data[*offset]);
 #ifndef _WIN32
 #ifndef _WIN32
@@ -122,7 +122,7 @@ UA_TYPE_BINARY_ENCODING_AS(UA_Int64, UA_UInt64)
 /* UInt64 */
 /* UInt64 */
 UA_TYPE_CALCSIZEBINARY_MEMSIZE(UA_UInt64)
 UA_TYPE_CALCSIZEBINARY_MEMSIZE(UA_UInt64)
 UA_StatusCode UA_UInt64_encodeBinary(UA_UInt64 const *src, UA_ByteString *dst, size_t *offset) {
 UA_StatusCode UA_UInt64_encodeBinary(UA_UInt64 const *src, UA_ByteString *dst, size_t *offset) {
-    if(*offset + sizeof(UA_UInt64) > (size_t)dst->length )
+    if((UA_Int32)(*offset + sizeof(UA_UInt64)) > dst->length )
         return UA_STATUSCODE_BADENCODINGERROR;
         return UA_STATUSCODE_BADENCODINGERROR;
     UA_UInt64 *dst_ptr = (UA_UInt64*)&dst->data[*offset];
     UA_UInt64 *dst_ptr = (UA_UInt64*)&dst->data[*offset];
 #ifndef _WIN32
 #ifndef _WIN32
@@ -135,7 +135,7 @@ UA_StatusCode UA_UInt64_encodeBinary(UA_UInt64 const *src, UA_ByteString *dst, s
 }
 }
 
 
 UA_StatusCode UA_UInt64_decodeBinary(UA_ByteString const *src, size_t *offset, UA_UInt64 * dst) {
 UA_StatusCode UA_UInt64_decodeBinary(UA_ByteString const *src, size_t *offset, UA_UInt64 * dst) {
-    if(*offset + sizeof(UA_UInt64) > (size_t)src->length)
+    if((UA_Int32)(*offset + sizeof(UA_UInt64)) > src->length)
         return UA_STATUSCODE_BADDECODINGERROR;
         return UA_STATUSCODE_BADDECODINGERROR;
     UA_UInt64 value = *((UA_UInt64*)&src->data[*offset]);
     UA_UInt64 value = *((UA_UInt64*)&src->data[*offset]);
 #ifndef _WIN32
 #ifndef _WIN32
@@ -202,7 +202,7 @@ size_t UA_String_calcSizeBinary(UA_String const *string) {
 }
 }
 
 
 UA_StatusCode UA_String_encodeBinary(UA_String const *src, UA_ByteString *dst, size_t *offset) {
 UA_StatusCode UA_String_encodeBinary(UA_String const *src, UA_ByteString *dst, size_t *offset) {
-    if(*offset + UA_String_calcSizeBinary(src) > (size_t)dst->length)
+    if((UA_Int32)(*offset + UA_String_calcSizeBinary(src)) > dst->length)
         return UA_STATUSCODE_BADENCODINGERROR;
         return UA_STATUSCODE_BADENCODINGERROR;
 
 
     UA_StatusCode retval = UA_Int32_encodeBinary(&src->length, dst, offset);
     UA_StatusCode retval = UA_Int32_encodeBinary(&src->length, dst, offset);
@@ -226,8 +226,8 @@ UA_StatusCode UA_String_decodeBinary(UA_ByteString const *src, size_t *offset, U
         return UA_STATUSCODE_GOOD;
         return UA_STATUSCODE_GOOD;
     }
     }
         
         
-    if(*offset + (size_t)length > (size_t)src->length)
-        return UA_STATUSCODE_BADINTERNALERROR;
+    if((UA_Int32)*offset + length > src->length)
+        return UA_STATUSCODE_BADDECODINGERROR;
     
     
     if(!(dst->data = UA_malloc(length)))
     if(!(dst->data = UA_malloc(length)))
         return UA_STATUSCODE_BADOUTOFMEMORY;
         return UA_STATUSCODE_BADOUTOFMEMORY;
@@ -452,7 +452,7 @@ UA_StatusCode UA_ExpandedNodeId_encodeBinary(UA_ExpandedNodeId const *src, UA_By
 UA_StatusCode UA_ExpandedNodeId_decodeBinary(UA_ByteString const *src, size_t *offset, UA_ExpandedNodeId *dst) {
 UA_StatusCode UA_ExpandedNodeId_decodeBinary(UA_ByteString const *src, size_t *offset, UA_ExpandedNodeId *dst) {
     UA_ExpandedNodeId_init(dst);
     UA_ExpandedNodeId_init(dst);
     // get encodingflags and leave a "clean" nodeidtype
     // get encodingflags and leave a "clean" nodeidtype
-    if(*offset >= (size_t)src->length)
+    if((UA_Int32)*offset >= src->length)
         return UA_STATUSCODE_BADDECODINGERROR;
         return UA_STATUSCODE_BADDECODINGERROR;
     UA_Byte encodingByte = src->data[*offset];
     UA_Byte encodingByte = src->data[*offset];
     src->data[*offset] = encodingByte & ~(UA_EXPANDEDNODEID_NAMESPACEURI_FLAG | UA_EXPANDEDNODEID_SERVERINDEX_FLAG);
     src->data[*offset] = encodingByte & ~(UA_EXPANDEDNODEID_NAMESPACEURI_FLAG | UA_EXPANDEDNODEID_SERVERINDEX_FLAG);
@@ -902,7 +902,7 @@ size_t UA_calcSizeBinary(const void *p, const UA_DataType *dataType) {
     size_t size = 0;
     size_t size = 0;
     uintptr_t ptr = (uintptr_t)p;
     uintptr_t ptr = (uintptr_t)p;
     UA_Byte membersSize = dataType->membersSize;
     UA_Byte membersSize = dataType->membersSize;
-    for(size_t i=0;i<membersSize; i++) {
+    for(size_t i = 0; i < membersSize; i++) {
         const UA_DataTypeMember *member = &dataType->members[i];
         const UA_DataTypeMember *member = &dataType->members[i];
         const UA_DataType *memberType;
         const UA_DataType *memberType;
         if(member->namespaceZero)
         if(member->namespaceZero)
@@ -985,7 +985,7 @@ UA_StatusCode UA_encodeBinary(const void *src, const UA_DataType *dataType, UA_B
     uintptr_t ptr = (uintptr_t)src;
     uintptr_t ptr = (uintptr_t)src;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_Byte membersSize = dataType->membersSize;
     UA_Byte membersSize = dataType->membersSize;
-    for(size_t i=0;i<membersSize && retval == UA_STATUSCODE_GOOD; i++) {
+    for(size_t i = 0; i < membersSize && retval == UA_STATUSCODE_GOOD; i++) {
         const UA_DataTypeMember *member = &dataType->members[i];
         const UA_DataTypeMember *member = &dataType->members[i];
         const UA_DataType *memberType;
         const UA_DataType *memberType;
         if(member->namespaceZero)
         if(member->namespaceZero)
@@ -1069,7 +1069,7 @@ UA_StatusCode UA_decodeBinary(const UA_ByteString *src, size_t *offset, void *ds
     uintptr_t ptr = (uintptr_t)dst;
     uintptr_t ptr = (uintptr_t)dst;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_Byte membersSize = dataType->membersSize;
     UA_Byte membersSize = dataType->membersSize;
-    for(size_t i=0;i<membersSize && retval == UA_STATUSCODE_GOOD; i++) {
+    for(size_t i = 0; i < membersSize && retval == UA_STATUSCODE_GOOD; i++) {
         const UA_DataTypeMember *member = &dataType->members[i];
         const UA_DataTypeMember *member = &dataType->members[i];
         const UA_DataType *memberType;
         const UA_DataType *memberType;
         if(member->namespaceZero)
         if(member->namespaceZero)

+ 4 - 3
tests/testing_networklayers.c

@@ -15,8 +15,9 @@ typedef struct {
 } NetworkLayer_FileInput;
 } NetworkLayer_FileInput;
 
 
 /** Accesses only the sockfd in the handle. Can be run from parallel threads. */
 /** Accesses only the sockfd in the handle. Can be run from parallel threads. */
-static void writeCallback(NetworkLayer_FileInput *handle, UA_ByteStringArray gather_buf) {
+static UA_StatusCode writeCallback(NetworkLayer_FileInput *handle, UA_ByteStringArray gather_buf) {
     handle->writeCallback(handle->callbackHandle, gather_buf);
     handle->writeCallback(handle->callbackHandle, gather_buf);
+    return UA_STATUSCODE_GOOD;
 }
 }
 
 
 static void closeCallback(NetworkLayer_FileInput *handle) {
 static void closeCallback(NetworkLayer_FileInput *handle) {
@@ -79,8 +80,8 @@ ServerNetworkLayerFileInput_new(UA_UInt32 files, char **filenames, void(*readCal
     layer->connection.state = UA_CONNECTION_OPENING;
     layer->connection.state = UA_CONNECTION_OPENING;
     layer->connection.localConf = UA_ConnectionConfig_standard;
     layer->connection.localConf = UA_ConnectionConfig_standard;
     layer->connection.channel = (void*)0;
     layer->connection.channel = (void*)0;
-    layer->connection.close = (void (*)(void*))closeCallback;
-    layer->connection.write = (void (*)(void*, UA_ByteStringArray))writeCallback;
+    layer->connection.close = (void (*)(UA_Connection*))closeCallback;
+    layer->connection.write = (UA_StatusCode (*)(UA_Connection*, UA_ByteStringArray))writeCallback;
 
 
     layer->files = files;
     layer->files = files;
     layer->filenames = filenames;
     layer->filenames = filenames;

+ 2 - 2
tests/testing_networklayers.h

@@ -2,9 +2,9 @@
 #define TESTING_NETWORKLAYERS_H_
 #define TESTING_NETWORKLAYERS_H_
 
 
 #ifdef NOT_AMALGATED
 #ifdef NOT_AMALGATED
-    #include "ua_server.h"
+# include "ua_server.h"
 #else
 #else
-    #include "open62541.h"
+# include "open62541.h"
 #endif
 #endif
 
 
 /** @brief Create the TCP networklayer and listen to the specified port */
 /** @brief Create the TCP networklayer and listen to the specified port */