2 * This file is called main.c, because it contains most of the new functions
3 * for use with LibVNCServer.
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.
10 * see GPL (latest version) for full details
13 #ifdef __STRICT_ANSI__
17 #include <rfb/rfbregion.h>
28 #ifdef LIBVNCSERVER_HAVE_SYS_TYPES_H
29 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <netinet/in.h>
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);
48 static int rfbEnableLogging=1;
50 #ifdef LIBVNCSERVER_WORDS_BIGENDIAN
51 char rfbEndianTest = (1==0);
53 char rfbEndianTest = (1==1);
60 static rfbProtocolExtension* rfbExtensionHead = NULL;
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.
69 rfbRegisterProtocolExtension(rfbProtocolExtension* extension)
71 rfbProtocolExtension *head = rfbExtensionHead, *next = NULL;
76 next = extension->next;
78 if (! extMutex_initialized) {
80 extMutex_initialized = 1;
86 if(head == extension) {
88 rfbRegisterProtocolExtension(next);
95 extension->next = rfbExtensionHead;
96 rfbExtensionHead = extension;
99 rfbRegisterProtocolExtension(next);
103 * This method unregisters a list of extensions.
104 * These extensions won't be available for any new
108 rfbUnregisterProtocolExtension(rfbProtocolExtension* extension)
111 rfbProtocolExtension *cur = NULL, *pre = NULL;
113 if(extension == NULL)
116 if (! extMutex_initialized) {
117 INIT_MUTEX(extMutex);
118 extMutex_initialized = 1;
123 if(rfbExtensionHead == extension) {
124 rfbExtensionHead = rfbExtensionHead->next;
126 rfbUnregisterProtocolExtension(extension->next);
130 cur = pre = rfbExtensionHead;
133 if(cur == extension) {
134 pre->next = cur->next;
143 rfbUnregisterProtocolExtension(extension->next);
146 rfbProtocolExtension* rfbGetExtensionIterator()
149 return rfbExtensionHead;
152 void rfbReleaseExtensionIterator()
157 rfbBool rfbEnableExtension(rfbClientPtr cl, rfbProtocolExtension* extension,
160 rfbExtensionData* extData;
162 /* make sure extension is not yet enabled. */
163 for(extData = cl->extensions; extData; extData = extData->next)
164 if(extData->extension == extension)
167 extData = calloc(sizeof(rfbExtensionData),1);
168 extData->extension = extension;
169 extData->data = data;
170 extData->next = cl->extensions;
171 cl->extensions = extData;
176 rfbBool rfbDisableExtension(rfbClientPtr cl, rfbProtocolExtension* extension)
178 rfbExtensionData* extData;
179 rfbExtensionData* prevData = NULL;
181 for(extData = cl->extensions; extData; extData = extData->next) {
182 if(extData->extension == extension) {
186 cl->extensions = extData->next;
188 prevData->next = extData->next;
197 void* rfbGetExtensionClientData(rfbClientPtr cl, rfbProtocolExtension* extension)
199 rfbExtensionData* data = cl->extensions;
201 while(data && data->extension != extension)
205 rfbLog("Extension is not enabled !\n");
206 /* rfbCloseClient(cl); */
217 void rfbLogEnable(int enabled) {
218 rfbEnableLogging=enabled;
222 * rfbLog prints a time-stamped message to the log file (stderr).
226 rfbDefaultLog(const char *format, ...)
232 if(!rfbEnableLogging)
235 if (! logMutex_initialized) {
236 INIT_MUTEX(logMutex);
237 logMutex_initialized = 1;
241 va_start(args, format);
244 strftime(buf, 255, "%d/%m/%Y %X ", localtime(&log_clock));
247 vfprintf(stderr, format, args);
254 rfbLogProc rfbLog=rfbDefaultLog;
255 rfbLogProc rfbErr=rfbDefaultLog;
257 void rfbLogPerror(const char *str)
259 rfbErr("%s: %s\n", str, strerror(errno));
262 void rfbScheduleCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,int dx,int dy)
264 rfbClientIteratorPtr iterator;
267 iterator=rfbGetClientIterator(rfbScreen);
268 while((cl=rfbClientIteratorNext(iterator))) {
269 LOCK(cl->updateMutex);
270 if(cl->useCopyRect) {
271 sraRegionPtr modifiedRegionBackup;
272 if(!sraRgnEmpty(cl->copyRegion)) {
273 if(cl->copyDX!=dx || cl->copyDY!=dy) {
274 /* if a copyRegion was not yet executed, treat it as a
275 * modifiedRegion. The idea: in this case it could be
276 * source of the new copyRect or modified anyway. */
277 sraRgnOr(cl->modifiedRegion,cl->copyRegion);
278 sraRgnMakeEmpty(cl->copyRegion);
280 /* we have to set the intersection of the source of the copy
281 * and the old copy to modified. */
282 modifiedRegionBackup=sraRgnCreateRgn(copyRegion);
283 sraRgnOffset(modifiedRegionBackup,-dx,-dy);
284 sraRgnAnd(modifiedRegionBackup,cl->copyRegion);
285 sraRgnOr(cl->modifiedRegion,modifiedRegionBackup);
286 sraRgnDestroy(modifiedRegionBackup);
290 sraRgnOr(cl->copyRegion,copyRegion);
294 /* if there were modified regions, which are now copied,
295 * mark them as modified, because the source of these can be overlapped
296 * either by new modified or now copied regions. */
297 modifiedRegionBackup=sraRgnCreateRgn(cl->modifiedRegion);
298 sraRgnOffset(modifiedRegionBackup,dx,dy);
299 sraRgnAnd(modifiedRegionBackup,cl->copyRegion);
300 sraRgnOr(cl->modifiedRegion,modifiedRegionBackup);
301 sraRgnDestroy(modifiedRegionBackup);
303 if(!cl->enableCursorShapeUpdates) {
305 * n.b. (dx, dy) is the vector pointing in the direction the
306 * copyrect displacement will take place. copyRegion is the
307 * destination rectangle (say), not the source rectangle.
309 sraRegionPtr cursorRegion;
310 int x = cl->cursorX - cl->screen->cursor->xhot;
311 int y = cl->cursorY - cl->screen->cursor->yhot;
312 int w = cl->screen->cursor->width;
313 int h = cl->screen->cursor->height;
315 cursorRegion = sraRgnCreateRect(x, y, x + w, y + h);
316 sraRgnAnd(cursorRegion, cl->copyRegion);
317 if(!sraRgnEmpty(cursorRegion)) {
319 * current cursor rect overlaps with the copy region *dest*,
320 * mark it as modified since we won't copy-rect stuff to it.
322 sraRgnOr(cl->modifiedRegion, cursorRegion);
324 sraRgnDestroy(cursorRegion);
326 cursorRegion = sraRgnCreateRect(x, y, x + w, y + h);
327 /* displace it to check for overlap with copy region source: */
328 sraRgnOffset(cursorRegion, dx, dy);
329 sraRgnAnd(cursorRegion, cl->copyRegion);
330 if(!sraRgnEmpty(cursorRegion)) {
332 * current cursor rect overlaps with the copy region *source*,
333 * mark the *displaced* cursorRegion as modified since we
334 * won't copyrect stuff to it.
336 sraRgnOr(cl->modifiedRegion, cursorRegion);
338 sraRgnDestroy(cursorRegion);
342 sraRgnOr(cl->modifiedRegion,copyRegion);
344 TSIGNAL(cl->updateCond);
345 UNLOCK(cl->updateMutex);
348 rfbReleaseClientIterator(iterator);
351 void rfbDoCopyRegion(rfbScreenInfoPtr screen,sraRegionPtr copyRegion,int dx,int dy)
353 sraRectangleIterator* i;
355 int j,widthInBytes,bpp=screen->serverFormat.bitsPerPixel/8,
356 rowstride=screen->paddedWidthInBytes;
359 /* copy it, really */
360 i = sraRgnGetReverseIterator(copyRegion,dx<0,dy<0);
361 while(sraRgnIteratorNext(i,&rect)) {
362 widthInBytes = (rect.x2-rect.x1)*bpp;
363 out = screen->frameBuffer+rect.x1*bpp+rect.y1*rowstride;
364 in = screen->frameBuffer+(rect.x1-dx)*bpp+(rect.y1-dy)*rowstride;
366 for(j=rect.y1;j<rect.y2;j++,out+=rowstride,in+=rowstride)
367 memmove(out,in,widthInBytes);
369 out += rowstride*(rect.y2-rect.y1-1);
370 in += rowstride*(rect.y2-rect.y1-1);
371 for(j=rect.y2-1;j>=rect.y1;j--,out-=rowstride,in-=rowstride)
372 memmove(out,in,widthInBytes);
375 sraRgnReleaseIterator(i);
377 rfbScheduleCopyRegion(screen,copyRegion,dx,dy);
380 void rfbDoCopyRect(rfbScreenInfoPtr screen,int x1,int y1,int x2,int y2,int dx,int dy)
382 sraRegionPtr region = sraRgnCreateRect(x1,y1,x2,y2);
383 rfbDoCopyRegion(screen,region,dx,dy);
384 sraRgnDestroy(region);
387 void rfbScheduleCopyRect(rfbScreenInfoPtr screen,int x1,int y1,int x2,int y2,int dx,int dy)
389 sraRegionPtr region = sraRgnCreateRect(x1,y1,x2,y2);
390 rfbScheduleCopyRegion(screen,region,dx,dy);
391 sraRgnDestroy(region);
394 void rfbMarkRegionAsModified(rfbScreenInfoPtr screen,sraRegionPtr modRegion)
396 rfbClientIteratorPtr iterator;
399 iterator=rfbGetClientIterator(screen);
400 while((cl=rfbClientIteratorNext(iterator))) {
401 LOCK(cl->updateMutex);
402 sraRgnOr(cl->modifiedRegion,modRegion);
403 TSIGNAL(cl->updateCond);
404 UNLOCK(cl->updateMutex);
407 rfbReleaseClientIterator(iterator);
410 void rfbScaledScreenUpdate(rfbScreenInfoPtr screen, int x1, int y1, int x2, int y2);
411 void rfbMarkRectAsModified(rfbScreenInfoPtr screen,int x1,int y1,int x2,int y2)
416 if(x1>x2) { i=x1; x1=x2; x2=i; }
418 if(x2>screen->width) x2=screen->width;
421 if(y1>y2) { i=y1; y1=y2; y2=i; }
423 if(y2>screen->height) y2=screen->height;
426 /* update scaled copies for this rectangle */
427 rfbScaledScreenUpdate(screen,x1,y1,x2,y2);
429 region = sraRgnCreateRect(x1,y1,x2,y2);
430 rfbMarkRegionAsModified(screen,region);
431 sraRgnDestroy(region);
434 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
438 clientOutput(void *data)
440 rfbClientPtr cl = (rfbClientPtr)data;
442 sraRegion* updateRegion;
446 while (!haveUpdate) {
447 if (cl->sock == -1) {
448 /* Client has disconnected. */
451 LOCK(cl->updateMutex);
452 haveUpdate = FB_UPDATE_PENDING(cl);
454 updateRegion = sraRgnCreateRgn(cl->modifiedRegion);
455 haveUpdate = sraRgnAnd(updateRegion,cl->requestedRegion);
456 sraRgnDestroy(updateRegion);
460 WAIT(cl->updateCond, cl->updateMutex);
462 UNLOCK(cl->updateMutex);
465 /* OK, now, to save bandwidth, wait a little while for more
466 updates to come along. */
467 usleep(cl->screen->deferUpdateTime * 1000);
469 /* Now, get the region we're going to update, and remove
470 it from cl->modifiedRegion _before_ we send the update.
471 That way, if anything that overlaps the region we're sending
472 is updated, we'll be sure to do another update later. */
473 LOCK(cl->updateMutex);
474 updateRegion = sraRgnCreateRgn(cl->modifiedRegion);
475 UNLOCK(cl->updateMutex);
477 /* Now actually send the update. */
478 rfbIncrClientRef(cl);
479 rfbSendFramebufferUpdate(cl, updateRegion);
480 rfbDecrClientRef(cl);
482 sraRgnDestroy(updateRegion);
490 clientInput(void *data)
492 rfbClientPtr cl = (rfbClientPtr)data;
493 pthread_t output_thread;
494 pthread_create(&output_thread, NULL, clientOutput, (void *)cl);
497 fd_set rfds, wfds, efds;
502 FD_SET(cl->sock, &rfds);
504 FD_SET(cl->sock, &efds);
506 /* Are we transferring a file in the background? */
508 if ((cl->fileTransfer.fd!=-1) && (cl->fileTransfer.sending==1))
509 FD_SET(cl->sock, &wfds);
511 tv.tv_sec = 60; /* 1 minute */
513 n = select(cl->sock + 1, &rfds, &wfds, &efds, &tv);
515 rfbLogPerror("ReadExact: select");
518 if (n == 0) /* timeout */
520 rfbSendFileTransferChunk(cl);
524 /* We have some space on the transmit queue, send some data */
525 if (FD_ISSET(cl->sock, &wfds))
526 rfbSendFileTransferChunk(cl);
528 if (FD_ISSET(cl->sock, &rfds) || FD_ISSET(cl->sock, &efds))
529 rfbProcessClientMessage(cl);
531 if (cl->sock == -1) {
532 /* Client has disconnected. */
537 /* Get rid of the output thread. */
538 LOCK(cl->updateMutex);
539 TSIGNAL(cl->updateCond);
540 UNLOCK(cl->updateMutex);
541 IF_PTHREADS(pthread_join(output_thread, NULL));
543 rfbClientConnectionGone(cl);
549 listenerRun(void *data)
551 rfbScreenInfoPtr screen=(rfbScreenInfoPtr)data;
553 struct sockaddr_in peer;
559 /* TODO: this thread wont die by restarting the server */
560 /* TODO: HTTP is not handled */
561 while ((client_fd = accept(screen->listenSock,
562 (struct sockaddr*)&peer, &len)) >= 0) {
563 cl = rfbNewClient(screen,client_fd);
566 if (cl && !cl->onHold )
567 rfbStartOnHoldClient(cl);
573 rfbStartOnHoldClient(rfbClientPtr cl)
575 pthread_create(&cl->client_thread, NULL, clientInput, (void *)cl);
581 rfbStartOnHoldClient(rfbClientPtr cl)
589 rfbRefuseOnHoldClient(rfbClientPtr cl)
592 rfbClientConnectionGone(cl);
596 rfbDefaultKbdAddEvent(rfbBool down, rfbKeySym keySym, rfbClientPtr cl)
601 rfbDefaultPtrAddEvent(int buttonMask, int x, int y, rfbClientPtr cl)
603 rfbClientIteratorPtr iterator;
604 rfbClientPtr other_client;
605 rfbScreenInfoPtr s = cl->screen;
607 if (x != s->cursorX || y != s->cursorY) {
608 LOCK(s->cursorMutex);
611 UNLOCK(s->cursorMutex);
613 /* The cursor was moved by this client, so don't send CursorPos. */
614 if (cl->enableCursorPosUpdates)
615 cl->cursorWasMoved = FALSE;
617 /* But inform all remaining clients about this cursor movement. */
618 iterator = rfbGetClientIterator(s);
619 while ((other_client = rfbClientIteratorNext(iterator)) != NULL) {
620 if (other_client != cl && other_client->enableCursorPosUpdates) {
621 other_client->cursorWasMoved = TRUE;
624 rfbReleaseClientIterator(iterator);
628 static void rfbDefaultSetXCutText(char* text, int len, rfbClientPtr cl)
632 /* TODO: add a nice VNC or RFB cursor */
634 #if defined(WIN32) || defined(sparc) || !defined(NO_STRICT_ANSI)
635 static rfbCursor myCursor =
637 FALSE, FALSE, FALSE, FALSE,
638 (unsigned char*)"\000\102\044\030\044\102\000",
639 (unsigned char*)"\347\347\176\074\176\347\347",
642 0xffff, 0xffff, 0xffff,
646 static rfbCursor myCursor =
649 cleanupSource: FALSE,
651 cleanupRichSource: FALSE,
652 source: "\000\102\044\030\044\102\000",
653 mask: "\347\347\176\074\176\347\347",
654 width: 8, height: 7, xhot: 3, yhot: 3,
655 foreRed: 0, foreGreen: 0, foreBlue: 0,
656 backRed: 0xffff, backGreen: 0xffff, backBlue: 0xffff,
661 static rfbCursorPtr rfbDefaultGetCursorPtr(rfbClientPtr cl)
663 return(cl->screen->cursor);
666 /* response is cl->authChallenge vncEncrypted with passwd */
667 static rfbBool rfbDefaultPasswordCheck(rfbClientPtr cl,const char* response,int len)
670 char *passwd=rfbDecryptPasswdFromFile(cl->screen->authPasswdData);
673 rfbErr("Couldn't read password file: %s\n",cl->screen->authPasswdData);
677 rfbEncryptBytes(cl->authChallenge, passwd);
679 /* Lose the password from memory */
680 for (i = strlen(passwd); i >= 0; i--) {
686 if (memcmp(cl->authChallenge, response, len) != 0) {
687 rfbErr("authProcessClientMessage: authentication failed from %s\n",
695 /* for this method, authPasswdData is really a pointer to an array
696 of char*'s, where the last pointer is 0. */
697 rfbBool rfbCheckPasswordByList(rfbClientPtr cl,const char* response,int len)
702 for(passwds=(char**)cl->screen->authPasswdData;*passwds;passwds++,i++) {
703 uint8_t auth_tmp[CHALLENGESIZE];
704 memcpy((char *)auth_tmp, (char *)cl->authChallenge, CHALLENGESIZE);
705 rfbEncryptBytes(auth_tmp, *passwds);
707 if (memcmp(auth_tmp, response, len) == 0) {
708 if(i>=cl->screen->authPasswdFirstViewOnly)
714 rfbErr("authProcessClientMessage: authentication failed from %s\n",
719 void rfbDoNothingWithClient(rfbClientPtr cl)
723 static enum rfbNewClientAction rfbDefaultNewClientHook(rfbClientPtr cl)
725 return RFB_CLIENT_ACCEPT;
729 * Update server's pixel format in screenInfo structure. This
730 * function is called from rfbGetScreen() and rfbNewFramebuffer().
733 static void rfbInitServerFormat(rfbScreenInfoPtr screen, int bitsPerSample)
735 rfbPixelFormat* format=&screen->serverFormat;
737 format->bitsPerPixel = screen->bitsPerPixel;
738 format->depth = screen->depth;
739 format->bigEndian = rfbEndianTest?FALSE:TRUE;
740 format->trueColour = TRUE;
741 screen->colourMap.count = 0;
742 screen->colourMap.is16 = 0;
743 screen->colourMap.data.bytes = NULL;
745 if (format->bitsPerPixel == 8) {
747 format->greenMax = 7;
749 format->redShift = 0;
750 format->greenShift = 3;
751 format->blueShift = 6;
753 format->redMax = (1 << bitsPerSample) - 1;
754 format->greenMax = (1 << bitsPerSample) - 1;
755 format->blueMax = (1 << bitsPerSample) - 1;
757 format->redShift = 0;
758 format->greenShift = bitsPerSample;
759 format->blueShift = bitsPerSample * 2;
761 if(format->bitsPerPixel==8*3) {
762 format->redShift = bitsPerSample*2;
763 format->greenShift = bitsPerSample*1;
764 format->blueShift = 0;
766 format->redShift = bitsPerSample*3;
767 format->greenShift = bitsPerSample*2;
768 format->blueShift = bitsPerSample;
774 rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv,
775 int width,int height,int bitsPerSample,int samplesPerPixel,
778 rfbScreenInfoPtr screen=calloc(sizeof(rfbScreenInfo),1);
780 if (! logMutex_initialized) {
781 INIT_MUTEX(logMutex);
782 logMutex_initialized = 1;
787 rfbErr("WARNING: Width (%d) is not a multiple of 4. VncViewer has problems with that.\n",width);
789 screen->autoPort=FALSE;
790 screen->clientHead=NULL;
791 screen->pointerClient=NULL;
793 screen->socketState=RFB_SOCKET_INIT;
795 screen->inetdInitDone = FALSE;
796 screen->inetdSock=-1;
799 screen->udpSockConnected=FALSE;
801 screen->udpClient=NULL;
804 screen->listenSock=-1;
806 screen->httpInitDone=FALSE;
807 screen->httpEnableProxyConnect=FALSE;
809 screen->httpDir=NULL;
810 screen->httpListenSock=-1;
813 screen->desktopName = "LibVNCServer";
814 screen->alwaysShared = FALSE;
815 screen->neverShared = FALSE;
816 screen->dontDisconnect = FALSE;
817 screen->authPasswdData = NULL;
818 screen->authPasswdFirstViewOnly = 1;
820 screen->width = width;
821 screen->height = height;
822 screen->bitsPerPixel = screen->depth = 8*bytesPerPixel;
824 screen->passwordCheck = rfbDefaultPasswordCheck;
826 screen->ignoreSIGPIPE = TRUE;
828 /* disable progressive updating per default */
829 screen->progressiveSliceHeight = 0;
831 screen->listenInterface = htonl(INADDR_ANY);
833 screen->deferUpdateTime=5;
834 screen->maxRectsPerUpdate=50;
836 screen->handleEventsEagerly = FALSE;
838 screen->protocolMajorVersion = rfbProtocolMajorVersion;
839 screen->protocolMinorVersion = rfbProtocolMinorVersion;
841 screen->permitFileTransfer = FALSE;
843 if(!rfbProcessArguments(screen,argc,argv)) {
851 GetComputerName(screen->thisHost,&dummy);
854 gethostname(screen->thisHost, 255);
857 screen->paddedWidthInBytes = width*bytesPerPixel;
861 rfbInitServerFormat(screen, bitsPerSample);
865 screen->cursorX=screen->cursorY=screen->underCursorBufferLen=0;
866 screen->underCursorBuffer=NULL;
867 screen->dontConvertRichCursorToXCursor = FALSE;
868 screen->cursor = &myCursor;
869 INIT_MUTEX(screen->cursorMutex);
871 IF_PTHREADS(screen->backgroundLoop = FALSE);
873 /* proc's and hook's */
875 screen->kbdAddEvent = rfbDefaultKbdAddEvent;
876 screen->kbdReleaseAllKeys = rfbDoNothingWithClient;
877 screen->ptrAddEvent = rfbDefaultPtrAddEvent;
878 screen->setXCutText = rfbDefaultSetXCutText;
879 screen->getCursorPtr = rfbDefaultGetCursorPtr;
880 screen->setTranslateFunction = rfbSetTranslateFunction;
881 screen->newClientHook = rfbDefaultNewClientHook;
882 screen->displayHook = NULL;
883 screen->getKeyboardLedStateHook = NULL;
885 /* initialize client list and iterator mutex */
886 rfbClientListInit(screen);
892 * Switch to another framebuffer (maybe of different size and color
893 * format). Clients supporting NewFBSize pseudo-encoding will change
894 * their local framebuffer dimensions if necessary.
895 * NOTE: Rich cursor data should be converted to new pixel format by
899 void rfbNewFramebuffer(rfbScreenInfoPtr screen, char *framebuffer,
900 int width, int height,
901 int bitsPerSample, int samplesPerPixel,
904 rfbPixelFormat old_format;
905 rfbBool format_changed = FALSE;
906 rfbClientIteratorPtr iterator;
909 /* Update information in the screenInfo structure */
911 old_format = screen->serverFormat;
914 rfbErr("WARNING: New width (%d) is not a multiple of 4.\n", width);
916 screen->width = width;
917 screen->height = height;
918 screen->bitsPerPixel = screen->depth = 8*bytesPerPixel;
919 screen->paddedWidthInBytes = width*bytesPerPixel;
921 rfbInitServerFormat(screen, bitsPerSample);
923 if (memcmp(&screen->serverFormat, &old_format,
924 sizeof(rfbPixelFormat)) != 0) {
925 format_changed = TRUE;
928 screen->frameBuffer = framebuffer;
930 /* Adjust pointer position if necessary */
932 if (screen->cursorX >= width)
933 screen->cursorX = width - 1;
934 if (screen->cursorY >= height)
935 screen->cursorY = height - 1;
937 /* For each client: */
938 iterator = rfbGetClientIterator(screen);
939 while ((cl = rfbClientIteratorNext(iterator)) != NULL) {
941 /* Re-install color translation tables if necessary */
944 screen->setTranslateFunction(cl);
946 /* Mark the screen contents as changed, and schedule sending
947 NewFBSize message if supported by this client. */
949 LOCK(cl->updateMutex);
950 sraRgnDestroy(cl->modifiedRegion);
951 cl->modifiedRegion = sraRgnCreateRect(0, 0, width, height);
952 sraRgnMakeEmpty(cl->copyRegion);
956 if (cl->useNewFBSize)
957 cl->newFBSizePending = TRUE;
959 TSIGNAL(cl->updateCond);
960 UNLOCK(cl->updateMutex);
962 rfbReleaseClientIterator(iterator);
965 /* hang up on all clients and free all reserved memory */
967 void rfbScreenCleanup(rfbScreenInfoPtr screen)
969 rfbClientIteratorPtr i=rfbGetClientIterator(screen);
970 rfbClientPtr cl,cl1=rfbClientIteratorNext(i);
972 cl=rfbClientIteratorNext(i);
973 rfbClientConnectionGone(cl1);
976 rfbReleaseClientIterator(i);
978 #define FREE_IF(x) if(screen->x) free(screen->x)
979 FREE_IF(colourMap.data.bytes);
980 FREE_IF(underCursorBuffer);
981 TINI_MUTEX(screen->cursorMutex);
982 if(screen->cursor && screen->cursor->cleanup)
983 rfbFreeCursor(screen->cursor);
985 rfbRRECleanup(screen);
986 rfbCoRRECleanup(screen);
987 rfbUltraCleanup(screen);
988 #ifdef LIBVNCSERVER_HAVE_LIBZ
989 rfbZlibCleanup(screen);
990 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
991 rfbTightCleanup(screen);
994 /* free all 'scaled' versions of this screen */
995 while (screen->scaledScreenNext!=NULL)
997 rfbScreenInfoPtr ptr;
998 ptr = screen->scaledScreenNext;
999 screen->scaledScreenNext = ptr->scaledScreenNext;
1000 free(ptr->frameBuffer);
1008 void rfbInitServer(rfbScreenInfoPtr screen)
1012 WSAStartup(MAKEWORD(2,2),&trash);
1014 rfbInitSockets(screen);
1015 rfbHttpInitSockets(screen);
1017 if(screen->ignoreSIGPIPE)
1018 signal(SIGPIPE,SIG_IGN);
1022 void rfbShutdownServer(rfbScreenInfoPtr screen,rfbBool disconnectClients) {
1023 if(disconnectClients) {
1025 rfbClientIteratorPtr iter = rfbGetClientIterator(screen);
1026 while( (cl = rfbClientIteratorNext(iter)) )
1028 /* we don't care about maxfd here, because the server goes away */
1030 rfbReleaseClientIterator(iter);
1033 rfbShutdownSockets(screen);
1034 rfbHttpShutdownSockets(screen);
1037 #ifndef LIBVNCSERVER_HAVE_GETTIMEOFDAY
1040 #include <sys/timeb.h>
1042 void gettimeofday(struct timeval* tv,char* dummy)
1046 tv->tv_sec=t.wHour*3600+t.wMinute*60+t.wSecond;
1047 tv->tv_usec=t.wMilliseconds*1000;
1052 rfbProcessEvents(rfbScreenInfoPtr screen,long usec)
1054 rfbClientIteratorPtr i;
1055 rfbClientPtr cl,clPrev;
1057 rfbBool result=FALSE;
1058 extern rfbClientIteratorPtr
1059 rfbGetClientIteratorWithClosed(rfbScreenInfoPtr rfbScreen);
1062 usec=screen->deferUpdateTime*1000;
1064 rfbCheckFds(screen,usec);
1065 rfbHttpCheckFds(screen);
1067 corbaCheckFds(screen);
1070 i = rfbGetClientIteratorWithClosed(screen);
1071 cl=rfbClientIteratorHead(i);
1073 if (cl->sock >= 0 && !cl->onHold && FB_UPDATE_PENDING(cl) &&
1074 !sraRgnEmpty(cl->requestedRegion)) {
1076 if(screen->deferUpdateTime == 0) {
1077 rfbSendFramebufferUpdate(cl,cl->modifiedRegion);
1078 } else if(cl->startDeferring.tv_usec == 0) {
1079 gettimeofday(&cl->startDeferring,NULL);
1080 if(cl->startDeferring.tv_usec == 0)
1081 cl->startDeferring.tv_usec++;
1083 gettimeofday(&tv,NULL);
1084 if(tv.tv_sec < cl->startDeferring.tv_sec /* at midnight */
1085 || ((tv.tv_sec-cl->startDeferring.tv_sec)*1000
1086 +(tv.tv_usec-cl->startDeferring.tv_usec)/1000)
1087 > screen->deferUpdateTime) {
1088 cl->startDeferring.tv_usec = 0;
1089 rfbSendFramebufferUpdate(cl,cl->modifiedRegion);
1094 if (!cl->viewOnly && cl->lastPtrX >= 0) {
1095 if(cl->startPtrDeferring.tv_usec == 0) {
1096 gettimeofday(&cl->startPtrDeferring,NULL);
1097 if(cl->startPtrDeferring.tv_usec == 0)
1098 cl->startPtrDeferring.tv_usec++;
1101 gettimeofday(&tv,NULL);
1102 if(tv.tv_sec < cl->startPtrDeferring.tv_sec /* at midnight */
1103 || ((tv.tv_sec-cl->startPtrDeferring.tv_sec)*1000
1104 +(tv.tv_usec-cl->startPtrDeferring.tv_usec)/1000)
1105 > cl->screen->deferPtrUpdateTime) {
1106 cl->startPtrDeferring.tv_usec = 0;
1107 cl->screen->ptrAddEvent(cl->lastPtrButtons,
1115 cl=rfbClientIteratorNext(i);
1116 if(clPrev->sock==-1) {
1117 rfbClientConnectionGone(clPrev);
1121 rfbReleaseClientIterator(i);
1126 rfbBool rfbIsActive(rfbScreenInfoPtr screenInfo) {
1127 return screenInfo->socketState!=RFB_SOCKET_SHUTDOWN || screenInfo->clientHead!=NULL;
1130 void rfbRunEventLoop(rfbScreenInfoPtr screen, long usec, rfbBool runInBackground)
1132 if(runInBackground) {
1133 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
1134 pthread_t listener_thread;
1136 screen->backgroundLoop = TRUE;
1138 pthread_create(&listener_thread, NULL, listenerRun, screen);
1141 rfbErr("Can't run in background, because I don't have PThreads!\n");
1147 usec=screen->deferUpdateTime*1000;
1149 while(rfbIsActive(screen))
1150 rfbProcessEvents(screen,usec);