From b52788764836086ae1e8d3048fe9c2c2b97839be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sl=C3=A1vek=20Banko?= Date: Wed, 9 Dec 2020 16:31:34 +0100 Subject: Rename main.c to main.cpp because it needs to be built as C++ for integration with TQt event loop. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use tq... includes instead of ntq.... Signed-off-by: Slávek Banko --- libvncserver/main.c | 1376 ------------------------------------------------- libvncserver/main.cpp | 1376 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1376 insertions(+), 1376 deletions(-) delete mode 100644 libvncserver/main.c create mode 100644 libvncserver/main.cpp diff --git a/libvncserver/main.c b/libvncserver/main.c deleted file mode 100644 index 74010d0..0000000 --- a/libvncserver/main.c +++ /dev/null @@ -1,1376 +0,0 @@ -/* - * This file is called main.c, because it contains most of the new functions - * for use with LibVNCServer. - * - * Copyright (C) 2015 Timothy Pearson . - * LibVNCServer (C) 2001 Johannes E. Schindelin - * Original OSXvnc (C) 2001 Dan McGuirk . - * Original Xvnc (C) 1999 AT&T Laboratories Cambridge. - * All Rights Reserved. - * - * see GPL (latest version) for full details - */ - -extern "C" { - #include - #include - #include "private.h" - - #include - #include - - #ifndef false - #define false 0 - #define true -1 - #endif - - #ifdef LIBVNCSERVER_HAVE_SYS_TYPES_H - #include - #endif - - #ifndef WIN32 - #include - #include - #include - #include - #endif - - #include - #include -} - -#include -#include -#include -#include - -#include "main.h" - -ControlPipeHandlerObject* mControlPipeHandler = NULL; -TQEventLoopThread* mControlPipeHandlerThread = NULL; - -OnHoldClientHandlerObject* mOnHoldClientHandler = NULL; -TQEventLoopThread* mOnHoldClientHandlerThread = NULL; - -extern "C" { - /* from scale.c */ - void rfbScaledScreenUpdate(rfbScreenInfoPtr screen, int x1, int y1, int x2, int y2); - - /* from rfbserver.c */ - rfbClientIteratorPtr rfbGetClientIteratorWithClosed(rfbScreenInfoPtr rfbScreen); -} - -static int extMutex_initialized = 0; -static int logMutex_initialized = 0; -#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD -static MUTEX(logMutex); -static MUTEX(extMutex); -#endif - -static int rfbEnableLogging=1; - -#ifdef LIBVNCSERVER_WORDS_BIGENDIAN -char rfbEndianTest = (1==0); -#else -char rfbEndianTest = (1==1); -#endif - -/* - * Protocol extensions - */ - -static rfbProtocolExtension* rfbExtensionHead = NULL; - -/* - * This method registers a list of new extensions. - * It avoids same extension getting registered multiple times. - * The order is not preserved if multiple extensions are - * registered at one-go. - */ -void -rfbRegisterProtocolExtension(rfbProtocolExtension* extension) -{ - rfbProtocolExtension *head = rfbExtensionHead, *next = NULL; - - if(extension == NULL) - return; - - next = extension->next; - - if (! extMutex_initialized) { - INIT_MUTEX(extMutex); - extMutex_initialized = 1; - } - - LOCK(extMutex); - - while(head != NULL) { - if(head == extension) { - UNLOCK(extMutex); - rfbRegisterProtocolExtension(next); - return; - } - - head = head->next; - } - - extension->next = rfbExtensionHead; - rfbExtensionHead = extension; - - UNLOCK(extMutex); - rfbRegisterProtocolExtension(next); -} - -/* - * This method unregisters a list of extensions. - * These extensions won't be available for any new - * client connection. - */ -void -rfbUnregisterProtocolExtension(rfbProtocolExtension* extension) -{ - - rfbProtocolExtension *cur = NULL, *pre = NULL; - - if(extension == NULL) - return; - - if (! extMutex_initialized) { - INIT_MUTEX(extMutex); - extMutex_initialized = 1; - } - - LOCK(extMutex); - - if(rfbExtensionHead == extension) { - rfbExtensionHead = rfbExtensionHead->next; - UNLOCK(extMutex); - rfbUnregisterProtocolExtension(extension->next); - return; - } - - cur = pre = rfbExtensionHead; - - while(cur) { - if(cur == extension) { - pre->next = cur->next; - break; - } - pre = cur; - cur = cur->next; - } - - UNLOCK(extMutex); - - rfbUnregisterProtocolExtension(extension->next); -} - -rfbProtocolExtension* rfbGetExtensionIterator() -{ - if (! extMutex_initialized) { - INIT_MUTEX(extMutex); - extMutex_initialized = 1; - } - - LOCK(extMutex); - return rfbExtensionHead; -} - -void rfbReleaseExtensionIterator() -{ - UNLOCK(extMutex); -} - -rfbBool rfbEnableExtension(rfbClientPtr cl, rfbProtocolExtension* extension, - void* data) -{ - rfbExtensionData* extData; - - /* make sure extension is not yet enabled. */ - for(extData = cl->extensions; extData; extData = extData->next) - if(extData->extension == extension) - return FALSE; - - extData = (rfbExtensionData*)calloc(sizeof(rfbExtensionData),1); - extData->extension = extension; - extData->data = data; - extData->next = cl->extensions; - cl->extensions = extData; - - return TRUE; -} - -rfbBool rfbDisableExtension(rfbClientPtr cl, rfbProtocolExtension* extension) -{ - rfbExtensionData* extData; - rfbExtensionData* prevData = NULL; - - for(extData = cl->extensions; extData; extData = extData->next) { - if(extData->extension == extension) { - if(extData->data) - free(extData->data); - if(prevData == NULL) - cl->extensions = extData->next; - else - prevData->next = extData->next; - return TRUE; - } - prevData = extData; - } - - return FALSE; -} - -void* rfbGetExtensionClientData(rfbClientPtr cl, rfbProtocolExtension* extension) -{ - rfbExtensionData* data = cl->extensions; - - while(data && data->extension != extension) - data = data->next; - - if(data == NULL) { - rfbLog("Extension is not enabled !\n"); - /* rfbCloseClient(cl); */ - return NULL; - } - - return data->data; -} - -/* - * Logging - */ - -void rfbLogEnable(int enabled) { - rfbEnableLogging=enabled; -} - -/* - * rfbLog prints a time-stamped message to the log file (stderr). - */ - -static void -rfbDefaultLog(const char *format, ...) -{ - va_list args; - char buf[256]; - time_t log_clock; - - if(!rfbEnableLogging) - return; - - if (! logMutex_initialized) { - INIT_MUTEX(logMutex); - logMutex_initialized = 1; - } - - LOCK(logMutex); - va_start(args, format); - - time(&log_clock); - strftime(buf, 255, "%d/%m/%Y %X ", localtime(&log_clock)); - fprintf(stderr, "%s", buf); - - vfprintf(stderr, format, args); - fflush(stderr); - - va_end(args); - UNLOCK(logMutex); -} - -rfbLogProc rfbLog=rfbDefaultLog; -rfbLogProc rfbErr=rfbDefaultLog; - -void rfbLogPerror(const char *str) -{ -#ifdef WIN32 - wchar_t *s = NULL; - FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, errno, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPWSTR)&s, 0, NULL); - rfbErr("%s: %S\n", str, s); - LocalFree(s); -#else - rfbErr("%s: %s\n", str, strerror(errno)); -#endif -} - -void rfbScheduleCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,int dx,int dy) -{ - rfbClientIteratorPtr iterator; - rfbClientPtr cl; - - iterator=rfbGetClientIterator(rfbScreen); - while((cl=rfbClientIteratorNext(iterator))) { - LOCK(cl->updateMutex); - if(cl->useCopyRect) { - sraRegionPtr modifiedRegionBackup; - if(!sraRgnEmpty(cl->copyRegion)) { - if(cl->copyDX!=dx || cl->copyDY!=dy) { - /* if a copyRegion was not yet executed, treat it as a - * modifiedRegion. The idea: in this case it could be - * source of the new copyRect or modified anyway. */ - sraRgnOr(cl->modifiedRegion,cl->copyRegion); - sraRgnMakeEmpty(cl->copyRegion); - } else { - /* we have to set the intersection of the source of the copy - * and the old copy to modified. */ - modifiedRegionBackup=sraRgnCreateRgn(copyRegion); - sraRgnOffset(modifiedRegionBackup,-dx,-dy); - sraRgnAnd(modifiedRegionBackup,cl->copyRegion); - sraRgnOr(cl->modifiedRegion,modifiedRegionBackup); - sraRgnDestroy(modifiedRegionBackup); - } - } - - sraRgnOr(cl->copyRegion,copyRegion); - cl->copyDX = dx; - cl->copyDY = dy; - - /* if there were modified regions, which are now copied, - * mark them as modified, because the source of these can be overlapped - * either by new modified or now copied regions. */ - modifiedRegionBackup=sraRgnCreateRgn(cl->modifiedRegion); - sraRgnOffset(modifiedRegionBackup,dx,dy); - sraRgnAnd(modifiedRegionBackup,cl->copyRegion); - sraRgnOr(cl->modifiedRegion,modifiedRegionBackup); - sraRgnDestroy(modifiedRegionBackup); - - if(!cl->enableCursorShapeUpdates) { - /* - * n.b. (dx, dy) is the vector pointing in the direction the - * copyrect displacement will take place. copyRegion is the - * destination rectangle (say), not the source rectangle. - */ - sraRegionPtr cursorRegion; - int x = cl->cursorX - cl->screen->cursor->xhot; - int y = cl->cursorY - cl->screen->cursor->yhot; - int w = cl->screen->cursor->width; - int h = cl->screen->cursor->height; - - cursorRegion = sraRgnCreateRect(x, y, x + w, y + h); - sraRgnAnd(cursorRegion, cl->copyRegion); - if(!sraRgnEmpty(cursorRegion)) { - /* - * current cursor rect overlaps with the copy region *dest*, - * mark it as modified since we won't copy-rect stuff to it. - */ - sraRgnOr(cl->modifiedRegion, cursorRegion); - } - sraRgnDestroy(cursorRegion); - - cursorRegion = sraRgnCreateRect(x, y, x + w, y + h); - /* displace it to check for overlap with copy region source: */ - sraRgnOffset(cursorRegion, dx, dy); - sraRgnAnd(cursorRegion, cl->copyRegion); - if(!sraRgnEmpty(cursorRegion)) { - /* - * current cursor rect overlaps with the copy region *source*, - * mark the *displaced* cursorRegion as modified since we - * won't copyrect stuff to it. - */ - sraRgnOr(cl->modifiedRegion, cursorRegion); - } - sraRgnDestroy(cursorRegion); - } - - } else { - sraRgnOr(cl->modifiedRegion,copyRegion); - } - TSIGNAL(cl->updateCond); - UNLOCK(cl->updateMutex); - } - - rfbReleaseClientIterator(iterator); -} - -void rfbDoCopyRegion(rfbScreenInfoPtr screen,sraRegionPtr copyRegion,int dx,int dy) -{ - sraRectangleIterator* i; - sraRect rect; - int j,widthInBytes,bpp=screen->serverFormat.bitsPerPixel/8, - rowstride=screen->paddedWidthInBytes; - char *in,*out; - - /* copy it, really */ - i = sraRgnGetReverseIterator(copyRegion,dx<0,dy<0); - while(sraRgnIteratorNext(i,&rect)) { - widthInBytes = (rect.x2-rect.x1)*bpp; - out = screen->frameBuffer+rect.x1*bpp+rect.y1*rowstride; - in = screen->frameBuffer+(rect.x1-dx)*bpp+(rect.y1-dy)*rowstride; - if(dy<0) - for(j=rect.y1;j=rect.y1;j--,out-=rowstride,in-=rowstride) - memmove(out,in,widthInBytes); - } - } - sraRgnReleaseIterator(i); - - rfbScheduleCopyRegion(screen,copyRegion,dx,dy); -} - -void rfbDoCopyRect(rfbScreenInfoPtr screen,int x1,int y1,int x2,int y2,int dx,int dy) -{ - sraRegionPtr region = sraRgnCreateRect(x1,y1,x2,y2); - rfbDoCopyRegion(screen,region,dx,dy); - sraRgnDestroy(region); -} - -void rfbScheduleCopyRect(rfbScreenInfoPtr screen,int x1,int y1,int x2,int y2,int dx,int dy) -{ - sraRegionPtr region = sraRgnCreateRect(x1,y1,x2,y2); - rfbScheduleCopyRegion(screen,region,dx,dy); - sraRgnDestroy(region); -} - -void rfbMarkRegionAsModified(rfbScreenInfoPtr screen,sraRegionPtr modRegion) -{ - rfbClientIteratorPtr iterator; - rfbClientPtr cl; - - iterator=rfbGetClientIterator(screen); - while((cl=rfbClientIteratorNext(iterator))) { - LOCK(cl->updateMutex); - sraRgnOr(cl->modifiedRegion,modRegion); - TSIGNAL(cl->updateCond); - UNLOCK(cl->updateMutex); - } - - rfbReleaseClientIterator(iterator); -} - -void rfbScaledScreenUpdate(rfbScreenInfoPtr screen, int x1, int y1, int x2, int y2); -void rfbMarkRectAsModified(rfbScreenInfoPtr screen,int x1,int y1,int x2,int y2) -{ - sraRegionPtr region; - int i; - - if(x1>x2) { i=x1; x1=x2; x2=i; } - if(x1<0) x1=0; - if(x2>screen->width) x2=screen->width; - if(x1==x2) return; - - if(y1>y2) { i=y1; y1=y2; y2=i; } - if(y1<0) y1=0; - if(y2>screen->height) y2=screen->height; - if(y1==y2) return; - - /* update scaled copies for this rectangle */ - rfbScaledScreenUpdate(screen,x1,y1,x2,y2); - - region = sraRgnCreateRect(x1,y1,x2,y2); - rfbMarkRegionAsModified(screen,region); - sraRgnDestroy(region); -} - -#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD -#include - -static void * -clientOutput(void *data) -{ - rfbClientPtr cl = (rfbClientPtr)data; - rfbBool haveUpdate; - sraRegion* updateRegion; - - while (1) { - haveUpdate = false; - while (!haveUpdate) { - if (cl->sock == -1) { - /* Client has disconnected. */ - return NULL; - } - if (cl->state != _rfbClientRec::RFB_NORMAL || cl->onHold) { - /* just sleep until things get normal */ - usleep(cl->screen->deferUpdateTime * 1000); - continue; - } - - LOCK(cl->updateMutex); - - if (sraRgnEmpty(cl->requestedRegion)) { - ; /* always require a FB Update Request (otherwise can crash.) */ - } else { - haveUpdate = FB_UPDATE_PENDING(cl); - if(!haveUpdate) { - updateRegion = sraRgnCreateRgn(cl->modifiedRegion); - haveUpdate = sraRgnAnd(updateRegion,cl->requestedRegion); - sraRgnDestroy(updateRegion); - } - } - - if (!haveUpdate) { - WAIT(cl->updateCond, cl->updateMutex); - } - - UNLOCK(cl->updateMutex); - } - - /* OK, now, to save bandwidth, wait a little while for more - updates to come along. */ - usleep(cl->screen->deferUpdateTime * 1000); - - /* Now, get the region we're going to update, and remove - it from cl->modifiedRegion _before_ we send the update. - That way, if anything that overlaps the region we're sending - is updated, we'll be sure to do another update later. */ - LOCK(cl->updateMutex); - updateRegion = sraRgnCreateRgn(cl->modifiedRegion); - UNLOCK(cl->updateMutex); - - /* Now actually send the update. */ - rfbIncrClientRef(cl); - LOCK(cl->sendMutex); - rfbSendFramebufferUpdate(cl, updateRegion); - UNLOCK(cl->sendMutex); - rfbDecrClientRef(cl); - - sraRgnDestroy(updateRegion); - } - - /* Not reached. */ - return NULL; -} - -static void * -clientInput(void *data) -{ - rfbClientPtr cl = (rfbClientPtr)data; - /* Start output thread */ - TQEventLoopThread* clientOutputHandlerThread = new TQEventLoopThread(); - ClientOutputHandlerObject* clientOutputHandler = new ClientOutputHandlerObject(); - clientOutputHandler->d = cl; - clientOutputHandler->moveToThread(clientOutputHandlerThread); - TQTimer::singleShot(0, clientOutputHandler, SLOT(run())); - clientOutputHandlerThread->start(); - - while (1) { - fd_set rfds, wfds, efds; - struct timeval tv; - int n; - - if (cl->sock == -1) { - /* Client has disconnected. */ - break; - } - - FD_ZERO(&rfds); - FD_SET(cl->sock, &rfds); - FD_SET(cl->pipe_notify_client_thread[0], &rfds); - FD_ZERO(&efds); - FD_SET(cl->sock, &efds); - - /* Are we transferring a file in the background? */ - FD_ZERO(&wfds); - if ((cl->fileTransfer.fd!=-1) && (cl->fileTransfer.sending==1)) - FD_SET(cl->sock, &wfds); - - int nfds = cl->pipe_notify_client_thread[0] > cl->sock ? cl->pipe_notify_client_thread[0] : cl->sock; - - tv.tv_sec = 60; /* 1 minute */ - tv.tv_usec = 0; - - n = select(nfds + 1, &rfds, &wfds, &efds, &tv); - - if (n < 0) { - rfbLogPerror("ReadExact: select"); - break; - } - if (n == 0) /* timeout */ - { - rfbSendFileTransferChunk(cl); - continue; - } - - /* We have some space on the transmit queue, send some data */ - if (FD_ISSET(cl->sock, &wfds)) - rfbSendFileTransferChunk(cl); - - if (FD_ISSET(cl->pipe_notify_client_thread[0], &rfds)) - { - /* Reset the pipe */ - char buf; - while (read(cl->pipe_notify_client_thread[0], &buf, sizeof(buf)) == sizeof(buf)); - } - - if (FD_ISSET(cl->sock, &rfds) || FD_ISSET(cl->sock, &efds)) - { -#ifdef LIBVNCSERVER_WITH_WEBSOCKETS - do { - rfbProcessClientMessage(cl); - } while (webSocketsHasDataInBuffer(cl)); -#else - rfbProcessClientMessage(cl); -#endif - } - } - - /* Get rid of the output thread. */ - LOCK(cl->updateMutex); - TSIGNAL(cl->updateCond); - UNLOCK(cl->updateMutex); - clientOutputHandlerThread->wait(); - delete clientOutputHandlerThread; - clientOutputHandlerThread = NULL; - delete clientOutputHandler; - clientOutputHandler = NULL; - - rfbClientConnectionGone(cl); - - return NULL; -} - -static void* -listenerRun(void *data) -{ - rfbScreenInfoPtr screen=(rfbScreenInfoPtr)data; - int client_fd; - struct sockaddr_storage peer; - rfbClientPtr cl = NULL; - socklen_t len; - fd_set listen_fds; /* temp file descriptor list for select() */ - - if (screen->inetdSock != -1) { - cl = rfbNewClient(screen, screen->inetdSock); - if (cl && !cl->onHold) - rfbStartOnHoldClient(cl); - else if (screen->inetdDisconnectHook && !cl) - screen->inetdDisconnectHook(); - return NULL; - } - - /* TODO: this thread won't die by restarting the server */ - /* TODO: HTTP is not handled */ - while (1) { - client_fd = -1; - FD_ZERO(&listen_fds); - if(screen->listenSock >= 0) - FD_SET(screen->listenSock, &listen_fds); - if(screen->listen6Sock >= 0) - FD_SET(screen->listen6Sock, &listen_fds); - - if (select(screen->maxFd+1, &listen_fds, NULL, NULL, NULL) == -1) { - rfbLogPerror("listenerRun: error in select"); - return NULL; - } - - /* there is something on the listening sockets, handle new connections */ - len = sizeof (peer); - if (FD_ISSET(screen->listenSock, &listen_fds)) - client_fd = accept(screen->listenSock, (struct sockaddr*)&peer, &len); - else if (FD_ISSET(screen->listen6Sock, &listen_fds)) - client_fd = accept(screen->listen6Sock, (struct sockaddr*)&peer, &len); - - if(client_fd >= 0) - cl = rfbNewClient(screen,client_fd); - if (cl && !cl->onHold ) - rfbStartOnHoldClient(cl); - } - return(NULL); -} - -void -rfbStartOnHoldClient(rfbClientPtr cl) -{ - mOnHoldClientHandlerThread = new TQEventLoopThread(); - mOnHoldClientHandler = new OnHoldClientHandlerObject(); - mOnHoldClientHandler->d = cl; - mOnHoldClientHandler->moveToThread(mOnHoldClientHandlerThread); - TQTimer::singleShot(0, mOnHoldClientHandler, SLOT(run())); - mOnHoldClientHandlerThread->start(); -} - -#else - -void -rfbStartOnHoldClient(rfbClientPtr cl) -{ - cl->onHold = FALSE; -#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD - if(cl->screen->backgroundLoop) { - if (pipe(cl->pipe_notify_client_thread) == -1) { - cl->pipe_notify_client_thread[0] = -1; - cl->pipe_notify_client_thread[1] = -1; - } - fcntl(cl->pipe_notify_client_thread[0], F_SETFL, O_NONBLOCK); - - pthread_create(&cl->client_thread, NULL, clientInput, (void *)cl); - } -#endif -} - -#endif - -void -rfbRefuseOnHoldClient(rfbClientPtr cl) -{ - rfbCloseClient(cl); - rfbClientConnectionGone(cl); -} - -static void -rfbDefaultKbdAddEvent(rfbBool down, rfbKeySym keySym, rfbClientPtr cl) -{ -} - -void -rfbDefaultPtrAddEvent(int buttonMask, int x, int y, rfbClientPtr cl) -{ - rfbClientIteratorPtr iterator; - rfbClientPtr other_client; - rfbScreenInfoPtr s = cl->screen; - - if (x != s->cursorX || y != s->cursorY) { - LOCK(s->cursorMutex); - s->cursorX = x; - s->cursorY = y; - UNLOCK(s->cursorMutex); - - /* The cursor was moved by this client, so don't send CursorPos. */ - if (cl->enableCursorPosUpdates) - cl->cursorWasMoved = FALSE; - - /* But inform all remaining clients about this cursor movement. */ - iterator = rfbGetClientIterator(s); - while ((other_client = rfbClientIteratorNext(iterator)) != NULL) { - if (other_client != cl && other_client->enableCursorPosUpdates) { - other_client->cursorWasMoved = TRUE; - } - } - rfbReleaseClientIterator(iterator); - } -} - -static void rfbDefaultSetXCutText(char* text, int len, rfbClientPtr cl) -{ -} - -/* TODO: add a nice VNC or RFB cursor */ - -#if defined(WIN32) || defined(sparc) || !defined(NO_STRICT_ANSI) -static rfbCursor myCursor = -{ - FALSE, FALSE, FALSE, FALSE, - (unsigned char*)"\000\102\044\030\044\102\000", - (unsigned char*)"\347\347\176\074\176\347\347", - 8, 7, 3, 3, - 0, 0, 0, - 0xffff, 0xffff, 0xffff, - NULL -}; -#else -static rfbCursor myCursor = -{ - cleanup: FALSE, - cleanupSource: FALSE, - cleanupMask: FALSE, - cleanupRichSource: FALSE, - source: "\000\102\044\030\044\102\000", - mask: "\347\347\176\074\176\347\347", - width: 8, height: 7, xhot: 3, yhot: 3, - foreRed: 0, foreGreen: 0, foreBlue: 0, - backRed: 0xffff, backGreen: 0xffff, backBlue: 0xffff, - richSource: NULL -}; -#endif - -static rfbCursorPtr rfbDefaultGetCursorPtr(rfbClientPtr cl) -{ - return(cl->screen->cursor); -} - -/* response is cl->authChallenge vncEncrypted with passwd */ -static rfbBool rfbDefaultPasswordCheck(rfbClientPtr cl,const char* response,int len) -{ - int i; - char *passwd=rfbDecryptPasswdFromFile((char*)cl->screen->authPasswdData); - - if(!passwd) { - rfbErr("Couldn't read password file: %s\n",cl->screen->authPasswdData); - return(FALSE); - } - - rfbEncryptBytes(cl->authChallenge, passwd); - - /* Lose the password from memory */ - for (i = strlen(passwd); i >= 0; i--) { - passwd[i] = '\0'; - } - - free(passwd); - - if (memcmp(cl->authChallenge, response, len) != 0) { - rfbErr("authProcessClientMessage: authentication failed from %s\n", - cl->host); - return(FALSE); - } - - return(TRUE); -} - -/* for this method, authPasswdData is really a pointer to an array - of char*'s, where the last pointer is 0. */ -rfbBool rfbCheckPasswordByList(rfbClientPtr cl,const char* response,int len) -{ - char **passwds; - int i=0; - - for(passwds=(char**)cl->screen->authPasswdData;*passwds;passwds++,i++) { - uint8_t auth_tmp[CHALLENGESIZE]; - memcpy((char *)auth_tmp, (char *)cl->authChallenge, CHALLENGESIZE); - rfbEncryptBytes(auth_tmp, *passwds); - - if (memcmp(auth_tmp, response, len) == 0) { - if(i>=cl->screen->authPasswdFirstViewOnly) - cl->viewOnly=TRUE; - return(TRUE); - } - } - - rfbErr("authProcessClientMessage: authentication failed from %s\n", - cl->host); - return(FALSE); -} - -void rfbDoNothingWithClient(rfbClientPtr cl) -{ -} - -static enum rfbNewClientAction rfbDefaultNewClientHook(rfbClientPtr cl) -{ - return RFB_CLIENT_ACCEPT; -} - -/* - * Update server's pixel format in screenInfo structure. This - * function is called from rfbGetScreen() and rfbNewFramebuffer(). - */ - -static void rfbInitServerFormat(rfbScreenInfoPtr screen, int bitsPerSample) -{ - rfbPixelFormat* format=&screen->serverFormat; - - format->bitsPerPixel = screen->bitsPerPixel; - format->depth = screen->depth; - format->bigEndian = rfbEndianTest?FALSE:TRUE; - format->trueColour = TRUE; - screen->colourMap.count = 0; - screen->colourMap.is16 = 0; - screen->colourMap.data.bytes = NULL; - - if (format->bitsPerPixel == 8) { - format->redMax = 7; - format->greenMax = 7; - format->blueMax = 3; - format->redShift = 0; - format->greenShift = 3; - format->blueShift = 6; - } else { - format->redMax = (1 << bitsPerSample) - 1; - format->greenMax = (1 << bitsPerSample) - 1; - format->blueMax = (1 << bitsPerSample) - 1; - if(rfbEndianTest) { - format->redShift = 0; - format->greenShift = bitsPerSample; - format->blueShift = bitsPerSample * 2; - } else { - if(format->bitsPerPixel==8*3) { - format->redShift = bitsPerSample*2; - format->greenShift = bitsPerSample*1; - format->blueShift = 0; - } else { - format->redShift = bitsPerSample*3; - format->greenShift = bitsPerSample*2; - format->blueShift = bitsPerSample; - } - } - } -} - -rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv, - int width,int height,int bitsPerSample,int samplesPerPixel, - int bytesPerPixel) -{ - rfbScreenInfoPtr screen=(rfbScreenInfoPtr)calloc(sizeof(rfbScreenInfo),1); - - if (! logMutex_initialized) { - INIT_MUTEX(logMutex); - logMutex_initialized = 1; - } - - - if(width&3) - rfbErr("WARNING: Width (%d) is not a multiple of 4. VncViewer has problems with that.\n",width); - - screen->autoPort=FALSE; - screen->clientHead=NULL; - screen->pointerClient=NULL; - screen->port=5900; - screen->ipv6port=5900; - screen->socketState=RFB_SOCKET_INIT; - - screen->inetdInitDone = FALSE; - screen->inetdSock=-1; - - screen->udpSock=-1; - screen->udpSockConnected=FALSE; - screen->udpPort=0; - screen->udpClient=NULL; - - screen->maxFd=0; - screen->listenSock=-1; - screen->listen6Sock=-1; - - screen->httpInitDone=FALSE; - screen->httpEnableProxyConnect=FALSE; - screen->httpPort=0; - screen->http6Port=0; - screen->httpDir=NULL; - screen->httpListenSock=-1; - screen->httpListen6Sock=-1; - screen->httpSock=-1; - - screen->desktopName = "LibVNCServer"; - screen->alwaysShared = FALSE; - screen->neverShared = FALSE; - screen->dontDisconnect = FALSE; - screen->authPasswdData = NULL; - screen->authPasswdFirstViewOnly = 1; - - screen->width = width; - screen->height = height; - screen->bitsPerPixel = screen->depth = 8*bytesPerPixel; - - screen->passwordCheck = rfbDefaultPasswordCheck; - - screen->ignoreSIGPIPE = TRUE; - - /* disable progressive updating per default */ - screen->progressiveSliceHeight = 0; - - screen->listenInterface = htonl(INADDR_ANY); - - screen->deferUpdateTime=5; - screen->maxRectsPerUpdate=50; - - screen->handleEventsEagerly = FALSE; - - screen->protocolMajorVersion = rfbProtocolMajorVersion; - screen->protocolMinorVersion = rfbProtocolMinorVersion; - - screen->permitFileTransfer = FALSE; - - if(!rfbProcessArguments(screen,argc,argv)) { - free(screen); - return NULL; - } - -#ifdef WIN32 - { - DWORD dummy=255; - GetComputerName(screen->thisHost,&dummy); - } -#else - gethostname(screen->thisHost, 255); -#endif - - screen->paddedWidthInBytes = width*bytesPerPixel; - - /* format */ - - rfbInitServerFormat(screen, bitsPerSample); - - /* cursor */ - - screen->cursorX=screen->cursorY=screen->underCursorBufferLen=0; - screen->underCursorBuffer=NULL; - screen->dontConvertRichCursorToXCursor = FALSE; - screen->cursor = &myCursor; - INIT_MUTEX(screen->cursorMutex); - - IF_PTHREADS(screen->backgroundLoop = FALSE); - - /* proc's and hook's */ - - screen->kbdAddEvent = rfbDefaultKbdAddEvent; - screen->kbdReleaseAllKeys = rfbDoNothingWithClient; - screen->ptrAddEvent = rfbDefaultPtrAddEvent; - screen->setXCutText = rfbDefaultSetXCutText; - screen->getCursorPtr = rfbDefaultGetCursorPtr; - screen->setTranslateFunction = rfbSetTranslateFunction; - screen->newClientHook = rfbDefaultNewClientHook; - screen->displayHook = NULL; - screen->inetdDisconnectHook = NULL; - screen->displayFinishedHook = NULL; - screen->getKeyboardLedStateHook = NULL; - screen->xvpHook = NULL; - - /* initialize client list and iterator mutex */ - rfbClientListInit(screen); - - return(screen); -} - -/* - * Switch to another framebuffer (maybe of different size and color - * format). Clients supporting NewFBSize pseudo-encoding will change - * their local framebuffer dimensions if necessary. - * NOTE: Rich cursor data should be converted to new pixel format by - * the caller. - */ - -void rfbNewFramebuffer(rfbScreenInfoPtr screen, char *framebuffer, - int width, int height, - int bitsPerSample, int samplesPerPixel, - int bytesPerPixel) -{ - rfbPixelFormat old_format; - rfbBool format_changed = FALSE; - rfbClientIteratorPtr iterator; - rfbClientPtr cl; - - /* Update information in the screenInfo structure */ - - old_format = screen->serverFormat; - - if (width & 3) - rfbErr("WARNING: New width (%d) is not a multiple of 4.\n", width); - - screen->width = width; - screen->height = height; - screen->bitsPerPixel = screen->depth = 8*bytesPerPixel; - screen->paddedWidthInBytes = width*bytesPerPixel; - - rfbInitServerFormat(screen, bitsPerSample); - - if (memcmp(&screen->serverFormat, &old_format, - sizeof(rfbPixelFormat)) != 0) { - format_changed = TRUE; - } - - screen->frameBuffer = framebuffer; - - /* Adjust pointer position if necessary */ - - if (screen->cursorX >= width) - screen->cursorX = width - 1; - if (screen->cursorY >= height) - screen->cursorY = height - 1; - - /* For each client: */ - iterator = rfbGetClientIterator(screen); - while ((cl = rfbClientIteratorNext(iterator)) != NULL) { - - /* Re-install color translation tables if necessary */ - - if (format_changed) - screen->setTranslateFunction(cl); - - /* Mark the screen contents as changed, and schedule sending - NewFBSize message if supported by this client. */ - - LOCK(cl->updateMutex); - sraRgnDestroy(cl->modifiedRegion); - cl->modifiedRegion = sraRgnCreateRect(0, 0, width, height); - sraRgnMakeEmpty(cl->copyRegion); - cl->copyDX = 0; - cl->copyDY = 0; - - if (cl->useNewFBSize) - cl->newFBSizePending = TRUE; - - TSIGNAL(cl->updateCond); - UNLOCK(cl->updateMutex); - } - rfbReleaseClientIterator(iterator); -} - -/* hang up on all clients and free all reserved memory */ - -void rfbScreenCleanup(rfbScreenInfoPtr screen) -{ - rfbClientIteratorPtr i=rfbGetClientIterator(screen); - rfbClientPtr cl,cl1=rfbClientIteratorNext(i); - while(cl1) { - cl=rfbClientIteratorNext(i); - rfbClientConnectionGone(cl1); - cl1=cl; - } - rfbReleaseClientIterator(i); - - if (mOnHoldClientHandlerThread) { - mOnHoldClientHandlerThread->exit(); - delete mOnHoldClientHandlerThread; - mOnHoldClientHandlerThread = NULL; - delete mOnHoldClientHandler; - mOnHoldClientHandler = NULL; - } - if (mControlPipeHandlerThread) { - mControlPipeHandlerThread->exit(); - delete mControlPipeHandlerThread; - mControlPipeHandlerThread = NULL; - delete mControlPipeHandler; - mControlPipeHandler = NULL; - } - -#define FREE_IF(x) if(screen->x) free(screen->x) - FREE_IF(colourMap.data.bytes); - FREE_IF(underCursorBuffer); - TINI_MUTEX(screen->cursorMutex); - if(screen->cursor && screen->cursor->cleanup) - rfbFreeCursor(screen->cursor); - -#ifdef LIBVNCSERVER_HAVE_LIBZ - rfbZlibCleanup(screen); -#ifdef LIBVNCSERVER_HAVE_LIBJPEG - rfbTightCleanup(screen); -#endif - - /* free all 'scaled' versions of this screen */ - while (screen->scaledScreenNext!=NULL) - { - rfbScreenInfoPtr ptr; - ptr = screen->scaledScreenNext; - screen->scaledScreenNext = ptr->scaledScreenNext; - free(ptr->frameBuffer); - free(ptr); - } - -#endif - free(screen); -} - -void rfbInitServer(rfbScreenInfoPtr screen) -{ -#ifdef WIN32 - WSADATA trash; - static rfbBool WSAinitted=FALSE; - if(!WSAinitted) { - int i=WSAStartup(MAKEWORD(2,0),&trash); - if(i!=0) { - rfbErr("Couldn't init Windows Sockets\n"); - return; - } - WSAinitted=TRUE; - } -#endif - rfbInitSockets(screen); - rfbHttpInitSockets(screen); -#ifndef WIN32 - if(screen->ignoreSIGPIPE) - signal(SIGPIPE,SIG_IGN); -#endif -} - -void rfbShutdownServer(rfbScreenInfoPtr screen,rfbBool disconnectClients) { - if(disconnectClients) { - rfbClientIteratorPtr iter = rfbGetClientIterator(screen); - rfbClientPtr nextCl, currentCl = rfbClientIteratorNext(iter); - - while(currentCl) { - nextCl = rfbClientIteratorNext(iter); - if (currentCl->sock > -1) { - /* we don't care about maxfd here, because the server goes away */ - rfbCloseClient(currentCl); - } - -#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD - /* - Notify the thread. This simply writes a NULL byte to the notify pipe in order to get past the select() - in clientInput(), the loop in there will then break because the rfbCloseClient() above has set - currentCl->sock to -1. - */ - write(currentCl->pipe_notify_client_thread[1], "\x00", 1); - /* And wait for it to finish. */ - pthread_join(currentCl->client_thread, NULL); -#else - rfbClientConnectionGone(currentCl); -#endif - - currentCl = nextCl; - } - - rfbReleaseClientIterator(iter); - } - - rfbShutdownSockets(screen); - rfbHttpShutdownSockets(screen); -} - -#ifndef LIBVNCSERVER_HAVE_GETTIMEOFDAY -#include -#include -#include - -void gettimeofday(struct timeval* tv,char* dummy) -{ - SYSTEMTIME t; - GetSystemTime(&t); - tv->tv_sec=t.wHour*3600+t.wMinute*60+t.wSecond; - tv->tv_usec=t.wMilliseconds*1000; -} -#endif - -rfbBool -rfbProcessEvents(rfbScreenInfoPtr screen,long usec) -{ - rfbClientIteratorPtr i; - rfbClientPtr cl,clPrev; - rfbBool result=FALSE; - extern rfbClientIteratorPtr - rfbGetClientIteratorWithClosed(rfbScreenInfoPtr rfbScreen); - - if(usec<0) - usec=screen->deferUpdateTime*1000; - - rfbCheckFds(screen,usec); - rfbHttpCheckFds(screen); - - i = rfbGetClientIteratorWithClosed(screen); - cl=rfbClientIteratorHead(i); - while(cl) { - result = rfbUpdateClient(cl); - clPrev=cl; - cl=rfbClientIteratorNext(i); - if(clPrev->sock==-1) { - rfbClientConnectionGone(clPrev); - result=TRUE; - } - } - rfbReleaseClientIterator(i); - - return result; -} - -rfbBool -rfbUpdateClient(rfbClientPtr cl) -{ - struct timeval tv; - rfbBool result=FALSE; - rfbScreenInfoPtr screen = cl->screen; - - if (cl->sock >= 0 && !cl->onHold && FB_UPDATE_PENDING(cl) && - !sraRgnEmpty(cl->requestedRegion)) { - result=TRUE; - if(screen->deferUpdateTime == 0) { - rfbSendFramebufferUpdate(cl,cl->modifiedRegion); - } else if(cl->startDeferring.tv_usec == 0) { - gettimeofday(&cl->startDeferring,NULL); - if(cl->startDeferring.tv_usec == 0) - cl->startDeferring.tv_usec++; - } else { - gettimeofday(&tv,NULL); - if(tv.tv_sec < cl->startDeferring.tv_sec /* at midnight */ - || ((tv.tv_sec-cl->startDeferring.tv_sec)*1000 - +(tv.tv_usec-cl->startDeferring.tv_usec)/1000) - > screen->deferUpdateTime) { - cl->startDeferring.tv_usec = 0; - rfbSendFramebufferUpdate(cl,cl->modifiedRegion); - } - } - } - - if (!cl->viewOnly && cl->lastPtrX >= 0) { - if(cl->startPtrDeferring.tv_usec == 0) { - gettimeofday(&cl->startPtrDeferring,NULL); - if(cl->startPtrDeferring.tv_usec == 0) - cl->startPtrDeferring.tv_usec++; - } else { - struct timeval tv; - gettimeofday(&tv,NULL); - if(tv.tv_sec < cl->startPtrDeferring.tv_sec /* at midnight */ - || ((tv.tv_sec-cl->startPtrDeferring.tv_sec)*1000 - +(tv.tv_usec-cl->startPtrDeferring.tv_usec)/1000) - > cl->screen->deferPtrUpdateTime) { - cl->startPtrDeferring.tv_usec = 0; - cl->screen->ptrAddEvent(cl->lastPtrButtons, - cl->lastPtrX, - cl->lastPtrY, cl); - cl->lastPtrX = -1; - } - } - } - - return result; -} - -rfbBool rfbIsActive(rfbScreenInfoPtr screenInfo) { - return screenInfo->socketState!=RFB_SOCKET_SHUTDOWN || screenInfo->clientHead!=NULL; -} - -void rfbRunEventLoop(rfbScreenInfoPtr screen, long usec, rfbBool runInBackground) -{ - if(runInBackground) { -#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD - screen->backgroundLoop = TRUE; - - mControlPipeHandlerThread = new TQEventLoopThread(); - mControlPipeHandler = new ControlPipeHandlerObject(); - mControlPipeHandler->d = screen; - mControlPipeHandler->moveToThread(mControlPipeHandlerThread); - TQTimer::singleShot(0, mControlPipeHandler, SLOT(run())); - mControlPipeHandlerThread->start(); - return; -#else - rfbErr("Can't run in background, because I don't have PThreads!\n"); - return; -#endif - } - - if(usec<0) - usec=screen->deferUpdateTime*1000; - - while(rfbIsActive(screen)) - rfbProcessEvents(screen,usec); -} - -ControlPipeHandlerObject::ControlPipeHandlerObject() : TQObject() { - // -} - -ControlPipeHandlerObject::~ControlPipeHandlerObject() { - // -} - -void ControlPipeHandlerObject::run(void) { - listenerRun(d); - - // Terminate thread - TQThread::exit(); -} - -OnHoldClientHandlerObject::OnHoldClientHandlerObject() : TQObject() { - // -} - -OnHoldClientHandlerObject::~OnHoldClientHandlerObject() { - // -} - -void OnHoldClientHandlerObject::run(void) { - clientInput(d); - - // Terminate thread - TQThread::exit(); -} - -ClientOutputHandlerObject::ClientOutputHandlerObject() : TQObject() { - // -} - -ClientOutputHandlerObject::~ClientOutputHandlerObject() { - // -} - -void ClientOutputHandlerObject::run(void) { - clientOutput(d); - - // Terminate thread - TQThread::exit(); -} - -#include "main.moc" diff --git a/libvncserver/main.cpp b/libvncserver/main.cpp new file mode 100644 index 0000000..a07402a --- /dev/null +++ b/libvncserver/main.cpp @@ -0,0 +1,1376 @@ +/* + * This file is called main.c, because it contains most of the new functions + * for use with LibVNCServer. + * + * Copyright (C) 2015 Timothy Pearson . + * LibVNCServer (C) 2001 Johannes E. Schindelin + * Original OSXvnc (C) 2001 Dan McGuirk . + * Original Xvnc (C) 1999 AT&T Laboratories Cambridge. + * All Rights Reserved. + * + * see GPL (latest version) for full details + */ + +extern "C" { + #include + #include + #include "private.h" + + #include + #include + + #ifndef false + #define false 0 + #define true -1 + #endif + + #ifdef LIBVNCSERVER_HAVE_SYS_TYPES_H + #include + #endif + + #ifndef WIN32 + #include + #include + #include + #include + #endif + + #include + #include +} + +#include +#include +#include +#include + +#include "main.h" + +ControlPipeHandlerObject* mControlPipeHandler = NULL; +TQEventLoopThread* mControlPipeHandlerThread = NULL; + +OnHoldClientHandlerObject* mOnHoldClientHandler = NULL; +TQEventLoopThread* mOnHoldClientHandlerThread = NULL; + +extern "C" { + /* from scale.c */ + void rfbScaledScreenUpdate(rfbScreenInfoPtr screen, int x1, int y1, int x2, int y2); + + /* from rfbserver.c */ + rfbClientIteratorPtr rfbGetClientIteratorWithClosed(rfbScreenInfoPtr rfbScreen); +} + +static int extMutex_initialized = 0; +static int logMutex_initialized = 0; +#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD +static MUTEX(logMutex); +static MUTEX(extMutex); +#endif + +static int rfbEnableLogging=1; + +#ifdef LIBVNCSERVER_WORDS_BIGENDIAN +char rfbEndianTest = (1==0); +#else +char rfbEndianTest = (1==1); +#endif + +/* + * Protocol extensions + */ + +static rfbProtocolExtension* rfbExtensionHead = NULL; + +/* + * This method registers a list of new extensions. + * It avoids same extension getting registered multiple times. + * The order is not preserved if multiple extensions are + * registered at one-go. + */ +void +rfbRegisterProtocolExtension(rfbProtocolExtension* extension) +{ + rfbProtocolExtension *head = rfbExtensionHead, *next = NULL; + + if(extension == NULL) + return; + + next = extension->next; + + if (! extMutex_initialized) { + INIT_MUTEX(extMutex); + extMutex_initialized = 1; + } + + LOCK(extMutex); + + while(head != NULL) { + if(head == extension) { + UNLOCK(extMutex); + rfbRegisterProtocolExtension(next); + return; + } + + head = head->next; + } + + extension->next = rfbExtensionHead; + rfbExtensionHead = extension; + + UNLOCK(extMutex); + rfbRegisterProtocolExtension(next); +} + +/* + * This method unregisters a list of extensions. + * These extensions won't be available for any new + * client connection. + */ +void +rfbUnregisterProtocolExtension(rfbProtocolExtension* extension) +{ + + rfbProtocolExtension *cur = NULL, *pre = NULL; + + if(extension == NULL) + return; + + if (! extMutex_initialized) { + INIT_MUTEX(extMutex); + extMutex_initialized = 1; + } + + LOCK(extMutex); + + if(rfbExtensionHead == extension) { + rfbExtensionHead = rfbExtensionHead->next; + UNLOCK(extMutex); + rfbUnregisterProtocolExtension(extension->next); + return; + } + + cur = pre = rfbExtensionHead; + + while(cur) { + if(cur == extension) { + pre->next = cur->next; + break; + } + pre = cur; + cur = cur->next; + } + + UNLOCK(extMutex); + + rfbUnregisterProtocolExtension(extension->next); +} + +rfbProtocolExtension* rfbGetExtensionIterator() +{ + if (! extMutex_initialized) { + INIT_MUTEX(extMutex); + extMutex_initialized = 1; + } + + LOCK(extMutex); + return rfbExtensionHead; +} + +void rfbReleaseExtensionIterator() +{ + UNLOCK(extMutex); +} + +rfbBool rfbEnableExtension(rfbClientPtr cl, rfbProtocolExtension* extension, + void* data) +{ + rfbExtensionData* extData; + + /* make sure extension is not yet enabled. */ + for(extData = cl->extensions; extData; extData = extData->next) + if(extData->extension == extension) + return FALSE; + + extData = (rfbExtensionData*)calloc(sizeof(rfbExtensionData),1); + extData->extension = extension; + extData->data = data; + extData->next = cl->extensions; + cl->extensions = extData; + + return TRUE; +} + +rfbBool rfbDisableExtension(rfbClientPtr cl, rfbProtocolExtension* extension) +{ + rfbExtensionData* extData; + rfbExtensionData* prevData = NULL; + + for(extData = cl->extensions; extData; extData = extData->next) { + if(extData->extension == extension) { + if(extData->data) + free(extData->data); + if(prevData == NULL) + cl->extensions = extData->next; + else + prevData->next = extData->next; + return TRUE; + } + prevData = extData; + } + + return FALSE; +} + +void* rfbGetExtensionClientData(rfbClientPtr cl, rfbProtocolExtension* extension) +{ + rfbExtensionData* data = cl->extensions; + + while(data && data->extension != extension) + data = data->next; + + if(data == NULL) { + rfbLog("Extension is not enabled !\n"); + /* rfbCloseClient(cl); */ + return NULL; + } + + return data->data; +} + +/* + * Logging + */ + +void rfbLogEnable(int enabled) { + rfbEnableLogging=enabled; +} + +/* + * rfbLog prints a time-stamped message to the log file (stderr). + */ + +static void +rfbDefaultLog(const char *format, ...) +{ + va_list args; + char buf[256]; + time_t log_clock; + + if(!rfbEnableLogging) + return; + + if (! logMutex_initialized) { + INIT_MUTEX(logMutex); + logMutex_initialized = 1; + } + + LOCK(logMutex); + va_start(args, format); + + time(&log_clock); + strftime(buf, 255, "%d/%m/%Y %X ", localtime(&log_clock)); + fprintf(stderr, "%s", buf); + + vfprintf(stderr, format, args); + fflush(stderr); + + va_end(args); + UNLOCK(logMutex); +} + +rfbLogProc rfbLog=rfbDefaultLog; +rfbLogProc rfbErr=rfbDefaultLog; + +void rfbLogPerror(const char *str) +{ +#ifdef WIN32 + wchar_t *s = NULL; + FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, errno, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPWSTR)&s, 0, NULL); + rfbErr("%s: %S\n", str, s); + LocalFree(s); +#else + rfbErr("%s: %s\n", str, strerror(errno)); +#endif +} + +void rfbScheduleCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,int dx,int dy) +{ + rfbClientIteratorPtr iterator; + rfbClientPtr cl; + + iterator=rfbGetClientIterator(rfbScreen); + while((cl=rfbClientIteratorNext(iterator))) { + LOCK(cl->updateMutex); + if(cl->useCopyRect) { + sraRegionPtr modifiedRegionBackup; + if(!sraRgnEmpty(cl->copyRegion)) { + if(cl->copyDX!=dx || cl->copyDY!=dy) { + /* if a copyRegion was not yet executed, treat it as a + * modifiedRegion. The idea: in this case it could be + * source of the new copyRect or modified anyway. */ + sraRgnOr(cl->modifiedRegion,cl->copyRegion); + sraRgnMakeEmpty(cl->copyRegion); + } else { + /* we have to set the intersection of the source of the copy + * and the old copy to modified. */ + modifiedRegionBackup=sraRgnCreateRgn(copyRegion); + sraRgnOffset(modifiedRegionBackup,-dx,-dy); + sraRgnAnd(modifiedRegionBackup,cl->copyRegion); + sraRgnOr(cl->modifiedRegion,modifiedRegionBackup); + sraRgnDestroy(modifiedRegionBackup); + } + } + + sraRgnOr(cl->copyRegion,copyRegion); + cl->copyDX = dx; + cl->copyDY = dy; + + /* if there were modified regions, which are now copied, + * mark them as modified, because the source of these can be overlapped + * either by new modified or now copied regions. */ + modifiedRegionBackup=sraRgnCreateRgn(cl->modifiedRegion); + sraRgnOffset(modifiedRegionBackup,dx,dy); + sraRgnAnd(modifiedRegionBackup,cl->copyRegion); + sraRgnOr(cl->modifiedRegion,modifiedRegionBackup); + sraRgnDestroy(modifiedRegionBackup); + + if(!cl->enableCursorShapeUpdates) { + /* + * n.b. (dx, dy) is the vector pointing in the direction the + * copyrect displacement will take place. copyRegion is the + * destination rectangle (say), not the source rectangle. + */ + sraRegionPtr cursorRegion; + int x = cl->cursorX - cl->screen->cursor->xhot; + int y = cl->cursorY - cl->screen->cursor->yhot; + int w = cl->screen->cursor->width; + int h = cl->screen->cursor->height; + + cursorRegion = sraRgnCreateRect(x, y, x + w, y + h); + sraRgnAnd(cursorRegion, cl->copyRegion); + if(!sraRgnEmpty(cursorRegion)) { + /* + * current cursor rect overlaps with the copy region *dest*, + * mark it as modified since we won't copy-rect stuff to it. + */ + sraRgnOr(cl->modifiedRegion, cursorRegion); + } + sraRgnDestroy(cursorRegion); + + cursorRegion = sraRgnCreateRect(x, y, x + w, y + h); + /* displace it to check for overlap with copy region source: */ + sraRgnOffset(cursorRegion, dx, dy); + sraRgnAnd(cursorRegion, cl->copyRegion); + if(!sraRgnEmpty(cursorRegion)) { + /* + * current cursor rect overlaps with the copy region *source*, + * mark the *displaced* cursorRegion as modified since we + * won't copyrect stuff to it. + */ + sraRgnOr(cl->modifiedRegion, cursorRegion); + } + sraRgnDestroy(cursorRegion); + } + + } else { + sraRgnOr(cl->modifiedRegion,copyRegion); + } + TSIGNAL(cl->updateCond); + UNLOCK(cl->updateMutex); + } + + rfbReleaseClientIterator(iterator); +} + +void rfbDoCopyRegion(rfbScreenInfoPtr screen,sraRegionPtr copyRegion,int dx,int dy) +{ + sraRectangleIterator* i; + sraRect rect; + int j,widthInBytes,bpp=screen->serverFormat.bitsPerPixel/8, + rowstride=screen->paddedWidthInBytes; + char *in,*out; + + /* copy it, really */ + i = sraRgnGetReverseIterator(copyRegion,dx<0,dy<0); + while(sraRgnIteratorNext(i,&rect)) { + widthInBytes = (rect.x2-rect.x1)*bpp; + out = screen->frameBuffer+rect.x1*bpp+rect.y1*rowstride; + in = screen->frameBuffer+(rect.x1-dx)*bpp+(rect.y1-dy)*rowstride; + if(dy<0) + for(j=rect.y1;j=rect.y1;j--,out-=rowstride,in-=rowstride) + memmove(out,in,widthInBytes); + } + } + sraRgnReleaseIterator(i); + + rfbScheduleCopyRegion(screen,copyRegion,dx,dy); +} + +void rfbDoCopyRect(rfbScreenInfoPtr screen,int x1,int y1,int x2,int y2,int dx,int dy) +{ + sraRegionPtr region = sraRgnCreateRect(x1,y1,x2,y2); + rfbDoCopyRegion(screen,region,dx,dy); + sraRgnDestroy(region); +} + +void rfbScheduleCopyRect(rfbScreenInfoPtr screen,int x1,int y1,int x2,int y2,int dx,int dy) +{ + sraRegionPtr region = sraRgnCreateRect(x1,y1,x2,y2); + rfbScheduleCopyRegion(screen,region,dx,dy); + sraRgnDestroy(region); +} + +void rfbMarkRegionAsModified(rfbScreenInfoPtr screen,sraRegionPtr modRegion) +{ + rfbClientIteratorPtr iterator; + rfbClientPtr cl; + + iterator=rfbGetClientIterator(screen); + while((cl=rfbClientIteratorNext(iterator))) { + LOCK(cl->updateMutex); + sraRgnOr(cl->modifiedRegion,modRegion); + TSIGNAL(cl->updateCond); + UNLOCK(cl->updateMutex); + } + + rfbReleaseClientIterator(iterator); +} + +void rfbScaledScreenUpdate(rfbScreenInfoPtr screen, int x1, int y1, int x2, int y2); +void rfbMarkRectAsModified(rfbScreenInfoPtr screen,int x1,int y1,int x2,int y2) +{ + sraRegionPtr region; + int i; + + if(x1>x2) { i=x1; x1=x2; x2=i; } + if(x1<0) x1=0; + if(x2>screen->width) x2=screen->width; + if(x1==x2) return; + + if(y1>y2) { i=y1; y1=y2; y2=i; } + if(y1<0) y1=0; + if(y2>screen->height) y2=screen->height; + if(y1==y2) return; + + /* update scaled copies for this rectangle */ + rfbScaledScreenUpdate(screen,x1,y1,x2,y2); + + region = sraRgnCreateRect(x1,y1,x2,y2); + rfbMarkRegionAsModified(screen,region); + sraRgnDestroy(region); +} + +#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD +#include + +static void * +clientOutput(void *data) +{ + rfbClientPtr cl = (rfbClientPtr)data; + rfbBool haveUpdate; + sraRegion* updateRegion; + + while (1) { + haveUpdate = false; + while (!haveUpdate) { + if (cl->sock == -1) { + /* Client has disconnected. */ + return NULL; + } + if (cl->state != _rfbClientRec::RFB_NORMAL || cl->onHold) { + /* just sleep until things get normal */ + usleep(cl->screen->deferUpdateTime * 1000); + continue; + } + + LOCK(cl->updateMutex); + + if (sraRgnEmpty(cl->requestedRegion)) { + ; /* always require a FB Update Request (otherwise can crash.) */ + } else { + haveUpdate = FB_UPDATE_PENDING(cl); + if(!haveUpdate) { + updateRegion = sraRgnCreateRgn(cl->modifiedRegion); + haveUpdate = sraRgnAnd(updateRegion,cl->requestedRegion); + sraRgnDestroy(updateRegion); + } + } + + if (!haveUpdate) { + WAIT(cl->updateCond, cl->updateMutex); + } + + UNLOCK(cl->updateMutex); + } + + /* OK, now, to save bandwidth, wait a little while for more + updates to come along. */ + usleep(cl->screen->deferUpdateTime * 1000); + + /* Now, get the region we're going to update, and remove + it from cl->modifiedRegion _before_ we send the update. + That way, if anything that overlaps the region we're sending + is updated, we'll be sure to do another update later. */ + LOCK(cl->updateMutex); + updateRegion = sraRgnCreateRgn(cl->modifiedRegion); + UNLOCK(cl->updateMutex); + + /* Now actually send the update. */ + rfbIncrClientRef(cl); + LOCK(cl->sendMutex); + rfbSendFramebufferUpdate(cl, updateRegion); + UNLOCK(cl->sendMutex); + rfbDecrClientRef(cl); + + sraRgnDestroy(updateRegion); + } + + /* Not reached. */ + return NULL; +} + +static void * +clientInput(void *data) +{ + rfbClientPtr cl = (rfbClientPtr)data; + /* Start output thread */ + TQEventLoopThread* clientOutputHandlerThread = new TQEventLoopThread(); + ClientOutputHandlerObject* clientOutputHandler = new ClientOutputHandlerObject(); + clientOutputHandler->d = cl; + clientOutputHandler->moveToThread(clientOutputHandlerThread); + TQTimer::singleShot(0, clientOutputHandler, SLOT(run())); + clientOutputHandlerThread->start(); + + while (1) { + fd_set rfds, wfds, efds; + struct timeval tv; + int n; + + if (cl->sock == -1) { + /* Client has disconnected. */ + break; + } + + FD_ZERO(&rfds); + FD_SET(cl->sock, &rfds); + FD_SET(cl->pipe_notify_client_thread[0], &rfds); + FD_ZERO(&efds); + FD_SET(cl->sock, &efds); + + /* Are we transferring a file in the background? */ + FD_ZERO(&wfds); + if ((cl->fileTransfer.fd!=-1) && (cl->fileTransfer.sending==1)) + FD_SET(cl->sock, &wfds); + + int nfds = cl->pipe_notify_client_thread[0] > cl->sock ? cl->pipe_notify_client_thread[0] : cl->sock; + + tv.tv_sec = 60; /* 1 minute */ + tv.tv_usec = 0; + + n = select(nfds + 1, &rfds, &wfds, &efds, &tv); + + if (n < 0) { + rfbLogPerror("ReadExact: select"); + break; + } + if (n == 0) /* timeout */ + { + rfbSendFileTransferChunk(cl); + continue; + } + + /* We have some space on the transmit queue, send some data */ + if (FD_ISSET(cl->sock, &wfds)) + rfbSendFileTransferChunk(cl); + + if (FD_ISSET(cl->pipe_notify_client_thread[0], &rfds)) + { + /* Reset the pipe */ + char buf; + while (read(cl->pipe_notify_client_thread[0], &buf, sizeof(buf)) == sizeof(buf)); + } + + if (FD_ISSET(cl->sock, &rfds) || FD_ISSET(cl->sock, &efds)) + { +#ifdef LIBVNCSERVER_WITH_WEBSOCKETS + do { + rfbProcessClientMessage(cl); + } while (webSocketsHasDataInBuffer(cl)); +#else + rfbProcessClientMessage(cl); +#endif + } + } + + /* Get rid of the output thread. */ + LOCK(cl->updateMutex); + TSIGNAL(cl->updateCond); + UNLOCK(cl->updateMutex); + clientOutputHandlerThread->wait(); + delete clientOutputHandlerThread; + clientOutputHandlerThread = NULL; + delete clientOutputHandler; + clientOutputHandler = NULL; + + rfbClientConnectionGone(cl); + + return NULL; +} + +static void* +listenerRun(void *data) +{ + rfbScreenInfoPtr screen=(rfbScreenInfoPtr)data; + int client_fd; + struct sockaddr_storage peer; + rfbClientPtr cl = NULL; + socklen_t len; + fd_set listen_fds; /* temp file descriptor list for select() */ + + if (screen->inetdSock != -1) { + cl = rfbNewClient(screen, screen->inetdSock); + if (cl && !cl->onHold) + rfbStartOnHoldClient(cl); + else if (screen->inetdDisconnectHook && !cl) + screen->inetdDisconnectHook(); + return NULL; + } + + /* TODO: this thread won't die by restarting the server */ + /* TODO: HTTP is not handled */ + while (1) { + client_fd = -1; + FD_ZERO(&listen_fds); + if(screen->listenSock >= 0) + FD_SET(screen->listenSock, &listen_fds); + if(screen->listen6Sock >= 0) + FD_SET(screen->listen6Sock, &listen_fds); + + if (select(screen->maxFd+1, &listen_fds, NULL, NULL, NULL) == -1) { + rfbLogPerror("listenerRun: error in select"); + return NULL; + } + + /* there is something on the listening sockets, handle new connections */ + len = sizeof (peer); + if (FD_ISSET(screen->listenSock, &listen_fds)) + client_fd = accept(screen->listenSock, (struct sockaddr*)&peer, &len); + else if (FD_ISSET(screen->listen6Sock, &listen_fds)) + client_fd = accept(screen->listen6Sock, (struct sockaddr*)&peer, &len); + + if(client_fd >= 0) + cl = rfbNewClient(screen,client_fd); + if (cl && !cl->onHold ) + rfbStartOnHoldClient(cl); + } + return(NULL); +} + +void +rfbStartOnHoldClient(rfbClientPtr cl) +{ + mOnHoldClientHandlerThread = new TQEventLoopThread(); + mOnHoldClientHandler = new OnHoldClientHandlerObject(); + mOnHoldClientHandler->d = cl; + mOnHoldClientHandler->moveToThread(mOnHoldClientHandlerThread); + TQTimer::singleShot(0, mOnHoldClientHandler, SLOT(run())); + mOnHoldClientHandlerThread->start(); +} + +#else + +void +rfbStartOnHoldClient(rfbClientPtr cl) +{ + cl->onHold = FALSE; +#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD + if(cl->screen->backgroundLoop) { + if (pipe(cl->pipe_notify_client_thread) == -1) { + cl->pipe_notify_client_thread[0] = -1; + cl->pipe_notify_client_thread[1] = -1; + } + fcntl(cl->pipe_notify_client_thread[0], F_SETFL, O_NONBLOCK); + + pthread_create(&cl->client_thread, NULL, clientInput, (void *)cl); + } +#endif +} + +#endif + +void +rfbRefuseOnHoldClient(rfbClientPtr cl) +{ + rfbCloseClient(cl); + rfbClientConnectionGone(cl); +} + +static void +rfbDefaultKbdAddEvent(rfbBool down, rfbKeySym keySym, rfbClientPtr cl) +{ +} + +void +rfbDefaultPtrAddEvent(int buttonMask, int x, int y, rfbClientPtr cl) +{ + rfbClientIteratorPtr iterator; + rfbClientPtr other_client; + rfbScreenInfoPtr s = cl->screen; + + if (x != s->cursorX || y != s->cursorY) { + LOCK(s->cursorMutex); + s->cursorX = x; + s->cursorY = y; + UNLOCK(s->cursorMutex); + + /* The cursor was moved by this client, so don't send CursorPos. */ + if (cl->enableCursorPosUpdates) + cl->cursorWasMoved = FALSE; + + /* But inform all remaining clients about this cursor movement. */ + iterator = rfbGetClientIterator(s); + while ((other_client = rfbClientIteratorNext(iterator)) != NULL) { + if (other_client != cl && other_client->enableCursorPosUpdates) { + other_client->cursorWasMoved = TRUE; + } + } + rfbReleaseClientIterator(iterator); + } +} + +static void rfbDefaultSetXCutText(char* text, int len, rfbClientPtr cl) +{ +} + +/* TODO: add a nice VNC or RFB cursor */ + +#if defined(WIN32) || defined(sparc) || !defined(NO_STRICT_ANSI) +static rfbCursor myCursor = +{ + FALSE, FALSE, FALSE, FALSE, + (unsigned char*)"\000\102\044\030\044\102\000", + (unsigned char*)"\347\347\176\074\176\347\347", + 8, 7, 3, 3, + 0, 0, 0, + 0xffff, 0xffff, 0xffff, + NULL +}; +#else +static rfbCursor myCursor = +{ + cleanup: FALSE, + cleanupSource: FALSE, + cleanupMask: FALSE, + cleanupRichSource: FALSE, + source: "\000\102\044\030\044\102\000", + mask: "\347\347\176\074\176\347\347", + width: 8, height: 7, xhot: 3, yhot: 3, + foreRed: 0, foreGreen: 0, foreBlue: 0, + backRed: 0xffff, backGreen: 0xffff, backBlue: 0xffff, + richSource: NULL +}; +#endif + +static rfbCursorPtr rfbDefaultGetCursorPtr(rfbClientPtr cl) +{ + return(cl->screen->cursor); +} + +/* response is cl->authChallenge vncEncrypted with passwd */ +static rfbBool rfbDefaultPasswordCheck(rfbClientPtr cl,const char* response,int len) +{ + int i; + char *passwd=rfbDecryptPasswdFromFile((char*)cl->screen->authPasswdData); + + if(!passwd) { + rfbErr("Couldn't read password file: %s\n",cl->screen->authPasswdData); + return(FALSE); + } + + rfbEncryptBytes(cl->authChallenge, passwd); + + /* Lose the password from memory */ + for (i = strlen(passwd); i >= 0; i--) { + passwd[i] = '\0'; + } + + free(passwd); + + if (memcmp(cl->authChallenge, response, len) != 0) { + rfbErr("authProcessClientMessage: authentication failed from %s\n", + cl->host); + return(FALSE); + } + + return(TRUE); +} + +/* for this method, authPasswdData is really a pointer to an array + of char*'s, where the last pointer is 0. */ +rfbBool rfbCheckPasswordByList(rfbClientPtr cl,const char* response,int len) +{ + char **passwds; + int i=0; + + for(passwds=(char**)cl->screen->authPasswdData;*passwds;passwds++,i++) { + uint8_t auth_tmp[CHALLENGESIZE]; + memcpy((char *)auth_tmp, (char *)cl->authChallenge, CHALLENGESIZE); + rfbEncryptBytes(auth_tmp, *passwds); + + if (memcmp(auth_tmp, response, len) == 0) { + if(i>=cl->screen->authPasswdFirstViewOnly) + cl->viewOnly=TRUE; + return(TRUE); + } + } + + rfbErr("authProcessClientMessage: authentication failed from %s\n", + cl->host); + return(FALSE); +} + +void rfbDoNothingWithClient(rfbClientPtr cl) +{ +} + +static enum rfbNewClientAction rfbDefaultNewClientHook(rfbClientPtr cl) +{ + return RFB_CLIENT_ACCEPT; +} + +/* + * Update server's pixel format in screenInfo structure. This + * function is called from rfbGetScreen() and rfbNewFramebuffer(). + */ + +static void rfbInitServerFormat(rfbScreenInfoPtr screen, int bitsPerSample) +{ + rfbPixelFormat* format=&screen->serverFormat; + + format->bitsPerPixel = screen->bitsPerPixel; + format->depth = screen->depth; + format->bigEndian = rfbEndianTest?FALSE:TRUE; + format->trueColour = TRUE; + screen->colourMap.count = 0; + screen->colourMap.is16 = 0; + screen->colourMap.data.bytes = NULL; + + if (format->bitsPerPixel == 8) { + format->redMax = 7; + format->greenMax = 7; + format->blueMax = 3; + format->redShift = 0; + format->greenShift = 3; + format->blueShift = 6; + } else { + format->redMax = (1 << bitsPerSample) - 1; + format->greenMax = (1 << bitsPerSample) - 1; + format->blueMax = (1 << bitsPerSample) - 1; + if(rfbEndianTest) { + format->redShift = 0; + format->greenShift = bitsPerSample; + format->blueShift = bitsPerSample * 2; + } else { + if(format->bitsPerPixel==8*3) { + format->redShift = bitsPerSample*2; + format->greenShift = bitsPerSample*1; + format->blueShift = 0; + } else { + format->redShift = bitsPerSample*3; + format->greenShift = bitsPerSample*2; + format->blueShift = bitsPerSample; + } + } + } +} + +rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv, + int width,int height,int bitsPerSample,int samplesPerPixel, + int bytesPerPixel) +{ + rfbScreenInfoPtr screen=(rfbScreenInfoPtr)calloc(sizeof(rfbScreenInfo),1); + + if (! logMutex_initialized) { + INIT_MUTEX(logMutex); + logMutex_initialized = 1; + } + + + if(width&3) + rfbErr("WARNING: Width (%d) is not a multiple of 4. VncViewer has problems with that.\n",width); + + screen->autoPort=FALSE; + screen->clientHead=NULL; + screen->pointerClient=NULL; + screen->port=5900; + screen->ipv6port=5900; + screen->socketState=RFB_SOCKET_INIT; + + screen->inetdInitDone = FALSE; + screen->inetdSock=-1; + + screen->udpSock=-1; + screen->udpSockConnected=FALSE; + screen->udpPort=0; + screen->udpClient=NULL; + + screen->maxFd=0; + screen->listenSock=-1; + screen->listen6Sock=-1; + + screen->httpInitDone=FALSE; + screen->httpEnableProxyConnect=FALSE; + screen->httpPort=0; + screen->http6Port=0; + screen->httpDir=NULL; + screen->httpListenSock=-1; + screen->httpListen6Sock=-1; + screen->httpSock=-1; + + screen->desktopName = "LibVNCServer"; + screen->alwaysShared = FALSE; + screen->neverShared = FALSE; + screen->dontDisconnect = FALSE; + screen->authPasswdData = NULL; + screen->authPasswdFirstViewOnly = 1; + + screen->width = width; + screen->height = height; + screen->bitsPerPixel = screen->depth = 8*bytesPerPixel; + + screen->passwordCheck = rfbDefaultPasswordCheck; + + screen->ignoreSIGPIPE = TRUE; + + /* disable progressive updating per default */ + screen->progressiveSliceHeight = 0; + + screen->listenInterface = htonl(INADDR_ANY); + + screen->deferUpdateTime=5; + screen->maxRectsPerUpdate=50; + + screen->handleEventsEagerly = FALSE; + + screen->protocolMajorVersion = rfbProtocolMajorVersion; + screen->protocolMinorVersion = rfbProtocolMinorVersion; + + screen->permitFileTransfer = FALSE; + + if(!rfbProcessArguments(screen,argc,argv)) { + free(screen); + return NULL; + } + +#ifdef WIN32 + { + DWORD dummy=255; + GetComputerName(screen->thisHost,&dummy); + } +#else + gethostname(screen->thisHost, 255); +#endif + + screen->paddedWidthInBytes = width*bytesPerPixel; + + /* format */ + + rfbInitServerFormat(screen, bitsPerSample); + + /* cursor */ + + screen->cursorX=screen->cursorY=screen->underCursorBufferLen=0; + screen->underCursorBuffer=NULL; + screen->dontConvertRichCursorToXCursor = FALSE; + screen->cursor = &myCursor; + INIT_MUTEX(screen->cursorMutex); + + IF_PTHREADS(screen->backgroundLoop = FALSE); + + /* proc's and hook's */ + + screen->kbdAddEvent = rfbDefaultKbdAddEvent; + screen->kbdReleaseAllKeys = rfbDoNothingWithClient; + screen->ptrAddEvent = rfbDefaultPtrAddEvent; + screen->setXCutText = rfbDefaultSetXCutText; + screen->getCursorPtr = rfbDefaultGetCursorPtr; + screen->setTranslateFunction = rfbSetTranslateFunction; + screen->newClientHook = rfbDefaultNewClientHook; + screen->displayHook = NULL; + screen->inetdDisconnectHook = NULL; + screen->displayFinishedHook = NULL; + screen->getKeyboardLedStateHook = NULL; + screen->xvpHook = NULL; + + /* initialize client list and iterator mutex */ + rfbClientListInit(screen); + + return(screen); +} + +/* + * Switch to another framebuffer (maybe of different size and color + * format). Clients supporting NewFBSize pseudo-encoding will change + * their local framebuffer dimensions if necessary. + * NOTE: Rich cursor data should be converted to new pixel format by + * the caller. + */ + +void rfbNewFramebuffer(rfbScreenInfoPtr screen, char *framebuffer, + int width, int height, + int bitsPerSample, int samplesPerPixel, + int bytesPerPixel) +{ + rfbPixelFormat old_format; + rfbBool format_changed = FALSE; + rfbClientIteratorPtr iterator; + rfbClientPtr cl; + + /* Update information in the screenInfo structure */ + + old_format = screen->serverFormat; + + if (width & 3) + rfbErr("WARNING: New width (%d) is not a multiple of 4.\n", width); + + screen->width = width; + screen->height = height; + screen->bitsPerPixel = screen->depth = 8*bytesPerPixel; + screen->paddedWidthInBytes = width*bytesPerPixel; + + rfbInitServerFormat(screen, bitsPerSample); + + if (memcmp(&screen->serverFormat, &old_format, + sizeof(rfbPixelFormat)) != 0) { + format_changed = TRUE; + } + + screen->frameBuffer = framebuffer; + + /* Adjust pointer position if necessary */ + + if (screen->cursorX >= width) + screen->cursorX = width - 1; + if (screen->cursorY >= height) + screen->cursorY = height - 1; + + /* For each client: */ + iterator = rfbGetClientIterator(screen); + while ((cl = rfbClientIteratorNext(iterator)) != NULL) { + + /* Re-install color translation tables if necessary */ + + if (format_changed) + screen->setTranslateFunction(cl); + + /* Mark the screen contents as changed, and schedule sending + NewFBSize message if supported by this client. */ + + LOCK(cl->updateMutex); + sraRgnDestroy(cl->modifiedRegion); + cl->modifiedRegion = sraRgnCreateRect(0, 0, width, height); + sraRgnMakeEmpty(cl->copyRegion); + cl->copyDX = 0; + cl->copyDY = 0; + + if (cl->useNewFBSize) + cl->newFBSizePending = TRUE; + + TSIGNAL(cl->updateCond); + UNLOCK(cl->updateMutex); + } + rfbReleaseClientIterator(iterator); +} + +/* hang up on all clients and free all reserved memory */ + +void rfbScreenCleanup(rfbScreenInfoPtr screen) +{ + rfbClientIteratorPtr i=rfbGetClientIterator(screen); + rfbClientPtr cl,cl1=rfbClientIteratorNext(i); + while(cl1) { + cl=rfbClientIteratorNext(i); + rfbClientConnectionGone(cl1); + cl1=cl; + } + rfbReleaseClientIterator(i); + + if (mOnHoldClientHandlerThread) { + mOnHoldClientHandlerThread->exit(); + delete mOnHoldClientHandlerThread; + mOnHoldClientHandlerThread = NULL; + delete mOnHoldClientHandler; + mOnHoldClientHandler = NULL; + } + if (mControlPipeHandlerThread) { + mControlPipeHandlerThread->exit(); + delete mControlPipeHandlerThread; + mControlPipeHandlerThread = NULL; + delete mControlPipeHandler; + mControlPipeHandler = NULL; + } + +#define FREE_IF(x) if(screen->x) free(screen->x) + FREE_IF(colourMap.data.bytes); + FREE_IF(underCursorBuffer); + TINI_MUTEX(screen->cursorMutex); + if(screen->cursor && screen->cursor->cleanup) + rfbFreeCursor(screen->cursor); + +#ifdef LIBVNCSERVER_HAVE_LIBZ + rfbZlibCleanup(screen); +#ifdef LIBVNCSERVER_HAVE_LIBJPEG + rfbTightCleanup(screen); +#endif + + /* free all 'scaled' versions of this screen */ + while (screen->scaledScreenNext!=NULL) + { + rfbScreenInfoPtr ptr; + ptr = screen->scaledScreenNext; + screen->scaledScreenNext = ptr->scaledScreenNext; + free(ptr->frameBuffer); + free(ptr); + } + +#endif + free(screen); +} + +void rfbInitServer(rfbScreenInfoPtr screen) +{ +#ifdef WIN32 + WSADATA trash; + static rfbBool WSAinitted=FALSE; + if(!WSAinitted) { + int i=WSAStartup(MAKEWORD(2,0),&trash); + if(i!=0) { + rfbErr("Couldn't init Windows Sockets\n"); + return; + } + WSAinitted=TRUE; + } +#endif + rfbInitSockets(screen); + rfbHttpInitSockets(screen); +#ifndef WIN32 + if(screen->ignoreSIGPIPE) + signal(SIGPIPE,SIG_IGN); +#endif +} + +void rfbShutdownServer(rfbScreenInfoPtr screen,rfbBool disconnectClients) { + if(disconnectClients) { + rfbClientIteratorPtr iter = rfbGetClientIterator(screen); + rfbClientPtr nextCl, currentCl = rfbClientIteratorNext(iter); + + while(currentCl) { + nextCl = rfbClientIteratorNext(iter); + if (currentCl->sock > -1) { + /* we don't care about maxfd here, because the server goes away */ + rfbCloseClient(currentCl); + } + +#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD + /* + Notify the thread. This simply writes a NULL byte to the notify pipe in order to get past the select() + in clientInput(), the loop in there will then break because the rfbCloseClient() above has set + currentCl->sock to -1. + */ + write(currentCl->pipe_notify_client_thread[1], "\x00", 1); + /* And wait for it to finish. */ + pthread_join(currentCl->client_thread, NULL); +#else + rfbClientConnectionGone(currentCl); +#endif + + currentCl = nextCl; + } + + rfbReleaseClientIterator(iter); + } + + rfbShutdownSockets(screen); + rfbHttpShutdownSockets(screen); +} + +#ifndef LIBVNCSERVER_HAVE_GETTIMEOFDAY +#include +#include +#include + +void gettimeofday(struct timeval* tv,char* dummy) +{ + SYSTEMTIME t; + GetSystemTime(&t); + tv->tv_sec=t.wHour*3600+t.wMinute*60+t.wSecond; + tv->tv_usec=t.wMilliseconds*1000; +} +#endif + +rfbBool +rfbProcessEvents(rfbScreenInfoPtr screen,long usec) +{ + rfbClientIteratorPtr i; + rfbClientPtr cl,clPrev; + rfbBool result=FALSE; + extern rfbClientIteratorPtr + rfbGetClientIteratorWithClosed(rfbScreenInfoPtr rfbScreen); + + if(usec<0) + usec=screen->deferUpdateTime*1000; + + rfbCheckFds(screen,usec); + rfbHttpCheckFds(screen); + + i = rfbGetClientIteratorWithClosed(screen); + cl=rfbClientIteratorHead(i); + while(cl) { + result = rfbUpdateClient(cl); + clPrev=cl; + cl=rfbClientIteratorNext(i); + if(clPrev->sock==-1) { + rfbClientConnectionGone(clPrev); + result=TRUE; + } + } + rfbReleaseClientIterator(i); + + return result; +} + +rfbBool +rfbUpdateClient(rfbClientPtr cl) +{ + struct timeval tv; + rfbBool result=FALSE; + rfbScreenInfoPtr screen = cl->screen; + + if (cl->sock >= 0 && !cl->onHold && FB_UPDATE_PENDING(cl) && + !sraRgnEmpty(cl->requestedRegion)) { + result=TRUE; + if(screen->deferUpdateTime == 0) { + rfbSendFramebufferUpdate(cl,cl->modifiedRegion); + } else if(cl->startDeferring.tv_usec == 0) { + gettimeofday(&cl->startDeferring,NULL); + if(cl->startDeferring.tv_usec == 0) + cl->startDeferring.tv_usec++; + } else { + gettimeofday(&tv,NULL); + if(tv.tv_sec < cl->startDeferring.tv_sec /* at midnight */ + || ((tv.tv_sec-cl->startDeferring.tv_sec)*1000 + +(tv.tv_usec-cl->startDeferring.tv_usec)/1000) + > screen->deferUpdateTime) { + cl->startDeferring.tv_usec = 0; + rfbSendFramebufferUpdate(cl,cl->modifiedRegion); + } + } + } + + if (!cl->viewOnly && cl->lastPtrX >= 0) { + if(cl->startPtrDeferring.tv_usec == 0) { + gettimeofday(&cl->startPtrDeferring,NULL); + if(cl->startPtrDeferring.tv_usec == 0) + cl->startPtrDeferring.tv_usec++; + } else { + struct timeval tv; + gettimeofday(&tv,NULL); + if(tv.tv_sec < cl->startPtrDeferring.tv_sec /* at midnight */ + || ((tv.tv_sec-cl->startPtrDeferring.tv_sec)*1000 + +(tv.tv_usec-cl->startPtrDeferring.tv_usec)/1000) + > cl->screen->deferPtrUpdateTime) { + cl->startPtrDeferring.tv_usec = 0; + cl->screen->ptrAddEvent(cl->lastPtrButtons, + cl->lastPtrX, + cl->lastPtrY, cl); + cl->lastPtrX = -1; + } + } + } + + return result; +} + +rfbBool rfbIsActive(rfbScreenInfoPtr screenInfo) { + return screenInfo->socketState!=RFB_SOCKET_SHUTDOWN || screenInfo->clientHead!=NULL; +} + +void rfbRunEventLoop(rfbScreenInfoPtr screen, long usec, rfbBool runInBackground) +{ + if(runInBackground) { +#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD + screen->backgroundLoop = TRUE; + + mControlPipeHandlerThread = new TQEventLoopThread(); + mControlPipeHandler = new ControlPipeHandlerObject(); + mControlPipeHandler->d = screen; + mControlPipeHandler->moveToThread(mControlPipeHandlerThread); + TQTimer::singleShot(0, mControlPipeHandler, SLOT(run())); + mControlPipeHandlerThread->start(); + return; +#else + rfbErr("Can't run in background, because I don't have PThreads!\n"); + return; +#endif + } + + if(usec<0) + usec=screen->deferUpdateTime*1000; + + while(rfbIsActive(screen)) + rfbProcessEvents(screen,usec); +} + +ControlPipeHandlerObject::ControlPipeHandlerObject() : TQObject() { + // +} + +ControlPipeHandlerObject::~ControlPipeHandlerObject() { + // +} + +void ControlPipeHandlerObject::run(void) { + listenerRun(d); + + // Terminate thread + TQThread::exit(); +} + +OnHoldClientHandlerObject::OnHoldClientHandlerObject() : TQObject() { + // +} + +OnHoldClientHandlerObject::~OnHoldClientHandlerObject() { + // +} + +void OnHoldClientHandlerObject::run(void) { + clientInput(d); + + // Terminate thread + TQThread::exit(); +} + +ClientOutputHandlerObject::ClientOutputHandlerObject() : TQObject() { + // +} + +ClientOutputHandlerObject::~ClientOutputHandlerObject() { + // +} + +void ClientOutputHandlerObject::run(void) { + clientOutput(d); + + // Terminate thread + TQThread::exit(); +} + +#include "main.moc" -- cgit v1.2.3