Home | History | Annotate | Download | only in libvncserver
      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 (at) gmx.de>
      6  *  Original OSXvnc (C) 2001 Dan McGuirk <mcguirk (at) 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
     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
    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 
    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 
    157 void rfbReleaseExtensionIterator()
    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 
    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 
    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 {
    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 
    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 	{
    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*
    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
    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);
    627     rfbClientConnectionGone(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);
   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 
   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 
   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 
   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
   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
   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 
   1175 rfbBool rfbIsActive(rfbScreenInfoPtr screenInfo) {
   1176   return screenInfo->socketState!=RFB_SOCKET_SHUTDOWN || screenInfo->clientHead!=NULL;
   1177 }
   1178 
   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