Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/1.4' into merge_14_master_3
Browse files Browse the repository at this point in the history
  • Loading branch information
jpfr committed Sep 6, 2023
2 parents 3ad448e + 50f992d commit c4ce4eb
Show file tree
Hide file tree
Showing 29 changed files with 838 additions and 346 deletions.
26 changes: 10 additions & 16 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -612,10 +612,10 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID STREQUAL "Clang")

# Force 32bit build
if(UA_FORCE_32BIT)
if(MSVC)
message(FATAL_ERROR "Select the 32bit (cross-) compiler instead of forcing compiler options")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") # GCC and Clang, possibly more
if(MSVC)
message(FATAL_ERROR "Select the 32bit (cross-) compiler instead of forcing compiler options")
endif()
check_add_cc_flag("-m32") # GCC and Clang, possibly more
endif()

if(NOT MINGW AND NOT UA_BUILD_OSS_FUZZ)
Expand Down Expand Up @@ -1233,17 +1233,6 @@ ua_generate_nodeset(NAME "ns0" FILE ${UA_FILE_NODESETS} ${UA_NODESET_FILE_DA}
IGNORE "${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/NodeID_NS0_Base.txt"
DEPENDS_TARGET "open62541-generator-types")

# stack protector and optimization needs to be disabled for the huge ns0 file, otherwise debian packaging fails due to long build times.
# We also disable optimization on Appveyor builds, since they take almost an hour otherwise
if(UA_PACK_DEBIAN OR (NOT "$ENV{APPVEYOR}" STREQUAL "") OR (
(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel" OR CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") AND (
# List of compilers which have problems with the huge ns0 optimization
(("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") AND (CMAKE_C_COMPILER_VERSION VERSION_LESS 7.0))
)
))
set_source_files_properties(${PROJECT_BINARY_DIR}/src_generated/open62541/namespace0_generated.c PROPERTIES COMPILE_FLAGS "-fno-stack-protector -O0")
endif()

if(UA_ENABLE_NODESET_INJECTOR)
message(STATUS "Nodesetinjector feature enabled")
cmake_minimum_required(VERSION 3.20)
Expand Down Expand Up @@ -1306,6 +1295,7 @@ if(UA_ENABLE_AMALGAMATION)
add_dependencies(open62541-amalgamation-header open62541-generator-namespace)
else()
add_library(open62541-object OBJECT ${lib_sources} ${lib_headers} ${exported_headers})
target_include_directories(open62541-object PRIVATE ${PROJECT_SOURCE_DIR}/src)

add_custom_target(open62541-code-generation DEPENDS
open62541-generator-types
Expand All @@ -1321,7 +1311,11 @@ else()
add_coverage(open62541-object)
endif()

target_include_directories(open62541-object PRIVATE ${PROJECT_SOURCE_DIR}/src)
# stack protector and optimization are disabled for the huge ns0 file
if(UA_NAMESPACE_ZERO STREQUAL "FULL" AND NOT MSVC)
set_source_files_properties(${PROJECT_BINARY_DIR}/src_generated/open62541/namespace0_generated.c
PROPERTIES COMPILE_FLAGS "-fno-stack-protector -O0")
endif()

add_library(open62541-plugins OBJECT ${plugin_sources} ${architecture_sources} ${exported_headers})
add_dependencies(open62541-plugins open62541-generator-types open62541-generator-transport open62541-generator-namespace)
Expand Down
2 changes: 1 addition & 1 deletion arch/eventloop_posix_eth.c
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,7 @@ ETH_openConnection(UA_ConnectionManager *cm, const UA_KeyValueMap *params,
/* Validate the parameters */
UA_StatusCode res =
UA_KeyValueRestriction_validate(el->eventLoop.logger, "ETH", ETHConfigParameters,
ETH_PARAMETERSSIZE, params);
ethParams, params);
if(res != UA_STATUSCODE_GOOD) {
UA_UNLOCK(&el->elMutex);
return res;
Expand Down
35 changes: 10 additions & 25 deletions deps/itoa.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,49 +66,34 @@ UA_UInt16 itoaUnsigned(UA_UInt64 value, char* buffer, UA_Byte base) {
return i;
}

/* adapted from http://www.techiedelight.com/implement-itoa-function-in-c/ to use UA_... types */
/* adapted from http://www.techiedelight.com/implement-itoa-function-in-c/ */
UA_UInt16 itoaSigned(UA_Int64 value, char* buffer) {
/* consider absolute value of number */


UA_UInt64 n;

/* Special case for UA_INT64_MIN which can not simply be negated */
/* it will cause a signed integer overflow */
if (value == UA_INT64_MIN) {
UA_UInt64 n;
if(value == UA_INT64_MIN) {
n = (UA_UInt64)UA_INT64_MAX + 1;
}
else {
} else {
n = (UA_UInt64)value;

if(value < 0){
n = (UA_UInt64)-value;
}
}

UA_UInt16 i = 0;
while (n) {
while(n) {
UA_UInt64 r = n % 10;

if (r >= 10)
buffer[i++] = (char)(65 + (r - 10));
else
buffer[i++] = (char)(48 + r);

buffer[i++] = (char)('0' + r);
n = n / 10;
}

/* if number is 0 */
if (i == 0)
buffer[i++] = '0';

if (value < 0)
if(i == 0)
buffer[i++] = '0'; /* if number is 0 */
if(value < 0)
buffer[i++] = '-';

buffer[i] = '\0'; /* null terminate string */
i--;
/* reverse the string and return it */
reverse(buffer, 0, i);
reverse(buffer, 0, i); /* reverse the string and return it */
i++;
return i;
}
Expand Down
65 changes: 37 additions & 28 deletions include/open62541/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -726,41 +726,37 @@ UA_Client_Service_queryNext(UA_Client *client,
* ---------------------
* All OPC UA services are asynchronous in nature. So several service calls can
* be made without waiting for the individual responses. Depending on the
* server's priorities responses may come in a different ordering than sent.
*
* As noted in :ref:`the client overview<client>` currently no means
* of handling asynchronous events automatically is provided. However, some
* synchronous function calls will trigger handling, but to ensure this
* happens a client should periodically call `UA_Client_run_iterate`
* explicitly.
*
* Connection and session management are also performed in
* `UA_Client_run_iterate`, so to keep a connection healthy any client needs to
* consider how and when it is appropriate to do the call.
* This is especially true for the periodic renewal of a SecureChannel's
* SecurityToken which is designed to have a limited lifetime and will
* invalidate the connection if not renewed.
*
* Use the typed wrappers instead of `__UA_Client_AsyncService` directly. See
* :ref:`client_async`. However, the general mechanism of async service calls is
* explained here.
*/

/* We say that an async service call has been dispatched once
* server's priorities responses may come in a different ordering than sent. Use
* the typed wrappers for async service requests instead of
* `__UA_Client_AsyncService` directly. See :ref:`client_async`. However, the
* general mechanism of async service calls is explained here.
*
* Connection and session management are performed in `UA_Client_run_iterate`,
* so to keep a connection healthy any client needs to consider how and when it
* is appropriate to do the call. This is especially true for the periodic
* renewal of a SecureChannel's SecurityToken which is designed to have a
* limited lifetime and will invalidate the connection if not renewed.
*
* We say that an async service call has been dispatched once
* __UA_Client_AsyncService returns UA_STATUSCODE_GOOD. If there is an error
* after an async service has been dispatched, the callback is called with an
* "empty" response where the StatusCode has been set accordingly. This is also
* done if the client is shutting down and the list of dispatched async services
* is emptied.
*
* The StatusCode received when the client is shutting down is
* UA_STATUSCODE_BADSHUTDOWN.
*
* The StatusCode received when the client doesn't receive response after the
* specified in config->timeout (can be overridden via the "timeoutHint" in the
* request header) is UA_STATUSCODE_BADTIMEOUT.
*
* The userdata and requestId arguments can be NULL. */
* UA_STATUSCODE_BADSHUTDOWN. The StatusCode received when the client doesn't
* receive response after the specified in config->timeout (can be overridden
* via the "timeoutHint" in the request header) is UA_STATUSCODE_BADTIMEOUT.
*
* The userdata and requestId arguments can be NULL. The (optional) requestId
* output can be used to cancel the service while it is still pending. The
* requestId is unique for each service request. Alternatively the requestHandle
* can be manually set (non necessarily unique) in the request header for full
* service call. This can be used to cancel all outstanding requests using that
* handle together. Note that the client will auto-generate a requestHandle
* >100,000 if none is defined. Avoid these when manually setting a requetHandle
* in the requestHeader to avoid clashes. */

typedef void (*UA_ClientAsyncServiceCallback)(UA_Client *client, void *userdata,
UA_UInt32 requestId, void *response);
Expand All @@ -772,6 +768,19 @@ __UA_Client_AsyncService(UA_Client *client, const void *request,
const UA_DataType *responseType,
void *userdata, UA_UInt32 *requestId);

/* Cancel all dispatched requests with the given requestHandle.
* The number if cancelled requests is returned by the server.
* The output argument cancelCount is not set if NULL. */
UA_EXPORT UA_THREADSAFE UA_StatusCode
UA_Client_cancelByRequestHandle(UA_Client *client, UA_UInt32 requestHandle,
UA_UInt32 *cancelCount);

/* Map the requestId to the requestHandle used for that request and call the
* Cancel service for that requestHandle. */
UA_EXPORT UA_THREADSAFE UA_StatusCode
UA_Client_cancelByRequestId(UA_Client *client, UA_UInt32 requestId,
UA_UInt32 *cancelCount);

/* Set new userdata and callback for an existing request.
*
* @param client Pointer to the UA_Client
Expand Down
53 changes: 52 additions & 1 deletion src/client/ua_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,15 @@ sendRequest(UA_Client *client, const void *request,
UA_NodeId oldToken = rr->authenticationToken; /* Put back in place later */
rr->authenticationToken = client->authenticationToken;
rr->timestamp = UA_DateTime_now();
rr->requestHandle = ++client->requestHandle;

/* Create a unique handle >100,000 if not manually defined. The handle is
* not necessarily unique when manually defined and used to cancel async
* service requests. */
if(rr->requestHandle == 0) {
if(UA_UNLIKELY(client->requestHandle < 100000))
client->requestHandle = 100000;
rr->requestHandle = ++client->requestHandle;
}

/* Set the timeout hint if not manually defined */
if(rr->timeoutHint == 0)
Expand Down Expand Up @@ -625,6 +633,7 @@ __Client_Service(UA_Client *client, const void *request,
ac.requestId = requestId;
ac.start = UA_DateTime_nowMonotonic(); /* Start timeout after sending */
ac.timeout = rh->timeoutHint;
ac.requestHandle = rh->requestHandle;
if(ac.timeout == 0)
ac.timeout = UA_UINT32_MAX; /* 0 -> unlimited */

Expand Down Expand Up @@ -809,6 +818,7 @@ __Client_AsyncService(UA_Client *client, const void *request,
ac->syncResponse = NULL;
ac->start = UA_DateTime_nowMonotonic();
ac->timeout = rh->timeoutHint;
ac->requestHandle = rh->requestHandle;
if(ac->timeout == 0)
ac->timeout = UA_UINT32_MAX; /* 0 -> unlimited */

Expand Down Expand Up @@ -838,6 +848,47 @@ __UA_Client_AsyncService(UA_Client *client, const void *request,
return res;
}

static UA_StatusCode
cancelByRequestHandle(UA_Client *client, UA_UInt32 requestHandle, UA_UInt32 *cancelCount) {
UA_CancelRequest creq;
UA_CancelRequest_init(&creq);
creq.requestHandle = requestHandle;
UA_CancelResponse cresp;
UA_CancelResponse_init(&cresp);
__Client_Service(client, &creq, &UA_TYPES[UA_TYPES_CANCELREQUEST],
&cresp, &UA_TYPES[UA_TYPES_CANCELRESPONSE]);
if(cancelCount)
*cancelCount = cresp.cancelCount;
UA_StatusCode res = cresp.responseHeader.serviceResult;
UA_CancelResponse_clear(&cresp);
return res;
}

UA_StatusCode
UA_Client_cancelByRequestHandle(UA_Client *client, UA_UInt32 requestHandle,
UA_UInt32 *cancelCount) {
UA_LOCK(&client->clientMutex);
UA_StatusCode res = cancelByRequestHandle(client, requestHandle, cancelCount);
UA_UNLOCK(&client->clientMutex);
return res;
}

UA_StatusCode
UA_Client_cancelByRequestId(UA_Client *client, UA_UInt32 requestId,
UA_UInt32 *cancelCount) {
UA_LOCK(&client->clientMutex);
UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
AsyncServiceCall *ac;
LIST_FOREACH(ac, &client->asyncServiceCalls, pointers) {
if(ac->requestId != requestId)
continue;
res = cancelByRequestHandle(client, ac->requestHandle, cancelCount);
break;
}
UA_UNLOCK(&client->clientMutex);
return res;
}

/*******************/
/* Timed Callbacks */
/*******************/
Expand Down
Loading

0 comments on commit c4ce4eb

Please sign in to comment.