Bladeren bron

renames client_proper -> client, server_datasource -> server, server -> server_simple, client -> client_legacy
everything builds with single-file distro
client works in wine

Stasik0 10 jaren geleden
bovenliggende
commit
0a2dd74f5c
9 gewijzigde bestanden met toevoegingen van 984 en 956 verwijderingen
  1. 5 5
      .travis.yml
  2. 24 16
      CMakeLists.txt
  3. 32 583
      examples/client.c
  4. 591 0
      examples/client_legacy.c
  5. 0 36
      examples/client_proper.c
  6. 4 0
      examples/networklayer_tcp.c
  7. 224 59
      examples/server.c
  8. 0 257
      examples/server_datasource.c
  9. 104 0
      examples/server_simple.c

+ 5 - 5
.travis.yml

@@ -36,19 +36,19 @@ script:
 - cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-mingw32.cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLESERVER=ON ..
 - make -j
 - cp ../README.md .
-- zip open62541-win32.zip README.md exampleServer_datasource.exe libopen62541.dll libopen62541.dll.a open62541.h open62541.c
+- zip open62541-win32.zip README.md exampleServere.exe exampleClient.exe libopen62541.dll libopen62541.dll.a open62541.h open62541.c
 - cp open62541-win32.zip ..
 - cd .. && rm build -rf && mkdir -p build && cd build
 - echo "Cross compile release build for 32-bit linux"
 - cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-gcc-m32.cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLESERVER=ON ..
 - make -j
-- tar -pczf open62541-linux32.tar.gz ../README.md exampleServer_datasource libopen62541.so open62541.h open62541.c
+- tar -pczf open62541-linux32.tar.gz ../README.md exampleServer exampleClient libopen62541.so open62541.h open62541.c
 - cp open62541-linux32.tar.gz ..
 - cd .. && rm build -rf && mkdir -p build && cd build
 - echo "Compile release build for 64-bit linux"
 - cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLESERVER=ON ..
 - make -j
-- tar -pczf open62541-linux64.tar.gz ../README.md exampleServer_datasource libopen62541.so open62541.h open62541.c
+- tar -pczf open62541-linux64.tar.gz ../README.md exampleServer exampleClient libopen62541.so open62541.h open62541.c
 - cp open62541-linux64.tar.gz ..
 - cd .. && rm build -rf && mkdir -p build && cd build
 - echo "Upgrade to gcc 4.8"
@@ -84,7 +84,7 @@ before_deploy:
 - export PATH=$PATH:~/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/
 - cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-rpi64.cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLESERVER=ON ..
 - make -j
-- tar -pczf open62541-raspberrypi.tar.gz ../README.md exampleServer_datasource libopen62541.so open62541.h open62541.c
+- tar -pczf open62541-raspberrypi.tar.gz ../README.md exampleServer exampleClient libopen62541.so open62541.h open62541.c
 - cp open62541-raspberrypi.tar.gz ..
 - cd ..
 deploy:
@@ -98,4 +98,4 @@ deploy:
     - open62541-raspberrypi.tar.gz
   skip_cleanup: true
   on:
-    tags: true
+    tags: true

+ 24 - 16
CMakeLists.txt

@@ -139,6 +139,7 @@ if(BUILD_DEMO_NODESET)
 endif()
 
 if(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel" OR CMAKE_BUILD_TYPE STREQUAL "Release")
+	set(AMALGATED ON)
     ## build amalgamated source files
     add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/open62541.h ${PROJECT_BINARY_DIR}/open62541.c
                    PRE_BUILD
@@ -181,23 +182,23 @@ endif()
 option(BUILD_EXAMPLESERVER "Build the example server" OFF)
 if(BUILD_EXAMPLESERVER)
     add_executable(exampleServer examples/server.c $<TARGET_OBJECTS:open62541-object> examples/networklayer_tcp.c examples/logger_stdout.c)
-    add_executable(exampleServer_datasource examples/server_datasource.c $<TARGET_OBJECTS:open62541-object> examples/networklayer_tcp.c examples/logger_stdout.c)
+    add_executable(exampleServer_simple examples/server_simple.c $<TARGET_OBJECTS:open62541-object> examples/networklayer_tcp.c examples/logger_stdout.c)
     target_include_directories(exampleServer PRIVATE ${PROJECT_BINARY_DIR})
-    target_include_directories(exampleServer_datasource PRIVATE ${PROJECT_BINARY_DIR})
+    target_include_directories(exampleServer_simple PRIVATE ${PROJECT_BINARY_DIR})
     if(WIN32)
         target_link_libraries(exampleServer ws2_32)
-        target_link_libraries(exampleServer_datasource ws2_32)
+        target_link_libraries(exampleServer_simple ws2_32)
     else()
         target_link_libraries(exampleServer rt)
-        target_link_libraries(exampleServer_datasource rt)
+        target_link_libraries(exampleServer_simple rt)
     endif()
     if(ENABLE_MULTITHREADING)
         target_link_libraries(exampleServer urcu-cds urcu urcu-common pthread)
-        target_link_libraries(exampleServer_datasource urcu-cds urcu urcu-common pthread)
+        target_link_libraries(exampleServer_simple urcu-cds urcu urcu-common pthread)
     endif()
     if((CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") AND (CMAKE_BUILD_TYPE STREQUAL "MinSizeRel" OR CMAKE_BUILD_TYPE STREQUAL "Release"))
     	add_custom_command(TARGET exampleServer POST_BUILD COMMAND ${CMAKE_STRIP} $<TARGET_FILE:exampleServer>)
-		add_custom_command(TARGET exampleServer_datasource POST_BUILD COMMAND ${CMAKE_STRIP} $<TARGET_FILE:exampleServer_datasource>)
+		add_custom_command(TARGET exampleServer_simple POST_BUILD COMMAND ${CMAKE_STRIP} $<TARGET_FILE:exampleServer_simple>)
 	endif()
 endif()
 
@@ -218,23 +219,30 @@ option(BUILD_EXAMPLECLIENT "Build a test client" OFF)
 if(BUILD_EXAMPLECLIENT)
 	message(STATUS "Extensions: enabling client")
 	add_definitions( -DBENCHMARK=1 )
-	add_executable(exampleClient $<TARGET_OBJECTS:open62541-object> examples/client.c)
-	add_executable(exampleClient_proper $<TARGET_OBJECTS:open62541-object> examples/client_proper.c examples/networklayer_tcp.c)
-    target_include_directories(exampleClient PRIVATE ${PROJECT_BINARY_DIR})
-    target_include_directories(exampleClient_proper PRIVATE ${PROJECT_BINARY_DIR})
-    if(ENABLE_MULTITHREADING)
-        target_link_libraries(exampleClient urcu-cds urcu urcu-common pthread)
+	if(NOT AMALGATED)
+		add_executable(exampleClient_legacy $<TARGET_OBJECTS:open62541-object> examples/client_legacy.c)
+	endif()
+	add_executable(exampleClient $<TARGET_OBJECTS:open62541-object> examples/client.c examples/networklayer_tcp.c)
+    if(NOT AMALGATED)
+    	target_include_directories(exampleClient_legacy PRIVATE ${PROJECT_BINARY_DIR})
     endif()
+    target_include_directories(exampleClient PRIVATE ${PROJECT_BINARY_DIR})
     if(WIN32)
+    	if(NOT AMALGATED)
+        	target_link_libraries(exampleClient_legacy ws2_32)
+        endif()
         target_link_libraries(exampleClient ws2_32)
-        target_link_libraries(exampleClient_proper ws2_32)
     else()
+   		if(NOT AMALGATED)
+        	target_link_libraries(exampleClient_legacy rt)
+        endif()
         target_link_libraries(exampleClient rt)
-        target_link_libraries(exampleClient_proper rt)
     endif()
     if ((CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") AND (CMAKE_BUILD_TYPE STREQUAL "MinSizeRel" OR CMAKE_BUILD_TYPE STREQUAL "Release"))
-       add_custom_command(TARGET exampleClient POST_BUILD COMMAND ${CMAKE_STRIP} $<TARGET_FILE:exampleClient>)
-	   add_custom_command(TARGET exampleClient_proper POST_BUILD COMMAND ${CMAKE_STRIP} $<TARGET_FILE:exampleClient_proper>)
+       if(NOT AMALGATED)
+       		add_custom_command(TARGET exampleClient_legacy POST_BUILD COMMAND ${CMAKE_STRIP} $<TARGET_FILE:exampleClient_legacy>)
+	   endif()
+	   add_custom_command(TARGET exampleClient POST_BUILD COMMAND ${CMAKE_STRIP} $<TARGET_FILE:exampleClient>)
 	endif()
     if(EXTENSION_STATELESS)
         add_executable(statelessClient ${PROJECT_BINARY_DIR}/open62541.c examples/client_stateless.c)

+ 32 - 583
examples/client.c

@@ -1,591 +1,40 @@
-/*
- C ECHO client example using sockets
-
- This is an example client for internal benchmarks. It works, but is not ready
- for serious use. We do not really check any of the returns from the server.
- */
-#include <stdio.h> //printf
-#include <string.h> //strlen
-#include <sys/socket.h> //socket
-#include <arpa/inet.h> //inet_addr
-#include <unistd.h> // for close
-#include <stdlib.h> // pulls in declaration of malloc, free
-
 #ifdef NOT_AMALGATED
-    #include "ua_transport_generated.h"
-    #include "ua_types_encoding_binary.h"
-    #include "ua_util.h"
+    #include "ua_types.h"
+    #include "ua_client.h"
 #else
     #include "open62541.h"
 #endif
 
-typedef struct ConnectionInfo {
-	UA_Int32 socket;
-	UA_UInt32 channelId;
-	UA_SequenceHeader sequenceHdr;
-	UA_NodeId authenticationToken;
-	UA_UInt32 tokenId;
-} ConnectionInfo;
-
-static UA_Int32 sendHello(UA_Int32 sock, UA_String *endpointURL) {
-
-	UA_TcpMessageHeader messageHeader;
-	messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_HELF;
-
-	UA_TcpHelloMessage hello;
-	UA_String_copy(endpointURL, &hello.endpointUrl);
-	hello.maxChunkCount = 1;
-	hello.maxMessageSize = 16777216;
-	hello.protocolVersion = 0;
-	hello.receiveBufferSize = 65536;
-	hello.sendBufferSize = 65536;
-
-	messageHeader.messageSize = UA_TcpHelloMessage_calcSizeBinary((UA_TcpHelloMessage const*) &hello) +
-                                UA_TcpMessageHeader_calcSizeBinary((UA_TcpMessageHeader const*) &messageHeader);
-	UA_ByteString message;
-	UA_ByteString_newMembers(&message, messageHeader.messageSize);
-
-	size_t offset = 0;
-	UA_TcpMessageHeader_encodeBinary((UA_TcpMessageHeader const*) &messageHeader, &message, &offset);
-	UA_TcpHelloMessage_encodeBinary((UA_TcpHelloMessage const*) &hello, &message, &offset);
-
-	UA_Int32 sendret = send(sock, message.data, offset, 0);
-
-	UA_ByteString_deleteMembers(&message);
-	free(hello.endpointUrl.data);
-	if (sendret < 0)
-		return 1;
-	return 0;
-}
-
-static int sendOpenSecureChannel(UA_Int32 sock) {
-	UA_TcpMessageHeader msghdr;
-	msghdr.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_OPNF;
-
-	UA_UInt32 secureChannelId = 0;
-	UA_String securityPolicy;
-	UA_String_copycstring("http://opcfoundation.org/UA/SecurityPolicy#None", &securityPolicy);
-
-	UA_String senderCert;
-	senderCert.data = UA_NULL;
-	senderCert.length = -1;
-
-	UA_String receiverCertThumb;
-	receiverCertThumb.data = UA_NULL;
-	receiverCertThumb.length = -1;
-
-	UA_UInt32 sequenceNumber = 51;
-
-	UA_UInt32 requestId = 1;
-
-	UA_NodeId type;
-	type.identifier.numeric = 446; // id of opensecurechannelrequest
-	type.identifierType = UA_NODEIDTYPE_NUMERIC;
-	type.namespaceIndex = 0;
-
-	UA_OpenSecureChannelRequest opnSecRq;
-	UA_OpenSecureChannelRequest_init(&opnSecRq);
-	opnSecRq.requestHeader.timestamp = UA_DateTime_now();
-	UA_ByteString_newMembers(&opnSecRq.clientNonce, 1);
-	opnSecRq.clientNonce.data[0] = 0;
-	opnSecRq.clientProtocolVersion = 0;
-	opnSecRq.requestedLifetime = 30000;
-	opnSecRq.securityMode = UA_MESSAGESECURITYMODE_NONE;
-	opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_ISSUE;
-	opnSecRq.requestHeader.authenticationToken.identifier.numeric = 10;
-	opnSecRq.requestHeader.authenticationToken.identifierType = UA_NODEIDTYPE_NUMERIC;
-	opnSecRq.requestHeader.authenticationToken.namespaceIndex = 10;
-
-	msghdr.messageSize = 135; // todo: compute the message size from the actual content
-
-	UA_ByteString message;
-	UA_ByteString_newMembers(&message, 1000);
-	size_t offset = 0;
-	UA_TcpMessageHeader_encodeBinary(&msghdr, &message, &offset);
-	UA_UInt32_encodeBinary(&secureChannelId, &message, &offset);
-	UA_String_encodeBinary(&securityPolicy, &message, &offset);
-	UA_String_encodeBinary(&senderCert, &message, &offset);
-	UA_String_encodeBinary(&receiverCertThumb, &message, &offset);
-	UA_UInt32_encodeBinary(&sequenceNumber, &message, &offset);
-	UA_UInt32_encodeBinary(&requestId, &message, &offset);
-	UA_NodeId_encodeBinary(&type, &message, &offset);
-	UA_OpenSecureChannelRequest_encodeBinary(&opnSecRq, &message, &offset);
-
-    UA_OpenSecureChannelRequest_deleteMembers(&opnSecRq);
-	UA_String_deleteMembers(&securityPolicy);
-
-	UA_Int32 sendret = send(sock, message.data, offset, 0);
-	UA_ByteString_deleteMembers(&message);
-	if (sendret < 0) {
-		printf("send opensecurechannel failed");
-		return 1;
-	}
-	return 0;
-}
-
-static UA_Int32 sendCreateSession(UA_Int32 sock, UA_UInt32 channelId, UA_UInt32 tokenId, UA_UInt32 sequenceNumber,
-                                  UA_UInt32 requestId, UA_String *endpointUrl) {
-    UA_ByteString message;
-	UA_ByteString_newMembers(&message, 65536);
-	UA_UInt32 tmpChannelId = channelId;
-	size_t offset = 0;
-
-	UA_TcpMessageHeader msghdr;
-	msghdr.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_MSGF;
-
-	UA_NodeId type;
-	type.identifier.numeric = 461;
-	type.identifierType = UA_NODEIDTYPE_NUMERIC;
-	type.namespaceIndex = 0;
-
-	UA_CreateSessionRequest rq;
-    UA_CreateSessionRequest_init(&rq);
-	rq.requestHeader.requestHandle = 1;
-	rq.requestHeader.timestamp = UA_DateTime_now();
-	rq.requestHeader.timeoutHint = 10000;
-	rq.requestHeader.authenticationToken.identifier.numeric = 10;
-	rq.requestHeader.authenticationToken.identifierType = UA_NODEIDTYPE_NUMERIC;
-	rq.requestHeader.authenticationToken.namespaceIndex = 10;
-	UA_String_copy(endpointUrl, &rq.endpointUrl);
-	UA_String_copycstring("mysession", &rq.sessionName);
-	UA_String_copycstring("abcd", &rq.clientCertificate);
-	UA_ByteString_newMembers(&rq.clientNonce, 1);
-	rq.clientNonce.data[0] = 0;
-	rq.requestedSessionTimeout = 1200000;
-	rq.maxResponseMessageSize = UA_INT32_MAX;
-
-	msghdr.messageSize = 16 + UA_TcpMessageHeader_calcSizeBinary(&msghdr) + UA_NodeId_calcSizeBinary(&type) +
-                         UA_CreateSessionRequest_calcSizeBinary(&rq);
-
-	UA_TcpMessageHeader_encodeBinary(&msghdr, &message, &offset);
-	UA_UInt32_encodeBinary(&tmpChannelId, &message, &offset);
-	UA_UInt32_encodeBinary(&tokenId, &message, &offset);
-	UA_UInt32_encodeBinary(&sequenceNumber, &message, &offset);
-	UA_UInt32_encodeBinary(&requestId, &message, &offset);
-	UA_NodeId_encodeBinary(&type, &message, &offset);
-	UA_CreateSessionRequest_encodeBinary(&rq, &message, &offset);
-
-	UA_Int32 sendret = send(sock, message.data, offset, 0);
-	UA_ByteString_deleteMembers(&message);
-	UA_CreateSessionRequest_deleteMembers(&rq);
-	if (sendret < 0) {
-		printf("send opensecurechannel failed");
-		return 1;
-	}
-	return 0;
-}
-
-static UA_Int32 closeSession(ConnectionInfo *connectionInfo) {
-	size_t offset = 0;
-
-	UA_ByteString message;
-	UA_ByteString_newMembers(&message, 65536);
-
-	UA_CloseSessionRequest rq;
-    UA_CloseSessionRequest_init(&rq);
-
-	rq.requestHeader.requestHandle = 1;
-	rq.requestHeader.timestamp = UA_DateTime_now();
-	rq.requestHeader.timeoutHint = 10000;
-	rq.requestHeader.authenticationToken.identifier.numeric = 10;
-	rq.requestHeader.authenticationToken.identifierType = UA_NODEIDTYPE_NUMERIC;
-	rq.requestHeader.authenticationToken.namespaceIndex = 10;
-    rq.deleteSubscriptions = UA_TRUE;
-
-	UA_TcpMessageHeader msghdr;
-	msghdr.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_MSGF;
-
-	UA_NodeId type;
-	type.identifier.numeric = 473;
-	type.identifierType = UA_NODEIDTYPE_NUMERIC;
-	type.namespaceIndex = 0;
-
-	msghdr.messageSize = 16 + UA_TcpMessageHeader_calcSizeBinary(&msghdr) + UA_NodeId_calcSizeBinary(&type) +
-                         UA_CloseSessionRequest_calcSizeBinary(&rq);
-
-	UA_TcpMessageHeader_encodeBinary(&msghdr, &message, &offset);
-	UA_UInt32_encodeBinary(&connectionInfo->channelId, &message, &offset);
-	UA_UInt32_encodeBinary(&connectionInfo->tokenId, &message, &offset);
-	UA_UInt32_encodeBinary(&connectionInfo->sequenceHdr.sequenceNumber, &message, &offset);
-	UA_UInt32_encodeBinary(&connectionInfo->sequenceHdr.requestId, &message, &offset);
-	UA_NodeId_encodeBinary(&type, &message, &offset);
-	UA_CloseSessionRequest_encodeBinary(&rq, &message, &offset);
-
-	UA_Int32 sendret = send(connectionInfo->socket, message.data, offset, 0);
-	UA_ByteString_deleteMembers(&message);
-	UA_CloseSessionRequest_deleteMembers(&rq);
-	if(sendret < 0) {
-		printf("send closesessionrequest failed");
-		return 1;
-	}
-
-    return 0;
-}
-
-static UA_Int32 closeSecureChannel(ConnectionInfo *connectionInfo) {
-	size_t offset = 0;
-
-	UA_ByteString message;
-	UA_ByteString_newMembers(&message, 65536);
-
-	UA_CloseSecureChannelRequest rq;
-    UA_CloseSecureChannelRequest_init(&rq);
-
-	rq.requestHeader.requestHandle = 1;
-	rq.requestHeader.timestamp = UA_DateTime_now();
-	rq.requestHeader.timeoutHint = 10000;
-	rq.requestHeader.authenticationToken.identifier.numeric = 10;
-	rq.requestHeader.authenticationToken.identifierType = UA_NODEIDTYPE_NUMERIC;
-	rq.requestHeader.authenticationToken.namespaceIndex = 10;
-
-	UA_TcpMessageHeader msghdr;
-	msghdr.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_CLOF;
-
-	msghdr.messageSize = 4 + UA_TcpMessageHeader_calcSizeBinary(&msghdr) +
-                         UA_CloseSecureChannelRequest_calcSizeBinary(&rq);
-
-	UA_TcpMessageHeader_encodeBinary(&msghdr, &message, &offset);
-	UA_UInt32_encodeBinary(&connectionInfo->channelId, &message, &offset);
-	UA_CloseSecureChannelRequest_encodeBinary(&rq, &message, &offset);
-
-	UA_Int32 sendret = send(connectionInfo->socket, message.data, offset, 0);
-	UA_ByteString_deleteMembers(&message);
-	UA_CloseSecureChannelRequest_deleteMembers(&rq);
-	if(sendret < 0) {
-		printf("send CloseSecureChannelRequest failed");
-		return 1;
-	}
-
-    return 0;
-}
-
-static UA_Int32 sendActivateSession(UA_Int32 sock, UA_UInt32 channelId, UA_UInt32 tokenId, UA_UInt32 sequenceNumber,
-                                    UA_UInt32 requestId, UA_NodeId authenticationToken) {
-	UA_ByteString *message = UA_ByteString_new();
-	UA_ByteString_newMembers(message, 65536);
-	UA_UInt32 tmpChannelId = channelId;
-	size_t offset = 0;
-
-	UA_TcpMessageHeader msghdr;
-	msghdr.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_MSGF;
-	msghdr.messageSize = 86;
-
-	UA_NodeId type;
-	type.identifier.numeric = 467;
-	type.identifierType = UA_NODEIDTYPE_NUMERIC;
-	type.namespaceIndex = 0;
-
-	UA_ActivateSessionRequest rq;
-	UA_ActivateSessionRequest_init(&rq);
-	rq.requestHeader.requestHandle = 2;
-	rq.requestHeader.authenticationToken = authenticationToken;
-	rq.requestHeader.timestamp = UA_DateTime_now();
-	rq.requestHeader.timeoutHint = 10000;
-    
-	msghdr.messageSize  = 16 + UA_TcpMessageHeader_calcSizeBinary(&msghdr) + UA_NodeId_calcSizeBinary(&type) +
-                          UA_ActivateSessionRequest_calcSizeBinary(&rq);
-
-	UA_TcpMessageHeader_encodeBinary(&msghdr, message, &offset);
-	UA_UInt32_encodeBinary(&tmpChannelId, message, &offset);
-	UA_UInt32_encodeBinary(&tokenId, message, &offset);
-	UA_UInt32_encodeBinary(&sequenceNumber, message, &offset);
-	UA_UInt32_encodeBinary(&requestId, message, &offset);
-	UA_NodeId_encodeBinary(&type, message, &offset);
-	UA_ActivateSessionRequest_encodeBinary(&rq, message, &offset);
-
-	UA_Int32 sendret = send(sock, message->data, offset, 0);
-	UA_ByteString_delete(message);
-
-	if (sendret < 0) {
-		printf("send opensecurechannel failed");
-		return 1;
-	}
-	return 0;
-
-}
-
-static UA_Int64 sendReadRequest(ConnectionInfo *connectionInfo, UA_Int32 nodeIds_size,UA_NodeId* nodeIds){
-		/*UA_Int32 sock, UA_UInt32 channelId, UA_UInt32 tokenId, UA_UInt32 sequenceNumber, UA_UInt32 requestId,
-                         UA_NodeId authenticationToken, UA_Int32 nodeIds_size,UA_NodeId* nodeIds) {
-                         */
-	UA_ByteString *message = UA_ByteString_new();
-	UA_ByteString_newMembers(message, 65536);
-	UA_UInt32 tmpChannelId = connectionInfo->channelId;
-	size_t offset = 0;
-
-	UA_TcpMessageHeader msghdr;
-	msghdr.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_MSGF;
-
-	UA_NodeId type;
-	type.identifier.numeric = 631;
-	type.identifierType = UA_NODEIDTYPE_NUMERIC;
-	type.namespaceIndex = 0;
-
-	UA_ReadRequest rq;
-	UA_ReadRequest_init(&rq);
-	rq.maxAge = 0;
-	rq.nodesToRead = UA_Array_new(&UA_TYPES[UA_TYPES_READVALUEID], nodeIds_size);
-	rq.nodesToReadSize = 1;
-	for(UA_Int32 i=0;i<nodeIds_size;i++) {
-		UA_ReadValueId_init(&(rq.nodesToRead[i]));
-		rq.nodesToRead[i].attributeId = 6; //WriteMask
-		UA_NodeId_init(&(rq.nodesToRead[i].nodeId));
-		rq.nodesToRead[i].nodeId = nodeIds[i];
-		UA_QualifiedName_init(&(rq.nodesToRead[0].dataEncoding));
-	}
-	rq.requestHeader.timeoutHint = 10000;
-	rq.requestHeader.timestamp = UA_DateTime_now();
-	rq.requestHeader.authenticationToken = connectionInfo->authenticationToken;
-	rq.timestampsToReturn = 0x03;
-	rq.requestHeader.requestHandle = 1 + connectionInfo->sequenceHdr.requestId;
-
-	msghdr.messageSize = 16 + UA_TcpMessageHeader_calcSizeBinary(&msghdr) + UA_NodeId_calcSizeBinary(&type) +
-                         UA_ReadRequest_calcSizeBinary(&rq);
-
-	UA_TcpMessageHeader_encodeBinary(&msghdr,message,&offset);
-	UA_UInt32_encodeBinary(&tmpChannelId, message, &offset);
-	UA_UInt32_encodeBinary(&connectionInfo->tokenId, message, &offset);
-	UA_UInt32_encodeBinary(&connectionInfo->sequenceHdr.sequenceNumber, message, &offset);
-	UA_UInt32_encodeBinary(&connectionInfo->sequenceHdr.requestId, message, &offset);
-	UA_NodeId_encodeBinary(&type,message,&offset);
-	UA_ReadRequest_encodeBinary(&rq, message, &offset);
-
-	UA_DateTime tic = UA_DateTime_now();
-	UA_Int32 sendret = send(connectionInfo->socket, message->data, offset, 0);
-	UA_Array_delete(rq.nodesToRead, &UA_TYPES[UA_TYPES_READVALUEID], nodeIds_size);
-	UA_ByteString_delete(message);
-
-	if (sendret < 0) {
-		printf("send readrequest failed");
-		return 1;
-	}
-	return tic;
-}
-
-static int ua_client_connectUA(char* ipaddress,int port, UA_String *endpointUrl, ConnectionInfo *connectionInfo,
-                               UA_Boolean stateless, UA_Boolean udp) {
-	UA_ByteString reply;
-	UA_ByteString_newMembers(&reply, 65536);
-	int sock;
-	struct sockaddr_in server;
-	//Create socket
-	if(udp==UA_TRUE){
-		sock = socket(AF_INET, SOCK_DGRAM, 0);
-	}else{
-		sock = socket(AF_INET, SOCK_STREAM, 0);
-	}
-	if(sock == -1) {
-		printf("Could not create socket");
-        return 1;
-    }
-	server.sin_addr.s_addr = inet_addr(ipaddress);
-	server.sin_family = AF_INET;
-	server.sin_port = htons(port);
-
-	if(connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0) {
-			perror("connect failed. Error");
-			return 1;
-		}
-		connectionInfo->socket = sock;
-
-		if(stateless){
-			UA_NodeId_init(&connectionInfo->authenticationToken);
-			connectionInfo->channelId=0;
-			UA_SequenceHeader_init(&connectionInfo->sequenceHdr);
-			connectionInfo->tokenId=0;
-			return 0;
-		}else{
-			sendHello(sock, endpointUrl);
-			recv(sock, reply.data, reply.length, 0);
-			sendOpenSecureChannel(sock);
-			recv(sock, reply.data, reply.length, 0);
-
-			size_t recvOffset = 0;
-			UA_TcpMessageHeader msghdr;
-			UA_TcpMessageHeader_decodeBinary(&reply, &recvOffset, &msghdr);
-
-			UA_AsymmetricAlgorithmSecurityHeader asymHeader;
-			UA_NodeId rspType;
-			UA_OpenSecureChannelResponse openSecChannelRsp;
-			UA_UInt32_decodeBinary(&reply, &recvOffset, &connectionInfo->channelId);
-			UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(&reply,&recvOffset,&asymHeader);
-			UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
-			UA_SequenceHeader_decodeBinary(&reply,&recvOffset,&connectionInfo->sequenceHdr);
-			UA_NodeId_decodeBinary(&reply,&recvOffset,&rspType);
-			UA_OpenSecureChannelResponse_decodeBinary(&reply,&recvOffset,&openSecChannelRsp);
-			connectionInfo->tokenId = openSecChannelRsp.securityToken.tokenId;
-
-			sendCreateSession(sock, connectionInfo->channelId, openSecChannelRsp.securityToken.tokenId, 52, 2, endpointUrl);
-			recv(sock, reply.data, reply.length, 0);
-
-			UA_NodeId messageType;
-			recvOffset = 24;
-			UA_NodeId_decodeBinary(&reply,&recvOffset,&messageType);
-			UA_CreateSessionResponse createSessionResponse;
-			UA_CreateSessionResponse_decodeBinary(&reply,&recvOffset,&createSessionResponse);
-			connectionInfo->authenticationToken = createSessionResponse.authenticationToken;
-			sendActivateSession(sock, connectionInfo->channelId, connectionInfo->tokenId, 53, 3,
-					connectionInfo->authenticationToken);
-			recv(sock, reply.data, reply.length, 0);
-
-			UA_OpenSecureChannelResponse_deleteMembers(&openSecChannelRsp);
-
-			UA_String_deleteMembers(&reply);
-			UA_CreateSessionResponse_deleteMembers(&createSessionResponse);
-			return 0;
-		}
-}
+#include <stdio.h>
+#include "networklayer_tcp.h"
 
 int main(int argc, char *argv[]) {
-	int defaultParams = argc < 8;
-
-	//start parameters
-	if(defaultParams) {
-		printf("1st parameter: number of nodes to read \n");
-		printf("2nd parameter: number of read-tries \n");
-		printf("3rd parameter: name of the file to save measurement data \n");
-		printf("4th parameter: 1 = read same node, 0 = read different nodes \n");
-		printf("5th parameter: ip adress \n");
-		printf("6th parameter: port \n");
-		printf("7th parameter: 0=stateful, 1=stateless\n");
-		printf("8th parameter: 0=tcp, 1=udp (only with stateless calls)\n");
-		printf("\nUsing default parameters. \n");
-	}
-
-	UA_UInt32 nodesToReadSize;
-	UA_UInt32 tries;
-	UA_Boolean alwaysSameNode;
-	UA_ByteString reply;
-	UA_ByteString_newMembers(&reply, 65536);
-	UA_Boolean stateless;
-	UA_Boolean udp;
-
-	if(defaultParams)
-		nodesToReadSize = 1;
-	else
-		nodesToReadSize = atoi(argv[1]);
-
-	if(defaultParams)
-		tries= 2;
-	else
-		tries = (UA_UInt32) atoi(argv[2]);
-
-	if(defaultParams){
-		alwaysSameNode = UA_TRUE;
-	}else{
-		if(atoi(argv[4]) != 0)
-			alwaysSameNode = UA_TRUE;
-		else
-			alwaysSameNode = UA_FALSE;
-	}
-
-	if(defaultParams){
-		stateless = UA_FALSE;
-	}else{
-		if(atoi(argv[7]) != 0)
-			stateless = UA_TRUE;
-		else
-			stateless = UA_FALSE;
-	}
-
-	if(defaultParams){
-		udp = UA_FALSE;
-	}else{
-		if(atoi(argv[8]) != 0)
-			udp = UA_TRUE;
-		else
-			udp = UA_FALSE;
-	}
-
-
-
-    //Connect to remote server
-	UA_String endpoint;
-	UA_String_copycstring("none",&endpoint);
-	ConnectionInfo connectionInfo;
-
-
-/* REQUEST START*/
-    UA_NodeId *nodesToRead;
-    nodesToRead = UA_Array_new(&UA_TYPES[UA_TYPES_NODEID], 1);
-
-	for(UA_UInt32 i = 0; i<1; i++) {
-		if(alwaysSameNode)
-			nodesToRead[i].identifier.numeric = 2253; //ask always the same node
-		else
-			nodesToRead[i].identifier.numeric = 19000 +i;
-		nodesToRead[i].identifierType = UA_NODEIDTYPE_NUMERIC;
-		nodesToRead[i].namespaceIndex = 0;
-	}
-
-	UA_DateTime tic, toc;
-	UA_Double *timeDiffs;
-	UA_Int32 received;
-	timeDiffs = UA_Array_new(&UA_TYPES[UA_TYPES_DOUBLE], tries);
-	UA_Double sum = 0;
-
-	for(UA_UInt32 i = 0; i < tries; i++) {
-		//if(stateless || (!stateless && i==0)){
-		tic = UA_DateTime_now();
-			if(defaultParams){
-				if(ua_client_connectUA("127.0.0.1",atoi("16664"),&endpoint,&connectionInfo,stateless,udp) != 0){
-					return 0;
-				}
-			}else{
-				if(ua_client_connectUA(argv[5],atoi(argv[6]),&endpoint,&connectionInfo,stateless,udp) != 0){
-					return 0;
-				}
-			}
-		//}
-		for(UA_UInt32 i = 0; i < nodesToReadSize; i++) {
-		sendReadRequest(&connectionInfo,1,nodesToRead);
-		received = recv(connectionInfo.socket, reply.data, 2000, 0);
-		}
-
-		if(!stateless){
-		closeSession(&connectionInfo);
-		recv(connectionInfo.socket, reply.data, 2000, 0);
-
-		closeSecureChannel(&connectionInfo);
-		}
-		//if(stateless || (!stateless && i==tries-1)){
-			close(connectionInfo.socket);
-		//}
-		toc = UA_DateTime_now() - tic;
-		timeDiffs[i] = (UA_Double)toc/(UA_Double)1e4;
-		sum = sum + timeDiffs[i];
-	}
-/* REQUEST END*/
-
-
-	UA_Double mean = sum / tries;
-	printf("mean time for handling request: %16.10f ms \n",mean);
-
-	if(received>0)
-		printf("received: %i\n",received); // dummy
-
-	//save to file
-	char data[100];
-	const char flag = 'a';
-	FILE* fHandle = UA_NULL;
-	if (defaultParams) {
-		fHandle =  fopen("client.log", &flag);
-	}else{
-		fHandle =  fopen(argv[3], &flag);
-	}
-	//header
-
-	UA_Int32 bytesToWrite = sprintf(data, "measurement %s in ms, nodesToRead %d \n", argv[3], 1);
-	fwrite(data,1,bytesToWrite,fHandle);
-	for(UA_UInt32 i=0;i<tries;i++) {
-		bytesToWrite = sprintf(data,"%16.10f \n",timeDiffs[i]);
-		fwrite(data,1,bytesToWrite,fHandle);
-	}
-	fclose(fHandle);
-
-	UA_String_deleteMembers(&reply);
-	UA_Array_delete(nodesToRead,&UA_TYPES[UA_TYPES_NODEID], 1);
-    UA_free(timeDiffs);
-
-	return 0;
+	UA_Client *client = UA_Client_new();
+	UA_ClientNetworkLayer nl = ClientNetworkLayerTCP_new(UA_ConnectionConfig_standard);
+    //if(UA_Client_connect(client, UA_ConnectionConfig_standard, nl, "opc.tcp://localhost:48020") != UA_STATUSCODE_GOOD)
+	if(UA_Client_connect(client, UA_ConnectionConfig_standard, nl, "opc.tcp://localhost:16664") != UA_STATUSCODE_GOOD)
+    	return 0;
+
+    UA_NodeId node;
+    //node.namespaceIndex = 4;
+    //node.identifierType = UA_NODEIDTYPE_STRING;
+    //UA_String_copycstring("Demo.Static.Scalar.Int32", &node.identifier.string);
+    node.namespaceIndex = 1;
+    node.identifierType = UA_NODEIDTYPE_NUMERIC;
+    node.identifier.numeric = 76;
+
+    UA_ReadRequest read_req;
+    UA_ReadRequest_init(&read_req);
+
+    read_req.nodesToRead = UA_ReadValueId_new();
+    read_req.nodesToReadSize = 1;
+    read_req.nodesToRead[0].nodeId = node;
+    read_req.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
+    UA_ReadResponse read_resp = UA_Client_read(client, &read_req);
+    printf("the answer is: %i\n", *(UA_Int32*)read_resp.results[0].value.dataPtr);
+    UA_ReadRequest_deleteMembers(&read_req);
+    UA_ReadResponse_deleteMembers(&read_resp);
+
+    UA_Client_disconnect(client);
+    UA_Client_delete(client);
 }

+ 591 - 0
examples/client_legacy.c

@@ -0,0 +1,591 @@
+/*
+ C ECHO client example using sockets
+
+ This is an example client for internal benchmarks. It works, but is not ready
+ for serious use. We do not really check any of the returns from the server.
+ */
+#include <stdio.h> //printf
+#include <string.h> //strlen
+#include <sys/socket.h> //socket
+#include <arpa/inet.h> //inet_addr
+#include <unistd.h> // for close
+#include <stdlib.h> // pulls in declaration of malloc, free
+
+#ifdef NOT_AMALGATED
+    #include "ua_transport_generated.h"
+    #include "ua_types_encoding_binary.h"
+    #include "ua_util.h"
+#else
+    #include "open62541.h"
+#endif
+
+typedef struct ConnectionInfo {
+	UA_Int32 socket;
+	UA_UInt32 channelId;
+	UA_SequenceHeader sequenceHdr;
+	UA_NodeId authenticationToken;
+	UA_UInt32 tokenId;
+} ConnectionInfo;
+
+static UA_Int32 sendHello(UA_Int32 sock, UA_String *endpointURL) {
+
+	UA_TcpMessageHeader messageHeader;
+	messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_HELF;
+
+	UA_TcpHelloMessage hello;
+	UA_String_copy(endpointURL, &hello.endpointUrl);
+	hello.maxChunkCount = 1;
+	hello.maxMessageSize = 16777216;
+	hello.protocolVersion = 0;
+	hello.receiveBufferSize = 65536;
+	hello.sendBufferSize = 65536;
+
+	messageHeader.messageSize = UA_TcpHelloMessage_calcSizeBinary((UA_TcpHelloMessage const*) &hello) +
+                                UA_TcpMessageHeader_calcSizeBinary((UA_TcpMessageHeader const*) &messageHeader);
+	UA_ByteString message;
+	UA_ByteString_newMembers(&message, messageHeader.messageSize);
+
+	size_t offset = 0;
+	UA_TcpMessageHeader_encodeBinary((UA_TcpMessageHeader const*) &messageHeader, &message, &offset);
+	UA_TcpHelloMessage_encodeBinary((UA_TcpHelloMessage const*) &hello, &message, &offset);
+
+	UA_Int32 sendret = send(sock, message.data, offset, 0);
+
+	UA_ByteString_deleteMembers(&message);
+	free(hello.endpointUrl.data);
+	if (sendret < 0)
+		return 1;
+	return 0;
+}
+
+static int sendOpenSecureChannel(UA_Int32 sock) {
+	UA_TcpMessageHeader msghdr;
+	msghdr.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_OPNF;
+
+	UA_UInt32 secureChannelId = 0;
+	UA_String securityPolicy;
+	UA_String_copycstring("http://opcfoundation.org/UA/SecurityPolicy#None", &securityPolicy);
+
+	UA_String senderCert;
+	senderCert.data = UA_NULL;
+	senderCert.length = -1;
+
+	UA_String receiverCertThumb;
+	receiverCertThumb.data = UA_NULL;
+	receiverCertThumb.length = -1;
+
+	UA_UInt32 sequenceNumber = 51;
+
+	UA_UInt32 requestId = 1;
+
+	UA_NodeId type;
+	type.identifier.numeric = 446; // id of opensecurechannelrequest
+	type.identifierType = UA_NODEIDTYPE_NUMERIC;
+	type.namespaceIndex = 0;
+
+	UA_OpenSecureChannelRequest opnSecRq;
+	UA_OpenSecureChannelRequest_init(&opnSecRq);
+	opnSecRq.requestHeader.timestamp = UA_DateTime_now();
+	UA_ByteString_newMembers(&opnSecRq.clientNonce, 1);
+	opnSecRq.clientNonce.data[0] = 0;
+	opnSecRq.clientProtocolVersion = 0;
+	opnSecRq.requestedLifetime = 30000;
+	opnSecRq.securityMode = UA_MESSAGESECURITYMODE_NONE;
+	opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_ISSUE;
+	opnSecRq.requestHeader.authenticationToken.identifier.numeric = 10;
+	opnSecRq.requestHeader.authenticationToken.identifierType = UA_NODEIDTYPE_NUMERIC;
+	opnSecRq.requestHeader.authenticationToken.namespaceIndex = 10;
+
+	msghdr.messageSize = 135; // todo: compute the message size from the actual content
+
+	UA_ByteString message;
+	UA_ByteString_newMembers(&message, 1000);
+	size_t offset = 0;
+	UA_TcpMessageHeader_encodeBinary(&msghdr, &message, &offset);
+	UA_UInt32_encodeBinary(&secureChannelId, &message, &offset);
+	UA_String_encodeBinary(&securityPolicy, &message, &offset);
+	UA_String_encodeBinary(&senderCert, &message, &offset);
+	UA_String_encodeBinary(&receiverCertThumb, &message, &offset);
+	UA_UInt32_encodeBinary(&sequenceNumber, &message, &offset);
+	UA_UInt32_encodeBinary(&requestId, &message, &offset);
+	UA_NodeId_encodeBinary(&type, &message, &offset);
+	UA_OpenSecureChannelRequest_encodeBinary(&opnSecRq, &message, &offset);
+
+    UA_OpenSecureChannelRequest_deleteMembers(&opnSecRq);
+	UA_String_deleteMembers(&securityPolicy);
+
+	UA_Int32 sendret = send(sock, message.data, offset, 0);
+	UA_ByteString_deleteMembers(&message);
+	if (sendret < 0) {
+		printf("send opensecurechannel failed");
+		return 1;
+	}
+	return 0;
+}
+
+static UA_Int32 sendCreateSession(UA_Int32 sock, UA_UInt32 channelId, UA_UInt32 tokenId, UA_UInt32 sequenceNumber,
+                                  UA_UInt32 requestId, UA_String *endpointUrl) {
+    UA_ByteString message;
+	UA_ByteString_newMembers(&message, 65536);
+	UA_UInt32 tmpChannelId = channelId;
+	size_t offset = 0;
+
+	UA_TcpMessageHeader msghdr;
+	msghdr.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_MSGF;
+
+	UA_NodeId type;
+	type.identifier.numeric = 461;
+	type.identifierType = UA_NODEIDTYPE_NUMERIC;
+	type.namespaceIndex = 0;
+
+	UA_CreateSessionRequest rq;
+    UA_CreateSessionRequest_init(&rq);
+	rq.requestHeader.requestHandle = 1;
+	rq.requestHeader.timestamp = UA_DateTime_now();
+	rq.requestHeader.timeoutHint = 10000;
+	rq.requestHeader.authenticationToken.identifier.numeric = 10;
+	rq.requestHeader.authenticationToken.identifierType = UA_NODEIDTYPE_NUMERIC;
+	rq.requestHeader.authenticationToken.namespaceIndex = 10;
+	UA_String_copy(endpointUrl, &rq.endpointUrl);
+	UA_String_copycstring("mysession", &rq.sessionName);
+	UA_String_copycstring("abcd", &rq.clientCertificate);
+	UA_ByteString_newMembers(&rq.clientNonce, 1);
+	rq.clientNonce.data[0] = 0;
+	rq.requestedSessionTimeout = 1200000;
+	rq.maxResponseMessageSize = UA_INT32_MAX;
+
+	msghdr.messageSize = 16 + UA_TcpMessageHeader_calcSizeBinary(&msghdr) + UA_NodeId_calcSizeBinary(&type) +
+                         UA_CreateSessionRequest_calcSizeBinary(&rq);
+
+	UA_TcpMessageHeader_encodeBinary(&msghdr, &message, &offset);
+	UA_UInt32_encodeBinary(&tmpChannelId, &message, &offset);
+	UA_UInt32_encodeBinary(&tokenId, &message, &offset);
+	UA_UInt32_encodeBinary(&sequenceNumber, &message, &offset);
+	UA_UInt32_encodeBinary(&requestId, &message, &offset);
+	UA_NodeId_encodeBinary(&type, &message, &offset);
+	UA_CreateSessionRequest_encodeBinary(&rq, &message, &offset);
+
+	UA_Int32 sendret = send(sock, message.data, offset, 0);
+	UA_ByteString_deleteMembers(&message);
+	UA_CreateSessionRequest_deleteMembers(&rq);
+	if (sendret < 0) {
+		printf("send opensecurechannel failed");
+		return 1;
+	}
+	return 0;
+}
+
+static UA_Int32 closeSession(ConnectionInfo *connectionInfo) {
+	size_t offset = 0;
+
+	UA_ByteString message;
+	UA_ByteString_newMembers(&message, 65536);
+
+	UA_CloseSessionRequest rq;
+    UA_CloseSessionRequest_init(&rq);
+
+	rq.requestHeader.requestHandle = 1;
+	rq.requestHeader.timestamp = UA_DateTime_now();
+	rq.requestHeader.timeoutHint = 10000;
+	rq.requestHeader.authenticationToken.identifier.numeric = 10;
+	rq.requestHeader.authenticationToken.identifierType = UA_NODEIDTYPE_NUMERIC;
+	rq.requestHeader.authenticationToken.namespaceIndex = 10;
+    rq.deleteSubscriptions = UA_TRUE;
+
+	UA_TcpMessageHeader msghdr;
+	msghdr.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_MSGF;
+
+	UA_NodeId type;
+	type.identifier.numeric = 473;
+	type.identifierType = UA_NODEIDTYPE_NUMERIC;
+	type.namespaceIndex = 0;
+
+	msghdr.messageSize = 16 + UA_TcpMessageHeader_calcSizeBinary(&msghdr) + UA_NodeId_calcSizeBinary(&type) +
+                         UA_CloseSessionRequest_calcSizeBinary(&rq);
+
+	UA_TcpMessageHeader_encodeBinary(&msghdr, &message, &offset);
+	UA_UInt32_encodeBinary(&connectionInfo->channelId, &message, &offset);
+	UA_UInt32_encodeBinary(&connectionInfo->tokenId, &message, &offset);
+	UA_UInt32_encodeBinary(&connectionInfo->sequenceHdr.sequenceNumber, &message, &offset);
+	UA_UInt32_encodeBinary(&connectionInfo->sequenceHdr.requestId, &message, &offset);
+	UA_NodeId_encodeBinary(&type, &message, &offset);
+	UA_CloseSessionRequest_encodeBinary(&rq, &message, &offset);
+
+	UA_Int32 sendret = send(connectionInfo->socket, message.data, offset, 0);
+	UA_ByteString_deleteMembers(&message);
+	UA_CloseSessionRequest_deleteMembers(&rq);
+	if(sendret < 0) {
+		printf("send closesessionrequest failed");
+		return 1;
+	}
+
+    return 0;
+}
+
+static UA_Int32 closeSecureChannel(ConnectionInfo *connectionInfo) {
+	size_t offset = 0;
+
+	UA_ByteString message;
+	UA_ByteString_newMembers(&message, 65536);
+
+	UA_CloseSecureChannelRequest rq;
+    UA_CloseSecureChannelRequest_init(&rq);
+
+	rq.requestHeader.requestHandle = 1;
+	rq.requestHeader.timestamp = UA_DateTime_now();
+	rq.requestHeader.timeoutHint = 10000;
+	rq.requestHeader.authenticationToken.identifier.numeric = 10;
+	rq.requestHeader.authenticationToken.identifierType = UA_NODEIDTYPE_NUMERIC;
+	rq.requestHeader.authenticationToken.namespaceIndex = 10;
+
+	UA_TcpMessageHeader msghdr;
+	msghdr.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_CLOF;
+
+	msghdr.messageSize = 4 + UA_TcpMessageHeader_calcSizeBinary(&msghdr) +
+                         UA_CloseSecureChannelRequest_calcSizeBinary(&rq);
+
+	UA_TcpMessageHeader_encodeBinary(&msghdr, &message, &offset);
+	UA_UInt32_encodeBinary(&connectionInfo->channelId, &message, &offset);
+	UA_CloseSecureChannelRequest_encodeBinary(&rq, &message, &offset);
+
+	UA_Int32 sendret = send(connectionInfo->socket, message.data, offset, 0);
+	UA_ByteString_deleteMembers(&message);
+	UA_CloseSecureChannelRequest_deleteMembers(&rq);
+	if(sendret < 0) {
+		printf("send CloseSecureChannelRequest failed");
+		return 1;
+	}
+
+    return 0;
+}
+
+static UA_Int32 sendActivateSession(UA_Int32 sock, UA_UInt32 channelId, UA_UInt32 tokenId, UA_UInt32 sequenceNumber,
+                                    UA_UInt32 requestId, UA_NodeId authenticationToken) {
+	UA_ByteString *message = UA_ByteString_new();
+	UA_ByteString_newMembers(message, 65536);
+	UA_UInt32 tmpChannelId = channelId;
+	size_t offset = 0;
+
+	UA_TcpMessageHeader msghdr;
+	msghdr.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_MSGF;
+	msghdr.messageSize = 86;
+
+	UA_NodeId type;
+	type.identifier.numeric = 467;
+	type.identifierType = UA_NODEIDTYPE_NUMERIC;
+	type.namespaceIndex = 0;
+
+	UA_ActivateSessionRequest rq;
+	UA_ActivateSessionRequest_init(&rq);
+	rq.requestHeader.requestHandle = 2;
+	rq.requestHeader.authenticationToken = authenticationToken;
+	rq.requestHeader.timestamp = UA_DateTime_now();
+	rq.requestHeader.timeoutHint = 10000;
+    
+	msghdr.messageSize  = 16 + UA_TcpMessageHeader_calcSizeBinary(&msghdr) + UA_NodeId_calcSizeBinary(&type) +
+                          UA_ActivateSessionRequest_calcSizeBinary(&rq);
+
+	UA_TcpMessageHeader_encodeBinary(&msghdr, message, &offset);
+	UA_UInt32_encodeBinary(&tmpChannelId, message, &offset);
+	UA_UInt32_encodeBinary(&tokenId, message, &offset);
+	UA_UInt32_encodeBinary(&sequenceNumber, message, &offset);
+	UA_UInt32_encodeBinary(&requestId, message, &offset);
+	UA_NodeId_encodeBinary(&type, message, &offset);
+	UA_ActivateSessionRequest_encodeBinary(&rq, message, &offset);
+
+	UA_Int32 sendret = send(sock, message->data, offset, 0);
+	UA_ByteString_delete(message);
+
+	if (sendret < 0) {
+		printf("send opensecurechannel failed");
+		return 1;
+	}
+	return 0;
+
+}
+
+static UA_Int64 sendReadRequest(ConnectionInfo *connectionInfo, UA_Int32 nodeIds_size,UA_NodeId* nodeIds){
+		/*UA_Int32 sock, UA_UInt32 channelId, UA_UInt32 tokenId, UA_UInt32 sequenceNumber, UA_UInt32 requestId,
+                         UA_NodeId authenticationToken, UA_Int32 nodeIds_size,UA_NodeId* nodeIds) {
+                         */
+	UA_ByteString *message = UA_ByteString_new();
+	UA_ByteString_newMembers(message, 65536);
+	UA_UInt32 tmpChannelId = connectionInfo->channelId;
+	size_t offset = 0;
+
+	UA_TcpMessageHeader msghdr;
+	msghdr.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_MSGF;
+
+	UA_NodeId type;
+	type.identifier.numeric = 631;
+	type.identifierType = UA_NODEIDTYPE_NUMERIC;
+	type.namespaceIndex = 0;
+
+	UA_ReadRequest rq;
+	UA_ReadRequest_init(&rq);
+	rq.maxAge = 0;
+	rq.nodesToRead = UA_Array_new(&UA_TYPES[UA_TYPES_READVALUEID], nodeIds_size);
+	rq.nodesToReadSize = 1;
+	for(UA_Int32 i=0;i<nodeIds_size;i++) {
+		UA_ReadValueId_init(&(rq.nodesToRead[i]));
+		rq.nodesToRead[i].attributeId = 6; //WriteMask
+		UA_NodeId_init(&(rq.nodesToRead[i].nodeId));
+		rq.nodesToRead[i].nodeId = nodeIds[i];
+		UA_QualifiedName_init(&(rq.nodesToRead[0].dataEncoding));
+	}
+	rq.requestHeader.timeoutHint = 10000;
+	rq.requestHeader.timestamp = UA_DateTime_now();
+	rq.requestHeader.authenticationToken = connectionInfo->authenticationToken;
+	rq.timestampsToReturn = 0x03;
+	rq.requestHeader.requestHandle = 1 + connectionInfo->sequenceHdr.requestId;
+
+	msghdr.messageSize = 16 + UA_TcpMessageHeader_calcSizeBinary(&msghdr) + UA_NodeId_calcSizeBinary(&type) +
+                         UA_ReadRequest_calcSizeBinary(&rq);
+
+	UA_TcpMessageHeader_encodeBinary(&msghdr,message,&offset);
+	UA_UInt32_encodeBinary(&tmpChannelId, message, &offset);
+	UA_UInt32_encodeBinary(&connectionInfo->tokenId, message, &offset);
+	UA_UInt32_encodeBinary(&connectionInfo->sequenceHdr.sequenceNumber, message, &offset);
+	UA_UInt32_encodeBinary(&connectionInfo->sequenceHdr.requestId, message, &offset);
+	UA_NodeId_encodeBinary(&type,message,&offset);
+	UA_ReadRequest_encodeBinary(&rq, message, &offset);
+
+	UA_DateTime tic = UA_DateTime_now();
+	UA_Int32 sendret = send(connectionInfo->socket, message->data, offset, 0);
+	UA_Array_delete(rq.nodesToRead, &UA_TYPES[UA_TYPES_READVALUEID], nodeIds_size);
+	UA_ByteString_delete(message);
+
+	if (sendret < 0) {
+		printf("send readrequest failed");
+		return 1;
+	}
+	return tic;
+}
+
+static int ua_client_connectUA(char* ipaddress,int port, UA_String *endpointUrl, ConnectionInfo *connectionInfo,
+                               UA_Boolean stateless, UA_Boolean udp) {
+	UA_ByteString reply;
+	UA_ByteString_newMembers(&reply, 65536);
+	int sock;
+	struct sockaddr_in server;
+	//Create socket
+	if(udp==UA_TRUE){
+		sock = socket(AF_INET, SOCK_DGRAM, 0);
+	}else{
+		sock = socket(AF_INET, SOCK_STREAM, 0);
+	}
+	if(sock == -1) {
+		printf("Could not create socket");
+        return 1;
+    }
+	server.sin_addr.s_addr = inet_addr(ipaddress);
+	server.sin_family = AF_INET;
+	server.sin_port = htons(port);
+
+	if(connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0) {
+			perror("connect failed. Error");
+			return 1;
+		}
+		connectionInfo->socket = sock;
+
+		if(stateless){
+			UA_NodeId_init(&connectionInfo->authenticationToken);
+			connectionInfo->channelId=0;
+			UA_SequenceHeader_init(&connectionInfo->sequenceHdr);
+			connectionInfo->tokenId=0;
+			return 0;
+		}else{
+			sendHello(sock, endpointUrl);
+			recv(sock, reply.data, reply.length, 0);
+			sendOpenSecureChannel(sock);
+			recv(sock, reply.data, reply.length, 0);
+
+			size_t recvOffset = 0;
+			UA_TcpMessageHeader msghdr;
+			UA_TcpMessageHeader_decodeBinary(&reply, &recvOffset, &msghdr);
+
+			UA_AsymmetricAlgorithmSecurityHeader asymHeader;
+			UA_NodeId rspType;
+			UA_OpenSecureChannelResponse openSecChannelRsp;
+			UA_UInt32_decodeBinary(&reply, &recvOffset, &connectionInfo->channelId);
+			UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(&reply,&recvOffset,&asymHeader);
+			UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
+			UA_SequenceHeader_decodeBinary(&reply,&recvOffset,&connectionInfo->sequenceHdr);
+			UA_NodeId_decodeBinary(&reply,&recvOffset,&rspType);
+			UA_OpenSecureChannelResponse_decodeBinary(&reply,&recvOffset,&openSecChannelRsp);
+			connectionInfo->tokenId = openSecChannelRsp.securityToken.tokenId;
+
+			sendCreateSession(sock, connectionInfo->channelId, openSecChannelRsp.securityToken.tokenId, 52, 2, endpointUrl);
+			recv(sock, reply.data, reply.length, 0);
+
+			UA_NodeId messageType;
+			recvOffset = 24;
+			UA_NodeId_decodeBinary(&reply,&recvOffset,&messageType);
+			UA_CreateSessionResponse createSessionResponse;
+			UA_CreateSessionResponse_decodeBinary(&reply,&recvOffset,&createSessionResponse);
+			connectionInfo->authenticationToken = createSessionResponse.authenticationToken;
+			sendActivateSession(sock, connectionInfo->channelId, connectionInfo->tokenId, 53, 3,
+					connectionInfo->authenticationToken);
+			recv(sock, reply.data, reply.length, 0);
+
+			UA_OpenSecureChannelResponse_deleteMembers(&openSecChannelRsp);
+
+			UA_String_deleteMembers(&reply);
+			UA_CreateSessionResponse_deleteMembers(&createSessionResponse);
+			return 0;
+		}
+}
+
+int main(int argc, char *argv[]) {
+	int defaultParams = argc < 8;
+
+	//start parameters
+	if(defaultParams) {
+		printf("1st parameter: number of nodes to read \n");
+		printf("2nd parameter: number of read-tries \n");
+		printf("3rd parameter: name of the file to save measurement data \n");
+		printf("4th parameter: 1 = read same node, 0 = read different nodes \n");
+		printf("5th parameter: ip adress \n");
+		printf("6th parameter: port \n");
+		printf("7th parameter: 0=stateful, 1=stateless\n");
+		printf("8th parameter: 0=tcp, 1=udp (only with stateless calls)\n");
+		printf("\nUsing default parameters. \n");
+	}
+
+	UA_UInt32 nodesToReadSize;
+	UA_UInt32 tries;
+	UA_Boolean alwaysSameNode;
+	UA_ByteString reply;
+	UA_ByteString_newMembers(&reply, 65536);
+	UA_Boolean stateless;
+	UA_Boolean udp;
+
+	if(defaultParams)
+		nodesToReadSize = 1;
+	else
+		nodesToReadSize = atoi(argv[1]);
+
+	if(defaultParams)
+		tries= 2;
+	else
+		tries = (UA_UInt32) atoi(argv[2]);
+
+	if(defaultParams){
+		alwaysSameNode = UA_TRUE;
+	}else{
+		if(atoi(argv[4]) != 0)
+			alwaysSameNode = UA_TRUE;
+		else
+			alwaysSameNode = UA_FALSE;
+	}
+
+	if(defaultParams){
+		stateless = UA_FALSE;
+	}else{
+		if(atoi(argv[7]) != 0)
+			stateless = UA_TRUE;
+		else
+			stateless = UA_FALSE;
+	}
+
+	if(defaultParams){
+		udp = UA_FALSE;
+	}else{
+		if(atoi(argv[8]) != 0)
+			udp = UA_TRUE;
+		else
+			udp = UA_FALSE;
+	}
+
+
+
+    //Connect to remote server
+	UA_String endpoint;
+	UA_String_copycstring("none",&endpoint);
+	ConnectionInfo connectionInfo;
+
+
+/* REQUEST START*/
+    UA_NodeId *nodesToRead;
+    nodesToRead = UA_Array_new(&UA_TYPES[UA_TYPES_NODEID], 1);
+
+	for(UA_UInt32 i = 0; i<1; i++) {
+		if(alwaysSameNode)
+			nodesToRead[i].identifier.numeric = 2253; //ask always the same node
+		else
+			nodesToRead[i].identifier.numeric = 19000 +i;
+		nodesToRead[i].identifierType = UA_NODEIDTYPE_NUMERIC;
+		nodesToRead[i].namespaceIndex = 0;
+	}
+
+	UA_DateTime tic, toc;
+	UA_Double *timeDiffs;
+	UA_Int32 received;
+	timeDiffs = UA_Array_new(&UA_TYPES[UA_TYPES_DOUBLE], tries);
+	UA_Double sum = 0;
+
+	for(UA_UInt32 i = 0; i < tries; i++) {
+		//if(stateless || (!stateless && i==0)){
+		tic = UA_DateTime_now();
+			if(defaultParams){
+				if(ua_client_connectUA("127.0.0.1",atoi("16664"),&endpoint,&connectionInfo,stateless,udp) != 0){
+					return 0;
+				}
+			}else{
+				if(ua_client_connectUA(argv[5],atoi(argv[6]),&endpoint,&connectionInfo,stateless,udp) != 0){
+					return 0;
+				}
+			}
+		//}
+		for(UA_UInt32 i = 0; i < nodesToReadSize; i++) {
+		sendReadRequest(&connectionInfo,1,nodesToRead);
+		received = recv(connectionInfo.socket, reply.data, 2000, 0);
+		}
+
+		if(!stateless){
+		closeSession(&connectionInfo);
+		recv(connectionInfo.socket, reply.data, 2000, 0);
+
+		closeSecureChannel(&connectionInfo);
+		}
+		//if(stateless || (!stateless && i==tries-1)){
+			close(connectionInfo.socket);
+		//}
+		toc = UA_DateTime_now() - tic;
+		timeDiffs[i] = (UA_Double)toc/(UA_Double)1e4;
+		sum = sum + timeDiffs[i];
+	}
+/* REQUEST END*/
+
+
+	UA_Double mean = sum / tries;
+	printf("mean time for handling request: %16.10f ms \n",mean);
+
+	if(received>0)
+		printf("received: %i\n",received); // dummy
+
+	//save to file
+	char data[100];
+	const char flag = 'a';
+	FILE* fHandle = UA_NULL;
+	if (defaultParams) {
+		fHandle =  fopen("client.log", &flag);
+	}else{
+		fHandle =  fopen(argv[3], &flag);
+	}
+	//header
+
+	UA_Int32 bytesToWrite = sprintf(data, "measurement %s in ms, nodesToRead %d \n", argv[3], 1);
+	fwrite(data,1,bytesToWrite,fHandle);
+	for(UA_UInt32 i=0;i<tries;i++) {
+		bytesToWrite = sprintf(data,"%16.10f \n",timeDiffs[i]);
+		fwrite(data,1,bytesToWrite,fHandle);
+	}
+	fclose(fHandle);
+
+	UA_String_deleteMembers(&reply);
+	UA_Array_delete(nodesToRead,&UA_TYPES[UA_TYPES_NODEID], 1);
+    UA_free(timeDiffs);
+
+	return 0;
+}

+ 0 - 36
examples/client_proper.c

@@ -1,36 +0,0 @@
-#ifdef NOT_AMALGATED
-    #include "ua_types.h"
-    #include "ua_client.h"
-#else
-    #include "open62541.h"
-#endif
-
-#include <stdio.h>
-#include "networklayer_tcp.h"
-
-int main(int argc, char *argv[]) {
-	UA_Client *client = UA_Client_new();
-	UA_ClientNetworkLayer nl = ClientNetworkLayerTCP_new(UA_ConnectionConfig_standard);
-    if(UA_Client_connect(client, UA_ConnectionConfig_standard, nl, "opc.tcp://localhost:48020") != UA_STATUSCODE_GOOD)
-    	return 0;
-
-    UA_NodeId node;
-    node.namespaceIndex = 4;
-    node.identifierType = UA_NODEIDTYPE_STRING;
-    UA_String_copycstring("Demo.Static.Scalar.Int32", &node.identifier.string);
-
-    UA_ReadRequest read_req;
-    UA_ReadRequest_init(&read_req);
-
-    read_req.nodesToRead = UA_ReadValueId_new();
-    read_req.nodesToReadSize = 1;
-    read_req.nodesToRead[0].nodeId = node;
-    read_req.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
-    UA_ReadResponse read_resp = UA_Client_read(client, &read_req);
-    printf("the answer is: %i\n", *(UA_Int32*)read_resp.results[0].value.dataPtr);
-    UA_ReadRequest_deleteMembers(&read_req);
-    UA_ReadResponse_deleteMembers(&read_resp);
-
-    UA_Client_disconnect(client);
-    UA_Client_delete(client);
-}

+ 4 - 0
examples/networklayer_tcp.c

@@ -477,6 +477,10 @@ static UA_StatusCode ClientNetworkLayerTCP_connect(const UA_String endpointUrl,
     UA_Int32 sock = 0;
 #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) {

+ 224 - 59
examples/server.c

@@ -2,12 +2,6 @@
  * This work is licensed under a Creative Commons CCZero 1.0 Universal License.
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
  */
-#include <time.h>
-#include <stdio.h>
-#include <stdlib.h> 
-#include <signal.h>
-#include <errno.h> // errno, EINTR
-
 #ifdef NOT_AMALGATED
     #include "ua_types.h"
     #include "ua_server.h"
@@ -15,60 +9,227 @@
     #include "open62541.h"
 #endif
 
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h> 
+#include <signal.h>
+#define __USE_XOPEN2K
+#ifdef UA_MULTITHREADING
+#include <pthread.h>
+#endif
+
 // provided by the user, implementations available in the /examples folder
 #include "logger_stdout.h"
 #include "networklayer_tcp.h"
 
+/****************************/
+/* Server-related variables */
+/****************************/
+
 UA_Boolean running = 1;
 UA_Logger logger;
 
-static void stopHandler(int sign) {
-    printf("Received Ctrl-C\n");
-	running = 0;
+/*************************/
+/* Read-only data source */
+/*************************/
+static UA_StatusCode readTimeData(const void *handle, UA_Boolean sourceTimeStamp, UA_DataValue *value) {
+	UA_DateTime *currentTime = UA_DateTime_new();
+	if(!currentTime)
+		return UA_STATUSCODE_BADOUTOFMEMORY;
+	*currentTime = UA_DateTime_now();
+	value->value.type = &UA_TYPES[UA_TYPES_DATETIME];
+	value->value.arrayLength = -1;
+	value->value.dataPtr = currentTime;
+	value->value.arrayDimensionsSize = -1;
+	value->value.arrayDimensions = NULL;
+	value->hasVariant = UA_TRUE;
+	if(sourceTimeStamp) {
+		value->hasSourceTimestamp = UA_TRUE;
+		value->sourceTimestamp = *currentTime;
+	}
+	return UA_STATUSCODE_GOOD;
+}
+
+static void releaseTimeData(const void *handle, UA_DataValue *value) {
+	UA_DateTime_delete((UA_DateTime*)value->value.dataPtr);
+}
+
+/*****************************/
+/* Read-only CPU temperature */
+/*      Only on Linux        */
+/*****************************/
+FILE* temperatureFile = NULL;
+static UA_StatusCode readTemperature(const void *handle, UA_Boolean sourceTimeStamp, UA_DataValue *value) {
+	UA_Double* currentTemperature = UA_Double_new();
+
+	if(!currentTemperature)
+		return UA_STATUSCODE_BADOUTOFMEMORY;
+
+	fseek(temperatureFile, 0, SEEK_SET);
+
+	if(fscanf(temperatureFile, "%lf", currentTemperature) != 1){
+		UA_LOG_WARNING(logger, UA_LOGGERCATEGORY_USERLAND, "Can not parse temperature");
+		exit(1);
+	}
+
+	*currentTemperature /= 1000.0;
+
+	value->value.type = &UA_TYPES[UA_TYPES_DOUBLE];
+	value->value.arrayLength = -1;
+	value->value.dataPtr = currentTemperature;
+	value->value.arrayDimensionsSize = -1;
+	value->value.arrayDimensions = NULL;
+	value->hasVariant = UA_TRUE;
+	return UA_STATUSCODE_GOOD;
+}
+
+static void releaseTemperature(const void *handle, UA_DataValue *value) {
+	UA_Double_delete((UA_Double*)value->value.dataPtr);
+}
+
+/*************************/
+/* Read-write status led */
+/*************************/
+#ifdef UA_MULTITHREADING
+pthread_rwlock_t writeLock;
+#endif
+FILE* triggerFile = NULL;
+FILE* ledFile = NULL;
+UA_Boolean ledStatus = 0;
+
+static UA_StatusCode readLedStatus(const void *handle, UA_Boolean sourceTimeStamp, UA_DataValue *value) {
+	/* In order to reduce blocking time, we could alloc memory for every read
+       and return a copy of the data. */
+#ifdef UA_MULTITHREADING
+	pthread_rwlock_rdlock(&writeLock);
+#endif
+	value->value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
+	value->value.arrayLength = -1;
+	value->value.dataPtr = &ledStatus;
+	value->value.arrayDimensionsSize = -1;
+	value->value.arrayDimensions = NULL;
+	value->hasVariant = UA_TRUE;
+	if(sourceTimeStamp) {
+		value->sourceTimestamp = UA_DateTime_now();
+		value->hasSourceTimestamp = UA_TRUE;
+	}
+	return UA_STATUSCODE_GOOD;
+}
+
+static void releaseLedStatus(const void *handle, UA_DataValue *value) {
+	/* If we allocated memory for a specific read, free the content of the
+       variantdata. */
+	value->value.arrayLength = -1;
+	value->value.dataPtr = NULL;
+#ifdef UA_MULTITHREADING
+	pthread_rwlock_unlock(&writeLock);
+#endif
+}
+
+static UA_StatusCode writeLedStatus(const void *handle, const UA_Variant *data) {
+#ifdef UA_MULTITHREADING
+	pthread_rwlock_wrlock(&writeLock);
+#endif
+	if(data->dataPtr)
+		ledStatus = *(UA_Boolean*)data->dataPtr;
+
+	if(triggerFile)
+		fseek(triggerFile, 0, SEEK_SET);
+
+	if(ledFile){
+		if(ledStatus == 1){
+			fprintf(ledFile, "%s", "1");
+		} else {
+			fprintf(ledFile, "%s", "0");
+		}
+		fflush(ledFile);
+	}
+#ifdef UA_MULTITHREADING
+	pthread_rwlock_unlock(&writeLock);
+#endif
+	return UA_STATUSCODE_GOOD;
 }
 
-static UA_ByteString loadCertificate(void) {
-    UA_ByteString certificate = UA_STRING_NULL;
-	FILE *fp = NULL;
-	//FIXME: a potiential bug of locating the certificate, we need to get the path from the server's config
-	fp=fopen("localhost.der", "rb");
-
-	if(!fp) {
-        errno = 0; // we read errno also from the tcp layer...
-        return certificate;
-    }
-
-    fseek(fp, 0, SEEK_END);
-    certificate.length = ftell(fp);
-    certificate.data = malloc(certificate.length*sizeof(UA_Byte));
-	if(!certificate.data)
-		return certificate;
-
-    fseek(fp, 0, SEEK_SET);
-    if(fread(certificate.data, sizeof(UA_Byte), certificate.length, fp) < (size_t)certificate.length)
-        UA_ByteString_deleteMembers(&certificate); // error reading the cert
-    fclose(fp);
-
-    return certificate;
+static void printLedStatus(UA_Server *server, void *data) {
+	UA_LOG_INFO(logger, UA_LOGGERCATEGORY_SERVER, ledStatus ? "LED is on" : "LED is off");
 }
 
-static void testCallback(UA_Server *server, void *data) {
-    logger.log_info(UA_LOGGERCATEGORY_USERLAND, "testcallback");
+static void stopHandler(int sign) {
+	printf("Received Ctrl-C\n");
+	running = 0;
 }
 
 int main(int argc, char** argv) {
 	signal(SIGINT, stopHandler); /* catches ctrl-c */
+#ifdef UA_MULTITHREADING
+	pthread_rwlock_init(&writeLock, 0);
+#endif
 
 	UA_Server *server = UA_Server_new();
-    logger = Logger_Stdout_new();
-    UA_Server_setLogger(server, logger);
-    UA_Server_setServerCertificate(server, loadCertificate());
-    UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
+	logger = Logger_Stdout_new();
+	UA_Server_setLogger(server, logger);
+	UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
+
+	// print the status every 2 sec
+	UA_WorkItem work = {.type = UA_WORKITEMTYPE_METHODCALL,
+			.work.methodCall = {.method = printLedStatus, .data = NULL} };
+	UA_Server_addRepeatedWorkItem(server, &work, 20000000, NULL);
+
+	// add node with the datetime data source
+	UA_DataSource dateDataSource = (UA_DataSource)
+        {.handle = NULL,
+		.read = readTimeData,
+		.release = releaseTimeData,
+		.write = NULL};
+	UA_QualifiedName dateName;
+	UA_QUALIFIEDNAME_ASSIGN(dateName, "current time");
+	UA_Server_addDataSourceVariableNode(server, dateDataSource, dateName, UA_NODEID_NULL,
+                                        UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                        UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+
+	if(!(temperatureFile = fopen("/sys/class/thermal/thermal_zone0/temp", "r"))){
+		UA_LOG_WARNING(logger, UA_LOGGERCATEGORY_USERLAND, "[Linux specific] Can not open temperature file, no temperature node will be added");
+	} else {
+		// add node with the datetime data source
+		UA_DataSource temperatureDataSource = (UA_DataSource)
+    	    {.handle = NULL,
+			.read = readTemperature,
+			.release = releaseTemperature,
+			.write = NULL};
+		UA_QualifiedName ledName;
+		UA_QUALIFIEDNAME_ASSIGN(ledName, "cpu temperature");
+		UA_Server_addDataSourceVariableNode(server, temperatureDataSource, ledName, UA_NODEID_NULL, 
+                                            UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                            UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+	}
 
-    UA_WorkItem work = {.type = UA_WORKITEMTYPE_METHODCALL, .work.methodCall = {.method = testCallback, .data = NULL} };
-    UA_Server_addRepeatedWorkItem(server, &work, 20000000, NULL); // call every 2 sec
+	if (	!(triggerFile = fopen("/sys/class/leds/led0/trigger", "w"))
+		|| 	!(ledFile = fopen("/sys/class/leds/led0/brightness", "w"))) {
+		UA_LOG_WARNING(logger, UA_LOGGERCATEGORY_USERLAND, "[Raspberry Pi specific] Can not open trigger or LED file (try to run server with sudo if on a Raspberry PI)");
+		UA_LOG_WARNING(logger, UA_LOGGERCATEGORY_USERLAND, "An LED node will be added but no physical LED will be operated");
+	} else {
+		//setting led mode to manual
+		fprintf(triggerFile, "%s", "none");
+		fflush(triggerFile);
 
-	// add a variable node to the adresspace
+		//turning off led initially
+		fprintf(ledFile, "%s", "1");
+		fflush(ledFile);
+	}
+
+	// add node with the LED status data source
+	UA_DataSource ledStatusDataSource = (UA_DataSource)
+   		{.handle = NULL,
+		.read = readLedStatus,
+		.release = releaseLedStatus,
+		.write = writeLedStatus};
+	UA_QualifiedName statusName;
+	UA_QUALIFIEDNAME_ASSIGN(statusName, "status LED");
+	UA_Server_addDataSourceVariableNode(server, ledStatusDataSource, statusName, UA_NODEID_NULL,
+                                        UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                        UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+
+	// add a static variable node to the adresspace
     UA_Variant *myIntegerVariant = UA_Variant_new();
     UA_Int32 myInteger = 42;
     UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
@@ -79,26 +240,30 @@ int main(int argc, char** argv) {
     UA_NodeId parentReferenceNodeId = UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES);
     UA_Server_addVariableNode(server, myIntegerVariant, myIntegerName,
                               myIntegerNodeId, parentNodeId, parentReferenceNodeId);
-    
-#ifdef BENCHMARK
-    UA_UInt32 nodeCount = 500;
-    char str[15];
-    for(UA_UInt32 i = 0;i<nodeCount;i++) {
-        UA_Int32 *data = UA_Int32_new();
-        *data = 42;
-        UA_Variant *variant = UA_Variant_new();
-        UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_INT32]);
-        UA_QualifiedName *nodeName = UA_QualifiedName_new();
-        sprintf(str,"%d",i);
-        UA_QualifiedName_copycstring(str, nodeName);
-        UA_Server_addVariableNode(server, variant, *nodeName, UA_NODEID_NULL,
-                                  UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
-                                  UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
-    }
-#endif
 
-    UA_StatusCode retval = UA_Server_run(server, 1, &running);
+	//start server
+	UA_StatusCode retval = UA_Server_run(server, 1, &running); //blocks until running=false
+
+	//ctrl-c received -> clean up
 	UA_Server_delete(server);
 
+	if(temperatureFile)
+		fclose(temperatureFile);
+
+	if(triggerFile){
+		fseek(triggerFile, 0, SEEK_SET);
+		//setting led mode to default
+		fprintf(triggerFile, "%s", "mmc0");
+		fclose(triggerFile);
+	}
+
+	if(ledFile){
+		fclose(ledFile);
+	}
+
+#ifdef UA_MULTITHREADING
+	pthread_rwlock_destroy(&writeLock);
+#endif
+
 	return retval;
 }

+ 0 - 257
examples/server_datasource.c

@@ -1,257 +0,0 @@
-/*
- * This work is licensed under a Creative Commons CCZero 1.0 Universal License.
- * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
- */
-#ifdef NOT_AMALGATED
-    #include "ua_types.h"
-    #include "ua_server.h"
-#else
-    #include "open62541.h"
-#endif
-
-#include <time.h>
-#include <stdio.h>
-#include <stdlib.h> 
-#include <signal.h>
-#define __USE_XOPEN2K
-#ifdef UA_MULTITHREADING
-#include <pthread.h>
-#endif
-
-// provided by the user, implementations available in the /examples folder
-#include "logger_stdout.h"
-#include "networklayer_tcp.h"
-
-/****************************/
-/* Server-related variables */
-/****************************/
-
-UA_Boolean running = 1;
-UA_Logger logger;
-
-/*************************/
-/* Read-only data source */
-/*************************/
-static UA_StatusCode readTimeData(const void *handle, UA_Boolean sourceTimeStamp, UA_DataValue *value) {
-	UA_DateTime *currentTime = UA_DateTime_new();
-	if(!currentTime)
-		return UA_STATUSCODE_BADOUTOFMEMORY;
-	*currentTime = UA_DateTime_now();
-	value->value.type = &UA_TYPES[UA_TYPES_DATETIME];
-	value->value.arrayLength = -1;
-	value->value.dataPtr = currentTime;
-	value->value.arrayDimensionsSize = -1;
-	value->value.arrayDimensions = NULL;
-	value->hasVariant = UA_TRUE;
-	if(sourceTimeStamp) {
-		value->hasSourceTimestamp = UA_TRUE;
-		value->sourceTimestamp = *currentTime;
-	}
-	return UA_STATUSCODE_GOOD;
-}
-
-static void releaseTimeData(const void *handle, UA_DataValue *value) {
-	UA_DateTime_delete((UA_DateTime*)value->value.dataPtr);
-}
-
-/*****************************/
-/* Read-only CPU temperature */
-/*      Only on Linux        */
-/*****************************/
-FILE* temperatureFile = NULL;
-static UA_StatusCode readTemperature(const void *handle, UA_Boolean sourceTimeStamp, UA_DataValue *value) {
-	UA_Double* currentTemperature = UA_Double_new();
-
-	if(!currentTemperature)
-		return UA_STATUSCODE_BADOUTOFMEMORY;
-
-	fseek(temperatureFile, 0, SEEK_SET);
-
-	if(fscanf(temperatureFile, "%lf", currentTemperature) != 1){
-		UA_LOG_WARNING(logger, UA_LOGGERCATEGORY_USERLAND, "Can not parse temperature");
-		exit(1);
-	}
-
-	*currentTemperature /= 1000.0;
-
-	value->value.type = &UA_TYPES[UA_TYPES_DOUBLE];
-	value->value.arrayLength = -1;
-	value->value.dataPtr = currentTemperature;
-	value->value.arrayDimensionsSize = -1;
-	value->value.arrayDimensions = NULL;
-	value->hasVariant = UA_TRUE;
-	return UA_STATUSCODE_GOOD;
-}
-
-static void releaseTemperature(const void *handle, UA_DataValue *value) {
-	UA_Double_delete((UA_Double*)value->value.dataPtr);
-}
-
-/*************************/
-/* Read-write status led */
-/*************************/
-#ifdef UA_MULTITHREADING
-pthread_rwlock_t writeLock;
-#endif
-FILE* triggerFile = NULL;
-FILE* ledFile = NULL;
-UA_Boolean ledStatus = 0;
-
-static UA_StatusCode readLedStatus(const void *handle, UA_Boolean sourceTimeStamp, UA_DataValue *value) {
-	/* In order to reduce blocking time, we could alloc memory for every read
-       and return a copy of the data. */
-#ifdef UA_MULTITHREADING
-	pthread_rwlock_rdlock(&writeLock);
-#endif
-	value->value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
-	value->value.arrayLength = -1;
-	value->value.dataPtr = &ledStatus;
-	value->value.arrayDimensionsSize = -1;
-	value->value.arrayDimensions = NULL;
-	value->hasVariant = UA_TRUE;
-	if(sourceTimeStamp) {
-		value->sourceTimestamp = UA_DateTime_now();
-		value->hasSourceTimestamp = UA_TRUE;
-	}
-	return UA_STATUSCODE_GOOD;
-}
-
-static void releaseLedStatus(const void *handle, UA_DataValue *value) {
-	/* If we allocated memory for a specific read, free the content of the
-       variantdata. */
-	value->value.arrayLength = -1;
-	value->value.dataPtr = NULL;
-#ifdef UA_MULTITHREADING
-	pthread_rwlock_unlock(&writeLock);
-#endif
-}
-
-static UA_StatusCode writeLedStatus(const void *handle, const UA_Variant *data) {
-#ifdef UA_MULTITHREADING
-	pthread_rwlock_wrlock(&writeLock);
-#endif
-	if(data->dataPtr)
-		ledStatus = *(UA_Boolean*)data->dataPtr;
-
-	if(triggerFile)
-		fseek(triggerFile, 0, SEEK_SET);
-
-	if(ledFile){
-		if(ledStatus == 1){
-			fprintf(ledFile, "%s", "1");
-		} else {
-			fprintf(ledFile, "%s", "0");
-		}
-		fflush(ledFile);
-	}
-#ifdef UA_MULTITHREADING
-	pthread_rwlock_unlock(&writeLock);
-#endif
-	return UA_STATUSCODE_GOOD;
-}
-
-static void printLedStatus(UA_Server *server, void *data) {
-	UA_LOG_INFO(logger, UA_LOGGERCATEGORY_SERVER, ledStatus ? "LED is on" : "LED is off");
-}
-
-static void stopHandler(int sign) {
-	printf("Received Ctrl-C\n");
-	running = 0;
-}
-
-int main(int argc, char** argv) {
-	signal(SIGINT, stopHandler); /* catches ctrl-c */
-#ifdef UA_MULTITHREADING
-	pthread_rwlock_init(&writeLock, 0);
-#endif
-
-	UA_Server *server = UA_Server_new();
-	logger = Logger_Stdout_new();
-	UA_Server_setLogger(server, logger);
-	UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
-
-	// print the status every 2 sec
-	UA_WorkItem work = {.type = UA_WORKITEMTYPE_METHODCALL,
-			.work.methodCall = {.method = printLedStatus, .data = NULL} };
-	UA_Server_addRepeatedWorkItem(server, &work, 20000000, NULL);
-
-	// add node with the datetime data source
-	UA_DataSource dateDataSource = (UA_DataSource)
-        {.handle = NULL,
-		.read = readTimeData,
-		.release = releaseTimeData,
-		.write = NULL};
-	UA_QualifiedName dateName;
-	UA_QUALIFIEDNAME_ASSIGN(dateName, "current time");
-	UA_Server_addDataSourceVariableNode(server, dateDataSource, dateName, UA_NODEID_NULL,
-                                        UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
-                                        UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
-
-	if(!(temperatureFile = fopen("/sys/class/thermal/thermal_zone0/temp", "r"))){
-		UA_LOG_WARNING(logger, UA_LOGGERCATEGORY_USERLAND, "[Linux specific] Can not open temperature file, no temperature node will be added");
-	} else {
-		// add node with the datetime data source
-		UA_DataSource temperatureDataSource = (UA_DataSource)
-    	    {.handle = NULL,
-			.read = readTemperature,
-			.release = releaseTemperature,
-			.write = NULL};
-		UA_QualifiedName ledName;
-		UA_QUALIFIEDNAME_ASSIGN(ledName, "cpu temperature");
-		UA_Server_addDataSourceVariableNode(server, temperatureDataSource, ledName, UA_NODEID_NULL, 
-                                            UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
-                                            UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
-	}
-
-	if (	!(triggerFile = fopen("/sys/class/leds/led0/trigger", "w"))
-		|| 	!(ledFile = fopen("/sys/class/leds/led0/brightness", "w"))) {
-		UA_LOG_WARNING(logger, UA_LOGGERCATEGORY_USERLAND, "[Raspberry Pi specific] Can not open trigger or LED file (try to run server with sudo if on a Raspberry PI)");
-		UA_LOG_WARNING(logger, UA_LOGGERCATEGORY_USERLAND, "An LED node will be added but no physical LED will be operated");
-	} else {
-		//setting led mode to manual
-		fprintf(triggerFile, "%s", "none");
-		fflush(triggerFile);
-
-		//turning off led initially
-		fprintf(ledFile, "%s", "1");
-		fflush(ledFile);
-	}
-
-	// add node with the LED status data source
-	UA_DataSource ledStatusDataSource = (UA_DataSource)
-   		{.handle = NULL,
-		.read = readLedStatus,
-		.release = releaseLedStatus,
-		.write = writeLedStatus};
-	UA_QualifiedName statusName;
-	UA_QUALIFIEDNAME_ASSIGN(statusName, "status LED");
-	UA_Server_addDataSourceVariableNode(server, ledStatusDataSource, statusName, UA_NODEID_NULL,
-                                        UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
-                                        UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
-
-	//start server
-	UA_StatusCode retval = UA_Server_run(server, 1, &running); //blocks until running=false
-
-	//ctrl-c received -> clean up
-	UA_Server_delete(server);
-
-	if(temperatureFile)
-		fclose(temperatureFile);
-
-	if(triggerFile){
-		fseek(triggerFile, 0, SEEK_SET);
-		//setting led mode to default
-		fprintf(triggerFile, "%s", "mmc0");
-		fclose(triggerFile);
-	}
-
-	if(ledFile){
-		fclose(ledFile);
-	}
-
-#ifdef UA_MULTITHREADING
-	pthread_rwlock_destroy(&writeLock);
-#endif
-
-	return retval;
-}

+ 104 - 0
examples/server_simple.c

@@ -0,0 +1,104 @@
+/*
+ * This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
+ */
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h> 
+#include <signal.h>
+#include <errno.h> // errno, EINTR
+
+#ifdef NOT_AMALGATED
+    #include "ua_types.h"
+    #include "ua_server.h"
+#else
+    #include "open62541.h"
+#endif
+
+// provided by the user, implementations available in the /examples folder
+#include "logger_stdout.h"
+#include "networklayer_tcp.h"
+
+UA_Boolean running = 1;
+UA_Logger logger;
+
+static void stopHandler(int sign) {
+    printf("Received Ctrl-C\n");
+	running = 0;
+}
+
+static UA_ByteString loadCertificate(void) {
+    UA_ByteString certificate = UA_STRING_NULL;
+	FILE *fp = NULL;
+	//FIXME: a potiential bug of locating the certificate, we need to get the path from the server's config
+	fp=fopen("localhost.der", "rb");
+
+	if(!fp) {
+        errno = 0; // we read errno also from the tcp layer...
+        return certificate;
+    }
+
+    fseek(fp, 0, SEEK_END);
+    certificate.length = ftell(fp);
+    certificate.data = malloc(certificate.length*sizeof(UA_Byte));
+	if(!certificate.data)
+		return certificate;
+
+    fseek(fp, 0, SEEK_SET);
+    if(fread(certificate.data, sizeof(UA_Byte), certificate.length, fp) < (size_t)certificate.length)
+        UA_ByteString_deleteMembers(&certificate); // error reading the cert
+    fclose(fp);
+
+    return certificate;
+}
+
+static void testCallback(UA_Server *server, void *data) {
+    logger.log_info(UA_LOGGERCATEGORY_USERLAND, "testcallback");
+}
+
+int main(int argc, char** argv) {
+	signal(SIGINT, stopHandler); /* catches ctrl-c */
+
+	UA_Server *server = UA_Server_new();
+    logger = Logger_Stdout_new();
+    UA_Server_setLogger(server, logger);
+    UA_Server_setServerCertificate(server, loadCertificate());
+    UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
+
+    UA_WorkItem work = {.type = UA_WORKITEMTYPE_METHODCALL, .work.methodCall = {.method = testCallback, .data = NULL} };
+    UA_Server_addRepeatedWorkItem(server, &work, 20000000, NULL); // call every 2 sec
+
+	// add a variable node to the adresspace
+    UA_Variant *myIntegerVariant = UA_Variant_new();
+    UA_Int32 myInteger = 42;
+    UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
+    UA_QualifiedName myIntegerName;
+    UA_QUALIFIEDNAME_ASSIGN(myIntegerName, "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);
+    UA_Server_addVariableNode(server, myIntegerVariant, myIntegerName,
+                              myIntegerNodeId, parentNodeId, parentReferenceNodeId);
+    
+#ifdef BENCHMARK
+    UA_UInt32 nodeCount = 500;
+    char str[15];
+    for(UA_UInt32 i = 0;i<nodeCount;i++) {
+        UA_Int32 *data = UA_Int32_new();
+        *data = 42;
+        UA_Variant *variant = UA_Variant_new();
+        UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_INT32]);
+        UA_QualifiedName *nodeName = UA_QualifiedName_new();
+        sprintf(str,"%d",i);
+        UA_QualifiedName_copycstring(str, nodeName);
+        UA_Server_addVariableNode(server, variant, *nodeName, UA_NODEID_NULL,
+                                  UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                  UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+    }
+#endif
+
+    UA_StatusCode retval = UA_Server_run(server, 1, &running);
+	UA_Server_delete(server);
+
+	return retval;
+}