From cedae6e6f97b14f5df3ea7c5f7efd59f2bc9ad82 Mon Sep 17 00:00:00 2001
From: Quentin BUATHIER <qbuathier@tetrane.com>
Date: Thu, 9 Aug 2018 09:33:59 +0200
Subject: [PATCH] Fix the concurrent issue hapenning between the freeing of the
 client and the clientOutput thread

---
 libvncserver/main.c      | 29 ++++++++++++++++++++++++++---
 libvncserver/rfbserver.c |  5 +++++
 rfb/rfb.h                |  1 +
 3 files changed, 32 insertions(+), 3 deletions(-)

--- a/libvncserver/main.c
+++ b/libvncserver/main.c
@@ -33,6 +33,7 @@
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <unistd.h>
+#include <fcntl.h>
 #endif
 
 #include <signal.h>
@@ -524,6 +525,7 @@
 
 	FD_ZERO(&rfds);
 	FD_SET(cl->sock, &rfds);
+	FD_SET(cl->pipe_notify_client_thread[0], &rfds);
 	FD_ZERO(&efds);
 	FD_SET(cl->sock, &efds);
 
@@ -532,9 +534,13 @@
 	if ((cl->fileTransfer.fd!=-1) && (cl->fileTransfer.sending==1))
 	    FD_SET(cl->sock, &wfds);
 
+	int nfds = cl->pipe_notify_client_thread[0] > cl->sock ? cl->pipe_notify_client_thread[0] : cl->sock;
+	
 	tv.tv_sec = 60; /* 1 minute */
 	tv.tv_usec = 0;
-	n = select(cl->sock + 1, &rfds, &wfds, &efds, &tv);
+
+	n = select(nfds + 1, &rfds, &wfds, &efds, &tv);
+
 	if (n < 0) {
 	    rfbLogPerror("ReadExact: select");
 	    break;
@@ -549,6 +555,13 @@
         if (FD_ISSET(cl->sock, &wfds))
             rfbSendFileTransferChunk(cl);
 
+	if (FD_ISSET(cl->pipe_notify_client_thread[0], &rfds))
+	{
+	    // Reset the pipe
+	    char buf;
+	    while (read(cl->pipe_notify_client_thread[0], &buf, sizeof(buf)) == sizeof(buf));
+	}
+
         if (FD_ISSET(cl->sock, &rfds) || FD_ISSET(cl->sock, &efds))
         {
 #ifdef LIBVNCSERVER_WITH_WEBSOCKETS
@@ -619,8 +632,12 @@
 {
     cl->onHold = FALSE;
 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
-    if(cl->screen->backgroundLoop)
-	pthread_create(&cl->client_thread, NULL, clientInput, (void *)cl);
+    if(cl->screen->backgroundLoop) {
+        pipe(cl->pipe_notify_client_thread);
+        fcntl(cl->pipe_notify_client_thread[0], F_SETFL, O_NONBLOCK);
+
+        pthread_create(&cl->client_thread, NULL, clientInput, (void *)cl);
+    }
 #endif
 }
 
@@ -1074,7 +1091,13 @@
         rfbCloseClient(currentCl);
       }
 
+#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
+      // Notify the thread and join it
+      write(currentCl->pipe_notify_client_thread[1], "\x00", 1);
+      pthread_join(currentCl->client_thread, NULL);
+#else
       rfbClientConnectionGone(currentCl);
+#endif
 
       currentCl = nextCl;
     }
--- a/libvncserver/rfbserver.c
+++ b/libvncserver/rfbserver.c
@@ -622,6 +622,11 @@
     UNLOCK(cl->sendMutex);
     TINI_MUTEX(cl->sendMutex);
 
+#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
+    close(cl->pipe_notify_client_thread[0]);
+    close(cl->pipe_notify_client_thread[1]);
+#endif
+
     rfbPrintStats(cl);
     rfbResetStats(cl);
 
--- a/rfb/rfb.h
+++ b/rfb/rfb.h
@@ -466,6 +466,7 @@
     int protocolMinorVersion;
 
 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
+    int pipe_notify_client_thread[2];
     pthread_t client_thread;
 #endif
 
