Skip to content

Commit c2cce42

Browse files
Roytakmichalvasko
authored andcommitted
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 e02dfef commit c2cce42

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)