From e7b8d069e7f626b8cbe2afabe6e6a49226628beb Mon Sep 17 00:00:00 2001 From: Roman Janota Date: Thu, 16 Apr 2026 16:10:34 +0200 Subject: [PATCH 1/4] session server BUGFIX intervals init out params --- src/session_server.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/session_server.c b/src/session_server.c index 72bbe023..a3268b1b 100644 --- a/src/session_server.c +++ b/src/session_server.c @@ -4551,6 +4551,9 @@ nc_server_notif_cert_exp_intervals_get(struct nc_cert_exp_time_interval *default { int rc = 0; + *intervals = NULL; + *interval_count = 0; + /* CONFIG LOCK */ if (nc_rwlock_lock(&server_opts.config_lock, NC_RWLOCK_READ, NC_CONFIG_LOCK_TIMEOUT, __func__) != 1) { return 1; From cdc7401d083b820978eb0201190229b5ef3d44b3 Mon Sep 17 00:00:00 2001 From: Roman Janota Date: Thu, 16 Apr 2026 16:12:45 +0200 Subject: [PATCH 2/4] session server UPDATE make thread running flag atomic --- src/session_p.h | 3 ++- src/session_server.c | 56 ++++++++------------------------------------ 2 files changed, 12 insertions(+), 47 deletions(-) diff --git a/src/session_p.h b/src/session_p.h index fe254693..7162c204 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -693,7 +693,8 @@ struct nc_server_ch_thread_arg { void *new_session_fail_cb_data; /**< new session fail cb data */ pthread_t tid; /**< Thread ID of the Call Home client thread. */ - int thread_running; /**< A boolean value that is truthy while the underlying Call Home thread is running */ + ATOMIC_T thread_running; /**< Non-zero while the Call Home thread is running. Atomic for lock-free checks, + but also used with the condition variable under cond_lock for signalling. */ pthread_mutex_t cond_lock; /**< Condition's lock used for signalling the thread to terminate */ pthread_cond_t cond; /**< Condition used for signalling the thread to terminate */ }; diff --git a/src/session_server.c b/src/session_server.c index a3268b1b..43bf0b14 100644 --- a/src/session_server.c +++ b/src/session_server.c @@ -3301,33 +3301,6 @@ nc_server_ch_client_get_idle_timeout(const char *client_name, uint32_t *idle_tim return ret; } -/** - * @brief Checks if a Call Home thread should terminate. - * - * Checks the shared boolean variable thread_running. This should be done everytime - * before entering a critical section. - * - * @param[in] data Call Home thread's data. - * @return 1 if running, 0 if the thread should terminate, -1 on error. - */ -static int -nc_server_ch_client_thread_is_running(struct nc_server_ch_thread_arg *data) -{ - int rc = -1; - - /* COND LOCK */ - if (nc_mutex_lock(&data->cond_lock, NC_CH_COND_LOCK_TIMEOUT, __func__) != 1) { - return -1; - } - - rc = data->thread_running; - - /* COND UNLOCK */ - nc_mutex_unlock(&data->cond_lock, __func__); - - return rc; -} - /** * @brief Wait for any event after a NC session was established on a CH client. * @@ -3411,11 +3384,7 @@ nc_server_ch_client_thread_session_cond_wait(struct nc_server_ch_thread_arg *dat } /* check if the thread should terminate */ - r = nc_server_ch_client_thread_is_running(data); - if (r != 1) { - if (r == -1) { - rc = -1; - } + if (!ATOMIC_LOAD_RELAXED(data->thread_running)) { terminate = 1; } @@ -3467,7 +3436,7 @@ static int nc_server_ch_client_thread_is_running_wait(struct nc_session *session, struct nc_server_ch_thread_arg *data, uint64_t cond_wait_time) { struct timespec ts; - int ret = 0, thread_running; + int ret = 0; /* COND LOCK */ if (nc_mutex_lock(&data->cond_lock, NC_CH_COND_LOCK_TIMEOUT, __func__) != 1) { @@ -3475,15 +3444,14 @@ nc_server_ch_client_thread_is_running_wait(struct nc_session *session, struct nc } /* get reconnect timeout in ms */ nc_timeouttime_get(&ts, cond_wait_time * 1000); - while (!ret && data->thread_running) { + while (!ret && ATOMIC_LOAD_RELAXED(data->thread_running)) { ret = pthread_cond_clockwait(&data->cond, &data->cond_lock, COMPAT_CLOCK_ID, &ts); } - thread_running = data->thread_running; /* COND UNLOCK */ nc_mutex_unlock(&data->cond_lock, __func__); - if (!thread_running) { + if (!ATOMIC_LOAD_RELAXED(data->thread_running)) { /* thread is terminating */ VRB(session, "Call Home thread signaled to exit, client \"%s\" probably removed.", data->client_name); ret = 0; @@ -3513,7 +3481,7 @@ nc_server_ch_client_with_endpt_get(struct nc_server_ch_thread_arg *data, const c { struct nc_ch_client *client; - while (nc_server_ch_client_thread_is_running(data)) { + while (ATOMIC_LOAD_RELAXED(data->thread_running)) { /* get the client */ client = nc_server_ch_client_get(name); if (!client) { @@ -3561,11 +3529,7 @@ nc_ch_client_thread(void *arg) uint32_t reconnect_in; /* mark the thread as running */ - if (nc_mutex_lock(&data->cond_lock, NC_CH_COND_LOCK_TIMEOUT, __func__) != 1) { - goto cleanup; - } - data->thread_running = 1; - nc_mutex_unlock(&data->cond_lock, __func__); + ATOMIC_STORE_RELAXED(data->thread_running, 1); /* CONFIG READ LOCK */ if (nc_rwlock_lock(&server_opts.config_lock, NC_RWLOCK_READ, NC_CONFIG_LOCK_TIMEOUT, __func__) != 1) { @@ -3583,7 +3547,7 @@ nc_ch_client_thread(void *arg) cur_endpt = &client->ch_endpts[0]; cur_endpt_name = strdup(cur_endpt->name); - while (nc_server_ch_client_thread_is_running(data)) { + while (ATOMIC_LOAD_RELAXED(data->thread_running)) { if (!cur_attempts) { VRB(NULL, "Call Home client \"%s\" endpoint \"%s\" connecting...", data->client_name, cur_endpt_name); } @@ -3594,7 +3558,7 @@ nc_ch_client_thread(void *arg) /* CONFIG READ UNLOCK - session established */ nc_rwlock_unlock(&server_opts.config_lock, __func__); - if (!nc_server_ch_client_thread_is_running(data)) { + if (!ATOMIC_LOAD_RELAXED(data->thread_running)) { /* thread should stop running */ goto cleanup; } @@ -3607,7 +3571,7 @@ nc_ch_client_thread(void *arg) session = NULL; VRB(NULL, "Call Home client \"%s\" session terminated.", data->client_name); - if (!nc_server_ch_client_thread_is_running(data)) { + if (!ATOMIC_LOAD_RELAXED(data->thread_running)) { /* thread should stop running */ goto cleanup; } @@ -3792,7 +3756,7 @@ nc_session_server_ch_client_dispatch_stop(struct nc_ch_client *ch_client) } /* notify the thread to stop */ - thread_arg->thread_running = 0; + ATOMIC_STORE_RELAXED(thread_arg->thread_running, 0); tid = thread_arg->tid; pthread_cond_signal(&thread_arg->cond); From 19b0349a02fde31b25df67921011fff4f8e78e39 Mon Sep 17 00:00:00 2001 From: Roman Janota Date: Thu, 16 Apr 2026 16:15:31 +0200 Subject: [PATCH 3/4] SOVERSION bump to version 5.3.8 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 14781983..fee57d75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,7 +66,7 @@ set(LIBNETCONF2_VERSION ${LIBNETCONF2_MAJOR_VERSION}.${LIBNETCONF2_MINOR_VERSION # with backward compatible change and micro version is connected with any internal change of the library. set(LIBNETCONF2_MAJOR_SOVERSION 5) set(LIBNETCONF2_MINOR_SOVERSION 3) -set(LIBNETCONF2_MICRO_SOVERSION 7) +set(LIBNETCONF2_MICRO_SOVERSION 8) set(LIBNETCONF2_SOVERSION_FULL ${LIBNETCONF2_MAJOR_SOVERSION}.${LIBNETCONF2_MINOR_SOVERSION}.${LIBNETCONF2_MICRO_SOVERSION}) set(LIBNETCONF2_SOVERSION ${LIBNETCONF2_MAJOR_SOVERSION}) From 3be0c2c8b95c5202da95985abd86be75e12cff77 Mon Sep 17 00:00:00 2001 From: Roman Janota Date: Thu, 16 Apr 2026 16:15:38 +0200 Subject: [PATCH 4/4] VERSION bump to version 4.3.2 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fee57d75..aec95476 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,7 +58,7 @@ set(CMAKE_MACOSX_RPATH TRUE) # micro version is changed with a set of small changes or bugfixes anywhere in the project. set(LIBNETCONF2_MAJOR_VERSION 4) set(LIBNETCONF2_MINOR_VERSION 3) -set(LIBNETCONF2_MICRO_VERSION 1) +set(LIBNETCONF2_MICRO_VERSION 2) set(LIBNETCONF2_VERSION ${LIBNETCONF2_MAJOR_VERSION}.${LIBNETCONF2_MINOR_VERSION}.${LIBNETCONF2_MICRO_VERSION}) # Version of the library