mirror of
https://github.com/open62541/open62541.git
synced 2025-06-03 04:00:21 +00:00
Merge remote-tracking branch 'origin/1.4' into merge_14_master_18
This commit is contained in:
commit
1f8e9f04fa
@ -36,7 +36,7 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
# overwritten with more detailed information if git is available.
|
||||
set(OPEN62541_VER_MAJOR 1)
|
||||
set(OPEN62541_VER_MINOR 4)
|
||||
set(OPEN62541_VER_PATCH 2)
|
||||
set(OPEN62541_VER_PATCH 3)
|
||||
set(OPEN62541_VER_LABEL "-undefined") # like "-rc1" or "-g4538abcd" or "-g4538abcd-dirty"
|
||||
set(OPEN62541_VER_COMMIT "unknown-commit")
|
||||
|
||||
@ -1009,7 +1009,7 @@ set(UA_NODESET_DIR ${PROJECT_SOURCE_DIR}/deps/ua-nodeset CACHE STRING "The path
|
||||
|
||||
if(UA_NAMESPACE_ZERO STREQUAL "FULL")
|
||||
# Use the "full" schema files also for datatypes and statuscodes
|
||||
set(UA_SCHEMA_DIR ${UA_NODESET_DIR}/Schema)
|
||||
set(UA_SCHEMA_DIR ${UA_NODESET_DIR}/Schema CACHE INTERNAL "")
|
||||
|
||||
# Set the full Nodeset for NS0
|
||||
if(NOT UA_FILE_NS0)
|
||||
@ -1028,7 +1028,7 @@ if(UA_NAMESPACE_ZERO STREQUAL "FULL")
|
||||
endif()
|
||||
else()
|
||||
# Directory with the schema files for installation
|
||||
set(UA_SCHEMA_DIR ${PROJECT_SOURCE_DIR}/tools/schema)
|
||||
set(UA_SCHEMA_DIR ${PROJECT_SOURCE_DIR}/tools/schema CACHE INTERNAL "")
|
||||
|
||||
# Set the reduced Nodeset for NS0
|
||||
if(NOT UA_FILE_NS0)
|
||||
@ -1374,7 +1374,12 @@ foreach(lib ${open62541_PUBLIC_LIBRARIES})
|
||||
set(pkgcfgpubliclibs "${pkgcfgpubliclibs}-l${lib} ")
|
||||
endforeach()
|
||||
|
||||
string(REPLACE ";" ", " pkgcfglibs "${open62541_LIBRARIES}")
|
||||
if(BUILD_SHARED_LIBS)
|
||||
foreach(lib ${open62541_LIBRARIES})
|
||||
set(pkgcfgpubliclibs "${pkgcfgpubliclibs}-l${lib} ")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
configure_file(tools/open62541.pc.in ${PROJECT_BINARY_DIR}/src_generated/open62541.pc @ONLY)
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
@ -1382,6 +1387,7 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
||||
endif()
|
||||
|
||||
# Install nodeset compiler
|
||||
install(DIRECTORY "tools/certs" "tools/nodeset_compiler"
|
||||
DESTINATION ${open62541_install_tools_dir}
|
||||
FILES_MATCHING
|
||||
@ -1391,6 +1397,7 @@ install(DIRECTORY "tools/certs" "tools/nodeset_compiler"
|
||||
PATTERN ".git*" EXCLUDE
|
||||
PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE)
|
||||
|
||||
# Install schemas
|
||||
# Trailing slash to prevent "schema/schema" nesting
|
||||
install(DIRECTORY ${UA_SCHEMA_DIR}/
|
||||
DESTINATION ${open62541_install_schema_dir}
|
||||
@ -1401,6 +1408,7 @@ install(DIRECTORY ${UA_SCHEMA_DIR}/
|
||||
PATTERN "NodeIds.csv"
|
||||
PERMISSIONS OWNER_READ GROUP_READ)
|
||||
|
||||
# Install python tools
|
||||
set(UA_install_tools_files "tools/generate_datatypes.py"
|
||||
"tools/generate_nodeid_header.py"
|
||||
"tools/generate_statuscode_descriptions.py")
|
||||
|
@ -384,21 +384,6 @@ TCP_registerListenSocket(UA_POSIXConnectionManager *pcm, struct addrinfo *ai,
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
}
|
||||
|
||||
/* If the INADDR_ANY is used, use the local hostname */
|
||||
char hoststr[UA_MAXHOSTNAME_LENGTH];
|
||||
if(hostname) {
|
||||
UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
|
||||
"TCP %u\t| Creating listen socket for \"%s\" on port %u",
|
||||
(unsigned)listenSocket, hostname, port);
|
||||
} else {
|
||||
gethostname(hoststr, UA_MAXHOSTNAME_LENGTH);
|
||||
hostname = hoststr;
|
||||
UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
|
||||
"TCP %u\t| Creating listen socket for \"%s\" "
|
||||
"(with local hostname \"%s\") on port %u",
|
||||
(unsigned)listenSocket, addrstr, hostname, port);
|
||||
}
|
||||
|
||||
/* Some Linux distributions have net.ipv6.bindv6only not activated. So
|
||||
* sockets can double-bind to IPv4 and IPv6. This leads to problems. Use
|
||||
* AF_INET6 sockets only for IPv6. */
|
||||
@ -445,6 +430,31 @@ TCP_registerListenSocket(UA_POSIXConnectionManager *pcm, struct addrinfo *ai,
|
||||
|
||||
/* Bind socket to address */
|
||||
int ret = bind(listenSocket, ai->ai_addr, (socklen_t)ai->ai_addrlen);
|
||||
|
||||
/* Get the port being used if dynamic porting was used */
|
||||
if(port == 0) {
|
||||
struct sockaddr_in sin;
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
socklen_t len = sizeof(sin);
|
||||
getsockname(listenSocket, (struct sockaddr *)&sin, &len);
|
||||
port = ntohs(sin.sin_port);
|
||||
}
|
||||
|
||||
/* If the INADDR_ANY is used, use the local hostname */
|
||||
char hoststr[UA_MAXHOSTNAME_LENGTH];
|
||||
if(hostname) {
|
||||
UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
|
||||
"TCP %u\t| Creating listen socket for \"%s\" on port %u",
|
||||
(unsigned)listenSocket, hostname, port);
|
||||
} else {
|
||||
gethostname(hoststr, UA_MAXHOSTNAME_LENGTH);
|
||||
hostname = hoststr;
|
||||
UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
|
||||
"TCP %u\t| Creating listen socket for \"%s\" "
|
||||
"(with local hostname \"%s\") on port %u",
|
||||
(unsigned)listenSocket, addrstr, hostname, port);
|
||||
}
|
||||
|
||||
if(ret < 0) {
|
||||
UA_LOG_SOCKET_ERRNO_WRAP(
|
||||
UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
|
||||
|
@ -771,10 +771,6 @@ UDP_registerListenSocket(UA_POSIXConnectionManager *pcm, UA_UInt16 port,
|
||||
return UA_STATUSCODE_BADCONNECTIONREJECTED;
|
||||
}
|
||||
|
||||
UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
|
||||
"UDP %u\t| New listen socket for \"%s\" on port %u",
|
||||
(unsigned)listenSocket, hoststr, port);
|
||||
|
||||
/* Set the socket configuration per the parameters */
|
||||
UA_StatusCode res =
|
||||
setConnectionConfig(listenSocket, params,
|
||||
@ -816,6 +812,20 @@ UDP_registerListenSocket(UA_POSIXConnectionManager *pcm, UA_UInt16 port,
|
||||
#else
|
||||
int ret = bind(listenSocket, info->ai_addr, (socklen_t)info->ai_addrlen);
|
||||
#endif
|
||||
|
||||
/* Get the port being used if dynamic porting was used */
|
||||
if(port == 0) {
|
||||
struct sockaddr_in sin;
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
socklen_t len = sizeof(sin);
|
||||
getsockname(listenSocket, (struct sockaddr *)&sin, &len);
|
||||
port = ntohs(sin.sin_port);
|
||||
}
|
||||
|
||||
UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
|
||||
"UDP %u\t| New listen socket for \"%s\" on port %u",
|
||||
(unsigned)listenSocket, hoststr, port);
|
||||
|
||||
if(ret < 0) {
|
||||
UA_LOG_SOCKET_ERRNO_WRAP(
|
||||
UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
|
||||
|
@ -241,7 +241,7 @@ int main(int argc, char **argv) {
|
||||
config->mdnsConfig.mdnsServerName = UA_String_fromChars("Sample-Multicast-Server");
|
||||
|
||||
//setting custom outbound interface
|
||||
config->mdnsInterfaceIP = UA_String_fromChars("42.42.42.42"); //this line will produce an error and set the interface to 0.0.0.0
|
||||
config->mdnsInterfaceIP = UA_String_fromChars("0.0.0.0");
|
||||
|
||||
// See http://www.opcfoundation.org/UA/schemas/1.03/ServerCapabilities.csv
|
||||
// For a LDS server, you should only indicate the LDS capability.
|
||||
|
@ -442,7 +442,7 @@ UA_Client_connectSecureChannelAsync(UA_Client *client, const char *endpointUrl)
|
||||
cc->endpointUrl = UA_STRING_ALLOC(endpointUrl);
|
||||
|
||||
/* Connect */
|
||||
return __UA_Client_connect(client, false);
|
||||
return __UA_Client_connect(client, true);
|
||||
})
|
||||
|
||||
/* Connect to the server and create+activate a Session with the given username
|
||||
|
@ -136,11 +136,13 @@
|
||||
# define _BSD_SOURCE
|
||||
# endif
|
||||
|
||||
/* Define _GNU_SOURCE to get functions like ppoll. Comment this out to
|
||||
/* Define _GNU_SOURCE to get functions like poll. Comment this out to
|
||||
* only use standard POSIX definitions. */
|
||||
# ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE
|
||||
# endif
|
||||
|
||||
#define UA_HAS_GETIFADDR 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
@ -119,16 +119,16 @@ typedef uint64_t UA_UInt64;
|
||||
* ^^^^^
|
||||
* An IEEE single precision (32 bit) floating point value. */
|
||||
typedef float UA_Float;
|
||||
#define UA_FLOAT_MIN FLT_MIN;
|
||||
#define UA_FLOAT_MAX FLT_MAX;
|
||||
#define UA_FLOAT_MIN FLT_MIN
|
||||
#define UA_FLOAT_MAX FLT_MAX
|
||||
|
||||
/**
|
||||
* Double
|
||||
* ^^^^^^
|
||||
* An IEEE double precision (64 bit) floating point value. */
|
||||
typedef double UA_Double;
|
||||
#define UA_DOUBLE_MIN DBL_MIN;
|
||||
#define UA_DOUBLE_MAX DBL_MAX;
|
||||
#define UA_DOUBLE_MIN DBL_MIN
|
||||
#define UA_DOUBLE_MAX DBL_MAX
|
||||
|
||||
/**
|
||||
* .. _statuscode:
|
||||
|
@ -28,8 +28,9 @@ UA_ConnectionConfig UA_ConnectionConfig_default;
|
||||
/* Creates a new server config with one endpoint and custom buffer size.
|
||||
*
|
||||
* The config will set the tcp network layer to the given port and adds a single
|
||||
* endpoint with the security policy ``SecurityPolicy#None`` to the server. A
|
||||
* server certificate may be supplied but is optional.
|
||||
* endpoint with the security policy ``SecurityPolicy#None`` to the server.
|
||||
* If the port is set to 0, it will be dynamically assigned.
|
||||
* A server certificate may be supplied but is optional.
|
||||
* Additionally you can define a custom buffer size for send and receive buffer.
|
||||
*
|
||||
* @param portNumber The port number for the tcp network layer
|
||||
@ -124,6 +125,7 @@ UA_ServerConfig_setBasics(UA_ServerConfig *conf);
|
||||
* Use the various UA_ServerConfig_addXxx functions to add them.
|
||||
* The config will set the tcp network layer to the given port if the
|
||||
* eventloop is not already set.
|
||||
* If the port is set to 0, it will be dynamically assigned.
|
||||
*
|
||||
* @param conf The configuration to manipulate
|
||||
* @param portNumber The port number for the tcp network layer
|
||||
|
@ -387,34 +387,34 @@ setDefaultConfig(UA_ServerConfig *conf, UA_UInt16 portNumber) {
|
||||
|
||||
if(portNumber == 0) {
|
||||
UA_LOG_WARNING(conf->logging, UA_LOGCATEGORY_USERLAND,
|
||||
"Cannot set the ServerUrl with a zero port");
|
||||
} else {
|
||||
if(conf->serverUrlsSize > 0) {
|
||||
UA_LOG_WARNING(conf->logging, UA_LOGCATEGORY_USERLAND,
|
||||
"ServerUrls already set. Overriding.");
|
||||
UA_Array_delete(conf->serverUrls, conf->serverUrlsSize,
|
||||
&UA_TYPES[UA_TYPES_STRING]);
|
||||
conf->serverUrls = NULL;
|
||||
conf->serverUrlsSize = 0;
|
||||
}
|
||||
|
||||
/* Listen on all interfaces (also external). This must be the first
|
||||
* entry if this is desired. Otherwise some interfaces may be blocked
|
||||
* (already in use) with a hostname that is only locally reachable.*/
|
||||
mp_snprintf(serverUrlBuffer[0], sizeof(serverUrlBuffer[0]),
|
||||
"opc.tcp://:%u", portNumber);
|
||||
serverUrls[serverUrlsSize] = UA_STRING(serverUrlBuffer[0]);
|
||||
serverUrlsSize++;
|
||||
|
||||
/* Add to the config */
|
||||
UA_StatusCode retval =
|
||||
UA_Array_copy(serverUrls, serverUrlsSize,
|
||||
(void**)&conf->serverUrls, &UA_TYPES[UA_TYPES_STRING]);
|
||||
if(retval != UA_STATUSCODE_GOOD)
|
||||
return retval;
|
||||
conf->serverUrlsSize = serverUrlsSize;
|
||||
"Dynamic port assignment will be used.");
|
||||
}
|
||||
|
||||
if(conf->serverUrlsSize > 0) {
|
||||
UA_LOG_WARNING(conf->logging, UA_LOGCATEGORY_USERLAND,
|
||||
"ServerUrls already set. Overriding.");
|
||||
UA_Array_delete(conf->serverUrls, conf->serverUrlsSize,
|
||||
&UA_TYPES[UA_TYPES_STRING]);
|
||||
conf->serverUrls = NULL;
|
||||
conf->serverUrlsSize = 0;
|
||||
}
|
||||
|
||||
/* Listen on all interfaces (also external). This must be the first
|
||||
* entry if this is desired. Otherwise some interfaces may be blocked
|
||||
* (already in use) with a hostname that is only locally reachable.*/
|
||||
mp_snprintf(serverUrlBuffer[0], sizeof(serverUrlBuffer[0]),
|
||||
"opc.tcp://:%u", portNumber);
|
||||
serverUrls[serverUrlsSize] = UA_STRING(serverUrlBuffer[0]);
|
||||
serverUrlsSize++;
|
||||
|
||||
/* Add to the config */
|
||||
UA_StatusCode retval =
|
||||
UA_Array_copy(serverUrls, serverUrlsSize,
|
||||
(void**)&conf->serverUrls, &UA_TYPES[UA_TYPES_STRING]);
|
||||
if(retval != UA_STATUSCODE_GOOD)
|
||||
return retval;
|
||||
conf->serverUrlsSize = serverUrlsSize;
|
||||
|
||||
/* Endpoints */
|
||||
/* conf->endpoints = {0, NULL}; */
|
||||
|
||||
|
@ -920,12 +920,12 @@ responseGetEndpoints(UA_Client *client, void *userdata,
|
||||
}
|
||||
|
||||
/* We have found a matching endpoint.
|
||||
* But does it contain a matching user token policy? */
|
||||
* But maybe not a amtching user token policy. */
|
||||
bestEndpointIndex = i;
|
||||
|
||||
/* Look for a supported user token policy */
|
||||
/* Compare the available UserTokenPolicies */
|
||||
for(size_t j = 0; j < endpoint->userIdentityTokensSize; ++j) {
|
||||
UA_UserTokenPolicy* tokenPolicy = &endpoint->userIdentityTokens[j];
|
||||
UA_UserTokenPolicy *tokenPolicy = &endpoint->userIdentityTokens[j];
|
||||
const UA_DataType *tokenType =
|
||||
client->config.userIdentityToken.content.decoded.type;
|
||||
|
||||
@ -998,19 +998,8 @@ responseGetEndpoints(UA_Client *client, void *userdata,
|
||||
bestEndpointLevel = endpoint->securityLevel;
|
||||
bestTokenIndex = j;
|
||||
|
||||
/* Move to the client config */
|
||||
UA_EndpointDescription_clear(&client->config.endpoint);
|
||||
client->config.endpoint = *endpoint;
|
||||
UA_EndpointDescription_init(endpoint);
|
||||
UA_UserTokenPolicy_clear(&client->config.userTokenPolicy);
|
||||
client->config.userTokenPolicy = *tokenPolicy;
|
||||
UA_UserTokenPolicy_init(tokenPolicy);
|
||||
|
||||
/* Store the Server Description */
|
||||
UA_ApplicationDescription_clear(&client->serverDescription);
|
||||
UA_ApplicationDescription_copy(&endpoint->server,
|
||||
&client->serverDescription);
|
||||
|
||||
/* Stop search for the UserTokenPolicy. But we go on searching for
|
||||
* an endpoints with a better security level. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1022,7 +1011,9 @@ responseGetEndpoints(UA_Client *client, void *userdata,
|
||||
closeSecureChannel(client);
|
||||
UA_UNLOCK(&client->clientMutex);
|
||||
return;
|
||||
} else if(bestTokenIndex == notFound) {
|
||||
}
|
||||
|
||||
if(!client->config.noSession && bestTokenIndex == notFound) {
|
||||
UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
|
||||
"No suitable UserTokenPolicy found for the possible endpoints");
|
||||
client->connectStatus = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
|
||||
@ -1031,27 +1022,43 @@ responseGetEndpoints(UA_Client *client, void *userdata,
|
||||
return;
|
||||
}
|
||||
|
||||
/* Log the selected Endpoint and UserTokenPolicy */
|
||||
#if UA_LOGLEVEL <= 300
|
||||
UA_EndpointDescription *endpoint = &client->config.endpoint;
|
||||
UA_UserTokenPolicy *tokenPolicy = &client->config.userTokenPolicy;
|
||||
const char *securityModeNames[3] = {"None", "Sign", "SignAndEncrypt"};
|
||||
const char *userTokenTypeNames[4] = {"Anonymous", "UserName", "Certificate", "IssuedToken"};
|
||||
/* Move the application description and endpoint information to the client config */
|
||||
UA_EndpointDescription *endpoint = &resp->endpoints[bestEndpointIndex];
|
||||
UA_ApplicationDescription_clear(&client->serverDescription);
|
||||
UA_ApplicationDescription_copy(&endpoint->server, &client->serverDescription);
|
||||
UA_EndpointDescription_clear(&client->config.endpoint);
|
||||
client->config.endpoint = *endpoint;
|
||||
|
||||
#if UA_LOGLEVEL <= 300
|
||||
const char *securityModeNames[3] = {"None", "Sign", "SignAndEncrypt"};
|
||||
UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
|
||||
"Selected endpoint %lu in URL %S with SecurityMode "
|
||||
"%s and SecurityPolicy %S",
|
||||
(long unsigned)bestEndpointIndex, endpoint->endpointUrl,
|
||||
securityModeNames[endpoint->securityMode - 1],
|
||||
endpoint->securityPolicyUri);
|
||||
|
||||
UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
|
||||
"Selected UserTokenPolicy %S with UserTokenType %s "
|
||||
"and SecurityPolicy %S", tokenPolicy->policyId,
|
||||
userTokenTypeNames[tokenPolicy->tokenType],
|
||||
tokenPolicy->securityPolicyUri);
|
||||
#endif
|
||||
|
||||
/* Move the UserTokenPolicy information to the client config */
|
||||
if(bestTokenIndex != notFound) {
|
||||
UA_UserTokenPolicy *tokenPolicy = &endpoint->userIdentityTokens[bestTokenIndex];
|
||||
UA_assert(tokenPolicy);
|
||||
#if UA_LOGLEVEL <= 300
|
||||
const char *userTokenTypeNames[4] = {"Anonymous", "UserName", "Certificate", "IssuedToken"};
|
||||
UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
|
||||
"Selected UserTokenPolicy %S with UserTokenType %s "
|
||||
"and SecurityPolicy %S", tokenPolicy->policyId,
|
||||
userTokenTypeNames[tokenPolicy->tokenType],
|
||||
tokenPolicy->securityPolicyUri);
|
||||
#endif
|
||||
UA_UserTokenPolicy_clear(&client->config.userTokenPolicy);
|
||||
client->config.userTokenPolicy = *tokenPolicy;
|
||||
UA_UserTokenPolicy_init(tokenPolicy);
|
||||
}
|
||||
|
||||
/* Don't clean up later -- was moved to the client config */
|
||||
UA_EndpointDescription_init(endpoint);
|
||||
|
||||
/* Close the SecureChannel -- a different SecurityMode or SecurityPolicy is
|
||||
* defined by the Endpoint. */
|
||||
if(client->config.endpoint.securityMode != client->channel.securityMode ||
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include <open62541/client_highlevel.h>
|
||||
#include <open62541/client_highlevel_async.h>
|
||||
#include "util/ua_util_internal.h"
|
||||
|
||||
/* The highlevel client API is an "outer onion layer". This file does not
|
||||
* include ua_client_internal.h on purpose. */
|
||||
@ -873,13 +874,21 @@ AttributeReadCallback(UA_Client *client, void *userdata,
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* Check we have a scalar value of the right datatype */
|
||||
if(!dv->hasValue ||
|
||||
!UA_Variant_hasScalarType(&dv->value, ctx->resultType)) {
|
||||
/* Check we have a value */
|
||||
if(!dv->hasValue) {
|
||||
res = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* Check the type. Try to adjust "in situ" if no match. */
|
||||
if(!UA_Variant_hasScalarType(&dv->value, ctx->resultType)) {
|
||||
adjustType(&dv->value, ctx->resultType);
|
||||
if(!UA_Variant_hasScalarType(&dv->value, ctx->resultType)) {
|
||||
res = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
/* Callback into userland */
|
||||
ctx->userCallback(client, ctx->userContext, requestId,
|
||||
UA_STATUSCODE_GOOD, dv->value.data);
|
||||
|
@ -543,7 +543,7 @@ UA_ReaderGroup_freezeConfiguration(UA_Server *server, UA_ReaderGroup *rg) {
|
||||
|
||||
if(dsrCount > 1) {
|
||||
UA_LOG_WARNING_READERGROUP(server->config.logging, rg,
|
||||
"Mutiple DSR in a readerGroup not supported in RT "
|
||||
"Multiple DSR in a readerGroup not supported in RT "
|
||||
"fixed size configuration");
|
||||
return UA_STATUSCODE_BADNOTIMPLEMENTED;
|
||||
}
|
||||
|
@ -581,7 +581,7 @@ mdns_set_address_record(UA_DiscoveryManager *dm, const char *fullServiceDomain,
|
||||
struct ifaddrs *ifaddr;
|
||||
struct ifaddrs *ifa;
|
||||
if(getifaddrs(&ifaddr) == -1) {
|
||||
UA_LOG_ERROR(dm->logging, UA_LOGCATEGORY_SERVER,
|
||||
UA_LOG_ERROR(dm->server->config.logging, UA_LOGCATEGORY_SERVER,
|
||||
"getifaddrs returned an unexpected error. Not setting mDNS A records.");
|
||||
return;
|
||||
}
|
||||
@ -1238,9 +1238,14 @@ UA_Discovery_addRecord(UA_DiscoveryManager *dm, const UA_String servername,
|
||||
|
||||
listEntry->txtSet = true;
|
||||
|
||||
UA_STACKARRAY(char, newUrl, 10 + hostname.length + 8 + path.length + 1);
|
||||
mp_snprintf(newUrl, 10 + hostname.length + 8 + path.length + 1,
|
||||
"opc.tcp://%S:%d%s%S", hostname, port, path.length > 0 ? "/" : "", path);
|
||||
const size_t newUrlSize = 10 + hostname.length + 8 + path.length + 1;
|
||||
UA_STACKARRAY(char, newUrl, newUrlSize);
|
||||
memset(newUrl, 0, newUrlSize);
|
||||
if(path.length > 0) {
|
||||
mp_snprintf(newUrl, newUrlSize, "opc.tcp://%S:%d/%S", hostname, port, path);
|
||||
} else {
|
||||
mp_snprintf(newUrl, newUrlSize, "opc.tcp://%S:%d", hostname, port);
|
||||
}
|
||||
listEntry->serverOnNetwork.discoveryUrl = UA_String_fromChars(newUrl);
|
||||
listEntry->srvSet = true;
|
||||
}
|
||||
|
@ -903,6 +903,8 @@ UA_Server_run_iterate(UA_Server *server, UA_Boolean waitInternal) {
|
||||
/* Return the time until the next scheduled callback */
|
||||
UA_DateTime now = el->dateTime_nowMonotonic(el);
|
||||
UA_DateTime nextTimeout = (el->nextCyclicTime(el) - now) / UA_DATETIME_MSEC;
|
||||
if(nextTimeout < 0)
|
||||
nextTimeout = 0;
|
||||
if(nextTimeout > UA_UINT16_MAX)
|
||||
nextTimeout = UA_UINT16_MAX;
|
||||
return (UA_UInt16)nextTimeout;
|
||||
|
@ -800,14 +800,6 @@ UA_Server_readObjectProperty(UA_Server *server, const UA_NodeId objectId,
|
||||
/* Type Checking */
|
||||
/*****************/
|
||||
|
||||
static UA_DataTypeKind
|
||||
typeEquivalence(const UA_DataType *t) {
|
||||
UA_DataTypeKind k = (UA_DataTypeKind)t->typeKind;
|
||||
if(k == UA_DATATYPEKIND_ENUM)
|
||||
return UA_DATATYPEKIND_INT32;
|
||||
return k;
|
||||
}
|
||||
|
||||
UA_Boolean
|
||||
compatibleValueDataType(UA_Server *server, const UA_DataType *dataType,
|
||||
const UA_NodeId *constraintDataType) {
|
||||
@ -1150,41 +1142,21 @@ adjustValueType(UA_Server *server, UA_Variant *value,
|
||||
if(!type)
|
||||
return;
|
||||
|
||||
/* Unwrap ExtensionObject arrays if they all contain the same DataType */
|
||||
unwrapEOArray(server, value);
|
||||
|
||||
/* The target type is already achieved. No adjustment needed. */
|
||||
if(UA_NodeId_equal(&type->typeId, targetDataTypeId))
|
||||
return;
|
||||
|
||||
/* Unwrap ExtensionObject arrays if they all contain the same DataType */
|
||||
unwrapEOArray(server, value);
|
||||
|
||||
/* Find the target type */
|
||||
const UA_DataType *targetType =
|
||||
UA_findDataTypeWithCustom(targetDataTypeId, server->config.customDataTypes);
|
||||
if(!targetType)
|
||||
return;
|
||||
|
||||
/* A string is written to a byte array. the valuerank and array dimensions
|
||||
* are checked later */
|
||||
if(targetType == &UA_TYPES[UA_TYPES_BYTE] &&
|
||||
type == &UA_TYPES[UA_TYPES_BYTESTRING] &&
|
||||
UA_Variant_isScalar(value)) {
|
||||
UA_ByteString *str = (UA_ByteString*)value->data;
|
||||
value->type = &UA_TYPES[UA_TYPES_BYTE];
|
||||
value->arrayLength = str->length;
|
||||
value->data = str->data;
|
||||
return;
|
||||
}
|
||||
|
||||
/* An enum was sent as an int32, or an opaque type as a bytestring. This
|
||||
* is detected with the typeKind indicating the "true" datatype. */
|
||||
UA_DataTypeKind te1 = typeEquivalence(targetType);
|
||||
UA_DataTypeKind te2 = typeEquivalence(type);
|
||||
if(te1 == te2 && te1 <= UA_DATATYPEKIND_ENUM) {
|
||||
value->type = targetType;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Add more possible type adjustments here. What are they? */
|
||||
/* Use the generic functionality shared by client and server */
|
||||
adjustType(value, targetType);
|
||||
}
|
||||
|
||||
static UA_StatusCode
|
||||
|
@ -54,6 +54,47 @@ UA_AttributeId_fromName(const UA_String name) {
|
||||
return UA_ATTRIBUTEID_INVALID;
|
||||
}
|
||||
|
||||
static UA_DataTypeKind
|
||||
typeEquivalence(const UA_DataType *t) {
|
||||
UA_DataTypeKind k = (UA_DataTypeKind)t->typeKind;
|
||||
if(k == UA_DATATYPEKIND_ENUM)
|
||||
return UA_DATATYPEKIND_INT32;
|
||||
return k;
|
||||
}
|
||||
|
||||
void
|
||||
adjustType(UA_Variant *value, const UA_DataType *targetType) {
|
||||
/* If the value is empty, there is nothing we can do here */
|
||||
const UA_DataType *type = value->type;
|
||||
if(!type || !targetType)
|
||||
return;
|
||||
|
||||
/* A string is written to a byte array. the valuerank and array dimensions
|
||||
* are checked later */
|
||||
if(targetType == &UA_TYPES[UA_TYPES_BYTE] &&
|
||||
type == &UA_TYPES[UA_TYPES_BYTESTRING] &&
|
||||
UA_Variant_isScalar(value)) {
|
||||
UA_ByteString *str = (UA_ByteString*)value->data;
|
||||
value->type = &UA_TYPES[UA_TYPES_BYTE];
|
||||
value->arrayLength = str->length;
|
||||
value->data = str->data;
|
||||
if(value->storageType != UA_VARIANT_DATA_NODELETE)
|
||||
UA_free(str);
|
||||
return;
|
||||
}
|
||||
|
||||
/* An enum was sent as an int32, or an opaque type as a bytestring. This
|
||||
* is detected with the typeKind indicating the "true" datatype. */
|
||||
UA_DataTypeKind te1 = typeEquivalence(targetType);
|
||||
UA_DataTypeKind te2 = typeEquivalence(type);
|
||||
if(te1 == te2 && te1 <= UA_DATATYPEKIND_ENUM) {
|
||||
value->type = targetType;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Add more possible type adjustments here. What are they? */
|
||||
}
|
||||
|
||||
size_t
|
||||
UA_readNumberWithBase(const UA_Byte *buf, size_t buflen, UA_UInt32 *number, UA_Byte base) {
|
||||
UA_assert(buf);
|
||||
|
@ -27,6 +27,11 @@ _UA_BEGIN_DECLS
|
||||
/* Macro-Expand for MSVC workarounds */
|
||||
#define UA_MACRO_EXPAND(x) x
|
||||
|
||||
/* Try if the type of the value can be adjusted "in situ" to the target type.
|
||||
* That can be done, for example, to map between int32 and an enum. */
|
||||
void
|
||||
adjustType(UA_Variant *value, const UA_DataType *targetType);
|
||||
|
||||
/* Short names for integer. These are not exposed on the public API, since many
|
||||
* user-applications make the same definitions in their headers. */
|
||||
typedef UA_Byte u8;
|
||||
|
@ -138,6 +138,37 @@ START_TEST(Client_read_async) {
|
||||
UA_Client_delete(client);
|
||||
} END_TEST
|
||||
|
||||
static void
|
||||
asyncReadNodeClassAttributeCallback(UA_Client *client, void *userdata,
|
||||
UA_UInt32 requestId, UA_StatusCode status,
|
||||
UA_NodeClass *nodeClass) {
|
||||
ck_assert_uint_eq(status, UA_STATUSCODE_GOOD);
|
||||
UA_UInt16 *asyncCounter = (UA_UInt16*)userdata;
|
||||
(*asyncCounter)++;
|
||||
}
|
||||
|
||||
START_TEST(Client_readNodeClass_async) {
|
||||
UA_Client *client = UA_Client_newForUnitTest();
|
||||
|
||||
UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
|
||||
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
||||
|
||||
UA_UInt16 asyncCounter = 0;
|
||||
UA_NodeId cTimeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
|
||||
retval = UA_Client_readNodeClassAttribute_async(client, cTimeId,
|
||||
asyncReadNodeClassAttributeCallback,
|
||||
&asyncCounter, NULL);
|
||||
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
||||
|
||||
/* Process async responses during 1s */
|
||||
while(asyncCounter == 0)
|
||||
retval |= UA_Client_run_iterate(client, 999);
|
||||
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
||||
|
||||
UA_Client_disconnect(client);
|
||||
UA_Client_delete(client);
|
||||
} END_TEST
|
||||
|
||||
START_TEST(Client_read_async_timed) {
|
||||
UA_Client *client = UA_Client_newForUnitTest();
|
||||
UA_ClientConfig *clientConfig = UA_Client_getConfig(client);
|
||||
@ -242,6 +273,7 @@ static Suite* testSuite_Client(void) {
|
||||
TCase *tc_client = tcase_create("Client Basic");
|
||||
tcase_add_checked_fixture(tc_client, setup, teardown);
|
||||
tcase_add_test(tc_client, Client_read_async);
|
||||
tcase_add_test(tc_client, Client_readNodeClass_async);
|
||||
tcase_add_test(tc_client, Client_read_async_timed);
|
||||
tcase_add_test(tc_client, Client_connectivity_check);
|
||||
tcase_add_test(tc_client, Client_highlevel_async_readValue);
|
||||
|
@ -19,20 +19,10 @@ else()
|
||||
find_library(MBEDCRYPTO_LIBRARY mbedcrypto HINTS ${MBEDTLS_FOLDER_LIBRARY})
|
||||
endif()
|
||||
|
||||
if (NOT TARGET mbedtls::mbedtls)
|
||||
# Only add library if not yet added. If project referenced multiple times, the target is also created multiple times.
|
||||
add_library(mbedtls::mbedtls UNKNOWN IMPORTED)
|
||||
set_property(TARGET mbedtls::mbedtls PROPERTY IMPORTED_LOCATION "${MBEDTLS_LIBRARY}")
|
||||
add_library(mbedtls::mbedx509 UNKNOWN IMPORTED)
|
||||
set_property(TARGET mbedtls::mbedx509 PROPERTY IMPORTED_LOCATION "${MBEDX509_LIBRARY}")
|
||||
add_library(mbedtls::mbedcrypto UNKNOWN IMPORTED)
|
||||
set_property(TARGET mbedtls::mbedcrypto PROPERTY IMPORTED_LOCATION "${MBEDCRYPTO_LIBRARY}")
|
||||
endif()
|
||||
|
||||
set(MBEDTLS_LIBRARIES mbedtls::mbedtls mbedtls::mbedx509 mbedtls::mbedcrypto)
|
||||
set(MBEDTLS_LIBRARIES ${MBEDTLS_LIBRARY} ${MBEDX509_LIBRARY} ${MBEDCRYPTO_LIBRARY})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(MbedTLS DEFAULT_MSG
|
||||
MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)
|
||||
find_package_handle_standard_args(MbedTLS DEFAULT_MSG MBEDTLS_INCLUDE_DIRS
|
||||
MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)
|
||||
|
||||
mark_as_advanced(MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)
|
||||
|
@ -6,5 +6,4 @@ Name: open62541
|
||||
Description: open62541 is an open source C (C99) implementation of OPC UA
|
||||
Version: @OPEN62541_VER_MAJOR@.@OPEN62541_VER_MINOR@.@OPEN62541_VER_PATCH@@OPEN62541_VER_LABEL@
|
||||
Libs: -L${libdir} -lopen62541 @pkgcfgpubliclibs@
|
||||
Requires.private: @pkgcfglibs@
|
||||
Cflags: -I${includedir}
|
||||
|
Loading…
Reference in New Issue
Block a user