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