@@ -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 */
32723272static int
32733273nc_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
38453853cleanup :
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