Skip to content

Commit 7a3b975

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 731bd65 commit 7a3b975

1 file changed

Lines changed: 46 additions & 36 deletions

File tree

src/session_server.c

Lines changed: 46 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3267,7 +3267,7 @@ nc_connect_ch_endpt(struct nc_ch_endpt *endpt, nc_server_ch_session_acquire_ctx_
32673267
*
32683268
* @param[in] client_name Name of the Call Home client.
32693269
* @param[out] idle_timeout Idle timeout in seconds.
3270-
* @return 0 on success, 1 if the client was not found.
3270+
* @return 0 on success, 1 if the client was not found, -1 on error.
32713271
*/
32723272
static int
32733273
nc_server_ch_client_get_idle_timeout(const char *client_name, uint32_t *idle_timeout)
@@ -3277,7 +3277,7 @@ nc_server_ch_client_get_idle_timeout(const char *client_name, uint32_t *idle_tim
32773277

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

32833283
client = nc_server_ch_client_get(client_name);
@@ -3298,6 +3298,35 @@ nc_server_ch_client_get_idle_timeout(const char *client_name, uint32_t *idle_tim
32983298
return ret;
32993299
}
33003300

3301+
/**
3302+
* @brief Checks if a Call Home thread should terminate.
3303+
*
3304+
* Checks the shared boolean variable thread_running. This should be done everytime
3305+
* before entering a critical section.
3306+
*
3307+
* @param[in] data Call Home thread's data.
3308+
*
3309+
* @return 0 if the thread should stop running, -1 if it can continue.
3310+
*/
3311+
static int
3312+
nc_server_ch_client_thread_is_running(struct nc_server_ch_thread_arg *data)
3313+
{
3314+
int ret = -1;
3315+
3316+
/* COND LOCK */
3317+
if (nc_mutex_lock(&data->cond_lock, NC_CH_COND_LOCK_TIMEOUT, __func__) != 1) {
3318+
return ret;
3319+
}
3320+
if (!data->thread_running) {
3321+
/* thread should stop running */
3322+
ret = 0;
3323+
}
3324+
/* COND UNLOCK */
3325+
nc_mutex_unlock(&data->cond_lock, __func__);
3326+
3327+
return ret;
3328+
}
3329+
33013330
/**
33023331
* @brief Wait for any event after a NC session was established on a CH client.
33033332
*
@@ -3369,10 +3398,12 @@ nc_server_ch_client_thread_session_cond_wait(struct nc_server_ch_thread_arg *dat
33693398
/* check if the client still exists and get its idle timeout */
33703399
r = nc_server_ch_client_get_idle_timeout(data->client_name, &idle_timeout);
33713400
if (r) {
3372-
/* client was removed, finish thread */
3373-
VRB(session, "Call Home client \"%s\" removed, but an established session will not be terminated.",
3374-
data->client_name);
3375-
rc = 1;
3401+
if (r == 1) {
3402+
/* the client must always be found, because if we delete it, then the configuring thread calls
3403+
* pthread_join() on this thread with the old config where the client still exists */
3404+
ERRINT;
3405+
}
3406+
rc = -1;
33763407

33773408
/* CH LOCK - to remain consistent */
33783409
if (nc_mutex_lock(&session->opts.server.ch_lock, NC_SESSION_CH_LOCK_TIMEOUT, __func__) != 1) {
@@ -3392,9 +3423,15 @@ nc_server_ch_client_thread_session_cond_wait(struct nc_server_ch_thread_arg *dat
33923423
session->status = NC_STATUS_INVALID;
33933424
session->term_reason = NC_SESSION_TERM_TIMEOUT;
33943425
}
3395-
} while (session->status == NC_STATUS_RUNNING);
3426+
} while ((session->status == NC_STATUS_RUNNING) && nc_server_ch_client_thread_is_running(data));
33963427
/* broke out of the loop, but still holding the ch_lock */
33973428

3429+
if (session->status == NC_STATUS_RUNNING) {
3430+
/* thread is terminating but the session is still running, so just log it */
3431+
VRB(session, "Call Home client \"%s\" removed, but an established session will not be terminated.",
3432+
data->client_name);
3433+
}
3434+
33983435
/* signal to nc_session_free() that CH thread is terminating */
33993436
session->flags &= ~NC_SESSION_CH_THREAD;
34003437
pthread_cond_signal(&session->opts.server.ch_cond);
@@ -3450,35 +3487,6 @@ nc_server_ch_client_thread_is_running_wait(struct nc_session *session, struct nc
34503487
return ret;
34513488
}
34523489

3453-
/**
3454-
* @brief Checks if a Call Home thread should terminate.
3455-
*
3456-
* Checks the shared boolean variable thread_running. This should be done everytime
3457-
* before entering a critical section.
3458-
*
3459-
* @param[in] data Call Home thread's data.
3460-
*
3461-
* @return 0 if the thread should stop running, -1 if it can continue.
3462-
*/
3463-
static int
3464-
nc_server_ch_client_thread_is_running(struct nc_server_ch_thread_arg *data)
3465-
{
3466-
int ret = -1;
3467-
3468-
/* COND LOCK */
3469-
if (nc_mutex_lock(&data->cond_lock, NC_CH_COND_LOCK_TIMEOUT, __func__) != 1) {
3470-
return ret;
3471-
}
3472-
if (!data->thread_running) {
3473-
/* thread should stop running */
3474-
ret = 0;
3475-
}
3476-
/* COND UNLOCK */
3477-
nc_mutex_unlock(&data->cond_lock, __func__);
3478-
3479-
return ret;
3480-
}
3481-
34823490
/**
34833491
* @brief Wait for a Call Home client to have at least one endpoint defined.
34843492
*
@@ -3845,6 +3853,8 @@ _nc_connect_ch_client_dispatch(struct nc_ch_client *ch_client, nc_server_ch_sess
38453853
cleanup:
38463854
if (arg) {
38473855
free(arg->client_name);
3856+
pthread_mutex_destroy(&arg->cond_lock);
3857+
pthread_cond_destroy(&arg->cond);
38483858
free(arg);
38493859
}
38503860
return rc;

0 commit comments

Comments
 (0)