mirror of
https://github.com/open62541/open62541.git
synced 2025-06-03 04:00:21 +00:00
feat: add new keyvaluemap structure + utilities
This commit is contained in:
parent
ddefacf02e
commit
87798df129
@ -9,10 +9,10 @@
|
|||||||
|
|
||||||
UA_StatusCode
|
UA_StatusCode
|
||||||
UA_KeyValueRestriction_validate(const UA_KeyValueRestriction *restrictions, size_t restrictionsSize,
|
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++) {
|
for(size_t i = 0; i < restrictionsSize; i++) {
|
||||||
const UA_KeyValueRestriction *r = &restrictions[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? */
|
/* Value not present but required? */
|
||||||
if(!val) {
|
if(!val) {
|
||||||
|
@ -26,8 +26,9 @@ typedef struct {
|
|||||||
} UA_KeyValueRestriction;
|
} UA_KeyValueRestriction;
|
||||||
|
|
||||||
UA_StatusCode
|
UA_StatusCode
|
||||||
UA_KeyValueRestriction_validate(const UA_KeyValueRestriction *restrictions, size_t restrictionsSiz,
|
UA_KeyValueRestriction_validate(const UA_KeyValueRestriction *restrictions,
|
||||||
const UA_KeyValuePair *params, size_t paramsSize);
|
size_t restrictionsSiz,
|
||||||
|
const UA_KeyValueMap *map);
|
||||||
|
|
||||||
_UA_END_DECLS
|
_UA_END_DECLS
|
||||||
|
|
||||||
|
@ -280,7 +280,7 @@ ETH_close(ETHConnectionManager *ecm, UA_RegisteredFD *rfd) {
|
|||||||
erfd->connectionCallback(&ecm->cm, (uintptr_t)rfd->fd,
|
erfd->connectionCallback(&ecm->cm, (uintptr_t)rfd->fd,
|
||||||
rfd->application, &rfd->context,
|
rfd->application, &rfd->context,
|
||||||
UA_CONNECTIONSTATE_CLOSING,
|
UA_CONNECTIONSTATE_CLOSING,
|
||||||
0, NULL, UA_BYTESTRING_NULL);
|
&UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);
|
||||||
|
|
||||||
/* Close the socket */
|
/* Close the socket */
|
||||||
int ret = UA_close(rfd->fd);
|
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,
|
efd->connectionCallback(cm, (uintptr_t)rfd->fd,
|
||||||
rfd->application, &rfd->context,
|
rfd->application, &rfd->context,
|
||||||
UA_CONNECTIONSTATE_CLOSING,
|
UA_CONNECTIONSTATE_CLOSING,
|
||||||
0, NULL, UA_BYTESTRING_NULL);
|
&UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);
|
||||||
ETH_close(ecm, rfd);
|
ETH_close(ecm, rfd);
|
||||||
UA_free(rfd);
|
UA_free(rfd);
|
||||||
return;
|
return;
|
||||||
@ -360,8 +360,10 @@ ETH_connectionSocketCallback(UA_ConnectionManager *cm, UA_RegisteredFD *rfd,
|
|||||||
|
|
||||||
/* Receive has failed */
|
/* Receive has failed */
|
||||||
if(ret <= 0) {
|
if(ret <= 0) {
|
||||||
if(UA_ERRNO == UA_INTERRUPTED)
|
if(UA_ERRNO == UA_INTERRUPTED) {
|
||||||
goto finish;
|
UA_ByteString_clear(&response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Orderly shutdown of the socket. We can immediately close as no method
|
/* 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
|
* "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));
|
(unsigned)rfd->fd, errno_str));
|
||||||
ETH_close(ecm, rfd);
|
ETH_close(ecm, rfd);
|
||||||
UA_free(rfd);
|
UA_free(rfd);
|
||||||
goto finish;
|
UA_ByteString_clear(&response);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the length of the received buffer */
|
/* Set the length of the received buffer */
|
||||||
@ -391,8 +394,10 @@ ETH_connectionSocketCallback(UA_ConnectionManager *cm, UA_RegisteredFD *rfd,
|
|||||||
UA_Boolean dei = 0;
|
UA_Boolean dei = 0;
|
||||||
size_t headerSize = parseETHHeader(&response, destAddr, sourceAddr,
|
size_t headerSize = parseETHHeader(&response, destAddr, sourceAddr,
|
||||||
ðerType, &vid, &pcp, &dei);
|
ðerType, &vid, &pcp, &dei);
|
||||||
if(headerSize == 0)
|
if(headerSize == 0) {
|
||||||
goto finish;
|
UA_ByteString_clear(&response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set up the parameter arguments */
|
/* Set up the parameter arguments */
|
||||||
unsigned char destAddrBytes[18];
|
unsigned char destAddrBytes[18];
|
||||||
@ -423,21 +428,21 @@ ETH_connectionSocketCallback(UA_ConnectionManager *cm, UA_RegisteredFD *rfd,
|
|||||||
paramsSize += 3;
|
paramsSize += 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UA_KeyValueMap map = {paramsSize, params};
|
||||||
|
|
||||||
/* Callback to the application layer with the Ethernet header hidden */
|
/* Callback to the application layer with the Ethernet header hidden */
|
||||||
response.data += headerSize;
|
response.data += headerSize;
|
||||||
response.length -= headerSize;
|
response.length -= headerSize;
|
||||||
efd->connectionCallback(cm, (uintptr_t)rfd->fd, rfd->application, &rfd->context,
|
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.data -= headerSize;
|
||||||
response.length += headerSize;
|
response.length += headerSize;
|
||||||
|
|
||||||
finish:
|
|
||||||
UA_ByteString_clear(&response);
|
UA_ByteString_clear(&response);
|
||||||
}
|
}
|
||||||
|
|
||||||
static UA_StatusCode
|
static UA_StatusCode
|
||||||
ETH_openListenConnection(UA_EventLoop *el, ETH_FD *fd,
|
ETH_openListenConnection(UA_EventLoop *el, ETH_FD *fd,
|
||||||
size_t paramsSize, const UA_KeyValuePair *params,
|
const UA_KeyValueMap *params,
|
||||||
int ifindex, UA_UInt16 etherType) {
|
int ifindex, UA_UInt16 etherType) {
|
||||||
/* Bind the socket to interface and EtherType. Don't receive anything else. */
|
/* Bind the socket to interface and EtherType. Don't receive anything else. */
|
||||||
struct sockaddr_ll sll = {0};
|
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) */
|
/* Set receiving to promiscuous (all target host addresses) */
|
||||||
const UA_Boolean *promiscuous = (const UA_Boolean*)
|
const UA_Boolean *promiscuous = (const UA_Boolean*)
|
||||||
UA_KeyValueMap_getScalar(params, paramsSize,
|
UA_KeyValueMap_getScalar(params, ETHConfigParameters[ETH_PARAMINDEX_PROMISCUOUS].name,
|
||||||
ETHConfigParameters[ETH_PARAMINDEX_PROMISCUOUS].name,
|
|
||||||
&UA_TYPES[UA_TYPES_BOOLEAN]);
|
&UA_TYPES[UA_TYPES_BOOLEAN]);
|
||||||
if(promiscuous && *promiscuous) {
|
if(promiscuous && *promiscuous) {
|
||||||
struct packet_mreq mreq = {0};
|
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 */
|
/* Register for multicast if an address is defined */
|
||||||
const UA_String *address = (const UA_String*)
|
const UA_String *address = (const UA_String*)
|
||||||
UA_KeyValueMap_getScalar(params, paramsSize,
|
UA_KeyValueMap_getScalar(params, ETHConfigParameters[ETH_PARAMINDEX_ADDR].name,
|
||||||
ETHConfigParameters[ETH_PARAMINDEX_ADDR].name,
|
|
||||||
&UA_TYPES[UA_TYPES_STRING]);
|
&UA_TYPES[UA_TYPES_STRING]);
|
||||||
if(address) {
|
if(address) {
|
||||||
UA_Byte addr[ETHER_ADDR_LEN];
|
UA_Byte addr[ETHER_ADDR_LEN];
|
||||||
@ -513,12 +516,11 @@ ETH_openListenConnection(UA_EventLoop *el, ETH_FD *fd,
|
|||||||
|
|
||||||
static UA_StatusCode
|
static UA_StatusCode
|
||||||
ETH_openSendConnection(UA_EventLoop *el, ETH_FD *fd,
|
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) {
|
UA_Byte source[ETHER_ADDR_LEN], int ifindex, UA_UInt16 etherType) {
|
||||||
/* Parse the target address (has to exist) */
|
/* Parse the target address (has to exist) */
|
||||||
const UA_String *address = (const UA_String*)
|
const UA_String *address = (const UA_String*)
|
||||||
UA_KeyValueMap_getScalar(params, paramsSize,
|
UA_KeyValueMap_getScalar(params, ETHConfigParameters[ETH_PARAMINDEX_ADDR].name,
|
||||||
ETHConfigParameters[ETH_PARAMINDEX_ADDR].name,
|
|
||||||
&UA_TYPES[UA_TYPES_STRING]);
|
&UA_TYPES[UA_TYPES_STRING]);
|
||||||
UA_Byte dest[ETHER_ADDR_LEN];
|
UA_Byte dest[ETHER_ADDR_LEN];
|
||||||
UA_StatusCode res = parseEthAddress(address, dest);
|
UA_StatusCode res = parseEthAddress(address, dest);
|
||||||
@ -535,22 +537,19 @@ ETH_openSendConnection(UA_EventLoop *el, ETH_FD *fd,
|
|||||||
UA_Boolean eid = false;
|
UA_Boolean eid = false;
|
||||||
|
|
||||||
const UA_UInt16 *vidp = (const UA_UInt16*)
|
const UA_UInt16 *vidp = (const UA_UInt16*)
|
||||||
UA_KeyValueMap_getScalar(params, paramsSize,
|
UA_KeyValueMap_getScalar(params, ETHConfigParameters[ETH_PARAMINDEX_VID].name,
|
||||||
ETHConfigParameters[ETH_PARAMINDEX_VID].name,
|
|
||||||
&UA_TYPES[UA_TYPES_UINT16]);
|
&UA_TYPES[UA_TYPES_UINT16]);
|
||||||
if(vidp)
|
if(vidp)
|
||||||
vid = *vidp;
|
vid = *vidp;
|
||||||
|
|
||||||
const UA_Byte *pcpp = (const UA_Byte*)
|
const UA_Byte *pcpp = (const UA_Byte*)
|
||||||
UA_KeyValueMap_getScalar(params, paramsSize,
|
UA_KeyValueMap_getScalar(params, ETHConfigParameters[ETH_PARAMINDEX_PCP].name,
|
||||||
ETHConfigParameters[ETH_PARAMINDEX_PCP].name,
|
|
||||||
&UA_TYPES[UA_TYPES_BYTE]);
|
&UA_TYPES[UA_TYPES_BYTE]);
|
||||||
if(pcpp)
|
if(pcpp)
|
||||||
pcp = *pcpp;
|
pcp = *pcpp;
|
||||||
|
|
||||||
const UA_Boolean *eidp = (const UA_Boolean*)
|
const UA_Boolean *eidp = (const UA_Boolean*)
|
||||||
UA_KeyValueMap_getScalar(params, paramsSize,
|
UA_KeyValueMap_getScalar(params, ETHConfigParameters[ETH_PARAMINDEX_DEI].name,
|
||||||
ETHConfigParameters[ETH_PARAMINDEX_DEI].name,
|
|
||||||
&UA_TYPES[UA_TYPES_BOOLEAN]);
|
&UA_TYPES[UA_TYPES_BOOLEAN]);
|
||||||
if(eidp)
|
if(eidp)
|
||||||
eid = *eidp;
|
eid = *eidp;
|
||||||
@ -567,7 +566,7 @@ ETH_openSendConnection(UA_EventLoop *el, ETH_FD *fd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static UA_StatusCode
|
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,
|
void *application, void *context,
|
||||||
UA_ConnectionManager_connectionCallback connectionCallback) {
|
UA_ConnectionManager_connectionCallback connectionCallback) {
|
||||||
ETHConnectionManager *ecm = (ETHConnectionManager*)cm;
|
ETHConnectionManager *ecm = (ETHConnectionManager*)cm;
|
||||||
@ -575,8 +574,7 @@ ETH_openConnection(UA_ConnectionManager *cm, size_t paramsSize, const UA_KeyValu
|
|||||||
|
|
||||||
/* Listen or send connection? */
|
/* Listen or send connection? */
|
||||||
const UA_Boolean *listen = (const UA_Boolean*)
|
const UA_Boolean *listen = (const UA_Boolean*)
|
||||||
UA_KeyValueMap_getScalar(params, paramsSize,
|
UA_KeyValueMap_getScalar(params, ETHConfigParameters[ETH_PARAMINDEX_LISTEN].name,
|
||||||
ETHConfigParameters[ETH_PARAMINDEX_LISTEN].name,
|
|
||||||
&UA_TYPES[UA_TYPES_BOOLEAN]);
|
&UA_TYPES[UA_TYPES_BOOLEAN]);
|
||||||
size_t ethParams = ETH_PARAMETERSSIZE;
|
size_t ethParams = ETH_PARAMETERSSIZE;
|
||||||
if(!listen || !*listen)
|
if(!listen || !*listen)
|
||||||
@ -584,24 +582,21 @@ ETH_openConnection(UA_ConnectionManager *cm, size_t paramsSize, const UA_KeyValu
|
|||||||
|
|
||||||
/* Validate the parameters */
|
/* Validate the parameters */
|
||||||
UA_StatusCode res =
|
UA_StatusCode res =
|
||||||
UA_KeyValueRestriction_validate(ETHConfigParameters, ETH_PARAMETERSSIZE,
|
UA_KeyValueRestriction_validate(ETHConfigParameters, ETH_PARAMETERSSIZE, params);
|
||||||
params, paramsSize);
|
|
||||||
if(res != UA_STATUSCODE_GOOD)
|
if(res != UA_STATUSCODE_GOOD)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
/* Get the EtherType parameter */
|
/* Get the EtherType parameter */
|
||||||
UA_UInt16 etherType = ETH_P_ALL;
|
UA_UInt16 etherType = ETH_P_ALL;
|
||||||
const UA_UInt16 *etParam = (const UA_UInt16*)
|
const UA_UInt16 *etParam = (const UA_UInt16*)
|
||||||
UA_KeyValueMap_getScalar(params, paramsSize,
|
UA_KeyValueMap_getScalar(params, ETHConfigParameters[ETH_PARAMINDEX_ETHERTYPE].name,
|
||||||
ETHConfigParameters[ETH_PARAMINDEX_ETHERTYPE].name,
|
|
||||||
&UA_TYPES[UA_TYPES_UINT16]);
|
&UA_TYPES[UA_TYPES_UINT16]);
|
||||||
if(etParam)
|
if(etParam)
|
||||||
etherType = *etParam;
|
etherType = *etParam;
|
||||||
|
|
||||||
/* Get the interface index */
|
/* Get the interface index */
|
||||||
const UA_String *interface = (const UA_String*)
|
const UA_String *interface = (const UA_String*)
|
||||||
UA_KeyValueMap_getScalar(params, paramsSize,
|
UA_KeyValueMap_getScalar(params, ETHConfigParameters[ETH_PARAMINDEX_IFACE].name,
|
||||||
ETHConfigParameters[ETH_PARAMINDEX_IFACE].name,
|
|
||||||
&UA_TYPES[UA_TYPES_STRING]);
|
&UA_TYPES[UA_TYPES_STRING]);
|
||||||
if(interface->length >= 128)
|
if(interface->length >= 128)
|
||||||
return UA_STATUSCODE_BADINTERNALERROR;
|
return UA_STATUSCODE_BADINTERNALERROR;
|
||||||
@ -660,11 +655,11 @@ ETH_openConnection(UA_ConnectionManager *cm, size_t paramsSize, const UA_KeyValu
|
|||||||
res = UA_STATUSCODE_BADCONNECTIONREJECTED;
|
res = UA_STATUSCODE_BADCONNECTIONREJECTED;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
res = ETH_openSendConnection(el, fd, paramsSize, params,
|
res = ETH_openSendConnection(el, fd, params,
|
||||||
(unsigned char*)ifr.ifr_hwaddr.sa_data,
|
(unsigned char*)ifr.ifr_hwaddr.sa_data,
|
||||||
ifindex, etherType);
|
ifindex, etherType);
|
||||||
} else {
|
} else {
|
||||||
res = ETH_openListenConnection(el, fd, paramsSize, params, ifindex, etherType);
|
res = ETH_openListenConnection(el, fd, params, ifindex, etherType);
|
||||||
}
|
}
|
||||||
if(res != UA_STATUSCODE_GOOD)
|
if(res != UA_STATUSCODE_GOOD)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -675,7 +670,8 @@ ETH_openConnection(UA_ConnectionManager *cm, size_t paramsSize, const UA_KeyValu
|
|||||||
|
|
||||||
/* Register the listen socket in the application */
|
/* Register the listen socket in the application */
|
||||||
connectionCallback(cm, (uintptr_t)sockfd, application, &fd->fd.context,
|
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;
|
return UA_STATUSCODE_GOOD;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
@ -723,8 +719,7 @@ ETH_shutdownConnection(UA_ConnectionManager *cm, uintptr_t connectionId) {
|
|||||||
|
|
||||||
static UA_StatusCode
|
static UA_StatusCode
|
||||||
ETH_sendWithConnection(UA_ConnectionManager *cm, uintptr_t connectionId,
|
ETH_sendWithConnection(UA_ConnectionManager *cm, uintptr_t connectionId,
|
||||||
size_t paramsSize, const UA_KeyValuePair *params,
|
const UA_KeyValueMap *params, UA_ByteString *buf) {
|
||||||
UA_ByteString *buf) {
|
|
||||||
ETHConnectionManager *ecm = (ETHConnectionManager*)cm;
|
ETHConnectionManager *ecm = (ETHConnectionManager*)cm;
|
||||||
UA_EventLoop *el = cm->eventSource.eventLoop;
|
UA_EventLoop *el = cm->eventSource.eventLoop;
|
||||||
UA_RegisteredFD *rfd = ETHConnectionManager_findRegisteredFD(ecm, connectionId);
|
UA_RegisteredFD *rfd = ETHConnectionManager_findRegisteredFD(ecm, connectionId);
|
||||||
@ -843,12 +838,7 @@ ETH_eventSourceDelete(UA_ConnectionManager *cm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Delete the parameters */
|
/* Delete the parameters */
|
||||||
UA_Array_delete(cm->eventSource.params,
|
UA_KeyValueMap_clear(cm->eventSource.params);
|
||||||
cm->eventSource.paramsSize,
|
|
||||||
&UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
|
|
||||||
cm->eventSource.params = NULL;
|
|
||||||
cm->eventSource.paramsSize = 0;
|
|
||||||
|
|
||||||
UA_String_clear(&cm->eventSource.name);
|
UA_String_clear(&cm->eventSource.name);
|
||||||
UA_free(cm);
|
UA_free(cm);
|
||||||
return UA_STATUSCODE_GOOD;
|
return UA_STATUSCODE_GOOD;
|
||||||
|
@ -67,7 +67,7 @@ handlePOSIXInterruptEvent(UA_EventSource *es, UA_RegisteredFD *rfd, short event)
|
|||||||
(unsigned)rfd->fd, fdsi.ssi_signo);
|
(unsigned)rfd->fd, fdsi.ssi_signo);
|
||||||
|
|
||||||
rs->signalCallback((UA_InterruptManager *)es,
|
rs->signalCallback((UA_InterruptManager *)es,
|
||||||
(uintptr_t)rfd->fd, rfd->context, 0, NULL);
|
(uintptr_t)rfd->fd, rfd->context, &UA_KEYVALUEMAP_NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -240,7 +240,7 @@ executeTriggeredPOSIXInterrupts(UA_EventSource *es, UA_RegisteredFD *rfd, short
|
|||||||
TAILQ_REMOVE(&singletonIM->triggered, rs, triggeredEntry);
|
TAILQ_REMOVE(&singletonIM->triggered, rs, triggeredEntry);
|
||||||
rs->triggered = false;
|
rs->triggered = false;
|
||||||
rs->signalCallback(&singletonIM->im, (uintptr_t)rs->signal,
|
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
|
static UA_StatusCode
|
||||||
registerPOSIXInterrupt(UA_InterruptManager *im, uintptr_t interruptHandle,
|
registerPOSIXInterrupt(UA_InterruptManager *im, uintptr_t interruptHandle,
|
||||||
size_t paramsSize, const UA_KeyValuePair *params,
|
const UA_KeyValueMap *params,
|
||||||
UA_InterruptCallback callback, void *interruptContext) {
|
UA_InterruptCallback callback, void *interruptContext) {
|
||||||
UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)im->eventSource.eventLoop;
|
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,
|
UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
|
||||||
"Interrupt\t| Supplied parameters invalid for the "
|
"Interrupt\t| Supplied parameters invalid for the "
|
||||||
"POSIX InterruptManager");
|
"POSIX InterruptManager");
|
||||||
|
@ -94,7 +94,7 @@ TCP_close(TCPConnectionManager *tcm, UA_RegisteredFD *rfd) {
|
|||||||
tcpfd->connectionCallback(&tcm->cm, (uintptr_t)rfd->fd,
|
tcpfd->connectionCallback(&tcm->cm, (uintptr_t)rfd->fd,
|
||||||
rfd->application, &rfd->context,
|
rfd->application, &rfd->context,
|
||||||
UA_CONNECTIONSTATE_CLOSING,
|
UA_CONNECTIONSTATE_CLOSING,
|
||||||
0, NULL, UA_BYTESTRING_NULL);
|
&UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);
|
||||||
|
|
||||||
/* Close the socket */
|
/* Close the socket */
|
||||||
int ret = UA_close(rfd->fd);
|
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. */
|
/* A new socket has opened. Signal it to the application. */
|
||||||
tcpfd->connectionCallback(cm, (uintptr_t)rfd->fd,
|
tcpfd->connectionCallback(cm, (uintptr_t)rfd->fd,
|
||||||
rfd->application, &rfd->context,
|
rfd->application, &rfd->context,
|
||||||
UA_CONNECTIONSTATE_ESTABLISHED, 0, NULL,
|
UA_CONNECTIONSTATE_ESTABLISHED, &UA_KEYVALUEMAP_NULL,
|
||||||
UA_BYTESTRING_NULL);
|
UA_BYTESTRING_NULL);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -229,7 +229,7 @@ TCP_connectionSocketCallback(UA_ConnectionManager *cm, UA_RegisteredFD *rfd,
|
|||||||
tcpfd->connectionCallback(cm, (uintptr_t)rfd->fd,
|
tcpfd->connectionCallback(cm, (uintptr_t)rfd->fd,
|
||||||
rfd->application, &rfd->context,
|
rfd->application, &rfd->context,
|
||||||
UA_CONNECTIONSTATE_ESTABLISHED,
|
UA_CONNECTIONSTATE_ESTABLISHED,
|
||||||
0, NULL, response);
|
&UA_KEYVALUEMAP_NULL, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Gets called when a new connection opens or if the listenSocket is closed */
|
/* 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_String hostName = UA_STRING(hoststr);
|
||||||
UA_Variant_setScalar(&kvp.value, &hostName, &UA_TYPES[UA_TYPES_STRING]);
|
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. */
|
/* The socket has opened. Signal it to the application. */
|
||||||
tcpfd->connectionCallback(cm, (uintptr_t)newsockfd,
|
tcpfd->connectionCallback(cm, (uintptr_t)newsockfd,
|
||||||
newtcpfd->fd.application, &newtcpfd->fd.context,
|
newtcpfd->fd.application, &newtcpfd->fd.context,
|
||||||
UA_CONNECTIONSTATE_ESTABLISHED,
|
UA_CONNECTIONSTATE_ESTABLISHED,
|
||||||
1, &kvp, UA_BYTESTRING_NULL);
|
&kvm, UA_BYTESTRING_NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static UA_StatusCode
|
static UA_StatusCode
|
||||||
@ -467,20 +471,22 @@ TCP_registerListenSocket(UA_ConnectionManager *cm, struct addrinfo *ai,
|
|||||||
UA_KeyValuePair params[2];
|
UA_KeyValuePair params[2];
|
||||||
params[0].key = UA_QUALIFIEDNAME(0, "listen-hostname");
|
params[0].key = UA_QUALIFIEDNAME(0, "listen-hostname");
|
||||||
params[1].key = UA_QUALIFIEDNAME(0, "listen-port");
|
params[1].key = UA_QUALIFIEDNAME(0, "listen-port");
|
||||||
|
UA_KeyValueMap paramMap;
|
||||||
|
paramMap.mapSize = 0;
|
||||||
UA_String hostname;
|
UA_String hostname;
|
||||||
size_t paramsSize = 0;
|
|
||||||
if(hoststr[0] != 0) {
|
if(hoststr[0] != 0) {
|
||||||
paramsSize = 2;
|
paramMap.mapSize = 2;
|
||||||
hostname = UA_STRING(hoststr);
|
hostname = UA_STRING(hoststr);
|
||||||
UA_Variant_setScalar(¶ms[0].value, &hostname, &UA_TYPES[UA_TYPES_STRING]);
|
UA_Variant_setScalar(¶ms[0].value, &hostname, &UA_TYPES[UA_TYPES_STRING]);
|
||||||
UA_Variant_setScalar(¶ms[1].value, &port, &UA_TYPES[UA_TYPES_UINT16]);
|
UA_Variant_setScalar(¶ms[1].value, &port, &UA_TYPES[UA_TYPES_UINT16]);
|
||||||
|
paramMap.map = params;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Announce the listen-socket in the application */
|
/* Announce the listen-socket in the application */
|
||||||
connectionCallback(cm, (uintptr_t)listenSocket, application,
|
connectionCallback(cm, (uintptr_t)listenSocket, application,
|
||||||
&newtcpfd->fd.context,
|
&newtcpfd->fd.context,
|
||||||
UA_CONNECTIONSTATE_ESTABLISHED,
|
UA_CONNECTIONSTATE_ESTABLISHED,
|
||||||
paramsSize, params, UA_BYTESTRING_NULL);
|
¶mMap, UA_BYTESTRING_NULL);
|
||||||
|
|
||||||
return UA_STATUSCODE_GOOD;
|
return UA_STATUSCODE_GOOD;
|
||||||
}
|
}
|
||||||
@ -599,7 +605,7 @@ TCP_shutdownConnection(UA_ConnectionManager *cm, uintptr_t connectionId) {
|
|||||||
|
|
||||||
static UA_StatusCode
|
static UA_StatusCode
|
||||||
TCP_sendWithConnection(UA_ConnectionManager *cm, uintptr_t connectionId,
|
TCP_sendWithConnection(UA_ConnectionManager *cm, uintptr_t connectionId,
|
||||||
size_t paramsSize, const UA_KeyValuePair *params,
|
const UA_KeyValueMap *params,
|
||||||
UA_ByteString *buf) {
|
UA_ByteString *buf) {
|
||||||
/* Prevent OS signals when sending to a closed socket */
|
/* Prevent OS signals when sending to a closed socket */
|
||||||
int flags = MSG_NOSIGNAL;
|
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 */
|
/* Create a listen-socket that waits for incoming connections */
|
||||||
static UA_StatusCode
|
static UA_StatusCode
|
||||||
TCP_openPassiveConnection(UA_ConnectionManager *cm,
|
TCP_openPassiveConnection(UA_ConnectionManager *cm,
|
||||||
size_t paramsSize, const UA_KeyValuePair *params,
|
const UA_KeyValueMap *params,
|
||||||
void *application, void *context,
|
void *application, void *context,
|
||||||
UA_ConnectionManager_connectionCallback connectionCallback) {
|
UA_ConnectionManager_connectionCallback connectionCallback) {
|
||||||
UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
|
UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
|
||||||
|
|
||||||
/* Get the port parameter */
|
/* Get the port parameter */
|
||||||
const UA_UInt16 *port = (const UA_UInt16*)
|
const UA_UInt16 *port = (const UA_UInt16*)
|
||||||
UA_KeyValueMap_getScalar(params, paramsSize,
|
UA_KeyValueMap_getScalar(params,
|
||||||
UA_QUALIFIEDNAME(0, "listen-port"),
|
UA_QUALIFIEDNAME(0, "listen-port"),
|
||||||
&UA_TYPES[UA_TYPES_UINT16]);
|
&UA_TYPES[UA_TYPES_UINT16]);
|
||||||
if(!port) {
|
if(!port) {
|
||||||
@ -673,7 +679,7 @@ TCP_openPassiveConnection(UA_ConnectionManager *cm,
|
|||||||
|
|
||||||
/* Get the hostnames parameter */
|
/* Get the hostnames parameter */
|
||||||
const UA_Variant *hostNames =
|
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) {
|
if(!hostNames) {
|
||||||
/* No listen-hostnames parameter -> listen on all interfaces */
|
/* No listen-hostnames parameter -> listen on all interfaces */
|
||||||
UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
|
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 */
|
/* Open a TCP connection to a remote host */
|
||||||
static UA_StatusCode
|
static UA_StatusCode
|
||||||
TCP_openActiveConnection(UA_ConnectionManager *cm,
|
TCP_openActiveConnection(UA_ConnectionManager *cm,
|
||||||
size_t paramsSize, const UA_KeyValuePair *params,
|
const UA_KeyValueMap *params,
|
||||||
void *application, void *context,
|
void *application, void *context,
|
||||||
UA_ConnectionManager_connectionCallback connectionCallback) {
|
UA_ConnectionManager_connectionCallback connectionCallback) {
|
||||||
TCPConnectionManager *tcm = (TCPConnectionManager*)cm;
|
TCPConnectionManager *tcm = (TCPConnectionManager*)cm;
|
||||||
UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
|
UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
|
||||||
|
|
||||||
if(paramsSize != 2) {
|
if(params->mapSize != 2) {
|
||||||
UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
|
UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
|
||||||
"TCP\t| Port and hostname need to be defined for the connection");
|
"TCP\t| Port and hostname need to be defined for the connection");
|
||||||
return UA_STATUSCODE_BADINTERNALERROR;
|
return UA_STATUSCODE_BADINTERNALERROR;
|
||||||
@ -735,7 +741,7 @@ TCP_openActiveConnection(UA_ConnectionManager *cm,
|
|||||||
|
|
||||||
/* Prepare the port parameter as a string */
|
/* Prepare the port parameter as a string */
|
||||||
const UA_UInt16 *port = (const UA_UInt16*)
|
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]);
|
&UA_TYPES[UA_TYPES_UINT16]);
|
||||||
if(!port) {
|
if(!port) {
|
||||||
UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
|
UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
|
||||||
@ -746,7 +752,7 @@ TCP_openActiveConnection(UA_ConnectionManager *cm,
|
|||||||
|
|
||||||
/* Prepare the hostname string */
|
/* Prepare the hostname string */
|
||||||
const UA_String *host = (const UA_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]);
|
&UA_TYPES[UA_TYPES_STRING]);
|
||||||
if(!host) {
|
if(!host) {
|
||||||
UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
|
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 */
|
/* Signal the new connection to the application as asynchonously opening */
|
||||||
connectionCallback(cm, (uintptr_t)newSock,
|
connectionCallback(cm, (uintptr_t)newSock,
|
||||||
application, &newtcpfd->fd.context,
|
application, &newtcpfd->fd.context,
|
||||||
UA_CONNECTIONSTATE_OPENING, 0, NULL,
|
UA_CONNECTIONSTATE_OPENING, &UA_KEYVALUEMAP_NULL,
|
||||||
UA_BYTESTRING_NULL);
|
UA_BYTESTRING_NULL);
|
||||||
|
|
||||||
return UA_STATUSCODE_GOOD;
|
return UA_STATUSCODE_GOOD;
|
||||||
@ -867,7 +873,7 @@ TCP_openActiveConnection(UA_ConnectionManager *cm,
|
|||||||
|
|
||||||
static UA_StatusCode
|
static UA_StatusCode
|
||||||
TCP_openConnection(UA_ConnectionManager *cm,
|
TCP_openConnection(UA_ConnectionManager *cm,
|
||||||
size_t paramsSize, const UA_KeyValuePair *params,
|
const UA_KeyValueMap *params,
|
||||||
void *application, void *context,
|
void *application, void *context,
|
||||||
UA_ConnectionManager_connectionCallback connectionCallback) {
|
UA_ConnectionManager_connectionCallback connectionCallback) {
|
||||||
UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
|
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
|
* connection. Otherwise try to open a socket that listens for incoming TCP
|
||||||
* connections. */
|
* connections. */
|
||||||
const UA_Variant *val =
|
const UA_Variant *val =
|
||||||
UA_KeyValueMap_get(params, paramsSize, UA_QUALIFIEDNAME(0, "port"));
|
UA_KeyValueMap_get(params, UA_QUALIFIEDNAME(0, "port"));
|
||||||
if(val) {
|
if(val) {
|
||||||
return TCP_openActiveConnection(cm, paramsSize, params,
|
return TCP_openActiveConnection(cm, params,
|
||||||
application, context, connectionCallback);
|
application, context, connectionCallback);
|
||||||
} else {
|
} else {
|
||||||
return TCP_openPassiveConnection(cm, paramsSize, params,
|
return TCP_openPassiveConnection(cm, params,
|
||||||
application, context, connectionCallback);
|
application, context, connectionCallback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -904,15 +910,17 @@ TCP_eventSourceStart(UA_ConnectionManager *cm) {
|
|||||||
"registered in an EventLoop and not started yet");
|
"registered in an EventLoop and not started yet");
|
||||||
return UA_STATUSCODE_BADINTERNALERROR;
|
return UA_STATUSCODE_BADINTERNALERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Configure the receive buffer */
|
/* Configure the receive buffer */
|
||||||
UA_UInt32 rxBufSize = 2u << 16; /* The default is 64kb */
|
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) {
|
||||||
UA_QUALIFIEDNAME(0, "recv-bufsize"),
|
const UA_UInt32 *configRxBufSize = (const UA_UInt32 *)
|
||||||
&UA_TYPES[UA_TYPES_UINT32]);
|
UA_KeyValueMap_getScalar(cm->eventSource.params,
|
||||||
if(configRxBufSize)
|
UA_QUALIFIEDNAME(0, "recv-bufsize"),
|
||||||
rxBufSize = *configRxBufSize;
|
&UA_TYPES[UA_TYPES_UINT32]);
|
||||||
|
if(configRxBufSize)
|
||||||
|
rxBufSize = *configRxBufSize;
|
||||||
|
}
|
||||||
UA_StatusCode res = UA_ByteString_allocBuffer(&tcm->rxBuffer, rxBufSize);
|
UA_StatusCode res = UA_ByteString_allocBuffer(&tcm->rxBuffer, rxBufSize);
|
||||||
if(res != UA_STATUSCODE_GOOD)
|
if(res != UA_STATUSCODE_GOOD)
|
||||||
return res;
|
return res;
|
||||||
@ -950,12 +958,10 @@ TCP_eventSourceDelete(UA_ConnectionManager *cm) {
|
|||||||
return UA_STATUSCODE_BADINTERNALERROR;
|
return UA_STATUSCODE_BADINTERNALERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Delete the parameters */
|
if(cm->eventSource.params != NULL) {
|
||||||
UA_Array_delete(cm->eventSource.params, cm->eventSource.paramsSize,
|
/* Delete the parameters */
|
||||||
&UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
|
UA_KeyValueMap_clear(cm->eventSource.params);
|
||||||
cm->eventSource.params = NULL;
|
}
|
||||||
cm->eventSource.paramsSize = 0;
|
|
||||||
|
|
||||||
UA_String_clear(&cm->eventSource.name);
|
UA_String_clear(&cm->eventSource.name);
|
||||||
UA_free(cm);
|
UA_free(cm);
|
||||||
return UA_STATUSCODE_GOOD;
|
return UA_STATUSCODE_GOOD;
|
||||||
|
@ -58,19 +58,18 @@ typedef union {
|
|||||||
|
|
||||||
/* Retrieves hostname and port from given key value parameters.
|
/* Retrieves hostname and port from given key value parameters.
|
||||||
*
|
*
|
||||||
* @param[in] paramsSize the size of the parameter list
|
* @param[in] params the parameter map to retrieve from
|
||||||
* @param[in] params the parameter list to retrieve from
|
|
||||||
* @param[out] hostname the retrieved hostname when present, NULL otherwise
|
* @param[out] hostname the retrieved hostname when present, NULL otherwise
|
||||||
* @param[out] portStr the retrieved port when present, NULL otherwise
|
* @param[out] portStr the retrieved port when present, NULL otherwise
|
||||||
* @param[in] logger the logger to log information
|
* @param[in] logger the logger to log information
|
||||||
* @return -1 upon error, 0 if there was no host or port parameter, 1 if
|
* @return -1 upon error, 0 if there was no host or port parameter, 1 if
|
||||||
* host and port are present */
|
* host and port are present */
|
||||||
static int
|
static int
|
||||||
getHostAndPortFromParams(size_t paramsSize, const UA_KeyValuePair *params,
|
getHostAndPortFromParams(const UA_KeyValueMap *params,
|
||||||
char *hostname, char *portStr, const UA_Logger *logger) {
|
char *hostname, char *portStr, const UA_Logger *logger) {
|
||||||
/* Prepare the port parameter as a string */
|
/* Prepare the port parameter as a string */
|
||||||
const UA_UInt16 *port = (const UA_UInt16*)
|
const UA_UInt16 *port = (const UA_UInt16*)
|
||||||
UA_KeyValueMap_getScalar(params, paramsSize,
|
UA_KeyValueMap_getScalar(params,
|
||||||
UA_QUALIFIEDNAME(0, "port"),
|
UA_QUALIFIEDNAME(0, "port"),
|
||||||
&UA_TYPES[UA_TYPES_UINT16]);
|
&UA_TYPES[UA_TYPES_UINT16]);
|
||||||
if(!port) {
|
if(!port) {
|
||||||
@ -82,7 +81,7 @@ getHostAndPortFromParams(size_t paramsSize, const UA_KeyValuePair *params,
|
|||||||
|
|
||||||
/* Prepare the hostname string */
|
/* Prepare the hostname string */
|
||||||
const UA_String *host = (const UA_String*)
|
const UA_String *host = (const UA_String*)
|
||||||
UA_KeyValueMap_getScalar(params, paramsSize,
|
UA_KeyValueMap_getScalar(params,
|
||||||
UA_QUALIFIEDNAME(0, "hostname"),
|
UA_QUALIFIEDNAME(0, "hostname"),
|
||||||
&UA_TYPES[UA_TYPES_STRING]);
|
&UA_TYPES[UA_TYPES_STRING]);
|
||||||
if(!host) {
|
if(!host) {
|
||||||
@ -101,11 +100,11 @@ getHostAndPortFromParams(size_t paramsSize, const UA_KeyValuePair *params,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
getNetworkInterfaceFromParams(size_t paramsSize, const UA_KeyValuePair *params,
|
getNetworkInterfaceFromParams(const UA_KeyValueMap *params,
|
||||||
UA_String *outNetworkInterface, const UA_Logger *logger) {
|
UA_String *outNetworkInterface, const UA_Logger *logger) {
|
||||||
/* Prepare the networkinterface string */
|
/* Prepare the networkinterface string */
|
||||||
const UA_String *networkInterface = (const UA_String*)
|
const UA_String *networkInterface = (const UA_String*)
|
||||||
UA_KeyValueMap_getScalar(params, paramsSize,
|
UA_KeyValueMap_getScalar(params,
|
||||||
UA_QUALIFIEDNAME(0, "network-interface"),
|
UA_QUALIFIEDNAME(0, "network-interface"),
|
||||||
&UA_TYPES[UA_TYPES_STRING]);
|
&UA_TYPES[UA_TYPES_STRING]);
|
||||||
if(!networkInterface) {
|
if(!networkInterface) {
|
||||||
@ -118,11 +117,11 @@ getNetworkInterfaceFromParams(size_t paramsSize, const UA_KeyValuePair *params,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
getConnectionInfoFromParams(size_t paramsSize, const UA_KeyValuePair *params,
|
getConnectionInfoFromParams(const UA_KeyValueMap *params,
|
||||||
char *hostname, char *portStr,
|
char *hostname, char *portStr,
|
||||||
struct addrinfo **info, const UA_Logger *logger) {
|
struct addrinfo **info, const UA_Logger *logger) {
|
||||||
|
|
||||||
int foundParams = getHostAndPortFromParams(paramsSize, params,
|
int foundParams = getHostAndPortFromParams(params,
|
||||||
hostname, portStr, logger);
|
hostname, portStr, logger);
|
||||||
if (foundParams < 0) {
|
if (foundParams < 0) {
|
||||||
UA_LOG_ERROR(logger, UA_LOGCATEGORY_EVENTLOOP,
|
UA_LOG_ERROR(logger, UA_LOGCATEGORY_EVENTLOOP,
|
||||||
@ -258,8 +257,7 @@ isIPv6MulticastAddress(const UA_Byte *address) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static UA_StatusCode
|
static UA_StatusCode
|
||||||
setConnectionConfig(UA_FD socket, const UA_KeyValuePair *connectionProperties,
|
setConnectionConfig(UA_FD socket, const UA_KeyValueMap *connectionProperties,
|
||||||
const size_t connectionPropertiesSize,
|
|
||||||
int ai_family, const UA_Logger *logger) {
|
int ai_family, const UA_Logger *logger) {
|
||||||
/* Iterate over the given KeyValuePair parameters */
|
/* Iterate over the given KeyValuePair parameters */
|
||||||
UA_String ttlParam = UA_STRING("ttl");
|
UA_String ttlParam = UA_STRING("ttl");
|
||||||
@ -275,8 +273,8 @@ setConnectionConfig(UA_FD socket, const UA_KeyValuePair *connectionProperties,
|
|||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
UA_String socketPriorityParam = UA_STRING("sockpriority");
|
UA_String socketPriorityParam = UA_STRING("sockpriority");
|
||||||
#endif
|
#endif
|
||||||
for(size_t i = 0; i < connectionPropertiesSize; i++) {
|
for(size_t i = 0; i < connectionProperties->mapSize; i++) {
|
||||||
const UA_KeyValuePair *prop = &connectionProperties[i];
|
const UA_KeyValuePair *prop = &connectionProperties->map[i];
|
||||||
if(UA_String_equal(&prop->key.name, &ttlParam)) {
|
if(UA_String_equal(&prop->key.name, &ttlParam)) {
|
||||||
if(UA_Variant_hasScalarType(&prop->value, &UA_TYPES[UA_TYPES_UINT32])){
|
if(UA_Variant_hasScalarType(&prop->value, &UA_TYPES[UA_TYPES_UINT32])){
|
||||||
UA_UInt32 messageTTL = *(UA_UInt32*)prop->value.data;
|
UA_UInt32 messageTTL = *(UA_UInt32*)prop->value.data;
|
||||||
@ -336,7 +334,7 @@ setConnectionConfig(UA_FD socket, const UA_KeyValuePair *connectionProperties,
|
|||||||
return UA_STATUSCODE_GOOD;
|
return UA_STATUSCODE_GOOD;
|
||||||
}
|
}
|
||||||
static UA_StatusCode
|
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) {
|
const UA_Logger *logger) {
|
||||||
struct in_addr address = addr->sin_addr;
|
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);
|
ipMulticastRequest.ipv4.imr_interface.s_addr = UA_htonl(INADDR_ANY);
|
||||||
|
|
||||||
UA_String netif = UA_STRING_NULL;
|
UA_String netif = UA_STRING_NULL;
|
||||||
int foundInterface = getNetworkInterfaceFromParams(paramsSize, params, &netif, logger);
|
int foundInterface = getNetworkInterfaceFromParams(params, &netif, logger);
|
||||||
if(foundInterface < 0) {
|
if(foundInterface < 0) {
|
||||||
UA_LOG_ERROR(logger, UA_LOGCATEGORY_NETWORK,
|
UA_LOG_ERROR(logger, UA_LOGCATEGORY_NETWORK,
|
||||||
"UDP\t| Opening a connection failed");
|
"UDP\t| Opening a connection failed");
|
||||||
@ -377,7 +375,7 @@ setupSendMulticastIPv4(UA_FD socket, struct sockaddr_in *addr, size_t paramsSize
|
|||||||
}
|
}
|
||||||
|
|
||||||
static UA_StatusCode
|
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) {
|
const UA_Logger *logger) {
|
||||||
struct in_addr address = addr->sin_addr;
|
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);
|
ipMulticastRequest.ipv4.imr_interface.s_addr = UA_htonl(INADDR_ANY);
|
||||||
|
|
||||||
UA_String netif = UA_STRING_NULL;
|
UA_String netif = UA_STRING_NULL;
|
||||||
int foundInterface = getNetworkInterfaceFromParams(paramsSize, params, &netif, logger);
|
int foundInterface = getNetworkInterfaceFromParams(params, &netif, logger);
|
||||||
if(foundInterface < 0) {
|
if(foundInterface < 0) {
|
||||||
UA_LOG_ERROR(logger, UA_LOGCATEGORY_NETWORK,
|
UA_LOG_ERROR(logger, UA_LOGCATEGORY_NETWORK,
|
||||||
"UDP\t| Opening a connection failed");
|
"UDP\t| Opening a connection failed");
|
||||||
@ -422,7 +420,7 @@ setupListenMulticastIPv4(UA_FD socket, size_t paramsSize, const UA_KeyValuePair
|
|||||||
|
|
||||||
#if UA_IPV6
|
#if UA_IPV6
|
||||||
static UA_StatusCode
|
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) {
|
const UA_Logger *logger) {
|
||||||
|
|
||||||
struct in6_addr address = addr->sin6_addr;
|
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;
|
ipMulticastRequest.ipv6.ipv6mr_interface = 0;
|
||||||
|
|
||||||
UA_String netif = UA_STRING_NULL;
|
UA_String netif = UA_STRING_NULL;
|
||||||
int foundInterface = getNetworkInterfaceFromParams(paramsSize, params, &netif, logger);
|
int foundInterface = getNetworkInterfaceFromParams(params, &netif, logger);
|
||||||
if(foundInterface < 0) {
|
if(foundInterface < 0) {
|
||||||
UA_LOG_ERROR(logger, UA_LOGCATEGORY_NETWORK,
|
UA_LOG_ERROR(logger, UA_LOGCATEGORY_NETWORK,
|
||||||
"UDP\t| Opening a connection failed");
|
"UDP\t| Opening a connection failed");
|
||||||
@ -466,7 +464,7 @@ setupListenMulticastIPv6(UA_FD socket, size_t paramsSize, const UA_KeyValuePair
|
|||||||
}
|
}
|
||||||
|
|
||||||
static UA_StatusCode
|
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) {
|
const UA_Logger *logger) {
|
||||||
struct in6_addr address = addr->sin6_addr;
|
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;
|
ipMulticastRequest.ipv6.ipv6mr_interface = 0;
|
||||||
|
|
||||||
UA_String netif = UA_STRING_NULL;
|
UA_String netif = UA_STRING_NULL;
|
||||||
int foundInterface = getNetworkInterfaceFromParams(paramsSize, params, &netif, logger);
|
int foundInterface = getNetworkInterfaceFromParams(params, &netif, logger);
|
||||||
if(foundInterface < 0) {
|
if(foundInterface < 0) {
|
||||||
UA_LOG_ERROR(logger, UA_LOGCATEGORY_NETWORK,
|
UA_LOG_ERROR(logger, UA_LOGCATEGORY_NETWORK,
|
||||||
"UDP\t| Opening a connection failed");
|
"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,
|
udpfd->connectionCallback(&ucm->cm, (uintptr_t)rfd->fd,
|
||||||
rfd->application, &rfd->context,
|
rfd->application, &rfd->context,
|
||||||
UA_CONNECTIONSTATE_CLOSING,
|
UA_CONNECTIONSTATE_CLOSING,
|
||||||
0, NULL, UA_BYTESTRING_NULL);
|
&UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);
|
||||||
|
|
||||||
/* Close the socket */
|
/* Close the socket */
|
||||||
int ret = UA_close(rfd->fd);
|
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,
|
udpfd->connectionCallback(cm, (uintptr_t)rfd->fd,
|
||||||
rfd->application, &rfd->context,
|
rfd->application, &rfd->context,
|
||||||
UA_CONNECTIONSTATE_ESTABLISHED,
|
UA_CONNECTIONSTATE_ESTABLISHED,
|
||||||
0, NULL, UA_BYTESTRING_NULL);
|
&UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);
|
||||||
|
|
||||||
/* Now we are interested in read-events. */
|
/* Now we are interested in read-events. */
|
||||||
rfd->listenEvents = UA_FDEVENT_IN;
|
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 */
|
response.length = (size_t)ret; /* Set the length of the received buffer */
|
||||||
udpfd->connectionCallback(cm, (uintptr_t)rfd->fd,
|
udpfd->connectionCallback(cm, (uintptr_t)rfd->fd,
|
||||||
rfd->application, &rfd->context,
|
rfd->application, &rfd->context,
|
||||||
UA_CONNECTIONSTATE_ESTABLISHED, 0, NULL, response);
|
UA_CONNECTIONSTATE_ESTABLISHED, &UA_KEYVALUEMAP_NULL, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
static UA_StatusCode
|
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_FD listenSocket, const UA_Logger *logger) {
|
||||||
UA_StatusCode res = UA_STATUSCODE_GOOD;
|
UA_StatusCode res = UA_STATUSCODE_GOOD;
|
||||||
if(info->ai_family == AF_INET) {
|
if(info->ai_family == AF_INET) {
|
||||||
UA_Byte *addressVal = (UA_Byte *) &((struct sockaddr_in *)info->ai_addr)->sin_addr;
|
UA_Byte *addressVal = (UA_Byte *) &((struct sockaddr_in *)info->ai_addr)->sin_addr;
|
||||||
if(isIPv4MulticastAddress(addressVal)) {
|
if(isIPv4MulticastAddress(addressVal)) {
|
||||||
res = setupListenMulticastIPv4(listenSocket,
|
res = setupListenMulticastIPv4(listenSocket,
|
||||||
paramsSize, params, (struct sockaddr_in *)info->ai_addr,
|
params, (struct sockaddr_in *)info->ai_addr,
|
||||||
logger);
|
logger);
|
||||||
}
|
}
|
||||||
#if UA_IPV6
|
#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;
|
UA_Byte *addressVal = (UA_Byte *) &((struct sockaddr_in6 *)info->ai_addr)->sin6_addr;
|
||||||
if(isIPv6MulticastAddress(addressVal)) {
|
if(isIPv6MulticastAddress(addressVal)) {
|
||||||
res = setupListenMulticastIPv6(listenSocket,
|
res = setupListenMulticastIPv6(listenSocket,
|
||||||
paramsSize, params, (struct sockaddr_in6 *)info->ai_addr, logger);
|
params, (struct sockaddr_in6 *)info->ai_addr, logger);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
@ -709,7 +707,7 @@ checkForListenMulticastAndConfigure(struct addrinfo *info, size_t paramsSize, co
|
|||||||
|
|
||||||
static UA_StatusCode
|
static UA_StatusCode
|
||||||
UDP_registerListenSocket(UA_ConnectionManager *cm, UA_UInt16 port, struct addrinfo *info,
|
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,
|
void *application, void *context,
|
||||||
UA_ConnectionManager_connectionCallback connectionCallback,
|
UA_ConnectionManager_connectionCallback connectionCallback,
|
||||||
UA_Boolean validate) {
|
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",
|
"UDP %u\t| New listen socket for \"%s\" on port %u",
|
||||||
(unsigned)listenSocket, hoststr, port);
|
(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) {
|
if(res != UA_STATUSCODE_GOOD) {
|
||||||
UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
|
UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
|
||||||
"UDP\t| Configuring listen multicast failed");
|
"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,
|
connectionCallback(cm, (uintptr_t)newudpfd->fd.fd,
|
||||||
application, &newudpfd->fd.context,
|
application, &newudpfd->fd.context,
|
||||||
UA_CONNECTIONSTATE_ESTABLISHED,
|
UA_CONNECTIONSTATE_ESTABLISHED,
|
||||||
0, NULL, UA_BYTESTRING_NULL);
|
&UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);
|
||||||
return UA_STATUSCODE_GOOD;
|
return UA_STATUSCODE_GOOD;
|
||||||
}
|
}
|
||||||
|
|
||||||
static UA_StatusCode
|
static UA_StatusCode
|
||||||
UDP_registerListenSockets(UA_ConnectionManager *cm, const char *hostname, UA_UInt16 port,
|
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,
|
void *application, void *context,
|
||||||
UA_ConnectionManager_connectionCallback connectionCallback,
|
UA_ConnectionManager_connectionCallback connectionCallback,
|
||||||
UA_Boolean validate) {
|
UA_Boolean validate) {
|
||||||
@ -891,7 +889,8 @@ UDP_registerListenSockets(UA_ConnectionManager *cm, const char *hostname, UA_UIn
|
|||||||
struct addrinfo *ai = res;
|
struct addrinfo *ai = res;
|
||||||
UA_StatusCode rv = UA_STATUSCODE_GOOD;
|
UA_StatusCode rv = UA_STATUSCODE_GOOD;
|
||||||
while(ai) {
|
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) {
|
if(rv != UA_STATUSCODE_GOOD && validate) {
|
||||||
UA_freeaddrinfo(res);
|
UA_freeaddrinfo(res);
|
||||||
return rv;
|
return rv;
|
||||||
@ -953,7 +952,7 @@ UDP_shutdownConnection(UA_ConnectionManager *cm, uintptr_t connectionId) {
|
|||||||
|
|
||||||
static UA_StatusCode
|
static UA_StatusCode
|
||||||
UDP_sendWithConnection(UA_ConnectionManager *cm, uintptr_t connectionId,
|
UDP_sendWithConnection(UA_ConnectionManager *cm, uintptr_t connectionId,
|
||||||
size_t paramsSize, const UA_KeyValuePair *params,
|
const UA_KeyValueMap *params,
|
||||||
UA_ByteString *buf) {
|
UA_ByteString *buf) {
|
||||||
/* Prevent OS signals when sending to a closed socket */
|
/* Prevent OS signals when sending to a closed socket */
|
||||||
int flags = MSG_NOSIGNAL;
|
int flags = MSG_NOSIGNAL;
|
||||||
@ -1019,7 +1018,7 @@ UDP_sendWithConnection(UA_ConnectionManager *cm, uintptr_t connectionId,
|
|||||||
|
|
||||||
|
|
||||||
static UA_StatusCode
|
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) {
|
const UA_Logger *logger) {
|
||||||
UA_StatusCode res = UA_STATUSCODE_GOOD;
|
UA_StatusCode res = UA_STATUSCODE_GOOD;
|
||||||
if(info->ai_family == AF_INET) {
|
if(info->ai_family == AF_INET) {
|
||||||
@ -1028,7 +1027,6 @@ checkForSendMulticastAndConfigure(size_t paramsSize, const UA_KeyValuePair *para
|
|||||||
|
|
||||||
if(isIPv4MulticastAddress(addressVal)) {
|
if(isIPv4MulticastAddress(addressVal)) {
|
||||||
res = setupSendMulticastIPv4(newSock, (struct sockaddr_in *)info->ai_addr,
|
res = setupSendMulticastIPv4(newSock, (struct sockaddr_in *)info->ai_addr,
|
||||||
paramsSize,
|
|
||||||
params, logger);
|
params, logger);
|
||||||
}
|
}
|
||||||
#if UA_IPV6
|
#if UA_IPV6
|
||||||
@ -1037,7 +1035,6 @@ checkForSendMulticastAndConfigure(size_t paramsSize, const UA_KeyValuePair *para
|
|||||||
UA_Byte *addressVal = (UA_Byte *) &addr->sin6_addr;
|
UA_Byte *addressVal = (UA_Byte *) &addr->sin6_addr;
|
||||||
if(isIPv6MulticastAddress(addressVal)) {
|
if(isIPv6MulticastAddress(addressVal)) {
|
||||||
res = setupSendMulticastIPv6(newSock, (struct sockaddr_in6 *)info->ai_addr,
|
res = setupSendMulticastIPv6(newSock, (struct sockaddr_in6 *)info->ai_addr,
|
||||||
paramsSize,
|
|
||||||
params, logger);
|
params, logger);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -1050,7 +1047,7 @@ checkForSendMulticastAndConfigure(size_t paramsSize, const UA_KeyValuePair *para
|
|||||||
}
|
}
|
||||||
|
|
||||||
static UA_StatusCode
|
static UA_StatusCode
|
||||||
registerSocketAndDestinationForSend(size_t paramsSize, const UA_KeyValuePair *params,
|
registerSocketAndDestinationForSend(const UA_KeyValueMap *params,
|
||||||
const char *hostname, struct addrinfo *info,
|
const char *hostname, struct addrinfo *info,
|
||||||
int error, UDP_FD * ufd, UA_FD *sock, const UA_Logger *logger) {
|
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);
|
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));
|
hostname, errno_str));
|
||||||
return UA_STATUSCODE_BADDISCONNECT;
|
return UA_STATUSCODE_BADDISCONNECT;
|
||||||
}
|
}
|
||||||
UA_StatusCode res = setConnectionConfig(newSock, params, paramsSize,
|
UA_StatusCode res = setConnectionConfig(newSock, params,
|
||||||
info->ai_family, logger);
|
info->ai_family, logger);
|
||||||
if(res != UA_STATUSCODE_GOOD) {
|
if(res != UA_STATUSCODE_GOOD) {
|
||||||
UA_close(newSock);
|
UA_close(newSock);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = checkForSendMulticastAndConfigure(paramsSize, params, info, newSock, logger);
|
res = checkForSendMulticastAndConfigure(params, info, newSock, logger);
|
||||||
if(res != UA_STATUSCODE_GOOD) {
|
if(res != UA_STATUSCODE_GOOD) {
|
||||||
UA_close(newSock);
|
UA_close(newSock);
|
||||||
UA_LOG_ERROR(logger, UA_LOGCATEGORY_NETWORK,
|
UA_LOG_ERROR(logger, UA_LOGCATEGORY_NETWORK,
|
||||||
@ -1084,7 +1081,7 @@ registerSocketAndDestinationForSend(size_t paramsSize, const UA_KeyValuePair *pa
|
|||||||
|
|
||||||
static UA_StatusCode
|
static UA_StatusCode
|
||||||
UDP_openSendConnection(UA_ConnectionManager *cm,
|
UDP_openSendConnection(UA_ConnectionManager *cm,
|
||||||
size_t paramsSize, const UA_KeyValuePair *params,
|
const UA_KeyValueMap *params,
|
||||||
void *application, void *context,
|
void *application, void *context,
|
||||||
UA_ConnectionManager_connectionCallback connectionCallback,
|
UA_ConnectionManager_connectionCallback connectionCallback,
|
||||||
UA_Boolean validate) {
|
UA_Boolean validate) {
|
||||||
@ -1095,7 +1092,7 @@ UDP_openSendConnection(UA_ConnectionManager *cm,
|
|||||||
char portStr[UA_MAXPORTSTR_LENGTH];
|
char portStr[UA_MAXPORTSTR_LENGTH];
|
||||||
struct addrinfo *info = NULL;
|
struct addrinfo *info = NULL;
|
||||||
|
|
||||||
int error = getConnectionInfoFromParams(paramsSize, params, hostname,
|
int error = getConnectionInfoFromParams(params, hostname,
|
||||||
portStr, &info, el->eventLoop.logger);
|
portStr, &info, el->eventLoop.logger);
|
||||||
if(error < 0 || info == NULL) {
|
if(error < 0 || info == NULL) {
|
||||||
if(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 */
|
/* Create a socket and register the destination address from the provided parameters */
|
||||||
UA_FD newSock = UA_INVALID_FD;
|
UA_FD newSock = UA_INVALID_FD;
|
||||||
UA_StatusCode res =
|
UA_StatusCode res =
|
||||||
registerSocketAndDestinationForSend(paramsSize, params, hostname, info,
|
registerSocketAndDestinationForSend(params, hostname, info,
|
||||||
error, newudpfd, &newSock, el->eventLoop.logger);
|
error, newudpfd, &newSock, el->eventLoop.logger);
|
||||||
UA_freeaddrinfo(info);
|
UA_freeaddrinfo(info);
|
||||||
if(validate && res == UA_STATUSCODE_GOOD) {
|
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
|
/* Signal the connection as opening. The connection fully opens in the next
|
||||||
* iteration of the EventLoop */
|
* iteration of the EventLoop */
|
||||||
connectionCallback(cm, (uintptr_t)newSock, application, &newudpfd->fd.context,
|
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;
|
return UA_STATUSCODE_GOOD;
|
||||||
}
|
}
|
||||||
|
|
||||||
static UA_StatusCode
|
static UA_StatusCode
|
||||||
UDP_openReceiveConnection(UA_ConnectionManager *cm,
|
UDP_openReceiveConnection(UA_ConnectionManager *cm,
|
||||||
size_t paramsSize, const UA_KeyValuePair *params,
|
const UA_KeyValueMap *params,
|
||||||
void *application, void *context,
|
void *application, void *context,
|
||||||
UA_ConnectionManager_connectionCallback connectionCallback,
|
UA_ConnectionManager_connectionCallback connectionCallback,
|
||||||
UA_Boolean validate) {
|
UA_Boolean validate) {
|
||||||
@ -1177,7 +1174,7 @@ UDP_openReceiveConnection(UA_ConnectionManager *cm,
|
|||||||
|
|
||||||
/* Get the socket */
|
/* Get the socket */
|
||||||
const UA_UInt16 *port = (const UA_UInt16*)
|
const UA_UInt16 *port = (const UA_UInt16*)
|
||||||
UA_KeyValueMap_getScalar(params, paramsSize,
|
UA_KeyValueMap_getScalar(params,
|
||||||
UA_QUALIFIEDNAME(0, "listen-port"),
|
UA_QUALIFIEDNAME(0, "listen-port"),
|
||||||
&UA_TYPES[UA_TYPES_UINT16]);
|
&UA_TYPES[UA_TYPES_UINT16]);
|
||||||
if(!port) {
|
if(!port) {
|
||||||
@ -1188,15 +1185,14 @@ UDP_openReceiveConnection(UA_ConnectionManager *cm,
|
|||||||
|
|
||||||
/* Get the hostnames configuration */
|
/* Get the hostnames configuration */
|
||||||
const UA_Variant *hostNames =
|
const UA_Variant *hostNames =
|
||||||
UA_KeyValueMap_get(params, paramsSize,
|
UA_KeyValueMap_get(params,
|
||||||
UA_QUALIFIEDNAME(0, "listen-hostnames"));
|
UA_QUALIFIEDNAME(0, "listen-hostnames"));
|
||||||
if(!hostNames) {
|
if(!hostNames) {
|
||||||
/* No hostnames configured -> listen on all interfaces*/
|
/* No hostnames configured -> listen on all interfaces*/
|
||||||
UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
|
UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
|
||||||
"UDP\t| Listening on all interfaces");
|
"UDP\t| Listening on all interfaces");
|
||||||
return UDP_registerListenSockets(cm, NULL, *port, paramsSize, params,
|
return UDP_registerListenSockets(cm, NULL, *port, params, application,
|
||||||
application, context, connectionCallback,
|
context, connectionCallback, validate);
|
||||||
validate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Correct datatype for the hostnames? */
|
/* Correct datatype for the hostnames? */
|
||||||
@ -1211,9 +1207,8 @@ UDP_openReceiveConnection(UA_ConnectionManager *cm,
|
|||||||
if(interfaces == 0) {
|
if(interfaces == 0) {
|
||||||
UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
|
UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
|
||||||
"UDP\t| Listening on all interfaces");
|
"UDP\t| Listening on all interfaces");
|
||||||
return UDP_registerListenSockets(cm, NULL, *port, paramsSize, params,
|
return UDP_registerListenSockets(cm, NULL, *port, params, application,
|
||||||
application, context, connectionCallback,
|
context, connectionCallback, validate);
|
||||||
validate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UA_StatusCode rv = UA_STATUSCODE_GOOD;
|
UA_StatusCode rv = UA_STATUSCODE_GOOD;
|
||||||
@ -1225,8 +1220,8 @@ UDP_openReceiveConnection(UA_ConnectionManager *cm,
|
|||||||
continue;
|
continue;
|
||||||
memcpy(hostname, hostStrings[i].data, hostStrings->length);
|
memcpy(hostname, hostStrings[i].data, hostStrings->length);
|
||||||
hostname[hostStrings->length] = '\0';
|
hostname[hostStrings->length] = '\0';
|
||||||
rv = UDP_registerListenSockets(cm, hostname, *port, paramsSize, params,
|
rv = UDP_registerListenSockets(cm, hostname, *port, params, application,
|
||||||
application, context, connectionCallback, validate);
|
context, connectionCallback, validate);
|
||||||
if(rv != UA_STATUSCODE_GOOD) {
|
if(rv != UA_STATUSCODE_GOOD) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@ -1237,11 +1232,11 @@ UDP_openReceiveConnection(UA_ConnectionManager *cm,
|
|||||||
|
|
||||||
static UA_StatusCode
|
static UA_StatusCode
|
||||||
UDP_openConnection(UA_ConnectionManager *cm,
|
UDP_openConnection(UA_ConnectionManager *cm,
|
||||||
size_t paramsSize, const UA_KeyValuePair *params,
|
const UA_KeyValueMap *params,
|
||||||
void *application, void *context,
|
void *application, void *context,
|
||||||
UA_ConnectionManager_connectionCallback connectionCallback) {
|
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_QUALIFIEDNAME(0, "validate"));
|
||||||
UA_Boolean validate = false;
|
UA_Boolean validate = false;
|
||||||
if(validationValue) {
|
if(validationValue) {
|
||||||
@ -1252,14 +1247,14 @@ UDP_openConnection(UA_ConnectionManager *cm,
|
|||||||
/* If the "port"-parameter is defined, then try to open a send connection.
|
/* If the "port"-parameter is defined, then try to open a send connection.
|
||||||
* Otherwise try to open a socket that listens for incoming TCP
|
* Otherwise try to open a socket that listens for incoming TCP
|
||||||
* connections. */
|
* connections. */
|
||||||
const UA_Variant *val = UA_KeyValueMap_get(params, paramsSize,
|
const UA_Variant *val = UA_KeyValueMap_get(params,
|
||||||
UA_QUALIFIEDNAME(0, "port"));
|
UA_QUALIFIEDNAME(0, "port"));
|
||||||
if(val) {
|
if(val) {
|
||||||
return UDP_openSendConnection(cm, paramsSize, params,
|
return UDP_openSendConnection(cm, params, application, context,
|
||||||
application, context, connectionCallback, validate);
|
connectionCallback, validate);
|
||||||
} else {
|
} else {
|
||||||
return UDP_openReceiveConnection(cm, paramsSize, params,
|
return UDP_openReceiveConnection(cm, params, application, context,
|
||||||
application, context, connectionCallback, validate);
|
connectionCallback, validate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1279,13 +1274,14 @@ UDP_eventSourceStart(UA_ConnectionManager *cm) {
|
|||||||
/* The receive buffersize was configured? */
|
/* The receive buffersize was configured? */
|
||||||
UDPConnectionManager *ucm = (UDPConnectionManager*)cm;
|
UDPConnectionManager *ucm = (UDPConnectionManager*)cm;
|
||||||
UA_UInt32 rxBufSize = 2u << 16; /* The default is 64kb */
|
UA_UInt32 rxBufSize = 2u << 16; /* The default is 64kb */
|
||||||
const UA_UInt32 *configRxBufSize = (const UA_UInt32*)
|
if(cm->eventSource.params != NULL) {
|
||||||
UA_KeyValueMap_getScalar(cm->eventSource.params,
|
const UA_UInt32 *configRxBufSize = (const UA_UInt32 *)
|
||||||
cm->eventSource.paramsSize,
|
UA_KeyValueMap_getScalar(cm->eventSource.params,
|
||||||
UA_QUALIFIEDNAME(0, "recv-bufsize"),
|
UA_QUALIFIEDNAME(0, "recv-bufsize"),
|
||||||
&UA_TYPES[UA_TYPES_UINT32]);
|
&UA_TYPES[UA_TYPES_UINT32]);
|
||||||
if(configRxBufSize)
|
if(configRxBufSize)
|
||||||
rxBufSize = *configRxBufSize;
|
rxBufSize = *configRxBufSize;
|
||||||
|
}
|
||||||
UA_StatusCode res = UA_ByteString_allocBuffer(&ucm->rxBuffer, rxBufSize);
|
UA_StatusCode res = UA_ByteString_allocBuffer(&ucm->rxBuffer, rxBufSize);
|
||||||
if(res != UA_STATUSCODE_GOOD)
|
if(res != UA_STATUSCODE_GOOD)
|
||||||
return res;
|
return res;
|
||||||
@ -1325,12 +1321,10 @@ UDP_eventSourceDelete(UA_ConnectionManager *cm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Delete the parameters */
|
/* Delete the parameters */
|
||||||
UA_Array_delete(cm->eventSource.params,
|
if(cm->eventSource.params != NULL) {
|
||||||
cm->eventSource.paramsSize,
|
UA_KeyValueMap_delete(cm->eventSource.params);
|
||||||
&UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
|
cm->eventSource.params = NULL;
|
||||||
cm->eventSource.params = NULL;
|
}
|
||||||
cm->eventSource.paramsSize = 0;
|
|
||||||
|
|
||||||
UA_String_clear(&cm->eventSource.name);
|
UA_String_clear(&cm->eventSource.name);
|
||||||
UA_free(cm);
|
UA_free(cm);
|
||||||
return UA_STATUSCODE_GOOD;
|
return UA_STATUSCODE_GOOD;
|
||||||
|
@ -75,8 +75,7 @@ struct UA_EventLoop {
|
|||||||
* ~~~~~~~~~~~~~~~
|
* ~~~~~~~~~~~~~~~
|
||||||
* The configuration should be set before the EventLoop is started */
|
* The configuration should be set before the EventLoop is started */
|
||||||
const UA_Logger *logger;
|
const UA_Logger *logger;
|
||||||
size_t paramsSize;
|
UA_KeyValueMap *params; /* See the implementation-specific documentation */
|
||||||
UA_KeyValuePair *params; /* See the implementation-specific documentation */
|
|
||||||
|
|
||||||
/* EventLoop Lifecycle
|
/* EventLoop Lifecycle
|
||||||
* ~~~~~~~~~~~~~~~~~~~~ */
|
* ~~~~~~~~~~~~~~~~~~~~ */
|
||||||
@ -213,8 +212,7 @@ struct UA_EventSource {
|
|||||||
* ~~~~~~~~~~~~~ */
|
* ~~~~~~~~~~~~~ */
|
||||||
UA_String name; /* Unique name of the ES */
|
UA_String name; /* Unique name of the ES */
|
||||||
UA_EventLoop *eventLoop; /* EventLoop where the ES is registered */
|
UA_EventLoop *eventLoop; /* EventLoop where the ES is registered */
|
||||||
size_t paramsSize; /* Configuration parameters */
|
UA_KeyValueMap *params;
|
||||||
UA_KeyValuePair *params;
|
|
||||||
|
|
||||||
/* Lifecycle
|
/* Lifecycle
|
||||||
* ~~~~~~~~~ */
|
* ~~~~~~~~~ */
|
||||||
@ -259,7 +257,7 @@ typedef void
|
|||||||
(*UA_ConnectionManager_connectionCallback)
|
(*UA_ConnectionManager_connectionCallback)
|
||||||
(UA_ConnectionManager *cm, uintptr_t connectionId,
|
(UA_ConnectionManager *cm, uintptr_t connectionId,
|
||||||
void *application, void **connectionContext, UA_ConnectionState state,
|
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 {
|
struct UA_ConnectionManager {
|
||||||
/* Every ConnectionManager is treated like an EventSource from the
|
/* Every ConnectionManager is treated like an EventSource from the
|
||||||
@ -307,7 +305,7 @@ struct UA_ConnectionManager {
|
|||||||
* connections might be opened at once. */
|
* connections might be opened at once. */
|
||||||
UA_StatusCode
|
UA_StatusCode
|
||||||
(*openConnection)(UA_ConnectionManager *cm,
|
(*openConnection)(UA_ConnectionManager *cm,
|
||||||
size_t paramsSize, const UA_KeyValuePair *params,
|
const UA_KeyValueMap *params,
|
||||||
void *application, void *context,
|
void *application, void *context,
|
||||||
UA_ConnectionManager_connectionCallback connectionCallback);
|
UA_ConnectionManager_connectionCallback connectionCallback);
|
||||||
|
|
||||||
@ -322,7 +320,7 @@ struct UA_ConnectionManager {
|
|||||||
* example a tx-time for sending in time-synchronized TSN settings. */
|
* example a tx-time for sending in time-synchronized TSN settings. */
|
||||||
UA_StatusCode
|
UA_StatusCode
|
||||||
(*sendWithConnection)(UA_ConnectionManager *cm, uintptr_t connectionId,
|
(*sendWithConnection)(UA_ConnectionManager *cm, uintptr_t connectionId,
|
||||||
size_t paramsSize, const UA_KeyValuePair *params,
|
const UA_KeyValueMap *params,
|
||||||
UA_ByteString *buf);
|
UA_ByteString *buf);
|
||||||
|
|
||||||
/* Close a Connection
|
/* Close a Connection
|
||||||
@ -369,8 +367,7 @@ struct UA_ConnectionManager {
|
|||||||
typedef void
|
typedef void
|
||||||
(*UA_InterruptCallback)(UA_InterruptManager *im,
|
(*UA_InterruptCallback)(UA_InterruptManager *im,
|
||||||
uintptr_t interruptHandle, void *interruptContext,
|
uintptr_t interruptHandle, void *interruptContext,
|
||||||
size_t instanceInfosSize,
|
const UA_KeyValueMap *instanceInfos);
|
||||||
const UA_KeyValuePair *instanceInfos);
|
|
||||||
|
|
||||||
struct UA_InterruptManager {
|
struct UA_InterruptManager {
|
||||||
/* Every InterruptManager is treated like an EventSource from the
|
/* Every InterruptManager is treated like an EventSource from the
|
||||||
@ -390,7 +387,7 @@ struct UA_InterruptManager {
|
|||||||
* through to the callback without modification. */
|
* through to the callback without modification. */
|
||||||
UA_StatusCode
|
UA_StatusCode
|
||||||
(*registerInterrupt)(UA_InterruptManager *im, uintptr_t interruptHandle,
|
(*registerInterrupt)(UA_InterruptManager *im, uintptr_t interruptHandle,
|
||||||
size_t paramsSize, const UA_KeyValuePair *params,
|
const UA_KeyValueMap *params,
|
||||||
UA_InterruptCallback callback, void *interruptContext);
|
UA_InterruptCallback callback, void *interruptContext);
|
||||||
|
|
||||||
/* Remove a registered interrupt. Returns no error code if the interrupt is
|
/* Remove a registered interrupt. Returns no error code if the interrupt is
|
||||||
|
@ -40,34 +40,77 @@ typedef enum {
|
|||||||
* Key Value Map
|
* Key Value Map
|
||||||
* -------------
|
* -------------
|
||||||
* Helper functions to work with configuration parameters in an array of
|
* Helper functions to work with configuration parameters in an array of
|
||||||
* UA_KeyValuePair. Lookup is linear. So this is for small numbers of
|
* UA_KeyValuePair. Lookup is linear. So this is for small numbers of keys. The
|
||||||
* keys. */
|
* 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
|
* 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_EXPORT UA_StatusCode
|
||||||
UA_KeyValueMap_set(UA_KeyValuePair **map, size_t *mapSize,
|
UA_KeyValueMap_set(UA_KeyValueMap *map,
|
||||||
const UA_QualifiedName key,
|
const UA_QualifiedName key,
|
||||||
const UA_Variant *value);
|
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_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);
|
const UA_QualifiedName key);
|
||||||
|
|
||||||
/* Returns NULL if the value for the key is not defined or not of the right
|
/* Returns NULL if the value for the key is not defined, not of the right
|
||||||
* datatype and scalar/array */
|
* datatype or not a scalar */
|
||||||
UA_EXPORT const void *
|
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_QualifiedName key,
|
||||||
const UA_DataType *type);
|
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_EXPORT UA_StatusCode
|
||||||
UA_KeyValueMap_delete(UA_KeyValuePair **map, size_t *mapSize,
|
UA_KeyValueMap_remove(UA_KeyValueMap *map,
|
||||||
const UA_QualifiedName key);
|
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
|
* Endpoint URL Parser
|
||||||
* -------------------
|
* -------------------
|
||||||
|
@ -333,7 +333,7 @@ sendHELMessage(UA_Client *client) {
|
|||||||
/* Send the HEL message */
|
/* Send the HEL message */
|
||||||
message.length = messageHeader.messageSize;
|
message.length = messageHeader.messageSize;
|
||||||
retval = cm->sendWithConnection(cm, client->channel.connectionId,
|
retval = cm->sendWithConnection(cm, client->channel.connectionId,
|
||||||
0, NULL, &message);
|
&UA_KEYVALUEMAP_NULL, &message);
|
||||||
if(retval != UA_STATUSCODE_GOOD) {
|
if(retval != UA_STATUSCODE_GOOD) {
|
||||||
UA_LOG_INFO(&client->config.logger, UA_LOGCATEGORY_CLIENT, "Sending HEL failed");
|
UA_LOG_INFO(&client->config.logger, UA_LOGCATEGORY_CLIENT, "Sending HEL failed");
|
||||||
closeSecureChannel(client);
|
closeSecureChannel(client);
|
||||||
@ -1065,7 +1065,7 @@ static void
|
|||||||
UA_Client_networkCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
|
UA_Client_networkCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
|
||||||
void *application, void **connectionContext,
|
void *application, void **connectionContext,
|
||||||
UA_ConnectionState state,
|
UA_ConnectionState state,
|
||||||
size_t paramsSize, const UA_KeyValuePair *params,
|
const UA_KeyValueMap *params,
|
||||||
UA_ByteString msg) {
|
UA_ByteString msg) {
|
||||||
UA_Client *client = (UA_Client*)application;
|
UA_Client *client = (UA_Client*)application;
|
||||||
|
|
||||||
@ -1255,8 +1255,12 @@ initConnect(UA_Client *client) {
|
|||||||
params[1].key = UA_QUALIFIEDNAME(0, "hostname");
|
params[1].key = UA_QUALIFIEDNAME(0, "hostname");
|
||||||
UA_Variant_setScalar(¶ms[1].value, &hostname, &UA_TYPES[UA_TYPES_STRING]);
|
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 */
|
/* 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)
|
if(res == UA_STATUSCODE_GOOD)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -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]);
|
UA_Variant_setArray(¶ms[2].value, &hostname, 1, &UA_TYPES[UA_TYPES_STRING]);
|
||||||
paramsSize = 3;
|
paramsSize = 3;
|
||||||
}
|
}
|
||||||
|
UA_KeyValueMap paramsMap;
|
||||||
|
paramsMap.map = params;
|
||||||
|
paramsMap.mapSize = paramsSize;
|
||||||
|
|
||||||
/* Open the server connection */
|
/* Open the server connection */
|
||||||
res = cm->openConnection(cm, paramsSize, params, server, NULL,
|
res = cm->openConnection(cm, ¶msMap, server, NULL,
|
||||||
UA_Server_networkCallback);
|
UA_Server_networkCallback);
|
||||||
if(res == UA_STATUSCODE_GOOD)
|
if(res == UA_STATUSCODE_GOOD)
|
||||||
return res;
|
return res;
|
||||||
|
@ -382,7 +382,7 @@ processHEL(UA_Server *server, UA_SecureChannel *channel, const UA_ByteString *ms
|
|||||||
}
|
}
|
||||||
|
|
||||||
ack_msg.length = ackHeader.messageSize;
|
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)
|
if(retval == UA_STATUSCODE_GOOD)
|
||||||
channel->state = UA_SECURECHANNELSTATE_ACK_SENT;
|
channel->state = UA_SECURECHANNELSTATE_ACK_SENT;
|
||||||
return retval;
|
return retval;
|
||||||
@ -893,7 +893,7 @@ void
|
|||||||
UA_Server_networkCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
|
UA_Server_networkCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
|
||||||
void *application, void **connectionContext,
|
void *application, void **connectionContext,
|
||||||
UA_ConnectionState state,
|
UA_ConnectionState state,
|
||||||
size_t paramsSize, const UA_KeyValuePair *params,
|
const UA_KeyValueMap *params,
|
||||||
UA_ByteString msg) {
|
UA_ByteString msg) {
|
||||||
UA_Server *server = (UA_Server*)application;
|
UA_Server *server = (UA_Server*)application;
|
||||||
|
|
||||||
|
@ -368,7 +368,7 @@ void
|
|||||||
UA_Server_networkCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
|
UA_Server_networkCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
|
||||||
void *application, void **connectionContext,
|
void *application, void **connectionContext,
|
||||||
UA_ConnectionState state,
|
UA_ConnectionState state,
|
||||||
size_t paramsSize, const UA_KeyValuePair *params,
|
const UA_KeyValueMap *params,
|
||||||
UA_ByteString msg);
|
UA_ByteString msg);
|
||||||
|
|
||||||
/******************************************/
|
/******************************************/
|
||||||
|
@ -55,10 +55,8 @@ void UA_Session_clear(UA_Session *session, UA_Server* server) {
|
|||||||
session->continuationPoints = NULL;
|
session->continuationPoints = NULL;
|
||||||
session->availableContinuationPoints = UA_MAXCONTINUATIONPOINTS;
|
session->availableContinuationPoints = UA_MAXCONTINUATIONPOINTS;
|
||||||
|
|
||||||
UA_Array_delete(session->attributes, session->attributesSize,
|
UA_KeyValueMap_delete(session->attributes);
|
||||||
&UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
|
|
||||||
session->attributes = NULL;
|
session->attributes = NULL;
|
||||||
session->attributesSize = 0;
|
|
||||||
|
|
||||||
UA_Array_delete(session->localeIds, session->localeIdsSize,
|
UA_Array_delete(session->localeIds, session->localeIdsSize,
|
||||||
&UA_TYPES[UA_TYPES_STRING]);
|
&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_Session *session = getSessionById(server, sessionId);
|
||||||
UA_StatusCode res = UA_STATUSCODE_BADSESSIONIDINVALID;
|
UA_StatusCode res = UA_STATUSCODE_BADSESSIONIDINVALID;
|
||||||
if(session)
|
if(session)
|
||||||
res = UA_KeyValueMap_set(&session->attributes, &session->attributesSize,
|
res = UA_KeyValueMap_set(session->attributes,
|
||||||
key, value);
|
key, value);
|
||||||
UA_UNLOCK(&server->serviceMutex);
|
UA_UNLOCK(&server->serviceMutex);
|
||||||
return res;
|
return res;
|
||||||
@ -294,7 +292,7 @@ UA_Server_deleteSessionAttribute(UA_Server *server, const UA_NodeId *sessionId,
|
|||||||
if(!session)
|
if(!session)
|
||||||
return UA_STATUSCODE_BADSESSIONIDINVALID;
|
return UA_STATUSCODE_BADSESSIONIDINVALID;
|
||||||
UA_StatusCode res =
|
UA_StatusCode res =
|
||||||
UA_KeyValueMap_delete(&session->attributes, &session->attributesSize, key);
|
UA_KeyValueMap_remove(session->attributes, key);
|
||||||
UA_UNLOCK(&server->serviceMutex);
|
UA_UNLOCK(&server->serviceMutex);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -330,7 +328,7 @@ getSessionAttribute(UA_Server *server, const UA_NodeId *sessionId,
|
|||||||
attr = &localAttr;
|
attr = &localAttr;
|
||||||
} else {
|
} else {
|
||||||
/* Get from the actual key-value list */
|
/* 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)
|
if(!attr)
|
||||||
return UA_STATUSCODE_BADNOTFOUND;
|
return UA_STATUSCODE_BADNOTFOUND;
|
||||||
}
|
}
|
||||||
|
@ -51,8 +51,7 @@ typedef struct {
|
|||||||
UA_UInt16 availableContinuationPoints;
|
UA_UInt16 availableContinuationPoints;
|
||||||
ContinuationPoint *continuationPoints;
|
ContinuationPoint *continuationPoints;
|
||||||
|
|
||||||
size_t attributesSize;
|
UA_KeyValueMap *attributes;
|
||||||
UA_KeyValuePair *attributes;
|
|
||||||
|
|
||||||
/* Localization information */
|
/* Localization information */
|
||||||
size_t localeIdsSize;
|
size_t localeIdsSize;
|
||||||
|
@ -120,7 +120,7 @@ UA_SecureChannel_sendError(UA_SecureChannel *channel, UA_TcpErrorMessage *error)
|
|||||||
&bufPos, &bufEnd, NULL, NULL);
|
&bufPos, &bufEnd, NULL, NULL);
|
||||||
(void)retval; /* Encoding of these cannot fail */
|
(void)retval; /* Encoding of these cannot fail */
|
||||||
msg.length = header.messageSize;
|
msg.length = header.messageSize;
|
||||||
cm->sendWithConnection(cm, channel->connectionId, 0, NULL, &msg);
|
cm->sendWithConnection(cm, channel->connectionId, &UA_KEYVALUEMAP_NULL, &msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -294,7 +294,7 @@ UA_SecureChannel_sendAsymmetricOPNMessage(UA_SecureChannel *channel,
|
|||||||
|
|
||||||
/* Send the message, the buffer is freed in the network layer */
|
/* Send the message, the buffer is freed in the network layer */
|
||||||
buf.length = encryptedLength;
|
buf.length = encryptedLength;
|
||||||
return cm->sendWithConnection(cm, channel->connectionId, 0, NULL, &buf);
|
return cm->sendWithConnection(cm, channel->connectionId, &UA_KEYVALUEMAP_NULL, &buf);
|
||||||
|
|
||||||
error:
|
error:
|
||||||
cm->freeNetworkBuffer(cm, channel->connectionId, &buf);
|
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
|
* wrong, the connection is removed in the next iteration of the
|
||||||
* SecureChannel. Set the SecureChannel to closing already. */
|
* SecureChannel. Set the SecureChannel to closing already. */
|
||||||
res = cm->sendWithConnection(cm, channel->connectionId,
|
res = cm->sendWithConnection(cm, channel->connectionId,
|
||||||
0, NULL, &mc->messageBuffer);
|
&UA_KEYVALUEMAP_NULL, &mc->messageBuffer);
|
||||||
if(res != UA_STATUSCODE_GOOD && UA_SecureChannel_isConnected(channel))
|
if(res != UA_STATUSCODE_GOOD && UA_SecureChannel_isConnected(channel))
|
||||||
channel->state = UA_SECURECHANNELSTATE_CLOSING;
|
channel->state = UA_SECURECHANNELSTATE_CLOSING;
|
||||||
|
|
||||||
|
173
src/ua_util.c
173
src/ua_util.c
@ -227,15 +227,25 @@ UA_ByteString_fromBase64(UA_ByteString *bs,
|
|||||||
|
|
||||||
/* Key Value Map */
|
/* 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_StatusCode
|
||||||
UA_KeyValueMap_set(UA_KeyValuePair **map, size_t *mapSize,
|
UA_KeyValueMap_set(UA_KeyValueMap *map,
|
||||||
const UA_QualifiedName key,
|
const UA_QualifiedName key,
|
||||||
const UA_Variant *value) {
|
const UA_Variant *value) {
|
||||||
/* Parameter exists already */
|
if(map == NULL || value == NULL)
|
||||||
const UA_Variant *v = UA_KeyValueMap_get(*map, *mapSize, key);
|
return UA_STATUSCODE_BADINVALIDARGUMENT;
|
||||||
|
|
||||||
|
/* Key exists already */
|
||||||
|
const UA_Variant *v = UA_KeyValueMap_get(map, key);
|
||||||
if(v) {
|
if(v) {
|
||||||
UA_Variant copyV;
|
UA_Variant copyV;
|
||||||
UA_StatusCode res = UA_Variant_copy(v, ©V);
|
UA_StatusCode res = UA_Variant_copy(value, ©V);
|
||||||
if(res != UA_STATUSCODE_GOOD)
|
if(res != UA_STATUSCODE_GOOD)
|
||||||
return res;
|
return res;
|
||||||
UA_Variant *target = (UA_Variant*)(uintptr_t)v;
|
UA_Variant *target = (UA_Variant*)(uintptr_t)v;
|
||||||
@ -248,60 +258,153 @@ UA_KeyValueMap_set(UA_KeyValuePair **map, size_t *mapSize,
|
|||||||
UA_KeyValuePair pair;
|
UA_KeyValuePair pair;
|
||||||
pair.key = key;
|
pair.key = key;
|
||||||
pair.value = *value;
|
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_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 *
|
const UA_Variant *
|
||||||
UA_KeyValueMap_get(const UA_KeyValuePair *map, size_t mapSize,
|
UA_KeyValueMap_get(const UA_KeyValueMap *map,
|
||||||
const UA_QualifiedName key) {
|
const UA_QualifiedName key) {
|
||||||
for(size_t i = 0; i < mapSize; i++) {
|
if(!map)
|
||||||
if(map[i].key.namespaceIndex == key.namespaceIndex &&
|
return NULL;
|
||||||
UA_String_equal(&map[i].key.name, &key.name))
|
for(size_t i = 0; i < map->mapSize; i++) {
|
||||||
return &map[i].value;
|
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;
|
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 *
|
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_QualifiedName key,
|
||||||
const UA_DataType *type) {
|
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))
|
if(!v || !UA_Variant_hasScalarType(v, type))
|
||||||
return NULL;
|
return NULL;
|
||||||
return v->data;
|
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_StatusCode
|
||||||
UA_KeyValueMap_delete(UA_KeyValuePair **map, size_t *mapSize,
|
UA_KeyValueMap_remove(UA_KeyValueMap *map,
|
||||||
const UA_QualifiedName key) {
|
const UA_QualifiedName key) {
|
||||||
UA_KeyValuePair *m = *map;
|
if(!map)
|
||||||
size_t s = *mapSize;
|
return UA_STATUSCODE_BADINVALIDARGUMENT;
|
||||||
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;
|
|
||||||
|
|
||||||
/* Clean the pair */
|
UA_KeyValuePair *m = map->map;
|
||||||
UA_KeyValuePair_clear(&m[i]);
|
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 */
|
/* Clean the slot and move the last entry to fill the slot */
|
||||||
if(s > 1 && i < s - 1) {
|
UA_KeyValuePair_clear(&m[i]);
|
||||||
m[i] = m[s-1];
|
if(s > 1 && i < s - 1) {
|
||||||
UA_KeyValuePair_init(&m[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_StatusCode
|
||||||
&UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
|
UA_KeyValueMap_copy(const UA_KeyValueMap *src, UA_KeyValueMap *dst) {
|
||||||
(void)res;
|
if(!dst)
|
||||||
*mapSize = s - 1; /* In case resize fails, keep the longer original
|
return UA_STATUSCODE_BADINVALIDARGUMENT;
|
||||||
* array around. Resize never fails when reducing
|
if(!src) {
|
||||||
* the size to zero. Reduce the size integer in
|
dst->map = NULL;
|
||||||
* any case. */
|
dst->mapSize = 0;
|
||||||
return UA_STATUSCODE_GOOD;
|
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;
|
||||||
}
|
}
|
||||||
|
@ -239,6 +239,7 @@ endif()
|
|||||||
ua_add_test(check_types_custom.c)
|
ua_add_test(check_types_custom.c)
|
||||||
ua_add_test(check_chunking.c)
|
ua_add_test(check_chunking.c)
|
||||||
ua_add_test(check_utils.c)
|
ua_add_test(check_utils.c)
|
||||||
|
ua_add_test(check_kvm_utils.c)
|
||||||
ua_add_test(check_securechannel.c)
|
ua_add_test(check_securechannel.c)
|
||||||
ua_add_test(check_timer.c)
|
ua_add_test(check_timer.c)
|
||||||
ua_add_test(check_eventloop.c)
|
ua_add_test(check_eventloop.c)
|
||||||
|
@ -26,8 +26,7 @@ typedef struct TestContext {
|
|||||||
static void
|
static void
|
||||||
connectionCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
|
connectionCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
|
||||||
void *application, void **connectionContext,
|
void *application, void **connectionContext,
|
||||||
UA_ConnectionState status,
|
UA_ConnectionState status, const UA_KeyValueMap *params,
|
||||||
size_t paramsSize, const UA_KeyValuePair *params,
|
|
||||||
UA_ByteString msg) {
|
UA_ByteString msg) {
|
||||||
TestContext *ctx = (TestContext*) *connectionContext;
|
TestContext *ctx = (TestContext*) *connectionContext;
|
||||||
if(status == UA_CONNECTIONSTATE_CLOSING) {
|
if(status == UA_CONNECTIONSTATE_CLOSING) {
|
||||||
@ -48,10 +47,9 @@ connectionCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
|
|||||||
clientId = connectionId;
|
clientId = connectionId;
|
||||||
|
|
||||||
/* The remote-hostname is set during the first callback */
|
/* The remote-hostname is set during the first callback */
|
||||||
if(paramsSize > 0) {
|
if(params->mapSize> 0) {
|
||||||
const void *hn =
|
const void *hn =
|
||||||
UA_KeyValueMap_getScalar(params, paramsSize,
|
UA_KeyValueMap_getScalar(params, UA_QUALIFIEDNAME(0, "remote-hostname"),
|
||||||
UA_QUALIFIEDNAME(0, "remote-hostname"),
|
|
||||||
&UA_TYPES[UA_TYPES_STRING]);
|
&UA_TYPES[UA_TYPES_STRING]);
|
||||||
ck_assert(hn != NULL);
|
ck_assert(hn != NULL);
|
||||||
}
|
}
|
||||||
@ -79,7 +77,7 @@ START_TEST(listenETH) {
|
|||||||
UA_String address = UA_STRING(MULTICAST_MAC_ADDRESS);
|
UA_String address = UA_STRING(MULTICAST_MAC_ADDRESS);
|
||||||
UA_Boolean listen = true;
|
UA_Boolean listen = true;
|
||||||
|
|
||||||
UA_KeyValuePair params[5];
|
UA_KeyValuePair params[3];
|
||||||
params[0].key = UA_QUALIFIEDNAME(0, "interface");
|
params[0].key = UA_QUALIFIEDNAME(0, "interface");
|
||||||
UA_Variant_setScalar(¶ms[0].value, &interface, &UA_TYPES[UA_TYPES_STRING]);
|
UA_Variant_setScalar(¶ms[0].value, &interface, &UA_TYPES[UA_TYPES_STRING]);
|
||||||
params[1].key = UA_QUALIFIEDNAME(0, "address");
|
params[1].key = UA_QUALIFIEDNAME(0, "address");
|
||||||
@ -87,7 +85,8 @@ START_TEST(listenETH) {
|
|||||||
params[2].key = UA_QUALIFIEDNAME(0, "listen");
|
params[2].key = UA_QUALIFIEDNAME(0, "listen");
|
||||||
UA_Variant_setScalar(¶ms[2].value, &listen, &UA_TYPES[UA_TYPES_BOOLEAN]);
|
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_uint_eq(res, UA_STATUSCODE_GOOD);
|
||||||
|
|
||||||
ck_assert(testContext.connCount == 1);
|
ck_assert(testContext.connCount == 1);
|
||||||
@ -138,15 +137,17 @@ START_TEST(connectETH) {
|
|||||||
testContext.connCount = 0;
|
testContext.connCount = 0;
|
||||||
|
|
||||||
/* Don't use the address parameter for listening */
|
/* Don't use the address parameter for listening */
|
||||||
|
UA_KeyValueMap kvm = {3, ¶ms[1]};
|
||||||
UA_StatusCode retval =
|
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);
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
||||||
|
|
||||||
size_t listenSockets = testContext.connCount;
|
size_t listenSockets = testContext.connCount;
|
||||||
|
|
||||||
/* Open a client connection. Don't use the listen parameter.*/
|
/* Open a client connection. Don't use the listen parameter.*/
|
||||||
|
kvm.map = params;
|
||||||
clientId = 0;
|
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);
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
||||||
for(size_t i = 0; i < 2; i++) {
|
for(size_t i = 0; i < 2; i++) {
|
||||||
UA_DateTime next = el->run(el, 1);
|
UA_DateTime next = el->run(el, 1);
|
||||||
@ -161,7 +162,7 @@ START_TEST(connectETH) {
|
|||||||
retval = cm->allocNetworkBuffer(cm, clientId, &snd, strlen(testMsg));
|
retval = cm->allocNetworkBuffer(cm, clientId, &snd, strlen(testMsg));
|
||||||
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
||||||
memcpy(snd.data, testMsg, strlen(testMsg));
|
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);
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
||||||
|
|
||||||
while(!received) {
|
while(!received) {
|
||||||
|
@ -23,7 +23,7 @@ unsigned counter = 0;
|
|||||||
static void
|
static void
|
||||||
interruptCallback(UA_InterruptManager *im,
|
interruptCallback(UA_InterruptManager *im,
|
||||||
uintptr_t interruptHandle, void *interruptContext,
|
uintptr_t interruptHandle, void *interruptContext,
|
||||||
size_t instanceInfosSize, const UA_KeyValuePair *instanceInfos) {
|
const UA_KeyValueMap *instanceInfos) {
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ START_TEST(catchInterrupt) {
|
|||||||
UA_InterruptManager *im = UA_InterruptManager_new_POSIX(UA_STRING("im1"));
|
UA_InterruptManager *im = UA_InterruptManager_new_POSIX(UA_STRING("im1"));
|
||||||
el->registerEventSource(el, &im->eventSource);
|
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);
|
el->start(el);
|
||||||
|
|
||||||
/* Send signal to self*/
|
/* Send signal to self*/
|
||||||
@ -63,11 +63,11 @@ START_TEST(registerDuplicate) {
|
|||||||
el->start(el);
|
el->start(el);
|
||||||
|
|
||||||
UA_StatusCode res =
|
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);
|
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
|
||||||
|
|
||||||
/* Registering the same signal twice must fail */
|
/* 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);
|
ck_assert_uint_ne(res, UA_STATUSCODE_GOOD);
|
||||||
|
|
||||||
/* Stop the EventLoop */
|
/* Stop the EventLoop */
|
||||||
|
@ -21,7 +21,7 @@ static void
|
|||||||
connectionCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
|
connectionCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
|
||||||
void *application, void **connectionContext,
|
void *application, void **connectionContext,
|
||||||
UA_ConnectionState status,
|
UA_ConnectionState status,
|
||||||
size_t paramsSize, const UA_KeyValuePair *params,
|
const UA_KeyValueMap *params,
|
||||||
UA_ByteString msg) {
|
UA_ByteString msg) {
|
||||||
if(status == UA_CONNECTIONSTATE_CLOSING) {
|
if(status == UA_CONNECTIONSTATE_CLOSING) {
|
||||||
UA_LOG_DEBUG(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
|
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].key = UA_QUALIFIEDNAME(0, "listen-port");
|
||||||
params[0].value = portVar;
|
params[0].value = portVar;
|
||||||
|
|
||||||
|
UA_KeyValueMap paramsMap;
|
||||||
|
paramsMap.map = params;
|
||||||
|
paramsMap.mapSize = 1;
|
||||||
|
|
||||||
ck_assert_uint_eq(connCount, 0);
|
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);
|
ck_assert(connCount > 0);
|
||||||
|
|
||||||
@ -106,9 +110,13 @@ START_TEST(connectTCP) {
|
|||||||
params[0].key = UA_QUALIFIEDNAME(0, "listen-port");
|
params[0].key = UA_QUALIFIEDNAME(0, "listen-port");
|
||||||
params[0].value = portVar;
|
params[0].value = portVar;
|
||||||
|
|
||||||
|
UA_KeyValueMap paramsMap;
|
||||||
|
paramsMap.map = params;
|
||||||
|
paramsMap.mapSize = 1;
|
||||||
|
|
||||||
connCount = 0;
|
connCount = 0;
|
||||||
|
|
||||||
cm->openConnection(cm, 1, params, NULL, NULL, connectionCallback);
|
cm->openConnection(cm, ¶msMap, NULL, NULL, connectionCallback);
|
||||||
|
|
||||||
size_t listenSockets = connCount;
|
size_t listenSockets = connCount;
|
||||||
|
|
||||||
@ -121,8 +129,10 @@ START_TEST(connectTCP) {
|
|||||||
params[1].key = UA_QUALIFIEDNAME(0, "hostname");
|
params[1].key = UA_QUALIFIEDNAME(0, "hostname");
|
||||||
UA_Variant_setScalar(¶ms[1].value, &targetHost, &UA_TYPES[UA_TYPES_STRING]);
|
UA_Variant_setScalar(¶ms[1].value, &targetHost, &UA_TYPES[UA_TYPES_STRING]);
|
||||||
|
|
||||||
|
paramsMap.mapSize = 2;
|
||||||
|
|
||||||
UA_StatusCode retval =
|
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);
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
||||||
for(size_t i = 0; i < 2; i++) {
|
for(size_t i = 0; i < 2; i++) {
|
||||||
UA_DateTime next = el->run(el, 1);
|
UA_DateTime next = el->run(el, 1);
|
||||||
@ -138,7 +148,7 @@ START_TEST(connectTCP) {
|
|||||||
retval = cm->allocNetworkBuffer(cm, clientId, &snd, strlen(testMsg));
|
retval = cm->allocNetworkBuffer(cm, clientId, &snd, strlen(testMsg));
|
||||||
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
||||||
memcpy(snd.data, testMsg, strlen(testMsg));
|
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);
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
||||||
for(size_t i = 0; i < 2; i++) {
|
for(size_t i = 0; i < 2; i++) {
|
||||||
UA_DateTime next = el->run(el, 1);
|
UA_DateTime next = el->run(el, 1);
|
||||||
|
@ -24,7 +24,7 @@ static void
|
|||||||
connectionCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
|
connectionCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
|
||||||
void *application, void **connectionContext,
|
void *application, void **connectionContext,
|
||||||
UA_ConnectionState status,
|
UA_ConnectionState status,
|
||||||
size_t paramsSize, const UA_KeyValuePair *params,
|
const UA_KeyValueMap *params,
|
||||||
UA_ByteString msg) {
|
UA_ByteString msg) {
|
||||||
TestContext *ctx = (TestContext*) *connectionContext;
|
TestContext *ctx = (TestContext*) *connectionContext;
|
||||||
if(status == UA_CONNECTIONSTATE_CLOSING) {
|
if(status == UA_CONNECTIONSTATE_CLOSING) {
|
||||||
@ -45,9 +45,9 @@ connectionCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
|
|||||||
clientId = connectionId;
|
clientId = connectionId;
|
||||||
|
|
||||||
/* The remote-hostname is set during the first callback */
|
/* The remote-hostname is set during the first callback */
|
||||||
if(paramsSize > 0) {
|
if(!UA_KeyValueMap_isEmpty(params)) {
|
||||||
const void *hn =
|
const void *hn =
|
||||||
UA_KeyValueMap_getScalar(params, paramsSize,
|
UA_KeyValueMap_getScalar(params,
|
||||||
UA_QUALIFIEDNAME(0, "remote-hostname"),
|
UA_QUALIFIEDNAME(0, "remote-hostname"),
|
||||||
&UA_TYPES[UA_TYPES_STRING]);
|
&UA_TYPES[UA_TYPES_STRING]);
|
||||||
ck_assert(hn != NULL);
|
ck_assert(hn != NULL);
|
||||||
@ -79,8 +79,11 @@ START_TEST(listenUDP) {
|
|||||||
UA_KeyValuePair params[1];
|
UA_KeyValuePair params[1];
|
||||||
params[0].key = UA_QUALIFIEDNAME(0, "listen-port");
|
params[0].key = UA_QUALIFIEDNAME(0, "listen-port");
|
||||||
params[0].value = portVar;
|
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);
|
ck_assert(testContext.connCount > 0);
|
||||||
|
|
||||||
@ -133,8 +136,12 @@ START_TEST(connectUDPValidationSucceeds) {
|
|||||||
TestContext testContext;
|
TestContext testContext;
|
||||||
testContext.connCount = 0;
|
testContext.connCount = 0;
|
||||||
|
|
||||||
|
UA_KeyValueMap paramsMap;
|
||||||
|
paramsMap.map = params;
|
||||||
|
paramsMap.mapSize = 3;
|
||||||
|
|
||||||
UA_StatusCode retval =
|
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);
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
||||||
|
|
||||||
/* Open a client connection */
|
/* Open a client connection */
|
||||||
@ -148,7 +155,10 @@ START_TEST(connectUDPValidationSucceeds) {
|
|||||||
params[2].key = UA_QUALIFIEDNAME(0, "validate");
|
params[2].key = UA_QUALIFIEDNAME(0, "validate");
|
||||||
params[2].value = validateVar;
|
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);
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
||||||
el->free(el);
|
el->free(el);
|
||||||
el = NULL;
|
el = NULL;
|
||||||
@ -182,8 +192,12 @@ START_TEST(connectUDPValidationFails) {
|
|||||||
TestContext testContext;
|
TestContext testContext;
|
||||||
testContext.connCount = 0;
|
testContext.connCount = 0;
|
||||||
|
|
||||||
|
UA_KeyValueMap paramsMap;
|
||||||
|
paramsMap.map = params;
|
||||||
|
paramsMap.mapSize = 3;
|
||||||
|
|
||||||
UA_StatusCode retval =
|
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);
|
ck_assert_uint_eq(retval, UA_STATUSCODE_BADCONNECTIONREJECTED);
|
||||||
|
|
||||||
/* Open a client connection */
|
/* Open a client connection */
|
||||||
@ -197,7 +211,7 @@ START_TEST(connectUDPValidationFails) {
|
|||||||
params[2].key = UA_QUALIFIEDNAME(0, "validate");
|
params[2].key = UA_QUALIFIEDNAME(0, "validate");
|
||||||
params[2].value = validateVar;
|
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);
|
ck_assert_uint_eq(retval, UA_STATUSCODE_BADCONNECTIONREJECTED);
|
||||||
el->free(el);
|
el->free(el);
|
||||||
el = NULL;
|
el = NULL;
|
||||||
@ -216,12 +230,15 @@ START_TEST(connectUDP) {
|
|||||||
UA_KeyValuePair params[2];
|
UA_KeyValuePair params[2];
|
||||||
params[0].key = UA_QUALIFIEDNAME(0, "listen-port");
|
params[0].key = UA_QUALIFIEDNAME(0, "listen-port");
|
||||||
params[0].value = portVar;
|
params[0].value = portVar;
|
||||||
|
UA_KeyValueMap paramsMap;
|
||||||
|
paramsMap.map = params;
|
||||||
|
paramsMap.mapSize = 1;
|
||||||
|
|
||||||
TestContext testContext;
|
TestContext testContext;
|
||||||
testContext.connCount = 0;
|
testContext.connCount = 0;
|
||||||
|
|
||||||
UA_StatusCode retval =
|
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);
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
||||||
|
|
||||||
size_t listenSockets = testContext.connCount;
|
size_t listenSockets = testContext.connCount;
|
||||||
@ -234,7 +251,9 @@ START_TEST(connectUDP) {
|
|||||||
params[1].key = UA_QUALIFIEDNAME(0, "hostname");
|
params[1].key = UA_QUALIFIEDNAME(0, "hostname");
|
||||||
UA_Variant_setScalar(¶ms[1].value, &targetHost, &UA_TYPES[UA_TYPES_STRING]);
|
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);
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
||||||
for(size_t i = 0; i < 2; i++) {
|
for(size_t i = 0; i < 2; i++) {
|
||||||
UA_DateTime next = el->run(el, 1);
|
UA_DateTime next = el->run(el, 1);
|
||||||
@ -249,7 +268,7 @@ START_TEST(connectUDP) {
|
|||||||
retval = cm->allocNetworkBuffer(cm, clientId, &snd, strlen(testMsg));
|
retval = cm->allocNetworkBuffer(cm, clientId, &snd, strlen(testMsg));
|
||||||
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
||||||
memcpy(snd.data, testMsg, strlen(testMsg));
|
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);
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
||||||
for(size_t i = 0; i < 2; i++) {
|
for(size_t i = 0; i < 2; i++) {
|
||||||
UA_DateTime next = el->run(el, 1);
|
UA_DateTime next = el->run(el, 1);
|
||||||
@ -302,11 +321,15 @@ START_TEST(udpTalkerAndListener) {
|
|||||||
params[0].key = UA_QUALIFIEDNAME(0, "listen-port");
|
params[0].key = UA_QUALIFIEDNAME(0, "listen-port");
|
||||||
params[0].value = portVar;
|
params[0].value = portVar;
|
||||||
|
|
||||||
|
UA_KeyValueMap paramsMap;
|
||||||
|
paramsMap.map = params;
|
||||||
|
paramsMap.mapSize = 1;
|
||||||
|
|
||||||
TestContext testContext;
|
TestContext testContext;
|
||||||
testContext.connCount = 0;
|
testContext.connCount = 0;
|
||||||
|
|
||||||
UA_StatusCode retval =
|
UA_StatusCode retval =
|
||||||
cmListener->openConnection(cmListener, 1, params, NULL, &testContext,
|
cmListener->openConnection(cmListener, ¶msMap, NULL, &testContext,
|
||||||
connectionCallback);
|
connectionCallback);
|
||||||
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
||||||
|
|
||||||
@ -321,7 +344,9 @@ START_TEST(udpTalkerAndListener) {
|
|||||||
params[1].key = UA_QUALIFIEDNAME(0, "hostname");
|
params[1].key = UA_QUALIFIEDNAME(0, "hostname");
|
||||||
UA_Variant_setScalar(¶ms[1].value, &targetHost, &UA_TYPES[UA_TYPES_STRING]);
|
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);
|
connectionCallback);
|
||||||
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
||||||
|
|
||||||
@ -340,7 +365,7 @@ START_TEST(udpTalkerAndListener) {
|
|||||||
retval = cmTalker->allocNetworkBuffer(cmTalker, clientId, &snd, strlen(testMsg));
|
retval = cmTalker->allocNetworkBuffer(cmTalker, clientId, &snd, strlen(testMsg));
|
||||||
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
||||||
memcpy(snd.data, testMsg, strlen(testMsg));
|
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);
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
||||||
for(size_t i = 0; i < 2; i++) {
|
for(size_t i = 0; i < 2; i++) {
|
||||||
UA_DateTime next = elListener->run(elListener, 1);
|
UA_DateTime next = elListener->run(elListener, 1);
|
||||||
@ -408,12 +433,15 @@ START_TEST(udpTalkerAndListenerDifferentDestination) {
|
|||||||
UA_KeyValuePair listenParams[2];
|
UA_KeyValuePair listenParams[2];
|
||||||
listenParams[0].key = UA_QUALIFIEDNAME(0, "listen-port");
|
listenParams[0].key = UA_QUALIFIEDNAME(0, "listen-port");
|
||||||
listenParams[0].value = portVar;
|
listenParams[0].value = portVar;
|
||||||
|
UA_KeyValueMap listenParamsMap;
|
||||||
|
listenParamsMap.map = listenParams;
|
||||||
|
listenParamsMap.mapSize = 1;
|
||||||
|
|
||||||
TestContext testContext;
|
TestContext testContext;
|
||||||
testContext.connCount = 0;
|
testContext.connCount = 0;
|
||||||
|
|
||||||
UA_StatusCode retval =
|
UA_StatusCode retval =
|
||||||
cmListener->openConnection(cmListener, 1, listenParams, NULL, &testContext,
|
cmListener->openConnection(cmListener, &listenParamsMap, NULL, &testContext,
|
||||||
connectionCallback);
|
connectionCallback);
|
||||||
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
||||||
|
|
||||||
@ -428,8 +456,11 @@ START_TEST(udpTalkerAndListenerDifferentDestination) {
|
|||||||
connectionParams[0].value = portVar;
|
connectionParams[0].value = portVar;
|
||||||
connectionParams[1].key = UA_QUALIFIEDNAME(0, "hostname");
|
connectionParams[1].key = UA_QUALIFIEDNAME(0, "hostname");
|
||||||
UA_Variant_setScalar(&connectionParams[1].value, &connectionTargetHost, &UA_TYPES[UA_TYPES_STRING]);
|
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);
|
connectionCallback);
|
||||||
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
||||||
|
|
||||||
@ -456,7 +487,11 @@ START_TEST(udpTalkerAndListenerDifferentDestination) {
|
|||||||
sendParams[1].key = UA_QUALIFIEDNAME(0, "hostname");
|
sendParams[1].key = UA_QUALIFIEDNAME(0, "hostname");
|
||||||
UA_Variant_setScalar(&sendParams[1].value, &sendTargetHost, &UA_TYPES[UA_TYPES_STRING]);
|
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);
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
||||||
for(size_t i = 0; i < 2; i++) {
|
for(size_t i = 0; i < 2; i++) {
|
||||||
UA_DateTime next = elListener->run(elListener, 1);
|
UA_DateTime next = elListener->run(elListener, 1);
|
||||||
|
183
tests/check_kvm_utils.c
Normal file
183
tests/check_kvm_utils.c
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -63,7 +63,7 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|||||||
void *ctx;
|
void *ctx;
|
||||||
UA_Server_networkCallback(&testConnectionManagerTCP, 0, server,
|
UA_Server_networkCallback(&testConnectionManagerTCP, 0, server,
|
||||||
&ctx, UA_CONNECTIONSTATE_ESTABLISHED,
|
&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
|
// if we got an invalid chunk, the message is not deleted, so delete it here
|
||||||
UA_ByteString_clear(&msg);
|
UA_ByteString_clear(&msg);
|
||||||
|
@ -8,7 +8,7 @@ UA_ByteString *testConnectionLastSentBuf;
|
|||||||
|
|
||||||
static UA_StatusCode
|
static UA_StatusCode
|
||||||
testOpenConnection(UA_ConnectionManager *cm,
|
testOpenConnection(UA_ConnectionManager *cm,
|
||||||
size_t paramsSize, const UA_KeyValuePair *params,
|
const UA_KeyValueMap *params,
|
||||||
void *application, void *context,
|
void *application, void *context,
|
||||||
UA_ConnectionManager_connectionCallback connectionCallback) {
|
UA_ConnectionManager_connectionCallback connectionCallback) {
|
||||||
return UA_STATUSCODE_BADNOTCONNECTED;
|
return UA_STATUSCODE_BADNOTCONNECTED;
|
||||||
@ -16,7 +16,7 @@ testOpenConnection(UA_ConnectionManager *cm,
|
|||||||
|
|
||||||
static UA_StatusCode
|
static UA_StatusCode
|
||||||
testSendWithConnection(UA_ConnectionManager *cm, uintptr_t connectionId,
|
testSendWithConnection(UA_ConnectionManager *cm, uintptr_t connectionId,
|
||||||
size_t paramsSize, const UA_KeyValuePair *params,
|
const UA_KeyValueMap *params,
|
||||||
UA_ByteString *buf) {
|
UA_ByteString *buf) {
|
||||||
if(testConnectionLastSentBuf) {
|
if(testConnectionLastSentBuf) {
|
||||||
UA_ByteString_clear(testConnectionLastSentBuf);
|
UA_ByteString_clear(testConnectionLastSentBuf);
|
||||||
|
Loading…
Reference in New Issue
Block a user