Browse Source

client code

Julius Pfrommer 10 years ago
parent
commit
b8f4420ce5

+ 13 - 0
CMakeLists.txt

@@ -28,6 +28,7 @@ set(lib_sources src/ua_types.c
                 ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.c
                 src/ua_securechannel.c
                 src/ua_session.c
+                src/client/ua_client.c
                 src/server/ua_server.c
 				src/server/ua_server_addressspace.c
 				src/server/ua_server_binary.c
@@ -168,6 +169,18 @@ endif()
 # set the precompiler flags
 configure_file("src/ua_config.h.in" "${PROJECT_BINARY_DIR}/src_generated/ua_config.h")
 
+# download queue.h if required
+if(WIN32)
+    if(NOT EXISTS "${PROJECT_BINARY_DIR}/src_generated/queue.h")
+        file(DOWNLOAD "http://openbsd.cs.toronto.edu/cgi-bin/cvsweb/~checkout~/src/sys/sys/queue.h" "${PROJECT_BINARY_DIR}/src_generated/queue.h" STATUS result)
+        list(GET result 0 download_ok)
+        if(NOT ${download_ok} MATCHES 0)
+            file(REMOVE "${PROJECT_BINARY_DIR}/src_generated/queue.h") # remove empty file if created
+            message(FATAL_ERROR "queue.h could not be downloaded")
+        endif()
+    endif()
+endif(WIN32)
+
 # generate code from xml definitions
 file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/src_generated")
 include_directories("${PROJECT_BINARY_DIR}/src_generated") 

+ 149 - 26
examples/networklayer_tcp.c

@@ -31,18 +31,20 @@
 #include <urcu/uatomic.h>
 #endif
 
-#define MAXBACKLOG 100
-
-struct Networklayer_TCP;
-
-/* Forwarded to the server as a (UA_Connection) and used for callbacks back into
-   the networklayer */
+/* Forwarded as a (UA_Connection) and used for callbacks back into the
+   networklayer */
 typedef struct {
 	UA_Connection connection;
 	UA_Int32 sockfd;
-	struct NetworkLayerTCP *layer;
+	void *layer;
 } TCPConnection;
 
+/***************************/
+/* Server NetworkLayer TCP */
+/***************************/
+
+#define MAXBACKLOG 100
+
 /* Internal mapping of sockets to connections */
 typedef struct {
     TCPConnection *connection;
@@ -53,7 +55,7 @@ typedef struct {
 #endif
 } ConnectionLink;
 
-typedef struct NetworkLayerTCP {
+typedef struct {
 	UA_ConnectionConfig conf;
 	fd_set fdset;
 #ifdef _WIN32
@@ -76,7 +78,7 @@ typedef struct NetworkLayerTCP {
 #endif
         struct deleteLink *next;
     } *deleteLinkList;
-} NetworkLayerTCP;
+} ServerNetworkLayerTCP;
 
 static UA_StatusCode setNonBlocking(int sockid) {
 #ifdef _WIN32
@@ -96,7 +98,7 @@ static void freeConnectionCallback(UA_Server *server, TCPConnection *connection)
 }
 
 // after every select, reset the set of sockets we want to listen on
-static void setFDSet(NetworkLayerTCP *layer) {
+static void setFDSet(ServerNetworkLayerTCP *layer) {
 	FD_ZERO(&layer->fdset);
 	FD_SET(layer->serversockfd, &layer->fdset);
 	layer->highestfd = layer->serversockfd;
@@ -111,7 +113,7 @@ static void setFDSet(NetworkLayerTCP *layer) {
 void closeConnection(TCPConnection *handle);
 void writeCallback(TCPConnection *handle, UA_ByteStringArray gather_buf);
 
-static UA_StatusCode NetworkLayerTCP_add(NetworkLayerTCP *layer, UA_Int32 newsockfd) {
+static UA_StatusCode ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_Int32 newsockfd) {
     setNonBlocking(newsockfd);
     TCPConnection *c = malloc(sizeof(TCPConnection));
 	if(!c)
@@ -136,7 +138,7 @@ static UA_StatusCode NetworkLayerTCP_add(NetworkLayerTCP *layer, UA_Int32 newsoc
 }
 
 // Takes the linked list of closed connections and returns the work for the server loop
-static UA_UInt32 batchDeleteLinks(NetworkLayerTCP *layer, UA_WorkItem **returnWork) {
+static UA_UInt32 batchDeleteLinks(ServerNetworkLayerTCP *layer, UA_WorkItem **returnWork) {
     UA_WorkItem *work = malloc(sizeof(UA_WorkItem)*layer->conLinksSize);
 	if (!work) {
 		*returnWork = NULL;
@@ -207,8 +209,9 @@ void closeConnection(TCPConnection *handle) {
 
     // Remove the link later in the main thread
     d->sockfd = handle->sockfd;
-    d->next = handle->layer->deleteLinkList;
-    handle->layer->deleteLinkList = d;
+    ServerNetworkLayerTCP *layer = (ServerNetworkLayerTCP*)handle->layer;
+    d->next = layer->deleteLinkList;
+    layer->deleteLinkList = d;
 }
 #endif
 
@@ -253,7 +256,7 @@ void writeCallback(TCPConnection *handle, UA_ByteStringArray gather_buf) {
 #endif
 }
 
-static UA_StatusCode NetworkLayerTCP_start(NetworkLayerTCP *layer) {
+static UA_StatusCode ServerNetworkLayerTCP_start(ServerNetworkLayerTCP *layer) {
 #ifdef _WIN32
 	WORD wVersionRequested;
 	WSADATA wsaData;
@@ -298,7 +301,7 @@ static UA_StatusCode NetworkLayerTCP_start(NetworkLayerTCP *layer) {
     return UA_STATUSCODE_GOOD;
 }
 
-static UA_Int32 NetworkLayerTCP_getWork(NetworkLayerTCP *layer, UA_WorkItem **workItems,
+static UA_Int32 ServerNetworkLayerTCP_getWork(ServerNetworkLayerTCP *layer, UA_WorkItem **workItems,
                                         UA_UInt16 timeout) {
     UA_WorkItem *items = UA_NULL;
     UA_Int32 itemsCount = batchDeleteLinks(layer, &items);
@@ -318,7 +321,7 @@ static UA_Int32 NetworkLayerTCP_getWork(NetworkLayerTCP *layer, UA_WorkItem **wo
 		socklen_t cli_len = sizeof(cli_addr);
 		int newsockfd = accept(layer->serversockfd, (struct sockaddr *) &cli_addr, &cli_len);
 		if (newsockfd >= 0)
-			NetworkLayerTCP_add(layer, newsockfd);
+			ServerNetworkLayerTCP_add(layer, newsockfd);
 	}
     
     items = realloc(items, sizeof(UA_WorkItem)*(itemsCount+resultsize));
@@ -364,7 +367,7 @@ static UA_Int32 NetworkLayerTCP_getWork(NetworkLayerTCP *layer, UA_WorkItem **wo
     return j;
 }
 
-static UA_Int32 NetworkLayerTCP_stop(NetworkLayerTCP * layer, UA_WorkItem **workItems) {
+static UA_Int32 ServerNetworkLayerTCP_stop(ServerNetworkLayerTCP * layer, UA_WorkItem **workItems) {
 	for(UA_Int32 index = 0;index < layer->conLinksSize;index++)
         closeConnection(layer->conLinks[index].connection);
 #ifdef _WIN32
@@ -373,24 +376,144 @@ static UA_Int32 NetworkLayerTCP_stop(NetworkLayerTCP * layer, UA_WorkItem **work
     return batchDeleteLinks(layer, workItems);
 }
 
-static void NetworkLayerTCP_delete(NetworkLayerTCP *layer) {
+static void ServerNetworkLayerTCP_delete(ServerNetworkLayerTCP *layer) {
 	free(layer->conLinks);
 	free(layer);
 }
 
-UA_NetworkLayer NetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UInt32 port) {
-    NetworkLayerTCP *tcplayer = malloc(sizeof(NetworkLayerTCP));
+UA_ServerNetworkLayer ServerNetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UInt32 port) {
+    ServerNetworkLayerTCP *tcplayer = malloc(sizeof(ServerNetworkLayerTCP));
 	tcplayer->conf = conf;
 	tcplayer->conLinksSize = 0;
 	tcplayer->conLinks = NULL;
     tcplayer->port = port;
     tcplayer->deleteLinkList = UA_NULL;
 
-    UA_NetworkLayer nl;
+    UA_ServerNetworkLayer nl;
     nl.nlHandle = tcplayer;
-    nl.start = (UA_StatusCode (*)(void*))NetworkLayerTCP_start;
-    nl.getWork = (UA_Int32 (*)(void*, UA_WorkItem**, UA_UInt16)) NetworkLayerTCP_getWork;
-    nl.stop = (UA_Int32 (*)(void*, UA_WorkItem**)) NetworkLayerTCP_stop;
-    nl.delete = (void (*)(void*))NetworkLayerTCP_delete;
+    nl.start = (UA_StatusCode (*)(void*))ServerNetworkLayerTCP_start;
+    nl.getWork = (UA_Int32 (*)(void*, UA_WorkItem**, UA_UInt16))ServerNetworkLayerTCP_getWork;
+    nl.stop = (UA_Int32 (*)(void*, UA_WorkItem**))ServerNetworkLayerTCP_stop;
+    nl.free = (void (*)(void*))ServerNetworkLayerTCP_delete;
     return nl;
 }
+
+/***************************/
+/* Client NetworkLayer TCP */
+/***************************/
+
+static UA_StatusCode ClientNetworkLayerTCP_connect(const UA_String endpointUrl, void **resultHandle) { 
+    if(endpointUrl.length < 11 || endpointUrl.length >= 512) {
+        printf("server url size invalid");
+        return UA_STATUSCODE_BADINTERNALERROR;
+    }
+
+    if(strncmp((char*)endpointUrl.data, "opc.tcp://", 10) != 0) {
+        printf("server url does not begin with opc.tcp://");
+        return UA_STATUSCODE_BADINTERNALERROR;
+    }
+
+    UA_UInt16 portpos = 9;
+    UA_UInt16 port = 0;
+    for(;portpos < endpointUrl.length; portpos++) {
+        if(endpointUrl.data[portpos] == ':') {
+            port = atoi((char*)&endpointUrl.data[portpos+1]);
+            break;
+        }
+    }
+    if(port == 0) {
+        printf("port invalid");
+        return UA_STATUSCODE_BADINTERNALERROR;
+    }
+    
+    char hostname[512];
+    for(int i=10; i < portpos; i++)
+        hostname[i-10] = endpointUrl.data[i];
+    hostname[portpos-10] = 0;
+
+    UA_Int32 *sock = UA_Int32_new();
+    if(!sock)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    if((*sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
+        free(sock);
+		printf("Could not create socket");
+        return UA_STATUSCODE_BADINTERNALERROR;
+    }
+
+	struct sockaddr_in server;
+	server.sin_addr.s_addr = inet_addr(hostname);
+	server.sin_family = AF_INET;
+	server.sin_port = port;
+
+	if(connect(*sock, (struct sockaddr *) &server, sizeof(server)) < 0) {
+        free(sock);
+        printf("Connect failed.");
+        return UA_STATUSCODE_BADINTERNALERROR;
+    }
+
+    if(setNonBlocking(*sock) != UA_STATUSCODE_GOOD) {
+        free(sock);
+        printf("Could not switch to nonblocking.");
+        return UA_STATUSCODE_BADINTERNALERROR;
+    }
+
+    *resultHandle = sock;
+    return UA_STATUSCODE_GOOD;
+}
+
+static void ClientNetworkLayerTCP_disconnect(UA_Int32 *handle) {
+    close(*handle);
+    free(handle);
+}
+
+static UA_StatusCode ClientNetworkLayerTCP_send(UA_Int32 *handle, UA_ByteStringArray gather_buf) {
+	struct iovec iov[gather_buf.stringsSize];
+    int total_len = 0;
+	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};
+    int nWritten = 0;
+	while (nWritten < total_len) {
+        int n = sendmsg(*handle, &message, 0);
+        if(n <= -1)
+            return UA_STATUSCODE_BADINTERNALERROR;
+        nWritten += n;
+	}
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode ClientNetworkLayerTCP_awaitResponse(UA_Int32 *handle, UA_ByteString *response,
+                                                         UA_UInt32 timeout) {
+    fd_set read_fds;
+    FD_ZERO(&read_fds);
+    struct timeval tmptv = {0, timeout};
+    int ret = select(*handle+1, &read_fds, NULL, NULL, &tmptv);
+    if(ret <= -1)
+        return UA_STATUSCODE_BADINTERNALERROR;
+    if(ret == 0)
+        return UA_STATUSCODE_BADTIMEOUT;
+
+    ret = recv(*handle, 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;
+}
+
+UA_ClientNetworkLayer ClientNetworkLayerTCP_new(UA_ConnectionConfig conf) {
+    UA_ClientNetworkLayer layer;
+    layer.connect = (UA_StatusCode (*)(const UA_String, void**)) ClientNetworkLayerTCP_connect;
+    layer.disconnect = (void (*)(void*)) ClientNetworkLayerTCP_disconnect;
+    layer.send = (UA_StatusCode (*)(void*, UA_ByteStringArray)) ClientNetworkLayerTCP_send;
+    layer.awaitResponse = (UA_StatusCode (*)(void*, UA_ByteString *, UA_UInt32))ClientNetworkLayerTCP_awaitResponse;
+    return layer;
+}

+ 3 - 1
examples/networklayer_tcp.h

@@ -11,9 +11,11 @@ extern "C" {
 #endif
 
 #include "ua_server.h"
+#include "ua_client.h"
 
 /** @brief Create the TCP networklayer and listen to the specified port */
-UA_NetworkLayer NetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UInt32 port);
+UA_ServerNetworkLayer ServerNetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UInt32 port);
+UA_ClientNetworkLayer ClientNetworkLayerTCP_new(UA_ConnectionConfig conf);
 
 #ifdef __cplusplus
 } // extern "C"

+ 1 - 1
examples/opcuaServer.c

@@ -64,7 +64,7 @@ int main(int argc, char** argv) {
 #ifdef EXTENSION_UDP
     UA_Server_addNetworkLayer(server, NetworkLayerUDP_new(UA_ConnectionConfig_standard, 16664));
 #else
-    UA_Server_addNetworkLayer(server, NetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
+    UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
 #endif
 
 

+ 26 - 0
include/ua_client.h

@@ -0,0 +1,26 @@
+#include "ua_util.h"
+#include "ua_types.h"
+#include "ua_connection.h"
+#include "ua_transport_generated.h"
+#include "ua_namespace_0.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 {
+    UA_StatusCode (*connect)(const UA_String endpointUrl, void **resultHandle);
+    void (*disconnect)(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;
+typedef struct UA_Client UA_Client;
+
+UA_Client UA_EXPORT * UA_Client_new(void);
+UA_Client UA_EXPORT * setUserDataPtr(UA_Client *c, void *userData);
+UA_StatusCode UA_EXPORT UA_Client_connect(UA_Client *c, UA_ConnectionConfig conf,
+                                          UA_ClientNetworkLayer networkLayer, char *endpointUrl);
+UA_StatusCode UA_EXPORT UA_Client_disconnect(UA_Client *c);

+ 3 - 3
include/ua_server.h

@@ -183,15 +183,15 @@ typedef struct {
     UA_Int32 (*stop)(void *nlhandle, UA_WorkItem **workItems);
 
     /** Deletes the network layer. Call only after a successfull shutdown. */
-    void (*delete)(void *nlhandle);
-} UA_NetworkLayer;
+    void (*free)(void *nlhandle);
+} UA_ServerNetworkLayer;
 
 /**
  * Adds a network layer to the server. The network layer is destroyed together
  * with the server. Do not use it after adding it as it might be moved around on
  * the heap.
  */
-void UA_EXPORT UA_Server_addNetworkLayer(UA_Server *server, UA_NetworkLayer networkLayer);
+void UA_EXPORT UA_Server_addNetworkLayer(UA_Server *server, UA_ServerNetworkLayer networkLayer);
 
 /** @} */
 

+ 3 - 3
src/server/ua_server.c

@@ -29,8 +29,8 @@ static void UA_ExternalNamespace_deleteMembers(UA_ExternalNamespace *ens) {
 /* Configuration */
 /*****************/
 
-void UA_Server_addNetworkLayer(UA_Server *server, UA_NetworkLayer networkLayer) {
-    server->nls = UA_realloc(server->nls, sizeof(UA_NetworkLayer)*(server->nlsSize+1));
+void UA_Server_addNetworkLayer(UA_Server *server, UA_ServerNetworkLayer networkLayer) {
+    server->nls = UA_realloc(server->nls, sizeof(UA_ServerNetworkLayer)*(server->nlsSize+1));
     server->nls[server->nlsSize] = networkLayer;
     server->nlsSize++;
 }
@@ -48,7 +48,7 @@ void UA_Server_delete(UA_Server *server) {
 
     // Delete the network layers
     for(UA_Int32 i=0;i<server->nlsSize;i++) {
-        server->nls[i].delete(server->nls[i].nlHandle);
+        server->nls[i].free(server->nls[i].nlHandle);
     }
     UA_free(server->nls);
 

+ 1 - 1
src/server/ua_server_internal.h

@@ -44,7 +44,7 @@ struct UA_Server {
     UA_ExternalNamespace *externalNamespaces;
 
     UA_Int32 nlsSize;
-    UA_NetworkLayer *nls;
+    UA_ServerNetworkLayer *nls;
 
     UA_UInt32 random_seed;
 

+ 1 - 1
src/server/ua_server_worker.c

@@ -418,7 +418,7 @@ UA_StatusCode UA_Server_run(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *r
 
         // 3.2) Get work from the networklayer and dispatch it
         for(UA_Int32 i=0;i<server->nlsSize;i++) {
-            UA_NetworkLayer *nl = &server->nls[i];
+            UA_ServerNetworkLayer *nl = &server->nls[i];
             UA_WorkItem *work;
             UA_Int32 workSize;
             if(*running) {

+ 0 - 2
src/ua_types.c

@@ -19,9 +19,7 @@
 #define RAND(SEED) (UA_UInt32)rand_r(SEED)
 #endif
 
-#ifdef UA_DEBUG
 #include <inttypes.h>
-#endif
 
 #include "ua_types.h"
 #include "ua_types_macros.h"

+ 11 - 14
src/ua_util.h

@@ -1,12 +1,6 @@
 #ifndef UA_UTIL_H_
 #define UA_UTIL_H_
 
-#ifndef _WIN32
-#include <alloca.h>
-#else
-#include <malloc.h>
-#endif
-
 #ifndef  __USE_POSIX
 #define __USE_POSIX
 #endif
@@ -14,11 +8,14 @@
 #include <string.h> // memcpy
 #include <assert.h> // assert
 #include <stddef.h> /* Needed for queue.h */
-#include "queue.h"
 
-#include "ua_types.h"
-
-#define UA_NULL ((void *)0)
+#ifdef _WIN32
+#  include <malloc.h>
+#  include "queue.h"
+#else
+#  include <alloca.h>
+#  include <sys/queue.h>
+#endif
 
 // subtract from nodeids to get from the encoding to the content
 #define UA_ENCODINGOFFSET_XML 1
@@ -26,17 +23,17 @@
 
 #define UA_assert(ignore) assert(ignore)
 
-/* Replace the macros with functions for custom allocators.. */
+/* Memory management. Replace the macros with functions for custom allocators.. */
+#define UA_NULL ((void *)0)
 #define UA_free(ptr) free(ptr)
 #define UA_malloc(size) malloc(size)
 #define UA_realloc(ptr, size) realloc(ptr, size)
 #define UA_memcpy(dst, src, size) memcpy(dst, src, size)
 #define UA_memset(ptr, value, size) memset(ptr, value, size)
-
 #ifdef _WIN32
-#define UA_alloca(SIZE) _alloca(SIZE)
+# define UA_alloca(SIZE) _alloca(SIZE)
 #else
-#define UA_alloca(SIZE) alloca(SIZE)
+# define UA_alloca(SIZE) alloca(SIZE)
 #endif
 
 #endif /* UA_UTIL_H_ */