Merge branch 'master' into new_tcp

Conflicts:
	examples/networklayer_tcp.c
	src/client/ua_client.c
	src/ua_session.c
This commit is contained in:
Julius Pfrommer 2015-04-20 12:07:22 +02:00
commit ba36eba3bc
26 changed files with 490 additions and 385 deletions

View File

@ -130,6 +130,8 @@ if(EXTENSION_UDP)
add_definitions(-DEXTENSION_STATELESS)
message(STATUS "Extensions: enabling udp")
add_definitions(-DEXTENSION_UDP)
add_executable(exampleServerUDP $<TARGET_OBJECTS:open62541-object> examples/networklayer_udp.c examples/server_udp.c)
target_link_libraries(exampleServerUDP rt)
endif()
option(EXTENSION_STATELESS "Enable stateless extension" OFF)

View File

@ -46,9 +46,9 @@ int main(int argc, char** argv) {
/* init the server */
UA_Server *server = UA_Server_new();
UA_Server_setLogger(server, Logger_Stdout_new());
UA_Server_addNetworkLayer(server,
ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, PORT));
UA_Server_setLogger(server, Logger_Stdout_new());
UA_UInt16 nsIndex = UA_Server_addNamespace(server, "myApplicationNamespace");
/* add a variable node */
@ -76,8 +76,7 @@ int main(int argc, char** argv) {
int main(int argc, char *argv[]) {
UA_Client *client = UA_Client_new(UA_ClientConfig_standard);
UA_ClientNetworkLayer nl = ClientNetworkLayerTCP_new(UA_ConnectionConfig_standard);
UA_StatusCode retval = UA_Client_connect(client, UA_ConnectionConfig_standard, nl,
UA_StatusCode retval = UA_Client_connect(client, ClientNetworkLayerTCP_connect,
"opc.tcp://localhost:16664");
if(retval != UA_STATUSCODE_GOOD) {
UA_Client_delete(client);

View File

@ -3,6 +3,7 @@
#include "ua_client.h"
#include "ua_nodeids.h"
#include "networklayer_tcp.h"
#include "logger_stdout.h"
#else
#include "open62541.h"
#endif
@ -11,7 +12,7 @@
#include "networklayer_tcp.h"
int main(int argc, char *argv[]) {
UA_Client *client = UA_Client_new(UA_ClientConfig_standard);
UA_Client *client = UA_Client_new(UA_ClientConfig_standard, Logger_Stdout_new());
UA_StatusCode retval = UA_Client_connect(client, ClientNetworkLayerTCP_connect,
"opc.tcp://localhost:16664");
if(retval != UA_STATUSCODE_GOOD) {

View File

@ -119,6 +119,20 @@ static UA_StatusCode socket_set_nonblocking(UA_Int32 sockfd) {
return UA_STATUSCODE_GOOD;
}
/*****************************/
/* Generic Buffer Management */
/*****************************/
static UA_StatusCode GetMallocedBuffer(UA_Connection *connection, UA_ByteString *buf, size_t minSize) {
if(minSize > connection->remoteConf.recvBufferSize)
return UA_STATUSCODE_BADINTERNALERROR;
return UA_ByteString_newMembers(buf, minSize);
}
static void ReleaseMallocedBuffer(UA_Connection *connection, UA_ByteString *buf) {
UA_ByteString_deleteMembers(buf);
}
/***************************/
/* Server NetworkLayer TCP */
/***************************/
@ -157,7 +171,7 @@ static UA_StatusCode socket_set_nonblocking(UA_Int32 sockfd) {
typedef struct {
/* config */
UA_Server *server;
UA_Logger *logger;
UA_UInt32 port;
UA_String discoveryUrl;
UA_ConnectionConfig conf; /* todo: rename to localconf. */
@ -209,9 +223,7 @@ static void ServerNetworkLayerTCP_closeConnection(UA_Connection *connection) {
return;
connection->state = UA_CONNECTION_CLOSED;
#endif
socket_close(connection);
ServerNetworkLayerTCP *layer = (ServerNetworkLayerTCP*)connection->handle;
struct DeleteList *d = malloc(sizeof(struct DeleteList));
d->connection = connection;
@ -232,65 +244,60 @@ static UA_StatusCode ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_
UA_Connection *c = malloc(sizeof(UA_Connection));
if(!c)
return UA_STATUSCODE_BADINTERNALERROR;
UA_Connection_init(c);
c->sockfd = newsockfd;
c->handle = layer;
c->localConf = layer->conf;
c->write = socket_write;
c->close = ServerNetworkLayerTCP_closeConnection;
struct ConnectionMapping *nm = realloc(layer->mappings,
sizeof(struct ConnectionMapping)*(layer->mappingsSize+1));
c->getBuffer = GetMallocedBuffer;
c->releaseBuffer = ReleaseMallocedBuffer;
struct ConnectionMapping *nm =
realloc(layer->mappings, sizeof(struct ConnectionMapping)*(layer->mappingsSize+1));
if(!nm) {
free(c);
return UA_STATUSCODE_BADINTERNALERROR;
}
layer->mappings = nm;
layer->mappings[layer->mappingsSize] = (struct ConnectionMapping){c, newsockfd};
layer->mappingsSize++;
return UA_STATUSCODE_GOOD;
}
static UA_StatusCode ServerNetworkLayerTCP_start(ServerNetworkLayerTCP *layer) {
UA_Logger *logger = UA_Server_getLogger(layer->server);
static UA_StatusCode ServerNetworkLayerTCP_start(ServerNetworkLayerTCP *layer, UA_Logger *logger) {
layer->logger = logger;
#ifdef _WIN32
if((layer->serversockfd = socket(PF_INET, SOCK_STREAM,0)) == (UA_Int32)INVALID_SOCKET) {
UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "Error opening socket, code: %d",
UA_LOG_WARNING((*layer->logger), UA_LOGGERCATEGORY_COMMUNICATION, "Error opening socket, code: %d",
WSAGetLastError());
return UA_STATUSCODE_BADINTERNALERROR;
}
#else
if((layer->serversockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "Error opening socket");
UA_LOG_WARNING((*layer->logger), UA_LOGGERCATEGORY_COMMUNICATION, "Error opening socket");
return UA_STATUSCODE_BADINTERNALERROR;
}
#endif
const struct sockaddr_in serv_addr = {
.sin_family = AF_INET, .sin_addr.s_addr = INADDR_ANY,
.sin_port = htons(layer->port), .sin_zero = {0}};
const struct sockaddr_in serv_addr =
{.sin_family = AF_INET, .sin_addr.s_addr = INADDR_ANY,
.sin_port = htons(layer->port), .sin_zero = {0}};
int optval = 1;
if(setsockopt(layer->serversockfd, SOL_SOCKET,
SO_REUSEADDR, (const char *)&optval,
sizeof(optval)) == -1) {
UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "Error during setting of socket options");
UA_LOG_WARNING((*layer->logger), UA_LOGGERCATEGORY_COMMUNICATION, "Error during setting of socket options");
CLOSESOCKET(layer->serversockfd);
return UA_STATUSCODE_BADINTERNALERROR;
}
if(bind(layer->serversockfd, (const struct sockaddr *)&serv_addr,
sizeof(serv_addr)) < 0) {
UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "Error during socket binding");
UA_LOG_WARNING((*layer->logger), UA_LOGGERCATEGORY_COMMUNICATION, "Error during socket binding");
CLOSESOCKET(layer->serversockfd);
return UA_STATUSCODE_BADINTERNALERROR;
}
socket_set_nonblocking(layer->serversockfd);
listen(layer->serversockfd, MAXBACKLOG);
UA_LOG_INFO((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "Listening on %.*s",
UA_LOG_INFO((*layer->logger), UA_LOGGERCATEGORY_COMMUNICATION, "Listening on %.*s",
layer->discoveryUrl.length, layer->discoveryUrl.data);
return UA_STATUSCODE_GOOD;
}
@ -335,7 +342,6 @@ static UA_Int32 ServerNetworkLayerTCP_getWork(ServerNetworkLayerTCP *layer, UA_W
setFDSet(layer);
struct timeval tmptv = {0, timeout * 1000};
UA_Int32 resultsize = select(layer->highestfd+1, &layer->fdset, NULL, NULL, &tmptv);
UA_WorkItem *items;
if(resultsize < 0 || !(items = malloc(sizeof(UA_WorkItem)*(resultsize+1)))) {
/* abort .. reattach the deletes so that they get deleted eventually.. */
@ -355,7 +361,7 @@ static UA_Int32 ServerNetworkLayerTCP_getWork(ServerNetworkLayerTCP *layer, UA_W
return 0;
}
// accept new connections (can only be a single one)
/* accept new connections (can only be a single one) */
if(FD_ISSET(layer->serversockfd, &layer->fdset)) {
resultsize--;
struct sockaddr_in cli_addr;
@ -375,14 +381,12 @@ static UA_Int32 ServerNetworkLayerTCP_getWork(ServerNetworkLayerTCP *layer, UA_W
for(size_t i = 0; i < layer->mappingsSize && j < resultsize; i++) {
if(!(FD_ISSET(layer->mappings[i].sockfd, &layer->fdset)))
continue;
if(!buf.data) {
buf.data = malloc(sizeof(UA_Byte) * layer->conf.recvBufferSize);
buf.length = layer->conf.recvBufferSize;
if(!buf.data)
break;
}
if(socket_recv(layer->mappings[i].connection, &buf, 0) == UA_STATUSCODE_GOOD) {
items[j].type = UA_WORKITEMTYPE_BINARYNETWORKMESSAGE;
items[j].work.binaryNetworkMessage.message = buf;
@ -403,6 +407,7 @@ static UA_Int32 ServerNetworkLayerTCP_getWork(ServerNetworkLayerTCP *layer, UA_W
j++;
}
/* free the array if there is no work */
if(j == 0) {
free(items);
*workItems = NULL;
@ -423,7 +428,6 @@ static UA_Int32 ServerNetworkLayerTCP_stop(ServerNetworkLayerTCP *layer, UA_Work
UA_WorkItem *items = malloc(sizeof(UA_WorkItem) * layer->mappingsSize);
if(!items)
return 0;
for(size_t i = 0; i < layer->mappingsSize; i++) {
items[i].type = UA_WORKITEMTYPE_CLOSECONNECTION;
items[i].work.closeConnection = layer->mappings[i].connection;
@ -445,7 +449,7 @@ static void ServerNetworkLayerTCP_delete(ServerNetworkLayerTCP *layer) {
free(layer);
}
UA_ServerNetworkLayer ServerNetworkLayerTCP_new(UA_Server *server, UA_ConnectionConfig conf, UA_UInt32 port) {
UA_ServerNetworkLayer ServerNetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UInt32 port) {
#ifdef _WIN32
WORD wVersionRequested;
WSADATA wsaData;
@ -453,7 +457,6 @@ UA_ServerNetworkLayer ServerNetworkLayerTCP_new(UA_Server *server, UA_Connection
WSAStartup(wVersionRequested, &wsaData);
#endif
ServerNetworkLayerTCP *layer = malloc(sizeof(ServerNetworkLayerTCP));
layer->server = server;
layer->conf = conf;
layer->mappingsSize = 0;
layer->mappings = NULL;
@ -477,16 +480,20 @@ UA_ServerNetworkLayer ServerNetworkLayerTCP_new(UA_Server *server, UA_Connection
/* Client NetworkLayer TCP */
/***************************/
UA_StatusCode ClientNetworkLayerTCP_connect(UA_Client *client, UA_Connection *conn, char *endpointUrl) {
UA_Connection ClientNetworkLayerTCP_connect(char *endpointUrl, UA_Logger *logger) {
UA_Connection connection;
UA_Connection_init(&connection);
size_t urlLength = strlen(endpointUrl);
if(urlLength < 11 || urlLength >= 512) {
printf("server url size invalid\n");
return UA_STATUSCODE_BADINTERNALERROR;
UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "Server url size invalid");
return connection;
}
if(strncmp(endpointUrl, "opc.tcp://", 10) != 0) {
printf("server url does not begin with opc.tcp://\n");
return UA_STATUSCODE_BADINTERNALERROR;
UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "Server url does not begin with opc.tcp://");
return connection;
}
UA_UInt16 portpos = 9;
UA_UInt16 port = 0;
for(;portpos < urlLength-1; portpos++) {
@ -496,8 +503,8 @@ UA_StatusCode ClientNetworkLayerTCP_connect(UA_Client *client, UA_Connection *co
}
}
if(port == 0) {
printf("port invalid");
return UA_STATUSCODE_BADINTERNALERROR;
UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "Port invalid");
return connection;
}
char hostname[512];
@ -509,30 +516,33 @@ UA_StatusCode ClientNetworkLayerTCP_connect(UA_Client *client, UA_Connection *co
WSADATA wsaData;
wVersionRequested = MAKEWORD(2, 2);
WSAStartup(wVersionRequested, &wsaData);
if((conn->sockfd = socket(PF_INET, SOCK_STREAM,0)) == (UA_Int32)INVALID_SOCKET) {
if((connection.sockfd = socket(PF_INET, SOCK_STREAM,0)) == (UA_Int32)INVALID_SOCKET) {
#else
if((conn->sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
if((connection.sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
#endif
printf("Could not create socket\n");
return UA_STATUSCODE_BADINTERNALERROR;
UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "Could not create socket");
return connection;
}
struct hostent *server = gethostbyname(hostname);
if (server == NULL) {
printf("DNS lookup of %s failed\n", hostname);
return UA_STATUSCODE_BADINTERNALERROR;
if(server == NULL) {
UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "DNS lookup of %s failed", hostname);
return connection;
}
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
memcpy((char *)&server_addr.sin_addr.s_addr, (char *)server->h_addr_list[0], server->h_length);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
if(connect(conn->sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {
printf("Connect failed.\n");
return UA_STATUSCODE_BADINTERNALERROR;
if(connect(connection.sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {
UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "Connection failed");
return connection;
}
socket_set_nonblocking(conn->sockfd);
conn->write = socket_write;
conn->recv = socket_recv;
conn->close = socket_close;
return UA_STATUSCODE_GOOD;
connection.state = UA_CONNECTION_OPENING;
socket_set_nonblocking(connection.sockfd);
connection.write = socket_write;
connection.recv = socket_recv;
connection.close = socket_close;
connection.getBuffer = GetMallocedBuffer;
connection.releaseBuffer = ReleaseMallocedBuffer;
return connection;
}

View File

@ -18,8 +18,8 @@ extern "C" {
#endif
/** @brief Create the TCP networklayer and listen to the specified port */
UA_ServerNetworkLayer ServerNetworkLayerTCP_new(UA_Server *server, UA_ConnectionConfig conf, UA_UInt32 port);
UA_StatusCode ClientNetworkLayerTCP_connect(UA_Client *client, UA_Connection *conn, char *endpointUrl);
UA_ServerNetworkLayer ServerNetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UInt32 port);
UA_Connection ClientNetworkLayerTCP_connect(char *endpointUrl, UA_Logger *logger);
#ifdef __cplusplus
} // extern "C"

View File

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

View File

@ -196,7 +196,7 @@ int main(int argc, char** argv) {
UA_ByteString certificate = loadCertificate();
UA_Server_setServerCertificate(server, certificate);
UA_ByteString_deleteMembers(&certificate);
UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(server, UA_ConnectionConfig_standard, 16664));
UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
UA_UInt16 nsIndex = UA_Server_addNamespace(server, "myApplicationNamespace");
// print the status every 2 sec

View File

@ -65,7 +65,7 @@ int main(int argc, char** argv) {
UA_ByteString certificate = loadCertificate();
UA_Server_setServerCertificate(server, certificate);
UA_ByteString_deleteMembers(&certificate);
UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(server, UA_ConnectionConfig_standard, 16664));
UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
UA_Server_addNamespace(server, "myApplicationNamespace");
UA_WorkItem work = {.type = UA_WORKITEMTYPE_METHODCALL,

View File

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

View File

@ -8,6 +8,7 @@ extern "C" {
#include "ua_util.h"
#include "ua_types.h"
#include "ua_connection.h"
#include "ua_log.h"
#include "ua_types_generated.h"
struct UA_Client;
@ -17,7 +18,7 @@ typedef struct UA_Client UA_Client;
* The client networklayer is defined by a single function that fills a UA_Connection struct after
* successfully connecting.
*/
typedef UA_StatusCode (*UA_ConnectClientConnection)(UA_Client *client, UA_Connection *conn, char *endpointUrl);
typedef UA_Connection (*UA_ConnectClientConnection)(char *endpointUrl, UA_Logger *logger);
typedef struct UA_ClientConfig {
UA_Int32 timeout; //sync response timeout
@ -25,7 +26,7 @@ typedef struct UA_ClientConfig {
} UA_ClientConfig;
extern const UA_ClientConfig UA_ClientConfig_standard;
UA_Client UA_EXPORT * UA_Client_new(UA_ClientConfig config);
UA_Client UA_EXPORT * UA_Client_new(UA_ClientConfig config, UA_Logger logger);
void UA_Client_delete(UA_Client* client);
@ -38,6 +39,7 @@ UA_WriteResponse UA_EXPORT UA_Client_write(UA_Client *client, UA_WriteRequest *r
/* View Service Set */
UA_BrowseResponse UA_EXPORT UA_Client_browse(UA_Client *client, UA_BrowseRequest *request);
UA_BrowseNextResponse UA_EXPORT UA_Client_browseNext(UA_Client *client, UA_BrowseNextRequest *request);
UA_TranslateBrowsePathsToNodeIdsResponse UA_EXPORT
UA_Client_translateTranslateBrowsePathsToNodeIds(UA_Client *client,
UA_TranslateBrowsePathsToNodeIdsRequest *request);

View File

@ -71,7 +71,7 @@ struct UA_Connection {
UA_Int32 sockfd; ///> Most connectivity solutions run on sockets. Having the socket id here simplifies the design.
void *handle; ///> A pointer to the networklayer
UA_ByteString incompleteMessage; ///> Half-received messages (tcp is a streaming protocol) get stored here
UA_StatusCode (*getBuffer)(UA_Connection *connection, UA_ByteString *buf); ///> Attach a buffer according to localConf
UA_StatusCode (*getBuffer)(UA_Connection *connection, UA_ByteString *buf, size_t minSize); ///> Attach the data array to the buffer. Fails if minSize is larger than remoteConf allows
void (*releaseBuffer)(UA_Connection *connection, UA_ByteString *buf); ///> Release the buffer
UA_StatusCode (*write)(UA_Connection *connection, UA_ByteStringArray buf); ///> The bytestrings cannot be reused after sending!
UA_StatusCode (*recv)(UA_Connection *connection, UA_ByteString *response, UA_UInt32 timeout); // timeout in milliseconds

View File

@ -35,10 +35,11 @@ extern "C" {
typedef enum UA_LoggerCategory {
UA_LOGGERCATEGORY_COMMUNICATION,
UA_LOGGERCATEGORY_SERVER,
UA_LOGGERCATEGORY_CLIENT,
UA_LOGGERCATEGORY_USERLAND
} UA_LoggerCategory;
extern UA_EXPORT const char *UA_LoggerCategoryNames[3];
extern UA_EXPORT const char *UA_LoggerCategoryNames[4];
typedef struct UA_Logger {
void (*log_trace)(UA_LoggerCategory category, const char *msg, ...);
@ -50,45 +51,45 @@ typedef struct UA_Logger {
} UA_Logger;
#if UA_LOGLEVEL <= 100
#define UA_LOG_TRACE(LOGGER, CATEGORY, MSG...) do { \
if(LOGGER.log_trace) LOGGER.log_trace(CATEGORY, MSG); } while(0)
#define UA_LOG_TRACE(LOGGER, CATEGORY, ...) do { \
if(LOGGER.log_trace) LOGGER.log_trace(CATEGORY, __VA_ARGS__); } while(0)
#else
#define UA_LOG_TRACE(LOGGER, CATEGORY, MSG...) do {} while(0)
#define UA_LOG_TRACE(LOGGER, CATEGORY, ...) do {} while(0)
#endif
#if UA_LOGLEVEL <= 200
#define UA_LOG_DEBUG(LOGGER, CATEGORY, MSG...) do { \
if(LOGGER.log_debug) LOGGER.log_debug(CATEGORY, MSG); } while(0)
#define UA_LOG_DEBUG(LOGGER, CATEGORY, ...) do { \
if(LOGGER.log_debug) LOGGER.log_debug(CATEGORY, __VA_ARGS__); } while(0)
#else
#define UA_LOG_DEBUG(LOGGER, CATEGORY, MSG...) do {} while(0)
#define UA_LOG_DEBUG(LOGGER, CATEGORY, ...) do {} while(0)
#endif
#if UA_LOGLEVEL <= 300
#define UA_LOG_INFO(LOGGER, CATEGORY, MSG...) do { \
if(LOGGER.log_info) LOGGER.log_info(CATEGORY, MSG); } while(0)
#define UA_LOG_INFO(LOGGER, CATEGORY, ...) do { \
if(LOGGER.log_info) LOGGER.log_info(CATEGORY, __VA_ARGS__); } while(0)
#else
#define UA_LOG_INFO(LOGGER, CATEGORY, MSG...) do {} while(0)
#define UA_LOG_INFO(LOGGER, CATEGORY, ...) do {} while(0)
#endif
#if UA_LOGLEVEL <= 400
#define UA_LOG_WARNING(LOGGER, CATEGORY, MSG...) do { \
if(LOGGER.log_warning) LOGGER.log_warning(CATEGORY, MSG); } while(0)
#define UA_LOG_WARNING(LOGGER, CATEGORY, ...) do { \
if(LOGGER.log_warning) LOGGER.log_warning(CATEGORY, __VA_ARGS__); } while(0)
#else
#define UA_LOG_WARNING(LOGGER, CATEGORY, MSG...) do {} while(0)
#define UA_LOG_WARNING(LOGGER, CATEGORY, ...) do {} while(0)
#endif
#if UA_LOGLEVEL <= 500
#define UA_LOG_ERROR(LOGGER, CATEGORY, MSG...) do { \
if(LOGGER.log_error) LOGGER.log_error(CATEGORY, MSG); } while(0)
#define UA_LOG_ERROR(LOGGER, CATEGORY, ...) do { \
if(LOGGER.log_error) LOGGER.log_error(CATEGORY, __VA_ARGS__); } while(0)
#else
#define UA_LOG_ERROR(LOGGER, CATEGORY, MSG...) do {} while(0)
#define UA_LOG_ERROR(LOGGER, CATEGORY, ...) do {} while(0)
#endif
#if UA_LOGLEVEL <= 600
#define UA_LOG_FATAL(LOGGER, CATEGORY, MSG...) do { \
if(LOGGER.log_fatal) LOGGER.log_fatal(CATEGORY, MSG); } while(0)
#define UA_LOG_FATAL(LOGGER, CATEGORY, ...) do { \
if(LOGGER.log_fatal) LOGGER.log_fatal(CATEGORY, __VA_ARGS__); } while(0)
#else
#define UA_LOG_FATAL(LOGGER, CATEGORY, MSG...) do {} while(0)
#define UA_LOG_FATAL(LOGGER, CATEGORY, ...) do {} while(0)
#endif
/** @} */

View File

@ -272,6 +272,10 @@ typedef UA_Int32 (*UA_ExternalNodeStore_browseNodes)
UA_UInt32 *indices, UA_UInt32 indicesSize, UA_UInt32 requestedMaxReferencesPerNode,
UA_BrowseResult *browseResults, UA_DiagnosticInfo *diagnosticInfos);
typedef UA_Int32 (*UA_ExternalNodeStore_translateBrowsePathsToNodeIds)
(void *ensHandle, const UA_RequestHeader *requestHeader, UA_BrowsePath *browsePath,
UA_UInt32 *indices, UA_UInt32 indicesSize, UA_BrowsePathResult *browsePathResults, UA_DiagnosticInfo *diagnosticInfos);
typedef UA_Int32 (*UA_ExternalNodeStore_delete)(void *ensHandle);
typedef struct UA_ExternalNodeStore {
@ -281,6 +285,7 @@ typedef struct UA_ExternalNodeStore {
UA_ExternalNodeStore_writeNodes writeNodes;
UA_ExternalNodeStore_readNodes readNodes;
UA_ExternalNodeStore_browseNodes browseNodes;
UA_ExternalNodeStore_translateBrowsePathsToNodeIds translateBrowsePathsToNodeIds;
UA_ExternalNodeStore_addReferences addReferences;
UA_ExternalNodeStore_deleteReferences deleteReferences;
UA_ExternalNodeStore_delete destroy;

View File

@ -24,6 +24,7 @@ struct UA_Client {
UA_NodeId authenticationToken;
/* Config */
UA_Logger logger;
UA_ClientConfig config;
};
@ -31,13 +32,13 @@ const UA_ClientConfig UA_ClientConfig_standard =
{ 5 /* ms receive timout */, {.protocolVersion = 0, .sendBufferSize = 65536, .recvBufferSize = 65536,
.maxMessageSize = 65536, .maxChunkCount = 1}};
UA_Client * UA_Client_new(UA_ClientConfig config) {
UA_Client * UA_Client_new(UA_ClientConfig config, UA_Logger logger) {
UA_Client *client = UA_malloc(sizeof(UA_Client));
if(!client)
return UA_NULL;
client->config = config;
client->logger = logger;
UA_String_init(&client->endpointUrl);
client->connection.state = UA_CONNECTION_OPENING;
UA_Connection_init(&client->connection);
client->sequenceNumber = 0;
@ -411,19 +412,17 @@ static UA_StatusCode CloseSecureChannel(UA_Client *client) {
/* User-Facing Functions */
/*************************/
UA_StatusCode UA_Client_connect(UA_Client *client, UA_ConnectClientConnection connectFunc, char *endpointUrl)
{
UA_StatusCode retval = connectFunc(client, &client->connection, endpointUrl);
if(retval != UA_STATUSCODE_GOOD) {
return retval;
}
UA_StatusCode UA_Client_connect(UA_Client *client, UA_ConnectClientConnection connectFunc, char *endpointUrl) {
client->connection = connectFunc(endpointUrl, &client->logger);
if(client->connection.state != UA_CONNECTION_OPENING)
return UA_STATUSCODE_BADCONNECTIONCLOSED;
client->endpointUrl = UA_STRING_ALLOC(endpointUrl);
if(client->endpointUrl.length < 0)
return UA_STATUSCODE_BADOUTOFMEMORY;
client->connection.localConf = client->config.localConnectionConfig;
retval = HelAckHandshake(client);
UA_StatusCode retval = HelAckHandshake(client);
if(retval == UA_STATUSCODE_GOOD)
retval = SecureChannelHandshake(client);
if(retval == UA_STATUSCODE_GOOD)
@ -433,7 +432,7 @@ UA_StatusCode UA_Client_connect(UA_Client *client, UA_ConnectClientConnection co
return retval;
}
UA_StatusCode UA_EXPORT UA_Client_disconnect(UA_Client *client) {
UA_StatusCode UA_Client_disconnect(UA_Client *client) {
UA_StatusCode retval;
retval = CloseSession(client);
if(retval == UA_STATUSCODE_GOOD)
@ -462,6 +461,13 @@ UA_BrowseResponse UA_Client_browse(UA_Client *client, UA_BrowseRequest *request)
return response;
}
UA_BrowseNextResponse UA_Client_browseNext(UA_Client *client, UA_BrowseNextRequest *request) {
UA_BrowseNextResponse response;
synchronousRequest(request, &UA_TYPES[UA_TYPES_BROWSENEXTREQUEST], &response,
&UA_TYPES[UA_TYPES_BROWSENEXTRESPONSE], client);
return response;
}
UA_TranslateBrowsePathsToNodeIdsResponse
UA_Client_translateTranslateBrowsePathsToNodeIds(UA_Client *client,
UA_TranslateBrowsePathsToNodeIdsRequest *request) {
@ -492,8 +498,7 @@ UA_DeleteNodesResponse UA_Client_deleteNodes(UA_Client *client, UA_DeleteNodesRe
return response;
}
UA_DeleteReferencesResponse UA_EXPORT
UA_Client_deleteReferences(UA_Client *client, UA_DeleteReferencesRequest *request) {
UA_DeleteReferencesResponse UA_Client_deleteReferences(UA_Client *client, UA_DeleteReferencesRequest *request) {
UA_DeleteReferencesResponse response;
synchronousRequest(request, &UA_TYPES[UA_TYPES_BROWSEREQUEST], &response,
&UA_TYPES[UA_TYPES_BROWSERESPONSE], client);

View File

@ -6,8 +6,6 @@
#include "ua_services.h"
#include "ua_nodeids.h"
const char *UA_LoggerCategoryNames[3] = {"communication", "server", "userland"};
/**********************/
/* Namespace Handling */
/**********************/

View File

@ -57,7 +57,31 @@ addOneWayReferenceWithSession(UA_Server *server, UA_Session *session, const UA_A
const UA_Node *node = UA_NodeStore_get(server->nodestore, &item->sourceNodeId);
if(!node)
return UA_STATUSCODE_BADINTERNALERROR;
UA_StatusCode retval = UA_STATUSCODE_GOOD;
#ifndef UA_MULTITHREADING
size_t i = node->referencesSize;
if(node->referencesSize < 0)
i = 0;
UA_ReferenceNode *new_refs = UA_realloc(node->references, sizeof(UA_ReferenceNode) * (i + 1));
if(!new_refs)
retval = UA_STATUSCODE_BADOUTOFMEMORY;
else {
UA_ReferenceNode_init(&new_refs[i]);
retval = UA_NodeId_copy(&item->referenceTypeId, &new_refs[i].referenceTypeId);
new_refs[i].isInverse = !item->isForward;
retval |= UA_ExpandedNodeId_copy(&item->targetNodeId, &new_refs[i].targetId);
/* hack. be careful! possible only in the single-threaded case. */
UA_Node *mutable_node = (UA_Node*)(uintptr_t)node;
mutable_node->references = new_refs;
if(retval != UA_STATUSCODE_GOOD) {
UA_NodeId_deleteMembers(&new_refs[node->referencesSize].referenceTypeId);
UA_ExpandedNodeId_deleteMembers(&new_refs[node->referencesSize].targetId);
} else
mutable_node->referencesSize = i+1;
}
UA_NodeStore_release(node);
return retval;
#else
UA_Node *newNode = UA_NULL;
void (*deleteNode)(UA_Node*) = UA_NULL;
switch(node->nodeClass) {
@ -119,7 +143,7 @@ addOneWayReferenceWithSession(UA_Server *server, UA_Session *session, const UA_A
// insert the new reference
UA_memcpy(new_refs, old_refs, sizeof(UA_ReferenceNode)*count);
UA_ReferenceNode_init(&new_refs[count]);
UA_StatusCode retval = UA_NodeId_copy(&item->referenceTypeId, &new_refs[count].referenceTypeId);
retval = UA_NodeId_copy(&item->referenceTypeId, &new_refs[count].referenceTypeId);
new_refs[count].isInverse = !item->isForward;
retval |= UA_ExpandedNodeId_copy(&item->targetNodeId, &new_refs[count].targetId);
if(retval != UA_STATUSCODE_GOOD) {
@ -135,13 +159,14 @@ addOneWayReferenceWithSession(UA_Server *server, UA_Session *session, const UA_A
newNode->references = new_refs;
newNode->referencesSize = ++count;
retval = UA_NodeStore_replace(server->nodestore, node, newNode, UA_NULL);
UA_NodeStore_release(node);
if(retval != UA_STATUSCODE_BADINTERNALERROR)
return retval;
// error presumably because the node was replaced and an old version was updated just try again
deleteNode(newNode);
return addOneWayReferenceWithSession(server, session, item);
UA_NodeStore_release(node);
if (retval == UA_STATUSCODE_BADINTERNALERROR) {
/* presumably because the node was replaced and an old version was updated at the same time. just try again */
deleteNode(newNode);
return addOneWayReferenceWithSession(server, session, item);
}
return retval;
#endif
}
/* userland version of addReferenceWithSession */

View File

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

View File

@ -89,7 +89,7 @@ void Service_ActivateSession(UA_Server *server, UA_SecureChannel *channel,
const UA_ActivateSessionRequest *request, UA_ActivateSessionResponse *response);
/** Used to terminate a Session. */
void Service_CloseSession(UA_Server *server, const UA_CloseSessionRequest *request,
void Service_CloseSession(UA_Server *server, UA_Session *session, const UA_CloseSessionRequest *request,
UA_CloseSessionResponse *response);
// Service_Cancel
/** @} */
@ -136,14 +136,23 @@ void Service_DeleteReferences(UA_Server *server, UA_Session *session, const UA_D
* further limited by the use of a View. This Browse Service also supports a
* primitive filtering capability.
*/
void Service_Browse(UA_Server *server, UA_Session *session,
const UA_BrowseRequest *request, UA_BrowseResponse *response);
void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseRequest *request,
UA_BrowseResponse *response);
/**
* Used to request the next set of Browse or BrowseNext response information
* that is too large to be sent in a single response. Too large in this
* context means that the Server is not able to return a larger response or that
* the number of results to return exceeds the maximum number of results to
* return that was specified by the Client in the original Browse request.
*/
void Service_BrowseNext(UA_Server *server, UA_Session *session, const UA_BrowseNextRequest *request,
UA_BrowseNextResponse *response);
/** Used to translate textual node paths to their respective ids. */
void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *session,
const UA_TranslateBrowsePathsToNodeIdsRequest *request,
UA_TranslateBrowsePathsToNodeIdsResponse *response);
// Service_BrowseNext
// Service_RegisterNodes
void Service_RegisterNodes(UA_Server *server, UA_Session *session, const UA_RegisterNodesRequest *request,

View File

@ -20,7 +20,7 @@ void Service_FindServers(UA_Server *server, const UA_FindServersRequest *request
void Service_GetEndpoints(UA_Server *server, const UA_GetEndpointsRequest *request, UA_GetEndpointsResponse *response) {
/* test if the supported binary profile shall be returned */
UA_Boolean relevant_endpoints[server->endpointDescriptionsSize];
UA_Boolean *relevant_endpoints = UA_alloca(sizeof(UA_Boolean)*server->endpointDescriptionsSize);
size_t relevant_count = 0;
for(UA_Int32 j = 0; j < server->endpointDescriptionsSize; j++) {
relevant_endpoints[j] = UA_FALSE;

View File

@ -53,8 +53,8 @@ void Service_ActivateSession(UA_Server *server,UA_SecureChannel *channel,
channel->session = foundSession;
}
void Service_CloseSession(UA_Server *server, const UA_CloseSessionRequest *request,
UA_CloseSessionResponse *response) {
void Service_CloseSession(UA_Server *server, UA_Session *session, const UA_CloseSessionRequest *request,
UA_CloseSessionResponse *response) {
UA_Session *foundSession;
UA_SessionManager_getSessionByToken(&server->sessionManager,
(const UA_NodeId*)&request->requestHeader.authenticationToken, &foundSession);
@ -64,8 +64,6 @@ void Service_CloseSession(UA_Server *server, const UA_CloseSessionRequest *reque
return;
}
if(UA_SessionManager_removeSession(&server->sessionManager, &foundSession->sessionId) == UA_STATUSCODE_GOOD)
response->responseHeader.serviceResult = UA_STATUSCODE_GOOD;
else
response->responseHeader.serviceResult = UA_STATUSCODE_BADSECURECHANNELIDINVALID;
response->responseHeader.serviceResult =
UA_SessionManager_removeSession(&server->sessionManager, &session->sessionId);
}

View File

@ -4,9 +4,8 @@
#include "ua_nodestore.h"
#include "ua_util.h"
static UA_StatusCode
fillrefdescr(UA_NodeStore *ns, const UA_Node *curr, UA_ReferenceNode *ref, UA_UInt32 mask,
UA_ReferenceDescription *descr)
static UA_StatusCode fillrefdescr(UA_NodeStore *ns, const UA_Node *curr, UA_ReferenceNode *ref,
UA_UInt32 mask, UA_ReferenceDescription *descr)
{
UA_StatusCode retval = UA_STATUSCODE_GOOD;
UA_ReferenceDescription_init(descr);
@ -25,13 +24,14 @@ fillrefdescr(UA_NodeStore *ns, const UA_Node *curr, UA_ReferenceNode *ref, UA_UI
retval |= UA_QualifiedName_copy(&curr->browseName, &descr->browseName);
if(mask & UA_BROWSERESULTMASK_DISPLAYNAME)
retval |= UA_LocalizedText_copy(&curr->displayName, &descr->displayName);
if(mask & UA_BROWSERESULTMASK_TYPEDEFINITION ) {
for(UA_Int32 i = 0;i < curr->referencesSize;i++) {
if(mask & UA_BROWSERESULTMASK_TYPEDEFINITION &&
(curr->nodeClass == UA_NODECLASS_OBJECT || curr->nodeClass == UA_NODECLASS_VARIABLE)) {
for(UA_Int32 i = 0; i < curr->referencesSize; i++) {
UA_ReferenceNode *refnode = &curr->references[i];
if(refnode->referenceTypeId.identifier.numeric == UA_NS0ID_HASTYPEDEFINITION) {
retval |= UA_ExpandedNodeId_copy(&refnode->targetId, &descr->typeDefinition);
break;
}
if(refnode->referenceTypeId.identifier.numeric != UA_NS0ID_HASTYPEDEFINITION)
continue;
retval |= UA_ExpandedNodeId_copy(&refnode->targetId, &descr->typeDefinition);
break;
}
}
@ -42,9 +42,9 @@ fillrefdescr(UA_NodeStore *ns, const UA_Node *curr, UA_ReferenceNode *ref, UA_UI
/* Tests if the node is relevant to the browse request and shall be returned. If
so, it is retrieved from the Nodestore. If not, null is returned. */
static const UA_Node
*relevant_node(UA_NodeStore *ns, const UA_BrowseDescription *descr, UA_Boolean return_all,
UA_ReferenceNode *reference, UA_NodeId *relevant, size_t relevant_count)
static const UA_Node *relevant_node(UA_NodeStore *ns, const UA_BrowseDescription *descr,
UA_Boolean return_all, UA_ReferenceNode *reference,
UA_NodeId *relevant, size_t relevant_count)
{
if(reference->isInverse == UA_TRUE && descr->browseDirection == UA_BROWSEDIRECTION_FORWARD)
return UA_NULL;
@ -73,14 +73,21 @@ is_relevant: ;
* the array and increase the size. Since the hierarchy is not cyclic, we can safely progress in the
* array to process the newly found referencetype nodeids (emulated recursion).
*/
static UA_StatusCode
findsubtypes(UA_NodeStore *ns, const UA_NodeId *root, UA_NodeId **reftypes, size_t *reftypes_count)
static UA_StatusCode findsubtypes(UA_NodeStore *ns, const UA_NodeId *root, UA_NodeId **reftypes,
size_t *reftypes_count)
{
size_t results_size = 20; // probably too big, but saves mallocs
UA_NodeId *results = UA_malloc(sizeof(UA_NodeId) * results_size);
if(!results)
return UA_STATUSCODE_BADOUTOFMEMORY;
const UA_Node *node = UA_NodeStore_get(ns, root);
if(!node || node->nodeClass != UA_NODECLASS_REFERENCETYPE) {
UA_NodeStore_release(node);
return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
}
UA_NodeStore_release(node);
UA_StatusCode retval = UA_NodeId_copy(root, &results[0]);
if(retval != UA_STATUSCODE_GOOD) {
UA_free(results);
@ -90,7 +97,7 @@ findsubtypes(UA_NodeStore *ns, const UA_NodeId *root, UA_NodeId **reftypes, size
size_t index = 0; // where are we currently in the array?
size_t last = 0; // where is the last element in the array?
do {
const UA_Node *node = UA_NodeStore_get(ns, &results[index]);
node = UA_NodeStore_get(ns, &results[index]);
if(!node || node->nodeClass != UA_NODECLASS_REFERENCETYPE)
continue;
for(UA_Int32 i = 0; i < node->referencesSize; i++) {
@ -127,19 +134,36 @@ findsubtypes(UA_NodeStore *ns, const UA_NodeId *root, UA_NodeId **reftypes, size
return UA_STATUSCODE_GOOD;
}
/* Results for a single browsedescription. */
static void
browse(UA_NodeStore *ns, const UA_BrowseDescription *descr, UA_UInt32 maxrefs, UA_BrowseResult *result)
/* Results for a single browsedescription. Call this either with an existing continuationpoint from
which we take the entire context for the search. Or, call with a browsedescription and maxrefs
value. If we need to create a new continuationpoint, it will be alloced and the new pointer
stored in *cp.
*/
static void browse(UA_NodeStore *ns, struct ContinuationPointEntry **cp, const UA_BrowseDescription *descr,
UA_UInt32 maxrefs, UA_BrowseResult *result)
{
UA_UInt32 continuationIndex = 0;
if(*cp) {
descr = &(*cp)->browseDescription;
maxrefs = (*cp)->maxReferences;
continuationIndex = (*cp)->continuationIndex;
}
if(descr->browseDirection != UA_BROWSEDIRECTION_BOTH &&
descr->browseDirection != UA_BROWSEDIRECTION_FORWARD &&
descr->browseDirection != UA_BROWSEDIRECTION_INVERSE) {
result->statusCode = UA_STATUSCODE_BADBROWSEDIRECTIONINVALID;
return;
}
size_t relevant_refs_size = 0;
UA_NodeId *relevant_refs = UA_NULL;
// what are the relevant references?
UA_Boolean all_refs = UA_NodeId_isNull(&descr->referenceTypeId);
if(!all_refs) {
if(descr->includeSubtypes) {
result->statusCode = findsubtypes(ns, &descr->referenceTypeId,
&relevant_refs, &relevant_refs_size);
result->statusCode = findsubtypes(ns, &descr->referenceTypeId, &relevant_refs,
&relevant_refs_size);
if(result->statusCode != UA_STATUSCODE_GOOD)
return;
} else {
@ -162,35 +186,64 @@ browse(UA_NodeStore *ns, const UA_BrowseDescription *descr, UA_UInt32 maxrefs, U
goto cleanup;
}
// allocate memory for the results
maxrefs = node->referencesSize; // allocate enough space for all of them
result->references = UA_malloc(sizeof(UA_ReferenceDescription) * maxrefs);
UA_UInt32 real_maxrefs = maxrefs;
if(real_maxrefs == 0)
real_maxrefs = node->referencesSize;
result->references = UA_malloc(sizeof(UA_ReferenceDescription) * real_maxrefs);
if(!result->references) {
result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
goto cleanup;
}
size_t count = 0;
for(UA_Int32 i = 0; i < node->referencesSize && count < maxrefs; i++) {
const UA_Node *current;
current = relevant_node(ns, descr, all_refs, &node->references[i], relevant_refs, relevant_refs_size);
size_t skipped = 0;
for(UA_Int32 i = 0; i < node->referencesSize && count < real_maxrefs; i++) {
const UA_Node *current = relevant_node(ns, descr, all_refs, &node->references[i],
relevant_refs, relevant_refs_size);
if(!current)
continue;
UA_StatusCode retval = fillrefdescr(ns, current, &node->references[i],
descr->resultMask, &result->references[count]);
if(skipped < continuationIndex) {
UA_NodeStore_release(current);
skipped++;
continue;
}
UA_StatusCode retval = fillrefdescr(ns, current, &node->references[i], descr->resultMask,
&result->references[count]);
UA_NodeStore_release(current);
if(retval) {
if(retval != UA_STATUSCODE_GOOD) {
UA_Array_delete(result->references, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION], count);
count = 0;
result->references = UA_NULL;
count = 0;
result->statusCode = UA_STATUSCODE_UNCERTAINNOTALLNODESAVAILABLE;
break;
goto cleanup;
}
count++;
}
if(count != 0)
if(*cp) {
(*cp)->continuationIndex += count;
if((*cp)->continuationIndex == node->referencesSize) {
/* remove a finished continuationPoint */
UA_ByteString_deleteMembers(&(*cp)->identifier);
UA_BrowseDescription_deleteMembers(&(*cp)->browseDescription);
LIST_REMOVE(*cp, pointers);
UA_free(*cp);
*cp = UA_NULL;
}
} else if(maxrefs != 0 && count >= maxrefs) {
/* create a continuationPoint */
*cp = UA_malloc(sizeof(struct ContinuationPointEntry));
UA_BrowseDescription_copy(descr,&(*cp)->browseDescription);
(*cp)->maxReferences = maxrefs;
(*cp)->continuationIndex = count;
UA_Guid *ident = UA_Guid_new();
UA_UInt32 seed = (uintptr_t)*cp;
*ident = UA_Guid_random(&seed);
(*cp)->identifier.data = (UA_Byte*)ident;
(*cp)->identifier.length = sizeof(UA_Guid);
}
if(count > 0)
result->referencesSize = count;
else {
UA_free(result->references);
@ -205,6 +258,11 @@ cleanup:
void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseRequest *request,
UA_BrowseResponse *response) {
if(!UA_NodeId_isNull(&request->view.viewId)) {
response->responseHeader.serviceResult = UA_STATUSCODE_BADVIEWIDUNKNOWN;
return;
}
if(request->nodesToBrowseSize <= 0) {
response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
return;
@ -240,13 +298,63 @@ void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseReque
/* ### End External Namespaces */
response->resultsSize = size;
for(size_t i = 0;i < size;i++){
if(!isExternal[i])
browse(server->nodestore, &request->nodesToBrowse[i],
for(size_t i = 0; i < size; i++) {
if(!isExternal[i]) {
struct ContinuationPointEntry *cp = UA_NULL;
browse(server->nodestore, &cp, &request->nodesToBrowse[i],
request->requestedMaxReferencesPerNode, &response->results[i]);
if(cp) {
LIST_INSERT_HEAD(&session->continuationPoints, cp, pointers);
UA_ByteString_copy(&cp->identifier, &response->results[i].continuationPoint);
}
}
}
}
void Service_BrowseNext(UA_Server *server, UA_Session *session, const UA_BrowseNextRequest *request,
UA_BrowseNextResponse *response) {
if(request->continuationPointsSize <= 0) {
response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
return;
}
size_t size = request->continuationPointsSize;
if(!request->releaseContinuationPoints) {
response->results = UA_Array_new(&UA_TYPES[UA_TYPES_BROWSERESULT], size);
if(!response->results) {
response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
return;
}
response->resultsSize = size;
for(size_t i = 0; i < size; i++) {
struct ContinuationPointEntry *cp = UA_NULL;
struct ContinuationPointEntry *search_cp;
LIST_FOREACH(search_cp, &session->continuationPoints, pointers) {
if(UA_ByteString_equal(&search_cp->identifier, &request->continuationPoints[i])) {
cp = search_cp;
break;
}
}
if(!cp)
response->results[i].statusCode = UA_STATUSCODE_BADCONTINUATIONPOINTINVALID;
else
browse(server->nodestore, &cp, UA_NULL, 0, &response->results[i]);
}
} else {
for(size_t i = 0; i < size; i++) {
struct ContinuationPointEntry *cp = UA_NULL;
LIST_FOREACH(cp, &session->continuationPoints, pointers) {
if(UA_ByteString_equal(&cp->identifier, &request->continuationPoints[i])) {
UA_ByteString_deleteMembers(&cp->identifier);
UA_BrowseDescription_deleteMembers(&cp->browseDescription);
LIST_REMOVE(cp, pointers);
UA_free(cp);
break;
}
}
}
}
}
/***********************/
/* TranslateBrowsePath */
/***********************/
@ -364,49 +472,67 @@ static void translateBrowsePath(UA_Server *server, UA_Session *session, const UA
void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *session,
const UA_TranslateBrowsePathsToNodeIdsRequest *request,
UA_TranslateBrowsePathsToNodeIdsResponse *response) {
if(request->browsePathsSize <= 0) {
size_t size = request->browsePathsSize;
if(size <= 0) {
response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
return;
}
response->results = UA_Array_new(&UA_TYPES[UA_TYPES_BROWSEPATHRESULT], request->browsePathsSize);
response->results = UA_Array_new(&UA_TYPES[UA_TYPES_BROWSEPATHRESULT], size);
if(!response->results) {
response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
return;
}
response->resultsSize = request->browsePathsSize;
for(UA_Int32 i = 0;i < response->resultsSize;i++)
translateBrowsePath(server, session, &request->browsePaths[i], &response->results[i]);
/* ### Begin External Namespaces */
UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
for(UA_Int32 j = 0;j<server->externalNamespacesSize;j++) {
size_t indexSize = 0;
for(size_t i = 0;i < size;i++) {
if(request->browsePaths[i].startingNode.namespaceIndex != server->externalNamespaces[j].index)
continue;
isExternal[i] = UA_TRUE;
indices[indexSize] = i;
indexSize++;
}
if(indexSize == 0)
continue;
UA_ExternalNodeStore *ens = &server->externalNamespaces[j].externalNodeStore;
ens->translateBrowsePathsToNodeIds(ens->ensHandle, &request->requestHeader, request->browsePaths,
indices, indexSize, response->results, response->diagnosticInfos);
}
/* ### End External Namespaces */
response->resultsSize = size;
for(size_t i = 0; i < size; i++){
if(!isExternal[i])
translateBrowsePath(server, session, &request->browsePaths[i], &response->results[i]);
}
}
void Service_RegisterNodes(UA_Server *server, UA_Session *session,
const UA_RegisterNodesRequest *request,
UA_RegisterNodesResponse *response) {
void Service_RegisterNodes(UA_Server *server, UA_Session *session, const UA_RegisterNodesRequest *request,
UA_RegisterNodesResponse *response) {
//TODO: hang the nodeids to the session if really needed
response->responseHeader.timestamp = UA_DateTime_now();
response->registeredNodeIdsSize = request->nodesToRegisterSize;
response->registeredNodeIds = request->nodesToRegister;
if(request->nodesToRegisterSize==0){
if(request->nodesToRegisterSize==0)
response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
}
if(UA_NodeId_equal(&request->requestHeader.authenticationToken, &UA_NODEID_NULL) || !UA_NodeId_equal(&request->requestHeader.authenticationToken, &session->authenticationToken) ){
if(UA_NodeId_equal(&request->requestHeader.authenticationToken, &UA_NODEID_NULL) ||
!UA_NodeId_equal(&request->requestHeader.authenticationToken, &session->authenticationToken))
response->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
}
}
void Service_UnregisterNodes(UA_Server *server, UA_Session *session,
const UA_UnregisterNodesRequest *request,
UA_UnregisterNodesResponse *response) {
void Service_UnregisterNodes(UA_Server *server, UA_Session *session, const UA_UnregisterNodesRequest *request,
UA_UnregisterNodesResponse *response) {
//TODO: remove the nodeids from the session if really needed
response->responseHeader.timestamp = UA_DateTime_now();
if(request->nodesToUnregisterSize==0){
if(request->nodesToUnregisterSize==0)
response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
}
if(UA_NodeId_equal(&request->requestHeader.authenticationToken, &UA_NODEID_NULL) || !UA_NodeId_equal(&request->requestHeader.authenticationToken, &session->authenticationToken) ){
if(UA_NodeId_equal(&request->requestHeader.authenticationToken, &UA_NODEID_NULL) ||
!UA_NodeId_equal(&request->requestHeader.authenticationToken, &session->authenticationToken))
response->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
}
}

View File

@ -2,13 +2,15 @@
#include "ua_connection.h"
#include "ua_types_encoding_binary.h"
const char *UA_LoggerCategoryNames[4] = {"communication", "server", "client", "userland"};
// max message size is 64k
const UA_ConnectionConfig UA_ConnectionConfig_standard =
{.protocolVersion = 0, .sendBufferSize = 65536, .recvBufferSize = 65536,
.maxMessageSize = 65536, .maxChunkCount = 1};
void UA_Connection_init(UA_Connection *connection) {
connection->state = UA_CONNECTION_OPENING;
connection->state = UA_CONNECTION_CLOSED;
connection->localConf = (UA_ConnectionConfig){0,0,0,0,0};
connection->remoteConf = (UA_ConnectionConfig){0,0,0,0,0};
connection->channel = UA_NULL;

View File

@ -10,10 +10,11 @@ UA_Session anonymousSession = {
.discoveryUrlsSize = -1, .discoveryUrls = UA_NULL},
.sessionName = {sizeof("Anonymous Session")-1, (UA_Byte*)"Anonymous Session"},
.authenticationToken = {.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC,
.identifier.numeric = 0},
.identifier.numeric = 0},
.sessionId = {.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 0},
.maxRequestMessageSize = UA_UINT32_MAX, .maxResponseMessageSize = UA_UINT32_MAX,
.timeout = UA_INT64_MAX, .validTill = UA_INT64_MAX, .channel = UA_NULL};
.timeout = UA_INT64_MAX, .validTill = UA_INT64_MAX, .channel = UA_NULL,
.continuationPoints = {UA_NULL}};
UA_Session adminSession = {
.clientDescription = {.applicationUri = {-1, UA_NULL}, .productUri = {-1, UA_NULL},
@ -26,7 +27,16 @@ UA_Session adminSession = {
.identifier.numeric = 1},
.sessionId = {.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 1},
.maxRequestMessageSize = UA_UINT32_MAX, .maxResponseMessageSize = UA_UINT32_MAX,
.timeout = UA_INT64_MAX, .validTill = UA_INT64_MAX, .channel = UA_NULL};
.timeout = UA_INT64_MAX, .validTill = UA_INT64_MAX, .channel = UA_NULL,
.continuationPoints = {UA_NULL}};
/* TODO: Nobody seems to call this function right now */
static UA_StatusCode UA_Session_generateToken(UA_NodeId *newToken, UA_UInt32 *seed) {
newToken->namespaceIndex = 0; // where else?
newToken->identifierType = UA_NODEIDTYPE_GUID;
newToken->identifier.guid = UA_Guid_random(seed);
return UA_STATUSCODE_GOOD;
}
void UA_Session_init(UA_Session *session) {
UA_ApplicationDescription_init(&session->clientDescription);
@ -38,6 +48,7 @@ void UA_Session_init(UA_Session *session) {
session->timeout = 0;
UA_DateTime_init(&session->validTill);
session->channel = UA_NULL;
session->continuationPoints = (struct ContinuationPointList){UA_NULL};
}
void UA_Session_deleteMembers(UA_Session *session) {
@ -46,6 +57,13 @@ void UA_Session_deleteMembers(UA_Session *session) {
UA_NodeId_deleteMembers(&session->sessionId);
UA_String_deleteMembers(&session->sessionName);
session->channel = UA_NULL;
struct ContinuationPointEntry *cp;
while((cp = LIST_FIRST(&session->continuationPoints))) {
UA_ByteString_deleteMembers(&cp->identifier);
UA_BrowseDescription_deleteMembers(&cp->browseDescription);
LIST_REMOVE(cp, pointers);
UA_free(cp);
}
}
UA_StatusCode UA_Session_setExpirationDate(UA_Session *session) {

View File

@ -3,6 +3,7 @@
#include "ua_types.h"
#include "ua_securechannel.h"
#include "queue.h"
/**
* @ingroup communication
@ -10,6 +11,14 @@
* @{
*/
struct ContinuationPointEntry {
LIST_ENTRY(ContinuationPointEntry) pointers;
UA_ByteString identifier;
UA_BrowseDescription browseDescription;
UA_Int32 continuationIndex;
UA_UInt32 maxReferences;
};
struct UA_Session {
UA_ApplicationDescription clientDescription;
UA_String sessionName;
@ -20,6 +29,7 @@ struct UA_Session {
UA_Int64 timeout;
UA_DateTime validTill;
UA_SecureChannel *channel;
LIST_HEAD(ContinuationPointList, ContinuationPointEntry) continuationPoints;
};
extern UA_Session anonymousSession; ///< If anonymous access is allowed, this session is used internally (Session ID: 0)

View File

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

View File

@ -48,6 +48,7 @@ minimal_types = ["InvalidType", "Node", "NodeClass", "ReferenceNode", "Applicati
"TranslateBrowsePathsToNodeIdsResponse", "BrowsePath", "BrowsePathResult", "RelativePath",
"BrowsePathTarget", "RelativePathElement", "CreateSubscriptionRequest", "CreateSubscriptionResponse",
"BrowseResponse", "BrowseResult", "ReferenceDescription", "BrowseRequest", "ViewDescription",
"BrowseNextRequest", "BrowseNextResponse",
"BrowseDescription", "BrowseDirection", "CloseSessionRequest", "AddNodesRequest", "AddNodesResponse",
"AddNodesItem", "AddNodesResult", "DeleteNodesItem","AddReferencesRequest", "AddReferencesResponse",
"AddReferencesItem","DeleteReferencesItem", "VariableNode", "MethodNode", "VariableTypeNode",