1 /*
2  *  This file is called main.c, because it contains most of the new functions
3  *  for use with LibVNCServer.
4  *
5  *  LibVNCServer (C) 2001 Johannes E. Schindelin <Johannes.Schindelin@gmx.de>
6  *  Original OSXvnc (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
7  *  Original Xvnc (C) 1999 AT&T Laboratories Cambridge.
8  *  All Rights Reserved.
9  *
10  *  see GPL (latest version) for full details
11  */
12 
13 #ifdef __STRICT_ANSI__
14 #define _BSD_SOURCE
15 #endif
16 #include <rfb/rfb.h>
17 #include <rfb/rfbregion.h>
18 #include "private.h"
19 
20 #include <stdarg.h>
21 #include <errno.h>
22 
23 #if defined(__DragonFly__)
24 #include <sys/socket.h>	/* For sockaddr_storage */
25 #endif
26 
27 #ifndef false
28 #define false 0
29 #define true -1
30 #endif
31 
32 #ifdef LIBVNCSERVER_HAVE_SYS_TIME_H
33 #include <sys/time.h>
34 #endif
35 
36 #ifdef LIBVNCSERVER_HAVE_SYS_TYPES_H
37 #include <sys/types.h>
38 #endif
39 
40 #ifdef LIBVNCSERVER_HAVE_FCNTL_H
41 #include <fcntl.h>
42 #endif
43 
44 #include <signal.h>
45 #include <time.h>
46 
47 static int extMutex_initialized = 0;
48 static int logMutex_initialized = 0;
49 #if defined(LIBVNCSERVER_HAVE_LIBPTHREAD) || defined(LIBVNCSERVER_HAVE_WIN32THREADS)
50 static MUTEX(logMutex);
51 static MUTEX(extMutex);
52 #endif
53 
54 static int rfbEnableLogging=1;
55 
56 #ifdef LIBVNCSERVER_WORDS_BIGENDIAN
57 char rfbEndianTest = (1==0);
58 #else
59 char rfbEndianTest = (1==1);
60 #endif
61 
62 /*
63  * Protocol extensions
64  */
65 
66 static rfbProtocolExtension* rfbExtensionHead = NULL;
67 
68 /*
69  * This method registers a list of new extensions.
70  * It avoids same extension getting registered multiple times.
71  * The order is not preserved if multiple extensions are
72  * registered at one-go.
73  */
74 void
rfbRegisterProtocolExtension(rfbProtocolExtension * extension)75 rfbRegisterProtocolExtension(rfbProtocolExtension* extension)
76 {
77 	rfbProtocolExtension *head = rfbExtensionHead, *next = NULL;
78 
79 	if(extension == NULL)
80 		return;
81 
82 	next = extension->next;
83 
84 	if (! extMutex_initialized) {
85 		INIT_MUTEX(extMutex);
86 		extMutex_initialized = 1;
87 	}
88 
89 	LOCK(extMutex);
90 
91 	while(head != NULL) {
92 		if(head == extension) {
93 			UNLOCK(extMutex);
94 			rfbRegisterProtocolExtension(next);
95 			return;
96 		}
97 
98 		head = head->next;
99 	}
100 
101 	extension->next = rfbExtensionHead;
102 	rfbExtensionHead = extension;
103 
104 	UNLOCK(extMutex);
105 	rfbRegisterProtocolExtension(next);
106 }
107 
108 /*
109  * This method unregisters a list of extensions.
110  * These extensions won't be available for any new
111  * client connection.
112  */
113 void
rfbUnregisterProtocolExtension(rfbProtocolExtension * extension)114 rfbUnregisterProtocolExtension(rfbProtocolExtension* extension)
115 {
116 
117 	rfbProtocolExtension *cur = NULL, *pre = NULL;
118 
119 	if(extension == NULL)
120 		return;
121 
122 	if (! extMutex_initialized) {
123 		INIT_MUTEX(extMutex);
124 		extMutex_initialized = 1;
125 	}
126 
127 	LOCK(extMutex);
128 
129 	if(rfbExtensionHead == extension) {
130 		rfbExtensionHead = rfbExtensionHead->next;
131 		UNLOCK(extMutex);
132 		rfbUnregisterProtocolExtension(extension->next);
133 		return;
134 	}
135 
136 	cur = pre = rfbExtensionHead;
137 
138 	while(cur) {
139 		if(cur == extension) {
140 			pre->next = cur->next;
141 			break;
142 		}
143 		pre = cur;
144 		cur = cur->next;
145 	}
146 
147 	UNLOCK(extMutex);
148 
149 	rfbUnregisterProtocolExtension(extension->next);
150 }
151 
rfbGetExtensionIterator()152 rfbProtocolExtension* rfbGetExtensionIterator()
153 {
154 	if (! extMutex_initialized) {
155 		INIT_MUTEX(extMutex);
156 		extMutex_initialized = 1;
157 	}
158 
159 	LOCK(extMutex);
160 	return rfbExtensionHead;
161 }
162 
rfbReleaseExtensionIterator()163 void rfbReleaseExtensionIterator()
164 {
165 	UNLOCK(extMutex);
166 }
167 
rfbEnableExtension(rfbClientPtr cl,rfbProtocolExtension * extension,void * data)168 rfbBool rfbEnableExtension(rfbClientPtr cl, rfbProtocolExtension* extension,
169 	void* data)
170 {
171 	rfbExtensionData* extData;
172 
173 	/* make sure extension is not yet enabled. */
174 	for(extData = cl->extensions; extData; extData = extData->next)
175 		if(extData->extension == extension)
176 			return FALSE;
177 
178 	extData = calloc(sizeof(rfbExtensionData),1);
179 	if(!extData)
180 		return FALSE;
181 	extData->extension = extension;
182 	extData->data = data;
183 	extData->next = cl->extensions;
184 	cl->extensions = extData;
185 
186 	return TRUE;
187 }
188 
rfbDisableExtension(rfbClientPtr cl,rfbProtocolExtension * extension)189 rfbBool rfbDisableExtension(rfbClientPtr cl, rfbProtocolExtension* extension)
190 {
191 	rfbExtensionData* extData;
192 	rfbExtensionData* prevData = NULL;
193 
194 	for(extData = cl->extensions; extData; extData = extData->next) {
195 		if(extData->extension == extension) {
196 			if(extData->data)
197 				free(extData->data);
198 			if(prevData == NULL)
199 				cl->extensions = extData->next;
200 			else
201 				prevData->next = extData->next;
202 			return TRUE;
203 		}
204 		prevData = extData;
205 	}
206 
207 	return FALSE;
208 }
209 
rfbGetExtensionClientData(rfbClientPtr cl,rfbProtocolExtension * extension)210 void* rfbGetExtensionClientData(rfbClientPtr cl, rfbProtocolExtension* extension)
211 {
212     rfbExtensionData* data = cl->extensions;
213 
214     while(data && data->extension != extension)
215 	data = data->next;
216 
217     if(data == NULL) {
218 	rfbLog("Extension is not enabled !\n");
219 	/* rfbCloseClient(cl); */
220 	return NULL;
221     }
222 
223     return data->data;
224 }
225 
226 /*
227  * Logging
228  */
229 
rfbLogEnable(int enabled)230 void rfbLogEnable(int enabled) {
231   rfbEnableLogging=enabled;
232 }
233 
234 /*
235  * rfbLog prints a time-stamped message to the log file (stderr).
236  */
237 
238 static void
rfbDefaultLog(const char * format,...)239 rfbDefaultLog(const char *format, ...)
240 {
241     va_list args;
242     char buf[256];
243     time_t log_clock;
244 
245     if(!rfbEnableLogging)
246       return;
247 
248     if (! logMutex_initialized) {
249       INIT_MUTEX(logMutex);
250       logMutex_initialized = 1;
251     }
252 
253     LOCK(logMutex);
254     va_start(args, format);
255 
256     time(&log_clock);
257     strftime(buf, 255, "%d/%m/%Y %X ", localtime(&log_clock));
258     fprintf(stderr, "%s", buf);
259 
260     vfprintf(stderr, format, args);
261     fflush(stderr);
262 
263     va_end(args);
264     UNLOCK(logMutex);
265 }
266 
267 rfbLogProc rfbLog=rfbDefaultLog;
268 rfbLogProc rfbErr=rfbDefaultLog;
269 
rfbLogPerror(const char * str)270 void rfbLogPerror(const char *str)
271 {
272 #ifdef WIN32
273     wchar_t *s = NULL;
274     FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
275                    NULL, errno, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
276                    (LPWSTR)&s, 0, NULL);
277     rfbErr("%s: %S\n", str, s);
278     LocalFree(s);
279 #else
280     rfbErr("%s: %s\n", str, strerror(errno));
281 #endif
282 }
283 
rfbScheduleCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,int dx,int dy)284 void rfbScheduleCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,int dx,int dy)
285 {
286    rfbClientIteratorPtr iterator;
287    rfbClientPtr cl;
288 
289    iterator=rfbGetClientIterator(rfbScreen);
290    while((cl=rfbClientIteratorNext(iterator))) {
291      LOCK(cl->updateMutex);
292      if(cl->useCopyRect) {
293        sraRegionPtr modifiedRegionBackup;
294        if(!sraRgnEmpty(cl->copyRegion)) {
295 	  if(cl->copyDX!=dx || cl->copyDY!=dy) {
296 	     /* if a copyRegion was not yet executed, treat it as a
297 	      * modifiedRegion. The idea: in this case it could be
298 	      * source of the new copyRect or modified anyway. */
299 	     sraRgnOr(cl->modifiedRegion,cl->copyRegion);
300 	     sraRgnMakeEmpty(cl->copyRegion);
301 	  } else {
302 	     /* we have to set the intersection of the source of the copy
303 	      * and the old copy to modified. */
304 	     modifiedRegionBackup=sraRgnCreateRgn(copyRegion);
305 	     sraRgnOffset(modifiedRegionBackup,-dx,-dy);
306 	     sraRgnAnd(modifiedRegionBackup,cl->copyRegion);
307 	     sraRgnOr(cl->modifiedRegion,modifiedRegionBackup);
308 	     sraRgnDestroy(modifiedRegionBackup);
309 	  }
310        }
311 
312        sraRgnOr(cl->copyRegion,copyRegion);
313        cl->copyDX = dx;
314        cl->copyDY = dy;
315 
316        /* if there were modified regions, which are now copied,
317 	* mark them as modified, because the source of these can be overlapped
318 	* either by new modified or now copied regions. */
319        modifiedRegionBackup=sraRgnCreateRgn(cl->modifiedRegion);
320        sraRgnOffset(modifiedRegionBackup,dx,dy);
321        sraRgnAnd(modifiedRegionBackup,cl->copyRegion);
322        sraRgnOr(cl->modifiedRegion,modifiedRegionBackup);
323        sraRgnDestroy(modifiedRegionBackup);
324 
325        if(!cl->enableCursorShapeUpdates) {
326           /*
327            * n.b. (dx, dy) is the vector pointing in the direction the
328            * copyrect displacement will take place.  copyRegion is the
329            * destination rectangle (say), not the source rectangle.
330            */
331           sraRegionPtr cursorRegion;
332           int x = cl->cursorX - cl->screen->cursor->xhot;
333           int y = cl->cursorY - cl->screen->cursor->yhot;
334           int w = cl->screen->cursor->width;
335           int h = cl->screen->cursor->height;
336 
337           cursorRegion = sraRgnCreateRect(x, y, x + w, y + h);
338           sraRgnAnd(cursorRegion, cl->copyRegion);
339           if(!sraRgnEmpty(cursorRegion)) {
340              /*
341               * current cursor rect overlaps with the copy region *dest*,
342               * mark it as modified since we won't copy-rect stuff to it.
343               */
344              sraRgnOr(cl->modifiedRegion, cursorRegion);
345           }
346           sraRgnDestroy(cursorRegion);
347 
348           cursorRegion = sraRgnCreateRect(x, y, x + w, y + h);
349           /* displace it to check for overlap with copy region source: */
350           sraRgnOffset(cursorRegion, dx, dy);
351           sraRgnAnd(cursorRegion, cl->copyRegion);
352           if(!sraRgnEmpty(cursorRegion)) {
353              /*
354               * current cursor rect overlaps with the copy region *source*,
355               * mark the *displaced* cursorRegion as modified since we
356               * won't copyrect stuff to it.
357               */
358              sraRgnOr(cl->modifiedRegion, cursorRegion);
359           }
360           sraRgnDestroy(cursorRegion);
361        }
362 
363      } else {
364        sraRgnOr(cl->modifiedRegion,copyRegion);
365      }
366      TSIGNAL(cl->updateCond);
367      UNLOCK(cl->updateMutex);
368    }
369 
370    rfbReleaseClientIterator(iterator);
371 }
372 
rfbDoCopyRegion(rfbScreenInfoPtr screen,sraRegionPtr copyRegion,int dx,int dy)373 void rfbDoCopyRegion(rfbScreenInfoPtr screen,sraRegionPtr copyRegion,int dx,int dy)
374 {
375    sraRectangleIterator* i;
376    sraRect rect;
377    int j,widthInBytes,bpp=screen->serverFormat.bitsPerPixel/8,
378     rowstride=screen->paddedWidthInBytes;
379    char *in,*out;
380 
381    /* copy it, really */
382    i = sraRgnGetReverseIterator(copyRegion,dx<0,dy<0);
383    while(sraRgnIteratorNext(i,&rect)) {
384      widthInBytes = (rect.x2-rect.x1)*bpp;
385      out = screen->frameBuffer+rect.x1*bpp+rect.y1*rowstride;
386      in = screen->frameBuffer+(rect.x1-dx)*bpp+(rect.y1-dy)*rowstride;
387      if(dy<0)
388        for(j=rect.y1;j<rect.y2;j++,out+=rowstride,in+=rowstride)
389 	 memmove(out,in,widthInBytes);
390      else {
391        out += rowstride*(rect.y2-rect.y1-1);
392        in += rowstride*(rect.y2-rect.y1-1);
393        for(j=rect.y2-1;j>=rect.y1;j--,out-=rowstride,in-=rowstride)
394 	 memmove(out,in,widthInBytes);
395      }
396    }
397    sraRgnReleaseIterator(i);
398 
399    rfbScheduleCopyRegion(screen,copyRegion,dx,dy);
400 }
401 
rfbDoCopyRect(rfbScreenInfoPtr screen,int x1,int y1,int x2,int y2,int dx,int dy)402 void rfbDoCopyRect(rfbScreenInfoPtr screen,int x1,int y1,int x2,int y2,int dx,int dy)
403 {
404   sraRegionPtr region = sraRgnCreateRect(x1,y1,x2,y2);
405   rfbDoCopyRegion(screen,region,dx,dy);
406   sraRgnDestroy(region);
407 }
408 
rfbScheduleCopyRect(rfbScreenInfoPtr screen,int x1,int y1,int x2,int y2,int dx,int dy)409 void rfbScheduleCopyRect(rfbScreenInfoPtr screen,int x1,int y1,int x2,int y2,int dx,int dy)
410 {
411   sraRegionPtr region = sraRgnCreateRect(x1,y1,x2,y2);
412   rfbScheduleCopyRegion(screen,region,dx,dy);
413   sraRgnDestroy(region);
414 }
415 
rfbMarkRegionAsModified(rfbScreenInfoPtr screen,sraRegionPtr modRegion)416 void rfbMarkRegionAsModified(rfbScreenInfoPtr screen,sraRegionPtr modRegion)
417 {
418    rfbClientIteratorPtr iterator;
419    rfbClientPtr cl;
420 
421    iterator=rfbGetClientIterator(screen);
422    while((cl=rfbClientIteratorNext(iterator))) {
423      LOCK(cl->updateMutex);
424      sraRgnOr(cl->modifiedRegion,modRegion);
425      TSIGNAL(cl->updateCond);
426      UNLOCK(cl->updateMutex);
427    }
428 
429    rfbReleaseClientIterator(iterator);
430 }
431 
432 void rfbScaledScreenUpdate(rfbScreenInfoPtr screen, int x1, int y1, int x2, int y2);
rfbMarkRectAsModified(rfbScreenInfoPtr screen,int x1,int y1,int x2,int y2)433 void rfbMarkRectAsModified(rfbScreenInfoPtr screen,int x1,int y1,int x2,int y2)
434 {
435    sraRegionPtr region;
436    int i;
437 
438    if(x1>x2) { i=x1; x1=x2; x2=i; }
439    if(x1<0) x1=0;
440    if(x2>screen->width) x2=screen->width;
441    if(x1==x2) return;
442 
443    if(y1>y2) { i=y1; y1=y2; y2=i; }
444    if(y1<0) y1=0;
445    if(y2>screen->height) y2=screen->height;
446    if(y1==y2) return;
447 
448    /* update scaled copies for this rectangle */
449    rfbScaledScreenUpdate(screen,x1,y1,x2,y2);
450 
451    region = sraRgnCreateRect(x1,y1,x2,y2);
452    rfbMarkRegionAsModified(screen,region);
453    sraRgnDestroy(region);
454 }
455 
456 #if defined(LIBVNCSERVER_HAVE_LIBPTHREAD) || defined(LIBVNCSERVER_HAVE_WIN32THREADS)
457 
458 static THREAD_ROUTINE_RETURN_TYPE
clientOutput(void * data)459 clientOutput(void *data)
460 {
461     rfbClientPtr cl = (rfbClientPtr)data;
462     rfbBool haveUpdate;
463     sraRegion* updateRegion;
464 
465     while (1) {
466         haveUpdate = false;
467         while (!haveUpdate) {
468 		if (cl->sock == RFB_INVALID_SOCKET) {
469 			/* Client has disconnected. */
470 			return THREAD_ROUTINE_RETURN_VALUE;
471 		}
472 		if (cl->state != RFB_NORMAL || cl->onHold) {
473 			/* just sleep until things get normal */
474 		        THREAD_SLEEP_MS(cl->screen->deferUpdateTime);
475 			continue;
476 		}
477 
478 		LOCK(cl->updateMutex);
479 
480 		if (sraRgnEmpty(cl->requestedRegion)) {
481 			; /* always require a FB Update Request (otherwise can crash.) */
482 		} else {
483 			haveUpdate = FB_UPDATE_PENDING(cl);
484 			if(!haveUpdate) {
485 				updateRegion = sraRgnCreateRgn(cl->modifiedRegion);
486 				haveUpdate   = sraRgnAnd(updateRegion,cl->requestedRegion);
487 				sraRgnDestroy(updateRegion);
488 			}
489 		}
490 
491 		if (!haveUpdate) {
492 			WAIT(cl->updateCond, cl->updateMutex);
493 		}
494 
495 		UNLOCK(cl->updateMutex);
496         }
497 
498         /* OK, now, to save bandwidth, wait a little while for more
499            updates to come along. */
500 	THREAD_SLEEP_MS(cl->screen->deferUpdateTime);
501 
502         /* Now, get the region we're going to update, and remove
503            it from cl->modifiedRegion _before_ we send the update.
504            That way, if anything that overlaps the region we're sending
505            is updated, we'll be sure to do another update later. */
506         LOCK(cl->updateMutex);
507 	updateRegion = sraRgnCreateRgn(cl->modifiedRegion);
508         UNLOCK(cl->updateMutex);
509 
510         /* Now actually send the update. */
511 	rfbIncrClientRef(cl);
512         LOCK(cl->sendMutex);
513         rfbSendFramebufferUpdate(cl, updateRegion);
514         UNLOCK(cl->sendMutex);
515 	rfbDecrClientRef(cl);
516 
517 	sraRgnDestroy(updateRegion);
518     }
519 
520     /* Not reached. */
521     return THREAD_ROUTINE_RETURN_VALUE;
522 }
523 
524 static THREAD_ROUTINE_RETURN_TYPE
clientInput(void * data)525 clientInput(void *data)
526 {
527     rfbClientPtr cl = (rfbClientPtr)data;
528 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
529     pthread_t output_thread;
530     pthread_create(&output_thread, NULL, clientOutput, (void *)cl);
531 #elif defined(LIBVNCSERVER_HAVE_WIN32THREADS)
532     uintptr_t output_thread = _beginthread(clientOutput, 0, cl);
533 #endif
534 
535     while (1) {
536 	fd_set rfds, wfds, efds;
537 	struct timeval tv;
538 	int n;
539 
540 	if (cl->sock == RFB_INVALID_SOCKET) {
541 	  /* Client has disconnected. */
542             break;
543         }
544 
545 	FD_ZERO(&rfds);
546 	FD_SET(cl->sock, &rfds);
547 #ifndef WIN32
548 	FD_SET(cl->pipe_notify_client_thread[0], &rfds);
549 #endif
550 	FD_ZERO(&efds);
551 	FD_SET(cl->sock, &efds);
552 
553 	/* Are we transferring a file in the background? */
554 	FD_ZERO(&wfds);
555 	if ((cl->fileTransfer.fd!=-1) && (cl->fileTransfer.sending==1))
556 	    FD_SET(cl->sock, &wfds);
557 
558 #ifndef WIN32
559 	int nfds = cl->pipe_notify_client_thread[0] > cl->sock ? cl->pipe_notify_client_thread[0] : cl->sock;
560 #else
561 	int nfds = cl->sock;
562 #endif
563 
564 	tv.tv_sec = 60; /* 1 minute */
565 	tv.tv_usec = 0;
566 
567 	n = select(nfds + 1, &rfds, &wfds, &efds, &tv);
568 
569 	if (n < 0) {
570 	    rfbLogPerror("ReadExact: select");
571 	    break;
572 	}
573 	if (n == 0) /* timeout */
574 	{
575             rfbSendFileTransferChunk(cl);
576 	    continue;
577         }
578 
579         /* We have some space on the transmit queue, send some data */
580         if (FD_ISSET(cl->sock, &wfds))
581             rfbSendFileTransferChunk(cl);
582 
583 #ifndef WIN32
584 	if (FD_ISSET(cl->pipe_notify_client_thread[0], &rfds))
585 	{
586 	    /* Reset the pipe */
587 	    char buf;
588 	    while (read(cl->pipe_notify_client_thread[0], &buf, sizeof(buf)) == sizeof(buf));
589 	}
590 #endif
591 
592         if (FD_ISSET(cl->sock, &rfds) || FD_ISSET(cl->sock, &efds))
593         {
594 #ifdef LIBVNCSERVER_WITH_WEBSOCKETS
595             do {
596                 rfbProcessClientMessage(cl);
597             } while (webSocketsHasDataInBuffer(cl));
598 #else
599             rfbProcessClientMessage(cl);
600 #endif
601         }
602     }
603 
604     /* Get rid of the output thread. */
605     LOCK(cl->updateMutex);
606     TSIGNAL(cl->updateCond);
607     UNLOCK(cl->updateMutex);
608     THREAD_JOIN(output_thread);
609 
610     rfbClientConnectionGone(cl);
611 
612     return THREAD_ROUTINE_RETURN_VALUE;
613 }
614 
615 
616 static THREAD_ROUTINE_RETURN_TYPE
listenerRun(void * data)617 listenerRun(void *data)
618 {
619     rfbScreenInfoPtr screen=(rfbScreenInfoPtr)data;
620     int client_fd;
621     struct sockaddr_storage peer;
622     rfbClientPtr cl = NULL;
623     socklen_t len;
624     fd_set listen_fds;  /* temp file descriptor list for select() */
625 
626     /* TODO: this thread won't die by restarting the server */
627     /* TODO: HTTP is not handled */
628     while (1) {
629         client_fd = -1;
630         FD_ZERO(&listen_fds);
631 	if(screen->listenSock != RFB_INVALID_SOCKET)
632 	  FD_SET(screen->listenSock, &listen_fds);
633 	if(screen->listen6Sock != RFB_INVALID_SOCKET)
634 	  FD_SET(screen->listen6Sock, &listen_fds);
635 
636         if (select(screen->maxFd+1, &listen_fds, NULL, NULL, NULL) == -1) {
637             rfbLogPerror("listenerRun: error in select");
638             return THREAD_ROUTINE_RETURN_VALUE;
639         }
640 
641 	/* there is something on the listening sockets, handle new connections */
642 	len = sizeof (peer);
643 	if (FD_ISSET(screen->listenSock, &listen_fds))
644 	    client_fd = accept(screen->listenSock, (struct sockaddr*)&peer, &len);
645 	else if (FD_ISSET(screen->listen6Sock, &listen_fds))
646 	    client_fd = accept(screen->listen6Sock, (struct sockaddr*)&peer, &len);
647 
648 	if(client_fd >= 0)
649 	  cl = rfbNewClient(screen,client_fd);
650 	if (cl && !cl->onHold )
651 	  rfbStartOnHoldClient(cl);
652     }
653     return THREAD_ROUTINE_RETURN_VALUE;
654 }
655 
656 #endif
657 
658 void
rfbStartOnHoldClient(rfbClientPtr cl)659 rfbStartOnHoldClient(rfbClientPtr cl)
660 {
661     cl->onHold = FALSE;
662 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
663     if(cl->screen->backgroundLoop) {
664 #ifndef WIN32
665         if (pipe(cl->pipe_notify_client_thread) == -1) {
666             cl->pipe_notify_client_thread[0] = -1;
667             cl->pipe_notify_client_thread[1] = -1;
668         }
669         fcntl(cl->pipe_notify_client_thread[0], F_SETFL, O_NONBLOCK);
670 #endif
671         pthread_create(&cl->client_thread, NULL, clientInput, (void *)cl);
672     }
673 #elif defined(LIBVNCSERVER_HAVE_WIN32THREADS)
674     if(cl->screen->backgroundLoop) {
675 	cl->client_thread = _beginthread(clientInput, 0, cl);
676     }
677 #endif
678 }
679 
680 
681 void
rfbRefuseOnHoldClient(rfbClientPtr cl)682 rfbRefuseOnHoldClient(rfbClientPtr cl)
683 {
684     rfbCloseClient(cl);
685     rfbClientConnectionGone(cl);
686 }
687 
688 static void
rfbDefaultKbdAddEvent(rfbBool down,rfbKeySym keySym,rfbClientPtr cl)689 rfbDefaultKbdAddEvent(rfbBool down, rfbKeySym keySym, rfbClientPtr cl)
690 {
691 }
692 
693 void
rfbDefaultPtrAddEvent(int buttonMask,int x,int y,rfbClientPtr cl)694 rfbDefaultPtrAddEvent(int buttonMask, int x, int y, rfbClientPtr cl)
695 {
696   rfbClientIteratorPtr iterator;
697   rfbClientPtr other_client;
698   rfbScreenInfoPtr s = cl->screen;
699 
700   if (x != s->cursorX || y != s->cursorY) {
701     LOCK(s->cursorMutex);
702     s->cursorX = x;
703     s->cursorY = y;
704     UNLOCK(s->cursorMutex);
705 
706     /* The cursor was moved by this client, so don't send CursorPos. */
707     if (cl->enableCursorPosUpdates)
708       cl->cursorWasMoved = FALSE;
709 
710     /* But inform all remaining clients about this cursor movement. */
711     iterator = rfbGetClientIterator(s);
712     while ((other_client = rfbClientIteratorNext(iterator)) != NULL) {
713       if (other_client != cl && other_client->enableCursorPosUpdates) {
714 	other_client->cursorWasMoved = TRUE;
715       }
716     }
717     rfbReleaseClientIterator(iterator);
718   }
719 }
720 
rfbDefaultSetXCutText(char * text,int len,rfbClientPtr cl)721 static void rfbDefaultSetXCutText(char* text, int len, rfbClientPtr cl)
722 {
723 }
724 
725 /* TODO: add a nice VNC or RFB cursor */
726 
727 #if defined(WIN32) || defined(sparc) || !defined(NO_STRICT_ANSI)
728 static rfbCursor myCursor =
729 {
730    FALSE, FALSE, FALSE, FALSE,
731    (unsigned char*)"\000\102\044\030\044\102\000",
732    (unsigned char*)"\347\347\176\074\176\347\347",
733    8, 7, 3, 3,
734    0, 0, 0,
735    0xffff, 0xffff, 0xffff,
736    NULL
737 };
738 #else
739 static rfbCursor myCursor =
740 {
741    cleanup: FALSE,
742    cleanupSource: FALSE,
743    cleanupMask: FALSE,
744    cleanupRichSource: FALSE,
745    source: "\000\102\044\030\044\102\000",
746    mask:   "\347\347\176\074\176\347\347",
747    width: 8, height: 7, xhot: 3, yhot: 3,
748    foreRed: 0, foreGreen: 0, foreBlue: 0,
749    backRed: 0xffff, backGreen: 0xffff, backBlue: 0xffff,
750    richSource: NULL
751 };
752 #endif
753 
rfbDefaultGetCursorPtr(rfbClientPtr cl)754 static rfbCursorPtr rfbDefaultGetCursorPtr(rfbClientPtr cl)
755 {
756    return(cl->screen->cursor);
757 }
758 
759 /* response is cl->authChallenge vncEncrypted with passwd */
rfbDefaultPasswordCheck(rfbClientPtr cl,const char * response,int len)760 static rfbBool rfbDefaultPasswordCheck(rfbClientPtr cl,const char* response,int len)
761 {
762   int i;
763   char *passwd=rfbDecryptPasswdFromFile(cl->screen->authPasswdData);
764 
765   if(!passwd) {
766     rfbErr("Couldn't read password file: %s\n",cl->screen->authPasswdData);
767     return(FALSE);
768   }
769 
770   rfbEncryptBytes(cl->authChallenge, passwd);
771 
772   /* Lose the password from memory */
773   for (i = strlen(passwd); i >= 0; i--) {
774     passwd[i] = '\0';
775   }
776 
777   free(passwd);
778 
779   if (memcmp(cl->authChallenge, response, len) != 0) {
780     rfbErr("authProcessClientMessage: authentication failed from %s\n",
781 	   cl->host);
782     return(FALSE);
783   }
784 
785   return(TRUE);
786 }
787 
788 /* for this method, authPasswdData is really a pointer to an array
789    of char*'s, where the last pointer is 0. */
rfbCheckPasswordByList(rfbClientPtr cl,const char * response,int len)790 rfbBool rfbCheckPasswordByList(rfbClientPtr cl,const char* response,int len)
791 {
792   char **passwds;
793   int i=0;
794 
795   for(passwds=(char**)cl->screen->authPasswdData;*passwds;passwds++,i++) {
796     uint8_t auth_tmp[CHALLENGESIZE];
797     memcpy((char *)auth_tmp, (char *)cl->authChallenge, CHALLENGESIZE);
798     rfbEncryptBytes(auth_tmp, *passwds);
799 
800     if (memcmp(auth_tmp, response, len) == 0) {
801       if(i>=cl->screen->authPasswdFirstViewOnly)
802 	cl->viewOnly=TRUE;
803       return(TRUE);
804     }
805   }
806 
807   rfbErr("authProcessClientMessage: authentication failed from %s\n",
808 	 cl->host);
809   return(FALSE);
810 }
811 
rfbDoNothingWithClient(rfbClientPtr cl)812 void rfbDoNothingWithClient(rfbClientPtr cl)
813 {
814 }
815 
rfbDefaultNewClientHook(rfbClientPtr cl)816 static enum rfbNewClientAction rfbDefaultNewClientHook(rfbClientPtr cl)
817 {
818 	return RFB_CLIENT_ACCEPT;
819 }
820 
rfbDefaultNumberOfExtDesktopScreens(rfbClientPtr cl)821 static int rfbDefaultNumberOfExtDesktopScreens(rfbClientPtr cl)
822 {
823     return 1;
824 }
825 
rfbDefaultGetExtDesktopScreen(int seqnumber,rfbExtDesktopScreen * s,rfbClientPtr cl)826 static rfbBool rfbDefaultGetExtDesktopScreen(int seqnumber, rfbExtDesktopScreen* s, rfbClientPtr cl)
827 {
828     if (seqnumber != 0)
829         return FALSE;
830 
831     /* Populate the provided rfbExtDesktopScreen structure */
832     s->id = 1;
833     s->width = cl->scaledScreen->width;
834     s->height = cl->scaledScreen->height;
835     s->x = 0;
836     s->y = 0;
837     s->flags = 0;
838 
839     return TRUE;
840 }
841 
rfbDefaultSetDesktopSize(int width,int height,int numScreens,rfbExtDesktopScreen * extDesktopScreens,rfbClientPtr cl)842 static int rfbDefaultSetDesktopSize(int width, int height, int numScreens, rfbExtDesktopScreen* extDesktopScreens, rfbClientPtr cl)
843 {
844     return rfbExtDesktopSize_ResizeProhibited;
845 }
846 
847 /*
848  * Update server's pixel format in screenInfo structure. This
849  * function is called from rfbGetScreen() and rfbNewFramebuffer().
850  */
851 
rfbInitServerFormat(rfbScreenInfoPtr screen,int bitsPerSample)852 static void rfbInitServerFormat(rfbScreenInfoPtr screen, int bitsPerSample)
853 {
854    rfbPixelFormat* format=&screen->serverFormat;
855 
856    format->bitsPerPixel = screen->bitsPerPixel;
857    format->depth = screen->depth;
858    format->bigEndian = rfbEndianTest?FALSE:TRUE;
859    format->trueColour = TRUE;
860    screen->colourMap.count = 0;
861    screen->colourMap.is16 = 0;
862    screen->colourMap.data.bytes = NULL;
863 
864    if (format->bitsPerPixel == 8) {
865      format->redMax = 7;
866      format->greenMax = 7;
867      format->blueMax = 3;
868      format->redShift = 0;
869      format->greenShift = 3;
870      format->blueShift = 6;
871    } else {
872      format->redMax = (1 << bitsPerSample) - 1;
873      format->greenMax = (1 << bitsPerSample) - 1;
874      format->blueMax = (1 << bitsPerSample) - 1;
875      if(rfbEndianTest) {
876        format->redShift = 0;
877        format->greenShift = bitsPerSample;
878        format->blueShift = bitsPerSample * 2;
879      } else {
880        if(format->bitsPerPixel==8*3) {
881 	 format->redShift = bitsPerSample*2;
882 	 format->greenShift = bitsPerSample*1;
883 	 format->blueShift = 0;
884        } else {
885 	 format->redShift = bitsPerSample*3;
886 	 format->greenShift = bitsPerSample*2;
887 	 format->blueShift = bitsPerSample;
888        }
889      }
890    }
891 }
892 
rfbGetScreen(int * argc,char ** argv,int width,int height,int bitsPerSample,int samplesPerPixel,int bytesPerPixel)893 rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv,
894  int width,int height,int bitsPerSample,int samplesPerPixel,
895  int bytesPerPixel)
896 {
897    rfbScreenInfoPtr screen=calloc(sizeof(rfbScreenInfo),1);
898    if (!screen)
899        return NULL;
900 
901    if (! logMutex_initialized) {
902      INIT_MUTEX(logMutex);
903      logMutex_initialized = 1;
904    }
905 
906 
907    if(width&3)
908      rfbErr("WARNING: Width (%d) is not a multiple of 4. VncViewer has problems with that.\n",width);
909 
910    screen->autoPort=FALSE;
911    screen->clientHead=NULL;
912    screen->pointerClient=NULL;
913    screen->port=5900;
914    screen->ipv6port=5900;
915    screen->socketState=RFB_SOCKET_INIT;
916 
917    screen->inetdInitDone = FALSE;
918    screen->inetdSock=RFB_INVALID_SOCKET;
919 
920    screen->udpSock=RFB_INVALID_SOCKET;
921    screen->udpSockConnected=FALSE;
922    screen->udpPort=0;
923    screen->udpClient=NULL;
924 
925    screen->maxFd=0;
926    screen->listenSock=RFB_INVALID_SOCKET;
927    screen->listen6Sock=RFB_INVALID_SOCKET;
928 
929    screen->fdQuota = 0.5;
930 
931    screen->httpInitDone=FALSE;
932    screen->httpEnableProxyConnect=FALSE;
933    screen->httpPort=0;
934    screen->http6Port=0;
935    screen->httpDir=NULL;
936    screen->httpListenSock=RFB_INVALID_SOCKET;
937    screen->httpListen6Sock=RFB_INVALID_SOCKET;
938    screen->httpSock=RFB_INVALID_SOCKET;
939 
940    screen->desktopName = "LibVNCServer";
941    screen->alwaysShared = FALSE;
942    screen->neverShared = FALSE;
943    screen->dontDisconnect = FALSE;
944    screen->authPasswdData = NULL;
945    screen->authPasswdFirstViewOnly = 1;
946 
947    screen->width = width;
948    screen->height = height;
949    screen->bitsPerPixel = screen->depth = 8*bytesPerPixel;
950 
951    screen->passwordCheck = rfbDefaultPasswordCheck;
952 
953    screen->ignoreSIGPIPE = TRUE;
954 
955    /* disable progressive updating per default */
956    screen->progressiveSliceHeight = 0;
957 
958    screen->listenInterface = htonl(INADDR_ANY);
959 
960    screen->deferUpdateTime=5;
961    screen->maxRectsPerUpdate=50;
962 
963    screen->handleEventsEagerly = FALSE;
964 
965    screen->protocolMajorVersion = rfbProtocolMajorVersion;
966    screen->protocolMinorVersion = rfbProtocolMinorVersion;
967 
968    screen->permitFileTransfer = FALSE;
969 
970    if(!rfbProcessArguments(screen,argc,argv)) {
971      free(screen);
972      return NULL;
973    }
974 
975 #ifdef WIN32
976    {
977 	   DWORD dummy=255;
978 	   GetComputerName(screen->thisHost,&dummy);
979    }
980 #else
981    gethostname(screen->thisHost, 255);
982 #endif
983 
984    screen->paddedWidthInBytes = width*bytesPerPixel;
985 
986    /* format */
987 
988    rfbInitServerFormat(screen, bitsPerSample);
989 
990    /* cursor */
991 
992    screen->cursorX=screen->cursorY=screen->underCursorBufferLen=0;
993    screen->underCursorBuffer=NULL;
994    screen->dontConvertRichCursorToXCursor = FALSE;
995    screen->cursor = &myCursor;
996    INIT_MUTEX(screen->cursorMutex);
997 
998 #if defined(LIBVNCSERVER_HAVE_LIBPTHREAD) || defined(LIBVNCSERVER_HAVE_WIN32THREADS)
999    screen->backgroundLoop = FALSE;
1000 #endif
1001 
1002    /* proc's and hook's */
1003 
1004    screen->kbdAddEvent = rfbDefaultKbdAddEvent;
1005    screen->kbdReleaseAllKeys = rfbDoNothingWithClient;
1006    screen->ptrAddEvent = rfbDefaultPtrAddEvent;
1007    screen->setXCutText = rfbDefaultSetXCutText;
1008    screen->getCursorPtr = rfbDefaultGetCursorPtr;
1009    screen->setTranslateFunction = rfbSetTranslateFunction;
1010    screen->newClientHook = rfbDefaultNewClientHook;
1011    screen->displayHook = NULL;
1012    screen->displayFinishedHook = NULL;
1013    screen->getKeyboardLedStateHook = NULL;
1014    screen->xvpHook = NULL;
1015    screen->setDesktopSizeHook = rfbDefaultSetDesktopSize;
1016    screen->numberOfExtDesktopScreensHook = rfbDefaultNumberOfExtDesktopScreens;
1017    screen->getExtDesktopScreenHook = rfbDefaultGetExtDesktopScreen;
1018 
1019    /* initialize client list and iterator mutex */
1020    rfbClientListInit(screen);
1021 
1022    return(screen);
1023 }
1024 
1025 /*
1026  * Switch to another framebuffer (maybe of different size and color
1027  * format). Clients supporting NewFBSize pseudo-encoding will change
1028  * their local framebuffer dimensions if necessary.
1029  * NOTE: Rich cursor data should be converted to new pixel format by
1030  * the caller.
1031  */
1032 
rfbNewFramebuffer(rfbScreenInfoPtr screen,char * framebuffer,int width,int height,int bitsPerSample,int samplesPerPixel,int bytesPerPixel)1033 void rfbNewFramebuffer(rfbScreenInfoPtr screen, char *framebuffer,
1034                        int width, int height,
1035                        int bitsPerSample, int samplesPerPixel,
1036                        int bytesPerPixel)
1037 {
1038   rfbPixelFormat old_format;
1039   rfbBool format_changed = FALSE;
1040   rfbClientIteratorPtr iterator;
1041   rfbClientPtr cl;
1042 
1043   /* Update information in the screenInfo structure */
1044 
1045   old_format = screen->serverFormat;
1046 
1047   if (width & 3)
1048     rfbErr("WARNING: New width (%d) is not a multiple of 4.\n", width);
1049 
1050   screen->width = width;
1051   screen->height = height;
1052   screen->bitsPerPixel = screen->depth = 8*bytesPerPixel;
1053   screen->paddedWidthInBytes = width*bytesPerPixel;
1054 
1055   rfbInitServerFormat(screen, bitsPerSample);
1056 
1057   if (memcmp(&screen->serverFormat, &old_format,
1058              sizeof(rfbPixelFormat)) != 0) {
1059     format_changed = TRUE;
1060   }
1061 
1062   screen->frameBuffer = framebuffer;
1063 
1064   /* Adjust pointer position if necessary */
1065 
1066   if (screen->cursorX >= width)
1067     screen->cursorX = width - 1;
1068   if (screen->cursorY >= height)
1069     screen->cursorY = height - 1;
1070 
1071   /* For each client: */
1072   iterator = rfbGetClientIterator(screen);
1073   while ((cl = rfbClientIteratorNext(iterator)) != NULL) {
1074 
1075     /* Re-install color translation tables if necessary */
1076 
1077     if (format_changed)
1078       screen->setTranslateFunction(cl);
1079 
1080     /* Mark the screen contents as changed, and schedule sending
1081        NewFBSize message if supported by this client. */
1082 
1083     LOCK(cl->updateMutex);
1084     sraRgnDestroy(cl->modifiedRegion);
1085     cl->modifiedRegion = sraRgnCreateRect(0, 0, width, height);
1086     sraRgnMakeEmpty(cl->copyRegion);
1087     cl->copyDX = 0;
1088     cl->copyDY = 0;
1089 
1090     if (cl->useNewFBSize)
1091       cl->newFBSizePending = TRUE;
1092 
1093     TSIGNAL(cl->updateCond);
1094     UNLOCK(cl->updateMutex);
1095   }
1096   rfbReleaseClientIterator(iterator);
1097 }
1098 
1099 /* hang up on all clients and free all reserved memory */
1100 
rfbScreenCleanup(rfbScreenInfoPtr screen)1101 void rfbScreenCleanup(rfbScreenInfoPtr screen)
1102 {
1103   rfbClientIteratorPtr i=rfbGetClientIterator(screen);
1104   rfbClientPtr cl,cl1=rfbClientIteratorNext(i);
1105   while(cl1) {
1106     cl=rfbClientIteratorNext(i);
1107     rfbClientConnectionGone(cl1);
1108     cl1=cl;
1109   }
1110   rfbReleaseClientIterator(i);
1111 
1112 #define FREE_IF(x) if(screen->x) free(screen->x)
1113   FREE_IF(colourMap.data.bytes);
1114   FREE_IF(underCursorBuffer);
1115   TINI_MUTEX(screen->cursorMutex);
1116 
1117   rfbFreeCursor(screen->cursor);
1118 
1119 #ifdef LIBVNCSERVER_HAVE_LIBZ
1120   rfbZlibCleanup(screen);
1121 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
1122   rfbTightCleanup(screen);
1123 #endif
1124 
1125   /* free all 'scaled' versions of this screen */
1126   while (screen->scaledScreenNext!=NULL)
1127   {
1128       rfbScreenInfoPtr ptr;
1129       ptr = screen->scaledScreenNext;
1130       screen->scaledScreenNext = ptr->scaledScreenNext;
1131       free(ptr->frameBuffer);
1132       free(ptr);
1133   }
1134 
1135 #endif
1136   free(screen);
1137 }
1138 
rfbInitServer(rfbScreenInfoPtr screen)1139 void rfbInitServer(rfbScreenInfoPtr screen)
1140 {
1141   rfbInitSockets(screen);
1142   rfbHttpInitSockets(screen);
1143 #ifndef WIN32
1144   if(screen->ignoreSIGPIPE)
1145     signal(SIGPIPE,SIG_IGN);
1146 #endif
1147 }
1148 
rfbShutdownServer(rfbScreenInfoPtr screen,rfbBool disconnectClients)1149 void rfbShutdownServer(rfbScreenInfoPtr screen,rfbBool disconnectClients) {
1150   if(disconnectClients) {
1151     rfbClientIteratorPtr iter = rfbGetClientIterator(screen);
1152     rfbClientPtr nextCl, currentCl = rfbClientIteratorNext(iter);
1153 
1154     while(currentCl) {
1155       nextCl = rfbClientIteratorNext(iter);
1156       if (currentCl->sock != RFB_INVALID_SOCKET) {
1157         /* we don't care about maxfd here, because the server goes away */
1158         rfbCloseClient(currentCl);
1159       }
1160 
1161 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
1162     if(currentCl->screen->backgroundLoop) {
1163       /*
1164 	Notify the thread. This simply writes a NULL byte to the notify pipe in order to get past the select()
1165 	in clientInput(), the loop in there will then break because the rfbCloseClient() above has set
1166 	currentCl->sock to -1.
1167       */
1168       write(currentCl->pipe_notify_client_thread[1], "\x00", 1);
1169       /* And wait for it to finish. */
1170       pthread_join(currentCl->client_thread, NULL);
1171     } else {
1172       rfbClientConnectionGone(currentCl);
1173     }
1174 #else
1175       rfbClientConnectionGone(currentCl);
1176 #endif
1177 
1178       currentCl = nextCl;
1179     }
1180 
1181     rfbReleaseClientIterator(iter);
1182   }
1183 
1184   rfbHttpShutdownSockets(screen);
1185   rfbShutdownSockets(screen);
1186 }
1187 
1188 #if !defined LIBVNCSERVER_HAVE_GETTIMEOFDAY && defined WIN32
1189 #include <fcntl.h>
1190 #include <conio.h>
1191 #include <sys/timeb.h>
1192 
gettimeofday(struct timeval * tv,char * dummy)1193 static void gettimeofday(struct timeval* tv,char* dummy)
1194 {
1195    SYSTEMTIME t;
1196    GetSystemTime(&t);
1197    tv->tv_sec=t.wHour*3600+t.wMinute*60+t.wSecond;
1198    tv->tv_usec=t.wMilliseconds*1000;
1199 }
1200 #endif
1201 
1202 rfbBool
rfbProcessEvents(rfbScreenInfoPtr screen,long usec)1203 rfbProcessEvents(rfbScreenInfoPtr screen,long usec)
1204 {
1205   rfbClientIteratorPtr i;
1206   rfbClientPtr cl,clPrev;
1207   rfbBool result=FALSE;
1208   extern rfbClientIteratorPtr
1209     rfbGetClientIteratorWithClosed(rfbScreenInfoPtr rfbScreen);
1210 
1211   if(usec<0)
1212     usec=screen->deferUpdateTime*1000;
1213 
1214   rfbCheckFds(screen,usec);
1215   rfbHttpCheckFds(screen);
1216 
1217   i = rfbGetClientIteratorWithClosed(screen);
1218   cl=rfbClientIteratorHead(i);
1219   while(cl) {
1220     result = rfbUpdateClient(cl);
1221     clPrev=cl;
1222     cl=rfbClientIteratorNext(i);
1223     if(clPrev->sock==RFB_INVALID_SOCKET) {
1224       rfbClientConnectionGone(clPrev);
1225       result=TRUE;
1226     }
1227   }
1228   rfbReleaseClientIterator(i);
1229 
1230   return result;
1231 }
1232 
1233 rfbBool
rfbUpdateClient(rfbClientPtr cl)1234 rfbUpdateClient(rfbClientPtr cl)
1235 {
1236   struct timeval tv;
1237   rfbBool result=FALSE;
1238   rfbScreenInfoPtr screen = cl->screen;
1239 
1240   if (cl->sock != RFB_INVALID_SOCKET && !cl->onHold && FB_UPDATE_PENDING(cl) &&
1241         !sraRgnEmpty(cl->requestedRegion)) {
1242       result=TRUE;
1243       if(screen->deferUpdateTime == 0) {
1244           rfbSendFramebufferUpdate(cl,cl->modifiedRegion);
1245       } else if(cl->startDeferring.tv_usec == 0) {
1246         gettimeofday(&cl->startDeferring,NULL);
1247         if(cl->startDeferring.tv_usec == 0)
1248           cl->startDeferring.tv_usec++;
1249       } else {
1250         gettimeofday(&tv,NULL);
1251         if(tv.tv_sec < cl->startDeferring.tv_sec /* at midnight */
1252            || ((tv.tv_sec-cl->startDeferring.tv_sec)*1000
1253                +(tv.tv_usec-cl->startDeferring.tv_usec)/1000)
1254              > screen->deferUpdateTime) {
1255           cl->startDeferring.tv_usec = 0;
1256           rfbSendFramebufferUpdate(cl,cl->modifiedRegion);
1257         }
1258       }
1259     }
1260 
1261     if (!cl->viewOnly && cl->lastPtrX >= 0) {
1262       if(cl->startPtrDeferring.tv_usec == 0) {
1263         gettimeofday(&cl->startPtrDeferring,NULL);
1264         if(cl->startPtrDeferring.tv_usec == 0)
1265           cl->startPtrDeferring.tv_usec++;
1266       } else {
1267         struct timeval tv;
1268         gettimeofday(&tv,NULL);
1269         if(tv.tv_sec < cl->startPtrDeferring.tv_sec /* at midnight */
1270            || ((tv.tv_sec-cl->startPtrDeferring.tv_sec)*1000
1271            +(tv.tv_usec-cl->startPtrDeferring.tv_usec)/1000)
1272            > cl->screen->deferPtrUpdateTime) {
1273           cl->startPtrDeferring.tv_usec = 0;
1274           cl->screen->ptrAddEvent(cl->lastPtrButtons,
1275                                   cl->lastPtrX,
1276                                   cl->lastPtrY, cl);
1277           cl->lastPtrX = -1;
1278         }
1279       }
1280     }
1281 
1282     return result;
1283 }
1284 
rfbIsActive(rfbScreenInfoPtr screenInfo)1285 rfbBool rfbIsActive(rfbScreenInfoPtr screenInfo) {
1286   return screenInfo->socketState!=RFB_SOCKET_SHUTDOWN || screenInfo->clientHead!=NULL;
1287 }
1288 
rfbRunEventLoop(rfbScreenInfoPtr screen,long usec,rfbBool runInBackground)1289 void rfbRunEventLoop(rfbScreenInfoPtr screen, long usec, rfbBool runInBackground)
1290 {
1291   if(runInBackground) {
1292 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
1293        pthread_t listener_thread;
1294 
1295        screen->backgroundLoop = TRUE;
1296 
1297        pthread_create(&listener_thread, NULL, listenerRun, screen);
1298     return;
1299 #elif defined(LIBVNCSERVER_HAVE_WIN32THREADS)
1300        screen->backgroundLoop = TRUE;
1301        _beginthread(listenerRun, 0, screen);
1302        return;
1303 #else
1304     rfbErr("Can't run in background, because I don't have PThreads!\n");
1305     return;
1306 #endif
1307   }
1308 
1309   if(usec<0)
1310     usec=screen->deferUpdateTime*1000;
1311 
1312   while(rfbIsActive(screen))
1313     rfbProcessEvents(screen,usec);
1314 }
1315