Skip to content

Commit 173044c

Browse files
committed
server config UPDATE thread safe config apply
1 parent 5c13f2c commit 173044c

File tree

2 files changed

+64
-8
lines changed

2 files changed

+64
-8
lines changed

src/server_config.c

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5870,6 +5870,41 @@ nc_server_config_cert_exp_notif_thread_wakeup(void)
58705870

58715871
#endif /* NC_ENABLED_SSH_TLS */
58725872

5873+
/**
5874+
* @brief Wait for any pending updates to complete, then mark the server as "applying configuration".
5875+
*
5876+
* @return 0 on success, 1 on timeout.
5877+
*/
5878+
static int
5879+
nc_server_config_update_start(void)
5880+
{
5881+
struct timespec ts_timeout;
5882+
5883+
/* get the time point of timeout */
5884+
nc_timeouttime_get(&ts_timeout, NC_SERVER_CONFIG_UPDATE_WAIT_TIMEOUT_SEC * 1000);
5885+
5886+
while (nc_timeouttime_cur_diff(&ts_timeout) > 0) {
5887+
/* WR LOCK */
5888+
pthread_rwlock_wrlock(&server_opts.config_lock);
5889+
5890+
if (!server_opts.applying_config) {
5891+
/* set the flag and end */
5892+
server_opts.applying_config = 1;
5893+
5894+
/* UNLOCK */
5895+
pthread_rwlock_unlock(&server_opts.config_lock);
5896+
return 0;
5897+
}
5898+
5899+
/* UNLOCK and wait */
5900+
pthread_rwlock_unlock(&server_opts.config_lock);
5901+
usleep(NC_TIMEOUT_STEP);
5902+
}
5903+
5904+
ERR(NULL, "Timeout expired while waiting for the server to apply the previous configuration.");
5905+
return 1;
5906+
}
5907+
58735908
API int
58745909
nc_server_config_setup_diff(const struct lyd_node *data)
58755910
{
@@ -5878,6 +5913,9 @@ nc_server_config_setup_diff(const struct lyd_node *data)
58785913

58795914
NC_CHECK_ARG_RET(NULL, data, 1);
58805915

5916+
/* wait until previous is done, then mark us as applying */
5917+
NC_CHECK_RET(nc_server_config_update_start());
5918+
58815919
/* CONFIG RD LOCK */
58825920
pthread_rwlock_rdlock(&server_opts.config_lock);
58835921

@@ -5919,11 +5957,10 @@ nc_server_config_setup_diff(const struct lyd_node *data)
59195957
ERR(NULL, "Dispatching new call-home threads failed."), cleanup_unlock);
59205958
#endif /* NC_ENABLED_SSH_TLS */
59215959

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

59285965
#ifdef NC_ENABLED_SSH_TLS
59295966
/* wake up the cert expiration notif thread */
@@ -5940,6 +5977,11 @@ nc_server_config_setup_diff(const struct lyd_node *data)
59405977
nc_server_config_free(&config_copy);
59415978
}
59425979

5980+
/* clear the applying_config flag */
5981+
pthread_rwlock_wrlock(&server_opts.config_lock);
5982+
server_opts.applying_config = 0;
5983+
pthread_rwlock_unlock(&server_opts.config_lock);
5984+
59435985
return ret;
59445986
}
59455987

@@ -5952,6 +5994,9 @@ nc_server_config_setup_data(const struct lyd_node *data)
59525994

59535995
NC_CHECK_ARG_RET(NULL, data, 1);
59545996

5997+
/* wait until previous is done, then mark us as applying */
5998+
NC_CHECK_RET(nc_server_config_update_start());
5999+
59556000
/* check that the config data are not diff (no op attr) */
59566001
LY_LIST_FOR(data, tree) {
59576002
LYD_TREE_DFS_BEGIN(tree, iter) {
@@ -6000,11 +6045,10 @@ nc_server_config_setup_data(const struct lyd_node *data)
60006045
ERR(NULL, "Dispatching new call-home connections failed."), cleanup_unlock);
60016046
#endif /* NC_ENABLED_SSH_TLS */
60026047

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

60096053
#ifdef NC_ENABLED_SSH_TLS
60106054
/* wake up the cert expiration notif thread */
@@ -6021,6 +6065,11 @@ nc_server_config_setup_data(const struct lyd_node *data)
60216065
nc_server_config_free(&config);
60226066
}
60236067

6068+
/* clear the applying_config flag */
6069+
pthread_rwlock_wrlock(&server_opts.config_lock);
6070+
server_opts.applying_config = 0;
6071+
pthread_rwlock_unlock(&server_opts.config_lock);
6072+
60246073
return ret;
60256074
}
60266075

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)