Skip to content

Commit 2f0a82d

Browse files
committed
session server ch BUGFIX check ch thread running
When ch sess is established, only the status of the sess was checked in a loop, which isn't enough when we just delete a CH client from the config without the client gracefully closing first.
1 parent 8cf2bb0 commit 2f0a82d

1 file changed

Lines changed: 59 additions & 40 deletions

File tree

src/session_server.c

Lines changed: 59 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3270,7 +3270,7 @@ nc_connect_ch_endpt(struct nc_ch_endpt *endpt, nc_server_ch_session_acquire_ctx_
32703270
*
32713271
* @param[in] client_name Name of the Call Home client.
32723272
* @param[out] idle_timeout Idle timeout in seconds.
3273-
* @return 0 on success, 1 if the client was not found.
3273+
* @return 0 on success, 1 if the client was not found, -1 on error.
32743274
*/
32753275
static int
32763276
nc_server_ch_client_get_idle_timeout(const char *client_name, uint32_t *idle_timeout)
@@ -3280,7 +3280,7 @@ nc_server_ch_client_get_idle_timeout(const char *client_name, uint32_t *idle_tim
32803280

32813281
/* CONFIG READ LOCK */
32823282
if (nc_rwlock_lock(&server_opts.config_lock, NC_RWLOCK_READ, NC_CONFIG_LOCK_TIMEOUT, __func__) != 1) {
3283-
return 1;
3283+
return -1;
32843284
}
32853285

32863286
client = nc_server_ch_client_get(client_name);
@@ -3301,6 +3301,33 @@ nc_server_ch_client_get_idle_timeout(const char *client_name, uint32_t *idle_tim
33013301
return ret;
33023302
}
33033303

3304+
/**
3305+
* @brief Checks if a Call Home thread should terminate.
3306+
*
3307+
* Checks the shared boolean variable thread_running. This should be done everytime
3308+
* before entering a critical section.
3309+
*
3310+
* @param[in] data Call Home thread's data.
3311+
* @return 1 if running, 0 if the thread should terminate, -1 on error.
3312+
*/
3313+
static int
3314+
nc_server_ch_client_thread_is_running(struct nc_server_ch_thread_arg *data)
3315+
{
3316+
int rc = -1;
3317+
3318+
/* COND LOCK */
3319+
if (nc_mutex_lock(&data->cond_lock, NC_CH_COND_LOCK_TIMEOUT, __func__) != 1) {
3320+
return -1;
3321+
}
3322+
3323+
rc = data->thread_running;
3324+
3325+
/* COND UNLOCK */
3326+
nc_mutex_unlock(&data->cond_lock, __func__);
3327+
3328+
return rc;
3329+
}
3330+
33043331
/**
33053332
* @brief Wait for any event after a NC session was established on a CH client.
33063333
*
@@ -3313,7 +3340,7 @@ nc_server_ch_client_get_idle_timeout(const char *client_name, uint32_t *idle_tim
33133340
static int
33143341
nc_server_ch_client_thread_session_cond_wait(struct nc_server_ch_thread_arg *data, struct nc_session *session)
33153342
{
3316-
int rc = 0, r;
3343+
int rc = 0, r, terminate;
33173344
uint32_t idle_timeout;
33183345
struct timespec ts;
33193346

@@ -3369,26 +3396,39 @@ nc_server_ch_client_thread_session_cond_wait(struct nc_server_ch_thread_arg *dat
33693396
/* CH UNLOCK */
33703397
nc_mutex_unlock(&session->opts.server.ch_lock, __func__);
33713398

3399+
terminate = 0;
3400+
33723401
/* check if the client still exists and get its idle timeout */
33733402
r = nc_server_ch_client_get_idle_timeout(data->client_name, &idle_timeout);
33743403
if (r) {
3375-
/* client was removed, finish thread */
3376-
VRB(session, "Call Home client \"%s\" removed, but an established session will not be terminated.",
3377-
data->client_name);
3378-
rc = 1;
3404+
if (r == 1) {
3405+
/* the client must always be found, because if we delete it, then the configuring thread calls
3406+
* pthread_join() on this thread with the old config where the client still exists */
3407+
ERRINT;
3408+
}
3409+
rc = -1;
3410+
terminate = 1;
3411+
}
33793412

3380-
/* CH LOCK - to remain consistent */
3381-
if (nc_mutex_lock(&session->opts.server.ch_lock, NC_SESSION_CH_LOCK_TIMEOUT, __func__) != 1) {
3382-
return -1;
3413+
/* check if the thread should terminate */
3414+
r = nc_server_ch_client_thread_is_running(data);
3415+
if (r != 1) {
3416+
if (r == -1) {
3417+
rc = -1;
33833418
}
3384-
break;
3419+
terminate = 1;
33853420
}
33863421

33873422
/* CH LOCK */
33883423
if (nc_mutex_lock(&session->opts.server.ch_lock, NC_SESSION_CH_LOCK_TIMEOUT, __func__) != 1) {
33893424
return -1;
33903425
}
33913426

3427+
if (terminate) {
3428+
/* the purpose of this is to break only after we've acquired the ch_lock */
3429+
break;
3430+
}
3431+
33923432
nc_timeouttime_get(&ts, 0);
33933433
if (!nc_session_get_notif_status(session) && idle_timeout && (ts.tv_sec >= session->opts.server.last_rpc + idle_timeout)) {
33943434
VRB(session, "Call Home client \"%s\": session idle timeout elapsed.", data->client_name);
@@ -3398,6 +3438,12 @@ nc_server_ch_client_thread_session_cond_wait(struct nc_server_ch_thread_arg *dat
33983438
} while (session->status == NC_STATUS_RUNNING);
33993439
/* broke out of the loop, but still holding the ch_lock */
34003440

3441+
if (session->status == NC_STATUS_RUNNING) {
3442+
/* thread is terminating but the session is still running, so just log it */
3443+
VRB(session, "Call Home client \"%s\" removed, but an established session will not be terminated.",
3444+
data->client_name);
3445+
}
3446+
34013447
/* signal to nc_session_free() that CH thread is terminating */
34023448
session->flags &= ~NC_SESSION_CH_THREAD;
34033449
pthread_cond_signal(&session->opts.server.ch_cond);
@@ -3453,35 +3499,6 @@ nc_server_ch_client_thread_is_running_wait(struct nc_session *session, struct nc
34533499
return ret;
34543500
}
34553501

3456-
/**
3457-
* @brief Checks if a Call Home thread should terminate.
3458-
*
3459-
* Checks the shared boolean variable thread_running. This should be done everytime
3460-
* before entering a critical section.
3461-
*
3462-
* @param[in] data Call Home thread's data.
3463-
*
3464-
* @return 0 if the thread should stop running, -1 if it can continue.
3465-
*/
3466-
static int
3467-
nc_server_ch_client_thread_is_running(struct nc_server_ch_thread_arg *data)
3468-
{
3469-
int ret = -1;
3470-
3471-
/* COND LOCK */
3472-
if (nc_mutex_lock(&data->cond_lock, NC_CH_COND_LOCK_TIMEOUT, __func__) != 1) {
3473-
return ret;
3474-
}
3475-
if (!data->thread_running) {
3476-
/* thread should stop running */
3477-
ret = 0;
3478-
}
3479-
/* COND UNLOCK */
3480-
nc_mutex_unlock(&data->cond_lock, __func__);
3481-
3482-
return ret;
3483-
}
3484-
34853502
/**
34863503
* @brief Wait for a Call Home client to have at least one endpoint defined.
34873504
*
@@ -3848,6 +3865,8 @@ _nc_connect_ch_client_dispatch(struct nc_ch_client *ch_client, nc_server_ch_sess
38483865
cleanup:
38493866
if (arg) {
38503867
free(arg->client_name);
3868+
pthread_mutex_destroy(&arg->cond_lock);
3869+
pthread_cond_destroy(&arg->cond);
38513870
free(arg);
38523871
}
38533872
return rc;

0 commit comments

Comments
 (0)