2 * rfbserver.c - deal with server-side of the RFB protocol.
6 * Copyright (C) 2005 Rohit Kumar, Johannes E. Schindelin
7 * Copyright (C) 2002 RealVNC Ltd.
8 * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
9 * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
10 * All Rights Reserved.
12 * This is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This software is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this software; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
28 #ifdef __STRICT_ANSI__
33 #include <rfb/rfbregion.h>
36 #ifdef LIBVNCSERVER_HAVE_FCNTL_H
41 #define write(sock,buf,len) send(sock,buf,len,0)
43 #ifdef LIBVNCSERVER_HAVE_UNISTD_H
47 #ifdef LIBVNCSERVER_HAVE_SYS_SOCKET_H
48 #include <sys/socket.h>
50 #ifdef LIBVNCSERVER_HAVE_NETINET_IN_H
51 #include <netinet/in.h>
52 #include <netinet/tcp.h>
53 #include <arpa/inet.h>
58 #include <vncserverctrl.h>
63 #define DEBUGPROTO(x) x
70 #include <sys/types.h>
81 static int compat_mkdir(const char *path, int mode)
85 #define mkdir compat_mkdir
88 static void rfbProcessClientProtocolVersion(rfbClientPtr cl);
89 static void rfbProcessClientNormalMessage(rfbClientPtr cl);
90 static void rfbProcessClientInitMessage(rfbClientPtr cl);
92 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
93 void rfbIncrClientRef(rfbClientPtr cl)
95 LOCK(cl->refCountMutex);
97 UNLOCK(cl->refCountMutex);
100 void rfbDecrClientRef(rfbClientPtr cl)
102 LOCK(cl->refCountMutex);
104 if(cl->refCount<=0) /* just to be sure also < 0 */
105 TSIGNAL(cl->deleteCond);
106 UNLOCK(cl->refCountMutex);
109 void rfbIncrClientRef(rfbClientPtr cl) {}
110 void rfbDecrClientRef(rfbClientPtr cl) {}
113 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
114 static MUTEX(rfbClientListMutex);
117 struct rfbClientIterator {
119 rfbScreenInfoPtr screen;
124 rfbClientListInit(rfbScreenInfoPtr rfbScreen)
126 if(sizeof(rfbBool)!=1) {
128 fprintf(stderr,"rfbBool's size is not 1 (%d)!\n",(int)sizeof(rfbBool));
129 /* we cannot continue, because rfbBool is supposed to be char everywhere */
132 rfbScreen->clientHead = NULL;
133 INIT_MUTEX(rfbClientListMutex);
137 rfbGetClientIterator(rfbScreenInfoPtr rfbScreen)
139 rfbClientIteratorPtr i =
140 (rfbClientIteratorPtr)malloc(sizeof(struct rfbClientIterator));
142 i->screen = rfbScreen;
143 i->closedToo = FALSE;
148 rfbGetClientIteratorWithClosed(rfbScreenInfoPtr rfbScreen)
150 rfbClientIteratorPtr i =
151 (rfbClientIteratorPtr)malloc(sizeof(struct rfbClientIterator));
153 i->screen = rfbScreen;
159 rfbClientIteratorHead(rfbClientIteratorPtr i)
161 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
163 rfbDecrClientRef(i->next);
164 rfbIncrClientRef(i->screen->clientHead);
167 LOCK(rfbClientListMutex);
168 i->next = i->screen->clientHead;
169 UNLOCK(rfbClientListMutex);
174 rfbClientIteratorNext(rfbClientIteratorPtr i)
177 LOCK(rfbClientListMutex);
178 i->next = i->screen->clientHead;
179 UNLOCK(rfbClientListMutex);
181 IF_PTHREADS(rfbClientPtr cl = i->next);
182 i->next = i->next->next;
183 IF_PTHREADS(rfbDecrClientRef(cl));
186 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
188 while(i->next && i->next->sock<0)
189 i->next = i->next->next;
191 rfbIncrClientRef(i->next);
198 rfbReleaseClientIterator(rfbClientIteratorPtr iterator)
200 IF_PTHREADS(if(iterator->next) rfbDecrClientRef(iterator->next));
206 * rfbNewClientConnection is called from sockets.c when a new connection
211 rfbNewClientConnection(rfbScreenInfoPtr rfbScreen,
216 cl = rfbNewClient(rfbScreen,sock);
219 newConnection(cl, (KEYBOARD_DEVICE|POINTER_DEVICE),1,1,1);
225 * rfbReverseConnection is called by the CORBA stuff to make an outward
226 * connection to a "listening" RFB client.
230 rfbReverseConnection(rfbScreenInfoPtr rfbScreen,
237 if ((sock = rfbConnect(rfbScreen, host, port)) < 0)
238 return (rfbClientPtr)NULL;
240 cl = rfbNewClient(rfbScreen, sock);
243 cl->reverseConnection = TRUE;
251 rfbSetProtocolVersion(rfbScreenInfoPtr rfbScreen, int major_, int minor_)
253 /* Permit the server to set the version to report */
254 /* TODO: sanity checking */
255 if ((major_==3) && (minor_ > 2 && minor_ < 9))
257 rfbScreen->protocolMajorVersion = major_;
258 rfbScreen->protocolMinorVersion = minor_;
261 rfbLog("rfbSetProtocolVersion(%d,%d) set to invalid values\n", major_, minor_);
265 * rfbNewClient is called when a new connection has been made by whatever
270 rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen,
274 rfbProtocolVersionMsg pv;
275 rfbClientIteratorPtr iterator;
277 struct sockaddr_in addr;
278 socklen_t addrlen = sizeof(struct sockaddr_in);
279 rfbProtocolExtension* extension;
281 cl = (rfbClientPtr)calloc(sizeof(rfbClientRec),1);
283 cl->screen = rfbScreen;
285 cl->viewOnly = FALSE;
286 /* setup pseudo scaling */
287 cl->scaledScreen = rfbScreen;
288 cl->scaledScreen->scaledScreenRefCount++;
292 cl->clientData = NULL;
293 cl->clientGoneHook = rfbDoNothingWithClient;
296 rfbLog(" accepted UDP client\n");
300 getpeername(sock, (struct sockaddr *)&addr, &addrlen);
301 cl->host = strdup(inet_ntoa(addr.sin_addr));
303 rfbLog(" other clients:\n");
304 iterator = rfbGetClientIterator(rfbScreen);
305 while ((cl_ = rfbClientIteratorNext(iterator)) != NULL) {
306 rfbLog(" %s\n",cl_->host);
308 rfbReleaseClientIterator(iterator);
311 if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
312 rfbLogPerror("fcntl failed");
318 if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
319 (char *)&one, sizeof(one)) < 0) {
320 rfbLogPerror("setsockopt failed");
325 FD_SET(sock,&(rfbScreen->allFds));
326 rfbScreen->maxFd = max(sock,rfbScreen->maxFd);
328 INIT_MUTEX(cl->outputMutex);
329 INIT_MUTEX(cl->refCountMutex);
330 INIT_COND(cl->deleteCond);
332 cl->state = RFB_PROTOCOL_VERSION;
334 cl->reverseConnection = FALSE;
335 cl->readyForSetColourMapEntries = FALSE;
336 cl->useCopyRect = FALSE;
337 cl->preferredEncoding = -1;
338 cl->correMaxWidth = 48;
339 cl->correMaxHeight = 48;
340 #ifdef LIBVNCSERVER_HAVE_LIBZ
344 cl->copyRegion = sraRgnCreate();
349 sraRgnCreateRect(0,0,rfbScreen->width,rfbScreen->height);
351 INIT_MUTEX(cl->updateMutex);
352 INIT_COND(cl->updateCond);
354 cl->requestedRegion = sraRgnCreate();
356 cl->format = cl->screen->serverFormat;
357 cl->translateFn = rfbTranslateNone;
358 cl->translateLookupTable = NULL;
360 LOCK(rfbClientListMutex);
362 IF_PTHREADS(cl->refCount = 0);
363 cl->next = rfbScreen->clientHead;
365 if (rfbScreen->clientHead)
366 rfbScreen->clientHead->prev = cl;
368 rfbScreen->clientHead = cl;
369 UNLOCK(rfbClientListMutex);
371 #ifdef LIBVNCSERVER_HAVE_LIBZ
372 cl->tightQualityLevel = -1;
373 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
374 cl->tightCompressLevel = TIGHT_DEFAULT_COMPRESSION;
377 for (i = 0; i < 4; i++)
378 cl->zsActive[i] = FALSE;
383 cl->fileTransfer.fd = -1;
385 cl->enableCursorShapeUpdates = FALSE;
386 cl->enableCursorPosUpdates = FALSE;
387 cl->useRichCursorEncoding = FALSE;
388 cl->enableLastRectEncoding = FALSE;
389 cl->enableKeyboardLedState = FALSE;
390 cl->enableSupportedMessages = FALSE;
391 cl->enableSupportedEncodings = FALSE;
392 cl->enableServerIdentity = FALSE;
393 cl->lastKeyboardLedState = -1;
394 cl->cursorX = rfbScreen->cursorX;
395 cl->cursorY = rfbScreen->cursorY;
396 cl->useNewFBSize = FALSE;
398 #ifdef LIBVNCSERVER_HAVE_LIBZ
399 cl->compStreamInited = FALSE;
400 cl->compStream.total_in = 0;
401 cl->compStream.total_out = 0;
402 cl->compStream.zalloc = Z_NULL;
403 cl->compStream.zfree = Z_NULL;
404 cl->compStream.opaque = Z_NULL;
406 cl->zlibCompressLevel = 5;
409 cl->progressiveSliceY = 0;
411 cl->extensions = NULL;
415 sprintf(pv,rfbProtocolVersionFormat,rfbScreen->protocolMajorVersion,
416 rfbScreen->protocolMinorVersion);
418 if (rfbWriteExact(cl, pv, sz_rfbProtocolVersionMsg) < 0) {
419 rfbLogPerror("rfbNewClient: write");
421 rfbClientConnectionGone(cl);
426 for(extension = rfbGetExtensionIterator(); extension;
427 extension=extension->next) {
429 /* if the extension does not have a newClient method, it wants
430 * to be initialized later. */
431 if(extension->newClient && extension->newClient(cl, &data))
432 rfbEnableExtension(cl, extension, data);
434 rfbReleaseExtensionIterator();
436 switch (cl->screen->newClientHook(cl)) {
437 case RFB_CLIENT_ON_HOLD:
440 case RFB_CLIENT_ACCEPT:
443 case RFB_CLIENT_REFUSE:
445 rfbClientConnectionGone(cl);
453 rfbNewClient(rfbScreenInfoPtr rfbScreen,
456 return(rfbNewTCPOrUDPClient(rfbScreen,sock,FALSE));
460 rfbNewUDPClient(rfbScreenInfoPtr rfbScreen)
462 return((rfbScreen->udpClient=
463 rfbNewTCPOrUDPClient(rfbScreen,rfbScreen->udpSock,TRUE)));
467 * rfbClientConnectionGone is called from sockets.c just after a connection
472 rfbClientConnectionGone(rfbClientPtr cl)
474 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
478 LOCK(rfbClientListMutex);
481 cl->prev->next = cl->next;
483 cl->screen->clientHead = cl->next;
485 cl->next->prev = cl->prev;
490 if (cl->scaledScreen!=NULL)
491 cl->scaledScreen->scaledScreenRefCount--;
493 #ifdef LIBVNCSERVER_HAVE_LIBZ
497 rfbFreeUltraData(cl);
499 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
500 if(cl->screen->backgroundLoop != FALSE) {
503 LOCK(cl->refCountMutex);
506 WAIT(cl->deleteCond,cl->refCountMutex);
507 UNLOCK(cl->refCountMutex);
512 UNLOCK(rfbClientListMutex);
515 FD_CLR(cl->sock,&(cl->screen->allFds));
517 cl->clientGoneHook(cl);
519 rfbLog("Client %s gone\n",cl->host);
522 #ifdef LIBVNCSERVER_HAVE_LIBZ
523 /* Release the compression state structures if any. */
524 if ( cl->compStreamInited ) {
525 deflateEnd( &(cl->compStream) );
528 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
529 for (i = 0; i < 4; i++) {
531 deflateEnd(&cl->zsStruct[i]);
536 if (cl->screen->pointerClient == cl)
537 cl->screen->pointerClient = NULL;
539 sraRgnDestroy(cl->modifiedRegion);
540 sraRgnDestroy(cl->requestedRegion);
541 sraRgnDestroy(cl->copyRegion);
543 if (cl->translateLookupTable) free(cl->translateLookupTable);
545 TINI_COND(cl->updateCond);
546 TINI_MUTEX(cl->updateMutex);
548 /* make sure outputMutex is unlocked before destroying */
549 LOCK(cl->outputMutex);
550 UNLOCK(cl->outputMutex);
551 TINI_MUTEX(cl->outputMutex);
554 destroyConnection(cl);
564 * rfbProcessClientMessage is called when there is data to read from a client.
568 rfbProcessClientMessage(rfbClientPtr cl)
571 case RFB_PROTOCOL_VERSION:
572 rfbProcessClientProtocolVersion(cl);
574 case RFB_SECURITY_TYPE:
575 rfbProcessClientSecurityType(cl);
577 case RFB_AUTHENTICATION:
578 rfbAuthProcessClientMessage(cl);
580 case RFB_INITIALISATION:
581 rfbProcessClientInitMessage(cl);
584 rfbProcessClientNormalMessage(cl);
591 * rfbProcessClientProtocolVersion is called when the client sends its
596 rfbProcessClientProtocolVersion(rfbClientPtr cl)
598 rfbProtocolVersionMsg pv;
599 int n, major_, minor_;
601 if ((n = rfbReadExact(cl, pv, sz_rfbProtocolVersionMsg)) <= 0) {
603 rfbLog("rfbProcessClientProtocolVersion: client gone\n");
605 rfbLogPerror("rfbProcessClientProtocolVersion: read");
610 pv[sz_rfbProtocolVersionMsg] = 0;
611 if (sscanf(pv,rfbProtocolVersionFormat,&major_,&minor_) != 2) {
613 if(sscanf(pv,"RFB %03d.%03d %1023s\n",&major_,&minor_,name) != 3) {
614 rfbErr("rfbProcessClientProtocolVersion: not a valid RFB client: %s\n", pv);
619 cl->host=strdup(name);
621 rfbLog("Client Protocol Version %d.%d\n", major_, minor_);
623 if (major_ != rfbProtocolMajorVersion) {
624 rfbErr("RFB protocol version mismatch - server %d.%d, client %d.%d",
625 cl->screen->protocolMajorVersion, cl->screen->protocolMinorVersion,
631 /* Check for the minor version use either of the two standard version of RFB */
633 * UltraVNC Viewer detects FileTransfer compatible servers via rfb versions
634 * 3.4, 3.6, 3.14, 3.16
635 * It's a bad method, but it is what they use to enable features...
636 * maintaining RFB version compatibility across multiple servers is a pain
637 * Should use something like ServerIdentity encoding
639 cl->protocolMajorVersion = major_;
640 cl->protocolMinorVersion = minor_;
642 rfbLog("Protocol version sent %d.%d, using %d.%d\n",
643 major_, minor_, rfbProtocolMajorVersion, cl->protocolMinorVersion);
645 rfbAuthNewClient(cl);
650 rfbClientSendString(rfbClientPtr cl, char *reason)
653 int len = strlen(reason);
655 rfbLog("rfbClientSendString(\"%s\")\n", reason);
657 buf = (char *)malloc(4 + len);
658 ((uint32_t *)buf)[0] = Swap32IfLE(len);
659 memcpy(buf + 4, reason, len);
661 if (rfbWriteExact(cl, buf, 4 + len) < 0)
662 rfbLogPerror("rfbClientSendString: write");
669 * rfbClientConnFailed is called when a client connection has failed either
670 * because it talks the wrong protocol or it has failed authentication.
674 rfbClientConnFailed(rfbClientPtr cl,
678 int len = strlen(reason);
680 rfbLog("rfbClientConnFailed(\"%s\")\n", reason);
682 buf = (char *)malloc(8 + len);
683 ((uint32_t *)buf)[0] = Swap32IfLE(rfbConnFailed);
684 ((uint32_t *)buf)[1] = Swap32IfLE(len);
685 memcpy(buf + 8, reason, len);
687 if (rfbWriteExact(cl, buf, 8 + len) < 0)
688 rfbLogPerror("rfbClientConnFailed: write");
696 * rfbProcessClientInitMessage is called when the client sends its
697 * initialisation message.
701 rfbProcessClientInitMessage(rfbClientPtr cl)
709 rfbClientIteratorPtr iterator;
710 rfbClientPtr otherCl;
711 rfbExtensionData* extension;
713 if ((n = rfbReadExact(cl, (char *)&ci,sz_rfbClientInitMsg)) <= 0) {
715 rfbLog("rfbProcessClientInitMessage: client gone\n");
717 rfbLogPerror("rfbProcessClientInitMessage: read");
722 memset(u.buf,0,sizeof(u.buf));
724 u.si.framebufferWidth = Swap16IfLE(cl->screen->width);
725 u.si.framebufferHeight = Swap16IfLE(cl->screen->height);
726 u.si.format = cl->screen->serverFormat;
727 u.si.format.redMax = Swap16IfLE(u.si.format.redMax);
728 u.si.format.greenMax = Swap16IfLE(u.si.format.greenMax);
729 u.si.format.blueMax = Swap16IfLE(u.si.format.blueMax);
731 strncpy(u.buf + sz_rfbServerInitMsg, cl->screen->desktopName, 127);
732 len = strlen(u.buf + sz_rfbServerInitMsg);
733 u.si.nameLength = Swap32IfLE(len);
735 if (rfbWriteExact(cl, u.buf, sz_rfbServerInitMsg + len) < 0) {
736 rfbLogPerror("rfbProcessClientInitMessage: write");
741 for(extension = cl->extensions; extension;) {
742 rfbExtensionData* next = extension->next;
743 if(extension->extension->init &&
744 !extension->extension->init(cl, extension->data))
745 /* extension requested that it be removed */
746 rfbDisableExtension(cl, extension->extension);
750 cl->state = RFB_NORMAL;
752 if (!cl->reverseConnection &&
753 (cl->screen->neverShared || (!cl->screen->alwaysShared && !ci.shared))) {
755 if (cl->screen->dontDisconnect) {
756 iterator = rfbGetClientIterator(cl->screen);
757 while ((otherCl = rfbClientIteratorNext(iterator)) != NULL) {
758 if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) {
759 rfbLog("-dontdisconnect: Not shared & existing client\n");
760 rfbLog(" refusing new client %s\n", cl->host);
762 rfbReleaseClientIterator(iterator);
766 rfbReleaseClientIterator(iterator);
768 iterator = rfbGetClientIterator(cl->screen);
769 while ((otherCl = rfbClientIteratorNext(iterator)) != NULL) {
770 if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) {
771 rfbLog("Not shared - closing connection to client %s\n",
773 rfbCloseClient(otherCl);
776 rfbReleaseClientIterator(iterator);
781 /* The values come in based on the scaled screen, we need to convert them to
782 * values based on the man screen's coordinate system
784 static rfbBool rectSwapIfLEAndClip(uint16_t* x,uint16_t* y,uint16_t* w,uint16_t* h,
787 int x1=Swap16IfLE(*x);
788 int y1=Swap16IfLE(*y);
789 int w1=Swap16IfLE(*w);
790 int h1=Swap16IfLE(*h);
792 rfbScaledCorrection(cl->scaledScreen, cl->screen, &x1, &y1, &w1, &h1, "rectSwapIfLEAndClip");
798 if(*w>cl->screen->width-*x)
799 *w=cl->screen->width-*x;
800 /* possible underflow */
801 if(*w>cl->screen->width-*x)
803 if(*h>cl->screen->height-*y)
804 *h=cl->screen->height-*y;
805 if(*h>cl->screen->height-*y)
812 * Send keyboard state (PointerPos pseudo-encoding).
816 rfbSendKeyboardLedState(rfbClientPtr cl)
818 rfbFramebufferUpdateRectHeader rect;
820 if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
821 if (!rfbSendUpdateBuf(cl))
825 rect.encoding = Swap32IfLE(rfbEncodingKeyboardLedState);
826 rect.r.x = Swap16IfLE(cl->lastKeyboardLedState);
831 memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
832 sz_rfbFramebufferUpdateRectHeader);
833 cl->ublen += sz_rfbFramebufferUpdateRectHeader;
835 rfbStatRecordEncodingSent(cl, rfbEncodingKeyboardLedState, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader);
837 if (!rfbSendUpdateBuf(cl))
844 #define rfbSetBit(buffer, position) (buffer[(position & 255) / 8] |= (1 << (position % 8)))
847 * Send rfbEncodingSupportedMessages.
851 rfbSendSupportedMessages(rfbClientPtr cl)
853 rfbFramebufferUpdateRectHeader rect;
854 rfbSupportedMessages msgs;
856 if (cl->ublen + sz_rfbFramebufferUpdateRectHeader
857 + sz_rfbSupportedMessages > UPDATE_BUF_SIZE) {
858 if (!rfbSendUpdateBuf(cl))
862 rect.encoding = Swap32IfLE(rfbEncodingSupportedMessages);
865 rect.r.w = Swap16IfLE(sz_rfbSupportedMessages);
868 memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
869 sz_rfbFramebufferUpdateRectHeader);
870 cl->ublen += sz_rfbFramebufferUpdateRectHeader;
872 memset((char *)&msgs, 0, sz_rfbSupportedMessages);
873 rfbSetBit(msgs.client2server, rfbSetPixelFormat);
874 rfbSetBit(msgs.client2server, rfbFixColourMapEntries);
875 rfbSetBit(msgs.client2server, rfbSetEncodings);
876 rfbSetBit(msgs.client2server, rfbFramebufferUpdateRequest);
877 rfbSetBit(msgs.client2server, rfbKeyEvent);
878 rfbSetBit(msgs.client2server, rfbPointerEvent);
879 rfbSetBit(msgs.client2server, rfbClientCutText);
880 rfbSetBit(msgs.client2server, rfbFileTransfer);
881 rfbSetBit(msgs.client2server, rfbSetScale);
882 /*rfbSetBit(msgs.client2server, rfbSetServerInput); */
883 /*rfbSetBit(msgs.client2server, rfbSetSW); */
884 /*rfbSetBit(msgs.client2server, rfbTextChat); */
885 /*rfbSetBit(msgs.client2server, rfbKeyFrameRequest); */
886 rfbSetBit(msgs.client2server, rfbPalmVNCSetScaleFactor);
888 rfbSetBit(msgs.server2client, rfbFramebufferUpdate);
889 rfbSetBit(msgs.server2client, rfbSetColourMapEntries);
890 rfbSetBit(msgs.server2client, rfbBell);
891 rfbSetBit(msgs.server2client, rfbServerCutText);
892 rfbSetBit(msgs.server2client, rfbResizeFrameBuffer);
893 /*rfbSetBit(msgs.server2client, rfbKeyFrameUpdate); */
894 rfbSetBit(msgs.server2client, rfbPalmVNCReSizeFrameBuffer);
896 memcpy(&cl->updateBuf[cl->ublen], (char *)&msgs, sz_rfbSupportedMessages);
897 cl->ublen += sz_rfbSupportedMessages;
899 rfbStatRecordEncodingSent(cl, rfbEncodingSupportedMessages,
900 sz_rfbFramebufferUpdateRectHeader+sz_rfbSupportedMessages,
901 sz_rfbFramebufferUpdateRectHeader+sz_rfbSupportedMessages);
902 if (!rfbSendUpdateBuf(cl))
911 * Send rfbEncodingSupportedEncodings.
915 rfbSendSupportedEncodings(rfbClientPtr cl)
917 rfbFramebufferUpdateRectHeader rect;
918 static uint32_t supported[] = {
924 #ifdef LIBVNCSERVER_HAVE_LIBZ
929 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
935 rfbEncodingRichCursor,
936 rfbEncodingPointerPos,
938 rfbEncodingNewFBSize,
939 rfbEncodingKeyboardLedState,
940 rfbEncodingSupportedMessages,
941 rfbEncodingSupportedEncodings,
942 rfbEncodingServerIdentity,
944 uint32_t nEncodings = sizeof(supported) / sizeof(supported[0]), i;
946 /* think rfbSetEncodingsMsg */
948 if (cl->ublen + sz_rfbFramebufferUpdateRectHeader
949 + (nEncodings * sizeof(uint32_t)) > UPDATE_BUF_SIZE) {
950 if (!rfbSendUpdateBuf(cl))
954 rect.encoding = Swap32IfLE(rfbEncodingSupportedEncodings);
957 rect.r.w = Swap16IfLE(nEncodings * sizeof(uint32_t));
958 rect.r.h = Swap16IfLE(nEncodings);
960 memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
961 sz_rfbFramebufferUpdateRectHeader);
962 cl->ublen += sz_rfbFramebufferUpdateRectHeader;
964 for (i = 0; i < nEncodings; i++) {
965 uint32_t encoding = Swap32IfLE(supported[i]);
966 memcpy(&cl->updateBuf[cl->ublen], (char *)&encoding, sizeof(encoding));
967 cl->ublen += sizeof(encoding);
970 rfbStatRecordEncodingSent(cl, rfbEncodingSupportedEncodings,
971 sz_rfbFramebufferUpdateRectHeader+(nEncodings * sizeof(uint32_t)),
972 sz_rfbFramebufferUpdateRectHeader+(nEncodings * sizeof(uint32_t)));
974 if (!rfbSendUpdateBuf(cl))
982 rfbSetServerVersionIdentity(rfbScreenInfoPtr screen, char *fmt, ...)
988 vsnprintf(buffer, sizeof(buffer)-1, fmt, ap);
991 if (screen->versionString!=NULL) free(screen->versionString);
992 screen->versionString = strdup(buffer);
996 * Send rfbEncodingServerIdentity.
1000 rfbSendServerIdentity(rfbClientPtr cl)
1002 rfbFramebufferUpdateRectHeader rect;
1005 /* tack on our library version */
1006 snprintf(buffer,sizeof(buffer)-1, "%s (%s)",
1007 (cl->screen->versionString==NULL ? "unknown" : cl->screen->versionString),
1008 LIBVNCSERVER_PACKAGE_STRING);
1010 if (cl->ublen + sz_rfbFramebufferUpdateRectHeader
1011 + (strlen(buffer)+1) > UPDATE_BUF_SIZE) {
1012 if (!rfbSendUpdateBuf(cl))
1016 rect.encoding = Swap32IfLE(rfbEncodingServerIdentity);
1019 rect.r.w = Swap16IfLE(strlen(buffer)+1);
1022 memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
1023 sz_rfbFramebufferUpdateRectHeader);
1024 cl->ublen += sz_rfbFramebufferUpdateRectHeader;
1026 memcpy(&cl->updateBuf[cl->ublen], buffer, strlen(buffer)+1);
1027 cl->ublen += strlen(buffer)+1;
1029 rfbStatRecordEncodingSent(cl, rfbEncodingServerIdentity,
1030 sz_rfbFramebufferUpdateRectHeader+strlen(buffer)+1,
1031 sz_rfbFramebufferUpdateRectHeader+strlen(buffer)+1);
1034 if (!rfbSendUpdateBuf(cl))
1040 rfbBool rfbSendTextChatMessage(rfbClientPtr cl, uint32_t length, char *buffer)
1045 memset((char *)&tc, 0, sizeof(tc));
1046 tc.type = rfbTextChat;
1047 tc.length = Swap32IfLE(length);
1050 case rfbTextChatOpen:
1051 case rfbTextChatClose:
1052 case rfbTextChatFinished:
1057 if (bytesToSend>rfbTextMaxSize)
1058 bytesToSend=rfbTextMaxSize;
1061 if (cl->ublen + sz_rfbTextChatMsg + bytesToSend > UPDATE_BUF_SIZE) {
1062 if (!rfbSendUpdateBuf(cl))
1066 memcpy(&cl->updateBuf[cl->ublen], (char *)&tc, sz_rfbTextChatMsg);
1067 cl->ublen += sz_rfbTextChatMsg;
1068 if (bytesToSend>0) {
1069 memcpy(&cl->updateBuf[cl->ublen], buffer, bytesToSend);
1070 cl->ublen += bytesToSend;
1072 rfbStatRecordMessageSent(cl, rfbTextChat, sz_rfbTextChatMsg+bytesToSend, sz_rfbTextChatMsg+bytesToSend);
1074 if (!rfbSendUpdateBuf(cl))
1080 #define FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN(msg, cl, ret) \
1081 if ((cl->screen->getFileTransferPermission != NULL \
1082 && cl->screen->getFileTransferPermission(cl) != TRUE) \
1083 || cl->screen->permitFileTransfer != TRUE) { \
1084 rfbLog("%sUltra File Transfer is disabled, dropping client: %s\n", msg, cl->host); \
1085 rfbCloseClient(cl); \
1091 rfbBool rfbSendFileTransferMessage(rfbClientPtr cl, uint8_t contentType, uint8_t contentParam, uint32_t size, uint32_t length, char *buffer)
1093 rfbFileTransferMsg ft;
1094 ft.type = rfbFileTransfer;
1095 ft.contentType = contentType;
1096 ft.contentParam = contentParam;
1097 ft.pad = 0; /* UltraVNC did not Swap16LE(ft.contentParam) (Looks like it might be BigEndian) */
1098 ft.size = Swap32IfLE(size);
1099 ft.length = Swap32IfLE(length);
1101 FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE);
1103 rfbLog("rfbSendFileTransferMessage( %dtype, %dparam, %dsize, %dlen, %p)\n", contentType, contentParam, size, length, buffer);
1105 if (rfbWriteExact(cl, (char *)&ft, sz_rfbFileTransferMsg) < 0) {
1106 rfbLogPerror("rfbSendFileTransferMessage: write");
1113 if (rfbWriteExact(cl, buffer, length) < 0) {
1114 rfbLogPerror("rfbSendFileTransferMessage: write");
1120 rfbStatRecordMessageSent(cl, rfbFileTransfer, sz_rfbFileTransferMsg+length, sz_rfbFileTransferMsg+length);
1127 * UltraVNC uses Windows Structures
1129 #define MAX_PATH 260
1132 uint32_t dwLowDateTime;
1133 uint32_t dwHighDateTime;
1137 uint32_t dwFileAttributes;
1138 RFB_FILETIME ftCreationTime;
1139 RFB_FILETIME ftLastAccessTime;
1140 RFB_FILETIME ftLastWriteTime;
1141 uint32_t nFileSizeHigh;
1142 uint32_t nFileSizeLow;
1143 uint32_t dwReserved0;
1144 uint32_t dwReserved1;
1145 uint8_t cFileName[ MAX_PATH ];
1146 uint8_t cAlternateFileName[ 14 ];
1149 #define RFB_FILE_ATTRIBUTE_READONLY 0x1
1150 #define RFB_FILE_ATTRIBUTE_HIDDEN 0x2
1151 #define RFB_FILE_ATTRIBUTE_SYSTEM 0x4
1152 #define RFB_FILE_ATTRIBUTE_DIRECTORY 0x10
1153 #define RFB_FILE_ATTRIBUTE_ARCHIVE 0x20
1154 #define RFB_FILE_ATTRIBUTE_NORMAL 0x80
1155 #define RFB_FILE_ATTRIBUTE_TEMPORARY 0x100
1156 #define RFB_FILE_ATTRIBUTE_COMPRESSED 0x800
1158 rfbBool rfbFilenameTranslate2UNIX(rfbClientPtr cl, char *path, char *unixPath)
1163 FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE);
1166 if (path[0]=='C' && path[1]==':')
1167 strcpy(unixPath, &path[2]);
1170 home = getenv("HOME");
1173 strcpy(unixPath, home);
1174 strcat(unixPath,"/");
1175 strcat(unixPath, path);
1178 strcpy(unixPath, path);
1180 for (x=0;x<strlen(unixPath);x++)
1181 if (unixPath[x]=='\\') unixPath[x]='/';
1185 rfbBool rfbFilenameTranslate2DOS(rfbClientPtr cl, char *unixPath, char *path)
1189 FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE);
1191 sprintf(path,"C:%s", unixPath);
1192 for (x=2;x<strlen(path);x++)
1193 if (path[x]=='/') path[x]='\\';
1197 rfbBool rfbSendDirContent(rfbClientPtr cl, int length, char *buffer)
1199 char retfilename[MAX_PATH];
1200 char path[MAX_PATH];
1201 struct stat statbuf;
1202 RFB_FIND_DATA win32filename;
1203 int nOptLen = 0, retval=0;
1205 struct dirent *direntp=NULL;
1207 FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE);
1209 /* Client thinks we are Winblows */
1210 rfbFilenameTranslate2UNIX(cl, buffer, path);
1212 if (DB) rfbLog("rfbProcessFileTransfer() rfbDirContentRequest: rfbRDirContent: \"%s\"->\"%s\"\n",buffer, path);
1216 return rfbSendFileTransferMessage(cl, rfbDirPacket, rfbADirectory, 0, 0, NULL);
1217 /* send back the path name (necessary for links) */
1218 if (rfbSendFileTransferMessage(cl, rfbDirPacket, rfbADirectory, 0, length, buffer)==FALSE) return FALSE;
1219 for (direntp=readdir(dirp); direntp!=NULL; direntp=readdir(dirp))
1222 snprintf(retfilename,sizeof(retfilename),"%s/%s", path, direntp->d_name);
1223 retval = stat(retfilename, &statbuf);
1227 memset((char *)&win32filename, 0, sizeof(win32filename));
1228 win32filename.dwFileAttributes = Swap32IfBE(RFB_FILE_ATTRIBUTE_NORMAL);
1229 if (S_ISDIR(statbuf.st_mode))
1230 win32filename.dwFileAttributes = Swap32IfBE(RFB_FILE_ATTRIBUTE_DIRECTORY);
1231 win32filename.ftCreationTime.dwLowDateTime = Swap32IfBE(statbuf.st_ctime); /* Intel Order */
1232 win32filename.ftCreationTime.dwHighDateTime = 0;
1233 win32filename.ftLastAccessTime.dwLowDateTime = Swap32IfBE(statbuf.st_atime); /* Intel Order */
1234 win32filename.ftLastAccessTime.dwHighDateTime = 0;
1235 win32filename.ftLastWriteTime.dwLowDateTime = Swap32IfBE(statbuf.st_mtime); /* Intel Order */
1236 win32filename.ftLastWriteTime.dwHighDateTime = 0;
1237 win32filename.nFileSizeLow = Swap32IfBE(statbuf.st_size); /* Intel Order */
1238 win32filename.nFileSizeHigh = 0;
1239 win32filename.dwReserved0 = 0;
1240 win32filename.dwReserved1 = 0;
1242 /* If this had the full path, we would need to translate to DOS format ("C:\") */
1243 /* rfbFilenameTranslate2DOS(cl, retfilename, win32filename.cFileName); */
1244 strcpy((char *)win32filename.cFileName, direntp->d_name);
1246 /* Do not show hidden files (but show how to move up the tree) */
1247 if ((strcmp(direntp->d_name, "..")==0) || (direntp->d_name[0]!='.'))
1249 nOptLen = sizeof(RFB_FIND_DATA) - MAX_PATH - 14 + strlen((char *)win32filename.cFileName);
1251 rfbLog("rfbProcessFileTransfer() rfbDirContentRequest: rfbRDirContent: Sending \"%s\"\n", (char *)win32filename.cFileName);
1253 if (rfbSendFileTransferMessage(cl, rfbDirPacket, rfbADirectory, 0, nOptLen, (char *)&win32filename)==FALSE) return FALSE;
1258 /* End of the transfer */
1259 return rfbSendFileTransferMessage(cl, rfbDirPacket, 0, 0, 0, NULL);
1263 char *rfbProcessFileTransferReadBuffer(rfbClientPtr cl, uint32_t length)
1268 FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, NULL);
1270 rfbLog("rfbProcessFileTransferReadBuffer(%dlen)\n", length);
1273 buffer=malloc(length+1);
1275 if ((n = rfbReadExact(cl, (char *)buffer, length)) <= 0) {
1277 rfbLogPerror("rfbProcessFileTransferReadBuffer: read");
1279 /* NOTE: don't forget to free(buffer) if you return early! */
1280 if (buffer!=NULL) free(buffer);
1283 /* Null Terminate */
1291 rfbBool rfbSendFileTransferChunk(rfbClientPtr cl)
1293 /* Allocate buffer for compression */
1294 unsigned char readBuf[sz_rfbBlockSize];
1300 #ifdef LIBVNCSERVER_HAVE_LIBZ
1301 unsigned char compBuf[sz_rfbBlockSize + 1024];
1302 unsigned long nMaxCompSize = sizeof(compBuf);
1307 * Don't close the client if we get into this one because
1308 * it is called from many places to service file transfers.
1309 * Note that permitFileTransfer is checked first.
1311 if (cl->screen->permitFileTransfer != TRUE ||
1312 (cl->screen->getFileTransferPermission != NULL
1313 && cl->screen->getFileTransferPermission(cl) != TRUE)) {
1317 /* If not sending, or no file open... Return as if we sent something! */
1318 if ((cl->fileTransfer.fd!=-1) && (cl->fileTransfer.sending==1))
1321 FD_SET(cl->sock, &wfds);
1323 /* return immediately */
1326 n = select(cl->sock + 1, NULL, &wfds, NULL, &tv);
1329 rfbLog("rfbSendFileTransferChunk() select failed: %s\n", strerror(errno));
1331 /* We have space on the transmit queue */
1334 bytesRead = read(cl->fileTransfer.fd, readBuf, sz_rfbBlockSize);
1335 switch (bytesRead) {
1338 rfbLog("rfbSendFileTransferChunk(): End-Of-File Encountered\n");
1340 retval = rfbSendFileTransferMessage(cl, rfbEndOfFile, 0, 0, 0, NULL);
1341 close(cl->fileTransfer.fd);
1342 cl->fileTransfer.fd = -1;
1343 cl->fileTransfer.sending = 0;
1344 cl->fileTransfer.receiving = 0;
1347 /* TODO : send an error msg to the client... */
1348 rfbLog("rfbSendFileTransferChunk(): %s\n",strerror(errno));
1349 retval = rfbSendFileTransferMessage(cl, rfbAbortFileTransfer, 0, 0, 0, NULL);
1350 close(cl->fileTransfer.fd);
1351 cl->fileTransfer.fd = -1;
1352 cl->fileTransfer.sending = 0;
1353 cl->fileTransfer.receiving = 0;
1357 rfbLog("rfbSendFileTransferChunk(): Read %d bytes\n", bytesRead);
1359 if (!cl->fileTransfer.compressionEnabled)
1360 return rfbSendFileTransferMessage(cl, rfbFilePacket, 0, 0, bytesRead, (char *)readBuf);
1363 #ifdef LIBVNCSERVER_HAVE_LIBZ
1364 nRetC = compress(compBuf, &nMaxCompSize, readBuf, bytesRead);
1366 rfbLog("Compressed the packet from %d -> %d bytes\n", nMaxCompSize, bytesRead);
1369 if ((nRetC==0) && (nMaxCompSize<bytesRead))
1370 return rfbSendFileTransferMessage(cl, rfbFilePacket, 0, 1, nMaxCompSize, (char *)compBuf);
1372 return rfbSendFileTransferMessage(cl, rfbFilePacket, 0, 0, bytesRead, (char *)readBuf);
1374 /* We do not support compression of the data stream */
1375 return rfbSendFileTransferMessage(cl, rfbFilePacket, 0, 0, bytesRead, (char *)readBuf);
1384 rfbBool rfbProcessFileTransfer(rfbClientPtr cl, uint8_t contentType, uint8_t contentParam, uint32_t size, uint32_t length)
1386 char *buffer=NULL, *p=NULL;
1388 char filename1[MAX_PATH];
1389 char filename2[MAX_PATH];
1390 char szFileTime[MAX_PATH];
1391 struct stat statbuf;
1392 uint32_t sizeHtmp=0;
1395 #ifdef LIBVNCSERVER_HAVE_LIBZ
1396 unsigned char compBuff[sz_rfbBlockSize];
1397 unsigned long nRawBytes = sz_rfbBlockSize;
1401 FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE);
1404 rfbLog("rfbProcessFileTransfer(%dtype, %dparam, %dsize, %dlen)\n", contentType, contentParam, size, length);
1407 switch (contentType) {
1408 case rfbDirContentRequest:
1409 switch (contentParam) {
1410 case rfbRDrivesList: /* Client requests the List of Local Drives */
1412 rfbLog("rfbProcessFileTransfer() rfbDirContentRequest: rfbRDrivesList:\n");
1414 /* Format when filled : "C:\<NULL>D:\<NULL>....Z:\<NULL><NULL>
1416 * We replace the "\" char following the drive letter and ":"
1417 * with a char corresponding to the type of drive
1418 * We obtain something like "C:l<NULL>D:c<NULL>....Z:n\<NULL><NULL>"
1420 * DRIVE_FIXED = 'l' (local?)
1421 * DRIVE_REMOVABLE = 'f' (floppy?)
1423 * DRIVE_REMOTE = 'n'
1426 /* in unix, there are no 'drives' (We could list mount points though)
1427 * We fake the root as a "C:" for the Winblows users
1434 retval = rfbSendFileTransferMessage(cl, rfbDirPacket, rfbADrivesList, 0, 5, filename2);
1435 if (buffer!=NULL) free(buffer);
1438 case rfbRDirContent: /* Client requests the content of a directory */
1440 rfbLog("rfbProcessFileTransfer() rfbDirContentRequest: rfbRDirContent\n");
1442 if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
1443 retval = rfbSendDirContent(cl, length, buffer);
1444 if (buffer!=NULL) free(buffer);
1450 rfbLog("rfbProcessFileTransfer() rfbDirPacket\n");
1452 case rfbFileAcceptHeader:
1453 rfbLog("rfbProcessFileTransfer() rfbFileAcceptHeader\n");
1455 case rfbCommandReturn:
1456 rfbLog("rfbProcessFileTransfer() rfbCommandReturn\n");
1458 case rfbFileChecksums:
1459 /* Destination file already exists - the viewer sends the checksums */
1460 rfbLog("rfbProcessFileTransfer() rfbFileChecksums\n");
1462 case rfbFileTransferAccess:
1463 rfbLog("rfbProcessFileTransfer() rfbFileTransferAccess\n");
1467 * sending from the server to the viewer
1470 case rfbFileTransferRequest:
1472 rfbLog("rfbProcessFileTransfer() rfbFileTransferRequest:\n");
1474 /* add some space to the end of the buffer as we will be adding a timespec to it */
1475 if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
1476 /* The client requests a File */
1477 rfbFilenameTranslate2UNIX(cl, buffer, filename1);
1478 cl->fileTransfer.fd=open(filename1, O_RDONLY, 0744);
1482 if (DB) rfbLog("rfbProcessFileTransfer() rfbFileTransferRequest(\"%s\"->\"%s\") Open: %s fd=%d\n", buffer, filename1, (cl->fileTransfer.fd==-1?"Failed":"Success"), cl->fileTransfer.fd);
1484 if (cl->fileTransfer.fd!=-1) {
1485 if (fstat(cl->fileTransfer.fd, &statbuf)!=0) {
1486 close(cl->fileTransfer.fd);
1487 cl->fileTransfer.fd=-1;
1491 /* Add the File Time Stamp to the filename */
1492 strftime(timespec, sizeof(timespec), "%m/%d/%Y %H:%M",gmtime(&statbuf.st_ctime));
1493 buffer=realloc(buffer, length + strlen(timespec) + 2); /* comma, and Null term */
1495 rfbLog("rfbProcessFileTransfer() rfbFileTransferRequest: Failed to malloc %d bytes\n", length + strlen(timespec) + 2);
1499 strcat(buffer, timespec);
1500 length = strlen(buffer);
1501 if (DB) rfbLog("rfbProcessFileTransfer() buffer is now: \"%s\"\n", buffer);
1505 /* The viewer supports compression if size==1 */
1506 cl->fileTransfer.compressionEnabled = (size==1);
1509 rfbLog("rfbProcessFileTransfer() rfbFileTransferRequest(\"%s\"->\"%s\")%s\n", buffer, filename1, (size==1?" <Compression Enabled>":""));
1512 /* File Size in bytes, 0xFFFFFFFF (-1) means error */
1513 retval = rfbSendFileTransferMessage(cl, rfbFileHeader, 0, (cl->fileTransfer.fd==-1 ? -1 : statbuf.st_size), length, buffer);
1515 if (cl->fileTransfer.fd==-1)
1517 if (buffer!=NULL) free(buffer);
1520 /* setup filetransfer stuff */
1521 cl->fileTransfer.fileSize = statbuf.st_size;
1522 cl->fileTransfer.numPackets = statbuf.st_size / sz_rfbBlockSize;
1523 cl->fileTransfer.receiving = 0;
1524 cl->fileTransfer.sending = 0; /* set when we receive a rfbFileHeader: */
1526 /* TODO: finish 64-bit file size support */
1528 if (rfbWriteExact(cl, (char *)&sizeHtmp, 4) < 0) {
1529 rfbLogPerror("rfbProcessFileTransfer: write");
1531 if (buffer!=NULL) free(buffer);
1537 /* Destination file (viewer side) is ready for reception (size > 0) or not (size = -1) */
1539 rfbLog("rfbProcessFileTransfer() rfbFileHeader (error, aborting)\n");
1540 close(cl->fileTransfer.fd);
1541 cl->fileTransfer.fd=-1;
1546 rfbLog("rfbProcessFileTransfer() rfbFileHeader (%d bytes of a file)\n", size);
1549 /* Starts the transfer! */
1550 cl->fileTransfer.sending=1;
1551 return rfbSendFileTransferChunk(cl);
1556 * sending from the viewer to the server
1559 case rfbFileTransferOffer:
1560 /* client is sending a file to us */
1561 /* buffer contains full path name (plus FileTime) */
1562 /* size contains size of the file */
1564 rfbLog("rfbProcessFileTransfer() rfbFileTransferOffer:\n");
1566 if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
1568 /* Parse the FileTime */
1569 p = strrchr(buffer, ',');
1572 strcpy(szFileTime, p+1);
1578 /* Need to read in sizeHtmp */
1579 if ((n = rfbReadExact(cl, (char *)&sizeHtmp, 4)) <= 0) {
1581 rfbLogPerror("rfbProcessFileTransfer: read sizeHtmp");
1583 /* NOTE: don't forget to free(buffer) if you return early! */
1584 if (buffer!=NULL) free(buffer);
1587 sizeHtmp = Swap32IfLE(sizeHtmp);
1589 rfbFilenameTranslate2UNIX(cl, buffer, filename1);
1591 /* If the file exists... We can send a rfbFileChecksums back to the client before we send an rfbFileAcceptHeader */
1592 /* TODO: Delta Transfer */
1594 cl->fileTransfer.fd=open(filename1, O_CREAT|O_WRONLY|O_TRUNC, 0744);
1595 if (DB) rfbLog("rfbProcessFileTransfer() rfbFileTransferOffer(\"%s\"->\"%s\") %s %s fd=%d\n", buffer, filename1, (cl->fileTransfer.fd==-1?"Failed":"Success"), (cl->fileTransfer.fd==-1?strerror(errno):""), cl->fileTransfer.fd);
1599 /* File Size in bytes, 0xFFFFFFFF (-1) means error */
1600 retval = rfbSendFileTransferMessage(cl, rfbFileAcceptHeader, 0, (cl->fileTransfer.fd==-1 ? -1 : 0), length, buffer);
1601 if (cl->fileTransfer.fd==-1) {
1606 /* setup filetransfer stuff */
1607 cl->fileTransfer.fileSize = size;
1608 cl->fileTransfer.numPackets = size / sz_rfbBlockSize;
1609 cl->fileTransfer.receiving = 1;
1610 cl->fileTransfer.sending = 0;
1615 rfbLog("rfbProcessFileTransfer() rfbFilePacket:\n");
1617 if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
1618 if (cl->fileTransfer.fd!=-1) {
1619 /* buffer contains the contents of the file */
1621 retval=write(cl->fileTransfer.fd, buffer, length);
1624 #ifdef LIBVNCSERVER_HAVE_LIBZ
1625 /* compressed packet */
1626 nRet = uncompress(compBuff,&nRawBytes,(const unsigned char*)buffer, length);
1627 retval=write(cl->fileTransfer.fd, compBuff, nRawBytes);
1629 /* Write the file out as received... */
1630 retval=write(cl->fileTransfer.fd, buffer, length);
1635 close(cl->fileTransfer.fd);
1636 cl->fileTransfer.fd=-1;
1637 cl->fileTransfer.sending = 0;
1638 cl->fileTransfer.receiving = 0;
1644 if (DB) rfbLog("rfbProcessFileTransfer() rfbEndOfFile\n");
1647 if (cl->fileTransfer.fd!=-1)
1648 close(cl->fileTransfer.fd);
1649 cl->fileTransfer.fd=-1;
1650 cl->fileTransfer.sending = 0;
1651 cl->fileTransfer.receiving = 0;
1654 case rfbAbortFileTransfer:
1655 if (DB) rfbLog("rfbProcessFileTransfer() rfbAbortFileTransfer\n");
1658 if (cl->fileTransfer.fd!=-1)
1660 close(cl->fileTransfer.fd);
1661 cl->fileTransfer.fd=-1;
1662 cl->fileTransfer.sending = 0;
1663 cl->fileTransfer.receiving = 0;
1667 /* We use this message for FileTransfer rights (<=RC18 versions)
1668 * The client asks for FileTransfer permission
1670 if (contentParam == 0)
1672 rfbLog("rfbProcessFileTransfer() File Transfer Permission DENIED! (Client Version <=RC18)\n");
1673 /* Old method for FileTransfer handshake perimssion (<=RC18) (Deny it)*/
1674 return rfbSendFileTransferMessage(cl, rfbAbortFileTransfer, 0, -1, 0, "");
1676 /* New method is allowed */
1677 if (cl->screen->getFileTransferPermission!=NULL)
1679 if (cl->screen->getFileTransferPermission(cl)==TRUE)
1681 rfbLog("rfbProcessFileTransfer() File Transfer Permission Granted!\n");
1682 return rfbSendFileTransferMessage(cl, rfbFileTransferAccess, 0, 1 , 0, ""); /* Permit */
1686 rfbLog("rfbProcessFileTransfer() File Transfer Permission DENIED!\n");
1687 return rfbSendFileTransferMessage(cl, rfbFileTransferAccess, 0, -1 , 0, ""); /* Deny */
1692 if (cl->screen->permitFileTransfer)
1694 rfbLog("rfbProcessFileTransfer() File Transfer Permission Granted!\n");
1695 return rfbSendFileTransferMessage(cl, rfbFileTransferAccess, 0, 1 , 0, ""); /* Permit */
1699 rfbLog("rfbProcessFileTransfer() File Transfer Permission DENIED by default!\n");
1700 return rfbSendFileTransferMessage(cl, rfbFileTransferAccess, 0, -1 , 0, ""); /* DEFAULT: DENY (for security) */
1710 rfbLog("rfbProcessFileTransfer() rfbCommand:\n");
1712 if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
1713 switch (contentParam) {
1714 case rfbCDirCreate: /* Client requests the creation of a directory */
1715 rfbFilenameTranslate2UNIX(cl, buffer, filename1);
1716 retval = mkdir(filename1, 0755);
1717 if (DB) rfbLog("rfbProcessFileTransfer() rfbCommand: rfbCDirCreate(\"%s\"->\"%s\") %s\n", buffer, filename1, (retval==-1?"Failed":"Success"));
1720 retval = rfbSendFileTransferMessage(cl, rfbCommandReturn, rfbADirCreate, retval, length, buffer);
1721 if (buffer!=NULL) free(buffer);
1723 case rfbCFileDelete: /* Client requests the deletion of a file */
1724 rfbFilenameTranslate2UNIX(cl, buffer, filename1);
1725 if (stat(filename1,&statbuf)==0)
1727 if (S_ISDIR(statbuf.st_mode))
1728 retval = rmdir(filename1);
1730 retval = unlink(filename1);
1733 retval = rfbSendFileTransferMessage(cl, rfbCommandReturn, rfbAFileDelete, retval, length, buffer);
1734 if (buffer!=NULL) free(buffer);
1736 case rfbCFileRename: /* Client requests the Renaming of a file/directory */
1737 p = strrchr(buffer, '*');
1740 /* Split into 2 filenames ('*' is a seperator) */
1742 rfbFilenameTranslate2UNIX(cl, buffer, filename1);
1743 rfbFilenameTranslate2UNIX(cl, p+1, filename2);
1744 retval = rename(filename1,filename2);
1745 if (DB) rfbLog("rfbProcessFileTransfer() rfbCommand: rfbCFileRename(\"%s\"->\"%s\" -->> \"%s\"->\"%s\") %s\n", buffer, filename1, p+1, filename2, (retval==-1?"Failed":"Success"));
1748 /* Restore the buffer so the reply is good */
1750 retval = rfbSendFileTransferMessage(cl, rfbCommandReturn, rfbAFileRename, retval, length, buffer);
1751 if (buffer!=NULL) free(buffer);
1760 /* NOTE: don't forget to free(buffer) if you return early! */
1761 if (buffer!=NULL) free(buffer);
1766 * rfbProcessClientNormalMessage is called when the client has sent a normal
1771 rfbProcessClientNormalMessage(rfbClientPtr cl)
1774 rfbClientToServerMsg msg;
1778 uint32_t lastPreferredEncoding = -1;
1782 if ((n = rfbReadExact(cl, (char *)&msg, 1)) <= 0) {
1784 rfbLogPerror("rfbProcessClientNormalMessage: read");
1791 case rfbSetPixelFormat:
1793 if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
1794 sz_rfbSetPixelFormatMsg - 1)) <= 0) {
1796 rfbLogPerror("rfbProcessClientNormalMessage: read");
1801 cl->format.bitsPerPixel = msg.spf.format.bitsPerPixel;
1802 cl->format.depth = msg.spf.format.depth;
1803 cl->format.bigEndian = (msg.spf.format.bigEndian ? TRUE : FALSE);
1804 cl->format.trueColour = (msg.spf.format.trueColour ? TRUE : FALSE);
1805 cl->format.redMax = Swap16IfLE(msg.spf.format.redMax);
1806 cl->format.greenMax = Swap16IfLE(msg.spf.format.greenMax);
1807 cl->format.blueMax = Swap16IfLE(msg.spf.format.blueMax);
1808 cl->format.redShift = msg.spf.format.redShift;
1809 cl->format.greenShift = msg.spf.format.greenShift;
1810 cl->format.blueShift = msg.spf.format.blueShift;
1812 cl->readyForSetColourMapEntries = TRUE;
1813 cl->screen->setTranslateFunction(cl);
1815 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetPixelFormatMsg, sz_rfbSetPixelFormatMsg);
1820 case rfbFixColourMapEntries:
1821 if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
1822 sz_rfbFixColourMapEntriesMsg - 1)) <= 0) {
1824 rfbLogPerror("rfbProcessClientNormalMessage: read");
1828 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetPixelFormatMsg, sz_rfbSetPixelFormatMsg);
1829 rfbLog("rfbProcessClientNormalMessage: %s",
1830 "FixColourMapEntries unsupported\n");
1835 /* NOTE: Some clients send us a set of encodings (ie: PointerPos) designed to enable/disable features...
1836 * We may want to look into this...
1838 * case rfbEncodingXCursor:
1839 * cl->enableCursorShapeUpdates = TRUE;
1841 * Currently: cl->enableCursorShapeUpdates can *never* be turned off...
1843 case rfbSetEncodings:
1846 if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
1847 sz_rfbSetEncodingsMsg - 1)) <= 0) {
1849 rfbLogPerror("rfbProcessClientNormalMessage: read");
1854 msg.se.nEncodings = Swap16IfLE(msg.se.nEncodings);
1856 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetEncodingsMsg+(msg.se.nEncodings*4),sz_rfbSetEncodingsMsg+(msg.se.nEncodings*4));
1859 * UltraVNC Client has the ability to adapt to changing network environments
1860 * So, let's give it a change to tell us what it wants now!
1862 if (cl->preferredEncoding!=-1)
1863 lastPreferredEncoding = cl->preferredEncoding;
1865 /* Reset all flags to defaults (allows us to switch between PointerPos and Server Drawn Cursors) */
1866 cl->preferredEncoding=-1;
1867 cl->useCopyRect = FALSE;
1868 cl->useNewFBSize = FALSE;
1869 cl->cursorWasChanged = FALSE;
1870 cl->useRichCursorEncoding = FALSE;
1871 cl->enableCursorPosUpdates = FALSE;
1872 cl->enableCursorShapeUpdates = FALSE;
1873 cl->enableCursorShapeUpdates = FALSE;
1874 cl->enableLastRectEncoding = FALSE;
1875 cl->enableKeyboardLedState = FALSE;
1876 cl->enableSupportedMessages = FALSE;
1877 cl->enableSupportedEncodings = FALSE;
1878 cl->enableServerIdentity = FALSE;
1881 for (i = 0; i < msg.se.nEncodings; i++) {
1882 if ((n = rfbReadExact(cl, (char *)&enc, 4)) <= 0) {
1884 rfbLogPerror("rfbProcessClientNormalMessage: read");
1888 enc = Swap32IfLE(enc);
1892 case rfbEncodingCopyRect:
1893 cl->useCopyRect = TRUE;
1895 case rfbEncodingRaw:
1896 case rfbEncodingRRE:
1897 case rfbEncodingCoRRE:
1898 case rfbEncodingHextile:
1899 case rfbEncodingUltra:
1900 #ifdef LIBVNCSERVER_HAVE_LIBZ
1901 case rfbEncodingZlib:
1902 case rfbEncodingZRLE:
1903 case rfbEncodingZYWRLE:
1904 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
1905 case rfbEncodingTight:
1908 /* The first supported encoding is the 'preferred' encoding */
1909 if (cl->preferredEncoding == -1)
1910 cl->preferredEncoding = enc;
1914 case rfbEncodingXCursor:
1915 if(!cl->screen->dontConvertRichCursorToXCursor) {
1916 rfbLog("Enabling X-style cursor updates for client %s\n",
1918 /* if cursor was drawn, hide the cursor */
1919 if(!cl->enableCursorShapeUpdates)
1920 rfbRedrawAfterHideCursor(cl,NULL);
1922 cl->enableCursorShapeUpdates = TRUE;
1923 cl->cursorWasChanged = TRUE;
1926 case rfbEncodingRichCursor:
1927 rfbLog("Enabling full-color cursor updates for client %s\n",
1929 /* if cursor was drawn, hide the cursor */
1930 if(!cl->enableCursorShapeUpdates)
1931 rfbRedrawAfterHideCursor(cl,NULL);
1933 cl->enableCursorShapeUpdates = TRUE;
1934 cl->useRichCursorEncoding = TRUE;
1935 cl->cursorWasChanged = TRUE;
1937 case rfbEncodingPointerPos:
1938 if (!cl->enableCursorPosUpdates) {
1939 rfbLog("Enabling cursor position updates for client %s\n",
1941 cl->enableCursorPosUpdates = TRUE;
1942 cl->cursorWasMoved = TRUE;
1945 case rfbEncodingLastRect:
1946 if (!cl->enableLastRectEncoding) {
1947 rfbLog("Enabling LastRect protocol extension for client "
1949 cl->enableLastRectEncoding = TRUE;
1952 case rfbEncodingNewFBSize:
1953 if (!cl->useNewFBSize) {
1954 rfbLog("Enabling NewFBSize protocol extension for client "
1956 cl->useNewFBSize = TRUE;
1959 case rfbEncodingKeyboardLedState:
1960 if (!cl->enableKeyboardLedState) {
1961 rfbLog("Enabling KeyboardLedState protocol extension for client "
1963 cl->enableKeyboardLedState = TRUE;
1966 case rfbEncodingSupportedMessages:
1967 if (!cl->enableSupportedMessages) {
1968 rfbLog("Enabling SupportedMessages protocol extension for client "
1970 cl->enableSupportedMessages = TRUE;
1973 case rfbEncodingSupportedEncodings:
1974 if (!cl->enableSupportedEncodings) {
1975 rfbLog("Enabling SupportedEncodings protocol extension for client "
1977 cl->enableSupportedEncodings = TRUE;
1980 case rfbEncodingServerIdentity:
1981 if (!cl->enableServerIdentity) {
1982 rfbLog("Enabling ServerIdentity protocol extension for client "
1984 cl->enableServerIdentity = TRUE;
1988 #ifdef LIBVNCSERVER_HAVE_LIBZ
1989 if ( enc >= (uint32_t)rfbEncodingCompressLevel0 &&
1990 enc <= (uint32_t)rfbEncodingCompressLevel9 ) {
1991 cl->zlibCompressLevel = enc & 0x0F;
1992 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
1993 cl->tightCompressLevel = enc & 0x0F;
1994 rfbLog("Using compression level %d for client %s\n",
1995 cl->tightCompressLevel, cl->host);
1997 } else if ( enc >= (uint32_t)rfbEncodingQualityLevel0 &&
1998 enc <= (uint32_t)rfbEncodingQualityLevel9 ) {
1999 cl->tightQualityLevel = enc & 0x0F;
2000 rfbLog("Using image quality level %d for client %s\n",
2001 cl->tightQualityLevel, cl->host);
2005 rfbExtensionData* e;
2006 for(e = cl->extensions; e;) {
2007 rfbExtensionData* next = e->next;
2008 if(e->extension->enablePseudoEncoding &&
2009 e->extension->enablePseudoEncoding(cl,
2010 &e->data, (int)enc))
2011 /* ext handles this encoding */
2016 rfbBool handled = FALSE;
2017 /* if the pseudo encoding is not handled by the
2018 enabled extensions, search through all
2020 rfbProtocolExtension* e;
2022 for(e = rfbGetExtensionIterator(); e;) {
2023 int* encs = e->pseudoEncodings;
2024 while(encs && *encs!=0) {
2025 if(*encs==(int)enc) {
2027 if(!e->enablePseudoEncoding(cl, &data, (int)enc)) {
2028 rfbLog("Installed extension pretends to handle pseudo encoding 0x%x, but does not!\n",(int)enc);
2030 rfbEnableExtension(cl, e, data);
2042 rfbReleaseExtensionIterator();
2045 rfbLog("rfbProcessClientNormalMessage: "
2046 "ignoring unsupported encoding type %s\n",
2047 encodingName(enc,encBuf,sizeof(encBuf)));
2055 if (cl->preferredEncoding == -1) {
2056 if (lastPreferredEncoding==-1) {
2057 cl->preferredEncoding = rfbEncodingRaw;
2058 rfbLog("Defaulting to %s encoding for client %s\n", encodingName(cl->preferredEncoding,encBuf,sizeof(encBuf)),cl->host);
2061 cl->preferredEncoding = lastPreferredEncoding;
2062 rfbLog("Sticking with %s encoding for client %s\n", encodingName(cl->preferredEncoding,encBuf,sizeof(encBuf)),cl->host);
2067 if (lastPreferredEncoding==-1) {
2068 rfbLog("Using %s encoding for client %s\n", encodingName(cl->preferredEncoding,encBuf,sizeof(encBuf)),cl->host);
2070 rfbLog("Switching from %s to %s Encoding for client %s\n",
2071 encodingName(lastPreferredEncoding,encBuf2,sizeof(encBuf2)),
2072 encodingName(cl->preferredEncoding,encBuf,sizeof(encBuf)), cl->host);
2076 if (cl->enableCursorPosUpdates && !cl->enableCursorShapeUpdates) {
2077 rfbLog("Disabling cursor position updates for client %s\n",
2079 cl->enableCursorPosUpdates = FALSE;
2086 case rfbFramebufferUpdateRequest:
2088 sraRegionPtr tmpRegion;
2090 if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2091 sz_rfbFramebufferUpdateRequestMsg-1)) <= 0) {
2093 rfbLogPerror("rfbProcessClientNormalMessage: read");
2098 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbFramebufferUpdateRequestMsg,sz_rfbFramebufferUpdateRequestMsg);
2100 /* The values come in based on the scaled screen, we need to convert them to
2101 * values based on the main screen's coordinate system
2103 if(!rectSwapIfLEAndClip(&msg.fur.x,&msg.fur.y,&msg.fur.w,&msg.fur.h,cl))
2105 rfbLog("Warning, ignoring rfbFramebufferUpdateRequest: %dXx%dY-%dWx%dH\n",msg.fur.x, msg.fur.y, msg.fur.w, msg.fur.h);
2111 sraRgnCreateRect(msg.fur.x,
2113 msg.fur.x+msg.fur.w,
2114 msg.fur.y+msg.fur.h);
2116 LOCK(cl->updateMutex);
2117 sraRgnOr(cl->requestedRegion,tmpRegion);
2119 if (!cl->readyForSetColourMapEntries) {
2120 /* client hasn't sent a SetPixelFormat so is using server's */
2121 cl->readyForSetColourMapEntries = TRUE;
2122 if (!cl->format.trueColour) {
2123 if (!rfbSetClientColourMap(cl, 0, 0)) {
2124 sraRgnDestroy(tmpRegion);
2125 UNLOCK(cl->updateMutex);
2131 if (!msg.fur.incremental) {
2132 sraRgnOr(cl->modifiedRegion,tmpRegion);
2133 sraRgnSubtract(cl->copyRegion,tmpRegion);
2135 TSIGNAL(cl->updateCond);
2136 UNLOCK(cl->updateMutex);
2138 sraRgnDestroy(tmpRegion);
2145 if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2146 sz_rfbKeyEventMsg - 1)) <= 0) {
2148 rfbLogPerror("rfbProcessClientNormalMessage: read");
2153 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbKeyEventMsg, sz_rfbKeyEventMsg);
2156 cl->screen->kbdAddEvent(msg.ke.down, (rfbKeySym)Swap32IfLE(msg.ke.key), cl);
2162 case rfbPointerEvent:
2164 if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2165 sz_rfbPointerEventMsg - 1)) <= 0) {
2167 rfbLogPerror("rfbProcessClientNormalMessage: read");
2172 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbPointerEventMsg, sz_rfbPointerEventMsg);
2174 if (cl->screen->pointerClient && cl->screen->pointerClient != cl)
2177 if (msg.pe.buttonMask == 0)
2178 cl->screen->pointerClient = NULL;
2180 cl->screen->pointerClient = cl;
2183 if (msg.pe.buttonMask != cl->lastPtrButtons ||
2184 cl->screen->deferPtrUpdateTime == 0) {
2185 cl->screen->ptrAddEvent(msg.pe.buttonMask,
2186 ScaleX(cl->scaledScreen, cl->screen, Swap16IfLE(msg.pe.x)),
2187 ScaleY(cl->scaledScreen, cl->screen, Swap16IfLE(msg.pe.y)),
2189 cl->lastPtrButtons = msg.pe.buttonMask;
2191 cl->lastPtrX = ScaleX(cl->scaledScreen, cl->screen, Swap16IfLE(msg.pe.x));
2192 cl->lastPtrY = ScaleY(cl->scaledScreen, cl->screen, Swap16IfLE(msg.pe.y));
2193 cl->lastPtrButtons = msg.pe.buttonMask;
2199 case rfbFileTransfer:
2200 if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2201 sz_rfbFileTransferMsg - 1)) <= 0) {
2203 rfbLogPerror("rfbProcessClientNormalMessage: read");
2207 msg.ft.size = Swap32IfLE(msg.ft.size);
2208 msg.ft.length = Swap32IfLE(msg.ft.length);
2209 /* record statistics in rfbProcessFileTransfer as length is filled with garbage when it is not valid */
2210 rfbProcessFileTransfer(cl, msg.ft.contentType, msg.ft.contentParam, msg.ft.size, msg.ft.length);
2214 if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2215 sz_rfbSetSWMsg - 1)) <= 0) {
2217 rfbLogPerror("rfbProcessClientNormalMessage: read");
2221 msg.sw.x = Swap16IfLE(msg.sw.x);
2222 msg.sw.y = Swap16IfLE(msg.sw.y);
2223 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetSWMsg, sz_rfbSetSWMsg);
2224 /* msg.sw.status is not initialized in the ultraVNC viewer and contains random numbers (why???) */
2226 rfbLog("Received a rfbSetSingleWindow(%d x, %d y)\n", msg.sw.x, msg.sw.y);
2227 if (cl->screen->setSingleWindow!=NULL)
2228 cl->screen->setSingleWindow(cl, msg.sw.x, msg.sw.y);
2231 case rfbSetServerInput:
2232 if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2233 sz_rfbSetServerInputMsg - 1)) <= 0) {
2235 rfbLogPerror("rfbProcessClientNormalMessage: read");
2239 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetServerInputMsg, sz_rfbSetServerInputMsg);
2241 /* msg.sim.pad is not initialized in the ultraVNC viewer and contains random numbers (why???) */
2242 /* msg.sim.pad = Swap16IfLE(msg.sim.pad); */
2244 rfbLog("Received a rfbSetServerInput(%d status)\n", msg.sim.status);
2245 if (cl->screen->setServerInput!=NULL)
2246 cl->screen->setServerInput(cl, msg.sim.status);
2250 if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2251 sz_rfbTextChatMsg - 1)) <= 0) {
2253 rfbLogPerror("rfbProcessClientNormalMessage: read");
2258 msg.tc.pad2 = Swap16IfLE(msg.tc.pad2);
2259 msg.tc.length = Swap32IfLE(msg.tc.length);
2261 switch (msg.tc.length) {
2262 case rfbTextChatOpen:
2263 case rfbTextChatClose:
2264 case rfbTextChatFinished:
2265 /* commands do not have text following */
2266 /* Why couldn't they have used the pad byte??? */
2268 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbTextChatMsg, sz_rfbTextChatMsg);
2271 if ((msg.tc.length>0) && (msg.tc.length<rfbTextMaxSize))
2273 str = (char *)malloc(msg.tc.length);
2276 rfbLog("Unable to malloc %d bytes for a TextChat Message\n", msg.tc.length);
2280 if ((n = rfbReadExact(cl, str, msg.tc.length)) <= 0) {
2282 rfbLogPerror("rfbProcessClientNormalMessage: read");
2287 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbTextChatMsg+msg.tc.length, sz_rfbTextChatMsg+msg.tc.length);
2291 /* This should never happen */
2292 rfbLog("client sent us a Text Message that is too big %d>%d\n", msg.tc.length, rfbTextMaxSize);
2298 /* Note: length can be commands: rfbTextChatOpen, rfbTextChatClose, and rfbTextChatFinished
2299 * at which point, the str is NULL (as it is not sent)
2301 if (cl->screen->setTextChat!=NULL)
2302 cl->screen->setTextChat(cl, msg.tc.length, str);
2308 case rfbClientCutText:
2310 if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2311 sz_rfbClientCutTextMsg - 1)) <= 0) {
2313 rfbLogPerror("rfbProcessClientNormalMessage: read");
2318 msg.cct.length = Swap32IfLE(msg.cct.length);
2320 str = (char *)malloc(msg.cct.length);
2322 if ((n = rfbReadExact(cl, str, msg.cct.length)) <= 0) {
2324 rfbLogPerror("rfbProcessClientNormalMessage: read");
2329 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbClientCutTextMsg+msg.cct.length, sz_rfbClientCutTextMsg+msg.cct.length);
2331 cl->screen->setXCutText(str, msg.cct.length, cl);
2337 case rfbPalmVNCSetScaleFactor:
2339 if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2340 sz_rfbSetScaleMsg - 1)) <= 0) {
2342 rfbLogPerror("rfbProcessClientNormalMessage: read");
2346 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetScaleMsg, sz_rfbSetScaleMsg);
2347 rfbLog("rfbSetScale(%d)\n", msg.ssc.scale);
2348 rfbScalingSetup(cl,cl->screen->width/msg.ssc.scale, cl->screen->height/msg.ssc.scale);
2350 rfbSendNewScaleSize(cl);
2355 if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2356 sz_rfbSetScaleMsg - 1)) <= 0) {
2358 rfbLogPerror("rfbProcessClientNormalMessage: read");
2362 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetScaleMsg, sz_rfbSetScaleMsg);
2363 rfbLog("rfbSetScale(%d)\n", msg.ssc.scale);
2364 rfbScalingSetup(cl,cl->screen->width/msg.ssc.scale, cl->screen->height/msg.ssc.scale);
2366 rfbSendNewScaleSize(cl);
2371 rfbExtensionData *e,*next;
2373 for(e=cl->extensions; e;) {
2375 if(e->extension->handleMessage &&
2376 e->extension->handleMessage(cl, e->data, &msg))
2378 rfbStatRecordMessageRcvd(cl, msg.type, 0, 0); /* Extension should handle this */
2384 rfbLog("rfbProcessClientNormalMessage: unknown message type %d\n",
2386 rfbLog(" ... closing connection\n");
2396 * rfbSendFramebufferUpdate - send the currently pending framebuffer update to
2398 * givenUpdateRegion is not changed.
2402 rfbSendFramebufferUpdate(rfbClientPtr cl,
2403 sraRegionPtr givenUpdateRegion)
2405 sraRectangleIterator* i=NULL;
2407 int nUpdateRegionRects;
2408 rfbFramebufferUpdateMsg *fu = (rfbFramebufferUpdateMsg *)cl->updateBuf;
2409 sraRegionPtr updateRegion,updateCopyRegion,tmpRegion;
2411 rfbBool sendCursorShape = FALSE;
2412 rfbBool sendCursorPos = FALSE;
2413 rfbBool sendKeyboardLedState = FALSE;
2414 rfbBool sendSupportedMessages = FALSE;
2415 rfbBool sendSupportedEncodings = FALSE;
2416 rfbBool sendServerIdentity = FALSE;
2417 rfbBool result = TRUE;
2420 if(cl->screen->displayHook)
2421 cl->screen->displayHook(cl);
2424 * If framebuffer size was changed and the client supports NewFBSize
2425 * encoding, just send NewFBSize marker and return.
2428 if (cl->useNewFBSize && cl->newFBSizePending) {
2429 LOCK(cl->updateMutex);
2430 cl->newFBSizePending = FALSE;
2431 UNLOCK(cl->updateMutex);
2432 fu->type = rfbFramebufferUpdate;
2433 fu->nRects = Swap16IfLE(1);
2434 cl->ublen = sz_rfbFramebufferUpdateMsg;
2435 if (!rfbSendNewFBSize(cl, cl->scaledScreen->width, cl->scaledScreen->height)) {
2438 return rfbSendUpdateBuf(cl);
2442 * If this client understands cursor shape updates, cursor should be
2443 * removed from the framebuffer. Otherwise, make sure it's put up.
2446 if (cl->enableCursorShapeUpdates) {
2447 if (cl->cursorWasChanged && cl->readyForSetColourMapEntries)
2448 sendCursorShape = TRUE;
2452 * Do we plan to send cursor position update?
2455 if (cl->enableCursorPosUpdates && cl->cursorWasMoved)
2456 sendCursorPos = TRUE;
2459 * Do we plan to send a keyboard state update?
2461 if ((cl->enableKeyboardLedState) &&
2462 (cl->screen->getKeyboardLedStateHook!=NULL))
2465 x=cl->screen->getKeyboardLedStateHook(cl->screen);
2466 if (x!=cl->lastKeyboardLedState)
2468 sendKeyboardLedState = TRUE;
2469 cl->lastKeyboardLedState=x;
2474 * Do we plan to send a rfbEncodingSupportedMessages?
2476 if (cl->enableSupportedMessages)
2478 sendSupportedMessages = TRUE;
2479 /* We only send this message ONCE <per setEncodings message received>
2480 * (We disable it here)
2482 cl->enableSupportedMessages = FALSE;
2485 * Do we plan to send a rfbEncodingSupportedEncodings?
2487 if (cl->enableSupportedEncodings)
2489 sendSupportedEncodings = TRUE;
2490 /* We only send this message ONCE <per setEncodings message received>
2491 * (We disable it here)
2493 cl->enableSupportedEncodings = FALSE;
2496 * Do we plan to send a rfbEncodingServerIdentity?
2498 if (cl->enableServerIdentity)
2500 sendServerIdentity = TRUE;
2501 /* We only send this message ONCE <per setEncodings message received>
2502 * (We disable it here)
2504 cl->enableServerIdentity = FALSE;
2507 LOCK(cl->updateMutex);
2510 * The modifiedRegion may overlap the destination copyRegion. We remove
2511 * any overlapping bits from the copyRegion (since they'd only be
2512 * overwritten anyway).
2515 sraRgnSubtract(cl->copyRegion,cl->modifiedRegion);
2518 * The client is interested in the region requestedRegion. The region
2519 * which should be updated now is the intersection of requestedRegion
2520 * and the union of modifiedRegion and copyRegion. If it's empty then
2521 * no update is needed.
2524 updateRegion = sraRgnCreateRgn(givenUpdateRegion);
2525 if(cl->screen->progressiveSliceHeight>0) {
2526 int height=cl->screen->progressiveSliceHeight,
2527 y=cl->progressiveSliceY;
2528 sraRegionPtr bbox=sraRgnBBox(updateRegion);
2530 if(sraRgnPopRect(bbox,&rect,0)) {
2532 if(y<rect.y1 || y>=rect.y2)
2534 slice=sraRgnCreateRect(0,y,cl->screen->width,y+height);
2535 sraRgnAnd(updateRegion,slice);
2536 sraRgnDestroy(slice);
2538 sraRgnDestroy(bbox);
2540 if(y>=cl->screen->height)
2542 cl->progressiveSliceY=y;
2545 sraRgnOr(updateRegion,cl->copyRegion);
2546 if(!sraRgnAnd(updateRegion,cl->requestedRegion) &&
2547 sraRgnEmpty(updateRegion) &&
2548 (cl->enableCursorShapeUpdates ||
2549 (cl->cursorX == cl->screen->cursorX && cl->cursorY == cl->screen->cursorY)) &&
2550 !sendCursorShape && !sendCursorPos && !sendKeyboardLedState &&
2551 !sendSupportedMessages && !sendSupportedEncodings && !sendServerIdentity) {
2552 sraRgnDestroy(updateRegion);
2553 UNLOCK(cl->updateMutex);
2558 * We assume that the client doesn't have any pixel data outside the
2559 * requestedRegion. In other words, both the source and destination of a
2560 * copy must lie within requestedRegion. So the region we can send as a
2561 * copy is the intersection of the copyRegion with both the requestedRegion
2562 * and the requestedRegion translated by the amount of the copy. We set
2563 * updateCopyRegion to this.
2566 updateCopyRegion = sraRgnCreateRgn(cl->copyRegion);
2567 sraRgnAnd(updateCopyRegion,cl->requestedRegion);
2568 tmpRegion = sraRgnCreateRgn(cl->requestedRegion);
2569 sraRgnOffset(tmpRegion,cl->copyDX,cl->copyDY);
2570 sraRgnAnd(updateCopyRegion,tmpRegion);
2571 sraRgnDestroy(tmpRegion);
2576 * Next we remove updateCopyRegion from updateRegion so that updateRegion
2577 * is the part of this update which is sent as ordinary pixel data (i.e not
2581 sraRgnSubtract(updateRegion,updateCopyRegion);
2584 * Finally we leave modifiedRegion to be the remainder (if any) of parts of
2585 * the screen which are modified but outside the requestedRegion. We also
2586 * empty both the requestedRegion and the copyRegion - note that we never
2587 * carry over a copyRegion for a future update.
2590 sraRgnOr(cl->modifiedRegion,cl->copyRegion);
2591 sraRgnSubtract(cl->modifiedRegion,updateRegion);
2592 sraRgnSubtract(cl->modifiedRegion,updateCopyRegion);
2594 sraRgnMakeEmpty(cl->requestedRegion);
2595 sraRgnMakeEmpty(cl->copyRegion);
2599 UNLOCK(cl->updateMutex);
2601 if (!cl->enableCursorShapeUpdates) {
2602 if(cl->cursorX != cl->screen->cursorX || cl->cursorY != cl->screen->cursorY) {
2603 rfbRedrawAfterHideCursor(cl,updateRegion);
2604 LOCK(cl->screen->cursorMutex);
2605 cl->cursorX = cl->screen->cursorX;
2606 cl->cursorY = cl->screen->cursorY;
2607 UNLOCK(cl->screen->cursorMutex);
2608 rfbRedrawAfterHideCursor(cl,updateRegion);
2614 * Now send the update.
2617 rfbStatRecordMessageSent(cl, rfbFramebufferUpdate, 0, 0);
2618 if (cl->preferredEncoding == rfbEncodingCoRRE) {
2619 nUpdateRegionRects = 0;
2621 for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){
2624 int w = rect.x2 - x;
2625 int h = rect.y2 - y;
2626 int rectsPerRow, rows;
2627 /* We need to count the number of rects in the scaled screen */
2628 if (cl->screen!=cl->scaledScreen)
2629 rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "rfbSendFramebufferUpdate");
2630 rectsPerRow = (w-1)/cl->correMaxWidth+1;
2631 rows = (h-1)/cl->correMaxHeight+1;
2632 nUpdateRegionRects += rectsPerRow*rows;
2634 sraRgnReleaseIterator(i); i=NULL;
2635 } else if (cl->preferredEncoding == rfbEncodingUltra) {
2636 nUpdateRegionRects = 0;
2638 for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){
2641 int w = rect.x2 - x;
2642 int h = rect.y2 - y;
2643 /* We need to count the number of rects in the scaled screen */
2644 if (cl->screen!=cl->scaledScreen)
2645 rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "rfbSendFramebufferUpdate");
2646 nUpdateRegionRects += (((h-1) / (ULTRA_MAX_SIZE( w ) / w)) + 1);
2648 sraRgnReleaseIterator(i); i=NULL;
2649 #ifdef LIBVNCSERVER_HAVE_LIBZ
2650 } else if (cl->preferredEncoding == rfbEncodingZlib) {
2651 nUpdateRegionRects = 0;
2653 for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){
2656 int w = rect.x2 - x;
2657 int h = rect.y2 - y;
2658 /* We need to count the number of rects in the scaled screen */
2659 if (cl->screen!=cl->scaledScreen)
2660 rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "rfbSendFramebufferUpdate");
2661 nUpdateRegionRects += (((h-1) / (ZLIB_MAX_SIZE( w ) / w)) + 1);
2663 sraRgnReleaseIterator(i); i=NULL;
2664 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
2665 } else if (cl->preferredEncoding == rfbEncodingTight) {
2666 nUpdateRegionRects = 0;
2668 for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){
2671 int w = rect.x2 - x;
2672 int h = rect.y2 - y;
2674 /* We need to count the number of rects in the scaled screen */
2675 if (cl->screen!=cl->scaledScreen)
2676 rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "rfbSendFramebufferUpdate");
2677 n = rfbNumCodedRectsTight(cl, x, y, w, h);
2679 nUpdateRegionRects = 0xFFFF;
2682 nUpdateRegionRects += n;
2684 sraRgnReleaseIterator(i); i=NULL;
2688 nUpdateRegionRects = sraRgnCountRects(updateRegion);
2691 fu->type = rfbFramebufferUpdate;
2692 if (nUpdateRegionRects != 0xFFFF) {
2693 if(cl->screen->maxRectsPerUpdate>0
2694 /* CoRRE splits the screen into smaller squares */
2695 && cl->preferredEncoding != rfbEncodingCoRRE
2696 /* Ultra encoding splits rectangles up into smaller chunks */
2697 && cl->preferredEncoding != rfbEncodingUltra
2698 #ifdef LIBVNCSERVER_HAVE_LIBZ
2699 /* Zlib encoding splits rectangles up into smaller chunks */
2700 && cl->preferredEncoding != rfbEncodingZlib
2701 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
2702 /* Tight encoding counts the rectangles differently */
2703 && cl->preferredEncoding != rfbEncodingTight
2706 && nUpdateRegionRects>cl->screen->maxRectsPerUpdate) {
2707 sraRegion* newUpdateRegion = sraRgnBBox(updateRegion);
2708 sraRgnDestroy(updateRegion);
2709 updateRegion = newUpdateRegion;
2710 nUpdateRegionRects = sraRgnCountRects(updateRegion);
2712 fu->nRects = Swap16IfLE((uint16_t)(sraRgnCountRects(updateCopyRegion) +
2713 nUpdateRegionRects +
2714 !!sendCursorShape + !!sendCursorPos + !!sendKeyboardLedState +
2715 !!sendSupportedMessages + !!sendSupportedEncodings + !!sendServerIdentity));
2717 fu->nRects = 0xFFFF;
2719 cl->ublen = sz_rfbFramebufferUpdateMsg;
2721 if (sendCursorShape) {
2722 cl->cursorWasChanged = FALSE;
2723 if (!rfbSendCursorShape(cl))
2727 if (sendCursorPos) {
2728 cl->cursorWasMoved = FALSE;
2729 if (!rfbSendCursorPos(cl))
2733 if (sendKeyboardLedState) {
2734 if (!rfbSendKeyboardLedState(cl))
2738 if (sendSupportedMessages) {
2739 if (!rfbSendSupportedMessages(cl))
2742 if (sendSupportedEncodings) {
2743 if (!rfbSendSupportedEncodings(cl))
2746 if (sendServerIdentity) {
2747 if (!rfbSendServerIdentity(cl))
2751 if (!sraRgnEmpty(updateCopyRegion)) {
2752 if (!rfbSendCopyRegion(cl,updateCopyRegion,dx,dy))
2756 for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){
2759 int w = rect.x2 - x;
2760 int h = rect.y2 - y;
2762 /* We need to count the number of rects in the scaled screen */
2763 if (cl->screen!=cl->scaledScreen)
2764 rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "rfbSendFramebufferUpdate");
2766 switch (cl->preferredEncoding) {
2768 case rfbEncodingRaw:
2769 if (!rfbSendRectEncodingRaw(cl, x, y, w, h))
2772 case rfbEncodingRRE:
2773 if (!rfbSendRectEncodingRRE(cl, x, y, w, h))
2776 case rfbEncodingCoRRE:
2777 if (!rfbSendRectEncodingCoRRE(cl, x, y, w, h))
2780 case rfbEncodingHextile:
2781 if (!rfbSendRectEncodingHextile(cl, x, y, w, h))
2784 case rfbEncodingUltra:
2785 if (!rfbSendRectEncodingUltra(cl, x, y, w, h))
2788 #ifdef LIBVNCSERVER_HAVE_LIBZ
2789 case rfbEncodingZlib:
2790 if (!rfbSendRectEncodingZlib(cl, x, y, w, h))
2793 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
2794 case rfbEncodingTight:
2795 if (!rfbSendRectEncodingTight(cl, x, y, w, h))
2800 #ifdef LIBVNCSERVER_HAVE_LIBZ
2801 case rfbEncodingZRLE:
2802 case rfbEncodingZYWRLE:
2803 if (!rfbSendRectEncodingZRLE(cl, x, y, w, h))
2810 sraRgnReleaseIterator(i);
2814 if ( nUpdateRegionRects == 0xFFFF &&
2815 !rfbSendLastRectMarker(cl) )
2818 if (!rfbSendUpdateBuf(cl)) {
2823 if (!cl->enableCursorShapeUpdates) {
2828 sraRgnReleaseIterator(i);
2829 sraRgnDestroy(updateRegion);
2830 sraRgnDestroy(updateCopyRegion);
2836 * Send the copy region as a string of CopyRect encoded rectangles.
2837 * The only slightly tricky thing is that we should send the messages in
2838 * the correct order so that an earlier CopyRect will not corrupt the source
2843 rfbSendCopyRegion(rfbClientPtr cl,
2849 rfbFramebufferUpdateRectHeader rect;
2851 sraRectangleIterator* i;
2854 /* printf("copyrect: "); sraRgnPrint(reg); putchar('\n');fflush(stdout); */
2855 i = sraRgnGetReverseIterator(reg,dx>0,dy>0);
2857 /* correct for the scale of the screen */
2858 dx = ScaleX(cl->screen, cl->scaledScreen, dx);
2859 dy = ScaleX(cl->screen, cl->scaledScreen, dy);
2861 while(sraRgnIteratorNext(i,&rect1)) {
2867 /* correct for scaling (if necessary) */
2868 rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "copyrect");
2870 rect.r.x = Swap16IfLE(x);
2871 rect.r.y = Swap16IfLE(y);
2872 rect.r.w = Swap16IfLE(w);
2873 rect.r.h = Swap16IfLE(h);
2874 rect.encoding = Swap32IfLE(rfbEncodingCopyRect);
2876 memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
2877 sz_rfbFramebufferUpdateRectHeader);
2878 cl->ublen += sz_rfbFramebufferUpdateRectHeader;
2880 cr.srcX = Swap16IfLE(x - dx);
2881 cr.srcY = Swap16IfLE(y - dy);
2883 memcpy(&cl->updateBuf[cl->ublen], (char *)&cr, sz_rfbCopyRect);
2884 cl->ublen += sz_rfbCopyRect;
2886 rfbStatRecordEncodingSent(cl, rfbEncodingCopyRect, sz_rfbFramebufferUpdateRectHeader + sz_rfbCopyRect,
2887 w * h * (cl->scaledScreen->bitsPerPixel / 8));
2889 sraRgnReleaseIterator(i);
2895 * Send a given rectangle in raw encoding (rfbEncodingRaw).
2899 rfbSendRectEncodingRaw(rfbClientPtr cl,
2905 rfbFramebufferUpdateRectHeader rect;
2907 int bytesPerLine = w * (cl->format.bitsPerPixel / 8);
2908 char *fbptr = (cl->scaledScreen->frameBuffer + (cl->scaledScreen->paddedWidthInBytes * y)
2909 + (x * (cl->scaledScreen->bitsPerPixel / 8)));
2911 /* Flush the buffer to guarantee correct alignment for translateFn(). */
2912 if (cl->ublen > 0) {
2913 if (!rfbSendUpdateBuf(cl))
2917 rect.r.x = Swap16IfLE(x);
2918 rect.r.y = Swap16IfLE(y);
2919 rect.r.w = Swap16IfLE(w);
2920 rect.r.h = Swap16IfLE(h);
2921 rect.encoding = Swap32IfLE(rfbEncodingRaw);
2923 memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
2924 cl->ublen += sz_rfbFramebufferUpdateRectHeader;
2927 rfbStatRecordEncodingSent(cl, rfbEncodingRaw, sz_rfbFramebufferUpdateRectHeader + bytesPerLine * h,
2928 sz_rfbFramebufferUpdateRectHeader + bytesPerLine * h);
2930 nlines = (UPDATE_BUF_SIZE - cl->ublen) / bytesPerLine;
2936 (*cl->translateFn)(cl->translateLookupTable,
2937 &(cl->screen->serverFormat),
2938 &cl->format, fbptr, &cl->updateBuf[cl->ublen],
2939 cl->scaledScreen->paddedWidthInBytes, w, nlines);
2941 cl->ublen += nlines * bytesPerLine;
2944 if (h == 0) /* rect fitted in buffer, do next one */
2947 /* buffer full - flush partial rect and do another nlines */
2949 if (!rfbSendUpdateBuf(cl))
2952 fbptr += (cl->scaledScreen->paddedWidthInBytes * nlines);
2954 nlines = (UPDATE_BUF_SIZE - cl->ublen) / bytesPerLine;
2956 rfbErr("rfbSendRectEncodingRaw: send buffer too small for %d "
2957 "bytes per line\n", bytesPerLine);
2967 * Send an empty rectangle with encoding field set to value of
2968 * rfbEncodingLastRect to notify client that this is the last
2969 * rectangle in framebuffer update ("LastRect" extension of RFB
2974 rfbSendLastRectMarker(rfbClientPtr cl)
2976 rfbFramebufferUpdateRectHeader rect;
2978 if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
2979 if (!rfbSendUpdateBuf(cl))
2983 rect.encoding = Swap32IfLE(rfbEncodingLastRect);
2989 memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
2990 cl->ublen += sz_rfbFramebufferUpdateRectHeader;
2993 rfbStatRecordEncodingSent(cl, rfbEncodingLastRect, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader);
3000 * Send NewFBSize pseudo-rectangle. This tells the client to change
3001 * its framebuffer size.
3005 rfbSendNewFBSize(rfbClientPtr cl,
3009 rfbFramebufferUpdateRectHeader rect;
3011 if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
3012 if (!rfbSendUpdateBuf(cl))
3016 if (cl->PalmVNC==TRUE)
3017 rfbLog("Sending rfbEncodingNewFBSize in response to a PalmVNC style framebuffer resize (%dx%d)\n", w, h);
3019 rfbLog("Sending rfbEncodingNewFBSize for resize to (%dx%d)\n", w, h);
3021 rect.encoding = Swap32IfLE(rfbEncodingNewFBSize);
3024 rect.r.w = Swap16IfLE(w);
3025 rect.r.h = Swap16IfLE(h);
3027 memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
3028 sz_rfbFramebufferUpdateRectHeader);
3029 cl->ublen += sz_rfbFramebufferUpdateRectHeader;
3031 rfbStatRecordEncodingSent(cl, rfbEncodingNewFBSize, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader);
3038 * Send the contents of cl->updateBuf. Returns 1 if successful, -1 if
3039 * not (errno should be set).
3043 rfbSendUpdateBuf(rfbClientPtr cl)
3048 if (rfbWriteExact(cl, cl->updateBuf, cl->ublen) < 0) {
3049 rfbLogPerror("rfbSendUpdateBuf: write");
3059 * rfbSendSetColourMapEntries sends a SetColourMapEntries message to the
3060 * client, using values from the currently installed colormap.
3064 rfbSendSetColourMapEntries(rfbClientPtr cl,
3068 char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2];
3070 rfbSetColourMapEntriesMsg *scme;
3072 rfbColourMap* cm = &cl->screen->colourMap;
3075 if (nColours > 256) {
3076 /* some rare hardware has, e.g., 4096 colors cells: PseudoColor:12 */
3077 wbuf = (char *) malloc(sz_rfbSetColourMapEntriesMsg + nColours * 3 * 2);
3080 scme = (rfbSetColourMapEntriesMsg *)wbuf;
3081 rgb = (uint16_t *)(&wbuf[sz_rfbSetColourMapEntriesMsg]);
3083 scme->type = rfbSetColourMapEntries;
3085 scme->firstColour = Swap16IfLE(firstColour);
3086 scme->nColours = Swap16IfLE(nColours);
3088 len = sz_rfbSetColourMapEntriesMsg;
3090 for (i = 0; i < nColours; i++) {
3091 if(i<(int)cm->count) {
3093 rgb[i*3] = Swap16IfLE(cm->data.shorts[i*3]);
3094 rgb[i*3+1] = Swap16IfLE(cm->data.shorts[i*3+1]);
3095 rgb[i*3+2] = Swap16IfLE(cm->data.shorts[i*3+2]);
3097 rgb[i*3] = Swap16IfLE((unsigned short)cm->data.bytes[i*3]);
3098 rgb[i*3+1] = Swap16IfLE((unsigned short)cm->data.bytes[i*3+1]);
3099 rgb[i*3+2] = Swap16IfLE((unsigned short)cm->data.bytes[i*3+2]);
3104 len += nColours * 3 * 2;
3106 if (rfbWriteExact(cl, wbuf, len) < 0) {
3107 rfbLogPerror("rfbSendSetColourMapEntries: write");
3109 if (wbuf != buf) free(wbuf);
3113 rfbStatRecordMessageSent(cl, rfbSetColourMapEntries, len, len);
3114 if (wbuf != buf) free(wbuf);
3119 * rfbSendBell sends a Bell message to all the clients.
3123 rfbSendBell(rfbScreenInfoPtr rfbScreen)
3125 rfbClientIteratorPtr i;
3129 i = rfbGetClientIterator(rfbScreen);
3130 while((cl=rfbClientIteratorNext(i))) {
3132 if (rfbWriteExact(cl, (char *)&b, sz_rfbBellMsg) < 0) {
3133 rfbLogPerror("rfbSendBell: write");
3137 rfbStatRecordMessageSent(cl, rfbBell, sz_rfbBellMsg, sz_rfbBellMsg);
3138 rfbReleaseClientIterator(i);
3143 * rfbSendServerCutText sends a ServerCutText message to all the clients.
3147 rfbSendServerCutText(rfbScreenInfoPtr rfbScreen,char *str, int len)
3150 rfbServerCutTextMsg sct;
3151 rfbClientIteratorPtr iterator;
3153 iterator = rfbGetClientIterator(rfbScreen);
3154 while ((cl = rfbClientIteratorNext(iterator)) != NULL) {
3155 sct.type = rfbServerCutText;
3156 sct.length = Swap32IfLE(len);
3157 if (rfbWriteExact(cl, (char *)&sct,
3158 sz_rfbServerCutTextMsg) < 0) {
3159 rfbLogPerror("rfbSendServerCutText: write");
3163 if (rfbWriteExact(cl, str, len) < 0) {
3164 rfbLogPerror("rfbSendServerCutText: write");
3167 rfbStatRecordMessageSent(cl, rfbServerCutText, sz_rfbServerCutTextMsg+len, sz_rfbServerCutTextMsg+len);
3169 rfbReleaseClientIterator(iterator);
3172 /*****************************************************************************
3174 * UDP can be used for keyboard and pointer events when the underlying
3175 * network is highly reliable. This is really here to support ORL's
3176 * videotile, whose TCP implementation doesn't like sending lots of small
3177 * packets (such as 100s of pen readings per second!).
3180 static unsigned char ptrAcceleration = 50;
3183 rfbNewUDPConnection(rfbScreenInfoPtr rfbScreen,
3186 if (write(sock, &ptrAcceleration, 1) < 0) {
3187 rfbLogPerror("rfbNewUDPConnection: write");
3192 * Because UDP is a message based service, we can't read the first byte and
3193 * then the rest of the packet separately like we do with TCP. We will always
3194 * get a whole packet delivered in one go, so we ask read() for the maximum
3195 * number of bytes we can possibly get.
3199 rfbProcessUDPInput(rfbScreenInfoPtr rfbScreen)
3202 rfbClientPtr cl=rfbScreen->udpClient;
3203 rfbClientToServerMsg msg;
3205 if((!cl) || cl->onHold)
3208 if ((n = read(rfbScreen->udpSock, (char *)&msg, sizeof(msg))) <= 0) {
3210 rfbLogPerror("rfbProcessUDPInput: read");
3212 rfbDisconnectUDPSock(rfbScreen);
3219 if (n != sz_rfbKeyEventMsg) {
3220 rfbErr("rfbProcessUDPInput: key event incorrect length\n");
3221 rfbDisconnectUDPSock(rfbScreen);
3224 cl->screen->kbdAddEvent(msg.ke.down, (rfbKeySym)Swap32IfLE(msg.ke.key), cl);
3227 case rfbPointerEvent:
3228 if (n != sz_rfbPointerEventMsg) {
3229 rfbErr("rfbProcessUDPInput: ptr event incorrect length\n");
3230 rfbDisconnectUDPSock(rfbScreen);
3233 cl->screen->ptrAddEvent(msg.pe.buttonMask,
3234 Swap16IfLE(msg.pe.x), Swap16IfLE(msg.pe.y), cl);
3238 rfbErr("rfbProcessUDPInput: unknown message type %d\n",
3240 rfbDisconnectUDPSock(rfbScreen);