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)
|
add_definitions(-DEXTENSION_STATELESS)
|
||||||
message(STATUS "Extensions: enabling udp")
|
message(STATUS "Extensions: enabling udp")
|
||||||
add_definitions(-DEXTENSION_UDP)
|
add_definitions(-DEXTENSION_UDP)
|
||||||
|
add_executable(exampleServerUDP $<TARGET_OBJECTS:open62541-object> examples/networklayer_udp.c examples/server_udp.c)
|
||||||
|
target_link_libraries(exampleServerUDP rt)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(EXTENSION_STATELESS "Enable stateless extension" OFF)
|
option(EXTENSION_STATELESS "Enable stateless extension" OFF)
|
||||||
|
@ -46,9 +46,9 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
/* init the server */
|
/* init the server */
|
||||||
UA_Server *server = UA_Server_new();
|
UA_Server *server = UA_Server_new();
|
||||||
|
UA_Server_setLogger(server, Logger_Stdout_new());
|
||||||
UA_Server_addNetworkLayer(server,
|
UA_Server_addNetworkLayer(server,
|
||||||
ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, PORT));
|
ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, PORT));
|
||||||
UA_Server_setLogger(server, Logger_Stdout_new());
|
|
||||||
UA_UInt16 nsIndex = UA_Server_addNamespace(server, "myApplicationNamespace");
|
UA_UInt16 nsIndex = UA_Server_addNamespace(server, "myApplicationNamespace");
|
||||||
|
|
||||||
/* add a variable node */
|
/* add a variable node */
|
||||||
@ -76,8 +76,7 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
UA_Client *client = UA_Client_new(UA_ClientConfig_standard);
|
UA_Client *client = UA_Client_new(UA_ClientConfig_standard);
|
||||||
UA_ClientNetworkLayer nl = ClientNetworkLayerTCP_new(UA_ConnectionConfig_standard);
|
UA_StatusCode retval = UA_Client_connect(client, ClientNetworkLayerTCP_connect,
|
||||||
UA_StatusCode retval = UA_Client_connect(client, UA_ConnectionConfig_standard, nl,
|
|
||||||
"opc.tcp://localhost:16664");
|
"opc.tcp://localhost:16664");
|
||||||
if(retval != UA_STATUSCODE_GOOD) {
|
if(retval != UA_STATUSCODE_GOOD) {
|
||||||
UA_Client_delete(client);
|
UA_Client_delete(client);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "ua_client.h"
|
#include "ua_client.h"
|
||||||
#include "ua_nodeids.h"
|
#include "ua_nodeids.h"
|
||||||
#include "networklayer_tcp.h"
|
#include "networklayer_tcp.h"
|
||||||
|
#include "logger_stdout.h"
|
||||||
#else
|
#else
|
||||||
#include "open62541.h"
|
#include "open62541.h"
|
||||||
#endif
|
#endif
|
||||||
@ -11,7 +12,7 @@
|
|||||||
#include "networklayer_tcp.h"
|
#include "networklayer_tcp.h"
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
UA_Client *client = UA_Client_new(UA_ClientConfig_standard);
|
UA_Client *client = UA_Client_new(UA_ClientConfig_standard, Logger_Stdout_new());
|
||||||
UA_StatusCode retval = UA_Client_connect(client, ClientNetworkLayerTCP_connect,
|
UA_StatusCode retval = UA_Client_connect(client, ClientNetworkLayerTCP_connect,
|
||||||
"opc.tcp://localhost:16664");
|
"opc.tcp://localhost:16664");
|
||||||
if(retval != UA_STATUSCODE_GOOD) {
|
if(retval != UA_STATUSCODE_GOOD) {
|
||||||
|
@ -119,6 +119,20 @@ static UA_StatusCode socket_set_nonblocking(UA_Int32 sockfd) {
|
|||||||
return UA_STATUSCODE_GOOD;
|
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 */
|
/* Server NetworkLayer TCP */
|
||||||
/***************************/
|
/***************************/
|
||||||
@ -157,7 +171,7 @@ static UA_StatusCode socket_set_nonblocking(UA_Int32 sockfd) {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* config */
|
/* config */
|
||||||
UA_Server *server;
|
UA_Logger *logger;
|
||||||
UA_UInt32 port;
|
UA_UInt32 port;
|
||||||
UA_String discoveryUrl;
|
UA_String discoveryUrl;
|
||||||
UA_ConnectionConfig conf; /* todo: rename to localconf. */
|
UA_ConnectionConfig conf; /* todo: rename to localconf. */
|
||||||
@ -209,9 +223,7 @@ static void ServerNetworkLayerTCP_closeConnection(UA_Connection *connection) {
|
|||||||
return;
|
return;
|
||||||
connection->state = UA_CONNECTION_CLOSED;
|
connection->state = UA_CONNECTION_CLOSED;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
socket_close(connection);
|
socket_close(connection);
|
||||||
|
|
||||||
ServerNetworkLayerTCP *layer = (ServerNetworkLayerTCP*)connection->handle;
|
ServerNetworkLayerTCP *layer = (ServerNetworkLayerTCP*)connection->handle;
|
||||||
struct DeleteList *d = malloc(sizeof(struct DeleteList));
|
struct DeleteList *d = malloc(sizeof(struct DeleteList));
|
||||||
d->connection = connection;
|
d->connection = connection;
|
||||||
@ -232,65 +244,60 @@ static UA_StatusCode ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_
|
|||||||
UA_Connection *c = malloc(sizeof(UA_Connection));
|
UA_Connection *c = malloc(sizeof(UA_Connection));
|
||||||
if(!c)
|
if(!c)
|
||||||
return UA_STATUSCODE_BADINTERNALERROR;
|
return UA_STATUSCODE_BADINTERNALERROR;
|
||||||
|
|
||||||
UA_Connection_init(c);
|
UA_Connection_init(c);
|
||||||
c->sockfd = newsockfd;
|
c->sockfd = newsockfd;
|
||||||
c->handle = layer;
|
c->handle = layer;
|
||||||
c->localConf = layer->conf;
|
c->localConf = layer->conf;
|
||||||
c->write = socket_write;
|
c->write = socket_write;
|
||||||
c->close = ServerNetworkLayerTCP_closeConnection;
|
c->close = ServerNetworkLayerTCP_closeConnection;
|
||||||
|
c->getBuffer = GetMallocedBuffer;
|
||||||
struct ConnectionMapping *nm = realloc(layer->mappings,
|
c->releaseBuffer = ReleaseMallocedBuffer;
|
||||||
sizeof(struct ConnectionMapping)*(layer->mappingsSize+1));
|
struct ConnectionMapping *nm =
|
||||||
|
realloc(layer->mappings, sizeof(struct ConnectionMapping)*(layer->mappingsSize+1));
|
||||||
if(!nm) {
|
if(!nm) {
|
||||||
free(c);
|
free(c);
|
||||||
return UA_STATUSCODE_BADINTERNALERROR;
|
return UA_STATUSCODE_BADINTERNALERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
layer->mappings = nm;
|
layer->mappings = nm;
|
||||||
layer->mappings[layer->mappingsSize] = (struct ConnectionMapping){c, newsockfd};
|
layer->mappings[layer->mappingsSize] = (struct ConnectionMapping){c, newsockfd};
|
||||||
layer->mappingsSize++;
|
layer->mappingsSize++;
|
||||||
return UA_STATUSCODE_GOOD;
|
return UA_STATUSCODE_GOOD;
|
||||||
}
|
}
|
||||||
|
|
||||||
static UA_StatusCode ServerNetworkLayerTCP_start(ServerNetworkLayerTCP *layer) {
|
static UA_StatusCode ServerNetworkLayerTCP_start(ServerNetworkLayerTCP *layer, UA_Logger *logger) {
|
||||||
UA_Logger *logger = UA_Server_getLogger(layer->server);
|
layer->logger = logger;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if((layer->serversockfd = socket(PF_INET, SOCK_STREAM,0)) == (UA_Int32)INVALID_SOCKET) {
|
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());
|
WSAGetLastError());
|
||||||
return UA_STATUSCODE_BADINTERNALERROR;
|
return UA_STATUSCODE_BADINTERNALERROR;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if((layer->serversockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
|
if((layer->serversockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
|
||||||
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;
|
return UA_STATUSCODE_BADINTERNALERROR;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
const struct sockaddr_in serv_addr =
|
||||||
const struct sockaddr_in serv_addr = {
|
{.sin_family = AF_INET, .sin_addr.s_addr = INADDR_ANY,
|
||||||
.sin_family = AF_INET, .sin_addr.s_addr = INADDR_ANY,
|
.sin_port = htons(layer->port), .sin_zero = {0}};
|
||||||
.sin_port = htons(layer->port), .sin_zero = {0}};
|
|
||||||
|
|
||||||
int optval = 1;
|
int optval = 1;
|
||||||
if(setsockopt(layer->serversockfd, SOL_SOCKET,
|
if(setsockopt(layer->serversockfd, SOL_SOCKET,
|
||||||
SO_REUSEADDR, (const char *)&optval,
|
SO_REUSEADDR, (const char *)&optval,
|
||||||
sizeof(optval)) == -1) {
|
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);
|
CLOSESOCKET(layer->serversockfd);
|
||||||
return UA_STATUSCODE_BADINTERNALERROR;
|
return UA_STATUSCODE_BADINTERNALERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(bind(layer->serversockfd, (const struct sockaddr *)&serv_addr,
|
if(bind(layer->serversockfd, (const struct sockaddr *)&serv_addr,
|
||||||
sizeof(serv_addr)) < 0) {
|
sizeof(serv_addr)) < 0) {
|
||||||
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);
|
CLOSESOCKET(layer->serversockfd);
|
||||||
return UA_STATUSCODE_BADINTERNALERROR;
|
return UA_STATUSCODE_BADINTERNALERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
socket_set_nonblocking(layer->serversockfd);
|
socket_set_nonblocking(layer->serversockfd);
|
||||||
listen(layer->serversockfd, MAXBACKLOG);
|
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);
|
layer->discoveryUrl.length, layer->discoveryUrl.data);
|
||||||
return UA_STATUSCODE_GOOD;
|
return UA_STATUSCODE_GOOD;
|
||||||
}
|
}
|
||||||
@ -335,7 +342,6 @@ static UA_Int32 ServerNetworkLayerTCP_getWork(ServerNetworkLayerTCP *layer, UA_W
|
|||||||
setFDSet(layer);
|
setFDSet(layer);
|
||||||
struct timeval tmptv = {0, timeout * 1000};
|
struct timeval tmptv = {0, timeout * 1000};
|
||||||
UA_Int32 resultsize = select(layer->highestfd+1, &layer->fdset, NULL, NULL, &tmptv);
|
UA_Int32 resultsize = select(layer->highestfd+1, &layer->fdset, NULL, NULL, &tmptv);
|
||||||
|
|
||||||
UA_WorkItem *items;
|
UA_WorkItem *items;
|
||||||
if(resultsize < 0 || !(items = malloc(sizeof(UA_WorkItem)*(resultsize+1)))) {
|
if(resultsize < 0 || !(items = malloc(sizeof(UA_WorkItem)*(resultsize+1)))) {
|
||||||
/* abort .. reattach the deletes so that they get deleted eventually.. */
|
/* 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;
|
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)) {
|
if(FD_ISSET(layer->serversockfd, &layer->fdset)) {
|
||||||
resultsize--;
|
resultsize--;
|
||||||
struct sockaddr_in cli_addr;
|
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++) {
|
for(size_t i = 0; i < layer->mappingsSize && j < resultsize; i++) {
|
||||||
if(!(FD_ISSET(layer->mappings[i].sockfd, &layer->fdset)))
|
if(!(FD_ISSET(layer->mappings[i].sockfd, &layer->fdset)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if(!buf.data) {
|
if(!buf.data) {
|
||||||
buf.data = malloc(sizeof(UA_Byte) * layer->conf.recvBufferSize);
|
buf.data = malloc(sizeof(UA_Byte) * layer->conf.recvBufferSize);
|
||||||
buf.length = layer->conf.recvBufferSize;
|
buf.length = layer->conf.recvBufferSize;
|
||||||
if(!buf.data)
|
if(!buf.data)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(socket_recv(layer->mappings[i].connection, &buf, 0) == UA_STATUSCODE_GOOD) {
|
if(socket_recv(layer->mappings[i].connection, &buf, 0) == UA_STATUSCODE_GOOD) {
|
||||||
items[j].type = UA_WORKITEMTYPE_BINARYNETWORKMESSAGE;
|
items[j].type = UA_WORKITEMTYPE_BINARYNETWORKMESSAGE;
|
||||||
items[j].work.binaryNetworkMessage.message = buf;
|
items[j].work.binaryNetworkMessage.message = buf;
|
||||||
@ -403,6 +407,7 @@ static UA_Int32 ServerNetworkLayerTCP_getWork(ServerNetworkLayerTCP *layer, UA_W
|
|||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* free the array if there is no work */
|
||||||
if(j == 0) {
|
if(j == 0) {
|
||||||
free(items);
|
free(items);
|
||||||
*workItems = NULL;
|
*workItems = NULL;
|
||||||
@ -423,7 +428,6 @@ static UA_Int32 ServerNetworkLayerTCP_stop(ServerNetworkLayerTCP *layer, UA_Work
|
|||||||
UA_WorkItem *items = malloc(sizeof(UA_WorkItem) * layer->mappingsSize);
|
UA_WorkItem *items = malloc(sizeof(UA_WorkItem) * layer->mappingsSize);
|
||||||
if(!items)
|
if(!items)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for(size_t i = 0; i < layer->mappingsSize; i++) {
|
for(size_t i = 0; i < layer->mappingsSize; i++) {
|
||||||
items[i].type = UA_WORKITEMTYPE_CLOSECONNECTION;
|
items[i].type = UA_WORKITEMTYPE_CLOSECONNECTION;
|
||||||
items[i].work.closeConnection = layer->mappings[i].connection;
|
items[i].work.closeConnection = layer->mappings[i].connection;
|
||||||
@ -445,7 +449,7 @@ static void ServerNetworkLayerTCP_delete(ServerNetworkLayerTCP *layer) {
|
|||||||
free(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
|
#ifdef _WIN32
|
||||||
WORD wVersionRequested;
|
WORD wVersionRequested;
|
||||||
WSADATA wsaData;
|
WSADATA wsaData;
|
||||||
@ -453,7 +457,6 @@ UA_ServerNetworkLayer ServerNetworkLayerTCP_new(UA_Server *server, UA_Connection
|
|||||||
WSAStartup(wVersionRequested, &wsaData);
|
WSAStartup(wVersionRequested, &wsaData);
|
||||||
#endif
|
#endif
|
||||||
ServerNetworkLayerTCP *layer = malloc(sizeof(ServerNetworkLayerTCP));
|
ServerNetworkLayerTCP *layer = malloc(sizeof(ServerNetworkLayerTCP));
|
||||||
layer->server = server;
|
|
||||||
layer->conf = conf;
|
layer->conf = conf;
|
||||||
layer->mappingsSize = 0;
|
layer->mappingsSize = 0;
|
||||||
layer->mappings = NULL;
|
layer->mappings = NULL;
|
||||||
@ -477,16 +480,20 @@ UA_ServerNetworkLayer ServerNetworkLayerTCP_new(UA_Server *server, UA_Connection
|
|||||||
/* Client NetworkLayer TCP */
|
/* 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);
|
size_t urlLength = strlen(endpointUrl);
|
||||||
if(urlLength < 11 || urlLength >= 512) {
|
if(urlLength < 11 || urlLength >= 512) {
|
||||||
printf("server url size invalid\n");
|
UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "Server url size invalid");
|
||||||
return UA_STATUSCODE_BADINTERNALERROR;
|
return connection;
|
||||||
}
|
}
|
||||||
if(strncmp(endpointUrl, "opc.tcp://", 10) != 0) {
|
if(strncmp(endpointUrl, "opc.tcp://", 10) != 0) {
|
||||||
printf("server url does not begin with opc.tcp://\n");
|
UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "Server url does not begin with opc.tcp://");
|
||||||
return UA_STATUSCODE_BADINTERNALERROR;
|
return connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
UA_UInt16 portpos = 9;
|
UA_UInt16 portpos = 9;
|
||||||
UA_UInt16 port = 0;
|
UA_UInt16 port = 0;
|
||||||
for(;portpos < urlLength-1; portpos++) {
|
for(;portpos < urlLength-1; portpos++) {
|
||||||
@ -496,8 +503,8 @@ UA_StatusCode ClientNetworkLayerTCP_connect(UA_Client *client, UA_Connection *co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(port == 0) {
|
if(port == 0) {
|
||||||
printf("port invalid");
|
UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "Port invalid");
|
||||||
return UA_STATUSCODE_BADINTERNALERROR;
|
return connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
char hostname[512];
|
char hostname[512];
|
||||||
@ -509,30 +516,33 @@ UA_StatusCode ClientNetworkLayerTCP_connect(UA_Client *client, UA_Connection *co
|
|||||||
WSADATA wsaData;
|
WSADATA wsaData;
|
||||||
wVersionRequested = MAKEWORD(2, 2);
|
wVersionRequested = MAKEWORD(2, 2);
|
||||||
WSAStartup(wVersionRequested, &wsaData);
|
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
|
#else
|
||||||
if((conn->sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
|
if((connection.sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
|
||||||
#endif
|
#endif
|
||||||
printf("Could not create socket\n");
|
UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "Could not create socket");
|
||||||
return UA_STATUSCODE_BADINTERNALERROR;
|
return connection;
|
||||||
}
|
}
|
||||||
struct hostent *server = gethostbyname(hostname);
|
struct hostent *server = gethostbyname(hostname);
|
||||||
if (server == NULL) {
|
if(server == NULL) {
|
||||||
printf("DNS lookup of %s failed\n", hostname);
|
UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "DNS lookup of %s failed", hostname);
|
||||||
return UA_STATUSCODE_BADINTERNALERROR;
|
return connection;
|
||||||
}
|
}
|
||||||
struct sockaddr_in server_addr;
|
struct sockaddr_in server_addr;
|
||||||
memset(&server_addr, 0, sizeof(server_addr));
|
memset(&server_addr, 0, sizeof(server_addr));
|
||||||
memcpy((char *)&server_addr.sin_addr.s_addr, (char *)server->h_addr_list[0], server->h_length);
|
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_family = AF_INET;
|
||||||
server_addr.sin_port = htons(port);
|
server_addr.sin_port = htons(port);
|
||||||
if(connect(conn->sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {
|
if(connect(connection.sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {
|
||||||
printf("Connect failed.\n");
|
UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "Connection failed");
|
||||||
return UA_STATUSCODE_BADINTERNALERROR;
|
return connection;
|
||||||
}
|
}
|
||||||
socket_set_nonblocking(conn->sockfd);
|
connection.state = UA_CONNECTION_OPENING;
|
||||||
conn->write = socket_write;
|
socket_set_nonblocking(connection.sockfd);
|
||||||
conn->recv = socket_recv;
|
connection.write = socket_write;
|
||||||
conn->close = socket_close;
|
connection.recv = socket_recv;
|
||||||
return UA_STATUSCODE_GOOD;
|
connection.close = socket_close;
|
||||||
|
connection.getBuffer = GetMallocedBuffer;
|
||||||
|
connection.releaseBuffer = ReleaseMallocedBuffer;
|
||||||
|
return connection;
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,8 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** @brief Create the TCP networklayer and listen to the specified port */
|
/** @brief Create the TCP networklayer and listen to the specified port */
|
||||||
UA_ServerNetworkLayer ServerNetworkLayerTCP_new(UA_Server *server, UA_ConnectionConfig conf, UA_UInt32 port);
|
UA_ServerNetworkLayer ServerNetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UInt32 port);
|
||||||
UA_StatusCode ClientNetworkLayerTCP_connect(UA_Client *client, UA_Connection *conn, char *endpointUrl);
|
UA_Connection ClientNetworkLayerTCP_connect(char *endpointUrl, UA_Logger *logger);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
@ -16,15 +16,6 @@
|
|||||||
/* with a space so amalgamation does not remove the includes */
|
/* with a space so amalgamation does not remove the includes */
|
||||||
# include <errno.h> // errno, EINTR
|
# include <errno.h> // errno, EINTR
|
||||||
# include <fcntl.h> // fcntl
|
# include <fcntl.h> // fcntl
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
# include <malloc.h>
|
|
||||||
# include <winsock2.h>
|
|
||||||
# include <sys/types.h>
|
|
||||||
# include <windows.h>
|
|
||||||
# include <ws2tcpip.h>
|
|
||||||
# define CLOSESOCKET(S) closesocket(S)
|
|
||||||
#else
|
|
||||||
# include <strings.h> //bzero
|
# include <strings.h> //bzero
|
||||||
# include <sys/select.h>
|
# include <sys/select.h>
|
||||||
# include <netinet/in.h>
|
# include <netinet/in.h>
|
||||||
@ -34,11 +25,30 @@
|
|||||||
# include <unistd.h> // read, write, close
|
# include <unistd.h> // read, write, close
|
||||||
# include <arpa/inet.h>
|
# include <arpa/inet.h>
|
||||||
# define CLOSESOCKET(S) close(S)
|
# define CLOSESOCKET(S) close(S)
|
||||||
#endif
|
|
||||||
|
|
||||||
#define MAXBACKLOG 100
|
#define MAXBACKLOG 100
|
||||||
|
|
||||||
struct ServerNetworklayerUDP;
|
#ifdef _WIN32
|
||||||
|
# error fixme: udp not yet implemented for windows
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*****************************/
|
||||||
|
/* Generic Buffer Management */
|
||||||
|
/*****************************/
|
||||||
|
|
||||||
|
static UA_StatusCode GetMallocedBuffer(UA_Connection *connection, UA_ByteString *buf, size_t minSize) {
|
||||||
|
if(minSize > connection->remoteConf.recvBufferSize)
|
||||||
|
return UA_STATUSCODE_BADINTERNALERROR;
|
||||||
|
return UA_ByteString_newMembers(buf, minSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ReleaseMallocedBuffer(UA_Connection *connection, UA_ByteString *buf) {
|
||||||
|
UA_ByteString_deleteMembers(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************/
|
||||||
|
/* UDP Network Layer */
|
||||||
|
/*********************/
|
||||||
|
|
||||||
/* Forwarded to the server as a (UA_Connection) and used for callbacks back into
|
/* Forwarded to the server as a (UA_Connection) and used for callbacks back into
|
||||||
the networklayer */
|
the networklayer */
|
||||||
@ -46,84 +56,28 @@ typedef struct {
|
|||||||
UA_Connection connection;
|
UA_Connection connection;
|
||||||
struct sockaddr from;
|
struct sockaddr from;
|
||||||
socklen_t fromlen;
|
socklen_t fromlen;
|
||||||
struct ServerNetworkLayerUDP *layer;
|
|
||||||
} UDPConnection;
|
} UDPConnection;
|
||||||
|
|
||||||
typedef struct ServerNetworkLayerUDP {
|
typedef struct {
|
||||||
|
UA_Server *server;
|
||||||
UA_ConnectionConfig conf;
|
UA_ConnectionConfig conf;
|
||||||
fd_set fdset;
|
fd_set fdset;
|
||||||
#ifdef _WIN32
|
|
||||||
UA_UInt32 serversockfd;
|
|
||||||
#else
|
|
||||||
UA_Int32 serversockfd;
|
UA_Int32 serversockfd;
|
||||||
#endif
|
|
||||||
UA_UInt32 port;
|
UA_UInt32 port;
|
||||||
|
UA_Logger *logger;
|
||||||
} ServerNetworkLayerUDP;
|
} ServerNetworkLayerUDP;
|
||||||
|
|
||||||
static UA_StatusCode setNonBlocking(int sockid) {
|
|
||||||
#ifdef _WIN32
|
|
||||||
u_long iMode = 1;
|
|
||||||
if(ioctlsocket(sockid, FIONBIO, &iMode) != NO_ERROR)
|
|
||||||
return UA_STATUSCODE_BADINTERNALERROR;
|
|
||||||
#else
|
|
||||||
int opts = fcntl(sockid,F_GETFL);
|
|
||||||
if(opts < 0 || fcntl(sockid,F_SETFL,opts|O_NONBLOCK) < 0)
|
|
||||||
return UA_STATUSCODE_BADINTERNALERROR;
|
|
||||||
#endif
|
|
||||||
return UA_STATUSCODE_GOOD;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setFDSet(ServerNetworkLayerUDP *layer) {
|
|
||||||
FD_ZERO(&layer->fdset);
|
|
||||||
FD_SET(layer->serversockfd, &layer->fdset);
|
|
||||||
}
|
|
||||||
|
|
||||||
// the callbacks are thread-safe if UA_MULTITHREADING is defined
|
|
||||||
static void closeConnectionUDP(UDPConnection *handle) {
|
|
||||||
free(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeCallbackUDP(UDPConnection *handle, UA_ByteStringArray gather_buf);
|
|
||||||
|
|
||||||
/** Accesses only the sockfd in the handle. Can be run from parallel threads. */
|
/** Accesses only the sockfd in the handle. Can be run from parallel threads. */
|
||||||
void writeCallbackUDP(UDPConnection *handle, UA_ByteStringArray gather_buf) {
|
static void writeCallbackUDP(UDPConnection *handle, UA_ByteStringArray gather_buf) {
|
||||||
UA_UInt32 total_len = 0, nWritten = 0;
|
UA_UInt32 total_len = 0, nWritten = 0;
|
||||||
#ifdef _WIN32
|
|
||||||
/*
|
|
||||||
LPWSABUF buf = _alloca(gather_buf.stringsSize * sizeof(WSABUF));
|
|
||||||
int result = 0;
|
|
||||||
for(UA_UInt32 i = 0; i<gather_buf.stringsSize; i++) {
|
|
||||||
buf[i].buf = (char*)gather_buf.strings[i].data;
|
|
||||||
buf[i].len = gather_buf.strings[i].length;
|
|
||||||
total_len += gather_buf.strings[i].length;
|
|
||||||
}
|
|
||||||
while(nWritten < total_len) {
|
|
||||||
UA_UInt32 n = 0;
|
|
||||||
do {
|
|
||||||
result = WSASendto(handle->layer->serversockfd, buf, gather_buf.stringsSize ,
|
|
||||||
(LPDWORD)&n, 0,
|
|
||||||
handle->from, handle->fromlen,
|
|
||||||
NULL, NULL);
|
|
||||||
//FIXME:
|
|
||||||
if(result != 0)
|
|
||||||
printf("Error WSASend, code: %d \n", WSAGetLastError());
|
|
||||||
} while(errno == EINTR);
|
|
||||||
nWritten += n;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
#error fixme: udp not yet implemented for windows
|
|
||||||
#else
|
|
||||||
struct iovec iov[gather_buf.stringsSize];
|
struct iovec iov[gather_buf.stringsSize];
|
||||||
for(UA_UInt32 i=0;i<gather_buf.stringsSize;i++) {
|
for(UA_UInt32 i=0;i<gather_buf.stringsSize;i++) {
|
||||||
iov[i] = (struct iovec) {.iov_base = gather_buf.strings[i].data,
|
iov[i] = (struct iovec) {.iov_base = gather_buf.strings[i].data,
|
||||||
.iov_len = gather_buf.strings[i].length};
|
.iov_len = gather_buf.strings[i].length};
|
||||||
total_len += gather_buf.strings[i].length;
|
total_len += gather_buf.strings[i].length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct sockaddr_in *sin = NULL;
|
struct sockaddr_in *sin = NULL;
|
||||||
if (handle->from.sa_family == AF_INET) {
|
if (handle->from.sa_family == AF_INET) {
|
||||||
|
|
||||||
#if defined(__GNUC__) || defined(__clang__)
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wcast-align"
|
#pragma GCC diagnostic ignored "-Wcast-align"
|
||||||
@ -132,49 +86,50 @@ void writeCallbackUDP(UDPConnection *handle, UA_ByteStringArray gather_buf) {
|
|||||||
#if defined(__GNUC__) || defined(__clang__)
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
//FIXME:
|
//FIXME:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct msghdr message = {.msg_name = sin, .msg_namelen = handle->fromlen, .msg_iov = iov,
|
struct msghdr message = {.msg_name = sin, .msg_namelen = handle->fromlen, .msg_iov = iov,
|
||||||
.msg_iovlen = gather_buf.stringsSize, .msg_control = NULL,
|
.msg_iovlen = gather_buf.stringsSize, .msg_control = NULL,
|
||||||
.msg_controllen = 0, .msg_flags = 0};
|
.msg_controllen = 0, .msg_flags = 0};
|
||||||
while (nWritten < total_len) {
|
while (nWritten < total_len) {
|
||||||
UA_Int32 n = 0;
|
UA_Int32 n = 0;
|
||||||
do {
|
do {
|
||||||
n = sendmsg(handle->layer->serversockfd, &message, 0);
|
n = sendmsg(((ServerNetworkLayerUDP*)handle->connection.handle)->serversockfd, &message, 0);
|
||||||
if(n==-1L){
|
if(n == -1L) {
|
||||||
printf("ERROR:%i\n", errno);
|
printf("ERROR:%i\n", errno);
|
||||||
}
|
}
|
||||||
} while (n == -1L && errno == EINTR);
|
} while (n == -1L && errno == EINTR);
|
||||||
nWritten += n;
|
nWritten += n;
|
||||||
}
|
}
|
||||||
#endif
|
}
|
||||||
|
|
||||||
|
static UA_StatusCode socket_set_nonblocking(UA_Int32 sockfd) {
|
||||||
|
int opts = fcntl(sockfd, F_GETFL);
|
||||||
|
if(opts < 0 || fcntl(sockfd, F_SETFL, opts|O_NONBLOCK) < 0)
|
||||||
|
return UA_STATUSCODE_BADINTERNALERROR;
|
||||||
|
return UA_STATUSCODE_GOOD;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setFDSet(ServerNetworkLayerUDP *layer) {
|
||||||
|
FD_ZERO(&layer->fdset);
|
||||||
|
FD_SET(layer->serversockfd, &layer->fdset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void closeConnectionUDP(UDPConnection *handle) {
|
||||||
|
free(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
static UA_StatusCode ServerNetworkLayerUDP_start(ServerNetworkLayerUDP *layer, UA_Logger *logger) {
|
static UA_StatusCode ServerNetworkLayerUDP_start(ServerNetworkLayerUDP *layer, UA_Logger *logger) {
|
||||||
#ifdef _WIN32
|
layer->logger = logger;
|
||||||
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
|
|
||||||
if((layer->serversockfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
|
if((layer->serversockfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||||
perror("ERROR opening socket");
|
perror("ERROR opening socket");
|
||||||
return UA_STATUSCODE_BADINTERNALERROR;
|
return UA_STATUSCODE_BADINTERNALERROR;
|
||||||
}
|
}
|
||||||
#endif
|
const struct sockaddr_in serv_addr =
|
||||||
|
{.sin_family = AF_INET, .sin_addr.s_addr = INADDR_ANY,
|
||||||
const struct sockaddr_in serv_addr = {
|
.sin_port = htons(layer->port), .sin_zero = {0}};
|
||||||
.sin_family = AF_INET, .sin_addr.s_addr = INADDR_ANY,
|
|
||||||
.sin_port = htons(layer->port), .sin_zero = {0}};
|
|
||||||
|
|
||||||
int optval = 1;
|
int optval = 1;
|
||||||
if(setsockopt(layer->serversockfd, SOL_SOCKET,
|
if(setsockopt(layer->serversockfd, SOL_SOCKET,
|
||||||
SO_REUSEADDR, (const char *)&optval,
|
SO_REUSEADDR, (const char *)&optval,
|
||||||
@ -183,84 +138,64 @@ static UA_StatusCode ServerNetworkLayerUDP_start(ServerNetworkLayerUDP *layer, U
|
|||||||
CLOSESOCKET(layer->serversockfd);
|
CLOSESOCKET(layer->serversockfd);
|
||||||
return UA_STATUSCODE_BADINTERNALERROR;
|
return UA_STATUSCODE_BADINTERNALERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(bind(layer->serversockfd, (const struct sockaddr *)&serv_addr,
|
if(bind(layer->serversockfd, (const struct sockaddr *)&serv_addr,
|
||||||
sizeof(serv_addr)) < 0) {
|
sizeof(serv_addr)) < 0) {
|
||||||
perror("binding");
|
perror("binding");
|
||||||
CLOSESOCKET(layer->serversockfd);
|
CLOSESOCKET(layer->serversockfd);
|
||||||
return UA_STATUSCODE_BADINTERNALERROR;
|
return UA_STATUSCODE_BADINTERNALERROR;
|
||||||
}
|
}
|
||||||
|
socket_set_nonblocking(layer->serversockfd);
|
||||||
setNonBlocking(layer->serversockfd);
|
printf("Listening for UDP connections on %s:%d", inet_ntoa(serv_addr.sin_addr),
|
||||||
UA_LOG_INFO((*logger), UA_LOGGERCATEGORY_SERVER, "Listening for UDP connections on %s:%d",
|
ntohs(serv_addr.sin_port));
|
||||||
inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port));
|
|
||||||
return UA_STATUSCODE_GOOD;
|
return UA_STATUSCODE_GOOD;
|
||||||
}
|
}
|
||||||
|
|
||||||
static UA_Int32 ServerNetworkLayerUDP_getWork(ServerNetworkLayerUDP *layer, UA_WorkItem **workItems,
|
static UA_Int32 ServerNetworkLayerUDP_getWork(ServerNetworkLayerUDP *layer, UA_WorkItem **workItems,
|
||||||
UA_UInt16 timeout) {
|
UA_UInt16 timeout) {
|
||||||
UA_WorkItem *items = NULL;
|
UA_WorkItem *items = NULL;
|
||||||
setFDSet(layer);
|
setFDSet(layer);
|
||||||
struct timeval tmptv = {0, timeout};
|
struct timeval tmptv = {0, timeout};
|
||||||
UA_Int32 resultsize = select(layer->serversockfd+1, &layer->fdset, NULL, NULL, &tmptv);
|
UA_Int32 resultsize = select(layer->serversockfd+1, &layer->fdset, NULL, NULL, &tmptv);
|
||||||
|
|
||||||
if(resultsize <= 0 || !FD_ISSET(layer->serversockfd, &layer->fdset)) {
|
if(resultsize <= 0 || !FD_ISSET(layer->serversockfd, &layer->fdset)) {
|
||||||
*workItems = items;
|
*workItems = items;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
items = malloc(sizeof(UA_WorkItem)*(resultsize));
|
items = malloc(sizeof(UA_WorkItem)*(resultsize));
|
||||||
|
|
||||||
// read from established sockets
|
// read from established sockets
|
||||||
UA_Int32 j = 0;
|
UA_Int32 j = 0;
|
||||||
UA_ByteString buf = { -1, NULL};
|
UA_ByteString buf = {-1, NULL};
|
||||||
if(!buf.data) {
|
if(!buf.data) {
|
||||||
buf.data = malloc(sizeof(UA_Byte) * layer->conf.recvBufferSize);
|
buf.data = malloc(sizeof(UA_Byte) * layer->conf.recvBufferSize);
|
||||||
if(!buf.data){
|
if(!buf.data)
|
||||||
//TODO:
|
|
||||||
printf("malloc failed");
|
printf("malloc failed");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sockaddr sender;
|
struct sockaddr sender;
|
||||||
socklen_t sendsize = sizeof(sender);
|
socklen_t sendsize = sizeof(sender);
|
||||||
bzero(&sender, sizeof(sender));
|
bzero(&sender, sizeof(sender));
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
buf.length = recvfrom(layer->conLinks[i].sockfd, (char *)buf.data,
|
|
||||||
layer->conf.recvBufferSize, 0);
|
|
||||||
//todo: fixme
|
|
||||||
#else
|
|
||||||
buf.length = recvfrom(layer->serversockfd, buf.data, layer->conf.recvBufferSize, 0, &sender, &sendsize);
|
buf.length = recvfrom(layer->serversockfd, buf.data, layer->conf.recvBufferSize, 0, &sender, &sendsize);
|
||||||
#endif
|
|
||||||
|
|
||||||
if (buf.length <= 0) {
|
if (buf.length <= 0) {
|
||||||
} else {
|
} else {
|
||||||
UDPConnection *c = malloc(sizeof(UDPConnection));
|
UDPConnection *c = malloc(sizeof(UDPConnection));
|
||||||
|
|
||||||
if(!c)
|
if(!c)
|
||||||
return UA_STATUSCODE_BADINTERNALERROR;
|
return UA_STATUSCODE_BADINTERNALERROR;
|
||||||
c->layer = layer;
|
|
||||||
c->from = sender;
|
c->from = sender;
|
||||||
c->fromlen = sendsize;
|
c->fromlen = sendsize;
|
||||||
c->connection.state = UA_CONNECTION_OPENING;
|
c->connection.state = UA_CONNECTION_OPENING;
|
||||||
c->connection.localConf = layer->conf;
|
c->connection.localConf = layer->conf;
|
||||||
c->connection.channel = NULL;
|
c->connection.channel = NULL;
|
||||||
c->connection.close = (void (*)(void*))closeConnectionUDP;
|
c->connection.close = (void (*)(UA_Connection*))closeConnectionUDP;
|
||||||
c->connection.write = (void (*)(void*, UA_ByteStringArray))writeCallbackUDP;
|
c->connection.write = (UA_StatusCode (*)(UA_Connection*, UA_ByteStringArray))writeCallbackUDP;
|
||||||
|
c->connection.getBuffer = GetMallocedBuffer;
|
||||||
|
c->connection.releaseBuffer = ReleaseMallocedBuffer;
|
||||||
|
c->connection.handle = layer;
|
||||||
items[j].type = UA_WORKITEMTYPE_BINARYNETWORKMESSAGE;
|
items[j].type = UA_WORKITEMTYPE_BINARYNETWORKMESSAGE;
|
||||||
items[j].work.binaryNetworkMessage.message = buf;
|
items[j].work.binaryNetworkMessage.message = buf;
|
||||||
items[j].work.binaryNetworkMessage.connection = (UA_Connection*)c;
|
items[j].work.binaryNetworkMessage.connection = (UA_Connection*)c;
|
||||||
buf.data = NULL;
|
buf.data = NULL;
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(buf.data)
|
if(buf.data)
|
||||||
free(buf.data);
|
free(buf.data);
|
||||||
|
|
||||||
if(j == 0) {
|
if(j == 0) {
|
||||||
free(items);
|
free(items);
|
||||||
*workItems = NULL;
|
*workItems = NULL;
|
||||||
@ -278,14 +213,14 @@ static void ServerNetworkLayerUDP_delete(ServerNetworkLayerUDP *layer) {
|
|||||||
free(layer);
|
free(layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
UA_ServerNetworkLayer ServerNetworkLayerUDP_new(UA_ConnectionConfig conf, UA_UInt32 port){
|
UA_ServerNetworkLayer ServerNetworkLayerUDP_new(UA_ConnectionConfig conf, UA_UInt32 port) {
|
||||||
ServerNetworkLayerUDP *udplayer = malloc(sizeof(ServerNetworkLayerUDP));
|
ServerNetworkLayerUDP *udplayer = malloc(sizeof(ServerNetworkLayerUDP));
|
||||||
udplayer->conf = conf;
|
udplayer->conf = conf;
|
||||||
udplayer->port = port;
|
udplayer->port = port;
|
||||||
|
|
||||||
UA_ServerNetworkLayer nl;
|
UA_ServerNetworkLayer nl;
|
||||||
nl.nlHandle = udplayer;
|
nl.nlHandle = udplayer;
|
||||||
nl.start = (UA_StatusCode (*)(void*))ServerNetworkLayerUDP_start;
|
nl.start = (UA_StatusCode (*)(void*, UA_Logger *logger))ServerNetworkLayerUDP_start;
|
||||||
nl.getWork = (UA_Int32 (*)(void*, UA_WorkItem**, UA_UInt16)) ServerNetworkLayerUDP_getWork;
|
nl.getWork = (UA_Int32 (*)(void*, UA_WorkItem**, UA_UInt16)) ServerNetworkLayerUDP_getWork;
|
||||||
nl.stop = (UA_Int32 (*)(void*, UA_WorkItem**)) ServerNetworkLayerUDP_stop;
|
nl.stop = (UA_Int32 (*)(void*, UA_WorkItem**)) ServerNetworkLayerUDP_stop;
|
||||||
nl.free = (void (*)(void*))ServerNetworkLayerUDP_delete;
|
nl.free = (void (*)(void*))ServerNetworkLayerUDP_delete;
|
||||||
|
@ -196,7 +196,7 @@ int main(int argc, char** argv) {
|
|||||||
UA_ByteString certificate = loadCertificate();
|
UA_ByteString certificate = loadCertificate();
|
||||||
UA_Server_setServerCertificate(server, certificate);
|
UA_Server_setServerCertificate(server, certificate);
|
||||||
UA_ByteString_deleteMembers(&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");
|
UA_UInt16 nsIndex = UA_Server_addNamespace(server, "myApplicationNamespace");
|
||||||
|
|
||||||
// print the status every 2 sec
|
// print the status every 2 sec
|
||||||
|
@ -65,7 +65,7 @@ int main(int argc, char** argv) {
|
|||||||
UA_ByteString certificate = loadCertificate();
|
UA_ByteString certificate = loadCertificate();
|
||||||
UA_Server_setServerCertificate(server, certificate);
|
UA_Server_setServerCertificate(server, certificate);
|
||||||
UA_ByteString_deleteMembers(&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_Server_addNamespace(server, "myApplicationNamespace");
|
||||||
|
|
||||||
UA_WorkItem work = {.type = UA_WORKITEMTYPE_METHODCALL,
|
UA_WorkItem work = {.type = UA_WORKITEMTYPE_METHODCALL,
|
||||||
|
@ -34,13 +34,14 @@ int main(int argc, char** argv) {
|
|||||||
UA_Variant *myIntegerVariant = UA_Variant_new();
|
UA_Variant *myIntegerVariant = UA_Variant_new();
|
||||||
UA_Int32 myInteger = 42;
|
UA_Int32 myInteger = 42;
|
||||||
UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
|
UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
|
||||||
UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
|
const UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
|
||||||
UA_NodeId myIntegerNodeId = UA_NODEID_NULL; /* assign a random free nodeid */
|
const UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
|
||||||
UA_NodeId parentNodeId = UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER);
|
UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
|
||||||
UA_NodeId parentReferenceNodeId = UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES);
|
UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
|
||||||
UA_Server_addVariableNode(server, myIntegerVariant, myIntegerName,
|
UA_Server_addVariableNode(server, myIntegerVariant, myIntegerName,
|
||||||
myIntegerNodeId, parentNodeId, parentReferenceNodeId);
|
myIntegerNodeId, parentNodeId, parentReferenceNodeId);
|
||||||
|
|
||||||
|
|
||||||
UA_StatusCode retval = UA_Server_run(server, 1, &running);
|
UA_StatusCode retval = UA_Server_run(server, 1, &running);
|
||||||
UA_Server_delete(server);
|
UA_Server_delete(server);
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ extern "C" {
|
|||||||
#include "ua_util.h"
|
#include "ua_util.h"
|
||||||
#include "ua_types.h"
|
#include "ua_types.h"
|
||||||
#include "ua_connection.h"
|
#include "ua_connection.h"
|
||||||
|
#include "ua_log.h"
|
||||||
#include "ua_types_generated.h"
|
#include "ua_types_generated.h"
|
||||||
|
|
||||||
struct UA_Client;
|
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
|
* The client networklayer is defined by a single function that fills a UA_Connection struct after
|
||||||
* successfully connecting.
|
* 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 {
|
typedef struct UA_ClientConfig {
|
||||||
UA_Int32 timeout; //sync response timeout
|
UA_Int32 timeout; //sync response timeout
|
||||||
@ -25,7 +26,7 @@ typedef struct UA_ClientConfig {
|
|||||||
} UA_ClientConfig;
|
} UA_ClientConfig;
|
||||||
|
|
||||||
extern const UA_ClientConfig UA_ClientConfig_standard;
|
extern const UA_ClientConfig UA_ClientConfig_standard;
|
||||||
UA_Client UA_EXPORT * UA_Client_new(UA_ClientConfig config);
|
UA_Client UA_EXPORT * UA_Client_new(UA_ClientConfig config, UA_Logger logger);
|
||||||
|
|
||||||
void UA_Client_delete(UA_Client* client);
|
void UA_Client_delete(UA_Client* client);
|
||||||
|
|
||||||
@ -38,6 +39,7 @@ UA_WriteResponse UA_EXPORT UA_Client_write(UA_Client *client, UA_WriteRequest *r
|
|||||||
|
|
||||||
/* View Service Set */
|
/* View Service Set */
|
||||||
UA_BrowseResponse UA_EXPORT UA_Client_browse(UA_Client *client, UA_BrowseRequest *request);
|
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_TranslateBrowsePathsToNodeIdsResponse UA_EXPORT
|
||||||
UA_Client_translateTranslateBrowsePathsToNodeIds(UA_Client *client,
|
UA_Client_translateTranslateBrowsePathsToNodeIds(UA_Client *client,
|
||||||
UA_TranslateBrowsePathsToNodeIdsRequest *request);
|
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.
|
UA_Int32 sockfd; ///> Most connectivity solutions run on sockets. Having the socket id here simplifies the design.
|
||||||
void *handle; ///> A pointer to the networklayer
|
void *handle; ///> A pointer to the networklayer
|
||||||
UA_ByteString incompleteMessage; ///> Half-received messages (tcp is a streaming protocol) get stored here
|
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
|
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 (*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
|
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 {
|
typedef enum UA_LoggerCategory {
|
||||||
UA_LOGGERCATEGORY_COMMUNICATION,
|
UA_LOGGERCATEGORY_COMMUNICATION,
|
||||||
UA_LOGGERCATEGORY_SERVER,
|
UA_LOGGERCATEGORY_SERVER,
|
||||||
|
UA_LOGGERCATEGORY_CLIENT,
|
||||||
UA_LOGGERCATEGORY_USERLAND
|
UA_LOGGERCATEGORY_USERLAND
|
||||||
} UA_LoggerCategory;
|
} UA_LoggerCategory;
|
||||||
|
|
||||||
extern UA_EXPORT const char *UA_LoggerCategoryNames[3];
|
extern UA_EXPORT const char *UA_LoggerCategoryNames[4];
|
||||||
|
|
||||||
typedef struct UA_Logger {
|
typedef struct UA_Logger {
|
||||||
void (*log_trace)(UA_LoggerCategory category, const char *msg, ...);
|
void (*log_trace)(UA_LoggerCategory category, const char *msg, ...);
|
||||||
@ -50,45 +51,45 @@ typedef struct UA_Logger {
|
|||||||
} UA_Logger;
|
} UA_Logger;
|
||||||
|
|
||||||
#if UA_LOGLEVEL <= 100
|
#if UA_LOGLEVEL <= 100
|
||||||
#define UA_LOG_TRACE(LOGGER, CATEGORY, MSG...) do { \
|
#define UA_LOG_TRACE(LOGGER, CATEGORY, ...) do { \
|
||||||
if(LOGGER.log_trace) LOGGER.log_trace(CATEGORY, MSG); } while(0)
|
if(LOGGER.log_trace) LOGGER.log_trace(CATEGORY, __VA_ARGS__); } while(0)
|
||||||
#else
|
#else
|
||||||
#define UA_LOG_TRACE(LOGGER, CATEGORY, MSG...) do {} while(0)
|
#define UA_LOG_TRACE(LOGGER, CATEGORY, ...) do {} while(0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if UA_LOGLEVEL <= 200
|
#if UA_LOGLEVEL <= 200
|
||||||
#define UA_LOG_DEBUG(LOGGER, CATEGORY, MSG...) do { \
|
#define UA_LOG_DEBUG(LOGGER, CATEGORY, ...) do { \
|
||||||
if(LOGGER.log_debug) LOGGER.log_debug(CATEGORY, MSG); } while(0)
|
if(LOGGER.log_debug) LOGGER.log_debug(CATEGORY, __VA_ARGS__); } while(0)
|
||||||
#else
|
#else
|
||||||
#define UA_LOG_DEBUG(LOGGER, CATEGORY, MSG...) do {} while(0)
|
#define UA_LOG_DEBUG(LOGGER, CATEGORY, ...) do {} while(0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if UA_LOGLEVEL <= 300
|
#if UA_LOGLEVEL <= 300
|
||||||
#define UA_LOG_INFO(LOGGER, CATEGORY, MSG...) do { \
|
#define UA_LOG_INFO(LOGGER, CATEGORY, ...) do { \
|
||||||
if(LOGGER.log_info) LOGGER.log_info(CATEGORY, MSG); } while(0)
|
if(LOGGER.log_info) LOGGER.log_info(CATEGORY, __VA_ARGS__); } while(0)
|
||||||
#else
|
#else
|
||||||
#define UA_LOG_INFO(LOGGER, CATEGORY, MSG...) do {} while(0)
|
#define UA_LOG_INFO(LOGGER, CATEGORY, ...) do {} while(0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if UA_LOGLEVEL <= 400
|
#if UA_LOGLEVEL <= 400
|
||||||
#define UA_LOG_WARNING(LOGGER, CATEGORY, MSG...) do { \
|
#define UA_LOG_WARNING(LOGGER, CATEGORY, ...) do { \
|
||||||
if(LOGGER.log_warning) LOGGER.log_warning(CATEGORY, MSG); } while(0)
|
if(LOGGER.log_warning) LOGGER.log_warning(CATEGORY, __VA_ARGS__); } while(0)
|
||||||
#else
|
#else
|
||||||
#define UA_LOG_WARNING(LOGGER, CATEGORY, MSG...) do {} while(0)
|
#define UA_LOG_WARNING(LOGGER, CATEGORY, ...) do {} while(0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if UA_LOGLEVEL <= 500
|
#if UA_LOGLEVEL <= 500
|
||||||
#define UA_LOG_ERROR(LOGGER, CATEGORY, MSG...) do { \
|
#define UA_LOG_ERROR(LOGGER, CATEGORY, ...) do { \
|
||||||
if(LOGGER.log_error) LOGGER.log_error(CATEGORY, MSG); } while(0)
|
if(LOGGER.log_error) LOGGER.log_error(CATEGORY, __VA_ARGS__); } while(0)
|
||||||
#else
|
#else
|
||||||
#define UA_LOG_ERROR(LOGGER, CATEGORY, MSG...) do {} while(0)
|
#define UA_LOG_ERROR(LOGGER, CATEGORY, ...) do {} while(0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if UA_LOGLEVEL <= 600
|
#if UA_LOGLEVEL <= 600
|
||||||
#define UA_LOG_FATAL(LOGGER, CATEGORY, MSG...) do { \
|
#define UA_LOG_FATAL(LOGGER, CATEGORY, ...) do { \
|
||||||
if(LOGGER.log_fatal) LOGGER.log_fatal(CATEGORY, MSG); } while(0)
|
if(LOGGER.log_fatal) LOGGER.log_fatal(CATEGORY, __VA_ARGS__); } while(0)
|
||||||
#else
|
#else
|
||||||
#define UA_LOG_FATAL(LOGGER, CATEGORY, MSG...) do {} while(0)
|
#define UA_LOG_FATAL(LOGGER, CATEGORY, ...) do {} while(0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
@ -272,6 +272,10 @@ typedef UA_Int32 (*UA_ExternalNodeStore_browseNodes)
|
|||||||
UA_UInt32 *indices, UA_UInt32 indicesSize, UA_UInt32 requestedMaxReferencesPerNode,
|
UA_UInt32 *indices, UA_UInt32 indicesSize, UA_UInt32 requestedMaxReferencesPerNode,
|
||||||
UA_BrowseResult *browseResults, UA_DiagnosticInfo *diagnosticInfos);
|
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 UA_Int32 (*UA_ExternalNodeStore_delete)(void *ensHandle);
|
||||||
|
|
||||||
typedef struct UA_ExternalNodeStore {
|
typedef struct UA_ExternalNodeStore {
|
||||||
@ -281,6 +285,7 @@ typedef struct UA_ExternalNodeStore {
|
|||||||
UA_ExternalNodeStore_writeNodes writeNodes;
|
UA_ExternalNodeStore_writeNodes writeNodes;
|
||||||
UA_ExternalNodeStore_readNodes readNodes;
|
UA_ExternalNodeStore_readNodes readNodes;
|
||||||
UA_ExternalNodeStore_browseNodes browseNodes;
|
UA_ExternalNodeStore_browseNodes browseNodes;
|
||||||
|
UA_ExternalNodeStore_translateBrowsePathsToNodeIds translateBrowsePathsToNodeIds;
|
||||||
UA_ExternalNodeStore_addReferences addReferences;
|
UA_ExternalNodeStore_addReferences addReferences;
|
||||||
UA_ExternalNodeStore_deleteReferences deleteReferences;
|
UA_ExternalNodeStore_deleteReferences deleteReferences;
|
||||||
UA_ExternalNodeStore_delete destroy;
|
UA_ExternalNodeStore_delete destroy;
|
||||||
|
@ -24,6 +24,7 @@ struct UA_Client {
|
|||||||
UA_NodeId authenticationToken;
|
UA_NodeId authenticationToken;
|
||||||
|
|
||||||
/* Config */
|
/* Config */
|
||||||
|
UA_Logger logger;
|
||||||
UA_ClientConfig config;
|
UA_ClientConfig config;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -31,13 +32,13 @@ const UA_ClientConfig UA_ClientConfig_standard =
|
|||||||
{ 5 /* ms receive timout */, {.protocolVersion = 0, .sendBufferSize = 65536, .recvBufferSize = 65536,
|
{ 5 /* ms receive timout */, {.protocolVersion = 0, .sendBufferSize = 65536, .recvBufferSize = 65536,
|
||||||
.maxMessageSize = 65536, .maxChunkCount = 1}};
|
.maxMessageSize = 65536, .maxChunkCount = 1}};
|
||||||
|
|
||||||
UA_Client * UA_Client_new(UA_ClientConfig config) {
|
UA_Client * UA_Client_new(UA_ClientConfig config, UA_Logger logger) {
|
||||||
UA_Client *client = UA_malloc(sizeof(UA_Client));
|
UA_Client *client = UA_malloc(sizeof(UA_Client));
|
||||||
if(!client)
|
if(!client)
|
||||||
return UA_NULL;
|
return UA_NULL;
|
||||||
client->config = config;
|
client->config = config;
|
||||||
|
client->logger = logger;
|
||||||
UA_String_init(&client->endpointUrl);
|
UA_String_init(&client->endpointUrl);
|
||||||
client->connection.state = UA_CONNECTION_OPENING;
|
|
||||||
UA_Connection_init(&client->connection);
|
UA_Connection_init(&client->connection);
|
||||||
|
|
||||||
client->sequenceNumber = 0;
|
client->sequenceNumber = 0;
|
||||||
@ -411,19 +412,17 @@ static UA_StatusCode CloseSecureChannel(UA_Client *client) {
|
|||||||
/* User-Facing Functions */
|
/* User-Facing Functions */
|
||||||
/*************************/
|
/*************************/
|
||||||
|
|
||||||
UA_StatusCode UA_Client_connect(UA_Client *client, UA_ConnectClientConnection connectFunc, char *endpointUrl)
|
UA_StatusCode UA_Client_connect(UA_Client *client, UA_ConnectClientConnection connectFunc, char *endpointUrl) {
|
||||||
{
|
client->connection = connectFunc(endpointUrl, &client->logger);
|
||||||
UA_StatusCode retval = connectFunc(client, &client->connection, endpointUrl);
|
if(client->connection.state != UA_CONNECTION_OPENING)
|
||||||
if(retval != UA_STATUSCODE_GOOD) {
|
return UA_STATUSCODE_BADCONNECTIONCLOSED;
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
client->endpointUrl = UA_STRING_ALLOC(endpointUrl);
|
client->endpointUrl = UA_STRING_ALLOC(endpointUrl);
|
||||||
if(client->endpointUrl.length < 0)
|
if(client->endpointUrl.length < 0)
|
||||||
return UA_STATUSCODE_BADOUTOFMEMORY;
|
return UA_STATUSCODE_BADOUTOFMEMORY;
|
||||||
|
|
||||||
client->connection.localConf = client->config.localConnectionConfig;
|
client->connection.localConf = client->config.localConnectionConfig;
|
||||||
retval = HelAckHandshake(client);
|
UA_StatusCode retval = HelAckHandshake(client);
|
||||||
if(retval == UA_STATUSCODE_GOOD)
|
if(retval == UA_STATUSCODE_GOOD)
|
||||||
retval = SecureChannelHandshake(client);
|
retval = SecureChannelHandshake(client);
|
||||||
if(retval == UA_STATUSCODE_GOOD)
|
if(retval == UA_STATUSCODE_GOOD)
|
||||||
@ -433,7 +432,7 @@ UA_StatusCode UA_Client_connect(UA_Client *client, UA_ConnectClientConnection co
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
UA_StatusCode UA_EXPORT UA_Client_disconnect(UA_Client *client) {
|
UA_StatusCode UA_Client_disconnect(UA_Client *client) {
|
||||||
UA_StatusCode retval;
|
UA_StatusCode retval;
|
||||||
retval = CloseSession(client);
|
retval = CloseSession(client);
|
||||||
if(retval == UA_STATUSCODE_GOOD)
|
if(retval == UA_STATUSCODE_GOOD)
|
||||||
@ -462,6 +461,13 @@ UA_BrowseResponse UA_Client_browse(UA_Client *client, UA_BrowseRequest *request)
|
|||||||
return response;
|
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_TranslateBrowsePathsToNodeIdsResponse
|
||||||
UA_Client_translateTranslateBrowsePathsToNodeIds(UA_Client *client,
|
UA_Client_translateTranslateBrowsePathsToNodeIds(UA_Client *client,
|
||||||
UA_TranslateBrowsePathsToNodeIdsRequest *request) {
|
UA_TranslateBrowsePathsToNodeIdsRequest *request) {
|
||||||
@ -492,8 +498,7 @@ UA_DeleteNodesResponse UA_Client_deleteNodes(UA_Client *client, UA_DeleteNodesRe
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
UA_DeleteReferencesResponse UA_EXPORT
|
UA_DeleteReferencesResponse UA_Client_deleteReferences(UA_Client *client, UA_DeleteReferencesRequest *request) {
|
||||||
UA_Client_deleteReferences(UA_Client *client, UA_DeleteReferencesRequest *request) {
|
|
||||||
UA_DeleteReferencesResponse response;
|
UA_DeleteReferencesResponse response;
|
||||||
synchronousRequest(request, &UA_TYPES[UA_TYPES_BROWSEREQUEST], &response,
|
synchronousRequest(request, &UA_TYPES[UA_TYPES_BROWSEREQUEST], &response,
|
||||||
&UA_TYPES[UA_TYPES_BROWSERESPONSE], client);
|
&UA_TYPES[UA_TYPES_BROWSERESPONSE], client);
|
||||||
|
@ -6,8 +6,6 @@
|
|||||||
#include "ua_services.h"
|
#include "ua_services.h"
|
||||||
#include "ua_nodeids.h"
|
#include "ua_nodeids.h"
|
||||||
|
|
||||||
const char *UA_LoggerCategoryNames[3] = {"communication", "server", "userland"};
|
|
||||||
|
|
||||||
/**********************/
|
/**********************/
|
||||||
/* Namespace Handling */
|
/* 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);
|
const UA_Node *node = UA_NodeStore_get(server->nodestore, &item->sourceNodeId);
|
||||||
if(!node)
|
if(!node)
|
||||||
return UA_STATUSCODE_BADINTERNALERROR;
|
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;
|
UA_Node *newNode = UA_NULL;
|
||||||
void (*deleteNode)(UA_Node*) = UA_NULL;
|
void (*deleteNode)(UA_Node*) = UA_NULL;
|
||||||
switch(node->nodeClass) {
|
switch(node->nodeClass) {
|
||||||
@ -119,7 +143,7 @@ addOneWayReferenceWithSession(UA_Server *server, UA_Session *session, const UA_A
|
|||||||
// insert the new reference
|
// insert the new reference
|
||||||
UA_memcpy(new_refs, old_refs, sizeof(UA_ReferenceNode)*count);
|
UA_memcpy(new_refs, old_refs, sizeof(UA_ReferenceNode)*count);
|
||||||
UA_ReferenceNode_init(&new_refs[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;
|
new_refs[count].isInverse = !item->isForward;
|
||||||
retval |= UA_ExpandedNodeId_copy(&item->targetNodeId, &new_refs[count].targetId);
|
retval |= UA_ExpandedNodeId_copy(&item->targetNodeId, &new_refs[count].targetId);
|
||||||
if(retval != UA_STATUSCODE_GOOD) {
|
if(retval != UA_STATUSCODE_GOOD) {
|
||||||
@ -135,13 +159,14 @@ addOneWayReferenceWithSession(UA_Server *server, UA_Session *session, const UA_A
|
|||||||
newNode->references = new_refs;
|
newNode->references = new_refs;
|
||||||
newNode->referencesSize = ++count;
|
newNode->referencesSize = ++count;
|
||||||
retval = UA_NodeStore_replace(server->nodestore, node, newNode, UA_NULL);
|
retval = UA_NodeStore_replace(server->nodestore, node, newNode, UA_NULL);
|
||||||
UA_NodeStore_release(node);
|
UA_NodeStore_release(node);
|
||||||
if(retval != UA_STATUSCODE_BADINTERNALERROR)
|
if (retval == UA_STATUSCODE_BADINTERNALERROR) {
|
||||||
return retval;
|
/* presumably because the node was replaced and an old version was updated at the same time. just try again */
|
||||||
|
deleteNode(newNode);
|
||||||
// error presumably because the node was replaced and an old version was updated just try again
|
return addOneWayReferenceWithSession(server, session, item);
|
||||||
deleteNode(newNode);
|
}
|
||||||
return addOneWayReferenceWithSession(server, session, item);
|
return retval;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* userland version of addReferenceWithSession */
|
/* 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) {
|
static void init_response_header(const UA_RequestHeader *p, UA_ResponseHeader *r) {
|
||||||
r->requestHandle = p->requestHandle;
|
r->requestHandle = p->requestHandle;
|
||||||
r->serviceResult = UA_STATUSCODE_GOOD;
|
|
||||||
r->stringTableSize = 0;
|
r->stringTableSize = 0;
|
||||||
r->timestamp = UA_DateTime_now();
|
r->timestamp = UA_DateTime_now();
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the message is small enough, we allocate it on the stack and save a malloc
|
|
||||||
#define ALLOC_MESSAGE(MESSAGE, SIZE) do { \
|
|
||||||
UA_UInt32 messageSize = SIZE; \
|
|
||||||
if(messageSize <= MAX_STACK_MESSAGE) { \
|
|
||||||
messageOnStack = UA_TRUE; \
|
|
||||||
*MESSAGE = (UA_ByteString){.length = messageSize, \
|
|
||||||
.data = UA_alloca(messageSize)}; \
|
|
||||||
} else \
|
|
||||||
UA_ByteString_newMembers(MESSAGE, messageSize); \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
#define INVOKE_SERVICE(TYPE) do { \
|
#define INVOKE_SERVICE(TYPE) do { \
|
||||||
UA_##TYPE##Request p; \
|
UA_##TYPE##Request p; \
|
||||||
UA_##TYPE##Response r; \
|
UA_##TYPE##Response r; \
|
||||||
if(UA_##TYPE##Request_decodeBinary(msg, pos, &p)) \
|
if(UA_##TYPE##Request_decodeBinary(msg, pos, &p)) \
|
||||||
return; \
|
return; \
|
||||||
|
if(clientChannel->session && \
|
||||||
|
UA_NodeId_equal(&clientChannel->session->authenticationToken, \
|
||||||
|
&p.requestHeader.authenticationToken)) \
|
||||||
|
clientSession = clientChannel->session; \
|
||||||
UA_##TYPE##Response_init(&r); \
|
UA_##TYPE##Response_init(&r); \
|
||||||
init_response_header(&p.requestHeader, &r.responseHeader); \
|
init_response_header(&p.requestHeader, &r.responseHeader); \
|
||||||
Service_##TYPE(server, clientSession, &p, &r); \
|
if(!clientSession) \
|
||||||
ALLOC_MESSAGE(message, UA_##TYPE##Response_calcSizeBinary(&r)); \
|
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##Response_encodeBinary(&r, message, &sendOffset); \
|
||||||
UA_##TYPE##Request_deleteMembers(&p); \
|
UA_##TYPE##Request_deleteMembers(&p); \
|
||||||
UA_##TYPE##Response_deleteMembers(&r); \
|
UA_##TYPE##Response_deleteMembers(&r); \
|
||||||
@ -167,15 +162,11 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
|
|||||||
|
|
||||||
UA_SecureChannel *clientChannel = connection->channel;
|
UA_SecureChannel *clientChannel = connection->channel;
|
||||||
UA_SecureChannel anonymousChannel;
|
UA_SecureChannel anonymousChannel;
|
||||||
|
#ifdef EXTENSION_STATELESS
|
||||||
if(!clientChannel) {
|
if(!clientChannel) {
|
||||||
UA_SecureChannel_init(&anonymousChannel);
|
UA_SecureChannel_init(&anonymousChannel);
|
||||||
clientChannel = &anonymousChannel;
|
clientChannel = &anonymousChannel;
|
||||||
}
|
}
|
||||||
|
|
||||||
UA_Session *clientSession = clientChannel->session;
|
|
||||||
#ifdef EXTENSION_STATELESS
|
|
||||||
if(secureChannelId == 0)
|
|
||||||
clientSession = &anonymousSession;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// 2) Read the security header
|
// 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->sequenceNumber = sequenceHeader.sequenceNumber;
|
||||||
clientChannel->requestId = sequenceHeader.requestId;
|
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
|
// 3) Read the nodeid of the request
|
||||||
UA_NodeId requestType;
|
UA_NodeId requestType;
|
||||||
if(UA_NodeId_decodeBinary(msg, pos, &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_UInt32 responseType;
|
||||||
UA_ByteString *header = &responseBufs[0];
|
UA_ByteString *header = &responseBufs[0];
|
||||||
UA_ByteString *message = &responseBufs[1];
|
UA_ByteString *message = &responseBufs[1];
|
||||||
UA_Boolean messageOnStack = UA_FALSE;
|
|
||||||
size_t sendOffset = 0;
|
size_t sendOffset = 0;
|
||||||
|
|
||||||
#ifdef EXTENSION_STATELESS
|
|
||||||
switch(requestType.identifier.numeric - UA_ENCODINGOFFSET_BINARY) {
|
|
||||||
case UA_NS0ID_READREQUEST:
|
|
||||||
case UA_NS0ID_WRITEREQUEST:
|
|
||||||
case UA_NS0ID_BROWSEREQUEST:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if(clientSession != &anonymousSession)
|
|
||||||
retval = UA_STATUSCODE_BADNOTCONNECTED;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//subtract UA_ENCODINGOFFSET_BINARY for binary encoding, if retval is set, this forces the default path
|
//subtract UA_ENCODINGOFFSET_BINARY for binary encoding, if retval is set, this forces the default path
|
||||||
switch(requestType.identifier.numeric - UA_ENCODINGOFFSET_BINARY + retval) {
|
switch(requestType.identifier.numeric - UA_ENCODINGOFFSET_BINARY + retval) {
|
||||||
case UA_NS0ID_GETENDPOINTSREQUEST: {
|
case UA_NS0ID_GETENDPOINTSREQUEST: {
|
||||||
@ -231,7 +215,7 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
|
|||||||
UA_GetEndpointsResponse_init(&r);
|
UA_GetEndpointsResponse_init(&r);
|
||||||
init_response_header(&p.requestHeader, &r.responseHeader);
|
init_response_header(&p.requestHeader, &r.responseHeader);
|
||||||
Service_GetEndpoints(server, &p, &r);
|
Service_GetEndpoints(server, &p, &r);
|
||||||
ALLOC_MESSAGE(message, UA_GetEndpointsResponse_calcSizeBinary(&r));
|
connection->getBuffer(connection, message, UA_GetEndpointsResponse_calcSizeBinary(&r));
|
||||||
UA_GetEndpointsResponse_encodeBinary(&r, message, &sendOffset);
|
UA_GetEndpointsResponse_encodeBinary(&r, message, &sendOffset);
|
||||||
UA_GetEndpointsRequest_deleteMembers(&p);
|
UA_GetEndpointsRequest_deleteMembers(&p);
|
||||||
UA_GetEndpointsResponse_deleteMembers(&r);
|
UA_GetEndpointsResponse_deleteMembers(&r);
|
||||||
@ -247,7 +231,7 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
|
|||||||
UA_FindServersResponse_init(&r);
|
UA_FindServersResponse_init(&r);
|
||||||
init_response_header(&p.requestHeader, &r.responseHeader);
|
init_response_header(&p.requestHeader, &r.responseHeader);
|
||||||
Service_FindServers(server, &p, &r);
|
Service_FindServers(server, &p, &r);
|
||||||
ALLOC_MESSAGE(message, UA_FindServersResponse_calcSizeBinary(&r));
|
connection->getBuffer(connection, message, UA_FindServersResponse_calcSizeBinary(&r));
|
||||||
UA_FindServersResponse_encodeBinary(&r, message, &sendOffset);
|
UA_FindServersResponse_encodeBinary(&r, message, &sendOffset);
|
||||||
UA_FindServersRequest_deleteMembers(&p);
|
UA_FindServersRequest_deleteMembers(&p);
|
||||||
UA_FindServersResponse_deleteMembers(&r);
|
UA_FindServersResponse_deleteMembers(&r);
|
||||||
@ -263,7 +247,7 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
|
|||||||
UA_CreateSessionResponse_init(&r);
|
UA_CreateSessionResponse_init(&r);
|
||||||
init_response_header(&p.requestHeader, &r.responseHeader);
|
init_response_header(&p.requestHeader, &r.responseHeader);
|
||||||
Service_CreateSession(server, clientChannel, &p, &r);
|
Service_CreateSession(server, clientChannel, &p, &r);
|
||||||
ALLOC_MESSAGE(message, UA_CreateSessionResponse_calcSizeBinary(&r));
|
connection->getBuffer(connection, message, UA_CreateSessionResponse_calcSizeBinary(&r));
|
||||||
UA_CreateSessionResponse_encodeBinary(&r, message, &sendOffset);
|
UA_CreateSessionResponse_encodeBinary(&r, message, &sendOffset);
|
||||||
UA_CreateSessionRequest_deleteMembers(&p);
|
UA_CreateSessionRequest_deleteMembers(&p);
|
||||||
UA_CreateSessionResponse_deleteMembers(&r);
|
UA_CreateSessionResponse_deleteMembers(&r);
|
||||||
@ -279,7 +263,7 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
|
|||||||
UA_ActivateSessionResponse_init(&r);
|
UA_ActivateSessionResponse_init(&r);
|
||||||
init_response_header(&p.requestHeader, &r.responseHeader);
|
init_response_header(&p.requestHeader, &r.responseHeader);
|
||||||
Service_ActivateSession(server, clientChannel, &p, &r);
|
Service_ActivateSession(server, clientChannel, &p, &r);
|
||||||
ALLOC_MESSAGE(message, UA_ActivateSessionResponse_calcSizeBinary(&r));
|
connection->getBuffer(connection, message, UA_ActivateSessionResponse_calcSizeBinary(&r));
|
||||||
UA_ActivateSessionResponse_encodeBinary(&r, message, &sendOffset);
|
UA_ActivateSessionResponse_encodeBinary(&r, message, &sendOffset);
|
||||||
UA_ActivateSessionRequest_deleteMembers(&p);
|
UA_ActivateSessionRequest_deleteMembers(&p);
|
||||||
UA_ActivateSessionResponse_deleteMembers(&r);
|
UA_ActivateSessionResponse_deleteMembers(&r);
|
||||||
@ -287,57 +271,39 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case UA_NS0ID_CLOSESESSIONREQUEST: {
|
case UA_NS0ID_CLOSESESSIONREQUEST:
|
||||||
UA_CloseSessionRequest p;
|
INVOKE_SERVICE(CloseSession);
|
||||||
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;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case UA_NS0ID_READREQUEST:
|
case UA_NS0ID_READREQUEST:
|
||||||
INVOKE_SERVICE(Read);
|
INVOKE_SERVICE(Read);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UA_NS0ID_WRITEREQUEST:
|
case UA_NS0ID_WRITEREQUEST:
|
||||||
INVOKE_SERVICE(Write);
|
INVOKE_SERVICE(Write);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UA_NS0ID_BROWSEREQUEST:
|
case UA_NS0ID_BROWSEREQUEST:
|
||||||
INVOKE_SERVICE(Browse);
|
INVOKE_SERVICE(Browse);
|
||||||
break;
|
break;
|
||||||
|
case UA_NS0ID_BROWSENEXTREQUEST:
|
||||||
|
INVOKE_SERVICE(BrowseNext);
|
||||||
|
break;
|
||||||
case UA_NS0ID_ADDREFERENCESREQUEST:
|
case UA_NS0ID_ADDREFERENCESREQUEST:
|
||||||
INVOKE_SERVICE(AddReferences);
|
INVOKE_SERVICE(AddReferences);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UA_NS0ID_REGISTERNODESREQUEST:
|
case UA_NS0ID_REGISTERNODESREQUEST:
|
||||||
INVOKE_SERVICE(RegisterNodes);
|
INVOKE_SERVICE(RegisterNodes);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UA_NS0ID_UNREGISTERNODESREQUEST:
|
case UA_NS0ID_UNREGISTERNODESREQUEST:
|
||||||
INVOKE_SERVICE(UnregisterNodes);
|
INVOKE_SERVICE(UnregisterNodes);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UA_NS0ID_TRANSLATEBROWSEPATHSTONODEIDSREQUEST:
|
case UA_NS0ID_TRANSLATEBROWSEPATHSTONODEIDSREQUEST:
|
||||||
INVOKE_SERVICE(TranslateBrowsePathsToNodeIds);
|
INVOKE_SERVICE(TranslateBrowsePathsToNodeIds);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
UA_LOG_INFO(server->logger, UA_LOGGERCATEGORY_COMMUNICATION, "Unknown request: NodeId(ns=%d, i=%d)",
|
UA_LOG_INFO(server->logger, UA_LOGGERCATEGORY_COMMUNICATION, "Unknown request: NodeId(ns=%d, i=%d)",
|
||||||
requestType.namespaceIndex, requestType.identifier.numeric);
|
requestType.namespaceIndex, requestType.identifier.numeric);
|
||||||
|
|
||||||
UA_RequestHeader p;
|
UA_RequestHeader p;
|
||||||
UA_ResponseHeader r;
|
UA_ResponseHeader r;
|
||||||
if(UA_RequestHeader_decodeBinary(msg, pos, &p))
|
if(UA_RequestHeader_decodeBinary(msg, pos, &p) != UA_STATUSCODE_GOOD)
|
||||||
return;
|
return;
|
||||||
UA_ResponseHeader_init(&r);
|
UA_ResponseHeader_init(&r);
|
||||||
init_response_header(&p, &r);
|
init_response_header(&p, &r);
|
||||||
@ -346,7 +312,7 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
|
|||||||
if(retval != UA_STATUSCODE_GOOD)
|
if(retval != UA_STATUSCODE_GOOD)
|
||||||
r.serviceResult = retval;
|
r.serviceResult = retval;
|
||||||
#endif
|
#endif
|
||||||
ALLOC_MESSAGE(message, UA_ResponseHeader_calcSizeBinary(&r));
|
connection->getBuffer(connection, message, UA_ResponseHeader_calcSizeBinary(&r));
|
||||||
UA_ResponseHeader_encodeBinary(&r, message, &sendOffset);
|
UA_ResponseHeader_encodeBinary(&r, message, &sendOffset);
|
||||||
UA_RequestHeader_deleteMembers(&p);
|
UA_RequestHeader_deleteMembers(&p);
|
||||||
UA_ResponseHeader_deleteMembers(&r);
|
UA_ResponseHeader_deleteMembers(&r);
|
||||||
@ -376,11 +342,10 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
|
|||||||
+ UA_SymmetricAlgorithmSecurityHeader_calcSizeBinary(&symSecHeader)
|
+ UA_SymmetricAlgorithmSecurityHeader_calcSizeBinary(&symSecHeader)
|
||||||
+ UA_SequenceHeader_calcSizeBinary(&seqHeader)
|
+ UA_SequenceHeader_calcSizeBinary(&seqHeader)
|
||||||
+ UA_NodeId_calcSizeBinary(&response_nodeid);
|
+ UA_NodeId_calcSizeBinary(&response_nodeid);
|
||||||
|
respHeader.messageHeader.messageSize = headerSize + message->length;
|
||||||
*header = (UA_ByteString){ .length = headerSize, .data = UA_alloca(headerSize) };
|
|
||||||
respHeader.messageHeader.messageSize = header->length + message->length;
|
|
||||||
|
|
||||||
size_t rpos = 0;
|
size_t rpos = 0;
|
||||||
|
connection->getBuffer(connection, header, headerSize);
|
||||||
UA_SecureConversationMessageHeader_encodeBinary(&respHeader, header, &rpos);
|
UA_SecureConversationMessageHeader_encodeBinary(&respHeader, header, &rpos);
|
||||||
UA_SymmetricAlgorithmSecurityHeader_encodeBinary(&symSecHeader, header, &rpos);
|
UA_SymmetricAlgorithmSecurityHeader_encodeBinary(&symSecHeader, header, &rpos);
|
||||||
UA_SequenceHeader_encodeBinary(&seqHeader, header, &rpos);
|
UA_SequenceHeader_encodeBinary(&seqHeader, header, &rpos);
|
||||||
@ -393,27 +358,22 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
|
|||||||
responseBufArray.strings = responseBufs;
|
responseBufArray.strings = responseBufs;
|
||||||
responseBufArray.stringsSize = 2;
|
responseBufArray.stringsSize = 2;
|
||||||
connection->write(connection, responseBufArray);
|
connection->write(connection, responseBufArray);
|
||||||
|
connection->releaseBuffer(connection, header);
|
||||||
if(!messageOnStack)
|
connection->releaseBuffer(connection, message);
|
||||||
UA_free(message->data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void processCLO(UA_Connection *connection, UA_Server *server, const UA_ByteString *msg,
|
static void processCLO(UA_Connection *connection, UA_Server *server, const UA_ByteString *msg, size_t *pos) {
|
||||||
size_t *pos) {
|
|
||||||
UA_UInt32 secureChannelId;
|
UA_UInt32 secureChannelId;
|
||||||
UA_StatusCode retval = UA_UInt32_decodeBinary(msg, pos, &secureChannelId);
|
UA_StatusCode retval = UA_UInt32_decodeBinary(msg, pos, &secureChannelId);
|
||||||
|
|
||||||
if(retval != UA_STATUSCODE_GOOD || !connection->channel ||
|
if(retval != UA_STATUSCODE_GOOD || !connection->channel ||
|
||||||
connection->channel->securityToken.channelId != secureChannelId)
|
connection->channel->securityToken.channelId != secureChannelId)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Service_CloseSecureChannel(server, secureChannelId);
|
Service_CloseSecureChannel(server, secureChannelId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection, UA_ByteString *msg) {
|
void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection, UA_ByteString *msg) {
|
||||||
if(msg->length <= 0)
|
if(msg->length <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
UA_TcpMessageHeader tcpMessageHeader;
|
UA_TcpMessageHeader tcpMessageHeader;
|
||||||
do {
|
do {
|
||||||
@ -423,9 +383,6 @@ void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(tcpMessageHeader.messageSize < 32)
|
|
||||||
break; // there is no usefull message of that size
|
|
||||||
|
|
||||||
size_t targetpos = pos - 8 + tcpMessageHeader.messageSize;
|
size_t targetpos = pos - 8 + tcpMessageHeader.messageSize;
|
||||||
|
|
||||||
switch(tcpMessageHeader.messageTypeAndFinal & 0xffffff) {
|
switch(tcpMessageHeader.messageTypeAndFinal & 0xffffff) {
|
||||||
|
@ -89,7 +89,7 @@ void Service_ActivateSession(UA_Server *server, UA_SecureChannel *channel,
|
|||||||
const UA_ActivateSessionRequest *request, UA_ActivateSessionResponse *response);
|
const UA_ActivateSessionRequest *request, UA_ActivateSessionResponse *response);
|
||||||
|
|
||||||
/** Used to terminate a Session. */
|
/** 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);
|
UA_CloseSessionResponse *response);
|
||||||
// Service_Cancel
|
// 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
|
* further limited by the use of a View. This Browse Service also supports a
|
||||||
* primitive filtering capability.
|
* primitive filtering capability.
|
||||||
*/
|
*/
|
||||||
void Service_Browse(UA_Server *server, UA_Session *session,
|
void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseRequest *request,
|
||||||
const UA_BrowseRequest *request, UA_BrowseResponse *response);
|
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. */
|
/** Used to translate textual node paths to their respective ids. */
|
||||||
void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *session,
|
void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *session,
|
||||||
const UA_TranslateBrowsePathsToNodeIdsRequest *request,
|
const UA_TranslateBrowsePathsToNodeIdsRequest *request,
|
||||||
UA_TranslateBrowsePathsToNodeIdsResponse *response);
|
UA_TranslateBrowsePathsToNodeIdsResponse *response);
|
||||||
// Service_BrowseNext
|
|
||||||
|
|
||||||
// Service_RegisterNodes
|
// Service_RegisterNodes
|
||||||
void Service_RegisterNodes(UA_Server *server, UA_Session *session, const UA_RegisterNodesRequest *request,
|
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) {
|
void Service_GetEndpoints(UA_Server *server, const UA_GetEndpointsRequest *request, UA_GetEndpointsResponse *response) {
|
||||||
/* test if the supported binary profile shall be returned */
|
/* 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;
|
size_t relevant_count = 0;
|
||||||
for(UA_Int32 j = 0; j < server->endpointDescriptionsSize; j++) {
|
for(UA_Int32 j = 0; j < server->endpointDescriptionsSize; j++) {
|
||||||
relevant_endpoints[j] = UA_FALSE;
|
relevant_endpoints[j] = UA_FALSE;
|
||||||
|
@ -53,8 +53,8 @@ void Service_ActivateSession(UA_Server *server,UA_SecureChannel *channel,
|
|||||||
channel->session = foundSession;
|
channel->session = foundSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
UA_CloseSessionResponse *response) {
|
||||||
UA_Session *foundSession;
|
UA_Session *foundSession;
|
||||||
UA_SessionManager_getSessionByToken(&server->sessionManager,
|
UA_SessionManager_getSessionByToken(&server->sessionManager,
|
||||||
(const UA_NodeId*)&request->requestHeader.authenticationToken, &foundSession);
|
(const UA_NodeId*)&request->requestHeader.authenticationToken, &foundSession);
|
||||||
@ -64,8 +64,6 @@ void Service_CloseSession(UA_Server *server, const UA_CloseSessionRequest *reque
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(UA_SessionManager_removeSession(&server->sessionManager, &foundSession->sessionId) == UA_STATUSCODE_GOOD)
|
response->responseHeader.serviceResult =
|
||||||
response->responseHeader.serviceResult = UA_STATUSCODE_GOOD;
|
UA_SessionManager_removeSession(&server->sessionManager, &session->sessionId);
|
||||||
else
|
|
||||||
response->responseHeader.serviceResult = UA_STATUSCODE_BADSECURECHANNELIDINVALID;
|
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,8 @@
|
|||||||
#include "ua_nodestore.h"
|
#include "ua_nodestore.h"
|
||||||
#include "ua_util.h"
|
#include "ua_util.h"
|
||||||
|
|
||||||
static UA_StatusCode
|
static UA_StatusCode fillrefdescr(UA_NodeStore *ns, const UA_Node *curr, UA_ReferenceNode *ref,
|
||||||
fillrefdescr(UA_NodeStore *ns, const UA_Node *curr, UA_ReferenceNode *ref, UA_UInt32 mask,
|
UA_UInt32 mask, UA_ReferenceDescription *descr)
|
||||||
UA_ReferenceDescription *descr)
|
|
||||||
{
|
{
|
||||||
UA_StatusCode retval = UA_STATUSCODE_GOOD;
|
UA_StatusCode retval = UA_STATUSCODE_GOOD;
|
||||||
UA_ReferenceDescription_init(descr);
|
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);
|
retval |= UA_QualifiedName_copy(&curr->browseName, &descr->browseName);
|
||||||
if(mask & UA_BROWSERESULTMASK_DISPLAYNAME)
|
if(mask & UA_BROWSERESULTMASK_DISPLAYNAME)
|
||||||
retval |= UA_LocalizedText_copy(&curr->displayName, &descr->displayName);
|
retval |= UA_LocalizedText_copy(&curr->displayName, &descr->displayName);
|
||||||
if(mask & UA_BROWSERESULTMASK_TYPEDEFINITION ) {
|
if(mask & UA_BROWSERESULTMASK_TYPEDEFINITION &&
|
||||||
for(UA_Int32 i = 0;i < curr->referencesSize;i++) {
|
(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];
|
UA_ReferenceNode *refnode = &curr->references[i];
|
||||||
if(refnode->referenceTypeId.identifier.numeric == UA_NS0ID_HASTYPEDEFINITION) {
|
if(refnode->referenceTypeId.identifier.numeric != UA_NS0ID_HASTYPEDEFINITION)
|
||||||
retval |= UA_ExpandedNodeId_copy(&refnode->targetId, &descr->typeDefinition);
|
continue;
|
||||||
break;
|
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
|
/* 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. */
|
so, it is retrieved from the Nodestore. If not, null is returned. */
|
||||||
static const UA_Node
|
static const UA_Node *relevant_node(UA_NodeStore *ns, const UA_BrowseDescription *descr,
|
||||||
*relevant_node(UA_NodeStore *ns, const UA_BrowseDescription *descr, UA_Boolean return_all,
|
UA_Boolean return_all, UA_ReferenceNode *reference,
|
||||||
UA_ReferenceNode *reference, UA_NodeId *relevant, size_t relevant_count)
|
UA_NodeId *relevant, size_t relevant_count)
|
||||||
{
|
{
|
||||||
if(reference->isInverse == UA_TRUE && descr->browseDirection == UA_BROWSEDIRECTION_FORWARD)
|
if(reference->isInverse == UA_TRUE && descr->browseDirection == UA_BROWSEDIRECTION_FORWARD)
|
||||||
return UA_NULL;
|
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
|
* 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).
|
* array to process the newly found referencetype nodeids (emulated recursion).
|
||||||
*/
|
*/
|
||||||
static UA_StatusCode
|
static UA_StatusCode findsubtypes(UA_NodeStore *ns, const UA_NodeId *root, UA_NodeId **reftypes,
|
||||||
findsubtypes(UA_NodeStore *ns, const UA_NodeId *root, UA_NodeId **reftypes, size_t *reftypes_count)
|
size_t *reftypes_count)
|
||||||
{
|
{
|
||||||
size_t results_size = 20; // probably too big, but saves mallocs
|
size_t results_size = 20; // probably too big, but saves mallocs
|
||||||
UA_NodeId *results = UA_malloc(sizeof(UA_NodeId) * results_size);
|
UA_NodeId *results = UA_malloc(sizeof(UA_NodeId) * results_size);
|
||||||
if(!results)
|
if(!results)
|
||||||
return UA_STATUSCODE_BADOUTOFMEMORY;
|
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]);
|
UA_StatusCode retval = UA_NodeId_copy(root, &results[0]);
|
||||||
if(retval != UA_STATUSCODE_GOOD) {
|
if(retval != UA_STATUSCODE_GOOD) {
|
||||||
UA_free(results);
|
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 index = 0; // where are we currently in the array?
|
||||||
size_t last = 0; // where is the last element in the array?
|
size_t last = 0; // where is the last element in the array?
|
||||||
do {
|
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)
|
if(!node || node->nodeClass != UA_NODECLASS_REFERENCETYPE)
|
||||||
continue;
|
continue;
|
||||||
for(UA_Int32 i = 0; i < node->referencesSize; i++) {
|
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;
|
return UA_STATUSCODE_GOOD;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Results for a single browsedescription. */
|
/* Results for a single browsedescription. Call this either with an existing continuationpoint from
|
||||||
static void
|
which we take the entire context for the search. Or, call with a browsedescription and maxrefs
|
||||||
browse(UA_NodeStore *ns, const UA_BrowseDescription *descr, UA_UInt32 maxrefs, UA_BrowseResult *result)
|
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;
|
size_t relevant_refs_size = 0;
|
||||||
UA_NodeId *relevant_refs = UA_NULL;
|
UA_NodeId *relevant_refs = UA_NULL;
|
||||||
|
|
||||||
// what are the relevant references?
|
// what are the relevant references?
|
||||||
UA_Boolean all_refs = UA_NodeId_isNull(&descr->referenceTypeId);
|
UA_Boolean all_refs = UA_NodeId_isNull(&descr->referenceTypeId);
|
||||||
if(!all_refs) {
|
if(!all_refs) {
|
||||||
if(descr->includeSubtypes) {
|
if(descr->includeSubtypes) {
|
||||||
result->statusCode = findsubtypes(ns, &descr->referenceTypeId,
|
result->statusCode = findsubtypes(ns, &descr->referenceTypeId, &relevant_refs,
|
||||||
&relevant_refs, &relevant_refs_size);
|
&relevant_refs_size);
|
||||||
if(result->statusCode != UA_STATUSCODE_GOOD)
|
if(result->statusCode != UA_STATUSCODE_GOOD)
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
@ -162,35 +186,64 @@ browse(UA_NodeStore *ns, const UA_BrowseDescription *descr, UA_UInt32 maxrefs, U
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
// allocate memory for the results
|
UA_UInt32 real_maxrefs = maxrefs;
|
||||||
maxrefs = node->referencesSize; // allocate enough space for all of them
|
if(real_maxrefs == 0)
|
||||||
result->references = UA_malloc(sizeof(UA_ReferenceDescription) * maxrefs);
|
real_maxrefs = node->referencesSize;
|
||||||
|
result->references = UA_malloc(sizeof(UA_ReferenceDescription) * real_maxrefs);
|
||||||
if(!result->references) {
|
if(!result->references) {
|
||||||
result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
|
result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
for(UA_Int32 i = 0; i < node->referencesSize && count < maxrefs; i++) {
|
size_t skipped = 0;
|
||||||
const UA_Node *current;
|
for(UA_Int32 i = 0; i < node->referencesSize && count < real_maxrefs; i++) {
|
||||||
current = relevant_node(ns, descr, all_refs, &node->references[i], relevant_refs, relevant_refs_size);
|
const UA_Node *current = relevant_node(ns, descr, all_refs, &node->references[i],
|
||||||
|
relevant_refs, relevant_refs_size);
|
||||||
if(!current)
|
if(!current)
|
||||||
continue;
|
continue;
|
||||||
|
if(skipped < continuationIndex) {
|
||||||
UA_StatusCode retval = fillrefdescr(ns, current, &node->references[i],
|
UA_NodeStore_release(current);
|
||||||
descr->resultMask, &result->references[count]);
|
skipped++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
UA_StatusCode retval = fillrefdescr(ns, current, &node->references[i], descr->resultMask,
|
||||||
|
&result->references[count]);
|
||||||
UA_NodeStore_release(current);
|
UA_NodeStore_release(current);
|
||||||
|
if(retval != UA_STATUSCODE_GOOD) {
|
||||||
if(retval) {
|
|
||||||
UA_Array_delete(result->references, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION], count);
|
UA_Array_delete(result->references, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION], count);
|
||||||
count = 0;
|
|
||||||
result->references = UA_NULL;
|
result->references = UA_NULL;
|
||||||
|
count = 0;
|
||||||
result->statusCode = UA_STATUSCODE_UNCERTAINNOTALLNODESAVAILABLE;
|
result->statusCode = UA_STATUSCODE_UNCERTAINNOTALLNODESAVAILABLE;
|
||||||
break;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
count++;
|
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;
|
result->referencesSize = count;
|
||||||
else {
|
else {
|
||||||
UA_free(result->references);
|
UA_free(result->references);
|
||||||
@ -205,6 +258,11 @@ cleanup:
|
|||||||
|
|
||||||
void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseRequest *request,
|
void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseRequest *request,
|
||||||
UA_BrowseResponse *response) {
|
UA_BrowseResponse *response) {
|
||||||
|
if(!UA_NodeId_isNull(&request->view.viewId)) {
|
||||||
|
response->responseHeader.serviceResult = UA_STATUSCODE_BADVIEWIDUNKNOWN;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(request->nodesToBrowseSize <= 0) {
|
if(request->nodesToBrowseSize <= 0) {
|
||||||
response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
|
response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
|
||||||
return;
|
return;
|
||||||
@ -240,13 +298,63 @@ void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseReque
|
|||||||
/* ### End External Namespaces */
|
/* ### End External Namespaces */
|
||||||
|
|
||||||
response->resultsSize = size;
|
response->resultsSize = size;
|
||||||
for(size_t i = 0;i < size;i++){
|
for(size_t i = 0; i < size; i++) {
|
||||||
if(!isExternal[i])
|
if(!isExternal[i]) {
|
||||||
browse(server->nodestore, &request->nodesToBrowse[i],
|
struct ContinuationPointEntry *cp = UA_NULL;
|
||||||
|
browse(server->nodestore, &cp, &request->nodesToBrowse[i],
|
||||||
request->requestedMaxReferencesPerNode, &response->results[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 */
|
/* 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,
|
void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *session,
|
||||||
const UA_TranslateBrowsePathsToNodeIdsRequest *request,
|
const UA_TranslateBrowsePathsToNodeIdsRequest *request,
|
||||||
UA_TranslateBrowsePathsToNodeIdsResponse *response) {
|
UA_TranslateBrowsePathsToNodeIdsResponse *response) {
|
||||||
if(request->browsePathsSize <= 0) {
|
size_t size = request->browsePathsSize;
|
||||||
|
if(size <= 0) {
|
||||||
response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
|
response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
|
||||||
return;
|
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) {
|
if(!response->results) {
|
||||||
response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
|
response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
response->resultsSize = request->browsePathsSize;
|
/* ### Begin External Namespaces */
|
||||||
for(UA_Int32 i = 0;i < response->resultsSize;i++)
|
UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
|
||||||
translateBrowsePath(server, session, &request->browsePaths[i], &response->results[i]);
|
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,
|
void Service_RegisterNodes(UA_Server *server, UA_Session *session, const UA_RegisterNodesRequest *request,
|
||||||
const UA_RegisterNodesRequest *request,
|
UA_RegisterNodesResponse *response) {
|
||||||
UA_RegisterNodesResponse *response) {
|
|
||||||
|
|
||||||
//TODO: hang the nodeids to the session if really needed
|
//TODO: hang the nodeids to the session if really needed
|
||||||
response->responseHeader.timestamp = UA_DateTime_now();
|
response->responseHeader.timestamp = UA_DateTime_now();
|
||||||
response->registeredNodeIdsSize = request->nodesToRegisterSize;
|
response->registeredNodeIdsSize = request->nodesToRegisterSize;
|
||||||
response->registeredNodeIds = request->nodesToRegister;
|
response->registeredNodeIds = request->nodesToRegister;
|
||||||
if(request->nodesToRegisterSize==0){
|
if(request->nodesToRegisterSize==0)
|
||||||
response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
|
response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
|
||||||
}
|
if(UA_NodeId_equal(&request->requestHeader.authenticationToken, &UA_NODEID_NULL) ||
|
||||||
if(UA_NodeId_equal(&request->requestHeader.authenticationToken, &UA_NODEID_NULL) || !UA_NodeId_equal(&request->requestHeader.authenticationToken, &session->authenticationToken) ){
|
!UA_NodeId_equal(&request->requestHeader.authenticationToken, &session->authenticationToken))
|
||||||
response->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
|
response->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Service_UnregisterNodes(UA_Server *server, UA_Session *session,
|
void Service_UnregisterNodes(UA_Server *server, UA_Session *session, const UA_UnregisterNodesRequest *request,
|
||||||
const UA_UnregisterNodesRequest *request,
|
UA_UnregisterNodesResponse *response) {
|
||||||
UA_UnregisterNodesResponse *response) {
|
|
||||||
|
|
||||||
//TODO: remove the nodeids from the session if really needed
|
//TODO: remove the nodeids from the session if really needed
|
||||||
response->responseHeader.timestamp = UA_DateTime_now();
|
response->responseHeader.timestamp = UA_DateTime_now();
|
||||||
if(request->nodesToUnregisterSize==0){
|
if(request->nodesToUnregisterSize==0)
|
||||||
response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
|
response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
|
||||||
}
|
if(UA_NodeId_equal(&request->requestHeader.authenticationToken, &UA_NODEID_NULL) ||
|
||||||
if(UA_NodeId_equal(&request->requestHeader.authenticationToken, &UA_NODEID_NULL) || !UA_NodeId_equal(&request->requestHeader.authenticationToken, &session->authenticationToken) ){
|
!UA_NodeId_equal(&request->requestHeader.authenticationToken, &session->authenticationToken))
|
||||||
response->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
|
response->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,15 @@
|
|||||||
#include "ua_connection.h"
|
#include "ua_connection.h"
|
||||||
#include "ua_types_encoding_binary.h"
|
#include "ua_types_encoding_binary.h"
|
||||||
|
|
||||||
|
const char *UA_LoggerCategoryNames[4] = {"communication", "server", "client", "userland"};
|
||||||
|
|
||||||
// max message size is 64k
|
// max message size is 64k
|
||||||
const UA_ConnectionConfig UA_ConnectionConfig_standard =
|
const UA_ConnectionConfig UA_ConnectionConfig_standard =
|
||||||
{.protocolVersion = 0, .sendBufferSize = 65536, .recvBufferSize = 65536,
|
{.protocolVersion = 0, .sendBufferSize = 65536, .recvBufferSize = 65536,
|
||||||
.maxMessageSize = 65536, .maxChunkCount = 1};
|
.maxMessageSize = 65536, .maxChunkCount = 1};
|
||||||
|
|
||||||
void UA_Connection_init(UA_Connection *connection) {
|
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->localConf = (UA_ConnectionConfig){0,0,0,0,0};
|
||||||
connection->remoteConf = (UA_ConnectionConfig){0,0,0,0,0};
|
connection->remoteConf = (UA_ConnectionConfig){0,0,0,0,0};
|
||||||
connection->channel = UA_NULL;
|
connection->channel = UA_NULL;
|
||||||
|
@ -10,10 +10,11 @@ UA_Session anonymousSession = {
|
|||||||
.discoveryUrlsSize = -1, .discoveryUrls = UA_NULL},
|
.discoveryUrlsSize = -1, .discoveryUrls = UA_NULL},
|
||||||
.sessionName = {sizeof("Anonymous Session")-1, (UA_Byte*)"Anonymous Session"},
|
.sessionName = {sizeof("Anonymous Session")-1, (UA_Byte*)"Anonymous Session"},
|
||||||
.authenticationToken = {.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC,
|
.authenticationToken = {.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC,
|
||||||
.identifier.numeric = 0},
|
.identifier.numeric = 0},
|
||||||
.sessionId = {.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 0},
|
.sessionId = {.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 0},
|
||||||
.maxRequestMessageSize = UA_UINT32_MAX, .maxResponseMessageSize = UA_UINT32_MAX,
|
.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 = {
|
UA_Session adminSession = {
|
||||||
.clientDescription = {.applicationUri = {-1, UA_NULL}, .productUri = {-1, UA_NULL},
|
.clientDescription = {.applicationUri = {-1, UA_NULL}, .productUri = {-1, UA_NULL},
|
||||||
@ -26,7 +27,16 @@ UA_Session adminSession = {
|
|||||||
.identifier.numeric = 1},
|
.identifier.numeric = 1},
|
||||||
.sessionId = {.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 1},
|
.sessionId = {.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 1},
|
||||||
.maxRequestMessageSize = UA_UINT32_MAX, .maxResponseMessageSize = UA_UINT32_MAX,
|
.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) {
|
void UA_Session_init(UA_Session *session) {
|
||||||
UA_ApplicationDescription_init(&session->clientDescription);
|
UA_ApplicationDescription_init(&session->clientDescription);
|
||||||
@ -38,6 +48,7 @@ void UA_Session_init(UA_Session *session) {
|
|||||||
session->timeout = 0;
|
session->timeout = 0;
|
||||||
UA_DateTime_init(&session->validTill);
|
UA_DateTime_init(&session->validTill);
|
||||||
session->channel = UA_NULL;
|
session->channel = UA_NULL;
|
||||||
|
session->continuationPoints = (struct ContinuationPointList){UA_NULL};
|
||||||
}
|
}
|
||||||
|
|
||||||
void UA_Session_deleteMembers(UA_Session *session) {
|
void UA_Session_deleteMembers(UA_Session *session) {
|
||||||
@ -46,6 +57,13 @@ void UA_Session_deleteMembers(UA_Session *session) {
|
|||||||
UA_NodeId_deleteMembers(&session->sessionId);
|
UA_NodeId_deleteMembers(&session->sessionId);
|
||||||
UA_String_deleteMembers(&session->sessionName);
|
UA_String_deleteMembers(&session->sessionName);
|
||||||
session->channel = UA_NULL;
|
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) {
|
UA_StatusCode UA_Session_setExpirationDate(UA_Session *session) {
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "ua_types.h"
|
#include "ua_types.h"
|
||||||
#include "ua_securechannel.h"
|
#include "ua_securechannel.h"
|
||||||
|
#include "queue.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ingroup communication
|
* @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 {
|
struct UA_Session {
|
||||||
UA_ApplicationDescription clientDescription;
|
UA_ApplicationDescription clientDescription;
|
||||||
UA_String sessionName;
|
UA_String sessionName;
|
||||||
@ -20,6 +29,7 @@ struct UA_Session {
|
|||||||
UA_Int64 timeout;
|
UA_Int64 timeout;
|
||||||
UA_DateTime validTill;
|
UA_DateTime validTill;
|
||||||
UA_SecureChannel *channel;
|
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)
|
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_
|
#define TESTING_NETWORKLAYERS_H_
|
||||||
|
|
||||||
#ifdef NOT_AMALGATED
|
#ifdef NOT_AMALGATED
|
||||||
#include "ua_server.h"
|
# include "ua_server.h"
|
||||||
#else
|
#else
|
||||||
#include "open62541.h"
|
# include "open62541.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** @brief Create the TCP networklayer and listen to the specified port */
|
/** @brief Create the TCP networklayer and listen to the specified port */
|
||||||
|
@ -48,6 +48,7 @@ minimal_types = ["InvalidType", "Node", "NodeClass", "ReferenceNode", "Applicati
|
|||||||
"TranslateBrowsePathsToNodeIdsResponse", "BrowsePath", "BrowsePathResult", "RelativePath",
|
"TranslateBrowsePathsToNodeIdsResponse", "BrowsePath", "BrowsePathResult", "RelativePath",
|
||||||
"BrowsePathTarget", "RelativePathElement", "CreateSubscriptionRequest", "CreateSubscriptionResponse",
|
"BrowsePathTarget", "RelativePathElement", "CreateSubscriptionRequest", "CreateSubscriptionResponse",
|
||||||
"BrowseResponse", "BrowseResult", "ReferenceDescription", "BrowseRequest", "ViewDescription",
|
"BrowseResponse", "BrowseResult", "ReferenceDescription", "BrowseRequest", "ViewDescription",
|
||||||
|
"BrowseNextRequest", "BrowseNextResponse",
|
||||||
"BrowseDescription", "BrowseDirection", "CloseSessionRequest", "AddNodesRequest", "AddNodesResponse",
|
"BrowseDescription", "BrowseDirection", "CloseSessionRequest", "AddNodesRequest", "AddNodesResponse",
|
||||||
"AddNodesItem", "AddNodesResult", "DeleteNodesItem","AddReferencesRequest", "AddReferencesResponse",
|
"AddNodesItem", "AddNodesResult", "DeleteNodesItem","AddReferencesRequest", "AddReferencesResponse",
|
||||||
"AddReferencesItem","DeleteReferencesItem", "VariableNode", "MethodNode", "VariableTypeNode",
|
"AddReferencesItem","DeleteReferencesItem", "VariableNode", "MethodNode", "VariableTypeNode",
|
||||||
|
Loading…
Reference in New Issue
Block a user