Skip to content

Commit b7012f4

Browse files
Roytakmichalvasko
authored andcommitted
server config UPDATE thread safe config apply
1 parent 3e28bcf commit b7012f4

File tree

2 files changed

+92
-8
lines changed

2 files changed

+92
-8
lines changed

src/server_config.c

Lines changed: 83 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include <assert.h>
1919
#include <ctype.h>
20+
#include <errno.h>
2021
#include <grp.h>
2122
#include <pthread.h>
2223
#include <pwd.h>
@@ -5870,6 +5871,76 @@ nc_server_config_cert_exp_notif_thread_wakeup(void)
58705871

58715872
#endif /* NC_ENABLED_SSH_TLS */
58725873

5874+
/**
5875+
* @brief Wait for any pending updates to complete, then mark the server as "applying configuration".
5876+
*
5877+
* @return 0 on success, 1 on timeout.
5878+
*/
5879+
static int
5880+
nc_server_config_update_start(void)
5881+
{
5882+
int r;
5883+
struct timespec ts_timeout;
5884+
5885+
/* get the time point of timeout */
5886+
nc_timeouttime_get(&ts_timeout, NC_SERVER_CONFIG_UPDATE_WAIT_TIMEOUT_SEC * 1000);
5887+
5888+
while (nc_timeouttime_cur_diff(&ts_timeout) > 0) {
5889+
/* WR LOCK */
5890+
r = pthread_rwlock_clockwrlock(&server_opts.config_lock, COMPAT_CLOCK_ID, &ts_timeout);
5891+
if (r == ETIMEDOUT) {
5892+
break;
5893+
} else if (r) {
5894+
ERR(NULL, "Failed to acquire server configuration write lock (%s).", strerror(r));
5895+
return 1;
5896+
}
5897+
5898+
if (!server_opts.applying_config) {
5899+
/* set the flag and end */
5900+
server_opts.applying_config = 1;
5901+
5902+
/* UNLOCK */
5903+
pthread_rwlock_unlock(&server_opts.config_lock);
5904+
return 0;
5905+
}
5906+
5907+
/* UNLOCK and wait */
5908+
pthread_rwlock_unlock(&server_opts.config_lock);
5909+
usleep(NC_TIMEOUT_STEP);
5910+
}
5911+
5912+
ERR(NULL, "Timeout expired while waiting for the server to apply the previous configuration.");
5913+
return 1;
5914+
}
5915+
5916+
/**
5917+
* @brief Clear the "applying configuration" flag once the configuration update is done.
5918+
*/
5919+
static void
5920+
nc_server_config_update_end(void)
5921+
{
5922+
int r;
5923+
struct timespec ts_timeout;
5924+
5925+
/* get the time point of timeout */
5926+
nc_timeouttime_get(&ts_timeout, NC_SERVER_CONFIG_UPDATE_WAIT_TIMEOUT_SEC * 1000);
5927+
5928+
/* WR LOCK */
5929+
r = pthread_rwlock_clockwrlock(&server_opts.config_lock, COMPAT_CLOCK_ID, &ts_timeout);
5930+
if (r) {
5931+
/* just log the error, there is nothing we can do */
5932+
ERR(NULL, "Failed to acquire server configuration write lock (%s).", strerror(r));
5933+
}
5934+
5935+
/* clear the flag */
5936+
server_opts.applying_config = 0;
5937+
5938+
if (!r) {
5939+
/* UNLOCK only if we locked it */
5940+
pthread_rwlock_unlock(&server_opts.config_lock);
5941+
}
5942+
}
5943+
58735944
API int
58745945
nc_server_config_setup_diff(const struct lyd_node *data)
58755946
{
@@ -5878,6 +5949,9 @@ nc_server_config_setup_diff(const struct lyd_node *data)
58785949

58795950
NC_CHECK_ARG_RET(NULL, data, 1);
58805951

5952+
/* wait until previous is done, then mark us as applying */
5953+
NC_CHECK_RET(nc_server_config_update_start());
5954+
58815955
/* CONFIG RD LOCK */
58825956
pthread_rwlock_rdlock(&server_opts.config_lock);
58835957

@@ -5919,11 +5993,10 @@ nc_server_config_setup_diff(const struct lyd_node *data)
59195993
ERR(NULL, "Dispatching new call-home threads failed."), cleanup_unlock);
59205994
#endif /* NC_ENABLED_SSH_TLS */
59215995

5922-
/* free the old config */
5996+
/* swap: free old, keep new, zero out the copy just in case to avoid double free */
59235997
nc_server_config_free(&server_opts.config);
5924-
5925-
/* replace it with the new one */
59265998
server_opts.config = config_copy;
5999+
memset(&config_copy, 0, sizeof config_copy);
59276000

59286001
#ifdef NC_ENABLED_SSH_TLS
59296002
/* wake up the cert expiration notif thread */
@@ -5939,6 +6012,7 @@ nc_server_config_setup_diff(const struct lyd_node *data)
59396012
/* free the new config in case of error */
59406013
nc_server_config_free(&config_copy);
59416014
}
6015+
nc_server_config_update_end();
59426016

59436017
return ret;
59446018
}
@@ -5952,6 +6026,9 @@ nc_server_config_setup_data(const struct lyd_node *data)
59526026

59536027
NC_CHECK_ARG_RET(NULL, data, 1);
59546028

6029+
/* wait until previous is done, then mark us as applying */
6030+
NC_CHECK_RET(nc_server_config_update_start());
6031+
59556032
/* check that the config data are not diff (no op attr) */
59566033
LY_LIST_FOR(data, tree) {
59576034
LYD_TREE_DFS_BEGIN(tree, iter) {
@@ -6000,11 +6077,10 @@ nc_server_config_setup_data(const struct lyd_node *data)
60006077
ERR(NULL, "Dispatching new call-home connections failed."), cleanup_unlock);
60016078
#endif /* NC_ENABLED_SSH_TLS */
60026079

6003-
/* free the old config */
6080+
/* swap: free old, keep new, zero out the copy just in case to avoid double free */
60046081
nc_server_config_free(&server_opts.config);
6005-
6006-
/* replace it with the new one */
60076082
server_opts.config = config;
6083+
memset(&config, 0, sizeof config);
60086084

60096085
#ifdef NC_ENABLED_SSH_TLS
60106086
/* wake up the cert expiration notif thread */
@@ -6020,6 +6096,7 @@ nc_server_config_setup_data(const struct lyd_node *data)
60206096
/* free the new config in case of error */
60216097
nc_server_config_free(&config);
60226098
}
6099+
nc_server_config_update_end();
60236100

60246101
return ret;
60256102
}

src/session_p.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ extern struct nc_server_opts server_opts;
7878
*/
7979
#define NC_PS_QUEUE_TIMEOUT 5000
8080

81+
/**
82+
* @brief Maximum time (in seconds) to wait for a pending configuration
83+
* update to complete before rejecting a new update request.
84+
*/
85+
#define NC_SERVER_CONFIG_UPDATE_WAIT_TIMEOUT_SEC 5
86+
8187
/**
8288
* Time slept in msec if no endpoint was created for a running Call Home client.
8389
*/
@@ -697,8 +703,9 @@ struct nc_server_opts {
697703

698704
/* ACCESS locked - options modified by YANG data/API - WRITE lock
699705
* - options read when accepting sessions - READ lock */
700-
pthread_rwlock_t config_lock; /**< Lock for the server configuration. */
701-
struct nc_server_config config; /**< YANG Server configuration. */
706+
pthread_rwlock_t config_lock; /**< Lock for the server configuration. */
707+
struct nc_server_config config; /**< YANG Server configuration. */
708+
int applying_config; /**< Flag indicating that the server configuration is currently being applied. */
702709

703710
#ifdef NC_ENABLED_SSH_TLS
704711
char *authkey_path_fmt; /**< Path to users' public keys that may contain tokens with special meaning. */

0 commit comments

Comments
 (0)