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