mirror of
https://github.com/open62541/open62541.git
synced 2025-06-03 04:00:21 +00:00
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:
commit
ba36eba3bc
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
/** @} */
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -6,8 +6,6 @@
|
||||
#include "ua_services.h"
|
||||
#include "ua_nodeids.h"
|
||||
|
||||
const char *UA_LoggerCategoryNames[3] = {"communication", "server", "userland"};
|
||||
|
||||
/**********************/
|
||||
/* Namespace Handling */
|
||||
/**********************/
|
||||
|
@ -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 */
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user