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);
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);
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);
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);
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
if ( nUpdateRegionRects == 0xFFFF &&
2811
!rfbSendLastRectMarker(cl) )
2814
if (!rfbSendUpdateBuf(cl)) {
2819
if (!cl->enableCursorShapeUpdates) {
2824
sraRgnReleaseIterator(i);
2825
sraRgnDestroy(updateRegion);
2826
sraRgnDestroy(updateCopyRegion);
2832
* Send the copy region as a string of CopyRect encoded rectangles.
2833
* The only slightly tricky thing is that we should send the messages in
2834
* the correct order so that an earlier CopyRect will not corrupt the source
2839
rfbSendCopyRegion(rfbClientPtr cl,
2845
rfbFramebufferUpdateRectHeader rect;
2847
sraRectangleIterator* i;
2850
/* printf("copyrect: "); sraRgnPrint(reg); putchar('\n');fflush(stdout); */
2851
i = sraRgnGetReverseIterator(reg,dx>0,dy>0);
2853
/* correct for the scale of the screen */
2854
dx = ScaleX(cl->screen, cl->scaledScreen, dx);
2855
dy = ScaleX(cl->screen, cl->scaledScreen, dy);
2857
while(sraRgnIteratorNext(i,&rect1)) {
2863
/* correct for scaling (if necessary) */
2864
rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "copyrect");
2866
rect.r.x = Swap16IfLE(x);
2867
rect.r.y = Swap16IfLE(y);
2868
rect.r.w = Swap16IfLE(w);
2869
rect.r.h = Swap16IfLE(h);
2870
rect.encoding = Swap32IfLE(rfbEncodingCopyRect);
2872
memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
2873
sz_rfbFramebufferUpdateRectHeader);
2874
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
2876
cr.srcX = Swap16IfLE(x - dx);
2877
cr.srcY = Swap16IfLE(y - dy);
2879
memcpy(&cl->updateBuf[cl->ublen], (char *)&cr, sz_rfbCopyRect);
2880
cl->ublen += sz_rfbCopyRect;
2882
rfbStatRecordEncodingSent(cl, rfbEncodingCopyRect, sz_rfbFramebufferUpdateRectHeader + sz_rfbCopyRect,
2883
w * h * (cl->scaledScreen->bitsPerPixel / 8));
2885
sraRgnReleaseIterator(i);
2891
* Send a given rectangle in raw encoding (rfbEncodingRaw).
2895
rfbSendRectEncodingRaw(rfbClientPtr cl,
2901
rfbFramebufferUpdateRectHeader rect;
2903
int bytesPerLine = w * (cl->format.bitsPerPixel / 8);
2904
char *fbptr = (cl->scaledScreen->frameBuffer + (cl->scaledScreen->paddedWidthInBytes * y)
2905
+ (x * (cl->scaledScreen->bitsPerPixel / 8)));
2907
/* Flush the buffer to guarantee correct alignment for translateFn(). */
2908
if (cl->ublen > 0) {
2909
if (!rfbSendUpdateBuf(cl))
2913
rect.r.x = Swap16IfLE(x);
2914
rect.r.y = Swap16IfLE(y);
2915
rect.r.w = Swap16IfLE(w);
2916
rect.r.h = Swap16IfLE(h);
2917
rect.encoding = Swap32IfLE(rfbEncodingRaw);
2919
memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
2920
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
2923
rfbStatRecordEncodingSent(cl, rfbEncodingRaw, sz_rfbFramebufferUpdateRectHeader + bytesPerLine * h,
2924
sz_rfbFramebufferUpdateRectHeader + bytesPerLine * h);
2926
nlines = (UPDATE_BUF_SIZE - cl->ublen) / bytesPerLine;
2932
(*cl->translateFn)(cl->translateLookupTable,
2933
&(cl->screen->serverFormat),
2934
&cl->format, fbptr, &cl->updateBuf[cl->ublen],
2935
cl->scaledScreen->paddedWidthInBytes, w, nlines);
2937
cl->ublen += nlines * bytesPerLine;
2940
if (h == 0) /* rect fitted in buffer, do next one */
2943
/* buffer full - flush partial rect and do another nlines */
2945
if (!rfbSendUpdateBuf(cl))
2948
fbptr += (cl->scaledScreen->paddedWidthInBytes * nlines);
2950
nlines = (UPDATE_BUF_SIZE - cl->ublen) / bytesPerLine;
2952
rfbErr("rfbSendRectEncodingRaw: send buffer too small for %d "
2953
"bytes per line\n", bytesPerLine);
2963
* Send an empty rectangle with encoding field set to value of
2964
* rfbEncodingLastRect to notify client that this is the last
2965
* rectangle in framebuffer update ("LastRect" extension of RFB
2970
rfbSendLastRectMarker(rfbClientPtr cl)
2972
rfbFramebufferUpdateRectHeader rect;
2974
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
2975
if (!rfbSendUpdateBuf(cl))
2979
rect.encoding = Swap32IfLE(rfbEncodingLastRect);
2985
memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
2986
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
2989
rfbStatRecordEncodingSent(cl, rfbEncodingLastRect, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader);
2996
* Send NewFBSize pseudo-rectangle. This tells the client to change
2997
* its framebuffer size.
3001
rfbSendNewFBSize(rfbClientPtr cl,
3005
rfbFramebufferUpdateRectHeader rect;
3007
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
3008
if (!rfbSendUpdateBuf(cl))
3012
if (cl->PalmVNC==TRUE)
3013
rfbLog("Sending rfbEncodingNewFBSize in response to a PalmVNC style framebuffer resize (%dx%d)\n", w, h);
3015
rfbLog("Sending rfbEncodingNewFBSize for resize to (%dx%d)\n", w, h);
3017
rect.encoding = Swap32IfLE(rfbEncodingNewFBSize);
3020
rect.r.w = Swap16IfLE(w);
3021
rect.r.h = Swap16IfLE(h);
3023
memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
3024
sz_rfbFramebufferUpdateRectHeader);
3025
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
3027
rfbStatRecordEncodingSent(cl, rfbEncodingNewFBSize, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader);
3034
* Send the contents of cl->updateBuf. Returns 1 if successful, -1 if
3035
* not (errno should be set).
3039
rfbSendUpdateBuf(rfbClientPtr cl)
3044
if (rfbWriteExact(cl, cl->updateBuf, cl->ublen) < 0) {
3045
rfbLogPerror("rfbSendUpdateBuf: write");
3055
* rfbSendSetColourMapEntries sends a SetColourMapEntries message to the
3056
* client, using values from the currently installed colormap.
3060
rfbSendSetColourMapEntries(rfbClientPtr cl,
3064
char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2];
3065
rfbSetColourMapEntriesMsg *scme = (rfbSetColourMapEntriesMsg *)buf;
3066
uint16_t *rgb = (uint16_t *)(&buf[sz_rfbSetColourMapEntriesMsg]);
3067
rfbColourMap* cm = &cl->screen->colourMap;
3071
scme->type = rfbSetColourMapEntries;
3073
scme->firstColour = Swap16IfLE(firstColour);
3074
scme->nColours = Swap16IfLE(nColours);
3076
len = sz_rfbSetColourMapEntriesMsg;
3078
for (i = 0; i < nColours; i++) {
3079
if(i<(int)cm->count) {
3081
rgb[i*3] = Swap16IfLE(cm->data.shorts[i*3]);
3082
rgb[i*3+1] = Swap16IfLE(cm->data.shorts[i*3+1]);
3083
rgb[i*3+2] = Swap16IfLE(cm->data.shorts[i*3+2]);
3085
rgb[i*3] = Swap16IfLE((unsigned short)cm->data.bytes[i*3]);
3086
rgb[i*3+1] = Swap16IfLE((unsigned short)cm->data.bytes[i*3+1]);
3087
rgb[i*3+2] = Swap16IfLE((unsigned short)cm->data.bytes[i*3+2]);
3092
len += nColours * 3 * 2;
3094
if (rfbWriteExact(cl, buf, len) < 0) {
3095
rfbLogPerror("rfbSendSetColourMapEntries: write");
3100
rfbStatRecordMessageSent(cl, rfbSetColourMapEntries, len, len);
3105
* rfbSendBell sends a Bell message to all the clients.
3109
rfbSendBell(rfbScreenInfoPtr rfbScreen)
3111
rfbClientIteratorPtr i;
3115
i = rfbGetClientIterator(rfbScreen);
3116
while((cl=rfbClientIteratorNext(i))) {
3118
if (rfbWriteExact(cl, (char *)&b, sz_rfbBellMsg) < 0) {
3119
rfbLogPerror("rfbSendBell: write");
3123
rfbStatRecordMessageSent(cl, rfbBell, sz_rfbBellMsg, sz_rfbBellMsg);
3124
rfbReleaseClientIterator(i);
3129
* rfbSendServerCutText sends a ServerCutText message to all the clients.
3133
rfbSendServerCutText(rfbScreenInfoPtr rfbScreen,char *str, int len)
3136
rfbServerCutTextMsg sct;
3137
rfbClientIteratorPtr iterator;
3139
iterator = rfbGetClientIterator(rfbScreen);
3140
while ((cl = rfbClientIteratorNext(iterator)) != NULL) {
3141
sct.type = rfbServerCutText;
3142
sct.length = Swap32IfLE(len);
3143
if (rfbWriteExact(cl, (char *)&sct,
3144
sz_rfbServerCutTextMsg) < 0) {
3145
rfbLogPerror("rfbSendServerCutText: write");
3149
if (rfbWriteExact(cl, str, len) < 0) {
3150
rfbLogPerror("rfbSendServerCutText: write");
3153
rfbStatRecordMessageSent(cl, rfbServerCutText, sz_rfbServerCutTextMsg+len, sz_rfbServerCutTextMsg+len);
3155
rfbReleaseClientIterator(iterator);
3158
/*****************************************************************************
3160
* UDP can be used for keyboard and pointer events when the underlying
3161
* network is highly reliable. This is really here to support ORL's
3162
* videotile, whose TCP implementation doesn't like sending lots of small
3163
* packets (such as 100s of pen readings per second!).
3166
static unsigned char ptrAcceleration = 50;
3169
rfbNewUDPConnection(rfbScreenInfoPtr rfbScreen,
3172
if (write(sock, &ptrAcceleration, 1) < 0) {
3173
rfbLogPerror("rfbNewUDPConnection: write");
3178
* Because UDP is a message based service, we can't read the first byte and
3179
* then the rest of the packet separately like we do with TCP. We will always
3180
* get a whole packet delivered in one go, so we ask read() for the maximum
3181
* number of bytes we can possibly get.
3185
rfbProcessUDPInput(rfbScreenInfoPtr rfbScreen)
3188
rfbClientPtr cl=rfbScreen->udpClient;
3189
rfbClientToServerMsg msg;
3191
if((!cl) || cl->onHold)
3194
if ((n = read(rfbScreen->udpSock, (char *)&msg, sizeof(msg))) <= 0) {
3196
rfbLogPerror("rfbProcessUDPInput: read");
3198
rfbDisconnectUDPSock(rfbScreen);
3205
if (n != sz_rfbKeyEventMsg) {
3206
rfbErr("rfbProcessUDPInput: key event incorrect length\n");
3207
rfbDisconnectUDPSock(rfbScreen);
3210
cl->screen->kbdAddEvent(msg.ke.down, (rfbKeySym)Swap32IfLE(msg.ke.key), cl);
3213
case rfbPointerEvent:
3214
if (n != sz_rfbPointerEventMsg) {
3215
rfbErr("rfbProcessUDPInput: ptr event incorrect length\n");
3216
rfbDisconnectUDPSock(rfbScreen);
3219
cl->screen->ptrAddEvent(msg.pe.buttonMask,
3220
Swap16IfLE(msg.pe.x), Swap16IfLE(msg.pe.y), cl);
3224
rfbErr("rfbProcessUDPInput: unknown message type %d\n",
3226
rfbDisconnectUDPSock(rfbScreen);