From 87798df12914e1f56925e99f85186af6d8725d35 Mon Sep 17 00:00:00 2001 From: Jan Hermes Date: Thu, 27 Oct 2022 11:49:52 +0200 Subject: [PATCH] feat: add new keyvaluemap structure + utilities --- arch/eventloop_common.c | 4 +- arch/eventloop_common.h | 5 +- arch/eventloop_posix_eth.c | 78 ++++---- arch/eventloop_posix_interrupt.c | 8 +- arch/eventloop_posix_tcp.c | 72 +++---- arch/eventloop_posix_udp.c | 142 +++++++------- include/open62541/plugin/eventloop.h | 17 +- include/open62541/util.h | 67 +++++-- src/client/ua_client_connect.c | 10 +- src/server/ua_server.c | 5 +- src/server/ua_server_binary.c | 4 +- src/server/ua_server_internal.h | 2 +- src/server/ua_session.c | 10 +- src/server/ua_session.h | 3 +- src/ua_securechannel.c | 6 +- src/ua_util.c | 173 +++++++++++++---- tests/CMakeLists.txt | 1 + tests/check_eventloop_eth.c | 21 +- tests/check_eventloop_interrupt.c | 8 +- tests/check_eventloop_tcp.c | 20 +- tests/check_eventloop_udp.c | 69 +++++-- tests/check_kvm_utils.c | 183 ++++++++++++++++++ tests/fuzz/fuzz_binary_message.cc | 2 +- tests/testing-plugins/testing_networklayers.c | 4 +- 24 files changed, 641 insertions(+), 273 deletions(-) create mode 100644 tests/check_kvm_utils.c diff --git a/arch/eventloop_common.c b/arch/eventloop_common.c index a2f1b8c2b..6841f350e 100644 --- a/arch/eventloop_common.c +++ b/arch/eventloop_common.c @@ -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) { diff --git a/arch/eventloop_common.h b/arch/eventloop_common.h index 1b3bebbaa..bc3734390 100644 --- a/arch/eventloop_common.h +++ b/arch/eventloop_common.h @@ -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 diff --git a/arch/eventloop_posix_eth.c b/arch/eventloop_posix_eth.c index 2dd41e269..23d2c1238 100644 --- a/arch/eventloop_posix_eth.c +++ b/arch/eventloop_posix_eth.c @@ -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, ðerType, &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; diff --git a/arch/eventloop_posix_interrupt.c b/arch/eventloop_posix_interrupt.c index badc0e869..4af177d13 100644 --- a/arch/eventloop_posix_interrupt.c +++ b/arch/eventloop_posix_interrupt.c @@ -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"); diff --git a/arch/eventloop_posix_tcp.c b/arch/eventloop_posix_tcp.c index cd5f1824f..02e8f24f4 100644 --- a/arch/eventloop_posix_tcp.c +++ b/arch/eventloop_posix_tcp.c @@ -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(¶ms[0].value, &hostname, &UA_TYPES[UA_TYPES_STRING]); UA_Variant_setScalar(¶ms[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); + ¶mMap, 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, - UA_QUALIFIEDNAME(0, "recv-bufsize"), - &UA_TYPES[UA_TYPES_UINT32]); - if(configRxBufSize) - rxBufSize = *configRxBufSize; + + 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; } - /* 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; - + if(cm->eventSource.params != NULL) { + /* Delete the parameters */ + UA_KeyValueMap_clear(cm->eventSource.params); + } UA_String_clear(&cm->eventSource.name); UA_free(cm); return UA_STATUSCODE_GOOD; diff --git a/arch/eventloop_posix_udp.c b/arch/eventloop_posix_udp.c index 066cfa790..9a1b5278e 100644 --- a/arch/eventloop_posix_udp.c +++ b/arch/eventloop_posix_udp.c @@ -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*) - UA_KeyValueMap_getScalar(cm->eventSource.params, - cm->eventSource.paramsSize, - UA_QUALIFIEDNAME(0, "recv-bufsize"), - &UA_TYPES[UA_TYPES_UINT32]); - if(configRxBufSize) - rxBufSize = *configRxBufSize; + 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(&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]); - cm->eventSource.params = NULL; - cm->eventSource.paramsSize = 0; - + if(cm->eventSource.params != NULL) { + UA_KeyValueMap_delete(cm->eventSource.params); + cm->eventSource.params = NULL; + } UA_String_clear(&cm->eventSource.name); UA_free(cm); return UA_STATUSCODE_GOOD; diff --git a/include/open62541/plugin/eventloop.h b/include/open62541/plugin/eventloop.h index 1e9140ac4..dda5ee13c 100644 --- a/include/open62541/plugin/eventloop.h +++ b/include/open62541/plugin/eventloop.h @@ -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 diff --git a/include/open62541/util.h b/include/open62541/util.h index 1005ca4a3..774535965 100644 --- a/include/open62541/util.h +++ b/include/open62541/util.h @@ -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 * ------------------- diff --git a/src/client/ua_client_connect.c b/src/client/ua_client_connect.c index ec43433f0..b702bcb69 100644 --- a/src/client/ua_client_connect.c +++ b/src/client/ua_client_connect.c @@ -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(¶ms[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, ¶mMap, client, NULL, UA_Client_networkCallback); if(res == UA_STATUSCODE_GOOD) break; } diff --git a/src/server/ua_server.c b/src/server/ua_server.c index ba94f2020..b2df91e01 100644 --- a/src/server/ua_server.c +++ b/src/server/ua_server.c @@ -602,9 +602,12 @@ UA_Server_createServerConnection(UA_Server *server, const UA_String *serverUrl) UA_Variant_setArray(¶ms[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, ¶msMap, server, NULL, UA_Server_networkCallback); if(res == UA_STATUSCODE_GOOD) return res; diff --git a/src/server/ua_server_binary.c b/src/server/ua_server_binary.c index 9fee4a028..c79c45bf3 100644 --- a/src/server/ua_server_binary.c +++ b/src/server/ua_server_binary.c @@ -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; diff --git a/src/server/ua_server_internal.h b/src/server/ua_server_internal.h index 993cd34e8..ab85f236d 100644 --- a/src/server/ua_server_internal.h +++ b/src/server/ua_server_internal.h @@ -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); /******************************************/ diff --git a/src/server/ua_session.c b/src/server/ua_session.c index f62187e41..994507977 100644 --- a/src/server/ua_session.c +++ b/src/server/ua_session.c @@ -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; } diff --git a/src/server/ua_session.h b/src/server/ua_session.h index 246d92eef..098a76cfb 100644 --- a/src/server/ua_session.h +++ b/src/server/ua_session.h @@ -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; diff --git a/src/ua_securechannel.c b/src/ua_securechannel.c index 5469953ac..7002e2456 100644 --- a/src/ua_securechannel.c +++ b/src/ua_securechannel.c @@ -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; diff --git a/src/ua_util.c b/src/ua_util.c index 88d522db3..2e6d58367 100644 --- a/src/ua_util.c +++ b/src/ua_util.c @@ -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, ©V); + UA_StatusCode res = UA_Variant_copy(value, ©V); 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_clear(&m[i]); + 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; - /* 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]); - } + /* Clean the slot and move the last entry to fill the slot */ + UA_KeyValuePair_clear(&m[i]); + if(s > 1 && i < s - 1) { + m[i] = m[s-1]; + UA_KeyValuePair_init(&m[s-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; + map->mapSize--; + return UA_STATUSCODE_GOOD; +} - UA_StatusCode res = UA_Array_resize((void**)map, mapSize, *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. */ +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; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2f6bfd31d..65f940a93 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -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) diff --git a/tests/check_eventloop_eth.c b/tests/check_eventloop_eth.c index 8af884800..c909acc9e 100644 --- a/tests/check_eventloop_eth.c +++ b/tests/check_eventloop_eth.c @@ -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(¶ms[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(¶ms[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, ¶ms[1]}; UA_StatusCode retval = - cm->openConnection(cm, 3, ¶ms[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) { diff --git a/tests/check_eventloop_interrupt.c b/tests/check_eventloop_interrupt.c index 945cf1fbf..292d3ba02 100644 --- a/tests/check_eventloop_interrupt.c +++ b/tests/check_eventloop_interrupt.c @@ -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 */ diff --git a/tests/check_eventloop_tcp.c b/tests/check_eventloop_tcp.c index 145c27db5..1b9d47c32 100644 --- a/tests/check_eventloop_tcp.c +++ b/tests/check_eventloop_tcp.c @@ -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, ¶msMap, 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, ¶msMap, NULL, NULL, connectionCallback); size_t listenSockets = connCount; @@ -121,8 +129,10 @@ START_TEST(connectTCP) { params[1].key = UA_QUALIFIEDNAME(0, "hostname"); UA_Variant_setScalar(¶ms[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, ¶msMap, 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); diff --git a/tests/check_eventloop_udp.c b/tests/check_eventloop_udp.c index 0779ad7e4..41d1d4a01 100644 --- a/tests/check_eventloop_udp.c +++ b/tests/check_eventloop_udp.c @@ -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, ¶msMap, 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, ¶msMap, 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, ¶msMap, 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, ¶msMap, 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, ¶msMap, 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, ¶msMap, 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(¶ms[1].value, &targetHost, &UA_TYPES[UA_TYPES_STRING]); - retval = cm->openConnection(cm, 2, params, NULL, &testContext, connectionCallback); + paramsMap.mapSize = 2; + + retval = cm->openConnection(cm, ¶msMap, 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, ¶msMap, 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(¶ms[1].value, &targetHost, &UA_TYPES[UA_TYPES_STRING]); - retval = cmTalker->openConnection(cmTalker, 2, params, NULL, &testContext, + paramsMap.mapSize = 2; + + retval = cmTalker->openConnection(cmTalker, ¶msMap, 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); diff --git a/tests/check_kvm_utils.c b/tests/check_kvm_utils.c new file mode 100644 index 000000000..b4db55b32 --- /dev/null +++ b/tests/check_kvm_utils.c @@ -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 + +#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; imap[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; +} + + diff --git a/tests/fuzz/fuzz_binary_message.cc b/tests/fuzz/fuzz_binary_message.cc index 164fd1ffb..6ca54a857 100644 --- a/tests/fuzz/fuzz_binary_message.cc +++ b/tests/fuzz/fuzz_binary_message.cc @@ -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); diff --git a/tests/testing-plugins/testing_networklayers.c b/tests/testing-plugins/testing_networklayers.c index 20e589c55..fef017da1 100644 --- a/tests/testing-plugins/testing_networklayers.c +++ b/tests/testing-plugins/testing_networklayers.c @@ -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);