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