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