feat: add new keyvaluemap structure + utilities

This commit is contained in:
Jan Hermes 2022-10-27 11:49:52 +02:00 committed by Julius Pfrommer
parent ddefacf02e
commit 87798df129
24 changed files with 641 additions and 273 deletions

View File

@ -9,10 +9,10 @@
UA_StatusCode
UA_KeyValueRestriction_validate(const UA_KeyValueRestriction *restrictions, size_t restrictionsSize,
const UA_KeyValuePair *params, size_t paramsSize) {
const UA_KeyValueMap *map) {
for(size_t i = 0; i < restrictionsSize; i++) {
const UA_KeyValueRestriction *r = &restrictions[i];
const UA_Variant *val = UA_KeyValueMap_get(params, paramsSize, r->name);
const UA_Variant *val = UA_KeyValueMap_get(map, r->name);
/* Value not present but required? */
if(!val) {

View File

@ -26,8 +26,9 @@ typedef struct {
} UA_KeyValueRestriction;
UA_StatusCode
UA_KeyValueRestriction_validate(const UA_KeyValueRestriction *restrictions, size_t restrictionsSiz,
const UA_KeyValuePair *params, size_t paramsSize);
UA_KeyValueRestriction_validate(const UA_KeyValueRestriction *restrictions,
size_t restrictionsSiz,
const UA_KeyValueMap *map);
_UA_END_DECLS

View File

@ -280,7 +280,7 @@ ETH_close(ETHConnectionManager *ecm, UA_RegisteredFD *rfd) {
erfd->connectionCallback(&ecm->cm, (uintptr_t)rfd->fd,
rfd->application, &rfd->context,
UA_CONNECTIONSTATE_CLOSING,
0, NULL, UA_BYTESTRING_NULL);
&UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);
/* Close the socket */
int ret = UA_close(rfd->fd);
@ -331,7 +331,7 @@ ETH_connectionSocketCallback(UA_ConnectionManager *cm, UA_RegisteredFD *rfd,
efd->connectionCallback(cm, (uintptr_t)rfd->fd,
rfd->application, &rfd->context,
UA_CONNECTIONSTATE_CLOSING,
0, NULL, UA_BYTESTRING_NULL);
&UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);
ETH_close(ecm, rfd);
UA_free(rfd);
return;
@ -360,8 +360,10 @@ ETH_connectionSocketCallback(UA_ConnectionManager *cm, UA_RegisteredFD *rfd,
/* Receive has failed */
if(ret <= 0) {
if(UA_ERRNO == UA_INTERRUPTED)
goto finish;
if(UA_ERRNO == UA_INTERRUPTED) {
UA_ByteString_clear(&response);
return;
}
/* Orderly shutdown of the socket. We can immediately close as no method
* "below" in the call stack will use the socket in this iteration of
@ -372,7 +374,8 @@ ETH_connectionSocketCallback(UA_ConnectionManager *cm, UA_RegisteredFD *rfd,
(unsigned)rfd->fd, errno_str));
ETH_close(ecm, rfd);
UA_free(rfd);
goto finish;
UA_ByteString_clear(&response);
return;
}
/* Set the length of the received buffer */
@ -391,8 +394,10 @@ ETH_connectionSocketCallback(UA_ConnectionManager *cm, UA_RegisteredFD *rfd,
UA_Boolean dei = 0;
size_t headerSize = parseETHHeader(&response, destAddr, sourceAddr,
&etherType, &vid, &pcp, &dei);
if(headerSize == 0)
goto finish;
if(headerSize == 0) {
UA_ByteString_clear(&response);
return;
}
/* Set up the parameter arguments */
unsigned char destAddrBytes[18];
@ -423,21 +428,21 @@ ETH_connectionSocketCallback(UA_ConnectionManager *cm, UA_RegisteredFD *rfd,
paramsSize += 3;
}
UA_KeyValueMap map = {paramsSize, params};
/* Callback to the application layer with the Ethernet header hidden */
response.data += headerSize;
response.length -= headerSize;
efd->connectionCallback(cm, (uintptr_t)rfd->fd, rfd->application, &rfd->context,
UA_CONNECTIONSTATE_ESTABLISHED, paramsSize, params, response);
UA_CONNECTIONSTATE_ESTABLISHED, &map, response);
response.data -= headerSize;
response.length += headerSize;
finish:
UA_ByteString_clear(&response);
}
static UA_StatusCode
ETH_openListenConnection(UA_EventLoop *el, ETH_FD *fd,
size_t paramsSize, const UA_KeyValuePair *params,
const UA_KeyValueMap *params,
int ifindex, UA_UInt16 etherType) {
/* Bind the socket to interface and EtherType. Don't receive anything else. */
struct sockaddr_ll sll = {0};
@ -453,8 +458,7 @@ ETH_openListenConnection(UA_EventLoop *el, ETH_FD *fd,
/* Set receiving to promiscuous (all target host addresses) */
const UA_Boolean *promiscuous = (const UA_Boolean*)
UA_KeyValueMap_getScalar(params, paramsSize,
ETHConfigParameters[ETH_PARAMINDEX_PROMISCUOUS].name,
UA_KeyValueMap_getScalar(params, ETHConfigParameters[ETH_PARAMINDEX_PROMISCUOUS].name,
&UA_TYPES[UA_TYPES_BOOLEAN]);
if(promiscuous && *promiscuous) {
struct packet_mreq mreq = {0};
@ -475,8 +479,7 @@ ETH_openListenConnection(UA_EventLoop *el, ETH_FD *fd,
/* Register for multicast if an address is defined */
const UA_String *address = (const UA_String*)
UA_KeyValueMap_getScalar(params, paramsSize,
ETHConfigParameters[ETH_PARAMINDEX_ADDR].name,
UA_KeyValueMap_getScalar(params, ETHConfigParameters[ETH_PARAMINDEX_ADDR].name,
&UA_TYPES[UA_TYPES_STRING]);
if(address) {
UA_Byte addr[ETHER_ADDR_LEN];
@ -513,12 +516,11 @@ ETH_openListenConnection(UA_EventLoop *el, ETH_FD *fd,
static UA_StatusCode
ETH_openSendConnection(UA_EventLoop *el, ETH_FD *fd,
size_t paramsSize, const UA_KeyValuePair *params,
const UA_KeyValueMap *params,
UA_Byte source[ETHER_ADDR_LEN], int ifindex, UA_UInt16 etherType) {
/* Parse the target address (has to exist) */
const UA_String *address = (const UA_String*)
UA_KeyValueMap_getScalar(params, paramsSize,
ETHConfigParameters[ETH_PARAMINDEX_ADDR].name,
UA_KeyValueMap_getScalar(params, ETHConfigParameters[ETH_PARAMINDEX_ADDR].name,
&UA_TYPES[UA_TYPES_STRING]);
UA_Byte dest[ETHER_ADDR_LEN];
UA_StatusCode res = parseEthAddress(address, dest);
@ -535,22 +537,19 @@ ETH_openSendConnection(UA_EventLoop *el, ETH_FD *fd,
UA_Boolean eid = false;
const UA_UInt16 *vidp = (const UA_UInt16*)
UA_KeyValueMap_getScalar(params, paramsSize,
ETHConfigParameters[ETH_PARAMINDEX_VID].name,
UA_KeyValueMap_getScalar(params, ETHConfigParameters[ETH_PARAMINDEX_VID].name,
&UA_TYPES[UA_TYPES_UINT16]);
if(vidp)
vid = *vidp;
const UA_Byte *pcpp = (const UA_Byte*)
UA_KeyValueMap_getScalar(params, paramsSize,
ETHConfigParameters[ETH_PARAMINDEX_PCP].name,
UA_KeyValueMap_getScalar(params, ETHConfigParameters[ETH_PARAMINDEX_PCP].name,
&UA_TYPES[UA_TYPES_BYTE]);
if(pcpp)
pcp = *pcpp;
const UA_Boolean *eidp = (const UA_Boolean*)
UA_KeyValueMap_getScalar(params, paramsSize,
ETHConfigParameters[ETH_PARAMINDEX_DEI].name,
UA_KeyValueMap_getScalar(params, ETHConfigParameters[ETH_PARAMINDEX_DEI].name,
&UA_TYPES[UA_TYPES_BOOLEAN]);
if(eidp)
eid = *eidp;
@ -567,7 +566,7 @@ ETH_openSendConnection(UA_EventLoop *el, ETH_FD *fd,
}
static UA_StatusCode
ETH_openConnection(UA_ConnectionManager *cm, size_t paramsSize, const UA_KeyValuePair *params,
ETH_openConnection(UA_ConnectionManager *cm, const UA_KeyValueMap *params,
void *application, void *context,
UA_ConnectionManager_connectionCallback connectionCallback) {
ETHConnectionManager *ecm = (ETHConnectionManager*)cm;
@ -575,8 +574,7 @@ ETH_openConnection(UA_ConnectionManager *cm, size_t paramsSize, const UA_KeyValu
/* Listen or send connection? */
const UA_Boolean *listen = (const UA_Boolean*)
UA_KeyValueMap_getScalar(params, paramsSize,
ETHConfigParameters[ETH_PARAMINDEX_LISTEN].name,
UA_KeyValueMap_getScalar(params, ETHConfigParameters[ETH_PARAMINDEX_LISTEN].name,
&UA_TYPES[UA_TYPES_BOOLEAN]);
size_t ethParams = ETH_PARAMETERSSIZE;
if(!listen || !*listen)
@ -584,24 +582,21 @@ ETH_openConnection(UA_ConnectionManager *cm, size_t paramsSize, const UA_KeyValu
/* Validate the parameters */
UA_StatusCode res =
UA_KeyValueRestriction_validate(ETHConfigParameters, ETH_PARAMETERSSIZE,
params, paramsSize);
UA_KeyValueRestriction_validate(ETHConfigParameters, ETH_PARAMETERSSIZE, params);
if(res != UA_STATUSCODE_GOOD)
return res;
/* Get the EtherType parameter */
UA_UInt16 etherType = ETH_P_ALL;
const UA_UInt16 *etParam = (const UA_UInt16*)
UA_KeyValueMap_getScalar(params, paramsSize,
ETHConfigParameters[ETH_PARAMINDEX_ETHERTYPE].name,
UA_KeyValueMap_getScalar(params, ETHConfigParameters[ETH_PARAMINDEX_ETHERTYPE].name,
&UA_TYPES[UA_TYPES_UINT16]);
if(etParam)
etherType = *etParam;
/* Get the interface index */
const UA_String *interface = (const UA_String*)
UA_KeyValueMap_getScalar(params, paramsSize,
ETHConfigParameters[ETH_PARAMINDEX_IFACE].name,
UA_KeyValueMap_getScalar(params, ETHConfigParameters[ETH_PARAMINDEX_IFACE].name,
&UA_TYPES[UA_TYPES_STRING]);
if(interface->length >= 128)
return UA_STATUSCODE_BADINTERNALERROR;
@ -660,11 +655,11 @@ ETH_openConnection(UA_ConnectionManager *cm, size_t paramsSize, const UA_KeyValu
res = UA_STATUSCODE_BADCONNECTIONREJECTED;
goto cleanup;
}
res = ETH_openSendConnection(el, fd, paramsSize, params,
res = ETH_openSendConnection(el, fd, params,
(unsigned char*)ifr.ifr_hwaddr.sa_data,
ifindex, etherType);
} else {
res = ETH_openListenConnection(el, fd, paramsSize, params, ifindex, etherType);
res = ETH_openListenConnection(el, fd, params, ifindex, etherType);
}
if(res != UA_STATUSCODE_GOOD)
goto cleanup;
@ -675,7 +670,8 @@ ETH_openConnection(UA_ConnectionManager *cm, size_t paramsSize, const UA_KeyValu
/* Register the listen socket in the application */
connectionCallback(cm, (uintptr_t)sockfd, application, &fd->fd.context,
UA_CONNECTIONSTATE_ESTABLISHED, 0, NULL, UA_BYTESTRING_NULL);
UA_CONNECTIONSTATE_ESTABLISHED, &UA_KEYVALUEMAP_NULL,
UA_BYTESTRING_NULL);
return UA_STATUSCODE_GOOD;
cleanup:
@ -723,8 +719,7 @@ ETH_shutdownConnection(UA_ConnectionManager *cm, uintptr_t connectionId) {
static UA_StatusCode
ETH_sendWithConnection(UA_ConnectionManager *cm, uintptr_t connectionId,
size_t paramsSize, const UA_KeyValuePair *params,
UA_ByteString *buf) {
const UA_KeyValueMap *params, UA_ByteString *buf) {
ETHConnectionManager *ecm = (ETHConnectionManager*)cm;
UA_EventLoop *el = cm->eventSource.eventLoop;
UA_RegisteredFD *rfd = ETHConnectionManager_findRegisteredFD(ecm, connectionId);
@ -843,12 +838,7 @@ ETH_eventSourceDelete(UA_ConnectionManager *cm) {
}
/* Delete the parameters */
UA_Array_delete(cm->eventSource.params,
cm->eventSource.paramsSize,
&UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
cm->eventSource.params = NULL;
cm->eventSource.paramsSize = 0;
UA_KeyValueMap_clear(cm->eventSource.params);
UA_String_clear(&cm->eventSource.name);
UA_free(cm);
return UA_STATUSCODE_GOOD;

View File

@ -67,7 +67,7 @@ handlePOSIXInterruptEvent(UA_EventSource *es, UA_RegisteredFD *rfd, short event)
(unsigned)rfd->fd, fdsi.ssi_signo);
rs->signalCallback((UA_InterruptManager *)es,
(uintptr_t)rfd->fd, rfd->context, 0, NULL);
(uintptr_t)rfd->fd, rfd->context, &UA_KEYVALUEMAP_NULL);
}
static void
@ -240,7 +240,7 @@ executeTriggeredPOSIXInterrupts(UA_EventSource *es, UA_RegisteredFD *rfd, short
TAILQ_REMOVE(&singletonIM->triggered, rs, triggeredEntry);
rs->triggered = false;
rs->signalCallback(&singletonIM->im, (uintptr_t)rs->signal,
rs->rfd.context, 0, NULL);
rs->rfd.context, &UA_KEYVALUEMAP_NULL);
}
}
@ -248,10 +248,10 @@ executeTriggeredPOSIXInterrupts(UA_EventSource *es, UA_RegisteredFD *rfd, short
static UA_StatusCode
registerPOSIXInterrupt(UA_InterruptManager *im, uintptr_t interruptHandle,
size_t paramsSize, const UA_KeyValuePair *params,
const UA_KeyValueMap *params,
UA_InterruptCallback callback, void *interruptContext) {
UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)im->eventSource.eventLoop;
if(paramsSize > 0) {
if(!UA_KeyValueMap_isEmpty(params)) {
UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
"Interrupt\t| Supplied parameters invalid for the "
"POSIX InterruptManager");

View File

@ -94,7 +94,7 @@ TCP_close(TCPConnectionManager *tcm, UA_RegisteredFD *rfd) {
tcpfd->connectionCallback(&tcm->cm, (uintptr_t)rfd->fd,
rfd->application, &rfd->context,
UA_CONNECTIONSTATE_CLOSING,
0, NULL, UA_BYTESTRING_NULL);
&UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);
/* Close the socket */
int ret = UA_close(rfd->fd);
@ -184,7 +184,7 @@ TCP_connectionSocketCallback(UA_ConnectionManager *cm, UA_RegisteredFD *rfd,
/* A new socket has opened. Signal it to the application. */
tcpfd->connectionCallback(cm, (uintptr_t)rfd->fd,
rfd->application, &rfd->context,
UA_CONNECTIONSTATE_ESTABLISHED, 0, NULL,
UA_CONNECTIONSTATE_ESTABLISHED, &UA_KEYVALUEMAP_NULL,
UA_BYTESTRING_NULL);
return;
@ -229,7 +229,7 @@ TCP_connectionSocketCallback(UA_ConnectionManager *cm, UA_RegisteredFD *rfd,
tcpfd->connectionCallback(cm, (uintptr_t)rfd->fd,
rfd->application, &rfd->context,
UA_CONNECTIONSTATE_ESTABLISHED,
0, NULL, response);
&UA_KEYVALUEMAP_NULL, response);
}
/* Gets called when a new connection opens or if the listenSocket is closed */
@ -327,11 +327,15 @@ TCP_listenSocketCallback(UA_ConnectionManager *cm, UA_RegisteredFD *rfd, short e
UA_String hostName = UA_STRING(hoststr);
UA_Variant_setScalar(&kvp.value, &hostName, &UA_TYPES[UA_TYPES_STRING]);
UA_KeyValueMap kvm;
kvm.mapSize = 1;
kvm.map = &kvp;
/* The socket has opened. Signal it to the application. */
tcpfd->connectionCallback(cm, (uintptr_t)newsockfd,
newtcpfd->fd.application, &newtcpfd->fd.context,
UA_CONNECTIONSTATE_ESTABLISHED,
1, &kvp, UA_BYTESTRING_NULL);
&kvm, UA_BYTESTRING_NULL);
}
static UA_StatusCode
@ -467,20 +471,22 @@ TCP_registerListenSocket(UA_ConnectionManager *cm, struct addrinfo *ai,
UA_KeyValuePair params[2];
params[0].key = UA_QUALIFIEDNAME(0, "listen-hostname");
params[1].key = UA_QUALIFIEDNAME(0, "listen-port");
UA_KeyValueMap paramMap;
paramMap.mapSize = 0;
UA_String hostname;
size_t paramsSize = 0;
if(hoststr[0] != 0) {
paramsSize = 2;
paramMap.mapSize = 2;
hostname = UA_STRING(hoststr);
UA_Variant_setScalar(&params[0].value, &hostname, &UA_TYPES[UA_TYPES_STRING]);
UA_Variant_setScalar(&params[1].value, &port, &UA_TYPES[UA_TYPES_UINT16]);
paramMap.map = params;
}
/* Announce the listen-socket in the application */
connectionCallback(cm, (uintptr_t)listenSocket, application,
&newtcpfd->fd.context,
UA_CONNECTIONSTATE_ESTABLISHED,
paramsSize, params, UA_BYTESTRING_NULL);
&paramMap, UA_BYTESTRING_NULL);
return UA_STATUSCODE_GOOD;
}
@ -599,7 +605,7 @@ TCP_shutdownConnection(UA_ConnectionManager *cm, uintptr_t connectionId) {
static UA_StatusCode
TCP_sendWithConnection(UA_ConnectionManager *cm, uintptr_t connectionId,
size_t paramsSize, const UA_KeyValuePair *params,
const UA_KeyValueMap *params,
UA_ByteString *buf) {
/* Prevent OS signals when sending to a closed socket */
int flags = MSG_NOSIGNAL;
@ -655,14 +661,14 @@ TCP_sendWithConnection(UA_ConnectionManager *cm, uintptr_t connectionId,
/* Create a listen-socket that waits for incoming connections */
static UA_StatusCode
TCP_openPassiveConnection(UA_ConnectionManager *cm,
size_t paramsSize, const UA_KeyValuePair *params,
const UA_KeyValueMap *params,
void *application, void *context,
UA_ConnectionManager_connectionCallback connectionCallback) {
UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
/* Get the port parameter */
const UA_UInt16 *port = (const UA_UInt16*)
UA_KeyValueMap_getScalar(params, paramsSize,
UA_KeyValueMap_getScalar(params,
UA_QUALIFIEDNAME(0, "listen-port"),
&UA_TYPES[UA_TYPES_UINT16]);
if(!port) {
@ -673,7 +679,7 @@ TCP_openPassiveConnection(UA_ConnectionManager *cm,
/* Get the hostnames parameter */
const UA_Variant *hostNames =
UA_KeyValueMap_get(params, paramsSize, UA_QUALIFIEDNAME(0, "listen-hostnames"));
UA_KeyValueMap_get(params, UA_QUALIFIEDNAME(0, "listen-hostnames"));
if(!hostNames) {
/* No listen-hostnames parameter -> listen on all interfaces */
UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
@ -717,13 +723,13 @@ TCP_openPassiveConnection(UA_ConnectionManager *cm,
/* Open a TCP connection to a remote host */
static UA_StatusCode
TCP_openActiveConnection(UA_ConnectionManager *cm,
size_t paramsSize, const UA_KeyValuePair *params,
const UA_KeyValueMap *params,
void *application, void *context,
UA_ConnectionManager_connectionCallback connectionCallback) {
TCPConnectionManager *tcm = (TCPConnectionManager*)cm;
UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
if(paramsSize != 2) {
if(params->mapSize != 2) {
UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
"TCP\t| Port and hostname need to be defined for the connection");
return UA_STATUSCODE_BADINTERNALERROR;
@ -735,7 +741,7 @@ TCP_openActiveConnection(UA_ConnectionManager *cm,
/* Prepare the port parameter as a string */
const UA_UInt16 *port = (const UA_UInt16*)
UA_KeyValueMap_getScalar(params, paramsSize, UA_QUALIFIEDNAME(0, "port"),
UA_KeyValueMap_getScalar(params, UA_QUALIFIEDNAME(0, "port"),
&UA_TYPES[UA_TYPES_UINT16]);
if(!port) {
UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
@ -746,7 +752,7 @@ TCP_openActiveConnection(UA_ConnectionManager *cm,
/* Prepare the hostname string */
const UA_String *host = (const UA_String*)
UA_KeyValueMap_getScalar(params, paramsSize, UA_QUALIFIEDNAME(0, "hostname"),
UA_KeyValueMap_getScalar(params, UA_QUALIFIEDNAME(0, "hostname"),
&UA_TYPES[UA_TYPES_STRING]);
if(!host) {
UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
@ -859,7 +865,7 @@ TCP_openActiveConnection(UA_ConnectionManager *cm,
/* Signal the new connection to the application as asynchonously opening */
connectionCallback(cm, (uintptr_t)newSock,
application, &newtcpfd->fd.context,
UA_CONNECTIONSTATE_OPENING, 0, NULL,
UA_CONNECTIONSTATE_OPENING, &UA_KEYVALUEMAP_NULL,
UA_BYTESTRING_NULL);
return UA_STATUSCODE_GOOD;
@ -867,7 +873,7 @@ TCP_openActiveConnection(UA_ConnectionManager *cm,
static UA_StatusCode
TCP_openConnection(UA_ConnectionManager *cm,
size_t paramsSize, const UA_KeyValuePair *params,
const UA_KeyValueMap *params,
void *application, void *context,
UA_ConnectionManager_connectionCallback connectionCallback) {
UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
@ -882,12 +888,12 @@ TCP_openConnection(UA_ConnectionManager *cm,
* connection. Otherwise try to open a socket that listens for incoming TCP
* connections. */
const UA_Variant *val =
UA_KeyValueMap_get(params, paramsSize, UA_QUALIFIEDNAME(0, "port"));
UA_KeyValueMap_get(params, UA_QUALIFIEDNAME(0, "port"));
if(val) {
return TCP_openActiveConnection(cm, paramsSize, params,
return TCP_openActiveConnection(cm, params,
application, context, connectionCallback);
} else {
return TCP_openPassiveConnection(cm, paramsSize, params,
return TCP_openPassiveConnection(cm, params,
application, context, connectionCallback);
}
}
@ -904,15 +910,17 @@ TCP_eventSourceStart(UA_ConnectionManager *cm) {
"registered in an EventLoop and not started yet");
return UA_STATUSCODE_BADINTERNALERROR;
}
/* Configure the receive buffer */
UA_UInt32 rxBufSize = 2u << 16; /* The default is 64kb */
const UA_UInt32 *configRxBufSize = (const UA_UInt32*)
UA_KeyValueMap_getScalar(cm->eventSource.params, cm->eventSource.paramsSize,
if(cm->eventSource.params != NULL) {
const UA_UInt32 *configRxBufSize = (const UA_UInt32 *)
UA_KeyValueMap_getScalar(cm->eventSource.params,
UA_QUALIFIEDNAME(0, "recv-bufsize"),
&UA_TYPES[UA_TYPES_UINT32]);
if(configRxBufSize)
rxBufSize = *configRxBufSize;
}
UA_StatusCode res = UA_ByteString_allocBuffer(&tcm->rxBuffer, rxBufSize);
if(res != UA_STATUSCODE_GOOD)
return res;
@ -950,12 +958,10 @@ TCP_eventSourceDelete(UA_ConnectionManager *cm) {
return UA_STATUSCODE_BADINTERNALERROR;
}
if(cm->eventSource.params != NULL) {
/* Delete the parameters */
UA_Array_delete(cm->eventSource.params, cm->eventSource.paramsSize,
&UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
cm->eventSource.params = NULL;
cm->eventSource.paramsSize = 0;
UA_KeyValueMap_clear(cm->eventSource.params);
}
UA_String_clear(&cm->eventSource.name);
UA_free(cm);
return UA_STATUSCODE_GOOD;

View File

@ -58,19 +58,18 @@ typedef union {
/* Retrieves hostname and port from given key value parameters.
*
* @param[in] paramsSize the size of the parameter list
* @param[in] params the parameter list to retrieve from
* @param[in] params the parameter map to retrieve from
* @param[out] hostname the retrieved hostname when present, NULL otherwise
* @param[out] portStr the retrieved port when present, NULL otherwise
* @param[in] logger the logger to log information
* @return -1 upon error, 0 if there was no host or port parameter, 1 if
* host and port are present */
static int
getHostAndPortFromParams(size_t paramsSize, const UA_KeyValuePair *params,
getHostAndPortFromParams(const UA_KeyValueMap *params,
char *hostname, char *portStr, const UA_Logger *logger) {
/* Prepare the port parameter as a string */
const UA_UInt16 *port = (const UA_UInt16*)
UA_KeyValueMap_getScalar(params, paramsSize,
UA_KeyValueMap_getScalar(params,
UA_QUALIFIEDNAME(0, "port"),
&UA_TYPES[UA_TYPES_UINT16]);
if(!port) {
@ -82,7 +81,7 @@ getHostAndPortFromParams(size_t paramsSize, const UA_KeyValuePair *params,
/* Prepare the hostname string */
const UA_String *host = (const UA_String*)
UA_KeyValueMap_getScalar(params, paramsSize,
UA_KeyValueMap_getScalar(params,
UA_QUALIFIEDNAME(0, "hostname"),
&UA_TYPES[UA_TYPES_STRING]);
if(!host) {
@ -101,11 +100,11 @@ getHostAndPortFromParams(size_t paramsSize, const UA_KeyValuePair *params,
}
static int
getNetworkInterfaceFromParams(size_t paramsSize, const UA_KeyValuePair *params,
getNetworkInterfaceFromParams(const UA_KeyValueMap *params,
UA_String *outNetworkInterface, const UA_Logger *logger) {
/* Prepare the networkinterface string */
const UA_String *networkInterface = (const UA_String*)
UA_KeyValueMap_getScalar(params, paramsSize,
UA_KeyValueMap_getScalar(params,
UA_QUALIFIEDNAME(0, "network-interface"),
&UA_TYPES[UA_TYPES_STRING]);
if(!networkInterface) {
@ -118,11 +117,11 @@ getNetworkInterfaceFromParams(size_t paramsSize, const UA_KeyValuePair *params,
}
static int
getConnectionInfoFromParams(size_t paramsSize, const UA_KeyValuePair *params,
getConnectionInfoFromParams(const UA_KeyValueMap *params,
char *hostname, char *portStr,
struct addrinfo **info, const UA_Logger *logger) {
int foundParams = getHostAndPortFromParams(paramsSize, params,
int foundParams = getHostAndPortFromParams(params,
hostname, portStr, logger);
if (foundParams < 0) {
UA_LOG_ERROR(logger, UA_LOGCATEGORY_EVENTLOOP,
@ -258,8 +257,7 @@ isIPv6MulticastAddress(const UA_Byte *address) {
#endif
static UA_StatusCode
setConnectionConfig(UA_FD socket, const UA_KeyValuePair *connectionProperties,
const size_t connectionPropertiesSize,
setConnectionConfig(UA_FD socket, const UA_KeyValueMap *connectionProperties,
int ai_family, const UA_Logger *logger) {
/* Iterate over the given KeyValuePair parameters */
UA_String ttlParam = UA_STRING("ttl");
@ -275,8 +273,8 @@ setConnectionConfig(UA_FD socket, const UA_KeyValuePair *connectionProperties,
#ifdef __linux__
UA_String socketPriorityParam = UA_STRING("sockpriority");
#endif
for(size_t i = 0; i < connectionPropertiesSize; i++) {
const UA_KeyValuePair *prop = &connectionProperties[i];
for(size_t i = 0; i < connectionProperties->mapSize; i++) {
const UA_KeyValuePair *prop = &connectionProperties->map[i];
if(UA_String_equal(&prop->key.name, &ttlParam)) {
if(UA_Variant_hasScalarType(&prop->value, &UA_TYPES[UA_TYPES_UINT32])){
UA_UInt32 messageTTL = *(UA_UInt32*)prop->value.data;
@ -336,7 +334,7 @@ setConnectionConfig(UA_FD socket, const UA_KeyValuePair *connectionProperties,
return UA_STATUSCODE_GOOD;
}
static UA_StatusCode
setupSendMulticastIPv4(UA_FD socket, struct sockaddr_in *addr, size_t paramsSize, const UA_KeyValuePair *params,
setupSendMulticastIPv4(UA_FD socket, struct sockaddr_in *addr, const UA_KeyValueMap *params,
const UA_Logger *logger) {
struct in_addr address = addr->sin_addr;
@ -346,7 +344,7 @@ setupSendMulticastIPv4(UA_FD socket, struct sockaddr_in *addr, size_t paramsSize
ipMulticastRequest.ipv4.imr_interface.s_addr = UA_htonl(INADDR_ANY);
UA_String netif = UA_STRING_NULL;
int foundInterface = getNetworkInterfaceFromParams(paramsSize, params, &netif, logger);
int foundInterface = getNetworkInterfaceFromParams(params, &netif, logger);
if(foundInterface < 0) {
UA_LOG_ERROR(logger, UA_LOGCATEGORY_NETWORK,
"UDP\t| Opening a connection failed");
@ -377,7 +375,7 @@ setupSendMulticastIPv4(UA_FD socket, struct sockaddr_in *addr, size_t paramsSize
}
static UA_StatusCode
setupListenMulticastIPv4(UA_FD socket, size_t paramsSize, const UA_KeyValuePair *params, struct sockaddr_in *addr,
setupListenMulticastIPv4(UA_FD socket, const UA_KeyValueMap *params, struct sockaddr_in *addr,
const UA_Logger *logger) {
struct in_addr address = addr->sin_addr;
@ -387,7 +385,7 @@ setupListenMulticastIPv4(UA_FD socket, size_t paramsSize, const UA_KeyValuePair
ipMulticastRequest.ipv4.imr_interface.s_addr = UA_htonl(INADDR_ANY);
UA_String netif = UA_STRING_NULL;
int foundInterface = getNetworkInterfaceFromParams(paramsSize, params, &netif, logger);
int foundInterface = getNetworkInterfaceFromParams(params, &netif, logger);
if(foundInterface < 0) {
UA_LOG_ERROR(logger, UA_LOGCATEGORY_NETWORK,
"UDP\t| Opening a connection failed");
@ -422,7 +420,7 @@ setupListenMulticastIPv4(UA_FD socket, size_t paramsSize, const UA_KeyValuePair
#if UA_IPV6
static UA_StatusCode
setupListenMulticastIPv6(UA_FD socket, size_t paramsSize, const UA_KeyValuePair *params, struct sockaddr_in6 *addr,
setupListenMulticastIPv6(UA_FD socket, const UA_KeyValueMap *params, struct sockaddr_in6 *addr,
const UA_Logger *logger) {
struct in6_addr address = addr->sin6_addr;
@ -433,7 +431,7 @@ setupListenMulticastIPv6(UA_FD socket, size_t paramsSize, const UA_KeyValuePair
ipMulticastRequest.ipv6.ipv6mr_interface = 0;
UA_String netif = UA_STRING_NULL;
int foundInterface = getNetworkInterfaceFromParams(paramsSize, params, &netif, logger);
int foundInterface = getNetworkInterfaceFromParams(params, &netif, logger);
if(foundInterface < 0) {
UA_LOG_ERROR(logger, UA_LOGCATEGORY_NETWORK,
"UDP\t| Opening a connection failed");
@ -466,7 +464,7 @@ setupListenMulticastIPv6(UA_FD socket, size_t paramsSize, const UA_KeyValuePair
}
static UA_StatusCode
setupSendMulticastIPv6(UA_FD socket, struct sockaddr_in6 *addr, size_t paramsSize, const UA_KeyValuePair *params,
setupSendMulticastIPv6(UA_FD socket, struct sockaddr_in6 *addr, const UA_KeyValueMap *params,
const UA_Logger *logger) {
struct in6_addr address = addr->sin6_addr;
@ -476,7 +474,7 @@ setupSendMulticastIPv6(UA_FD socket, struct sockaddr_in6 *addr, size_t paramsSiz
ipMulticastRequest.ipv6.ipv6mr_interface = 0;
UA_String netif = UA_STRING_NULL;
int foundInterface = getNetworkInterfaceFromParams(paramsSize, params, &netif, logger);
int foundInterface = getNetworkInterfaceFromParams(params, &netif, logger);
if(foundInterface < 0) {
UA_LOG_ERROR(logger, UA_LOGCATEGORY_NETWORK,
"UDP\t| Opening a connection failed");
@ -578,7 +576,7 @@ UDP_close(UDPConnectionManager *ucm, UA_RegisteredFD *rfd) {
udpfd->connectionCallback(&ucm->cm, (uintptr_t)rfd->fd,
rfd->application, &rfd->context,
UA_CONNECTIONSTATE_CLOSING,
0, NULL, UA_BYTESTRING_NULL);
&UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);
/* Close the socket */
int ret = UA_close(rfd->fd);
@ -630,7 +628,7 @@ UDP_connectionSocketCallback(UA_ConnectionManager *cm, UA_RegisteredFD *rfd,
udpfd->connectionCallback(cm, (uintptr_t)rfd->fd,
rfd->application, &rfd->context,
UA_CONNECTIONSTATE_ESTABLISHED,
0, NULL, UA_BYTESTRING_NULL);
&UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);
/* Now we are interested in read-events. */
rfd->listenEvents = UA_FDEVENT_IN;
@ -677,18 +675,18 @@ UDP_connectionSocketCallback(UA_ConnectionManager *cm, UA_RegisteredFD *rfd,
response.length = (size_t)ret; /* Set the length of the received buffer */
udpfd->connectionCallback(cm, (uintptr_t)rfd->fd,
rfd->application, &rfd->context,
UA_CONNECTIONSTATE_ESTABLISHED, 0, NULL, response);
UA_CONNECTIONSTATE_ESTABLISHED, &UA_KEYVALUEMAP_NULL, response);
}
static UA_StatusCode
checkForListenMulticastAndConfigure(struct addrinfo *info, size_t paramsSize, const UA_KeyValuePair *params,
checkForListenMulticastAndConfigure(struct addrinfo *info, const UA_KeyValueMap *params,
UA_FD listenSocket, const UA_Logger *logger) {
UA_StatusCode res = UA_STATUSCODE_GOOD;
if(info->ai_family == AF_INET) {
UA_Byte *addressVal = (UA_Byte *) &((struct sockaddr_in *)info->ai_addr)->sin_addr;
if(isIPv4MulticastAddress(addressVal)) {
res = setupListenMulticastIPv4(listenSocket,
paramsSize, params, (struct sockaddr_in *)info->ai_addr,
params, (struct sockaddr_in *)info->ai_addr,
logger);
}
#if UA_IPV6
@ -696,7 +694,7 @@ checkForListenMulticastAndConfigure(struct addrinfo *info, size_t paramsSize, co
UA_Byte *addressVal = (UA_Byte *) &((struct sockaddr_in6 *)info->ai_addr)->sin6_addr;
if(isIPv6MulticastAddress(addressVal)) {
res = setupListenMulticastIPv6(listenSocket,
paramsSize, params, (struct sockaddr_in6 *)info->ai_addr, logger);
params, (struct sockaddr_in6 *)info->ai_addr, logger);
}
#endif
} else {
@ -709,7 +707,7 @@ checkForListenMulticastAndConfigure(struct addrinfo *info, size_t paramsSize, co
static UA_StatusCode
UDP_registerListenSocket(UA_ConnectionManager *cm, UA_UInt16 port, struct addrinfo *info,
size_t paramsSize, const UA_KeyValuePair *params,
const UA_KeyValueMap *params,
void *application, void *context,
UA_ConnectionManager_connectionCallback connectionCallback,
UA_Boolean validate) {
@ -747,7 +745,7 @@ UDP_registerListenSocket(UA_ConnectionManager *cm, UA_UInt16 port, struct addrin
"UDP %u\t| New listen socket for \"%s\" on port %u",
(unsigned)listenSocket, hoststr, port);
UA_StatusCode res = checkForListenMulticastAndConfigure(info, paramsSize, params, listenSocket, el->eventLoop.logger);
UA_StatusCode res = checkForListenMulticastAndConfigure(info, params, listenSocket, el->eventLoop.logger);
if(res != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
"UDP\t| Configuring listen multicast failed");
@ -847,13 +845,13 @@ UDP_registerListenSocket(UA_ConnectionManager *cm, UA_UInt16 port, struct addrin
connectionCallback(cm, (uintptr_t)newudpfd->fd.fd,
application, &newudpfd->fd.context,
UA_CONNECTIONSTATE_ESTABLISHED,
0, NULL, UA_BYTESTRING_NULL);
&UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);
return UA_STATUSCODE_GOOD;
}
static UA_StatusCode
UDP_registerListenSockets(UA_ConnectionManager *cm, const char *hostname, UA_UInt16 port,
size_t paramsSize, const UA_KeyValuePair *params,
const UA_KeyValueMap *params,
void *application, void *context,
UA_ConnectionManager_connectionCallback connectionCallback,
UA_Boolean validate) {
@ -891,7 +889,8 @@ UDP_registerListenSockets(UA_ConnectionManager *cm, const char *hostname, UA_UIn
struct addrinfo *ai = res;
UA_StatusCode rv = UA_STATUSCODE_GOOD;
while(ai) {
rv = UDP_registerListenSocket(cm, port, ai, paramsSize, params, application, context, connectionCallback, validate);
rv = UDP_registerListenSocket(cm, port, ai, params, application,
context, connectionCallback, validate);
if(rv != UA_STATUSCODE_GOOD && validate) {
UA_freeaddrinfo(res);
return rv;
@ -953,7 +952,7 @@ UDP_shutdownConnection(UA_ConnectionManager *cm, uintptr_t connectionId) {
static UA_StatusCode
UDP_sendWithConnection(UA_ConnectionManager *cm, uintptr_t connectionId,
size_t paramsSize, const UA_KeyValuePair *params,
const UA_KeyValueMap *params,
UA_ByteString *buf) {
/* Prevent OS signals when sending to a closed socket */
int flags = MSG_NOSIGNAL;
@ -1019,7 +1018,7 @@ UDP_sendWithConnection(UA_ConnectionManager *cm, uintptr_t connectionId,
static UA_StatusCode
checkForSendMulticastAndConfigure(size_t paramsSize, const UA_KeyValuePair *params, struct addrinfo *info, UA_FD newSock,
checkForSendMulticastAndConfigure(const UA_KeyValueMap *params, struct addrinfo *info, UA_FD newSock,
const UA_Logger *logger) {
UA_StatusCode res = UA_STATUSCODE_GOOD;
if(info->ai_family == AF_INET) {
@ -1028,7 +1027,6 @@ checkForSendMulticastAndConfigure(size_t paramsSize, const UA_KeyValuePair *para
if(isIPv4MulticastAddress(addressVal)) {
res = setupSendMulticastIPv4(newSock, (struct sockaddr_in *)info->ai_addr,
paramsSize,
params, logger);
}
#if UA_IPV6
@ -1037,7 +1035,6 @@ checkForSendMulticastAndConfigure(size_t paramsSize, const UA_KeyValuePair *para
UA_Byte *addressVal = (UA_Byte *) &addr->sin6_addr;
if(isIPv6MulticastAddress(addressVal)) {
res = setupSendMulticastIPv6(newSock, (struct sockaddr_in6 *)info->ai_addr,
paramsSize,
params, logger);
}
#endif
@ -1050,7 +1047,7 @@ checkForSendMulticastAndConfigure(size_t paramsSize, const UA_KeyValuePair *para
}
static UA_StatusCode
registerSocketAndDestinationForSend(size_t paramsSize, const UA_KeyValuePair *params,
registerSocketAndDestinationForSend(const UA_KeyValueMap *params,
const char *hostname, struct addrinfo *info,
int error, UDP_FD * ufd, UA_FD *sock, const UA_Logger *logger) {
UA_FD newSock = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
@ -1062,14 +1059,14 @@ registerSocketAndDestinationForSend(size_t paramsSize, const UA_KeyValuePair *pa
hostname, errno_str));
return UA_STATUSCODE_BADDISCONNECT;
}
UA_StatusCode res = setConnectionConfig(newSock, params, paramsSize,
UA_StatusCode res = setConnectionConfig(newSock, params,
info->ai_family, logger);
if(res != UA_STATUSCODE_GOOD) {
UA_close(newSock);
return res;
}
res = checkForSendMulticastAndConfigure(paramsSize, params, info, newSock, logger);
res = checkForSendMulticastAndConfigure(params, info, newSock, logger);
if(res != UA_STATUSCODE_GOOD) {
UA_close(newSock);
UA_LOG_ERROR(logger, UA_LOGCATEGORY_NETWORK,
@ -1084,7 +1081,7 @@ registerSocketAndDestinationForSend(size_t paramsSize, const UA_KeyValuePair *pa
static UA_StatusCode
UDP_openSendConnection(UA_ConnectionManager *cm,
size_t paramsSize, const UA_KeyValuePair *params,
const UA_KeyValueMap *params,
void *application, void *context,
UA_ConnectionManager_connectionCallback connectionCallback,
UA_Boolean validate) {
@ -1095,7 +1092,7 @@ UDP_openSendConnection(UA_ConnectionManager *cm,
char portStr[UA_MAXPORTSTR_LENGTH];
struct addrinfo *info = NULL;
int error = getConnectionInfoFromParams(paramsSize, params, hostname,
int error = getConnectionInfoFromParams(params, hostname,
portStr, &info, el->eventLoop.logger);
if(error < 0 || info == NULL) {
if(info != NULL) {
@ -1119,7 +1116,7 @@ UDP_openSendConnection(UA_ConnectionManager *cm,
/* Create a socket and register the destination address from the provided parameters */
UA_FD newSock = UA_INVALID_FD;
UA_StatusCode res =
registerSocketAndDestinationForSend(paramsSize, params, hostname, info,
registerSocketAndDestinationForSend(params, hostname, info,
error, newudpfd, &newSock, el->eventLoop.logger);
UA_freeaddrinfo(info);
if(validate && res == UA_STATUSCODE_GOOD) {
@ -1162,14 +1159,14 @@ UDP_openSendConnection(UA_ConnectionManager *cm,
/* Signal the connection as opening. The connection fully opens in the next
* iteration of the EventLoop */
connectionCallback(cm, (uintptr_t)newSock, application, &newudpfd->fd.context,
UA_CONNECTIONSTATE_OPENING, 0, NULL, UA_BYTESTRING_NULL);
UA_CONNECTIONSTATE_OPENING, &UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);
return UA_STATUSCODE_GOOD;
}
static UA_StatusCode
UDP_openReceiveConnection(UA_ConnectionManager *cm,
size_t paramsSize, const UA_KeyValuePair *params,
const UA_KeyValueMap *params,
void *application, void *context,
UA_ConnectionManager_connectionCallback connectionCallback,
UA_Boolean validate) {
@ -1177,7 +1174,7 @@ UDP_openReceiveConnection(UA_ConnectionManager *cm,
/* Get the socket */
const UA_UInt16 *port = (const UA_UInt16*)
UA_KeyValueMap_getScalar(params, paramsSize,
UA_KeyValueMap_getScalar(params,
UA_QUALIFIEDNAME(0, "listen-port"),
&UA_TYPES[UA_TYPES_UINT16]);
if(!port) {
@ -1188,15 +1185,14 @@ UDP_openReceiveConnection(UA_ConnectionManager *cm,
/* Get the hostnames configuration */
const UA_Variant *hostNames =
UA_KeyValueMap_get(params, paramsSize,
UA_KeyValueMap_get(params,
UA_QUALIFIEDNAME(0, "listen-hostnames"));
if(!hostNames) {
/* No hostnames configured -> listen on all interfaces*/
UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
"UDP\t| Listening on all interfaces");
return UDP_registerListenSockets(cm, NULL, *port, paramsSize, params,
application, context, connectionCallback,
validate);
return UDP_registerListenSockets(cm, NULL, *port, params, application,
context, connectionCallback, validate);
}
/* Correct datatype for the hostnames? */
@ -1211,9 +1207,8 @@ UDP_openReceiveConnection(UA_ConnectionManager *cm,
if(interfaces == 0) {
UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
"UDP\t| Listening on all interfaces");
return UDP_registerListenSockets(cm, NULL, *port, paramsSize, params,
application, context, connectionCallback,
validate);
return UDP_registerListenSockets(cm, NULL, *port, params, application,
context, connectionCallback, validate);
}
UA_StatusCode rv = UA_STATUSCODE_GOOD;
@ -1225,8 +1220,8 @@ UDP_openReceiveConnection(UA_ConnectionManager *cm,
continue;
memcpy(hostname, hostStrings[i].data, hostStrings->length);
hostname[hostStrings->length] = '\0';
rv = UDP_registerListenSockets(cm, hostname, *port, paramsSize, params,
application, context, connectionCallback, validate);
rv = UDP_registerListenSockets(cm, hostname, *port, params, application,
context, connectionCallback, validate);
if(rv != UA_STATUSCODE_GOOD) {
return rv;
}
@ -1237,11 +1232,11 @@ UDP_openReceiveConnection(UA_ConnectionManager *cm,
static UA_StatusCode
UDP_openConnection(UA_ConnectionManager *cm,
size_t paramsSize, const UA_KeyValuePair *params,
const UA_KeyValueMap *params,
void *application, void *context,
UA_ConnectionManager_connectionCallback connectionCallback) {
const UA_Variant *validationValue = UA_KeyValueMap_get(params, paramsSize,
const UA_Variant *validationValue = UA_KeyValueMap_get(params,
UA_QUALIFIEDNAME(0, "validate"));
UA_Boolean validate = false;
if(validationValue) {
@ -1252,14 +1247,14 @@ UDP_openConnection(UA_ConnectionManager *cm,
/* If the "port"-parameter is defined, then try to open a send connection.
* Otherwise try to open a socket that listens for incoming TCP
* connections. */
const UA_Variant *val = UA_KeyValueMap_get(params, paramsSize,
const UA_Variant *val = UA_KeyValueMap_get(params,
UA_QUALIFIEDNAME(0, "port"));
if(val) {
return UDP_openSendConnection(cm, paramsSize, params,
application, context, connectionCallback, validate);
return UDP_openSendConnection(cm, params, application, context,
connectionCallback, validate);
} else {
return UDP_openReceiveConnection(cm, paramsSize, params,
application, context, connectionCallback, validate);
return UDP_openReceiveConnection(cm, params, application, context,
connectionCallback, validate);
}
}
@ -1279,13 +1274,14 @@ UDP_eventSourceStart(UA_ConnectionManager *cm) {
/* The receive buffersize was configured? */
UDPConnectionManager *ucm = (UDPConnectionManager*)cm;
UA_UInt32 rxBufSize = 2u << 16; /* The default is 64kb */
const UA_UInt32 *configRxBufSize = (const UA_UInt32*)
if(cm->eventSource.params != NULL) {
const UA_UInt32 *configRxBufSize = (const UA_UInt32 *)
UA_KeyValueMap_getScalar(cm->eventSource.params,
cm->eventSource.paramsSize,
UA_QUALIFIEDNAME(0, "recv-bufsize"),
&UA_TYPES[UA_TYPES_UINT32]);
if(configRxBufSize)
rxBufSize = *configRxBufSize;
}
UA_StatusCode res = UA_ByteString_allocBuffer(&ucm->rxBuffer, rxBufSize);
if(res != UA_STATUSCODE_GOOD)
return res;
@ -1325,12 +1321,10 @@ UDP_eventSourceDelete(UA_ConnectionManager *cm) {
}
/* Delete the parameters */
UA_Array_delete(cm->eventSource.params,
cm->eventSource.paramsSize,
&UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
if(cm->eventSource.params != NULL) {
UA_KeyValueMap_delete(cm->eventSource.params);
cm->eventSource.params = NULL;
cm->eventSource.paramsSize = 0;
}
UA_String_clear(&cm->eventSource.name);
UA_free(cm);
return UA_STATUSCODE_GOOD;

View File

@ -75,8 +75,7 @@ struct UA_EventLoop {
* ~~~~~~~~~~~~~~~
* The configuration should be set before the EventLoop is started */
const UA_Logger *logger;
size_t paramsSize;
UA_KeyValuePair *params; /* See the implementation-specific documentation */
UA_KeyValueMap *params; /* See the implementation-specific documentation */
/* EventLoop Lifecycle
* ~~~~~~~~~~~~~~~~~~~~ */
@ -213,8 +212,7 @@ struct UA_EventSource {
* ~~~~~~~~~~~~~ */
UA_String name; /* Unique name of the ES */
UA_EventLoop *eventLoop; /* EventLoop where the ES is registered */
size_t paramsSize; /* Configuration parameters */
UA_KeyValuePair *params;
UA_KeyValueMap *params;
/* Lifecycle
* ~~~~~~~~~ */
@ -259,7 +257,7 @@ typedef void
(*UA_ConnectionManager_connectionCallback)
(UA_ConnectionManager *cm, uintptr_t connectionId,
void *application, void **connectionContext, UA_ConnectionState state,
size_t paramsSize, const UA_KeyValuePair *params, UA_ByteString msg);
const UA_KeyValueMap *params, UA_ByteString msg);
struct UA_ConnectionManager {
/* Every ConnectionManager is treated like an EventSource from the
@ -307,7 +305,7 @@ struct UA_ConnectionManager {
* connections might be opened at once. */
UA_StatusCode
(*openConnection)(UA_ConnectionManager *cm,
size_t paramsSize, const UA_KeyValuePair *params,
const UA_KeyValueMap *params,
void *application, void *context,
UA_ConnectionManager_connectionCallback connectionCallback);
@ -322,7 +320,7 @@ struct UA_ConnectionManager {
* example a tx-time for sending in time-synchronized TSN settings. */
UA_StatusCode
(*sendWithConnection)(UA_ConnectionManager *cm, uintptr_t connectionId,
size_t paramsSize, const UA_KeyValuePair *params,
const UA_KeyValueMap *params,
UA_ByteString *buf);
/* Close a Connection
@ -369,8 +367,7 @@ struct UA_ConnectionManager {
typedef void
(*UA_InterruptCallback)(UA_InterruptManager *im,
uintptr_t interruptHandle, void *interruptContext,
size_t instanceInfosSize,
const UA_KeyValuePair *instanceInfos);
const UA_KeyValueMap *instanceInfos);
struct UA_InterruptManager {
/* Every InterruptManager is treated like an EventSource from the
@ -390,7 +387,7 @@ struct UA_InterruptManager {
* through to the callback without modification. */
UA_StatusCode
(*registerInterrupt)(UA_InterruptManager *im, uintptr_t interruptHandle,
size_t paramsSize, const UA_KeyValuePair *params,
const UA_KeyValueMap *params,
UA_InterruptCallback callback, void *interruptContext);
/* Remove a registered interrupt. Returns no error code if the interrupt is

View File

@ -40,34 +40,77 @@ typedef enum {
* Key Value Map
* -------------
* Helper functions to work with configuration parameters in an array of
* UA_KeyValuePair. Lookup is linear. So this is for small numbers of
* keys. */
* UA_KeyValuePair. Lookup is linear. So this is for small numbers of keys. The
* methods below that accept a `const UA_KeyValueMap` as an argument also accept
* NULL for that argument and treat it as an empty map. */
/* Makes a copy of the value. Can reallocate the underlying array. This
typedef struct {
size_t mapSize;
UA_KeyValuePair *map;
} UA_KeyValueMap;
UA_EXPORT extern const UA_KeyValueMap UA_KEYVALUEMAP_NULL;
UA_EXPORT UA_KeyValueMap *
UA_KeyValueMap_new(void);
UA_EXPORT void
UA_KeyValueMap_clear(UA_KeyValueMap *map);
UA_EXPORT void
UA_KeyValueMap_delete(UA_KeyValueMap *map);
/* Is the map empty (or NULL)? */
UA_EXPORT UA_Boolean
UA_KeyValueMap_isEmpty(const UA_KeyValueMap *map);
/* Does the map contain an entry for the key? */
UA_EXPORT UA_Boolean
UA_KeyValueMap_contains(const UA_KeyValueMap *map, const UA_QualifiedName key);
/* Insert a copy of the value. Can reallocate the underlying array. This
* invalidates pointers into the previous array. If the key exists already, the
* value is overwritten. */
* value is overwritten (upsert semantics). */
UA_EXPORT UA_StatusCode
UA_KeyValueMap_set(UA_KeyValuePair **map, size_t *mapSize,
UA_KeyValueMap_set(UA_KeyValueMap *map,
const UA_QualifiedName key,
const UA_Variant *value);
/* Returns a pointer to the value or NULL if the key is not found.*/
/* Helper function for scalar insertion that internally calls
* `UA_KeyValueMap_set` */
UA_EXPORT UA_StatusCode
UA_KeyValueMap_setScalar(UA_KeyValueMap *map,
const UA_QualifiedName key,
void * UA_RESTRICT p,
const UA_DataType *type);
/* Returns a pointer to the value or NULL if the key is not found */
UA_EXPORT const UA_Variant *
UA_KeyValueMap_get(const UA_KeyValuePair *map, size_t mapSize,
UA_KeyValueMap_get(const UA_KeyValueMap *map,
const UA_QualifiedName key);
/* Returns NULL if the value for the key is not defined or not of the right
* datatype and scalar/array */
/* Returns NULL if the value for the key is not defined, not of the right
* datatype or not a scalar */
UA_EXPORT const void *
UA_KeyValueMap_getScalar(const UA_KeyValuePair *map, size_t mapSize,
UA_KeyValueMap_getScalar(const UA_KeyValueMap *map,
const UA_QualifiedName key,
const UA_DataType *type);
/* Remove a single entry. To delete the entire map, use UA_Array_delete. */
/* Remove a single entry. To delete the entire map, use `UA_KeyValueMap_clear`. */
UA_EXPORT UA_StatusCode
UA_KeyValueMap_delete(UA_KeyValuePair **map, size_t *mapSize,
UA_KeyValueMap_remove(UA_KeyValueMap *map,
const UA_QualifiedName key);
/* Create a deep copy of the given KeyValueMap */
UA_EXPORT UA_StatusCode
UA_KeyValueMap_copy(const UA_KeyValueMap *src, UA_KeyValueMap *dst);
/* Copy entries from the right-hand-side into the left-hand-size. Reallocates
* previous memory in the left-hand-side. If the operation fails, both maps are
* left untouched. */
UA_EXPORT UA_StatusCode
UA_KeyValueMap_merge(UA_KeyValueMap *lhs, const UA_KeyValueMap *rhs);
/**
* Endpoint URL Parser
* -------------------

View File

@ -333,7 +333,7 @@ sendHELMessage(UA_Client *client) {
/* Send the HEL message */
message.length = messageHeader.messageSize;
retval = cm->sendWithConnection(cm, client->channel.connectionId,
0, NULL, &message);
&UA_KEYVALUEMAP_NULL, &message);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_INFO(&client->config.logger, UA_LOGCATEGORY_CLIENT, "Sending HEL failed");
closeSecureChannel(client);
@ -1065,7 +1065,7 @@ static void
UA_Client_networkCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
void *application, void **connectionContext,
UA_ConnectionState state,
size_t paramsSize, const UA_KeyValuePair *params,
const UA_KeyValueMap *params,
UA_ByteString msg) {
UA_Client *client = (UA_Client*)application;
@ -1255,8 +1255,12 @@ initConnect(UA_Client *client) {
params[1].key = UA_QUALIFIEDNAME(0, "hostname");
UA_Variant_setScalar(&params[1].value, &hostname, &UA_TYPES[UA_TYPES_STRING]);
UA_KeyValueMap paramMap;
paramMap.map = params;
paramMap.mapSize = 2;
/* Open the client TCP connection */
res = cm->openConnection(cm, 2, params, client, NULL, UA_Client_networkCallback);
res = cm->openConnection(cm, &paramMap, client, NULL, UA_Client_networkCallback);
if(res == UA_STATUSCODE_GOOD)
break;
}

View File

@ -602,9 +602,12 @@ UA_Server_createServerConnection(UA_Server *server, const UA_String *serverUrl)
UA_Variant_setArray(&params[2].value, &hostname, 1, &UA_TYPES[UA_TYPES_STRING]);
paramsSize = 3;
}
UA_KeyValueMap paramsMap;
paramsMap.map = params;
paramsMap.mapSize = paramsSize;
/* Open the server connection */
res = cm->openConnection(cm, paramsSize, params, server, NULL,
res = cm->openConnection(cm, &paramsMap, server, NULL,
UA_Server_networkCallback);
if(res == UA_STATUSCODE_GOOD)
return res;

View File

@ -382,7 +382,7 @@ processHEL(UA_Server *server, UA_SecureChannel *channel, const UA_ByteString *ms
}
ack_msg.length = ackHeader.messageSize;
retval = cm->sendWithConnection(cm, channel->connectionId, 0, NULL, &ack_msg);
retval = cm->sendWithConnection(cm, channel->connectionId, &UA_KEYVALUEMAP_NULL, &ack_msg);
if(retval == UA_STATUSCODE_GOOD)
channel->state = UA_SECURECHANNELSTATE_ACK_SENT;
return retval;
@ -893,7 +893,7 @@ void
UA_Server_networkCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
void *application, void **connectionContext,
UA_ConnectionState state,
size_t paramsSize, const UA_KeyValuePair *params,
const UA_KeyValueMap *params,
UA_ByteString msg) {
UA_Server *server = (UA_Server*)application;

View File

@ -368,7 +368,7 @@ void
UA_Server_networkCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
void *application, void **connectionContext,
UA_ConnectionState state,
size_t paramsSize, const UA_KeyValuePair *params,
const UA_KeyValueMap *params,
UA_ByteString msg);
/******************************************/

View File

@ -55,10 +55,8 @@ void UA_Session_clear(UA_Session *session, UA_Server* server) {
session->continuationPoints = NULL;
session->availableContinuationPoints = UA_MAXCONTINUATIONPOINTS;
UA_Array_delete(session->attributes, session->attributesSize,
&UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
UA_KeyValueMap_delete(session->attributes);
session->attributes = NULL;
session->attributesSize = 0;
UA_Array_delete(session->localeIds, session->localeIdsSize,
&UA_TYPES[UA_TYPES_STRING]);
@ -278,7 +276,7 @@ UA_Server_setSessionAttribute(UA_Server *server, const UA_NodeId *sessionId,
UA_Session *session = getSessionById(server, sessionId);
UA_StatusCode res = UA_STATUSCODE_BADSESSIONIDINVALID;
if(session)
res = UA_KeyValueMap_set(&session->attributes, &session->attributesSize,
res = UA_KeyValueMap_set(session->attributes,
key, value);
UA_UNLOCK(&server->serviceMutex);
return res;
@ -294,7 +292,7 @@ UA_Server_deleteSessionAttribute(UA_Server *server, const UA_NodeId *sessionId,
if(!session)
return UA_STATUSCODE_BADSESSIONIDINVALID;
UA_StatusCode res =
UA_KeyValueMap_delete(&session->attributes, &session->attributesSize, key);
UA_KeyValueMap_remove(session->attributes, key);
UA_UNLOCK(&server->serviceMutex);
return res;
}
@ -330,7 +328,7 @@ getSessionAttribute(UA_Server *server, const UA_NodeId *sessionId,
attr = &localAttr;
} else {
/* Get from the actual key-value list */
attr = UA_KeyValueMap_get(session->attributes, session->attributesSize, key);
attr = UA_KeyValueMap_get(session->attributes, key);
if(!attr)
return UA_STATUSCODE_BADNOTFOUND;
}

View File

@ -51,8 +51,7 @@ typedef struct {
UA_UInt16 availableContinuationPoints;
ContinuationPoint *continuationPoints;
size_t attributesSize;
UA_KeyValuePair *attributes;
UA_KeyValueMap *attributes;
/* Localization information */
size_t localeIdsSize;

View File

@ -120,7 +120,7 @@ UA_SecureChannel_sendError(UA_SecureChannel *channel, UA_TcpErrorMessage *error)
&bufPos, &bufEnd, NULL, NULL);
(void)retval; /* Encoding of these cannot fail */
msg.length = header.messageSize;
cm->sendWithConnection(cm, channel->connectionId, 0, NULL, &msg);
cm->sendWithConnection(cm, channel->connectionId, &UA_KEYVALUEMAP_NULL, &msg);
}
static void
@ -294,7 +294,7 @@ UA_SecureChannel_sendAsymmetricOPNMessage(UA_SecureChannel *channel,
/* Send the message, the buffer is freed in the network layer */
buf.length = encryptedLength;
return cm->sendWithConnection(cm, channel->connectionId, 0, NULL, &buf);
return cm->sendWithConnection(cm, channel->connectionId, &UA_KEYVALUEMAP_NULL, &buf);
error:
cm->freeNetworkBuffer(cm, channel->connectionId, &buf);
@ -420,7 +420,7 @@ sendSymmetricChunk(UA_MessageContext *mc) {
* wrong, the connection is removed in the next iteration of the
* SecureChannel. Set the SecureChannel to closing already. */
res = cm->sendWithConnection(cm, channel->connectionId,
0, NULL, &mc->messageBuffer);
&UA_KEYVALUEMAP_NULL, &mc->messageBuffer);
if(res != UA_STATUSCODE_GOOD && UA_SecureChannel_isConnected(channel))
channel->state = UA_SECURECHANNELSTATE_CLOSING;

View File

@ -227,15 +227,25 @@ UA_ByteString_fromBase64(UA_ByteString *bs,
/* Key Value Map */
const UA_KeyValueMap UA_KEYVALUEMAP_NULL = {0};
UA_KeyValueMap *
UA_KeyValueMap_new(void) {
return (UA_KeyValueMap*)UA_calloc(1, sizeof(UA_KeyValueMap));
}
UA_StatusCode
UA_KeyValueMap_set(UA_KeyValuePair **map, size_t *mapSize,
UA_KeyValueMap_set(UA_KeyValueMap *map,
const UA_QualifiedName key,
const UA_Variant *value) {
/* Parameter exists already */
const UA_Variant *v = UA_KeyValueMap_get(*map, *mapSize, key);
if(map == NULL || value == NULL)
return UA_STATUSCODE_BADINVALIDARGUMENT;
/* Key exists already */
const UA_Variant *v = UA_KeyValueMap_get(map, key);
if(v) {
UA_Variant copyV;
UA_StatusCode res = UA_Variant_copy(v, &copyV);
UA_StatusCode res = UA_Variant_copy(value, &copyV);
if(res != UA_STATUSCODE_GOOD)
return res;
UA_Variant *target = (UA_Variant*)(uintptr_t)v;
@ -248,60 +258,153 @@ UA_KeyValueMap_set(UA_KeyValuePair **map, size_t *mapSize,
UA_KeyValuePair pair;
pair.key = key;
pair.value = *value;
return UA_Array_appendCopy((void**)map, mapSize, &pair,
return UA_Array_appendCopy((void**)&map->map, &map->mapSize, &pair,
&UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
}
UA_StatusCode
UA_KeyValueMap_setScalar(UA_KeyValueMap *map,
const UA_QualifiedName key,
void * UA_RESTRICT p,
const UA_DataType *type) {
if(p == NULL || type == NULL)
return UA_STATUSCODE_BADINVALIDARGUMENT;
UA_Variant v;
UA_Variant_init(&v);
v.type = type;
v.arrayLength = 0;
v.data = p;
return UA_KeyValueMap_set(map, key, &v);
}
const UA_Variant *
UA_KeyValueMap_get(const UA_KeyValuePair *map, size_t mapSize,
UA_KeyValueMap_get(const UA_KeyValueMap *map,
const UA_QualifiedName key) {
for(size_t i = 0; i < mapSize; i++) {
if(map[i].key.namespaceIndex == key.namespaceIndex &&
UA_String_equal(&map[i].key.name, &key.name))
return &map[i].value;
if(!map)
return NULL;
for(size_t i = 0; i < map->mapSize; i++) {
if(map->map[i].key.namespaceIndex == key.namespaceIndex &&
UA_String_equal(&map->map[i].key.name, &key.name))
return &map->map[i].value;
}
return NULL;
}
/* Returns NULL if the parameter is not defined or not of the right datatype */
UA_Boolean
UA_KeyValueMap_isEmpty(const UA_KeyValueMap *map) {
if(!map)
return true;
return map->mapSize == 0;
}
const void *
UA_KeyValueMap_getScalar(const UA_KeyValuePair *map, size_t mapSize,
UA_KeyValueMap_getScalar(const UA_KeyValueMap *map,
const UA_QualifiedName key,
const UA_DataType *type) {
const UA_Variant *v = UA_KeyValueMap_get(map, mapSize, key);
const UA_Variant *v = UA_KeyValueMap_get(map, key);
if(!v || !UA_Variant_hasScalarType(v, type))
return NULL;
return v->data;
}
void
UA_KeyValueMap_clear(UA_KeyValueMap *map) {
if(!map)
return;
UA_Array_delete(map->map, map->mapSize, &UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
map->mapSize = 0;
}
void
UA_KeyValueMap_delete(UA_KeyValueMap *map) {
UA_KeyValueMap_clear(map);
UA_free(map);
}
UA_StatusCode
UA_KeyValueMap_delete(UA_KeyValuePair **map, size_t *mapSize,
UA_KeyValueMap_remove(UA_KeyValueMap *map,
const UA_QualifiedName key) {
UA_KeyValuePair *m = *map;
size_t s = *mapSize;
for(size_t i = 0; i < s; i++) {
if(m[i].key.namespaceIndex != key.namespaceIndex ||
!UA_String_equal(&m[i].key.name, &key.name))
continue;
if(!map)
return UA_STATUSCODE_BADINVALIDARGUMENT;
/* Clean the pair */
UA_KeyValuePair *m = map->map;
size_t s = map->mapSize;
size_t i = 0;
for(; i < s; i++) {
if(m[i].key.namespaceIndex == key.namespaceIndex &&
UA_String_equal(&m[i].key.name, &key.name))
break;
}
if(i == s)
return UA_STATUSCODE_BADNOTFOUND;
/* Clean the slot and move the last entry to fill the slot */
UA_KeyValuePair_clear(&m[i]);
/* Move the last pair to fill the empty slot */
if(s > 1 && i < s - 1) {
m[i] = m[s-1];
UA_KeyValuePair_init(&m[s-1]);
}
UA_StatusCode res = UA_Array_resize((void**)map, mapSize, *mapSize-1,
/* Ignore the result. In case resize fails, keep the longer original array
* around. Resize never fails when reducing the size to zero. Reduce the
* size integer in any case. */
UA_StatusCode res =
UA_Array_resize((void**)&map->map, &map->mapSize, map->mapSize - 1,
&UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
(void)res;
*mapSize = s - 1; /* In case resize fails, keep the longer original
* array around. Resize never fails when reducing
* the size to zero. Reduce the size integer in
* any case. */
map->mapSize--;
return UA_STATUSCODE_GOOD;
}
UA_StatusCode
UA_KeyValueMap_copy(const UA_KeyValueMap *src, UA_KeyValueMap *dst) {
if(!dst)
return UA_STATUSCODE_BADINVALIDARGUMENT;
if(!src) {
dst->map = NULL;
dst->mapSize = 0;
return UA_STATUSCODE_GOOD;
}
return UA_STATUSCODE_BADNOTFOUND;
UA_StatusCode res = UA_Array_copy(src->map, src->mapSize, (void**)&dst->map,
&UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
if(res == UA_STATUSCODE_GOOD)
dst->mapSize = src->mapSize;
return res;
}
UA_Boolean
UA_KeyValueMap_contains(const UA_KeyValueMap *map, const UA_QualifiedName key) {
if(!map)
return false;
for(size_t i = 0; i < map->mapSize; ++i) {
if(UA_QualifiedName_equal(&map->map[i].key, &key))
return true;
}
return false;
}
UA_StatusCode
UA_KeyValueMap_merge(UA_KeyValueMap *lhs, const UA_KeyValueMap *rhs) {
if(!lhs)
return UA_STATUSCODE_BADINVALIDARGUMENT;
if(!rhs)
return UA_STATUSCODE_GOOD;
UA_KeyValueMap merge;
UA_StatusCode res = UA_KeyValueMap_copy(lhs, &merge);
if(res != UA_STATUSCODE_GOOD)
return res;
for(size_t i = 0; i < rhs->mapSize; ++i) {
res = UA_KeyValueMap_set(&merge, rhs->map[i].key, &rhs->map[i].value);
if(res != UA_STATUSCODE_GOOD) {
UA_KeyValueMap_clear(&merge);
return res;
}
}
UA_KeyValueMap_clear(lhs);
*lhs = merge;
return UA_STATUSCODE_GOOD;
}

View File

@ -239,6 +239,7 @@ endif()
ua_add_test(check_types_custom.c)
ua_add_test(check_chunking.c)
ua_add_test(check_utils.c)
ua_add_test(check_kvm_utils.c)
ua_add_test(check_securechannel.c)
ua_add_test(check_timer.c)
ua_add_test(check_eventloop.c)

View File

@ -26,8 +26,7 @@ typedef struct TestContext {
static void
connectionCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
void *application, void **connectionContext,
UA_ConnectionState status,
size_t paramsSize, const UA_KeyValuePair *params,
UA_ConnectionState status, const UA_KeyValueMap *params,
UA_ByteString msg) {
TestContext *ctx = (TestContext*) *connectionContext;
if(status == UA_CONNECTIONSTATE_CLOSING) {
@ -48,10 +47,9 @@ connectionCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
clientId = connectionId;
/* The remote-hostname is set during the first callback */
if(paramsSize > 0) {
if(params->mapSize> 0) {
const void *hn =
UA_KeyValueMap_getScalar(params, paramsSize,
UA_QUALIFIEDNAME(0, "remote-hostname"),
UA_KeyValueMap_getScalar(params, UA_QUALIFIEDNAME(0, "remote-hostname"),
&UA_TYPES[UA_TYPES_STRING]);
ck_assert(hn != NULL);
}
@ -79,7 +77,7 @@ START_TEST(listenETH) {
UA_String address = UA_STRING(MULTICAST_MAC_ADDRESS);
UA_Boolean listen = true;
UA_KeyValuePair params[5];
UA_KeyValuePair params[3];
params[0].key = UA_QUALIFIEDNAME(0, "interface");
UA_Variant_setScalar(&params[0].value, &interface, &UA_TYPES[UA_TYPES_STRING]);
params[1].key = UA_QUALIFIEDNAME(0, "address");
@ -87,7 +85,8 @@ START_TEST(listenETH) {
params[2].key = UA_QUALIFIEDNAME(0, "listen");
UA_Variant_setScalar(&params[2].value, &listen, &UA_TYPES[UA_TYPES_BOOLEAN]);
UA_StatusCode res = cm->openConnection(cm, 3, params, NULL, &testContext, connectionCallback);
UA_KeyValueMap kvm = {3, params};
UA_StatusCode res = cm->openConnection(cm, &kvm, NULL, &testContext, connectionCallback);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
ck_assert(testContext.connCount == 1);
@ -138,15 +137,17 @@ START_TEST(connectETH) {
testContext.connCount = 0;
/* Don't use the address parameter for listening */
UA_KeyValueMap kvm = {3, &params[1]};
UA_StatusCode retval =
cm->openConnection(cm, 3, &params[1], NULL, &testContext, connectionCallback);
cm->openConnection(cm, &kvm, NULL, &testContext, connectionCallback);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
size_t listenSockets = testContext.connCount;
/* Open a client connection. Don't use the listen parameter.*/
kvm.map = params;
clientId = 0;
retval = cm->openConnection(cm, 3, params, NULL, &testContext, connectionCallback);
retval = cm->openConnection(cm, &kvm, NULL, &testContext, connectionCallback);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
for(size_t i = 0; i < 2; i++) {
UA_DateTime next = el->run(el, 1);
@ -161,7 +162,7 @@ START_TEST(connectETH) {
retval = cm->allocNetworkBuffer(cm, clientId, &snd, strlen(testMsg));
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
memcpy(snd.data, testMsg, strlen(testMsg));
retval = cm->sendWithConnection(cm, clientId, 0, NULL, &snd);
retval = cm->sendWithConnection(cm, clientId, NULL, &snd);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
while(!received) {

View File

@ -23,7 +23,7 @@ unsigned counter = 0;
static void
interruptCallback(UA_InterruptManager *im,
uintptr_t interruptHandle, void *interruptContext,
size_t instanceInfosSize, const UA_KeyValuePair *instanceInfos) {
const UA_KeyValueMap *instanceInfos) {
counter++;
}
@ -32,7 +32,7 @@ START_TEST(catchInterrupt) {
UA_InterruptManager *im = UA_InterruptManager_new_POSIX(UA_STRING("im1"));
el->registerEventSource(el, &im->eventSource);
im->registerInterrupt(im, TESTSIG, 0, NULL, interruptCallback, NULL);
im->registerInterrupt(im, TESTSIG, &UA_KEYVALUEMAP_NULL, interruptCallback, NULL);
el->start(el);
/* Send signal to self*/
@ -63,11 +63,11 @@ START_TEST(registerDuplicate) {
el->start(el);
UA_StatusCode res =
im->registerInterrupt(im, TESTSIG, 0, NULL, interruptCallback, NULL);
im->registerInterrupt(im, TESTSIG, &UA_KEYVALUEMAP_NULL, interruptCallback, NULL);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
/* Registering the same signal twice must fail */
res = im->registerInterrupt(im, TESTSIG, 0, NULL, interruptCallback, NULL);
res = im->registerInterrupt(im, TESTSIG, &UA_KEYVALUEMAP_NULL, interruptCallback, NULL);
ck_assert_uint_ne(res, UA_STATUSCODE_GOOD);
/* Stop the EventLoop */

View File

@ -21,7 +21,7 @@ static void
connectionCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
void *application, void **connectionContext,
UA_ConnectionState status,
size_t paramsSize, const UA_KeyValuePair *params,
const UA_KeyValueMap *params,
UA_ByteString msg) {
if(status == UA_CONNECTIONSTATE_CLOSING) {
UA_LOG_DEBUG(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
@ -65,9 +65,13 @@ START_TEST(listenTCP) {
params[0].key = UA_QUALIFIEDNAME(0, "listen-port");
params[0].value = portVar;
UA_KeyValueMap paramsMap;
paramsMap.map = params;
paramsMap.mapSize = 1;
ck_assert_uint_eq(connCount, 0);
cm->openConnection(cm, 1, params, NULL, NULL, connectionCallback);
cm->openConnection(cm, &paramsMap, NULL, NULL, connectionCallback);
ck_assert(connCount > 0);
@ -106,9 +110,13 @@ START_TEST(connectTCP) {
params[0].key = UA_QUALIFIEDNAME(0, "listen-port");
params[0].value = portVar;
UA_KeyValueMap paramsMap;
paramsMap.map = params;
paramsMap.mapSize = 1;
connCount = 0;
cm->openConnection(cm, 1, params, NULL, NULL, connectionCallback);
cm->openConnection(cm, &paramsMap, NULL, NULL, connectionCallback);
size_t listenSockets = connCount;
@ -121,8 +129,10 @@ START_TEST(connectTCP) {
params[1].key = UA_QUALIFIEDNAME(0, "hostname");
UA_Variant_setScalar(&params[1].value, &targetHost, &UA_TYPES[UA_TYPES_STRING]);
paramsMap.mapSize = 2;
UA_StatusCode retval =
cm->openConnection(cm, 2, params, NULL, (void*)0x01, connectionCallback);
cm->openConnection(cm, &paramsMap, NULL, (void*)0x01, connectionCallback);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
for(size_t i = 0; i < 2; i++) {
UA_DateTime next = el->run(el, 1);
@ -138,7 +148,7 @@ START_TEST(connectTCP) {
retval = cm->allocNetworkBuffer(cm, clientId, &snd, strlen(testMsg));
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
memcpy(snd.data, testMsg, strlen(testMsg));
retval = cm->sendWithConnection(cm, clientId, 0, NULL, &snd);
retval = cm->sendWithConnection(cm, clientId, NULL, &snd);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
for(size_t i = 0; i < 2; i++) {
UA_DateTime next = el->run(el, 1);

View File

@ -24,7 +24,7 @@ static void
connectionCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
void *application, void **connectionContext,
UA_ConnectionState status,
size_t paramsSize, const UA_KeyValuePair *params,
const UA_KeyValueMap *params,
UA_ByteString msg) {
TestContext *ctx = (TestContext*) *connectionContext;
if(status == UA_CONNECTIONSTATE_CLOSING) {
@ -45,9 +45,9 @@ connectionCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
clientId = connectionId;
/* The remote-hostname is set during the first callback */
if(paramsSize > 0) {
if(!UA_KeyValueMap_isEmpty(params)) {
const void *hn =
UA_KeyValueMap_getScalar(params, paramsSize,
UA_KeyValueMap_getScalar(params,
UA_QUALIFIEDNAME(0, "remote-hostname"),
&UA_TYPES[UA_TYPES_STRING]);
ck_assert(hn != NULL);
@ -79,8 +79,11 @@ START_TEST(listenUDP) {
UA_KeyValuePair params[1];
params[0].key = UA_QUALIFIEDNAME(0, "listen-port");
params[0].value = portVar;
UA_KeyValueMap paramsMap;
paramsMap.map = params;
paramsMap.mapSize = 1;
cm->openConnection(cm, 1, params, NULL, &testContext, connectionCallback);
cm->openConnection(cm, &paramsMap, NULL, &testContext, connectionCallback);
ck_assert(testContext.connCount > 0);
@ -133,8 +136,12 @@ START_TEST(connectUDPValidationSucceeds) {
TestContext testContext;
testContext.connCount = 0;
UA_KeyValueMap paramsMap;
paramsMap.map = params;
paramsMap.mapSize = 3;
UA_StatusCode retval =
cm->openConnection(cm, 3, params, NULL, &testContext, connectionCallback);
cm->openConnection(cm, &paramsMap, NULL, &testContext, connectionCallback);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
/* Open a client connection */
@ -148,7 +155,10 @@ START_TEST(connectUDPValidationSucceeds) {
params[2].key = UA_QUALIFIEDNAME(0, "validate");
params[2].value = validateVar;
retval = cm->openConnection(cm, 3, params, NULL, &testContext, connectionCallback);
paramsMap.map = params;
paramsMap.mapSize = 3;
retval = cm->openConnection(cm, &paramsMap, NULL, &testContext, connectionCallback);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
el->free(el);
el = NULL;
@ -182,8 +192,12 @@ START_TEST(connectUDPValidationFails) {
TestContext testContext;
testContext.connCount = 0;
UA_KeyValueMap paramsMap;
paramsMap.map = params;
paramsMap.mapSize = 3;
UA_StatusCode retval =
cm->openConnection(cm, 3, params, NULL, &testContext, connectionCallback);
cm->openConnection(cm, &paramsMap, NULL, &testContext, connectionCallback);
ck_assert_uint_eq(retval, UA_STATUSCODE_BADCONNECTIONREJECTED);
/* Open a client connection */
@ -197,7 +211,7 @@ START_TEST(connectUDPValidationFails) {
params[2].key = UA_QUALIFIEDNAME(0, "validate");
params[2].value = validateVar;
retval = cm->openConnection(cm, 3, params, NULL, &testContext, connectionCallback);
retval = cm->openConnection(cm, &paramsMap, NULL, &testContext, connectionCallback);
ck_assert_uint_eq(retval, UA_STATUSCODE_BADCONNECTIONREJECTED);
el->free(el);
el = NULL;
@ -216,12 +230,15 @@ START_TEST(connectUDP) {
UA_KeyValuePair params[2];
params[0].key = UA_QUALIFIEDNAME(0, "listen-port");
params[0].value = portVar;
UA_KeyValueMap paramsMap;
paramsMap.map = params;
paramsMap.mapSize = 1;
TestContext testContext;
testContext.connCount = 0;
UA_StatusCode retval =
cm->openConnection(cm, 1, params, NULL, &testContext, connectionCallback);
cm->openConnection(cm, &paramsMap, NULL, &testContext, connectionCallback);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
size_t listenSockets = testContext.connCount;
@ -234,7 +251,9 @@ START_TEST(connectUDP) {
params[1].key = UA_QUALIFIEDNAME(0, "hostname");
UA_Variant_setScalar(&params[1].value, &targetHost, &UA_TYPES[UA_TYPES_STRING]);
retval = cm->openConnection(cm, 2, params, NULL, &testContext, connectionCallback);
paramsMap.mapSize = 2;
retval = cm->openConnection(cm, &paramsMap, NULL, &testContext, connectionCallback);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
for(size_t i = 0; i < 2; i++) {
UA_DateTime next = el->run(el, 1);
@ -249,7 +268,7 @@ START_TEST(connectUDP) {
retval = cm->allocNetworkBuffer(cm, clientId, &snd, strlen(testMsg));
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
memcpy(snd.data, testMsg, strlen(testMsg));
retval = cm->sendWithConnection(cm, clientId, 0, NULL, &snd);
retval = cm->sendWithConnection(cm, clientId, &UA_KEYVALUEMAP_NULL, &snd);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
for(size_t i = 0; i < 2; i++) {
UA_DateTime next = el->run(el, 1);
@ -302,11 +321,15 @@ START_TEST(udpTalkerAndListener) {
params[0].key = UA_QUALIFIEDNAME(0, "listen-port");
params[0].value = portVar;
UA_KeyValueMap paramsMap;
paramsMap.map = params;
paramsMap.mapSize = 1;
TestContext testContext;
testContext.connCount = 0;
UA_StatusCode retval =
cmListener->openConnection(cmListener, 1, params, NULL, &testContext,
cmListener->openConnection(cmListener, &paramsMap, NULL, &testContext,
connectionCallback);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
@ -321,7 +344,9 @@ START_TEST(udpTalkerAndListener) {
params[1].key = UA_QUALIFIEDNAME(0, "hostname");
UA_Variant_setScalar(&params[1].value, &targetHost, &UA_TYPES[UA_TYPES_STRING]);
retval = cmTalker->openConnection(cmTalker, 2, params, NULL, &testContext,
paramsMap.mapSize = 2;
retval = cmTalker->openConnection(cmTalker, &paramsMap, NULL, &testContext,
connectionCallback);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
@ -340,7 +365,7 @@ START_TEST(udpTalkerAndListener) {
retval = cmTalker->allocNetworkBuffer(cmTalker, clientId, &snd, strlen(testMsg));
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
memcpy(snd.data, testMsg, strlen(testMsg));
retval = cmTalker->sendWithConnection(cmTalker, clientId, 0, NULL, &snd);
retval = cmTalker->sendWithConnection(cmTalker, clientId, &UA_KEYVALUEMAP_NULL, &snd);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
for(size_t i = 0; i < 2; i++) {
UA_DateTime next = elListener->run(elListener, 1);
@ -408,12 +433,15 @@ START_TEST(udpTalkerAndListenerDifferentDestination) {
UA_KeyValuePair listenParams[2];
listenParams[0].key = UA_QUALIFIEDNAME(0, "listen-port");
listenParams[0].value = portVar;
UA_KeyValueMap listenParamsMap;
listenParamsMap.map = listenParams;
listenParamsMap.mapSize = 1;
TestContext testContext;
testContext.connCount = 0;
UA_StatusCode retval =
cmListener->openConnection(cmListener, 1, listenParams, NULL, &testContext,
cmListener->openConnection(cmListener, &listenParamsMap, NULL, &testContext,
connectionCallback);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
@ -428,8 +456,11 @@ START_TEST(udpTalkerAndListenerDifferentDestination) {
connectionParams[0].value = portVar;
connectionParams[1].key = UA_QUALIFIEDNAME(0, "hostname");
UA_Variant_setScalar(&connectionParams[1].value, &connectionTargetHost, &UA_TYPES[UA_TYPES_STRING]);
UA_KeyValueMap connectionParamsMap;
connectionParamsMap.map = connectionParams;
connectionParamsMap.mapSize = 2;
retval = cmTalker->openConnection(cmTalker, 2, connectionParams, NULL, &testContext,
retval = cmTalker->openConnection(cmTalker, &connectionParamsMap, NULL, &testContext,
connectionCallback);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
@ -456,7 +487,11 @@ START_TEST(udpTalkerAndListenerDifferentDestination) {
sendParams[1].key = UA_QUALIFIEDNAME(0, "hostname");
UA_Variant_setScalar(&sendParams[1].value, &sendTargetHost, &UA_TYPES[UA_TYPES_STRING]);
retval = cmTalker->sendWithConnection(cmTalker, clientId, 2, sendParams, &snd);
UA_KeyValueMap sendParamsMap;
sendParamsMap.map = sendParams;
sendParamsMap.mapSize = 2;
retval = cmTalker->sendWithConnection(cmTalker, clientId, &sendParamsMap, &snd);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
for(size_t i = 0; i < 2; i++) {
UA_DateTime next = elListener->run(elListener, 1);

183
tests/check_kvm_utils.c Normal file
View File

@ -0,0 +1,183 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ua_util_internal.h"
#include <stdlib.h>
#include "check.h"
static UA_KeyValueMap*
keyValueMap_setup(size_t n, size_t offsetKey, size_t offsetValue) {
UA_KeyValueMap *kvm = UA_KeyValueMap_new();
for(size_t i=0; i<n; i++) {
char key[10];
snprintf(key, 10, "key%02d", (UA_UInt16) (i + offsetKey));
UA_UInt16 *value = UA_UInt16_new();
*value = (UA_UInt16) (i + offsetValue);
UA_KeyValueMap_setScalar(kvm, UA_QUALIFIEDNAME(0, key), value, &UA_TYPES[UA_TYPES_UINT16]);
UA_free(value);
}
return kvm;
}
START_TEST(CheckNullArgs) {
// UA_KeyValueMap_setScalar(&UA_KEYVALUEMAP_NULL, UA_QUALIFIEDNAME(0, "any"), 0, &UA_TYPES[UA_TYPES_UINT16]);
//UA_KeyValueMap_get(&UA_KEYVALUEMAP_NULL, UA_QUALIFIEDNAME(0, "any"));
// UA_KeyValueMap_isEmpty(&UA_KEYVALUEMAP_NULL);
UA_KeyValueMap map;
UA_StatusCode res = UA_KeyValueMap_copy(&UA_KEYVALUEMAP_NULL, &map);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
ck_assert_uint_eq(map.mapSize, UA_KEYVALUEMAP_NULL.mapSize);
ck_assert(map.map == UA_KEYVALUEMAP_NULL.map);
res = UA_KeyValueMap_copy(NULL, &map);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
res = UA_KeyValueMap_copy(&UA_KEYVALUEMAP_NULL, NULL);
ck_assert_uint_eq(res, UA_STATUSCODE_BADINVALIDARGUMENT);
res = UA_KeyValueMap_copy(NULL, NULL);
ck_assert_uint_eq(res, UA_STATUSCODE_BADINVALIDARGUMENT);
UA_KeyValueMap_clear(&map);
} END_TEST
START_TEST(CheckKVMContains) {
UA_KeyValueMap *kvm = keyValueMap_setup(10, 0, 0);
for(UA_UInt16 i=0; i<10; i++) {
char key[6] = "key00";
sprintf(&key[3], "%02d", i);
UA_Boolean doesContain = UA_KeyValueMap_contains(kvm, UA_QUALIFIEDNAME(0, key));
ck_assert(doesContain);
}
for(UA_UInt16 i=10; i<20; i++) {
char key[6] = "key10";
sprintf(&key[3], "%02d", i);
UA_Boolean doesContain = UA_KeyValueMap_contains(kvm, UA_QUALIFIEDNAME(0, key));
ck_assert(!doesContain);
}
UA_KeyValueMap_delete(kvm);
}
END_TEST
START_TEST(CheckKVMCopy) {
UA_KeyValueMap *kvm = keyValueMap_setup(10, 0, 0);
UA_KeyValueMap kvmCopy;
UA_KeyValueMap_copy(kvm, &kvmCopy);
for(size_t i = 0; i < 10; i++) {
ck_assert(UA_QualifiedName_equal(&kvm->map[i].key, &kvmCopy.map[i].key));
}
UA_KeyValueMap_delete(kvm);
UA_KeyValueMap_clear(&kvmCopy);
}
END_TEST
START_TEST(CheckKVMCountMergedIntersecting) {
UA_KeyValueMap *kvmLhs = keyValueMap_setup(10, 0, 0);
UA_KeyValueMap *kvmRhs = keyValueMap_setup(10, 5, 10);
/**
key00: 0
key01: 1
...
key09: 9
---------------------
key05: 10
key06: 11
...
key14: 19
*/
UA_KeyValueMap_merge(kvmLhs, kvmRhs);
ck_assert_uint_eq(kvmLhs->mapSize, 15);
for(size_t i = 0; i < kvmLhs->mapSize; i++) {
char key[10];
snprintf(key, 10, "key%02d", (UA_UInt16) i);
const UA_UInt16 *value = (const UA_UInt16*)
UA_KeyValueMap_getScalar(kvmLhs, UA_QUALIFIEDNAME(0, key),
&UA_TYPES[UA_TYPES_UINT16]);
if(i < 5) {
ck_assert_uint_eq(*value, i);
} else {
ck_assert_uint_eq(*value, i+5);
}
}
UA_KeyValueMap_delete(kvmLhs);
UA_KeyValueMap_delete(kvmRhs);
}
END_TEST
START_TEST(CheckKVMCountMergedCommon) {
UA_KeyValueMap *kvmLhs = keyValueMap_setup(10, 0, 0);
UA_KeyValueMap *kvmRhs = keyValueMap_setup(10, 0, 10);
UA_KeyValueMap_merge(kvmLhs, kvmRhs);
ck_assert_uint_eq(kvmLhs->mapSize, 10);
for(size_t i = 0; i < kvmLhs->mapSize; i++) {
char key[10];
snprintf(key, 10, "key%02d", (UA_UInt16) i);
const UA_UInt16 *value = (const UA_UInt16*)
UA_KeyValueMap_getScalar(kvmLhs, UA_QUALIFIEDNAME(0, key),
&UA_TYPES[UA_TYPES_UINT16]);
ck_assert_uint_eq(*value, i+10);
}
UA_KeyValueMap_delete(kvmLhs);
UA_KeyValueMap_delete(kvmRhs);
}
END_TEST
START_TEST(CheckKVMCountMergedComplementary) {
UA_KeyValueMap *kvmLhs = keyValueMap_setup(10, 0, 0);
UA_KeyValueMap *kvmRhs = keyValueMap_setup(10, 10, 10);
UA_KeyValueMap_merge(kvmLhs, kvmRhs);
ck_assert_uint_eq(kvmLhs->mapSize, 20);
for(size_t i = 0; i < kvmLhs->mapSize; i++) {
char key[10];
snprintf(key, 10, "key%02d", (UA_UInt16) i);
const UA_UInt16 *value = (const UA_UInt16*)
UA_KeyValueMap_getScalar(kvmLhs, UA_QUALIFIEDNAME(0, key),
&UA_TYPES[UA_TYPES_UINT16]);
ck_assert_uint_eq(*value, i);
}
UA_KeyValueMap_delete(kvmLhs);
UA_KeyValueMap_delete(kvmRhs);
}
END_TEST
int main(void) {
Suite *s = suite_create("Test KeyValueMap Utilities");
TCase *tc = tcase_create("test cases");
tcase_add_test(tc, CheckNullArgs);
tcase_add_test(tc, CheckKVMContains);
tcase_add_test(tc, CheckKVMCopy);
tcase_add_test(tc, CheckKVMCountMergedIntersecting);
tcase_add_test(tc, CheckKVMCountMergedComplementary);
tcase_add_test(tc, CheckKVMCountMergedCommon);
suite_add_tcase(s, tc);
SRunner *sr = srunner_create(s);
srunner_set_fork_status(sr, CK_NOFORK);
srunner_run_all (sr, CK_NORMAL);
int number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}

View File

@ -63,7 +63,7 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
void *ctx;
UA_Server_networkCallback(&testConnectionManagerTCP, 0, server,
&ctx, UA_CONNECTIONSTATE_ESTABLISHED,
0, NULL, msg);
&UA_KEYVALUEMAP_NULL, msg);
// if we got an invalid chunk, the message is not deleted, so delete it here
UA_ByteString_clear(&msg);

View File

@ -8,7 +8,7 @@ UA_ByteString *testConnectionLastSentBuf;
static UA_StatusCode
testOpenConnection(UA_ConnectionManager *cm,
size_t paramsSize, const UA_KeyValuePair *params,
const UA_KeyValueMap *params,
void *application, void *context,
UA_ConnectionManager_connectionCallback connectionCallback) {
return UA_STATUSCODE_BADNOTCONNECTED;
@ -16,7 +16,7 @@ testOpenConnection(UA_ConnectionManager *cm,
static UA_StatusCode
testSendWithConnection(UA_ConnectionManager *cm, uintptr_t connectionId,
size_t paramsSize, const UA_KeyValuePair *params,
const UA_KeyValueMap *params,
UA_ByteString *buf) {
if(testConnectionLastSentBuf) {
UA_ByteString_clear(testConnectionLastSentBuf);