LibVNCServer/LibVNCClient
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
main.c
Go to the documentation of this file.
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
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);
89  return;
90  }
91 
92  head = head->next;
93  }
94 
95  extension->next = rfbExtensionHead;
96  rfbExtensionHead = extension;
97 
98  UNLOCK(extMutex);
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
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);
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 
144 }
145 
147 {
148  if (! extMutex_initialized) {
149  INIT_MUTEX(extMutex);
150  extMutex_initialized = 1;
151  }
152 
153  LOCK(extMutex);
154  return rfbExtensionHead;
155 }
156 
158 {
159  UNLOCK(extMutex);
160 }
161 
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 
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 
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 
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
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 
262 void rfbLogPerror(const char *str)
263 {
264  rfbErr("%s: %s\n", str, strerror(errno));
265 }
266 
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 
356 void rfbDoCopyRegion(rfbScreenInfoPtr screen,sraRegionPtr copyRegion,int dx,int dy)
357 {
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  }
381 
382  rfbScheduleCopyRegion(screen,copyRegion,dx,dy);
383 }
384 
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 
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 
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);
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 *
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 *
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  {
545  continue;
546  }
547 
548  /* We have some space on the transmit queue, send some data */
549  if (FD_ISSET(cl->sock, &wfds))
551 
552  if (FD_ISSET(cl->sock, &rfds) || FD_ISSET(cl->sock, &efds))
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 
563 
564  return NULL;
565 }
566 
567 static void*
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 )
603  }
604  return(NULL);
605 }
606 
607 void
608 rfbStartOnHoldClient(rfbClientPtr cl)
609 {
610  pthread_create(&cl->client_thread, NULL, clientInput, (void *)cl);
611 }
612 
613 #else
614 
615 void
616 rfbStartOnHoldClient(rfbClientPtr cl)
617 {
618  cl->onHold = FALSE;
619 }
620 
621 #endif
622 
623 void
624 rfbRefuseOnHoldClient(rfbClientPtr cl)
625 {
626  rfbCloseClient(cl);
628 }
629 
630 static void
631 rfbDefaultKbdAddEvent(rfbBool down, rfbKeySym keySym, rfbClientPtr cl)
632 {
633 }
634 
635 void
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 
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 
696 static rfbCursorPtr rfbDefaultGetCursorPtr(rfbClientPtr cl)
697 {
698  return(cl->screen->cursor);
699 }
700 
701 /* response is cl->authChallenge vncEncrypted with passwd */
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. */
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 
754 void rfbDoNothingWithClient(rfbClientPtr cl)
755 {
756 }
757 
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 
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 
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 
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 
1008 void rfbScreenCleanup(rfbScreenInfoPtr screen)
1009 {
1010  rfbClientIteratorPtr i=rfbGetClientIterator(screen);
1011  rfbClientPtr cl,cl1=rfbClientIteratorNext(i);
1012  while(cl1) {
1013  cl=rfbClientIteratorNext(i);
1015  cl1=cl;
1016  }
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 
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 __MINGW32__
1055  if(screen->ignoreSIGPIPE)
1056  signal(SIGPIPE,SIG_IGN);
1057 #endif
1058 }
1059 
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);
1069  }
1070 
1071  rfbShutdownSockets(screen);
1072  rfbHttpShutdownSockets(screen);
1073 }
1074 
1075 #ifndef LIBVNCSERVER_HAVE_GETTIMEOFDAY
1076 #include <fcntl.h>
1077 #include <conio.h>
1078 #include <sys/timeb.h>
1079 
1080 void gettimeofday(struct timeval* tv,char* dummy)
1081 {
1082  SYSTEMTIME t;
1083  GetSystemTime(&t);
1084  tv->tv_sec=t.wHour*3600+t.wMinute*60+t.wSecond;
1085  tv->tv_usec=t.wMilliseconds*1000;
1086 }
1087 #endif
1088 
1089 rfbBool
1090 rfbProcessEvents(rfbScreenInfoPtr screen,long usec)
1091 {
1092  rfbClientIteratorPtr i;
1093  rfbClientPtr cl,clPrev;
1094  rfbBool result=FALSE;
1095  extern rfbClientIteratorPtr
1096  rfbGetClientIteratorWithClosed(rfbScreenInfoPtr rfbScreen);
1097 
1098  if(usec<0)
1099  usec=screen->deferUpdateTime*1000;
1100 
1101  rfbCheckFds(screen,usec);
1102  rfbHttpCheckFds(screen);
1103 
1104  i = rfbGetClientIteratorWithClosed(screen);
1105  cl=rfbClientIteratorHead(i);
1106  while(cl) {
1107  result = rfbUpdateClient(cl);
1108  clPrev=cl;
1109  cl=rfbClientIteratorNext(i);
1110  if(clPrev->sock==-1) {
1111  rfbClientConnectionGone(clPrev);
1112  result=TRUE;
1113  }
1114  }
1116 
1117  return result;
1118 }
1119 
1120 rfbBool
1121 rfbUpdateClient(rfbClientPtr cl)
1122 {
1123  struct timeval tv;
1124  rfbBool result=FALSE;
1125  rfbScreenInfoPtr screen = cl->screen;
1126 
1127  if (cl->sock >= 0 && !cl->onHold && FB_UPDATE_PENDING(cl) &&
1128  !sraRgnEmpty(cl->requestedRegion)) {
1129  result=TRUE;
1130  if(screen->deferUpdateTime == 0) {
1131  rfbSendFramebufferUpdate(cl,cl->modifiedRegion);
1132  } else if(cl->startDeferring.tv_usec == 0) {
1133  gettimeofday(&cl->startDeferring,NULL);
1134  if(cl->startDeferring.tv_usec == 0)
1135  cl->startDeferring.tv_usec++;
1136  } else {
1137  gettimeofday(&tv,NULL);
1138  if(tv.tv_sec < cl->startDeferring.tv_sec /* at midnight */
1139  || ((tv.tv_sec-cl->startDeferring.tv_sec)*1000
1140  +(tv.tv_usec-cl->startDeferring.tv_usec)/1000)
1141  > screen->deferUpdateTime) {
1142  cl->startDeferring.tv_usec = 0;
1143  rfbSendFramebufferUpdate(cl,cl->modifiedRegion);
1144  }
1145  }
1146  }
1147 
1148  if (!cl->viewOnly && cl->lastPtrX >= 0) {
1149  if(cl->startPtrDeferring.tv_usec == 0) {
1150  gettimeofday(&cl->startPtrDeferring,NULL);
1151  if(cl->startPtrDeferring.tv_usec == 0)
1152  cl->startPtrDeferring.tv_usec++;
1153  } else {
1154  struct timeval tv;
1155  gettimeofday(&tv,NULL);
1156  if(tv.tv_sec < cl->startPtrDeferring.tv_sec /* at midnight */
1157  || ((tv.tv_sec-cl->startPtrDeferring.tv_sec)*1000
1158  +(tv.tv_usec-cl->startPtrDeferring.tv_usec)/1000)
1159  > cl->screen->deferPtrUpdateTime) {
1160  cl->startPtrDeferring.tv_usec = 0;
1161  cl->screen->ptrAddEvent(cl->lastPtrButtons,
1162  cl->lastPtrX,
1163  cl->lastPtrY, cl);
1164  cl->lastPtrX = -1;
1165  }
1166  }
1167  }
1168 
1169  return result;
1170 }
1171 
1172 rfbBool rfbIsActive(rfbScreenInfoPtr screenInfo) {
1173  return screenInfo->socketState!=RFB_SOCKET_SHUTDOWN || screenInfo->clientHead!=NULL;
1174 }
1175 
1176 void rfbRunEventLoop(rfbScreenInfoPtr screen, long usec, rfbBool runInBackground)
1177 {
1178  if(runInBackground) {
1179 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
1180  pthread_t listener_thread;
1181 
1182  screen->backgroundLoop = TRUE;
1183 
1184  pthread_create(&listener_thread, NULL, listenerRun, screen);
1185  return;
1186 #else
1187  rfbErr("Can't run in background, because I don't have PThreads!\n");
1188  return;
1189 #endif
1190  }
1191 
1192  if(usec<0)
1193  usec=screen->deferUpdateTime*1000;
1194 
1195  while(rfbIsActive(screen))
1196  rfbProcessEvents(screen,usec);
1197 }