1 /*
2 * rfbserver.c - deal with server-side of the RFB protocol.
3 */
4
5 /*
6 * Copyright (C) 2011-2012 D. R. Commander
7 * Copyright (C) 2005 Rohit Kumar, Johannes E. Schindelin
8 * Copyright (C) 2002 RealVNC Ltd.
9 * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
10 * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
11 * All Rights Reserved.
12 *
13 * This is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This software is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this software; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
26 * USA.
27 */
28
29 #ifdef __STRICT_ANSI__
30 #define _BSD_SOURCE
31 #define _POSIX_SOURCE
32 #define _XOPEN_SOURCE 600
33 #endif
34
35 #include <stdio.h>
36 #include <string.h>
37 #include <rfb/rfb.h>
38 #include <rfb/rfbregion.h>
39 #include "private.h"
40
41 #ifdef LIBVNCSERVER_HAVE_FCNTL_H
42 #include <fcntl.h>
43 #endif
44
45 #ifdef WIN32
46 #include <winsock2.h>
47 #include <ws2tcpip.h>
48 #include <io.h>
49 #define write(sock,buf,len) send(sock,buf,len,0)
50 #else
51 #ifdef LIBVNCSERVER_HAVE_UNISTD_H
52 #include <unistd.h>
53 #endif
54 #include <pwd.h>
55 #ifdef LIBVNCSERVER_HAVE_SYS_SOCKET_H
56 #include <sys/socket.h>
57 #endif
58 #ifdef LIBVNCSERVER_HAVE_NETINET_IN_H
59 #include <netinet/in.h>
60 #include <netinet/tcp.h>
61 #include <netdb.h>
62 #include <arpa/inet.h>
63 #endif
64 #endif
65
66 #ifdef DEBUGPROTO
67 #undef DEBUGPROTO
68 #define DEBUGPROTO(x) x
69 #else
70 #define DEBUGPROTO(x)
71 #endif
72 #include <stdarg.h>
73 #include <scale.h>
74 /* stst() */
75 #include <sys/types.h>
76 #include <sys/stat.h>
77 #include <unistd.h>
78
79 #ifndef WIN32
80 /* readdir() */
81 #include <dirent.h>
82 #endif
83
84 /* errno */
85 #include <errno.h>
86 /* strftime() */
87 #include <time.h>
88
89 #ifdef LIBVNCSERVER_WITH_WEBSOCKETS
90 #include "rfbssl.h"
91 #endif
92
93 #ifdef _MSC_VER
94 #define snprintf _snprintf /* Missing in MSVC */
95 /* Prevent POSIX deprecation warnings */
96 #define close _close
97 #define strdup _strdup
98 #endif
99
100 #ifdef WIN32
101 #ifdef __MINGW32__
102 #define mkdir(path, perms) mkdir(path) /* Omit the perms argument to match POSIX signature */
103 #else /* MSVC and other windows compilers */
104 #define mkdir(path, perms) _mkdir(path) /* Omit the perms argument to match POSIX signature */
105 #endif /* __MINGW32__ else... */
106 #define S_ISDIR(m) (((m) & S_IFDIR) == S_IFDIR)
107 #include <direct.h>
108 #endif
109
110 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
111 /*
112 * Map of quality levels to provide compatibility with TightVNC/TigerVNC
113 * clients. This emulates the behavior of the TigerVNC Server.
114 */
115
116 static const int tight2turbo_qual[10] = {
117 15, 29, 41, 42, 62, 77, 79, 86, 92, 100
118 };
119
120 static const int tight2turbo_subsamp[10] = {
121 1, 1, 1, 2, 2, 2, 0, 0, 0, 0
122 };
123 #endif
124
125 static void rfbProcessClientProtocolVersion(rfbClientPtr cl);
126 static void rfbProcessClientNormalMessage(rfbClientPtr cl);
127 static void rfbProcessClientInitMessage(rfbClientPtr cl);
128
129 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
rfbIncrClientRef(rfbClientPtr cl)130 void rfbIncrClientRef(rfbClientPtr cl)
131 {
132 LOCK(cl->refCountMutex);
133 cl->refCount++;
134 UNLOCK(cl->refCountMutex);
135 }
136
rfbDecrClientRef(rfbClientPtr cl)137 void rfbDecrClientRef(rfbClientPtr cl)
138 {
139 LOCK(cl->refCountMutex);
140 cl->refCount--;
141 if(cl->refCount<=0) /* just to be sure also < 0 */
142 TSIGNAL(cl->deleteCond);
143 UNLOCK(cl->refCountMutex);
144 }
145 #else
rfbIncrClientRef(rfbClientPtr cl)146 void rfbIncrClientRef(rfbClientPtr cl) {}
rfbDecrClientRef(rfbClientPtr cl)147 void rfbDecrClientRef(rfbClientPtr cl) {}
148 #endif
149
150 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
151 static MUTEX(rfbClientListMutex);
152 #endif
153
154 struct rfbClientIterator {
155 rfbClientPtr next;
156 rfbScreenInfoPtr screen;
157 rfbBool closedToo;
158 };
159
160 void
rfbClientListInit(rfbScreenInfoPtr rfbScreen)161 rfbClientListInit(rfbScreenInfoPtr rfbScreen)
162 {
163 if(sizeof(rfbBool)!=1) {
164 /* a sanity check */
165 fprintf(stderr,"rfbBool's size is not 1 (%d)!\n",(int)sizeof(rfbBool));
166 /* we cannot continue, because rfbBool is supposed to be char everywhere */
167 exit(1);
168 }
169 rfbScreen->clientHead = NULL;
170 INIT_MUTEX(rfbClientListMutex);
171 }
172
173 rfbClientIteratorPtr
rfbGetClientIterator(rfbScreenInfoPtr rfbScreen)174 rfbGetClientIterator(rfbScreenInfoPtr rfbScreen)
175 {
176 rfbClientIteratorPtr i =
177 (rfbClientIteratorPtr)malloc(sizeof(struct rfbClientIterator));
178 i->next = NULL;
179 i->screen = rfbScreen;
180 i->closedToo = FALSE;
181 return i;
182 }
183
184 rfbClientIteratorPtr
rfbGetClientIteratorWithClosed(rfbScreenInfoPtr rfbScreen)185 rfbGetClientIteratorWithClosed(rfbScreenInfoPtr rfbScreen)
186 {
187 rfbClientIteratorPtr i =
188 (rfbClientIteratorPtr)malloc(sizeof(struct rfbClientIterator));
189 i->next = NULL;
190 i->screen = rfbScreen;
191 i->closedToo = TRUE;
192 return i;
193 }
194
195 rfbClientPtr
rfbClientIteratorHead(rfbClientIteratorPtr i)196 rfbClientIteratorHead(rfbClientIteratorPtr i)
197 {
198 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
199 if(i->next != 0) {
200 rfbDecrClientRef(i->next);
201 rfbIncrClientRef(i->screen->clientHead);
202 }
203 #endif
204 LOCK(rfbClientListMutex);
205 i->next = i->screen->clientHead;
206 UNLOCK(rfbClientListMutex);
207 return i->next;
208 }
209
210 rfbClientPtr
rfbClientIteratorNext(rfbClientIteratorPtr i)211 rfbClientIteratorNext(rfbClientIteratorPtr i)
212 {
213 if(i->next == 0) {
214 LOCK(rfbClientListMutex);
215 i->next = i->screen->clientHead;
216 UNLOCK(rfbClientListMutex);
217 } else {
218 IF_PTHREADS(rfbClientPtr cl = i->next);
219 i->next = i->next->next;
220 IF_PTHREADS(rfbDecrClientRef(cl));
221 }
222
223 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
224 if(!i->closedToo)
225 while(i->next && i->next->sock<0)
226 i->next = i->next->next;
227 if(i->next)
228 rfbIncrClientRef(i->next);
229 #endif
230
231 return i->next;
232 }
233
234 void
rfbReleaseClientIterator(rfbClientIteratorPtr iterator)235 rfbReleaseClientIterator(rfbClientIteratorPtr iterator)
236 {
237 IF_PTHREADS(if(iterator->next) rfbDecrClientRef(iterator->next));
238 free(iterator);
239 }
240
241
242 /*
243 * rfbNewClientConnection is called from sockets.c when a new connection
244 * comes in.
245 */
246
247 void
rfbNewClientConnection(rfbScreenInfoPtr rfbScreen,int sock)248 rfbNewClientConnection(rfbScreenInfoPtr rfbScreen,
249 int sock)
250 {
251 rfbNewClient(rfbScreen,sock);
252 }
253
254
255 /*
256 * rfbReverseConnection is called to make an outward
257 * connection to a "listening" RFB client.
258 */
259
260 rfbClientPtr
rfbReverseConnection(rfbScreenInfoPtr rfbScreen,char * host,int port)261 rfbReverseConnection(rfbScreenInfoPtr rfbScreen,
262 char *host,
263 int port)
264 {
265 int sock;
266 rfbClientPtr cl;
267
268 if ((sock = rfbConnect(rfbScreen, host, port)) < 0)
269 return (rfbClientPtr)NULL;
270
271 cl = rfbNewClient(rfbScreen, sock);
272
273 if (cl) {
274 cl->reverseConnection = TRUE;
275 }
276
277 return cl;
278 }
279
280
281 void
rfbSetProtocolVersion(rfbScreenInfoPtr rfbScreen,int major_,int minor_)282 rfbSetProtocolVersion(rfbScreenInfoPtr rfbScreen, int major_, int minor_)
283 {
284 /* Permit the server to set the version to report */
285 /* TODO: sanity checking */
286 if ((major_==3) && (minor_ > 2 && minor_ < 9))
287 {
288 rfbScreen->protocolMajorVersion = major_;
289 rfbScreen->protocolMinorVersion = minor_;
290 }
291 else
292 rfbLog("rfbSetProtocolVersion(%d,%d) set to invalid values\n", major_, minor_);
293 }
294
295 /*
296 * rfbNewClient is called when a new connection has been made by whatever
297 * means.
298 */
299
300 static rfbClientPtr
rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen,int sock,rfbBool isUDP)301 rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen,
302 int sock,
303 rfbBool isUDP)
304 {
305 rfbProtocolVersionMsg pv;
306 rfbClientIteratorPtr iterator;
307 rfbClientPtr cl,cl_;
308 #ifdef LIBVNCSERVER_IPv6
309 struct sockaddr_storage addr;
310 #else
311 struct sockaddr_in addr;
312 #endif
313 socklen_t addrlen = sizeof(addr);
314 rfbProtocolExtension* extension;
315
316 cl = (rfbClientPtr)calloc(sizeof(rfbClientRec),1);
317
318 cl->screen = rfbScreen;
319 cl->sock = sock;
320 cl->viewOnly = FALSE;
321 /* setup pseudo scaling */
322 cl->scaledScreen = rfbScreen;
323 cl->scaledScreen->scaledScreenRefCount++;
324
325 rfbResetStats(cl);
326
327 cl->clientData = NULL;
328 cl->clientGoneHook = rfbDoNothingWithClient;
329
330 if(isUDP) {
331 rfbLog(" accepted UDP client\n");
332 } else {
333 #ifdef LIBVNCSERVER_IPv6
334 char host[1024];
335 #endif
336 int one=1;
337
338 getpeername(sock, (struct sockaddr *)&addr, &addrlen);
339 #ifdef LIBVNCSERVER_IPv6
340 if(getnameinfo((struct sockaddr*)&addr, addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST) != 0) {
341 rfbLogPerror("rfbNewClient: error in getnameinfo");
342 cl->host = strdup("");
343 }
344 else
345 cl->host = strdup(host);
346 #else
347 cl->host = strdup(inet_ntoa(addr.sin_addr));
348 #endif
349
350 rfbLog(" other clients:\n");
351 iterator = rfbGetClientIterator(rfbScreen);
352 while ((cl_ = rfbClientIteratorNext(iterator)) != NULL) {
353 rfbLog(" %s\n",cl_->host);
354 }
355 rfbReleaseClientIterator(iterator);
356
357 if(!rfbSetNonBlocking(sock)) {
358 close(sock);
359 return NULL;
360 }
361
362 if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
363 (char *)&one, sizeof(one)) < 0) {
364 rfbLogPerror("setsockopt failed");
365 close(sock);
366 return NULL;
367 }
368
369 FD_SET(sock,&(rfbScreen->allFds));
370 rfbScreen->maxFd = max(sock,rfbScreen->maxFd);
371
372 INIT_MUTEX(cl->outputMutex);
373 INIT_MUTEX(cl->refCountMutex);
374 INIT_MUTEX(cl->sendMutex);
375 INIT_COND(cl->deleteCond);
376
377 cl->state = RFB_PROTOCOL_VERSION;
378
379 cl->reverseConnection = FALSE;
380 cl->readyForSetColourMapEntries = FALSE;
381 cl->useCopyRect = FALSE;
382 cl->preferredEncoding = -1;
383 cl->correMaxWidth = 48;
384 cl->correMaxHeight = 48;
385 #ifdef LIBVNCSERVER_HAVE_LIBZ
386 cl->zrleData = NULL;
387 #endif
388
389 cl->copyRegion = sraRgnCreate();
390 cl->copyDX = 0;
391 cl->copyDY = 0;
392
393 cl->modifiedRegion =
394 sraRgnCreateRect(0,0,rfbScreen->width,rfbScreen->height);
395
396 INIT_MUTEX(cl->updateMutex);
397 INIT_COND(cl->updateCond);
398
399 cl->requestedRegion = sraRgnCreate();
400
401 cl->format = cl->screen->serverFormat;
402 cl->translateFn = rfbTranslateNone;
403 cl->translateLookupTable = NULL;
404
405 LOCK(rfbClientListMutex);
406
407 IF_PTHREADS(cl->refCount = 0);
408 cl->next = rfbScreen->clientHead;
409 cl->prev = NULL;
410 if (rfbScreen->clientHead)
411 rfbScreen->clientHead->prev = cl;
412
413 rfbScreen->clientHead = cl;
414 UNLOCK(rfbClientListMutex);
415
416 #if defined(LIBVNCSERVER_HAVE_LIBZ) || defined(LIBVNCSERVER_HAVE_LIBPNG)
417 cl->tightQualityLevel = -1;
418 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
419 cl->tightCompressLevel = TIGHT_DEFAULT_COMPRESSION;
420 cl->turboSubsampLevel = TURBO_DEFAULT_SUBSAMP;
421 {
422 int i;
423 for (i = 0; i < 4; i++)
424 cl->zsActive[i] = FALSE;
425 }
426 #endif
427 #endif
428
429 cl->fileTransfer.fd = -1;
430
431 cl->enableCursorShapeUpdates = FALSE;
432 cl->enableCursorPosUpdates = FALSE;
433 cl->useRichCursorEncoding = FALSE;
434 cl->enableLastRectEncoding = FALSE;
435 cl->enableKeyboardLedState = FALSE;
436 cl->enableSupportedMessages = FALSE;
437 cl->enableSupportedEncodings = FALSE;
438 cl->enableServerIdentity = FALSE;
439 cl->lastKeyboardLedState = -1;
440 cl->cursorX = rfbScreen->cursorX;
441 cl->cursorY = rfbScreen->cursorY;
442 cl->useNewFBSize = FALSE;
443
444 #ifdef LIBVNCSERVER_HAVE_LIBZ
445 cl->compStreamInited = FALSE;
446 cl->compStream.total_in = 0;
447 cl->compStream.total_out = 0;
448 cl->compStream.zalloc = Z_NULL;
449 cl->compStream.zfree = Z_NULL;
450 cl->compStream.opaque = Z_NULL;
451
452 cl->zlibCompressLevel = 5;
453 #endif
454
455 cl->progressiveSliceY = 0;
456
457 cl->extensions = NULL;
458
459 cl->lastPtrX = -1;
460
461 #ifdef LIBVNCSERVER_WITH_WEBSOCKETS
462 /*
463 * Wait a few ms for the client to send one of:
464 * - Flash policy request
465 * - WebSockets connection (TLS/SSL or plain)
466 */
467 if (!webSocketsCheck(cl)) {
468 /* Error reporting handled in webSocketsHandshake */
469 rfbCloseClient(cl);
470 rfbClientConnectionGone(cl);
471 return NULL;
472 }
473 #endif
474
475 sprintf(pv,rfbProtocolVersionFormat,rfbScreen->protocolMajorVersion,
476 rfbScreen->protocolMinorVersion);
477
478 if (rfbWriteExact(cl, pv, sz_rfbProtocolVersionMsg) < 0) {
479 rfbLogPerror("rfbNewClient: write");
480 rfbCloseClient(cl);
481 rfbClientConnectionGone(cl);
482 return NULL;
483 }
484 }
485
486 for(extension = rfbGetExtensionIterator(); extension;
487 extension=extension->next) {
488 void* data = NULL;
489 /* if the extension does not have a newClient method, it wants
490 * to be initialized later. */
491 if(extension->newClient && extension->newClient(cl, &data))
492 rfbEnableExtension(cl, extension, data);
493 }
494 rfbReleaseExtensionIterator();
495
496 switch (cl->screen->newClientHook(cl)) {
497 case RFB_CLIENT_ON_HOLD:
498 cl->onHold = TRUE;
499 break;
500 case RFB_CLIENT_ACCEPT:
501 cl->onHold = FALSE;
502 break;
503 case RFB_CLIENT_REFUSE:
504 rfbCloseClient(cl);
505 rfbClientConnectionGone(cl);
506 cl = NULL;
507 break;
508 }
509 return cl;
510 }
511
512 rfbClientPtr
rfbNewClient(rfbScreenInfoPtr rfbScreen,int sock)513 rfbNewClient(rfbScreenInfoPtr rfbScreen,
514 int sock)
515 {
516 return(rfbNewTCPOrUDPClient(rfbScreen,sock,FALSE));
517 }
518
519 rfbClientPtr
rfbNewUDPClient(rfbScreenInfoPtr rfbScreen)520 rfbNewUDPClient(rfbScreenInfoPtr rfbScreen)
521 {
522 return((rfbScreen->udpClient=
523 rfbNewTCPOrUDPClient(rfbScreen,rfbScreen->udpSock,TRUE)));
524 }
525
526 /*
527 * rfbClientConnectionGone is called from sockets.c just after a connection
528 * has gone away.
529 */
530
531 void
rfbClientConnectionGone(rfbClientPtr cl)532 rfbClientConnectionGone(rfbClientPtr cl)
533 {
534 #if defined(LIBVNCSERVER_HAVE_LIBZ) && defined(LIBVNCSERVER_HAVE_LIBJPEG)
535 int i;
536 #endif
537
538 LOCK(rfbClientListMutex);
539
540 if (cl->prev)
541 cl->prev->next = cl->next;
542 else
543 cl->screen->clientHead = cl->next;
544 if (cl->next)
545 cl->next->prev = cl->prev;
546
547 UNLOCK(rfbClientListMutex);
548
549 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
550 if(cl->screen->backgroundLoop != FALSE) {
551 int i;
552 do {
553 LOCK(cl->refCountMutex);
554 i=cl->refCount;
555 if(i>0)
556 WAIT(cl->deleteCond,cl->refCountMutex);
557 UNLOCK(cl->refCountMutex);
558 } while(i>0);
559 }
560 #endif
561
562 if(cl->sock>=0)
563 close(cl->sock);
564
565 if (cl->scaledScreen!=NULL)
566 cl->scaledScreen->scaledScreenRefCount--;
567
568 #ifdef LIBVNCSERVER_HAVE_LIBZ
569 rfbFreeZrleData(cl);
570 #endif
571
572 rfbFreeUltraData(cl);
573
574 /* free buffers holding pixel data before and after encoding */
575 free(cl->beforeEncBuf);
576 free(cl->afterEncBuf);
577
578 if(cl->sock>=0)
579 FD_CLR(cl->sock,&(cl->screen->allFds));
580
581 cl->clientGoneHook(cl);
582
583 rfbLog("Client %s gone\n",cl->host);
584 free(cl->host);
585
586 #ifdef LIBVNCSERVER_HAVE_LIBZ
587 /* Release the compression state structures if any. */
588 if ( cl->compStreamInited ) {
589 deflateEnd( &(cl->compStream) );
590 }
591
592 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
593 for (i = 0; i < 4; i++) {
594 if (cl->zsActive[i])
595 deflateEnd(&cl->zsStruct[i]);
596 }
597 #endif
598 #endif
599
600 if (cl->screen->pointerClient == cl)
601 cl->screen->pointerClient = NULL;
602
603 sraRgnDestroy(cl->modifiedRegion);
604 sraRgnDestroy(cl->requestedRegion);
605 sraRgnDestroy(cl->copyRegion);
606
607 if (cl->translateLookupTable) free(cl->translateLookupTable);
608
609 TINI_COND(cl->updateCond);
610 TINI_MUTEX(cl->updateMutex);
611
612 /* make sure outputMutex is unlocked before destroying */
613 LOCK(cl->outputMutex);
614 UNLOCK(cl->outputMutex);
615 TINI_MUTEX(cl->outputMutex);
616
617 LOCK(cl->sendMutex);
618 UNLOCK(cl->sendMutex);
619 TINI_MUTEX(cl->sendMutex);
620
621 rfbPrintStats(cl);
622 rfbResetStats(cl);
623
624 free(cl);
625 }
626
627
628 /*
629 * rfbProcessClientMessage is called when there is data to read from a client.
630 */
631
632 void
rfbProcessClientMessage(rfbClientPtr cl)633 rfbProcessClientMessage(rfbClientPtr cl)
634 {
635 switch (cl->state) {
636 case RFB_PROTOCOL_VERSION:
637 rfbProcessClientProtocolVersion(cl);
638 return;
639 case RFB_SECURITY_TYPE:
640 rfbProcessClientSecurityType(cl);
641 return;
642 case RFB_AUTHENTICATION:
643 rfbAuthProcessClientMessage(cl);
644 return;
645 case RFB_INITIALISATION:
646 case RFB_INITIALISATION_SHARED:
647 rfbProcessClientInitMessage(cl);
648 return;
649 default:
650 rfbProcessClientNormalMessage(cl);
651 return;
652 }
653 }
654
655
656 /*
657 * rfbProcessClientProtocolVersion is called when the client sends its
658 * protocol version.
659 */
660
661 static void
rfbProcessClientProtocolVersion(rfbClientPtr cl)662 rfbProcessClientProtocolVersion(rfbClientPtr cl)
663 {
664 rfbProtocolVersionMsg pv;
665 int n, major_, minor_;
666
667 if ((n = rfbReadExact(cl, pv, sz_rfbProtocolVersionMsg)) <= 0) {
668 if (n == 0)
669 rfbLog("rfbProcessClientProtocolVersion: client gone\n");
670 else
671 rfbLogPerror("rfbProcessClientProtocolVersion: read");
672 rfbCloseClient(cl);
673 return;
674 }
675
676 pv[sz_rfbProtocolVersionMsg] = 0;
677 if (sscanf(pv,rfbProtocolVersionFormat,&major_,&minor_) != 2) {
678 rfbErr("rfbProcessClientProtocolVersion: not a valid RFB client: %s\n", pv);
679 rfbCloseClient(cl);
680 return;
681 }
682 rfbLog("Client Protocol Version %d.%d\n", major_, minor_);
683
684 if (major_ != rfbProtocolMajorVersion) {
685 rfbErr("RFB protocol version mismatch - server %d.%d, client %d.%d",
686 cl->screen->protocolMajorVersion, cl->screen->protocolMinorVersion,
687 major_,minor_);
688 rfbCloseClient(cl);
689 return;
690 }
691
692 /* Check for the minor version use either of the two standard version of RFB */
693 /*
694 * UltraVNC Viewer detects FileTransfer compatible servers via rfb versions
695 * 3.4, 3.6, 3.14, 3.16
696 * It's a bad method, but it is what they use to enable features...
697 * maintaining RFB version compatibility across multiple servers is a pain
698 * Should use something like ServerIdentity encoding
699 */
700 cl->protocolMajorVersion = major_;
701 cl->protocolMinorVersion = minor_;
702
703 rfbLog("Protocol version sent %d.%d, using %d.%d\n",
704 major_, minor_, rfbProtocolMajorVersion, cl->protocolMinorVersion);
705
706 rfbAuthNewClient(cl);
707 }
708
709
710 void
rfbClientSendString(rfbClientPtr cl,const char * reason)711 rfbClientSendString(rfbClientPtr cl, const char *reason)
712 {
713 char *buf;
714 int len = strlen(reason);
715
716 rfbLog("rfbClientSendString(\"%s\")\n", reason);
717
718 buf = (char *)malloc(4 + len);
719 ((uint32_t *)buf)[0] = Swap32IfLE(len);
720 memcpy(buf + 4, reason, len);
721
722 if (rfbWriteExact(cl, buf, 4 + len) < 0)
723 rfbLogPerror("rfbClientSendString: write");
724 free(buf);
725
726 rfbCloseClient(cl);
727 }
728
729 /*
730 * rfbClientConnFailed is called when a client connection has failed either
731 * because it talks the wrong protocol or it has failed authentication.
732 */
733
734 void
rfbClientConnFailed(rfbClientPtr cl,const char * reason)735 rfbClientConnFailed(rfbClientPtr cl,
736 const char *reason)
737 {
738 char *buf;
739 int len = strlen(reason);
740
741 rfbLog("rfbClientConnFailed(\"%s\")\n", reason);
742
743 buf = (char *)malloc(8 + len);
744 ((uint32_t *)buf)[0] = Swap32IfLE(rfbConnFailed);
745 ((uint32_t *)buf)[1] = Swap32IfLE(len);
746 memcpy(buf + 8, reason, len);
747
748 if (rfbWriteExact(cl, buf, 8 + len) < 0)
749 rfbLogPerror("rfbClientConnFailed: write");
750 free(buf);
751
752 rfbCloseClient(cl);
753 }
754
755
756 /*
757 * rfbProcessClientInitMessage is called when the client sends its
758 * initialisation message.
759 */
760
761 static void
rfbProcessClientInitMessage(rfbClientPtr cl)762 rfbProcessClientInitMessage(rfbClientPtr cl)
763 {
764 rfbClientInitMsg ci;
765 union {
766 char buf[256];
767 rfbServerInitMsg si;
768 } u;
769 int len, n;
770 rfbClientIteratorPtr iterator;
771 rfbClientPtr otherCl;
772 rfbExtensionData* extension;
773
774 if (cl->state == RFB_INITIALISATION_SHARED) {
775 /* In this case behave as though an implicit ClientInit message has
776 * already been received with a shared-flag of true. */
777 ci.shared = 1;
778 /* Avoid the possibility of exposing the RFB_INITIALISATION_SHARED
779 * state to calling software. */
780 cl->state = RFB_INITIALISATION;
781 } else {
782 if ((n = rfbReadExact(cl, (char *)&ci,sz_rfbClientInitMsg)) <= 0) {
783 if (n == 0)
784 rfbLog("rfbProcessClientInitMessage: client gone\n");
785 else
786 rfbLogPerror("rfbProcessClientInitMessage: read");
787 rfbCloseClient(cl);
788 return;
789 }
790 }
791
792 memset(u.buf,0,sizeof(u.buf));
793
794 u.si.framebufferWidth = Swap16IfLE(cl->screen->width);
795 u.si.framebufferHeight = Swap16IfLE(cl->screen->height);
796 u.si.format = cl->screen->serverFormat;
797 u.si.format.redMax = Swap16IfLE(u.si.format.redMax);
798 u.si.format.greenMax = Swap16IfLE(u.si.format.greenMax);
799 u.si.format.blueMax = Swap16IfLE(u.si.format.blueMax);
800
801 strncpy(u.buf + sz_rfbServerInitMsg, cl->screen->desktopName, 127);
802 len = strlen(u.buf + sz_rfbServerInitMsg);
803 u.si.nameLength = Swap32IfLE(len);
804
805 if (rfbWriteExact(cl, u.buf, sz_rfbServerInitMsg + len) < 0) {
806 rfbLogPerror("rfbProcessClientInitMessage: write");
807 rfbCloseClient(cl);
808 return;
809 }
810
811 for(extension = cl->extensions; extension;) {
812 rfbExtensionData* next = extension->next;
813 if(extension->extension->init &&
814 !extension->extension->init(cl, extension->data))
815 /* extension requested that it be removed */
816 rfbDisableExtension(cl, extension->extension);
817 extension = next;
818 }
819
820 cl->state = RFB_NORMAL;
821
822 if (!cl->reverseConnection &&
823 (cl->screen->neverShared || (!cl->screen->alwaysShared && !ci.shared))) {
824
825 if (cl->screen->dontDisconnect) {
826 iterator = rfbGetClientIterator(cl->screen);
827 while ((otherCl = rfbClientIteratorNext(iterator)) != NULL) {
828 if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) {
829 rfbLog("-dontdisconnect: Not shared & existing client\n");
830 rfbLog(" refusing new client %s\n", cl->host);
831 rfbCloseClient(cl);
832 rfbReleaseClientIterator(iterator);
833 return;
834 }
835 }
836 rfbReleaseClientIterator(iterator);
837 } else {
838 iterator = rfbGetClientIterator(cl->screen);
839 while ((otherCl = rfbClientIteratorNext(iterator)) != NULL) {
840 if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) {
841 rfbLog("Not shared - closing connection to client %s\n",
842 otherCl->host);
843 rfbCloseClient(otherCl);
844 }
845 }
846 rfbReleaseClientIterator(iterator);
847 }
848 }
849 }
850
851 /* The values come in based on the scaled screen, we need to convert them to
852 * values based on the man screen's coordinate system
853 */
rectSwapIfLEAndClip(uint16_t * x,uint16_t * y,uint16_t * w,uint16_t * h,rfbClientPtr cl)854 static rfbBool rectSwapIfLEAndClip(uint16_t* x,uint16_t* y,uint16_t* w,uint16_t* h,
855 rfbClientPtr cl)
856 {
857 int x1=Swap16IfLE(*x);
858 int y1=Swap16IfLE(*y);
859 int w1=Swap16IfLE(*w);
860 int h1=Swap16IfLE(*h);
861
862 rfbScaledCorrection(cl->scaledScreen, cl->screen, &x1, &y1, &w1, &h1, "rectSwapIfLEAndClip");
863 *x = x1;
864 *y = y1;
865 *w = w1;
866 *h = h1;
867
868 if(*w>cl->screen->width-*x)
869 *w=cl->screen->width-*x;
870 /* possible underflow */
871 if(*w>cl->screen->width-*x)
872 return FALSE;
873 if(*h>cl->screen->height-*y)
874 *h=cl->screen->height-*y;
875 if(*h>cl->screen->height-*y)
876 return FALSE;
877
878 return TRUE;
879 }
880
881 /*
882 * Send keyboard state (PointerPos pseudo-encoding).
883 */
884
885 rfbBool
rfbSendKeyboardLedState(rfbClientPtr cl)886 rfbSendKeyboardLedState(rfbClientPtr cl)
887 {
888 rfbFramebufferUpdateRectHeader rect;
889
890 if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
891 if (!rfbSendUpdateBuf(cl))
892 return FALSE;
893 }
894
895 rect.encoding = Swap32IfLE(rfbEncodingKeyboardLedState);
896 rect.r.x = Swap16IfLE(cl->lastKeyboardLedState);
897 rect.r.y = 0;
898 rect.r.w = 0;
899 rect.r.h = 0;
900
901 memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
902 sz_rfbFramebufferUpdateRectHeader);
903 cl->ublen += sz_rfbFramebufferUpdateRectHeader;
904
905 rfbStatRecordEncodingSent(cl, rfbEncodingKeyboardLedState, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader);
906
907 if (!rfbSendUpdateBuf(cl))
908 return FALSE;
909
910 return TRUE;
911 }
912
913
914 #define rfbSetBit(buffer, position) (buffer[(position & 255) / 8] |= (1 << (position % 8)))
915
916 /*
917 * Send rfbEncodingSupportedMessages.
918 */
919
920 rfbBool
rfbSendSupportedMessages(rfbClientPtr cl)921 rfbSendSupportedMessages(rfbClientPtr cl)
922 {
923 rfbFramebufferUpdateRectHeader rect;
924 rfbSupportedMessages msgs;
925
926 if (cl->ublen + sz_rfbFramebufferUpdateRectHeader
927 + sz_rfbSupportedMessages > UPDATE_BUF_SIZE) {
928 if (!rfbSendUpdateBuf(cl))
929 return FALSE;
930 }
931
932 rect.encoding = Swap32IfLE(rfbEncodingSupportedMessages);
933 rect.r.x = 0;
934 rect.r.y = 0;
935 rect.r.w = Swap16IfLE(sz_rfbSupportedMessages);
936 rect.r.h = 0;
937
938 memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
939 sz_rfbFramebufferUpdateRectHeader);
940 cl->ublen += sz_rfbFramebufferUpdateRectHeader;
941
942 memset((char *)&msgs, 0, sz_rfbSupportedMessages);
943 rfbSetBit(msgs.client2server, rfbSetPixelFormat);
944 rfbSetBit(msgs.client2server, rfbFixColourMapEntries);
945 rfbSetBit(msgs.client2server, rfbSetEncodings);
946 rfbSetBit(msgs.client2server, rfbFramebufferUpdateRequest);
947 rfbSetBit(msgs.client2server, rfbKeyEvent);
948 rfbSetBit(msgs.client2server, rfbPointerEvent);
949 rfbSetBit(msgs.client2server, rfbClientCutText);
950 rfbSetBit(msgs.client2server, rfbFileTransfer);
951 rfbSetBit(msgs.client2server, rfbSetScale);
952 /*rfbSetBit(msgs.client2server, rfbSetServerInput); */
953 /*rfbSetBit(msgs.client2server, rfbSetSW); */
954 /*rfbSetBit(msgs.client2server, rfbTextChat); */
955 rfbSetBit(msgs.client2server, rfbPalmVNCSetScaleFactor);
956 rfbSetBit(msgs.client2server, rfbXvp);
957
958 rfbSetBit(msgs.server2client, rfbFramebufferUpdate);
959 rfbSetBit(msgs.server2client, rfbSetColourMapEntries);
960 rfbSetBit(msgs.server2client, rfbBell);
961 rfbSetBit(msgs.server2client, rfbServerCutText);
962 rfbSetBit(msgs.server2client, rfbResizeFrameBuffer);
963 rfbSetBit(msgs.server2client, rfbPalmVNCReSizeFrameBuffer);
964 rfbSetBit(msgs.server2client, rfbXvp);
965
966 memcpy(&cl->updateBuf[cl->ublen], (char *)&msgs, sz_rfbSupportedMessages);
967 cl->ublen += sz_rfbSupportedMessages;
968
969 rfbStatRecordEncodingSent(cl, rfbEncodingSupportedMessages,
970 sz_rfbFramebufferUpdateRectHeader+sz_rfbSupportedMessages,
971 sz_rfbFramebufferUpdateRectHeader+sz_rfbSupportedMessages);
972 if (!rfbSendUpdateBuf(cl))
973 return FALSE;
974
975 return TRUE;
976 }
977
978
979
980 /*
981 * Send rfbEncodingSupportedEncodings.
982 */
983
984 rfbBool
rfbSendSupportedEncodings(rfbClientPtr cl)985 rfbSendSupportedEncodings(rfbClientPtr cl)
986 {
987 rfbFramebufferUpdateRectHeader rect;
988 static uint32_t supported[] = {
989 rfbEncodingRaw,
990 rfbEncodingCopyRect,
991 rfbEncodingRRE,
992 rfbEncodingCoRRE,
993 rfbEncodingHextile,
994 #ifdef LIBVNCSERVER_HAVE_LIBZ
995 rfbEncodingZlib,
996 rfbEncodingZRLE,
997 rfbEncodingZYWRLE,
998 #endif
999 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
1000 rfbEncodingTight,
1001 #endif
1002 #ifdef LIBVNCSERVER_HAVE_LIBPNG
1003 rfbEncodingTightPng,
1004 #endif
1005 rfbEncodingUltra,
1006 rfbEncodingUltraZip,
1007 rfbEncodingXCursor,
1008 rfbEncodingRichCursor,
1009 rfbEncodingPointerPos,
1010 rfbEncodingLastRect,
1011 rfbEncodingNewFBSize,
1012 rfbEncodingKeyboardLedState,
1013 rfbEncodingSupportedMessages,
1014 rfbEncodingSupportedEncodings,
1015 rfbEncodingServerIdentity,
1016 };
1017 uint32_t nEncodings = sizeof(supported) / sizeof(supported[0]), i;
1018
1019 /* think rfbSetEncodingsMsg */
1020
1021 if (cl->ublen + sz_rfbFramebufferUpdateRectHeader
1022 + (nEncodings * sizeof(uint32_t)) > UPDATE_BUF_SIZE) {
1023 if (!rfbSendUpdateBuf(cl))
1024 return FALSE;
1025 }
1026
1027 rect.encoding = Swap32IfLE(rfbEncodingSupportedEncodings);
1028 rect.r.x = 0;
1029 rect.r.y = 0;
1030 rect.r.w = Swap16IfLE(nEncodings * sizeof(uint32_t));
1031 rect.r.h = Swap16IfLE(nEncodings);
1032
1033 memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
1034 sz_rfbFramebufferUpdateRectHeader);
1035 cl->ublen += sz_rfbFramebufferUpdateRectHeader;
1036
1037 for (i = 0; i < nEncodings; i++) {
1038 uint32_t encoding = Swap32IfLE(supported[i]);
1039 memcpy(&cl->updateBuf[cl->ublen], (char *)&encoding, sizeof(encoding));
1040 cl->ublen += sizeof(encoding);
1041 }
1042
1043 rfbStatRecordEncodingSent(cl, rfbEncodingSupportedEncodings,
1044 sz_rfbFramebufferUpdateRectHeader+(nEncodings * sizeof(uint32_t)),
1045 sz_rfbFramebufferUpdateRectHeader+(nEncodings * sizeof(uint32_t)));
1046
1047 if (!rfbSendUpdateBuf(cl))
1048 return FALSE;
1049
1050 return TRUE;
1051 }
1052
1053
1054 void
rfbSetServerVersionIdentity(rfbScreenInfoPtr screen,char * fmt,...)1055 rfbSetServerVersionIdentity(rfbScreenInfoPtr screen, char *fmt, ...)
1056 {
1057 char buffer[256];
1058 va_list ap;
1059
1060 va_start(ap, fmt);
1061 vsnprintf(buffer, sizeof(buffer)-1, fmt, ap);
1062 va_end(ap);
1063
1064 if (screen->versionString!=NULL) free(screen->versionString);
1065 screen->versionString = strdup(buffer);
1066 }
1067
1068 /*
1069 * Send rfbEncodingServerIdentity.
1070 */
1071
1072 rfbBool
rfbSendServerIdentity(rfbClientPtr cl)1073 rfbSendServerIdentity(rfbClientPtr cl)
1074 {
1075 rfbFramebufferUpdateRectHeader rect;
1076 char buffer[512];
1077
1078 /* tack on our library version */
1079 snprintf(buffer,sizeof(buffer)-1, "%s (%s)",
1080 (cl->screen->versionString==NULL ? "unknown" : cl->screen->versionString),
1081 LIBVNCSERVER_PACKAGE_STRING);
1082
1083 if (cl->ublen + sz_rfbFramebufferUpdateRectHeader
1084 + (strlen(buffer)+1) > UPDATE_BUF_SIZE) {
1085 if (!rfbSendUpdateBuf(cl))
1086 return FALSE;
1087 }
1088
1089 rect.encoding = Swap32IfLE(rfbEncodingServerIdentity);
1090 rect.r.x = 0;
1091 rect.r.y = 0;
1092 rect.r.w = Swap16IfLE(strlen(buffer)+1);
1093 rect.r.h = 0;
1094
1095 memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
1096 sz_rfbFramebufferUpdateRectHeader);
1097 cl->ublen += sz_rfbFramebufferUpdateRectHeader;
1098
1099 memcpy(&cl->updateBuf[cl->ublen], buffer, strlen(buffer)+1);
1100 cl->ublen += strlen(buffer)+1;
1101
1102 rfbStatRecordEncodingSent(cl, rfbEncodingServerIdentity,
1103 sz_rfbFramebufferUpdateRectHeader+strlen(buffer)+1,
1104 sz_rfbFramebufferUpdateRectHeader+strlen(buffer)+1);
1105
1106
1107 if (!rfbSendUpdateBuf(cl))
1108 return FALSE;
1109
1110 return TRUE;
1111 }
1112
1113 /*
1114 * Send an xvp server message
1115 */
1116
1117 rfbBool
rfbSendXvp(rfbClientPtr cl,uint8_t version,uint8_t code)1118 rfbSendXvp(rfbClientPtr cl, uint8_t version, uint8_t code)
1119 {
1120 rfbXvpMsg xvp;
1121
1122 xvp.type = rfbXvp;
1123 xvp.pad = 0;
1124 xvp.version = version;
1125 xvp.code = code;
1126
1127 LOCK(cl->sendMutex);
1128 if (rfbWriteExact(cl, (char *)&xvp, sz_rfbXvpMsg) < 0) {
1129 rfbLogPerror("rfbSendXvp: write");
1130 rfbCloseClient(cl);
1131 }
1132 UNLOCK(cl->sendMutex);
1133
1134 rfbStatRecordMessageSent(cl, rfbXvp, sz_rfbXvpMsg, sz_rfbXvpMsg);
1135
1136 return TRUE;
1137 }
1138
1139
rfbSendTextChatMessage(rfbClientPtr cl,uint32_t length,char * buffer)1140 rfbBool rfbSendTextChatMessage(rfbClientPtr cl, uint32_t length, char *buffer)
1141 {
1142 rfbTextChatMsg tc;
1143 int bytesToSend=0;
1144
1145 memset((char *)&tc, 0, sizeof(tc));
1146 tc.type = rfbTextChat;
1147 tc.length = Swap32IfLE(length);
1148
1149 switch(length) {
1150 case rfbTextChatOpen:
1151 case rfbTextChatClose:
1152 case rfbTextChatFinished:
1153 bytesToSend=0;
1154 break;
1155 default:
1156 bytesToSend=length;
1157 if (bytesToSend>rfbTextMaxSize)
1158 bytesToSend=rfbTextMaxSize;
1159 }
1160
1161 if (cl->ublen + sz_rfbTextChatMsg + bytesToSend > UPDATE_BUF_SIZE) {
1162 if (!rfbSendUpdateBuf(cl))
1163 return FALSE;
1164 }
1165
1166 memcpy(&cl->updateBuf[cl->ublen], (char *)&tc, sz_rfbTextChatMsg);
1167 cl->ublen += sz_rfbTextChatMsg;
1168 if (bytesToSend>0) {
1169 memcpy(&cl->updateBuf[cl->ublen], buffer, bytesToSend);
1170 cl->ublen += bytesToSend;
1171 }
1172 rfbStatRecordMessageSent(cl, rfbTextChat, sz_rfbTextChatMsg+bytesToSend, sz_rfbTextChatMsg+bytesToSend);
1173
1174 if (!rfbSendUpdateBuf(cl))
1175 return FALSE;
1176
1177 return TRUE;
1178 }
1179
1180 #define FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN(msg, cl, ret) \
1181 if ((cl->screen->getFileTransferPermission != NULL \
1182 && cl->screen->getFileTransferPermission(cl) != TRUE) \
1183 || cl->screen->permitFileTransfer != TRUE) { \
1184 rfbLog("%sUltra File Transfer is disabled, dropping client: %s\n", msg, cl->host); \
1185 rfbCloseClient(cl); \
1186 return ret; \
1187 }
1188
1189 int DB = 1;
1190
rfbSendFileTransferMessage(rfbClientPtr cl,uint8_t contentType,uint8_t contentParam,uint32_t size,uint32_t length,const char * buffer)1191 rfbBool rfbSendFileTransferMessage(rfbClientPtr cl, uint8_t contentType, uint8_t contentParam, uint32_t size, uint32_t length, const char *buffer)
1192 {
1193 rfbFileTransferMsg ft;
1194 ft.type = rfbFileTransfer;
1195 ft.contentType = contentType;
1196 ft.contentParam = contentParam;
1197 ft.pad = 0; /* UltraVNC did not Swap16LE(ft.contentParam) (Looks like it might be BigEndian) */
1198 ft.size = Swap32IfLE(size);
1199 ft.length = Swap32IfLE(length);
1200
1201 FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE);
1202 /*
1203 rfbLog("rfbSendFileTransferMessage( %dtype, %dparam, %dsize, %dlen, %p)\n", contentType, contentParam, size, length, buffer);
1204 */
1205 LOCK(cl->sendMutex);
1206 if (rfbWriteExact(cl, (char *)&ft, sz_rfbFileTransferMsg) < 0) {
1207 rfbLogPerror("rfbSendFileTransferMessage: write");
1208 rfbCloseClient(cl);
1209 UNLOCK(cl->sendMutex);
1210 return FALSE;
1211 }
1212
1213 if (length>0)
1214 {
1215 if (rfbWriteExact(cl, buffer, length) < 0) {
1216 rfbLogPerror("rfbSendFileTransferMessage: write");
1217 rfbCloseClient(cl);
1218 UNLOCK(cl->sendMutex);
1219 return FALSE;
1220 }
1221 }
1222 UNLOCK(cl->sendMutex);
1223
1224 rfbStatRecordMessageSent(cl, rfbFileTransfer, sz_rfbFileTransferMsg+length, sz_rfbFileTransferMsg+length);
1225
1226 return TRUE;
1227 }
1228
1229
1230 /*
1231 * UltraVNC uses Windows Structures
1232 */
1233 #define MAX_PATH 260
1234
1235 typedef struct {
1236 uint32_t dwLowDateTime;
1237 uint32_t dwHighDateTime;
1238 } RFB_FILETIME;
1239
1240 typedef struct {
1241 uint32_t dwFileAttributes;
1242 RFB_FILETIME ftCreationTime;
1243 RFB_FILETIME ftLastAccessTime;
1244 RFB_FILETIME ftLastWriteTime;
1245 uint32_t nFileSizeHigh;
1246 uint32_t nFileSizeLow;
1247 uint32_t dwReserved0;
1248 uint32_t dwReserved1;
1249 uint8_t cFileName[ MAX_PATH ];
1250 uint8_t cAlternateFileName[ 14 ];
1251 } RFB_FIND_DATA;
1252
1253 #define RFB_FILE_ATTRIBUTE_READONLY 0x1
1254 #define RFB_FILE_ATTRIBUTE_HIDDEN 0x2
1255 #define RFB_FILE_ATTRIBUTE_SYSTEM 0x4
1256 #define RFB_FILE_ATTRIBUTE_DIRECTORY 0x10
1257 #define RFB_FILE_ATTRIBUTE_ARCHIVE 0x20
1258 #define RFB_FILE_ATTRIBUTE_NORMAL 0x80
1259 #define RFB_FILE_ATTRIBUTE_TEMPORARY 0x100
1260 #define RFB_FILE_ATTRIBUTE_COMPRESSED 0x800
1261
rfbFilenameTranslate2UNIX(rfbClientPtr cl,char * path,char * unixPath,size_t unixPathMaxLen)1262 rfbBool rfbFilenameTranslate2UNIX(rfbClientPtr cl, /* in */ char *path, /* out */ char *unixPath, size_t unixPathMaxLen)
1263 {
1264 int x;
1265 char *home=NULL;
1266
1267 FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE);
1268
1269 /*
1270 * Do not use strncpy() - truncating the file name would probably have undesirable side effects
1271 * Instead check if destination buffer is big enough
1272 */
1273 if (strlen(path) >= unixPathMaxLen)
1274 return FALSE;
1275
1276 /* C: */
1277 if (path[0]=='C' && path[1]==':')
1278 strcpy(unixPath, &path[2]);
1279 else
1280 {
1281 home = getenv("HOME");
1282 if (home!=NULL)
1283 {
1284 /* Re-check buffer size */
1285 if ((strlen(path) + strlen(home) + 1) >= unixPathMaxLen)
1286 return FALSE;
1287
1288 strcpy(unixPath, home);
1289 strcat(unixPath,"/");
1290 strcat(unixPath, path);
1291 }
1292 else
1293 strcpy(unixPath, path);
1294 }
1295 for (x=0;x<strlen(unixPath);x++)
1296 if (unixPath[x]=='\\') unixPath[x]='/';
1297 return TRUE;
1298 }
1299
rfbFilenameTranslate2DOS(rfbClientPtr cl,char * unixPath,char * path)1300 rfbBool rfbFilenameTranslate2DOS(rfbClientPtr cl, char *unixPath, char *path)
1301 {
1302 int x;
1303
1304 FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE);
1305
1306 sprintf(path,"C:%s", unixPath);
1307 for (x=2;x<strlen(path);x++)
1308 if (path[x]=='/') path[x]='\\';
1309 return TRUE;
1310 }
1311
rfbSendDirContent(rfbClientPtr cl,int length,char * buffer)1312 rfbBool rfbSendDirContent(rfbClientPtr cl, int length, char *buffer)
1313 {
1314 char retfilename[MAX_PATH];
1315 char path[MAX_PATH];
1316 struct stat statbuf;
1317 RFB_FIND_DATA win32filename;
1318 int nOptLen = 0, retval=0;
1319 #ifdef WIN32
1320 WIN32_FIND_DATAA winFindData;
1321 HANDLE findHandle;
1322 int pathLen, basePathLength;
1323 char *basePath;
1324 #else
1325 DIR *dirp=NULL;
1326 struct dirent *direntp=NULL;
1327 #endif
1328
1329 FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE);
1330
1331 /* Client thinks we are Winblows */
1332 if (!rfbFilenameTranslate2UNIX(cl, buffer, path, sizeof(path)))
1333 return FALSE;
1334
1335 if (DB) rfbLog("rfbProcessFileTransfer() rfbDirContentRequest: rfbRDirContent: \"%s\"->\"%s\"\n",buffer, path);
1336
1337 #ifdef WIN32
1338 // Create a search string, like C:\folder\*
1339
1340 pathLen = strlen(path);
1341 basePath = malloc(pathLen + 3);
1342 memcpy(basePath, path, pathLen);
1343 basePathLength = pathLen;
1344 basePath[basePathLength] = '\\';
1345 basePath[basePathLength + 1] = '*';
1346 basePath[basePathLength + 2] = '\0';
1347
1348 // Start a search
1349 memset(&winFindData, 0, sizeof(winFindData));
1350 findHandle = FindFirstFileA(path, &winFindData);
1351 free(basePath);
1352
1353 if (findHandle == INVALID_HANDLE_VALUE)
1354 #else
1355 dirp=opendir(path);
1356 if (dirp==NULL)
1357 #endif
1358 return rfbSendFileTransferMessage(cl, rfbDirPacket, rfbADirectory, 0, 0, NULL);
1359
1360 /* send back the path name (necessary for links) */
1361 if (rfbSendFileTransferMessage(cl, rfbDirPacket, rfbADirectory, 0, length, buffer)==FALSE) return FALSE;
1362
1363 #ifdef WIN32
1364 while (findHandle != INVALID_HANDLE_VALUE)
1365 #else
1366 for (direntp=readdir(dirp); direntp!=NULL; direntp=readdir(dirp))
1367 #endif
1368 {
1369 /* get stats */
1370 #ifdef WIN32
1371 snprintf(retfilename,sizeof(retfilename),"%s/%s", path, winFindData.cFileName);
1372 #else
1373 snprintf(retfilename,sizeof(retfilename),"%s/%s", path, direntp->d_name);
1374 #endif
1375 retval = stat(retfilename, &statbuf);
1376
1377 if (retval==0)
1378 {
1379 memset((char *)&win32filename, 0, sizeof(win32filename));
1380 #ifdef WIN32
1381 win32filename.dwFileAttributes = winFindData.dwFileAttributes;
1382 win32filename.ftCreationTime.dwLowDateTime = winFindData.ftCreationTime.dwLowDateTime;
1383 win32filename.ftCreationTime.dwHighDateTime = winFindData.ftCreationTime.dwHighDateTime;
1384 win32filename.ftLastAccessTime.dwLowDateTime = winFindData.ftLastAccessTime.dwLowDateTime;
1385 win32filename.ftLastAccessTime.dwHighDateTime = winFindData.ftLastAccessTime.dwHighDateTime;
1386 win32filename.ftLastWriteTime.dwLowDateTime = winFindData.ftLastWriteTime.dwLowDateTime;
1387 win32filename.ftLastWriteTime.dwHighDateTime = winFindData.ftLastWriteTime.dwHighDateTime;
1388 win32filename.nFileSizeLow = winFindData.nFileSizeLow;
1389 win32filename.nFileSizeHigh = winFindData.nFileSizeHigh;
1390 win32filename.dwReserved0 = winFindData.dwReserved0;
1391 win32filename.dwReserved1 = winFindData.dwReserved1;
1392 strcpy((char *)win32filename.cFileName, winFindData.cFileName);
1393 strcpy((char *)win32filename.cAlternateFileName, winFindData.cAlternateFileName);
1394 #else
1395 win32filename.dwFileAttributes = Swap32IfBE(RFB_FILE_ATTRIBUTE_NORMAL);
1396 if (S_ISDIR(statbuf.st_mode))
1397 win32filename.dwFileAttributes = Swap32IfBE(RFB_FILE_ATTRIBUTE_DIRECTORY);
1398 win32filename.ftCreationTime.dwLowDateTime = Swap32IfBE(statbuf.st_ctime); /* Intel Order */
1399 win32filename.ftCreationTime.dwHighDateTime = 0;
1400 win32filename.ftLastAccessTime.dwLowDateTime = Swap32IfBE(statbuf.st_atime); /* Intel Order */
1401 win32filename.ftLastAccessTime.dwHighDateTime = 0;
1402 win32filename.ftLastWriteTime.dwLowDateTime = Swap32IfBE(statbuf.st_mtime); /* Intel Order */
1403 win32filename.ftLastWriteTime.dwHighDateTime = 0;
1404 win32filename.nFileSizeLow = Swap32IfBE(statbuf.st_size); /* Intel Order */
1405 win32filename.nFileSizeHigh = 0;
1406 win32filename.dwReserved0 = 0;
1407 win32filename.dwReserved1 = 0;
1408
1409 /* If this had the full path, we would need to translate to DOS format ("C:\") */
1410 /* rfbFilenameTranslate2DOS(cl, retfilename, win32filename.cFileName); */
1411 strcpy((char *)win32filename.cFileName, direntp->d_name);
1412 #endif
1413
1414 /* Do not show hidden files (but show how to move up the tree) */
1415 if ((strcmp((char *)win32filename.cFileName, "..")==0) || (win32filename.cFileName[0]!='.'))
1416 {
1417 nOptLen = sizeof(RFB_FIND_DATA) - MAX_PATH - 14 + strlen((char *)win32filename.cFileName);
1418 /*
1419 rfbLog("rfbProcessFileTransfer() rfbDirContentRequest: rfbRDirContent: Sending \"%s\"\n", (char *)win32filename.cFileName);
1420 */
1421 if (rfbSendFileTransferMessage(cl, rfbDirPacket, rfbADirectory, 0, nOptLen, (char *)&win32filename)==FALSE)
1422 {
1423 #ifdef WIN32
1424 FindClose(findHandle);
1425 #else
1426 closedir(dirp);
1427 #endif
1428 return FALSE;
1429 }
1430 }
1431 }
1432
1433 #ifdef WIN32
1434 if (FindNextFileA(findHandle, &winFindData) == 0)
1435 {
1436 FindClose(findHandle);
1437 findHandle = INVALID_HANDLE_VALUE;
1438 }
1439 #endif
1440 }
1441 #ifdef WIN32
1442 if (findHandle != INVALID_HANDLE_VALUE)
1443 {
1444 FindClose(findHandle);
1445 }
1446 #else
1447 closedir(dirp);
1448 #endif
1449 /* End of the transfer */
1450 return rfbSendFileTransferMessage(cl, rfbDirPacket, 0, 0, 0, NULL);
1451 }
1452
1453
rfbProcessFileTransferReadBuffer(rfbClientPtr cl,uint32_t length)1454 char *rfbProcessFileTransferReadBuffer(rfbClientPtr cl, uint32_t length)
1455 {
1456 char *buffer=NULL;
1457 int n=0;
1458
1459 FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, NULL);
1460 /*
1461 rfbLog("rfbProcessFileTransferReadBuffer(%dlen)\n", length);
1462 */
1463 if (length>0) {
1464 buffer=malloc(length+1);
1465 if (buffer!=NULL) {
1466 if ((n = rfbReadExact(cl, (char *)buffer, length)) <= 0) {
1467 if (n != 0)
1468 rfbLogPerror("rfbProcessFileTransferReadBuffer: read");
1469 rfbCloseClient(cl);
1470 /* NOTE: don't forget to free(buffer) if you return early! */
1471 if (buffer!=NULL) free(buffer);
1472 return NULL;
1473 }
1474 /* Null Terminate */
1475 buffer[length]=0;
1476 }
1477 }
1478 return buffer;
1479 }
1480
1481
rfbSendFileTransferChunk(rfbClientPtr cl)1482 rfbBool rfbSendFileTransferChunk(rfbClientPtr cl)
1483 {
1484 /* Allocate buffer for compression */
1485 unsigned char readBuf[sz_rfbBlockSize];
1486 int bytesRead=0;
1487 int retval=0;
1488 fd_set wfds;
1489 struct timeval tv;
1490 int n;
1491 #ifdef LIBVNCSERVER_HAVE_LIBZ
1492 unsigned char compBuf[sz_rfbBlockSize + 1024];
1493 unsigned long nMaxCompSize = sizeof(compBuf);
1494 int nRetC = 0;
1495 #endif
1496
1497 /*
1498 * Don't close the client if we get into this one because
1499 * it is called from many places to service file transfers.
1500 * Note that permitFileTransfer is checked first.
1501 */
1502 if (cl->screen->permitFileTransfer != TRUE ||
1503 (cl->screen->getFileTransferPermission != NULL
1504 && cl->screen->getFileTransferPermission(cl) != TRUE)) {
1505 return TRUE;
1506 }
1507
1508 /* If not sending, or no file open... Return as if we sent something! */
1509 if ((cl->fileTransfer.fd!=-1) && (cl->fileTransfer.sending==1))
1510 {
1511 FD_ZERO(&wfds);
1512 FD_SET(cl->sock, &wfds);
1513
1514 /* return immediately */
1515 tv.tv_sec = 0;
1516 tv.tv_usec = 0;
1517 n = select(cl->sock + 1, NULL, &wfds, NULL, &tv);
1518
1519 if (n<0) {
1520 #ifdef WIN32
1521 errno=WSAGetLastError();
1522 #endif
1523 rfbLog("rfbSendFileTransferChunk() select failed: %s\n", strerror(errno));
1524 }
1525 /* We have space on the transmit queue */
1526 if (n > 0)
1527 {
1528 bytesRead = read(cl->fileTransfer.fd, readBuf, sz_rfbBlockSize);
1529 switch (bytesRead) {
1530 case 0:
1531 /*
1532 rfbLog("rfbSendFileTransferChunk(): End-Of-File Encountered\n");
1533 */
1534 retval = rfbSendFileTransferMessage(cl, rfbEndOfFile, 0, 0, 0, NULL);
1535 close(cl->fileTransfer.fd);
1536 cl->fileTransfer.fd = -1;
1537 cl->fileTransfer.sending = 0;
1538 cl->fileTransfer.receiving = 0;
1539 return retval;
1540 case -1:
1541 /* TODO : send an error msg to the client... */
1542 #ifdef WIN32
1543 errno=WSAGetLastError();
1544 #endif
1545 rfbLog("rfbSendFileTransferChunk(): %s\n",strerror(errno));
1546 retval = rfbSendFileTransferMessage(cl, rfbAbortFileTransfer, 0, 0, 0, NULL);
1547 close(cl->fileTransfer.fd);
1548 cl->fileTransfer.fd = -1;
1549 cl->fileTransfer.sending = 0;
1550 cl->fileTransfer.receiving = 0;
1551 return retval;
1552 default:
1553 /*
1554 rfbLog("rfbSendFileTransferChunk(): Read %d bytes\n", bytesRead);
1555 */
1556 if (!cl->fileTransfer.compressionEnabled)
1557 return rfbSendFileTransferMessage(cl, rfbFilePacket, 0, 0, bytesRead, (char *)readBuf);
1558 else
1559 {
1560 #ifdef LIBVNCSERVER_HAVE_LIBZ
1561 nRetC = compress(compBuf, &nMaxCompSize, readBuf, bytesRead);
1562 /*
1563 rfbLog("Compressed the packet from %d -> %d bytes\n", nMaxCompSize, bytesRead);
1564 */
1565
1566 if ((nRetC==0) && (nMaxCompSize<bytesRead))
1567 return rfbSendFileTransferMessage(cl, rfbFilePacket, 0, 1, nMaxCompSize, (char *)compBuf);
1568 else
1569 return rfbSendFileTransferMessage(cl, rfbFilePacket, 0, 0, bytesRead, (char *)readBuf);
1570 #else
1571 /* We do not support compression of the data stream */
1572 return rfbSendFileTransferMessage(cl, rfbFilePacket, 0, 0, bytesRead, (char *)readBuf);
1573 #endif
1574 }
1575 }
1576 }
1577 }
1578 return TRUE;
1579 }
1580
rfbProcessFileTransfer(rfbClientPtr cl,uint8_t contentType,uint8_t contentParam,uint32_t size,uint32_t length)1581 rfbBool rfbProcessFileTransfer(rfbClientPtr cl, uint8_t contentType, uint8_t contentParam, uint32_t size, uint32_t length)
1582 {
1583 char *buffer=NULL, *p=NULL;
1584 int retval=0;
1585 char filename1[MAX_PATH];
1586 char filename2[MAX_PATH];
1587 char szFileTime[MAX_PATH];
1588 struct stat statbuf;
1589 uint32_t sizeHtmp=0;
1590 int n=0;
1591 char timespec[64];
1592 #ifdef LIBVNCSERVER_HAVE_LIBZ
1593 unsigned char compBuff[sz_rfbBlockSize];
1594 unsigned long nRawBytes = sz_rfbBlockSize;
1595 int nRet = 0;
1596 #endif
1597
1598 FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE);
1599
1600 /*
1601 rfbLog("rfbProcessFileTransfer(%dtype, %dparam, %dsize, %dlen)\n", contentType, contentParam, size, length);
1602 */
1603
1604 switch (contentType) {
1605 case rfbDirContentRequest:
1606 switch (contentParam) {
1607 case rfbRDrivesList: /* Client requests the List of Local Drives */
1608 /*
1609 rfbLog("rfbProcessFileTransfer() rfbDirContentRequest: rfbRDrivesList:\n");
1610 */
1611 /* Format when filled : "C:\<NULL>D:\<NULL>....Z:\<NULL><NULL>
1612 *
1613 * We replace the "\" char following the drive letter and ":"
1614 * with a char corresponding to the type of drive
1615 * We obtain something like "C:l<NULL>D:c<NULL>....Z:n\<NULL><NULL>"
1616 * Isn't it ugly ?
1617 * DRIVE_FIXED = 'l' (local?)
1618 * DRIVE_REMOVABLE = 'f' (floppy?)
1619 * DRIVE_CDROM = 'c'
1620 * DRIVE_REMOTE = 'n'
1621 */
1622
1623 /* in unix, there are no 'drives' (We could list mount points though)
1624 * We fake the root as a "C:" for the Winblows users
1625 */
1626 filename2[0]='C';
1627 filename2[1]=':';
1628 filename2[2]='l';
1629 filename2[3]=0;
1630 filename2[4]=0;
1631 retval = rfbSendFileTransferMessage(cl, rfbDirPacket, rfbADrivesList, 0, 5, filename2);
1632 if (buffer!=NULL) free(buffer);
1633 return retval;
1634 break;
1635 case rfbRDirContent: /* Client requests the content of a directory */
1636 /*
1637 rfbLog("rfbProcessFileTransfer() rfbDirContentRequest: rfbRDirContent\n");
1638 */
1639 if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
1640 retval = rfbSendDirContent(cl, length, buffer);
1641 if (buffer!=NULL) free(buffer);
1642 return retval;
1643 }
1644 break;
1645
1646 case rfbDirPacket:
1647 rfbLog("rfbProcessFileTransfer() rfbDirPacket\n");
1648 break;
1649 case rfbFileAcceptHeader:
1650 rfbLog("rfbProcessFileTransfer() rfbFileAcceptHeader\n");
1651 break;
1652 case rfbCommandReturn:
1653 rfbLog("rfbProcessFileTransfer() rfbCommandReturn\n");
1654 break;
1655 case rfbFileChecksums:
1656 /* Destination file already exists - the viewer sends the checksums */
1657 rfbLog("rfbProcessFileTransfer() rfbFileChecksums\n");
1658 break;
1659 case rfbFileTransferAccess:
1660 rfbLog("rfbProcessFileTransfer() rfbFileTransferAccess\n");
1661 break;
1662
1663 /*
1664 * sending from the server to the viewer
1665 */
1666
1667 case rfbFileTransferRequest:
1668 /*
1669 rfbLog("rfbProcessFileTransfer() rfbFileTransferRequest:\n");
1670 */
1671 /* add some space to the end of the buffer as we will be adding a timespec to it */
1672 if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
1673 /* The client requests a File */
1674 if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1)))
1675 goto fail;
1676 cl->fileTransfer.fd=open(filename1, O_RDONLY, 0744);
1677
1678 /*
1679 */
1680 if (DB) rfbLog("rfbProcessFileTransfer() rfbFileTransferRequest(\"%s\"->\"%s\") Open: %s fd=%d\n", buffer, filename1, (cl->fileTransfer.fd==-1?"Failed":"Success"), cl->fileTransfer.fd);
1681
1682 if (cl->fileTransfer.fd!=-1) {
1683 if (fstat(cl->fileTransfer.fd, &statbuf)!=0) {
1684 close(cl->fileTransfer.fd);
1685 cl->fileTransfer.fd=-1;
1686 }
1687 else
1688 {
1689 /* Add the File Time Stamp to the filename */
1690 strftime(timespec, sizeof(timespec), "%m/%d/%Y %H:%M",gmtime(&statbuf.st_ctime));
1691 buffer=realloc(buffer, length + strlen(timespec) + 2); /* comma, and Null term */
1692 if (buffer==NULL) {
1693 rfbLog("rfbProcessFileTransfer() rfbFileTransferRequest: Failed to malloc %d bytes\n", length + strlen(timespec) + 2);
1694 return FALSE;
1695 }
1696 strcat(buffer,",");
1697 strcat(buffer, timespec);
1698 length = strlen(buffer);
1699 if (DB) rfbLog("rfbProcessFileTransfer() buffer is now: \"%s\"\n", buffer);
1700 }
1701 }
1702
1703 /* The viewer supports compression if size==1 */
1704 cl->fileTransfer.compressionEnabled = (size==1);
1705
1706 /*
1707 rfbLog("rfbProcessFileTransfer() rfbFileTransferRequest(\"%s\"->\"%s\")%s\n", buffer, filename1, (size==1?" <Compression Enabled>":""));
1708 */
1709
1710 /* File Size in bytes, 0xFFFFFFFF (-1) means error */
1711 retval = rfbSendFileTransferMessage(cl, rfbFileHeader, 0, (cl->fileTransfer.fd==-1 ? -1 : statbuf.st_size), length, buffer);
1712
1713 if (cl->fileTransfer.fd==-1)
1714 {
1715 if (buffer!=NULL) free(buffer);
1716 return retval;
1717 }
1718 /* setup filetransfer stuff */
1719 cl->fileTransfer.fileSize = statbuf.st_size;
1720 cl->fileTransfer.numPackets = statbuf.st_size / sz_rfbBlockSize;
1721 cl->fileTransfer.receiving = 0;
1722 cl->fileTransfer.sending = 0; /* set when we receive a rfbFileHeader: */
1723
1724 /* TODO: finish 64-bit file size support */
1725 sizeHtmp = 0;
1726 LOCK(cl->sendMutex);
1727 if (rfbWriteExact(cl, (char *)&sizeHtmp, 4) < 0) {
1728 rfbLogPerror("rfbProcessFileTransfer: write");
1729 rfbCloseClient(cl);
1730 UNLOCK(cl->sendMutex);
1731 if (buffer!=NULL) free(buffer);
1732 return FALSE;
1733 }
1734 UNLOCK(cl->sendMutex);
1735 break;
1736
1737 case rfbFileHeader:
1738 /* Destination file (viewer side) is ready for reception (size > 0) or not (size = -1) */
1739 if (size==-1) {
1740 rfbLog("rfbProcessFileTransfer() rfbFileHeader (error, aborting)\n");
1741 close(cl->fileTransfer.fd);
1742 cl->fileTransfer.fd=-1;
1743 return TRUE;
1744 }
1745
1746 /*
1747 rfbLog("rfbProcessFileTransfer() rfbFileHeader (%d bytes of a file)\n", size);
1748 */
1749
1750 /* Starts the transfer! */
1751 cl->fileTransfer.sending=1;
1752 return rfbSendFileTransferChunk(cl);
1753 break;
1754
1755
1756 /*
1757 * sending from the viewer to the server
1758 */
1759
1760 case rfbFileTransferOffer:
1761 /* client is sending a file to us */
1762 /* buffer contains full path name (plus FileTime) */
1763 /* size contains size of the file */
1764 /*
1765 rfbLog("rfbProcessFileTransfer() rfbFileTransferOffer:\n");
1766 */
1767 if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
1768
1769 /* Parse the FileTime */
1770 p = strrchr(buffer, ',');
1771 if (p!=NULL) {
1772 *p = '\0';
1773 strncpy(szFileTime, p+1, sizeof(szFileTime));
1774 szFileTime[sizeof(szFileTime)-1] = '\x00'; /* ensure NULL terminating byte is present, even if copy overflowed */
1775 } else
1776 szFileTime[0]=0;
1777
1778
1779
1780 /* Need to read in sizeHtmp */
1781 if ((n = rfbReadExact(cl, (char *)&sizeHtmp, 4)) <= 0) {
1782 if (n != 0)
1783 rfbLogPerror("rfbProcessFileTransfer: read sizeHtmp");
1784 rfbCloseClient(cl);
1785 /* NOTE: don't forget to free(buffer) if you return early! */
1786 if (buffer!=NULL) free(buffer);
1787 return FALSE;
1788 }
1789 sizeHtmp = Swap32IfLE(sizeHtmp);
1790
1791 if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1)))
1792 goto fail;
1793
1794 /* If the file exists... We can send a rfbFileChecksums back to the client before we send an rfbFileAcceptHeader */
1795 /* TODO: Delta Transfer */
1796
1797 cl->fileTransfer.fd=open(filename1, O_CREAT|O_WRONLY|O_TRUNC, 0744);
1798 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);
1799 /*
1800 */
1801
1802 /* File Size in bytes, 0xFFFFFFFF (-1) means error */
1803 retval = rfbSendFileTransferMessage(cl, rfbFileAcceptHeader, 0, (cl->fileTransfer.fd==-1 ? -1 : 0), length, buffer);
1804 if (cl->fileTransfer.fd==-1) {
1805 free(buffer);
1806 return retval;
1807 }
1808
1809 /* setup filetransfer stuff */
1810 cl->fileTransfer.fileSize = size;
1811 cl->fileTransfer.numPackets = size / sz_rfbBlockSize;
1812 cl->fileTransfer.receiving = 1;
1813 cl->fileTransfer.sending = 0;
1814 break;
1815
1816 case rfbFilePacket:
1817 /*
1818 rfbLog("rfbProcessFileTransfer() rfbFilePacket:\n");
1819 */
1820 if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
1821 if (cl->fileTransfer.fd!=-1) {
1822 /* buffer contains the contents of the file */
1823 if (size==0)
1824 retval=write(cl->fileTransfer.fd, buffer, length);
1825 else
1826 {
1827 #ifdef LIBVNCSERVER_HAVE_LIBZ
1828 /* compressed packet */
1829 nRet = uncompress(compBuff,&nRawBytes,(const unsigned char*)buffer, length);
1830 if(nRet == Z_OK)
1831 retval=write(cl->fileTransfer.fd, (char*)compBuff, nRawBytes);
1832 else
1833 retval = -1;
1834 #else
1835 /* Write the file out as received... */
1836 retval=write(cl->fileTransfer.fd, buffer, length);
1837 #endif
1838 }
1839 if (retval==-1)
1840 {
1841 close(cl->fileTransfer.fd);
1842 cl->fileTransfer.fd=-1;
1843 cl->fileTransfer.sending = 0;
1844 cl->fileTransfer.receiving = 0;
1845 }
1846 }
1847 break;
1848
1849 case rfbEndOfFile:
1850 if (DB) rfbLog("rfbProcessFileTransfer() rfbEndOfFile\n");
1851 /*
1852 */
1853 if (cl->fileTransfer.fd!=-1)
1854 close(cl->fileTransfer.fd);
1855 cl->fileTransfer.fd=-1;
1856 cl->fileTransfer.sending = 0;
1857 cl->fileTransfer.receiving = 0;
1858 break;
1859
1860 case rfbAbortFileTransfer:
1861 if (DB) rfbLog("rfbProcessFileTransfer() rfbAbortFileTransfer\n");
1862 /*
1863 */
1864 if (cl->fileTransfer.fd!=-1)
1865 {
1866 close(cl->fileTransfer.fd);
1867 cl->fileTransfer.fd=-1;
1868 cl->fileTransfer.sending = 0;
1869 cl->fileTransfer.receiving = 0;
1870 }
1871 else
1872 {
1873 /* We use this message for FileTransfer rights (<=RC18 versions)
1874 * The client asks for FileTransfer permission
1875 */
1876 if (contentParam == 0)
1877 {
1878 rfbLog("rfbProcessFileTransfer() File Transfer Permission DENIED! (Client Version <=RC18)\n");
1879 /* Old method for FileTransfer handshake perimssion (<=RC18) (Deny it)*/
1880 return rfbSendFileTransferMessage(cl, rfbAbortFileTransfer, 0, -1, 0, "");
1881 }
1882 /* New method is allowed */
1883 if (cl->screen->getFileTransferPermission!=NULL)
1884 {
1885 if (cl->screen->getFileTransferPermission(cl)==TRUE)
1886 {
1887 rfbLog("rfbProcessFileTransfer() File Transfer Permission Granted!\n");
1888 return rfbSendFileTransferMessage(cl, rfbFileTransferAccess, 0, 1 , 0, ""); /* Permit */
1889 }
1890 else
1891 {
1892 rfbLog("rfbProcessFileTransfer() File Transfer Permission DENIED!\n");
1893 return rfbSendFileTransferMessage(cl, rfbFileTransferAccess, 0, -1 , 0, ""); /* Deny */
1894 }
1895 }
1896 else
1897 {
1898 if (cl->screen->permitFileTransfer)
1899 {
1900 rfbLog("rfbProcessFileTransfer() File Transfer Permission Granted!\n");
1901 return rfbSendFileTransferMessage(cl, rfbFileTransferAccess, 0, 1 , 0, ""); /* Permit */
1902 }
1903 else
1904 {
1905 rfbLog("rfbProcessFileTransfer() File Transfer Permission DENIED by default!\n");
1906 return rfbSendFileTransferMessage(cl, rfbFileTransferAccess, 0, -1 , 0, ""); /* DEFAULT: DENY (for security) */
1907 }
1908
1909 }
1910 }
1911 break;
1912
1913
1914 case rfbCommand:
1915 /*
1916 rfbLog("rfbProcessFileTransfer() rfbCommand:\n");
1917 */
1918 if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
1919 switch (contentParam) {
1920 case rfbCDirCreate: /* Client requests the creation of a directory */
1921 if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1)))
1922 goto fail;
1923 retval = mkdir(filename1, 0755);
1924 if (DB) rfbLog("rfbProcessFileTransfer() rfbCommand: rfbCDirCreate(\"%s\"->\"%s\") %s\n", buffer, filename1, (retval==-1?"Failed":"Success"));
1925 /*
1926 */
1927 retval = rfbSendFileTransferMessage(cl, rfbCommandReturn, rfbADirCreate, retval, length, buffer);
1928 if (buffer!=NULL) free(buffer);
1929 return retval;
1930 case rfbCFileDelete: /* Client requests the deletion of a file */
1931 if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1)))
1932 goto fail;
1933 if (stat(filename1,&statbuf)==0)
1934 {
1935 if (S_ISDIR(statbuf.st_mode))
1936 retval = rmdir(filename1);
1937 else
1938 retval = unlink(filename1);
1939 }
1940 else retval=-1;
1941 retval = rfbSendFileTransferMessage(cl, rfbCommandReturn, rfbAFileDelete, retval, length, buffer);
1942 if (buffer!=NULL) free(buffer);
1943 return retval;
1944 case rfbCFileRename: /* Client requests the Renaming of a file/directory */
1945 p = strrchr(buffer, '*');
1946 if (p != NULL)
1947 {
1948 /* Split into 2 filenames ('*' is a seperator) */
1949 *p = '\0';
1950 if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1)))
1951 goto fail;
1952 if (!rfbFilenameTranslate2UNIX(cl, p+1, filename2, sizeof(filename2)))
1953 goto fail;
1954 retval = rename(filename1,filename2);
1955 if (DB) rfbLog("rfbProcessFileTransfer() rfbCommand: rfbCFileRename(\"%s\"->\"%s\" -->> \"%s\"->\"%s\") %s\n", buffer, filename1, p+1, filename2, (retval==-1?"Failed":"Success"));
1956 /*
1957 */
1958 /* Restore the buffer so the reply is good */
1959 *p = '*';
1960 retval = rfbSendFileTransferMessage(cl, rfbCommandReturn, rfbAFileRename, retval, length, buffer);
1961 if (buffer!=NULL) free(buffer);
1962 return retval;
1963 }
1964 break;
1965 }
1966
1967 break;
1968 }
1969
1970 /* NOTE: don't forget to free(buffer) if you return early! */
1971 if (buffer!=NULL) free(buffer);
1972 return TRUE;
1973
1974 fail:
1975 if (buffer!=NULL) free(buffer);
1976 return FALSE;
1977 }
1978
1979 /*
1980 * rfbProcessClientNormalMessage is called when the client has sent a normal
1981 * protocol message.
1982 */
1983
1984 static void
rfbProcessClientNormalMessage(rfbClientPtr cl)1985 rfbProcessClientNormalMessage(rfbClientPtr cl)
1986 {
1987 int n=0;
1988 rfbClientToServerMsg msg;
1989 char *str;
1990 int i;
1991 uint32_t enc=0;
1992 uint32_t lastPreferredEncoding = -1;
1993 char encBuf[64];
1994 char encBuf2[64];
1995
1996 #ifdef LIBVNCSERVER_WITH_WEBSOCKETS
1997 if (cl->wsctx && webSocketCheckDisconnect(cl))
1998 return;
1999 #endif
2000
2001 if ((n = rfbReadExact(cl, (char *)&msg, 1)) <= 0) {
2002 if (n != 0)
2003 rfbLogPerror("rfbProcessClientNormalMessage: read");
2004 rfbCloseClient(cl);
2005 return;
2006 }
2007
2008 switch (msg.type) {
2009
2010 case rfbSetPixelFormat:
2011
2012 if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2013 sz_rfbSetPixelFormatMsg - 1)) <= 0) {
2014 if (n != 0)
2015 rfbLogPerror("rfbProcessClientNormalMessage: read");
2016 rfbCloseClient(cl);
2017 return;
2018 }
2019
2020 cl->format.bitsPerPixel = msg.spf.format.bitsPerPixel;
2021 cl->format.depth = msg.spf.format.depth;
2022 cl->format.bigEndian = (msg.spf.format.bigEndian ? TRUE : FALSE);
2023 cl->format.trueColour = (msg.spf.format.trueColour ? TRUE : FALSE);
2024 cl->format.redMax = Swap16IfLE(msg.spf.format.redMax);
2025 cl->format.greenMax = Swap16IfLE(msg.spf.format.greenMax);
2026 cl->format.blueMax = Swap16IfLE(msg.spf.format.blueMax);
2027 cl->format.redShift = msg.spf.format.redShift;
2028 cl->format.greenShift = msg.spf.format.greenShift;
2029 cl->format.blueShift = msg.spf.format.blueShift;
2030
2031 cl->readyForSetColourMapEntries = TRUE;
2032 cl->screen->setTranslateFunction(cl);
2033
2034 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetPixelFormatMsg, sz_rfbSetPixelFormatMsg);
2035
2036 return;
2037
2038
2039 case rfbFixColourMapEntries:
2040 if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2041 sz_rfbFixColourMapEntriesMsg - 1)) <= 0) {
2042 if (n != 0)
2043 rfbLogPerror("rfbProcessClientNormalMessage: read");
2044 rfbCloseClient(cl);
2045 return;
2046 }
2047 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetPixelFormatMsg, sz_rfbSetPixelFormatMsg);
2048 rfbLog("rfbProcessClientNormalMessage: %s",
2049 "FixColourMapEntries unsupported\n");
2050 rfbCloseClient(cl);
2051 return;
2052
2053
2054 /* NOTE: Some clients send us a set of encodings (ie: PointerPos) designed to enable/disable features...
2055 * We may want to look into this...
2056 * Example:
2057 * case rfbEncodingXCursor:
2058 * cl->enableCursorShapeUpdates = TRUE;
2059 *
2060 * Currently: cl->enableCursorShapeUpdates can *never* be turned off...
2061 */
2062 case rfbSetEncodings:
2063 {
2064
2065 if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2066 sz_rfbSetEncodingsMsg - 1)) <= 0) {
2067 if (n != 0)
2068 rfbLogPerror("rfbProcessClientNormalMessage: read");
2069 rfbCloseClient(cl);
2070 return;
2071 }
2072
2073 msg.se.nEncodings = Swap16IfLE(msg.se.nEncodings);
2074
2075 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetEncodingsMsg+(msg.se.nEncodings*4),sz_rfbSetEncodingsMsg+(msg.se.nEncodings*4));
2076
2077 /*
2078 * UltraVNC Client has the ability to adapt to changing network environments
2079 * So, let's give it a change to tell us what it wants now!
2080 */
2081 if (cl->preferredEncoding!=-1)
2082 lastPreferredEncoding = cl->preferredEncoding;
2083
2084 /* Reset all flags to defaults (allows us to switch between PointerPos and Server Drawn Cursors) */
2085 cl->preferredEncoding=-1;
2086 cl->useCopyRect = FALSE;
2087 cl->useNewFBSize = FALSE;
2088 cl->cursorWasChanged = FALSE;
2089 cl->useRichCursorEncoding = FALSE;
2090 cl->enableCursorPosUpdates = FALSE;
2091 cl->enableCursorShapeUpdates = FALSE;
2092 cl->enableCursorShapeUpdates = FALSE;
2093 cl->enableLastRectEncoding = FALSE;
2094 cl->enableKeyboardLedState = FALSE;
2095 cl->enableSupportedMessages = FALSE;
2096 cl->enableSupportedEncodings = FALSE;
2097 cl->enableServerIdentity = FALSE;
2098 #if defined(LIBVNCSERVER_HAVE_LIBZ) || defined(LIBVNCSERVER_HAVE_LIBPNG)
2099 cl->tightQualityLevel = -1;
2100 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
2101 cl->tightCompressLevel = TIGHT_DEFAULT_COMPRESSION;
2102 cl->turboSubsampLevel = TURBO_DEFAULT_SUBSAMP;
2103 cl->turboQualityLevel = -1;
2104 #endif
2105 #endif
2106
2107
2108 for (i = 0; i < msg.se.nEncodings; i++) {
2109 if ((n = rfbReadExact(cl, (char *)&enc, 4)) <= 0) {
2110 if (n != 0)
2111 rfbLogPerror("rfbProcessClientNormalMessage: read");
2112 rfbCloseClient(cl);
2113 return;
2114 }
2115 enc = Swap32IfLE(enc);
2116
2117 switch (enc) {
2118
2119 case rfbEncodingCopyRect:
2120 cl->useCopyRect = TRUE;
2121 break;
2122 case rfbEncodingRaw:
2123 case rfbEncodingRRE:
2124 case rfbEncodingCoRRE:
2125 case rfbEncodingHextile:
2126 case rfbEncodingUltra:
2127 #ifdef LIBVNCSERVER_HAVE_LIBZ
2128 case rfbEncodingZlib:
2129 case rfbEncodingZRLE:
2130 case rfbEncodingZYWRLE:
2131 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
2132 case rfbEncodingTight:
2133 #endif
2134 #endif
2135 #ifdef LIBVNCSERVER_HAVE_LIBPNG
2136 case rfbEncodingTightPng:
2137 #endif
2138 /* The first supported encoding is the 'preferred' encoding */
2139 if (cl->preferredEncoding == -1)
2140 cl->preferredEncoding = enc;
2141
2142
2143 break;
2144 case rfbEncodingXCursor:
2145 if(!cl->screen->dontConvertRichCursorToXCursor) {
2146 rfbLog("Enabling X-style cursor updates for client %s\n",
2147 cl->host);
2148 /* if cursor was drawn, hide the cursor */
2149 if(!cl->enableCursorShapeUpdates)
2150 rfbRedrawAfterHideCursor(cl,NULL);
2151
2152 cl->enableCursorShapeUpdates = TRUE;
2153 cl->cursorWasChanged = TRUE;
2154 }
2155 break;
2156 case rfbEncodingRichCursor:
2157 rfbLog("Enabling full-color cursor updates for client %s\n",
2158 cl->host);
2159 /* if cursor was drawn, hide the cursor */
2160 if(!cl->enableCursorShapeUpdates)
2161 rfbRedrawAfterHideCursor(cl,NULL);
2162
2163 cl->enableCursorShapeUpdates = TRUE;
2164 cl->useRichCursorEncoding = TRUE;
2165 cl->cursorWasChanged = TRUE;
2166 break;
2167 case rfbEncodingPointerPos:
2168 if (!cl->enableCursorPosUpdates) {
2169 rfbLog("Enabling cursor position updates for client %s\n",
2170 cl->host);
2171 cl->enableCursorPosUpdates = TRUE;
2172 cl->cursorWasMoved = TRUE;
2173 }
2174 break;
2175 case rfbEncodingLastRect:
2176 if (!cl->enableLastRectEncoding) {
2177 rfbLog("Enabling LastRect protocol extension for client "
2178 "%s\n", cl->host);
2179 cl->enableLastRectEncoding = TRUE;
2180 }
2181 break;
2182 case rfbEncodingNewFBSize:
2183 if (!cl->useNewFBSize) {
2184 rfbLog("Enabling NewFBSize protocol extension for client "
2185 "%s\n", cl->host);
2186 cl->useNewFBSize = TRUE;
2187 }
2188 break;
2189 case rfbEncodingKeyboardLedState:
2190 if (!cl->enableKeyboardLedState) {
2191 rfbLog("Enabling KeyboardLedState protocol extension for client "
2192 "%s\n", cl->host);
2193 cl->enableKeyboardLedState = TRUE;
2194 }
2195 break;
2196 case rfbEncodingSupportedMessages:
2197 if (!cl->enableSupportedMessages) {
2198 rfbLog("Enabling SupportedMessages protocol extension for client "
2199 "%s\n", cl->host);
2200 cl->enableSupportedMessages = TRUE;
2201 }
2202 break;
2203 case rfbEncodingSupportedEncodings:
2204 if (!cl->enableSupportedEncodings) {
2205 rfbLog("Enabling SupportedEncodings protocol extension for client "
2206 "%s\n", cl->host);
2207 cl->enableSupportedEncodings = TRUE;
2208 }
2209 break;
2210 case rfbEncodingServerIdentity:
2211 if (!cl->enableServerIdentity) {
2212 rfbLog("Enabling ServerIdentity protocol extension for client "
2213 "%s\n", cl->host);
2214 cl->enableServerIdentity = TRUE;
2215 }
2216 break;
2217 case rfbEncodingXvp:
2218 rfbLog("Enabling Xvp protocol extension for client "
2219 "%s\n", cl->host);
2220 if (!rfbSendXvp(cl, 1, rfbXvp_Init)) {
2221 rfbCloseClient(cl);
2222 return;
2223 }
2224 break;
2225 default:
2226 #if defined(LIBVNCSERVER_HAVE_LIBZ) || defined(LIBVNCSERVER_HAVE_LIBPNG)
2227 if ( enc >= (uint32_t)rfbEncodingCompressLevel0 &&
2228 enc <= (uint32_t)rfbEncodingCompressLevel9 ) {
2229 cl->zlibCompressLevel = enc & 0x0F;
2230 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
2231 cl->tightCompressLevel = enc & 0x0F;
2232 rfbLog("Using compression level %d for client %s\n",
2233 cl->tightCompressLevel, cl->host);
2234 #endif
2235 } else if ( enc >= (uint32_t)rfbEncodingQualityLevel0 &&
2236 enc <= (uint32_t)rfbEncodingQualityLevel9 ) {
2237 cl->tightQualityLevel = enc & 0x0F;
2238 rfbLog("Using image quality level %d for client %s\n",
2239 cl->tightQualityLevel, cl->host);
2240 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
2241 cl->turboQualityLevel = tight2turbo_qual[enc & 0x0F];
2242 cl->turboSubsampLevel = tight2turbo_subsamp[enc & 0x0F];
2243 rfbLog("Using JPEG subsampling %d, Q%d for client %s\n",
2244 cl->turboSubsampLevel, cl->turboQualityLevel, cl->host);
2245 } else if ( enc >= (uint32_t)rfbEncodingFineQualityLevel0 + 1 &&
2246 enc <= (uint32_t)rfbEncodingFineQualityLevel100 ) {
2247 cl->turboQualityLevel = enc & 0xFF;
2248 rfbLog("Using fine quality level %d for client %s\n",
2249 cl->turboQualityLevel, cl->host);
2250 } else if ( enc >= (uint32_t)rfbEncodingSubsamp1X &&
2251 enc <= (uint32_t)rfbEncodingSubsampGray ) {
2252 cl->turboSubsampLevel = enc & 0xFF;
2253 rfbLog("Using subsampling level %d for client %s\n",
2254 cl->turboSubsampLevel, cl->host);
2255 #endif
2256 } else
2257 #endif
2258 {
2259 rfbExtensionData* e;
2260 for(e = cl->extensions; e;) {
2261 rfbExtensionData* next = e->next;
2262 if(e->extension->enablePseudoEncoding &&
2263 e->extension->enablePseudoEncoding(cl,
2264 &e->data, (int)enc))
2265 /* ext handles this encoding */
2266 break;
2267 e = next;
2268 }
2269 if(e == NULL) {
2270 rfbBool handled = FALSE;
2271 /* if the pseudo encoding is not handled by the
2272 enabled extensions, search through all
2273 extensions. */
2274 rfbProtocolExtension* e;
2275
2276 for(e = rfbGetExtensionIterator(); e;) {
2277 int* encs = e->pseudoEncodings;
2278 while(encs && *encs!=0) {
2279 if(*encs==(int)enc) {
2280 void* data = NULL;
2281 if(!e->enablePseudoEncoding(cl, &data, (int)enc)) {
2282 rfbLog("Installed extension pretends to handle pseudo encoding 0x%x, but does not!\n",(int)enc);
2283 } else {
2284 rfbEnableExtension(cl, e, data);
2285 handled = TRUE;
2286 e = NULL;
2287 break;
2288 }
2289 }
2290 encs++;
2291 }
2292
2293 if(e)
2294 e = e->next;
2295 }
2296 rfbReleaseExtensionIterator();
2297
2298 if(!handled)
2299 rfbLog("rfbProcessClientNormalMessage: "
2300 "ignoring unsupported encoding type %s\n",
2301 encodingName(enc,encBuf,sizeof(encBuf)));
2302 }
2303 }
2304 }
2305 }
2306
2307
2308
2309 if (cl->preferredEncoding == -1) {
2310 if (lastPreferredEncoding==-1) {
2311 cl->preferredEncoding = rfbEncodingRaw;
2312 rfbLog("Defaulting to %s encoding for client %s\n", encodingName(cl->preferredEncoding,encBuf,sizeof(encBuf)),cl->host);
2313 }
2314 else {
2315 cl->preferredEncoding = lastPreferredEncoding;
2316 rfbLog("Sticking with %s encoding for client %s\n", encodingName(cl->preferredEncoding,encBuf,sizeof(encBuf)),cl->host);
2317 }
2318 }
2319 else
2320 {
2321 if (lastPreferredEncoding==-1) {
2322 rfbLog("Using %s encoding for client %s\n", encodingName(cl->preferredEncoding,encBuf,sizeof(encBuf)),cl->host);
2323 } else {
2324 rfbLog("Switching from %s to %s Encoding for client %s\n",
2325 encodingName(lastPreferredEncoding,encBuf2,sizeof(encBuf2)),
2326 encodingName(cl->preferredEncoding,encBuf,sizeof(encBuf)), cl->host);
2327 }
2328 }
2329
2330 if (cl->enableCursorPosUpdates && !cl->enableCursorShapeUpdates) {
2331 rfbLog("Disabling cursor position updates for client %s\n",
2332 cl->host);
2333 cl->enableCursorPosUpdates = FALSE;
2334 }
2335
2336 return;
2337 }
2338
2339
2340 case rfbFramebufferUpdateRequest:
2341 {
2342 sraRegionPtr tmpRegion;
2343
2344 if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2345 sz_rfbFramebufferUpdateRequestMsg-1)) <= 0) {
2346 if (n != 0)
2347 rfbLogPerror("rfbProcessClientNormalMessage: read");
2348 rfbCloseClient(cl);
2349 return;
2350 }
2351
2352 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbFramebufferUpdateRequestMsg,sz_rfbFramebufferUpdateRequestMsg);
2353
2354 /* The values come in based on the scaled screen, we need to convert them to
2355 * values based on the main screen's coordinate system
2356 */
2357 if(!rectSwapIfLEAndClip(&msg.fur.x,&msg.fur.y,&msg.fur.w,&msg.fur.h,cl))
2358 {
2359 rfbLog("Warning, ignoring rfbFramebufferUpdateRequest: %dXx%dY-%dWx%dH\n",msg.fur.x, msg.fur.y, msg.fur.w, msg.fur.h);
2360 return;
2361 }
2362
2363
2364 tmpRegion =
2365 sraRgnCreateRect(msg.fur.x,
2366 msg.fur.y,
2367 msg.fur.x+msg.fur.w,
2368 msg.fur.y+msg.fur.h);
2369
2370 LOCK(cl->updateMutex);
2371 sraRgnOr(cl->requestedRegion,tmpRegion);
2372
2373 if (!cl->readyForSetColourMapEntries) {
2374 /* client hasn't sent a SetPixelFormat so is using server's */
2375 cl->readyForSetColourMapEntries = TRUE;
2376 if (!cl->format.trueColour) {
2377 if (!rfbSetClientColourMap(cl, 0, 0)) {
2378 sraRgnDestroy(tmpRegion);
2379 TSIGNAL(cl->updateCond);
2380 UNLOCK(cl->updateMutex);
2381 return;
2382 }
2383 }
2384 }
2385
2386 if (!msg.fur.incremental) {
2387 sraRgnOr(cl->modifiedRegion,tmpRegion);
2388 sraRgnSubtract(cl->copyRegion,tmpRegion);
2389 }
2390 TSIGNAL(cl->updateCond);
2391 UNLOCK(cl->updateMutex);
2392
2393 sraRgnDestroy(tmpRegion);
2394
2395 return;
2396 }
2397
2398 case rfbKeyEvent:
2399
2400 if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2401 sz_rfbKeyEventMsg - 1)) <= 0) {
2402 if (n != 0)
2403 rfbLogPerror("rfbProcessClientNormalMessage: read");
2404 rfbCloseClient(cl);
2405 return;
2406 }
2407
2408 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbKeyEventMsg, sz_rfbKeyEventMsg);
2409
2410 if(!cl->viewOnly) {
2411 cl->screen->kbdAddEvent(msg.ke.down, (rfbKeySym)Swap32IfLE(msg.ke.key), cl);
2412 }
2413
2414 return;
2415
2416
2417 case rfbPointerEvent:
2418
2419 if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2420 sz_rfbPointerEventMsg - 1)) <= 0) {
2421 if (n != 0)
2422 rfbLogPerror("rfbProcessClientNormalMessage: read");
2423 rfbCloseClient(cl);
2424 return;
2425 }
2426
2427 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbPointerEventMsg, sz_rfbPointerEventMsg);
2428
2429 if (cl->screen->pointerClient && cl->screen->pointerClient != cl)
2430 return;
2431
2432 if (msg.pe.buttonMask == 0)
2433 cl->screen->pointerClient = NULL;
2434 else
2435 cl->screen->pointerClient = cl;
2436
2437 if(!cl->viewOnly) {
2438 if (msg.pe.buttonMask != cl->lastPtrButtons ||
2439 cl->screen->deferPtrUpdateTime == 0) {
2440 cl->screen->ptrAddEvent(msg.pe.buttonMask,
2441 ScaleX(cl->scaledScreen, cl->screen, Swap16IfLE(msg.pe.x)),
2442 ScaleY(cl->scaledScreen, cl->screen, Swap16IfLE(msg.pe.y)),
2443 cl);
2444 cl->lastPtrButtons = msg.pe.buttonMask;
2445 } else {
2446 cl->lastPtrX = ScaleX(cl->scaledScreen, cl->screen, Swap16IfLE(msg.pe.x));
2447 cl->lastPtrY = ScaleY(cl->scaledScreen, cl->screen, Swap16IfLE(msg.pe.y));
2448 cl->lastPtrButtons = msg.pe.buttonMask;
2449 }
2450 }
2451 return;
2452
2453
2454 case rfbFileTransfer:
2455 if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2456 sz_rfbFileTransferMsg - 1)) <= 0) {
2457 if (n != 0)
2458 rfbLogPerror("rfbProcessClientNormalMessage: read");
2459 rfbCloseClient(cl);
2460 return;
2461 }
2462 msg.ft.size = Swap32IfLE(msg.ft.size);
2463 msg.ft.length = Swap32IfLE(msg.ft.length);
2464 /* record statistics in rfbProcessFileTransfer as length is filled with garbage when it is not valid */
2465 rfbProcessFileTransfer(cl, msg.ft.contentType, msg.ft.contentParam, msg.ft.size, msg.ft.length);
2466 return;
2467
2468 case rfbSetSW:
2469 if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2470 sz_rfbSetSWMsg - 1)) <= 0) {
2471 if (n != 0)
2472 rfbLogPerror("rfbProcessClientNormalMessage: read");
2473 rfbCloseClient(cl);
2474 return;
2475 }
2476 msg.sw.x = Swap16IfLE(msg.sw.x);
2477 msg.sw.y = Swap16IfLE(msg.sw.y);
2478 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetSWMsg, sz_rfbSetSWMsg);
2479 /* msg.sw.status is not initialized in the ultraVNC viewer and contains random numbers (why???) */
2480
2481 rfbLog("Received a rfbSetSingleWindow(%d x, %d y)\n", msg.sw.x, msg.sw.y);
2482 if (cl->screen->setSingleWindow!=NULL)
2483 cl->screen->setSingleWindow(cl, msg.sw.x, msg.sw.y);
2484 return;
2485
2486 case rfbSetServerInput:
2487 if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2488 sz_rfbSetServerInputMsg - 1)) <= 0) {
2489 if (n != 0)
2490 rfbLogPerror("rfbProcessClientNormalMessage: read");
2491 rfbCloseClient(cl);
2492 return;
2493 }
2494 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetServerInputMsg, sz_rfbSetServerInputMsg);
2495
2496 /* msg.sim.pad is not initialized in the ultraVNC viewer and contains random numbers (why???) */
2497 /* msg.sim.pad = Swap16IfLE(msg.sim.pad); */
2498
2499 rfbLog("Received a rfbSetServerInput(%d status)\n", msg.sim.status);
2500 if (cl->screen->setServerInput!=NULL)
2501 cl->screen->setServerInput(cl, msg.sim.status);
2502 return;
2503
2504 case rfbTextChat:
2505 if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2506 sz_rfbTextChatMsg - 1)) <= 0) {
2507 if (n != 0)
2508 rfbLogPerror("rfbProcessClientNormalMessage: read");
2509 rfbCloseClient(cl);
2510 return;
2511 }
2512
2513 msg.tc.pad2 = Swap16IfLE(msg.tc.pad2);
2514 msg.tc.length = Swap32IfLE(msg.tc.length);
2515
2516 switch (msg.tc.length) {
2517 case rfbTextChatOpen:
2518 case rfbTextChatClose:
2519 case rfbTextChatFinished:
2520 /* commands do not have text following */
2521 /* Why couldn't they have used the pad byte??? */
2522 str=NULL;
2523 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbTextChatMsg, sz_rfbTextChatMsg);
2524 break;
2525 default:
2526 if ((msg.tc.length>0) && (msg.tc.length<rfbTextMaxSize))
2527 {
2528 str = (char *)malloc(msg.tc.length);
2529 if (str==NULL)
2530 {
2531 rfbLog("Unable to malloc %d bytes for a TextChat Message\n", msg.tc.length);
2532 rfbCloseClient(cl);
2533 return;
2534 }
2535 if ((n = rfbReadExact(cl, str, msg.tc.length)) <= 0) {
2536 if (n != 0)
2537 rfbLogPerror("rfbProcessClientNormalMessage: read");
2538 free(str);
2539 rfbCloseClient(cl);
2540 return;
2541 }
2542 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbTextChatMsg+msg.tc.length, sz_rfbTextChatMsg+msg.tc.length);
2543 }
2544 else
2545 {
2546 /* This should never happen */
2547 rfbLog("client sent us a Text Message that is too big %d>%d\n", msg.tc.length, rfbTextMaxSize);
2548 rfbCloseClient(cl);
2549 return;
2550 }
2551 }
2552
2553 /* Note: length can be commands: rfbTextChatOpen, rfbTextChatClose, and rfbTextChatFinished
2554 * at which point, the str is NULL (as it is not sent)
2555 */
2556 if (cl->screen->setTextChat!=NULL)
2557 cl->screen->setTextChat(cl, msg.tc.length, str);
2558
2559 free(str);
2560 return;
2561
2562
2563 case rfbClientCutText:
2564
2565 if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2566 sz_rfbClientCutTextMsg - 1)) <= 0) {
2567 if (n != 0)
2568 rfbLogPerror("rfbProcessClientNormalMessage: read");
2569 rfbCloseClient(cl);
2570 return;
2571 }
2572
2573 msg.cct.length = Swap32IfLE(msg.cct.length);
2574
2575 str = (char *)malloc(msg.cct.length);
2576 if (str == NULL) {
2577 rfbLogPerror("rfbProcessClientNormalMessage: not enough memory");
2578 rfbCloseClient(cl);
2579 return;
2580 }
2581
2582 if ((n = rfbReadExact(cl, str, msg.cct.length)) <= 0) {
2583 if (n != 0)
2584 rfbLogPerror("rfbProcessClientNormalMessage: read");
2585 free(str);
2586 rfbCloseClient(cl);
2587 return;
2588 }
2589 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbClientCutTextMsg+msg.cct.length, sz_rfbClientCutTextMsg+msg.cct.length);
2590 if(!cl->viewOnly) {
2591 cl->screen->setXCutText(str, msg.cct.length, cl);
2592 }
2593 free(str);
2594
2595 return;
2596
2597 case rfbPalmVNCSetScaleFactor:
2598 cl->PalmVNC = TRUE;
2599 if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2600 sz_rfbSetScaleMsg - 1)) <= 0) {
2601 if (n != 0)
2602 rfbLogPerror("rfbProcessClientNormalMessage: read");
2603 rfbCloseClient(cl);
2604 return;
2605 }
2606
2607 if (msg.ssc.scale == 0) {
2608 rfbLogPerror("rfbProcessClientNormalMessage: will not accept a scale factor of zero");
2609 rfbCloseClient(cl);
2610 return;
2611 }
2612
2613 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetScaleMsg, sz_rfbSetScaleMsg);
2614 rfbLog("rfbSetScale(%d)\n", msg.ssc.scale);
2615 rfbScalingSetup(cl,cl->screen->width/msg.ssc.scale, cl->screen->height/msg.ssc.scale);
2616
2617 rfbSendNewScaleSize(cl);
2618 return;
2619
2620 case rfbSetScale:
2621
2622 if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2623 sz_rfbSetScaleMsg - 1)) <= 0) {
2624 if (n != 0)
2625 rfbLogPerror("rfbProcessClientNormalMessage: read");
2626 rfbCloseClient(cl);
2627 return;
2628 }
2629
2630 if (msg.ssc.scale == 0) {
2631 rfbLogPerror("rfbProcessClientNormalMessage: will not accept a scale factor of zero");
2632 rfbCloseClient(cl);
2633 return;
2634 }
2635
2636 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetScaleMsg, sz_rfbSetScaleMsg);
2637 rfbLog("rfbSetScale(%d)\n", msg.ssc.scale);
2638 rfbScalingSetup(cl,cl->screen->width/msg.ssc.scale, cl->screen->height/msg.ssc.scale);
2639
2640 rfbSendNewScaleSize(cl);
2641 return;
2642
2643 case rfbXvp:
2644
2645 if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
2646 sz_rfbXvpMsg - 1)) <= 0) {
2647 if (n != 0)
2648 rfbLogPerror("rfbProcessClientNormalMessage: read");
2649 rfbCloseClient(cl);
2650 return;
2651 }
2652 rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbXvpMsg, sz_rfbXvpMsg);
2653
2654 /* only version when is defined, so echo back a fail */
2655 if(msg.xvp.version != 1) {
2656 rfbSendXvp(cl, msg.xvp.version, rfbXvp_Fail);
2657 }
2658 else {
2659 /* if the hook exists and fails, send a fail msg */
2660 if(cl->screen->xvpHook && !cl->screen->xvpHook(cl, msg.xvp.version, msg.xvp.code))
2661 rfbSendXvp(cl, 1, rfbXvp_Fail);
2662 }
2663 return;
2664
2665 default:
2666 {
2667 rfbExtensionData *e,*next;
2668
2669 for(e=cl->extensions; e;) {
2670 next = e->next;
2671 if(e->extension->handleMessage &&
2672 e->extension->handleMessage(cl, e->data, &msg))
2673 {
2674 rfbStatRecordMessageRcvd(cl, msg.type, 0, 0); /* Extension should handle this */
2675 return;
2676 }
2677 e = next;
2678 }
2679
2680 rfbLog("rfbProcessClientNormalMessage: unknown message type %d\n",
2681 msg.type);
2682 rfbLog(" ... closing connection\n");
2683 rfbCloseClient(cl);
2684 return;
2685 }
2686 }
2687 }
2688
2689
2690
2691 /*
2692 * rfbSendFramebufferUpdate - send the currently pending framebuffer update to
2693 * the RFB client.
2694 * givenUpdateRegion is not changed.
2695 */
2696
2697 rfbBool
rfbSendFramebufferUpdate(rfbClientPtr cl,sraRegionPtr givenUpdateRegion)2698 rfbSendFramebufferUpdate(rfbClientPtr cl,
2699 sraRegionPtr givenUpdateRegion)
2700 {
2701 sraRectangleIterator* i=NULL;
2702 sraRect rect;
2703 int nUpdateRegionRects;
2704 rfbFramebufferUpdateMsg *fu = (rfbFramebufferUpdateMsg *)cl->updateBuf;
2705 sraRegionPtr updateRegion,updateCopyRegion,tmpRegion;
2706 int dx, dy;
2707 rfbBool sendCursorShape = FALSE;
2708 rfbBool sendCursorPos = FALSE;
2709 rfbBool sendKeyboardLedState = FALSE;
2710 rfbBool sendSupportedMessages = FALSE;
2711 rfbBool sendSupportedEncodings = FALSE;
2712 rfbBool sendServerIdentity = FALSE;
2713 rfbBool result = TRUE;
2714
2715
2716 if(cl->screen->displayHook)
2717 cl->screen->displayHook(cl);
2718
2719 /*
2720 * If framebuffer size was changed and the client supports NewFBSize
2721 * encoding, just send NewFBSize marker and return.
2722 */
2723
2724 if (cl->useNewFBSize && cl->newFBSizePending) {
2725 LOCK(cl->updateMutex);
2726 cl->newFBSizePending = FALSE;
2727 UNLOCK(cl->updateMutex);
2728 fu->type = rfbFramebufferUpdate;
2729 fu->nRects = Swap16IfLE(1);
2730 cl->ublen = sz_rfbFramebufferUpdateMsg;
2731 if (!rfbSendNewFBSize(cl, cl->scaledScreen->width, cl->scaledScreen->height)) {
2732 if(cl->screen->displayFinishedHook)
2733 cl->screen->displayFinishedHook(cl, FALSE);
2734 return FALSE;
2735 }
2736 result = rfbSendUpdateBuf(cl);
2737 if(cl->screen->displayFinishedHook)
2738 cl->screen->displayFinishedHook(cl, result);
2739 return result;
2740 }
2741
2742 /*
2743 * If this client understands cursor shape updates, cursor should be
2744 * removed from the framebuffer. Otherwise, make sure it's put up.
2745 */
2746
2747 if (cl->enableCursorShapeUpdates) {
2748 if (cl->cursorWasChanged && cl->readyForSetColourMapEntries)
2749 sendCursorShape = TRUE;
2750 }
2751
2752 /*
2753 * Do we plan to send cursor position update?
2754 */
2755
2756 if (cl->enableCursorPosUpdates && cl->cursorWasMoved)
2757 sendCursorPos = TRUE;
2758
2759 /*
2760 * Do we plan to send a keyboard state update?
2761 */
2762 if ((cl->enableKeyboardLedState) &&
2763 (cl->screen->getKeyboardLedStateHook!=NULL))
2764 {
2765 int x;
2766 x=cl->screen->getKeyboardLedStateHook(cl->screen);
2767 if (x!=cl->lastKeyboardLedState)
2768 {
2769 sendKeyboardLedState = TRUE;
2770 cl->lastKeyboardLedState=x;
2771 }
2772 }
2773
2774 /*
2775 * Do we plan to send a rfbEncodingSupportedMessages?
2776 */
2777 if (cl->enableSupportedMessages)
2778 {
2779 sendSupportedMessages = TRUE;
2780 /* We only send this message ONCE <per setEncodings message received>
2781 * (We disable it here)
2782 */
2783 cl->enableSupportedMessages = FALSE;
2784 }
2785 /*
2786 * Do we plan to send a rfbEncodingSupportedEncodings?
2787 */
2788 if (cl->enableSupportedEncodings)
2789 {
2790 sendSupportedEncodings = TRUE;
2791 /* We only send this message ONCE <per setEncodings message received>
2792 * (We disable it here)
2793 */
2794 cl->enableSupportedEncodings = FALSE;
2795 }
2796 /*
2797 * Do we plan to send a rfbEncodingServerIdentity?
2798 */
2799 if (cl->enableServerIdentity)
2800 {
2801 sendServerIdentity = TRUE;
2802 /* We only send this message ONCE <per setEncodings message received>
2803 * (We disable it here)
2804 */
2805 cl->enableServerIdentity = FALSE;
2806 }
2807
2808 LOCK(cl->updateMutex);
2809
2810 /*
2811 * The modifiedRegion may overlap the destination copyRegion. We remove
2812 * any overlapping bits from the copyRegion (since they'd only be
2813 * overwritten anyway).
2814 */
2815
2816 sraRgnSubtract(cl->copyRegion,cl->modifiedRegion);
2817
2818 /*
2819 * The client is interested in the region requestedRegion. The region
2820 * which should be updated now is the intersection of requestedRegion
2821 * and the union of modifiedRegion and copyRegion. If it's empty then
2822 * no update is needed.
2823 */
2824
2825 updateRegion = sraRgnCreateRgn(givenUpdateRegion);
2826 if(cl->screen->progressiveSliceHeight>0) {
2827 int height=cl->screen->progressiveSliceHeight,
2828 y=cl->progressiveSliceY;
2829 sraRegionPtr bbox=sraRgnBBox(updateRegion);
2830 sraRect rect;
2831 if(sraRgnPopRect(bbox,&rect,0)) {
2832 sraRegionPtr slice;
2833 if(y<rect.y1 || y>=rect.y2)
2834 y=rect.y1;
2835 slice=sraRgnCreateRect(0,y,cl->screen->width,y+height);
2836 sraRgnAnd(updateRegion,slice);
2837 sraRgnDestroy(slice);
2838 }
2839 sraRgnDestroy(bbox);
2840 y+=height;
2841 if(y>=cl->screen->height)
2842 y=0;
2843 cl->progressiveSliceY=y;
2844 }
2845
2846 sraRgnOr(updateRegion,cl->copyRegion);
2847 if(!sraRgnAnd(updateRegion,cl->requestedRegion) &&
2848 sraRgnEmpty(updateRegion) &&
2849 (cl->enableCursorShapeUpdates ||
2850 (cl->cursorX == cl->screen->cursorX && cl->cursorY == cl->screen->cursorY)) &&
2851 !sendCursorShape && !sendCursorPos && !sendKeyboardLedState &&
2852 !sendSupportedMessages && !sendSupportedEncodings && !sendServerIdentity) {
2853 sraRgnDestroy(updateRegion);
2854 UNLOCK(cl->updateMutex);
2855 if(cl->screen->displayFinishedHook)
2856 cl->screen->displayFinishedHook(cl, TRUE);
2857 return TRUE;
2858 }
2859
2860 /*
2861 * We assume that the client doesn't have any pixel data outside the
2862 * requestedRegion. In other words, both the source and destination of a
2863 * copy must lie within requestedRegion. So the region we can send as a
2864 * copy is the intersection of the copyRegion with both the requestedRegion
2865 * and the requestedRegion translated by the amount of the copy. We set
2866 * updateCopyRegion to this.
2867 */
2868
2869 updateCopyRegion = sraRgnCreateRgn(cl->copyRegion);
2870 sraRgnAnd(updateCopyRegion,cl->requestedRegion);
2871 tmpRegion = sraRgnCreateRgn(cl->requestedRegion);
2872 sraRgnOffset(tmpRegion,cl->copyDX,cl->copyDY);
2873 sraRgnAnd(updateCopyRegion,tmpRegion);
2874 sraRgnDestroy(tmpRegion);
2875 dx = cl->copyDX;
2876 dy = cl->copyDY;
2877
2878 /*
2879 * Next we remove updateCopyRegion from updateRegion so that updateRegion
2880 * is the part of this update which is sent as ordinary pixel data (i.e not
2881 * a copy).
2882 */
2883
2884 sraRgnSubtract(updateRegion,updateCopyRegion);
2885
2886 /*
2887 * Finally we leave modifiedRegion to be the remainder (if any) of parts of
2888 * the screen which are modified but outside the requestedRegion. We also
2889 * empty both the requestedRegion and the copyRegion - note that we never
2890 * carry over a copyRegion for a future update.
2891 */
2892
2893 sraRgnOr(cl->modifiedRegion,cl->copyRegion);
2894 sraRgnSubtract(cl->modifiedRegion,updateRegion);
2895 sraRgnSubtract(cl->modifiedRegion,updateCopyRegion);
2896
2897 sraRgnMakeEmpty(cl->requestedRegion);
2898 sraRgnMakeEmpty(cl->copyRegion);
2899 cl->copyDX = 0;
2900 cl->copyDY = 0;
2901
2902 UNLOCK(cl->updateMutex);
2903
2904 if (!cl->enableCursorShapeUpdates) {
2905 if(cl->cursorX != cl->screen->cursorX || cl->cursorY != cl->screen->cursorY) {
2906 rfbRedrawAfterHideCursor(cl,updateRegion);
2907 LOCK(cl->screen->cursorMutex);
2908 cl->cursorX = cl->screen->cursorX;
2909 cl->cursorY = cl->screen->cursorY;
2910 UNLOCK(cl->screen->cursorMutex);
2911 rfbRedrawAfterHideCursor(cl,updateRegion);
2912 }
2913 rfbShowCursor(cl);
2914 }
2915
2916 /*
2917 * Now send the update.
2918 */
2919
2920 rfbStatRecordMessageSent(cl, rfbFramebufferUpdate, 0, 0);
2921 if (cl->preferredEncoding == rfbEncodingCoRRE) {
2922 nUpdateRegionRects = 0;
2923
2924 for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){
2925 int x = rect.x1;
2926 int y = rect.y1;
2927 int w = rect.x2 - x;
2928 int h = rect.y2 - y;
2929 int rectsPerRow, rows;
2930 /* We need to count the number of rects in the scaled screen */
2931 if (cl->screen!=cl->scaledScreen)
2932 rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "rfbSendFramebufferUpdate");
2933 rectsPerRow = (w-1)/cl->correMaxWidth+1;
2934 rows = (h-1)/cl->correMaxHeight+1;
2935 nUpdateRegionRects += rectsPerRow*rows;
2936 }
2937 sraRgnReleaseIterator(i); i=NULL;
2938 } else if (cl->preferredEncoding == rfbEncodingUltra) {
2939 nUpdateRegionRects = 0;
2940
2941 for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){
2942 int x = rect.x1;
2943 int y = rect.y1;
2944 int w = rect.x2 - x;
2945 int h = rect.y2 - y;
2946 /* We need to count the number of rects in the scaled screen */
2947 if (cl->screen!=cl->scaledScreen)
2948 rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "rfbSendFramebufferUpdate");
2949 nUpdateRegionRects += (((h-1) / (ULTRA_MAX_SIZE( w ) / w)) + 1);
2950 }
2951 sraRgnReleaseIterator(i); i=NULL;
2952 #ifdef LIBVNCSERVER_HAVE_LIBZ
2953 } else if (cl->preferredEncoding == rfbEncodingZlib) {
2954 nUpdateRegionRects = 0;
2955
2956 for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){
2957 int x = rect.x1;
2958 int y = rect.y1;
2959 int w = rect.x2 - x;
2960 int h = rect.y2 - y;
2961 /* We need to count the number of rects in the scaled screen */
2962 if (cl->screen!=cl->scaledScreen)
2963 rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "rfbSendFramebufferUpdate");
2964 nUpdateRegionRects += (((h-1) / (ZLIB_MAX_SIZE( w ) / w)) + 1);
2965 }
2966 sraRgnReleaseIterator(i); i=NULL;
2967 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
2968 } else if (cl->preferredEncoding == rfbEncodingTight) {
2969 nUpdateRegionRects = 0;
2970
2971 for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){
2972 int x = rect.x1;
2973 int y = rect.y1;
2974 int w = rect.x2 - x;
2975 int h = rect.y2 - y;
2976 int n;
2977 /* We need to count the number of rects in the scaled screen */
2978 if (cl->screen!=cl->scaledScreen)
2979 rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "rfbSendFramebufferUpdate");
2980 n = rfbNumCodedRectsTight(cl, x, y, w, h);
2981 if (n == 0) {
2982 nUpdateRegionRects = 0xFFFF;
2983 break;
2984 }
2985 nUpdateRegionRects += n;
2986 }
2987 sraRgnReleaseIterator(i); i=NULL;
2988 #endif
2989 #endif
2990 #if defined(LIBVNCSERVER_HAVE_LIBJPEG) && defined(LIBVNCSERVER_HAVE_LIBPNG)
2991 } else if (cl->preferredEncoding == rfbEncodingTightPng) {
2992 nUpdateRegionRects = 0;
2993
2994 for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){
2995 int x = rect.x1;
2996 int y = rect.y1;
2997 int w = rect.x2 - x;
2998 int h = rect.y2 - y;
2999 int n;
3000 /* We need to count the number of rects in the scaled screen */
3001 if (cl->screen!=cl->scaledScreen)
3002 rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "rfbSendFramebufferUpdate");
3003 n = rfbNumCodedRectsTight(cl, x, y, w, h);
3004 if (n == 0) {
3005 nUpdateRegionRects = 0xFFFF;
3006 break;
3007 }
3008 nUpdateRegionRects += n;
3009 }
3010 sraRgnReleaseIterator(i); i=NULL;
3011 #endif
3012 } else {
3013 nUpdateRegionRects = sraRgnCountRects(updateRegion);
3014 }
3015
3016 fu->type = rfbFramebufferUpdate;
3017 if (nUpdateRegionRects != 0xFFFF) {
3018 if(cl->screen->maxRectsPerUpdate>0
3019 /* CoRRE splits the screen into smaller squares */
3020 && cl->preferredEncoding != rfbEncodingCoRRE
3021 /* Ultra encoding splits rectangles up into smaller chunks */
3022 && cl->preferredEncoding != rfbEncodingUltra
3023 #ifdef LIBVNCSERVER_HAVE_LIBZ
3024 /* Zlib encoding splits rectangles up into smaller chunks */
3025 && cl->preferredEncoding != rfbEncodingZlib
3026 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
3027 /* Tight encoding counts the rectangles differently */
3028 && cl->preferredEncoding != rfbEncodingTight
3029 #endif
3030 #endif
3031 #ifdef LIBVNCSERVER_HAVE_LIBPNG
3032 /* Tight encoding counts the rectangles differently */
3033 && cl->preferredEncoding != rfbEncodingTightPng
3034 #endif
3035 && nUpdateRegionRects>cl->screen->maxRectsPerUpdate) {
3036 sraRegion* newUpdateRegion = sraRgnBBox(updateRegion);
3037 sraRgnDestroy(updateRegion);
3038 updateRegion = newUpdateRegion;
3039 nUpdateRegionRects = sraRgnCountRects(updateRegion);
3040 }
3041 fu->nRects = Swap16IfLE((uint16_t)(sraRgnCountRects(updateCopyRegion) +
3042 nUpdateRegionRects +
3043 !!sendCursorShape + !!sendCursorPos + !!sendKeyboardLedState +
3044 !!sendSupportedMessages + !!sendSupportedEncodings + !!sendServerIdentity));
3045 } else {
3046 fu->nRects = 0xFFFF;
3047 }
3048 cl->ublen = sz_rfbFramebufferUpdateMsg;
3049
3050 if (sendCursorShape) {
3051 cl->cursorWasChanged = FALSE;
3052 if (!rfbSendCursorShape(cl))
3053 goto updateFailed;
3054 }
3055
3056 if (sendCursorPos) {
3057 cl->cursorWasMoved = FALSE;
3058 if (!rfbSendCursorPos(cl))
3059 goto updateFailed;
3060 }
3061
3062 if (sendKeyboardLedState) {
3063 if (!rfbSendKeyboardLedState(cl))
3064 goto updateFailed;
3065 }
3066
3067 if (sendSupportedMessages) {
3068 if (!rfbSendSupportedMessages(cl))
3069 goto updateFailed;
3070 }
3071 if (sendSupportedEncodings) {
3072 if (!rfbSendSupportedEncodings(cl))
3073 goto updateFailed;
3074 }
3075 if (sendServerIdentity) {
3076 if (!rfbSendServerIdentity(cl))
3077 goto updateFailed;
3078 }
3079
3080 if (!sraRgnEmpty(updateCopyRegion)) {
3081 if (!rfbSendCopyRegion(cl,updateCopyRegion,dx,dy))
3082 goto updateFailed;
3083 }
3084
3085 for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){
3086 int x = rect.x1;
3087 int y = rect.y1;
3088 int w = rect.x2 - x;
3089 int h = rect.y2 - y;
3090
3091 /* We need to count the number of rects in the scaled screen */
3092 if (cl->screen!=cl->scaledScreen)
3093 rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "rfbSendFramebufferUpdate");
3094
3095 switch (cl->preferredEncoding) {
3096 case -1:
3097 case rfbEncodingRaw:
3098 if (!rfbSendRectEncodingRaw(cl, x, y, w, h))
3099 goto updateFailed;
3100 break;
3101 case rfbEncodingRRE:
3102 if (!rfbSendRectEncodingRRE(cl, x, y, w, h))
3103 goto updateFailed;
3104 break;
3105 case rfbEncodingCoRRE:
3106 if (!rfbSendRectEncodingCoRRE(cl, x, y, w, h))
3107 goto updateFailed;
3108 break;
3109 case rfbEncodingHextile:
3110 if (!rfbSendRectEncodingHextile(cl, x, y, w, h))
3111 goto updateFailed;
3112 break;
3113 case rfbEncodingUltra:
3114 if (!rfbSendRectEncodingUltra(cl, x, y, w, h))
3115 goto updateFailed;
3116 break;
3117 #ifdef LIBVNCSERVER_HAVE_LIBZ
3118 case rfbEncodingZlib:
3119 if (!rfbSendRectEncodingZlib(cl, x, y, w, h))
3120 goto updateFailed;
3121 break;
3122 case rfbEncodingZRLE:
3123 case rfbEncodingZYWRLE:
3124 if (!rfbSendRectEncodingZRLE(cl, x, y, w, h))
3125 goto updateFailed;
3126 break;
3127 #endif
3128 #if defined(LIBVNCSERVER_HAVE_LIBJPEG) && (defined(LIBVNCSERVER_HAVE_LIBZ) || defined(LIBVNCSERVER_HAVE_LIBPNG))
3129 case rfbEncodingTight:
3130 if (!rfbSendRectEncodingTight(cl, x, y, w, h))
3131 goto updateFailed;
3132 break;
3133 #ifdef LIBVNCSERVER_HAVE_LIBPNG
3134 case rfbEncodingTightPng:
3135 if (!rfbSendRectEncodingTightPng(cl, x, y, w, h))
3136 goto updateFailed;
3137 break;
3138 #endif
3139 #endif
3140 }
3141 }
3142 if (i) {
3143 sraRgnReleaseIterator(i);
3144 i = NULL;
3145 }
3146
3147 if ( nUpdateRegionRects == 0xFFFF &&
3148 !rfbSendLastRectMarker(cl) )
3149 goto updateFailed;
3150
3151 if (!rfbSendUpdateBuf(cl)) {
3152 updateFailed:
3153 result = FALSE;
3154 }
3155
3156 if (!cl->enableCursorShapeUpdates) {
3157 rfbHideCursor(cl);
3158 }
3159
3160 if(i)
3161 sraRgnReleaseIterator(i);
3162 sraRgnDestroy(updateRegion);
3163 sraRgnDestroy(updateCopyRegion);
3164
3165 if(cl->screen->displayFinishedHook)
3166 cl->screen->displayFinishedHook(cl, result);
3167 return result;
3168 }
3169
3170
3171 /*
3172 * Send the copy region as a string of CopyRect encoded rectangles.
3173 * The only slightly tricky thing is that we should send the messages in
3174 * the correct order so that an earlier CopyRect will not corrupt the source
3175 * of a later one.
3176 */
3177
3178 rfbBool
rfbSendCopyRegion(rfbClientPtr cl,sraRegionPtr reg,int dx,int dy)3179 rfbSendCopyRegion(rfbClientPtr cl,
3180 sraRegionPtr reg,
3181 int dx,
3182 int dy)
3183 {
3184 int x, y, w, h;
3185 rfbFramebufferUpdateRectHeader rect;
3186 rfbCopyRect cr;
3187 sraRectangleIterator* i;
3188 sraRect rect1;
3189
3190 /* printf("copyrect: "); sraRgnPrint(reg); putchar('\n');fflush(stdout); */
3191 i = sraRgnGetReverseIterator(reg,dx>0,dy>0);
3192
3193 /* correct for the scale of the screen */
3194 dx = ScaleX(cl->screen, cl->scaledScreen, dx);
3195 dy = ScaleX(cl->screen, cl->scaledScreen, dy);
3196
3197 while(sraRgnIteratorNext(i,&rect1)) {
3198 x = rect1.x1;
3199 y = rect1.y1;
3200 w = rect1.x2 - x;
3201 h = rect1.y2 - y;
3202
3203 /* correct for scaling (if necessary) */
3204 rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "copyrect");
3205
3206 rect.r.x = Swap16IfLE(x);
3207 rect.r.y = Swap16IfLE(y);
3208 rect.r.w = Swap16IfLE(w);
3209 rect.r.h = Swap16IfLE(h);
3210 rect.encoding = Swap32IfLE(rfbEncodingCopyRect);
3211
3212 memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
3213 sz_rfbFramebufferUpdateRectHeader);
3214 cl->ublen += sz_rfbFramebufferUpdateRectHeader;
3215
3216 cr.srcX = Swap16IfLE(x - dx);
3217 cr.srcY = Swap16IfLE(y - dy);
3218
3219 memcpy(&cl->updateBuf[cl->ublen], (char *)&cr, sz_rfbCopyRect);
3220 cl->ublen += sz_rfbCopyRect;
3221
3222 rfbStatRecordEncodingSent(cl, rfbEncodingCopyRect, sz_rfbFramebufferUpdateRectHeader + sz_rfbCopyRect,
3223 w * h * (cl->scaledScreen->bitsPerPixel / 8));
3224 }
3225 sraRgnReleaseIterator(i);
3226
3227 return TRUE;
3228 }
3229
3230 /*
3231 * Send a given rectangle in raw encoding (rfbEncodingRaw).
3232 */
3233
3234 rfbBool
rfbSendRectEncodingRaw(rfbClientPtr cl,int x,int y,int w,int h)3235 rfbSendRectEncodingRaw(rfbClientPtr cl,
3236 int x,
3237 int y,
3238 int w,
3239 int h)
3240 {
3241 rfbFramebufferUpdateRectHeader rect;
3242 int nlines;
3243 int bytesPerLine = w * (cl->format.bitsPerPixel / 8);
3244 char *fbptr = (cl->scaledScreen->frameBuffer + (cl->scaledScreen->paddedWidthInBytes * y)
3245 + (x * (cl->scaledScreen->bitsPerPixel / 8)));
3246
3247 /* Flush the buffer to guarantee correct alignment for translateFn(). */
3248 if (cl->ublen > 0) {
3249 if (!rfbSendUpdateBuf(cl))
3250 return FALSE;
3251 }
3252
3253 rect.r.x = Swap16IfLE(x);
3254 rect.r.y = Swap16IfLE(y);
3255 rect.r.w = Swap16IfLE(w);
3256 rect.r.h = Swap16IfLE(h);
3257 rect.encoding = Swap32IfLE(rfbEncodingRaw);
3258
3259 memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
3260 cl->ublen += sz_rfbFramebufferUpdateRectHeader;
3261
3262
3263 rfbStatRecordEncodingSent(cl, rfbEncodingRaw, sz_rfbFramebufferUpdateRectHeader + bytesPerLine * h,
3264 sz_rfbFramebufferUpdateRectHeader + bytesPerLine * h);
3265
3266 nlines = (UPDATE_BUF_SIZE - cl->ublen) / bytesPerLine;
3267
3268 while (TRUE) {
3269 if (nlines > h)
3270 nlines = h;
3271
3272 (*cl->translateFn)(cl->translateLookupTable,
3273 &(cl->screen->serverFormat),
3274 &cl->format, fbptr, &cl->updateBuf[cl->ublen],
3275 cl->scaledScreen->paddedWidthInBytes, w, nlines);
3276
3277 cl->ublen += nlines * bytesPerLine;
3278 h -= nlines;
3279
3280 if (h == 0) /* rect fitted in buffer, do next one */
3281 return TRUE;
3282
3283 /* buffer full - flush partial rect and do another nlines */
3284
3285 if (!rfbSendUpdateBuf(cl))
3286 return FALSE;
3287
3288 fbptr += (cl->scaledScreen->paddedWidthInBytes * nlines);
3289
3290 nlines = (UPDATE_BUF_SIZE - cl->ublen) / bytesPerLine;
3291 if (nlines == 0) {
3292 rfbErr("rfbSendRectEncodingRaw: send buffer too small for %d "
3293 "bytes per line\n", bytesPerLine);
3294 rfbCloseClient(cl);
3295 return FALSE;
3296 }
3297 }
3298 }
3299
3300
3301
3302 /*
3303 * Send an empty rectangle with encoding field set to value of
3304 * rfbEncodingLastRect to notify client that this is the last
3305 * rectangle in framebuffer update ("LastRect" extension of RFB
3306 * protocol).
3307 */
3308
3309 rfbBool
rfbSendLastRectMarker(rfbClientPtr cl)3310 rfbSendLastRectMarker(rfbClientPtr cl)
3311 {
3312 rfbFramebufferUpdateRectHeader rect;
3313
3314 if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
3315 if (!rfbSendUpdateBuf(cl))
3316 return FALSE;
3317 }
3318
3319 rect.encoding = Swap32IfLE(rfbEncodingLastRect);
3320 rect.r.x = 0;
3321 rect.r.y = 0;
3322 rect.r.w = 0;
3323 rect.r.h = 0;
3324
3325 memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
3326 cl->ublen += sz_rfbFramebufferUpdateRectHeader;
3327
3328
3329 rfbStatRecordEncodingSent(cl, rfbEncodingLastRect, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader);
3330
3331 return TRUE;
3332 }
3333
3334
3335 /*
3336 * Send NewFBSize pseudo-rectangle. This tells the client to change
3337 * its framebuffer size.
3338 */
3339
3340 rfbBool
rfbSendNewFBSize(rfbClientPtr cl,int w,int h)3341 rfbSendNewFBSize(rfbClientPtr cl,
3342 int w,
3343 int h)
3344 {
3345 rfbFramebufferUpdateRectHeader rect;
3346
3347 if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
3348 if (!rfbSendUpdateBuf(cl))
3349 return FALSE;
3350 }
3351
3352 if (cl->PalmVNC==TRUE)
3353 rfbLog("Sending rfbEncodingNewFBSize in response to a PalmVNC style framebuffer resize (%dx%d)\n", w, h);
3354 else
3355 rfbLog("Sending rfbEncodingNewFBSize for resize to (%dx%d)\n", w, h);
3356
3357 rect.encoding = Swap32IfLE(rfbEncodingNewFBSize);
3358 rect.r.x = 0;
3359 rect.r.y = 0;
3360 rect.r.w = Swap16IfLE(w);
3361 rect.r.h = Swap16IfLE(h);
3362
3363 memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
3364 sz_rfbFramebufferUpdateRectHeader);
3365 cl->ublen += sz_rfbFramebufferUpdateRectHeader;
3366
3367 rfbStatRecordEncodingSent(cl, rfbEncodingNewFBSize, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader);
3368
3369 return TRUE;
3370 }
3371
3372
3373 /*
3374 * Send the contents of cl->updateBuf. Returns 1 if successful, -1 if
3375 * not (errno should be set).
3376 */
3377
3378 rfbBool
rfbSendUpdateBuf(rfbClientPtr cl)3379 rfbSendUpdateBuf(rfbClientPtr cl)
3380 {
3381 if(cl->sock<0)
3382 return FALSE;
3383
3384 if (rfbWriteExact(cl, cl->updateBuf, cl->ublen) < 0) {
3385 rfbLogPerror("rfbSendUpdateBuf: write");
3386 rfbCloseClient(cl);
3387 return FALSE;
3388 }
3389
3390 cl->ublen = 0;
3391 return TRUE;
3392 }
3393
3394 /*
3395 * rfbSendSetColourMapEntries sends a SetColourMapEntries message to the
3396 * client, using values from the currently installed colormap.
3397 */
3398
3399 rfbBool
rfbSendSetColourMapEntries(rfbClientPtr cl,int firstColour,int nColours)3400 rfbSendSetColourMapEntries(rfbClientPtr cl,
3401 int firstColour,
3402 int nColours)
3403 {
3404 char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2];
3405 char *wbuf = buf;
3406 rfbSetColourMapEntriesMsg *scme;
3407 uint16_t *rgb;
3408 rfbColourMap* cm = &cl->screen->colourMap;
3409 int i, len;
3410
3411 if (nColours > 256) {
3412 /* some rare hardware has, e.g., 4096 colors cells: PseudoColor:12 */
3413 wbuf = (char *) malloc(sz_rfbSetColourMapEntriesMsg + nColours * 3 * 2);
3414 }
3415
3416 scme = (rfbSetColourMapEntriesMsg *)wbuf;
3417 rgb = (uint16_t *)(&wbuf[sz_rfbSetColourMapEntriesMsg]);
3418
3419 scme->type = rfbSetColourMapEntries;
3420
3421 scme->firstColour = Swap16IfLE(firstColour);
3422 scme->nColours = Swap16IfLE(nColours);
3423
3424 len = sz_rfbSetColourMapEntriesMsg;
3425
3426 for (i = 0; i < nColours; i++) {
3427 if(i<(int)cm->count) {
3428 if(cm->is16) {
3429 rgb[i*3] = Swap16IfLE(cm->data.shorts[i*3]);
3430 rgb[i*3+1] = Swap16IfLE(cm->data.shorts[i*3+1]);
3431 rgb[i*3+2] = Swap16IfLE(cm->data.shorts[i*3+2]);
3432 } else {
3433 rgb[i*3] = Swap16IfLE((unsigned short)cm->data.bytes[i*3]);
3434 rgb[i*3+1] = Swap16IfLE((unsigned short)cm->data.bytes[i*3+1]);
3435 rgb[i*3+2] = Swap16IfLE((unsigned short)cm->data.bytes[i*3+2]);
3436 }
3437 }
3438 }
3439
3440 len += nColours * 3 * 2;
3441
3442 LOCK(cl->sendMutex);
3443 if (rfbWriteExact(cl, wbuf, len) < 0) {
3444 rfbLogPerror("rfbSendSetColourMapEntries: write");
3445 rfbCloseClient(cl);
3446 if (wbuf != buf) free(wbuf);
3447 UNLOCK(cl->sendMutex);
3448 return FALSE;
3449 }
3450 UNLOCK(cl->sendMutex);
3451
3452 rfbStatRecordMessageSent(cl, rfbSetColourMapEntries, len, len);
3453 if (wbuf != buf) free(wbuf);
3454 return TRUE;
3455 }
3456
3457 /*
3458 * rfbSendBell sends a Bell message to all the clients.
3459 */
3460
3461 void
rfbSendBell(rfbScreenInfoPtr rfbScreen)3462 rfbSendBell(rfbScreenInfoPtr rfbScreen)
3463 {
3464 rfbClientIteratorPtr i;
3465 rfbClientPtr cl;
3466 rfbBellMsg b;
3467
3468 i = rfbGetClientIterator(rfbScreen);
3469 while((cl=rfbClientIteratorNext(i))) {
3470 b.type = rfbBell;
3471 LOCK(cl->sendMutex);
3472 if (rfbWriteExact(cl, (char *)&b, sz_rfbBellMsg) < 0) {
3473 rfbLogPerror("rfbSendBell: write");
3474 rfbCloseClient(cl);
3475 }
3476 UNLOCK(cl->sendMutex);
3477 }
3478 rfbStatRecordMessageSent(cl, rfbBell, sz_rfbBellMsg, sz_rfbBellMsg);
3479 rfbReleaseClientIterator(i);
3480 }
3481
3482
3483 /*
3484 * rfbSendServerCutText sends a ServerCutText message to all the clients.
3485 */
3486
3487 void
rfbSendServerCutText(rfbScreenInfoPtr rfbScreen,char * str,int len)3488 rfbSendServerCutText(rfbScreenInfoPtr rfbScreen,char *str, int len)
3489 {
3490 rfbClientPtr cl;
3491 rfbServerCutTextMsg sct;
3492 rfbClientIteratorPtr iterator;
3493
3494 iterator = rfbGetClientIterator(rfbScreen);
3495 while ((cl = rfbClientIteratorNext(iterator)) != NULL) {
3496 sct.type = rfbServerCutText;
3497 sct.length = Swap32IfLE(len);
3498 LOCK(cl->sendMutex);
3499 if (rfbWriteExact(cl, (char *)&sct,
3500 sz_rfbServerCutTextMsg) < 0) {
3501 rfbLogPerror("rfbSendServerCutText: write");
3502 rfbCloseClient(cl);
3503 UNLOCK(cl->sendMutex);
3504 continue;
3505 }
3506 if (rfbWriteExact(cl, str, len) < 0) {
3507 rfbLogPerror("rfbSendServerCutText: write");
3508 rfbCloseClient(cl);
3509 }
3510 UNLOCK(cl->sendMutex);
3511 rfbStatRecordMessageSent(cl, rfbServerCutText, sz_rfbServerCutTextMsg+len, sz_rfbServerCutTextMsg+len);
3512 }
3513 rfbReleaseClientIterator(iterator);
3514 }
3515
3516 /*****************************************************************************
3517 *
3518 * UDP can be used for keyboard and pointer events when the underlying
3519 * network is highly reliable. This is really here to support ORL's
3520 * videotile, whose TCP implementation doesn't like sending lots of small
3521 * packets (such as 100s of pen readings per second!).
3522 */
3523
3524 static unsigned char ptrAcceleration = 50;
3525
3526 void
rfbNewUDPConnection(rfbScreenInfoPtr rfbScreen,int sock)3527 rfbNewUDPConnection(rfbScreenInfoPtr rfbScreen,
3528 int sock)
3529 {
3530 if (write(sock, (char*) &ptrAcceleration, 1) < 0) {
3531 rfbLogPerror("rfbNewUDPConnection: write");
3532 }
3533 }
3534
3535 /*
3536 * Because UDP is a message based service, we can't read the first byte and
3537 * then the rest of the packet separately like we do with TCP. We will always
3538 * get a whole packet delivered in one go, so we ask read() for the maximum
3539 * number of bytes we can possibly get.
3540 */
3541
3542 void
rfbProcessUDPInput(rfbScreenInfoPtr rfbScreen)3543 rfbProcessUDPInput(rfbScreenInfoPtr rfbScreen)
3544 {
3545 int n;
3546 rfbClientPtr cl=rfbScreen->udpClient;
3547 rfbClientToServerMsg msg;
3548
3549 if((!cl) || cl->onHold)
3550 return;
3551
3552 if ((n = read(rfbScreen->udpSock, (char *)&msg, sizeof(msg))) <= 0) {
3553 if (n < 0) {
3554 rfbLogPerror("rfbProcessUDPInput: read");
3555 }
3556 rfbDisconnectUDPSock(rfbScreen);
3557 return;
3558 }
3559
3560 switch (msg.type) {
3561
3562 case rfbKeyEvent:
3563 if (n != sz_rfbKeyEventMsg) {
3564 rfbErr("rfbProcessUDPInput: key event incorrect length\n");
3565 rfbDisconnectUDPSock(rfbScreen);
3566 return;
3567 }
3568 cl->screen->kbdAddEvent(msg.ke.down, (rfbKeySym)Swap32IfLE(msg.ke.key), cl);
3569 break;
3570
3571 case rfbPointerEvent:
3572 if (n != sz_rfbPointerEventMsg) {
3573 rfbErr("rfbProcessUDPInput: ptr event incorrect length\n");
3574 rfbDisconnectUDPSock(rfbScreen);
3575 return;
3576 }
3577 cl->screen->ptrAddEvent(msg.pe.buttonMask,
3578 Swap16IfLE(msg.pe.x), Swap16IfLE(msg.pe.y), cl);
3579 break;
3580
3581 default:
3582 rfbErr("rfbProcessUDPInput: unknown message type %d\n",
3583 msg.type);
3584 rfbDisconnectUDPSock(rfbScreen);
3585 }
3586 }
3587
3588
3589