GUACAMOLE-221: Terminate keep-alive thread immediately upon guac_socket_free().

The keep-alive interval is identical to the timed client free used by
guacd. This results in a race condition where there is a random chance
that guacd will assume that the client has failed to terminate in a
timely manner simply because guac_socket_free() is waiting for the
keep-alive thread to finish.
This commit is contained in:
Michael Jumper 2020-11-02 14:57:40 -08:00
parent 0be71a8c67
commit 2a4ecda216

View File

@ -44,6 +44,8 @@ char __guac_socket_BASE64_CHARACTERS[64] = {
static void* __guac_socket_keep_alive_thread(void* data) { static void* __guac_socket_keep_alive_thread(void* data) {
int old_cancelstate;
/* Calculate sleep interval */ /* Calculate sleep interval */
struct timespec interval; struct timespec interval;
interval.tv_sec = GUAC_SOCKET_KEEP_ALIVE_INTERVAL / 1000; interval.tv_sec = GUAC_SOCKET_KEEP_ALIVE_INTERVAL / 1000;
@ -65,8 +67,11 @@ static void* __guac_socket_keep_alive_thread(void* data) {
} }
/* Sleep until next keep-alive check */ /* Sleep until next keep-alive check, but allow thread cancellation
* during that sleep */
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_cancelstate);
nanosleep(&interval, NULL); nanosleep(&interval, NULL);
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_cancelstate);
} }
@ -202,9 +207,11 @@ void guac_socket_free(guac_socket* socket) {
/* Mark as closed */ /* Mark as closed */
socket->state = GUAC_SOCKET_CLOSED; socket->state = GUAC_SOCKET_CLOSED;
/* Wait for keep-alive, if enabled */ /* Stop keep-alive thread, if enabled */
if (socket->__keep_alive_enabled) if (socket->__keep_alive_enabled) {
pthread_cancel(socket->__keep_alive_thread);
pthread_join(socket->__keep_alive_thread, NULL); pthread_join(socket->__keep_alive_thread, NULL);
}
free(socket); free(socket);
} }