1 /* 2 * This file is called main.c, because it contains most of the new functions 3 * for use with LibVNCServer. 4 * 5 * LibVNCServer (C) 2001 Johannes E. Schindelin <Johannes.Schindelin (at) gmx.de> 6 * Original OSXvnc (C) 2001 Dan McGuirk <mcguirk (at) incompleteness.net>. 7 * Original Xvnc (C) 1999 AT&T Laboratories Cambridge. 8 * All Rights Reserved. 9 * 10 * see GPL (latest version) for full details 11 */ 12 13 #ifdef __STRICT_ANSI__ 14 #define _BSD_SOURCE 15 #endif 16 #include <rfb/rfb.h> 17 #include <rfb/rfbregion.h> 18 #include "private.h" 19 20 #include <stdarg.h> 21 #include <errno.h> 22 23 #ifndef false 24 #define false 0 25 #define true -1 26 #endif 27 28 #ifdef LIBVNCSERVER_HAVE_SYS_TYPES_H 29 #include <sys/types.h> 30 #endif 31 32 #ifndef WIN32 33 #include <sys/socket.h> 34 #include <netinet/in.h> 35 #include <unistd.h> 36 #endif 37 38 #include <signal.h> 39 #include <time.h> 40 41 static int extMutex_initialized = 0; 42 static int logMutex_initialized = 0; 43 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD 44 static MUTEX(logMutex); 45 static MUTEX(extMutex); 46 #endif 47 48 static int rfbEnableLogging=1; 49 50 #ifdef LIBVNCSERVER_WORDS_BIGENDIAN 51 char rfbEndianTest = (1==0); 52 #else 53 char rfbEndianTest = (1==1); 54 #endif 55 56 /* 57 * Protocol extensions 58 */ 59 60 static rfbProtocolExtension* rfbExtensionHead = NULL; 61 62 /* 63 * This method registers a list of new extensions. 64 * It avoids same extension getting registered multiple times. 65 * The order is not preserved if multiple extensions are 66 * registered at one-go. 67 */ 68 void 69 rfbRegisterProtocolExtension(rfbProtocolExtension* extension) 70 { 71 rfbProtocolExtension *head = rfbExtensionHead, *next = NULL; 72 73 if(extension == NULL) 74 return; 75 76 next = extension->next; 77 78 if (! extMutex_initialized) { 79 INIT_MUTEX(extMutex); 80 extMutex_initialized = 1; 81 } 82 83 LOCK(extMutex); 84 85 while(head != NULL) { 86 if(head == extension) { 87 UNLOCK(extMutex); 88 rfbRegisterProtocolExtension(next); 89 return; 90 } 91 92 head = head->next; 93 } 94 95 extension->next = rfbExtensionHead; 96 rfbExtensionHead = extension; 97 98 UNLOCK(extMutex); 99 rfbRegisterProtocolExtension(next); 100 } 101 102 /* 103 * This method unregisters a list of extensions. 104 * These extensions won't be available for any new 105 * client connection. 106 */ 107 void 108 rfbUnregisterProtocolExtension(rfbProtocolExtension* extension) 109 { 110 111 rfbProtocolExtension *cur = NULL, *pre = NULL; 112 113 if(extension == NULL) 114 return; 115 116 if (! extMutex_initialized) { 117 INIT_MUTEX(extMutex); 118 extMutex_initialized = 1; 119 } 120 121 LOCK(extMutex); 122 123 if(rfbExtensionHead == extension) { 124 rfbExtensionHead = rfbExtensionHead->next; 125 UNLOCK(extMutex); 126 rfbUnregisterProtocolExtension(extension->next); 127 return; 128 } 129 130 cur = pre = rfbExtensionHead; 131 132 while(cur) { 133 if(cur == extension) { 134 pre->next = cur->next; 135 break; 136 } 137 pre = cur; 138 cur = cur->next; 139 } 140 141 UNLOCK(extMutex); 142 143 rfbUnregisterProtocolExtension(extension->next); 144 } 145 146 rfbProtocolExtension* rfbGetExtensionIterator() 147 { 148 if (! extMutex_initialized) { 149 INIT_MUTEX(extMutex); 150 extMutex_initialized = 1; 151 } 152 153 LOCK(extMutex); 154 return rfbExtensionHead; 155 } 156 157 void rfbReleaseExtensionIterator() 158 { 159 UNLOCK(extMutex); 160 } 161 162 rfbBool rfbEnableExtension(rfbClientPtr cl, rfbProtocolExtension* extension, 163 void* data) 164 { 165 rfbExtensionData* extData; 166 167 /* make sure extension is not yet enabled. */ 168 for(extData = cl->extensions; extData; extData = extData->next) 169 if(extData->extension == extension) 170 return FALSE; 171 172 extData = calloc(sizeof(rfbExtensionData),1); 173 extData->extension = extension; 174 extData->data = data; 175 extData->next = cl->extensions; 176 cl->extensions = extData; 177 178 return TRUE; 179 } 180 181 rfbBool rfbDisableExtension(rfbClientPtr cl, rfbProtocolExtension* extension) 182 { 183 rfbExtensionData* extData; 184 rfbExtensionData* prevData = NULL; 185 186 for(extData = cl->extensions; extData; extData = extData->next) { 187 if(extData->extension == extension) { 188 if(extData->data) 189 free(extData->data); 190 if(prevData == NULL) 191 cl->extensions = extData->next; 192 else 193 prevData->next = extData->next; 194 return TRUE; 195 } 196 prevData = extData; 197 } 198 199 return FALSE; 200 } 201 202 void* rfbGetExtensionClientData(rfbClientPtr cl, rfbProtocolExtension* extension) 203 { 204 rfbExtensionData* data = cl->extensions; 205 206 while(data && data->extension != extension) 207 data = data->next; 208 209 if(data == NULL) { 210 rfbLog("Extension is not enabled !\n"); 211 /* rfbCloseClient(cl); */ 212 return NULL; 213 } 214 215 return data->data; 216 } 217 218 /* 219 * Logging 220 */ 221 222 void rfbLogEnable(int enabled) { 223 rfbEnableLogging=enabled; 224 } 225 226 /* 227 * rfbLog prints a time-stamped message to the log file (stderr). 228 */ 229 230 static void 231 rfbDefaultLog(const char *format, ...) 232 { 233 va_list args; 234 char buf[256]; 235 time_t log_clock; 236 237 if(!rfbEnableLogging) 238 return; 239 240 if (! logMutex_initialized) { 241 INIT_MUTEX(logMutex); 242 logMutex_initialized = 1; 243 } 244 245 LOCK(logMutex); 246 va_start(args, format); 247 248 time(&log_clock); 249 strftime(buf, 255, "%d/%m/%Y %X ", localtime(&log_clock)); 250 fprintf(stderr, "%s", buf); 251 252 vfprintf(stderr, format, args); 253 fflush(stderr); 254 255 va_end(args); 256 UNLOCK(logMutex); 257 } 258 259 rfbLogProc rfbLog=rfbDefaultLog; 260 rfbLogProc rfbErr=rfbDefaultLog; 261 262 void rfbLogPerror(const char *str) 263 { 264 rfbErr("%s: %s\n", str, strerror(errno)); 265 } 266 267 void rfbScheduleCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,int dx,int dy) 268 { 269 rfbClientIteratorPtr iterator; 270 rfbClientPtr cl; 271 272 iterator=rfbGetClientIterator(rfbScreen); 273 while((cl=rfbClientIteratorNext(iterator))) { 274 LOCK(cl->updateMutex); 275 if(cl->useCopyRect) { 276 sraRegionPtr modifiedRegionBackup; 277 if(!sraRgnEmpty(cl->copyRegion)) { 278 if(cl->copyDX!=dx || cl->copyDY!=dy) { 279 /* if a copyRegion was not yet executed, treat it as a 280 * modifiedRegion. The idea: in this case it could be 281 * source of the new copyRect or modified anyway. */ 282 sraRgnOr(cl->modifiedRegion,cl->copyRegion); 283 sraRgnMakeEmpty(cl->copyRegion); 284 } else { 285 /* we have to set the intersection of the source of the copy 286 * and the old copy to modified. */ 287 modifiedRegionBackup=sraRgnCreateRgn(copyRegion); 288 sraRgnOffset(modifiedRegionBackup,-dx,-dy); 289 sraRgnAnd(modifiedRegionBackup,cl->copyRegion); 290 sraRgnOr(cl->modifiedRegion,modifiedRegionBackup); 291 sraRgnDestroy(modifiedRegionBackup); 292 } 293 } 294 295 sraRgnOr(cl->copyRegion,copyRegion); 296 cl->copyDX = dx; 297 cl->copyDY = dy; 298 299 /* if there were modified regions, which are now copied, 300 * mark them as modified, because the source of these can be overlapped 301 * either by new modified or now copied regions. */ 302 modifiedRegionBackup=sraRgnCreateRgn(cl->modifiedRegion); 303 sraRgnOffset(modifiedRegionBackup,dx,dy); 304 sraRgnAnd(modifiedRegionBackup,cl->copyRegion); 305 sraRgnOr(cl->modifiedRegion,modifiedRegionBackup); 306 sraRgnDestroy(modifiedRegionBackup); 307 308 if(!cl->enableCursorShapeUpdates) { 309 /* 310 * n.b. (dx, dy) is the vector pointing in the direction the 311 * copyrect displacement will take place. copyRegion is the 312 * destination rectangle (say), not the source rectangle. 313 */ 314 sraRegionPtr cursorRegion; 315 int x = cl->cursorX - cl->screen->cursor->xhot; 316 int y = cl->cursorY - cl->screen->cursor->yhot; 317 int w = cl->screen->cursor->width; 318 int h = cl->screen->cursor->height; 319 320 cursorRegion = sraRgnCreateRect(x, y, x + w, y + h); 321 sraRgnAnd(cursorRegion, cl->copyRegion); 322 if(!sraRgnEmpty(cursorRegion)) { 323 /* 324 * current cursor rect overlaps with the copy region *dest*, 325 * mark it as modified since we won't copy-rect stuff to it. 326 */ 327 sraRgnOr(cl->modifiedRegion, cursorRegion); 328 } 329 sraRgnDestroy(cursorRegion); 330 331 cursorRegion = sraRgnCreateRect(x, y, x + w, y + h); 332 /* displace it to check for overlap with copy region source: */ 333 sraRgnOffset(cursorRegion, dx, dy); 334 sraRgnAnd(cursorRegion, cl->copyRegion); 335 if(!sraRgnEmpty(cursorRegion)) { 336 /* 337 * current cursor rect overlaps with the copy region *source*, 338 * mark the *displaced* cursorRegion as modified since we 339 * won't copyrect stuff to it. 340 */ 341 sraRgnOr(cl->modifiedRegion, cursorRegion); 342 } 343 sraRgnDestroy(cursorRegion); 344 } 345 346 } else { 347 sraRgnOr(cl->modifiedRegion,copyRegion); 348 } 349 TSIGNAL(cl->updateCond); 350 UNLOCK(cl->updateMutex); 351 } 352 353 rfbReleaseClientIterator(iterator); 354 } 355 356 void rfbDoCopyRegion(rfbScreenInfoPtr screen,sraRegionPtr copyRegion,int dx,int dy) 357 { 358 sraRectangleIterator* i; 359 sraRect rect; 360 int j,widthInBytes,bpp=screen->serverFormat.bitsPerPixel/8, 361 rowstride=screen->paddedWidthInBytes; 362 char *in,*out; 363 364 /* copy it, really */ 365 i = sraRgnGetReverseIterator(copyRegion,dx<0,dy<0); 366 while(sraRgnIteratorNext(i,&rect)) { 367 widthInBytes = (rect.x2-rect.x1)*bpp; 368 out = screen->frameBuffer+rect.x1*bpp+rect.y1*rowstride; 369 in = screen->frameBuffer+(rect.x1-dx)*bpp+(rect.y1-dy)*rowstride; 370 if(dy<0) 371 for(j=rect.y1;j<rect.y2;j++,out+=rowstride,in+=rowstride) 372 memmove(out,in,widthInBytes); 373 else { 374 out += rowstride*(rect.y2-rect.y1-1); 375 in += rowstride*(rect.y2-rect.y1-1); 376 for(j=rect.y2-1;j>=rect.y1;j--,out-=rowstride,in-=rowstride) 377 memmove(out,in,widthInBytes); 378 } 379 } 380 sraRgnReleaseIterator(i); 381 382 rfbScheduleCopyRegion(screen,copyRegion,dx,dy); 383 } 384 385 void rfbDoCopyRect(rfbScreenInfoPtr screen,int x1,int y1,int x2,int y2,int dx,int dy) 386 { 387 sraRegionPtr region = sraRgnCreateRect(x1,y1,x2,y2); 388 rfbDoCopyRegion(screen,region,dx,dy); 389 sraRgnDestroy(region); 390 } 391 392 void rfbScheduleCopyRect(rfbScreenInfoPtr screen,int x1,int y1,int x2,int y2,int dx,int dy) 393 { 394 sraRegionPtr region = sraRgnCreateRect(x1,y1,x2,y2); 395 rfbScheduleCopyRegion(screen,region,dx,dy); 396 sraRgnDestroy(region); 397 } 398 399 void rfbMarkRegionAsModified(rfbScreenInfoPtr screen,sraRegionPtr modRegion) 400 { 401 rfbClientIteratorPtr iterator; 402 rfbClientPtr cl; 403 404 iterator=rfbGetClientIterator(screen); 405 while((cl=rfbClientIteratorNext(iterator))) { 406 LOCK(cl->updateMutex); 407 sraRgnOr(cl->modifiedRegion,modRegion); 408 TSIGNAL(cl->updateCond); 409 UNLOCK(cl->updateMutex); 410 } 411 412 rfbReleaseClientIterator(iterator); 413 } 414 415 void rfbScaledScreenUpdate(rfbScreenInfoPtr screen, int x1, int y1, int x2, int y2); 416 void rfbMarkRectAsModified(rfbScreenInfoPtr screen,int x1,int y1,int x2,int y2) 417 { 418 sraRegionPtr region; 419 int i; 420 421 if(x1>x2) { i=x1; x1=x2; x2=i; } 422 if(x1<0) x1=0; 423 if(x2>screen->width) x2=screen->width; 424 if(x1==x2) return; 425 426 if(y1>y2) { i=y1; y1=y2; y2=i; } 427 if(y1<0) y1=0; 428 if(y2>screen->height) y2=screen->height; 429 if(y1==y2) return; 430 431 /* update scaled copies for this rectangle */ 432 rfbScaledScreenUpdate(screen,x1,y1,x2,y2); 433 434 region = sraRgnCreateRect(x1,y1,x2,y2); 435 rfbMarkRegionAsModified(screen,region); 436 sraRgnDestroy(region); 437 } 438 439 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD 440 #include <unistd.h> 441 442 static void * 443 clientOutput(void *data) 444 { 445 rfbClientPtr cl = (rfbClientPtr)data; 446 rfbBool haveUpdate; 447 sraRegion* updateRegion; 448 449 while (1) { 450 haveUpdate = false; 451 while (!haveUpdate) { 452 if (cl->sock == -1) { 453 /* Client has disconnected. */ 454 return NULL; 455 } 456 if (cl->state != RFB_NORMAL || cl->onHold) { 457 /* just sleep until things get normal */ 458 usleep(cl->screen->deferUpdateTime * 1000); 459 continue; 460 } 461 462 LOCK(cl->updateMutex); 463 464 if (sraRgnEmpty(cl->requestedRegion)) { 465 ; /* always require a FB Update Request (otherwise can crash.) */ 466 } else { 467 haveUpdate = FB_UPDATE_PENDING(cl); 468 if(!haveUpdate) { 469 updateRegion = sraRgnCreateRgn(cl->modifiedRegion); 470 haveUpdate = sraRgnAnd(updateRegion,cl->requestedRegion); 471 sraRgnDestroy(updateRegion); 472 } 473 } 474 475 if (!haveUpdate) { 476 WAIT(cl->updateCond, cl->updateMutex); 477 } 478 479 UNLOCK(cl->updateMutex); 480 } 481 482 /* OK, now, to save bandwidth, wait a little while for more 483 updates to come along. */ 484 usleep(cl->screen->deferUpdateTime * 1000); 485 486 /* Now, get the region we're going to update, and remove 487 it from cl->modifiedRegion _before_ we send the update. 488 That way, if anything that overlaps the region we're sending 489 is updated, we'll be sure to do another update later. */ 490 LOCK(cl->updateMutex); 491 updateRegion = sraRgnCreateRgn(cl->modifiedRegion); 492 UNLOCK(cl->updateMutex); 493 494 /* Now actually send the update. */ 495 rfbIncrClientRef(cl); 496 LOCK(cl->sendMutex); 497 rfbSendFramebufferUpdate(cl, updateRegion); 498 UNLOCK(cl->sendMutex); 499 rfbDecrClientRef(cl); 500 501 sraRgnDestroy(updateRegion); 502 } 503 504 /* Not reached. */ 505 return NULL; 506 } 507 508 static void * 509 clientInput(void *data) 510 { 511 rfbClientPtr cl = (rfbClientPtr)data; 512 pthread_t output_thread; 513 pthread_create(&output_thread, NULL, clientOutput, (void *)cl); 514 515 while (1) { 516 fd_set rfds, wfds, efds; 517 struct timeval tv; 518 int n; 519 520 if (cl->sock == -1) { 521 /* Client has disconnected. */ 522 break; 523 } 524 525 FD_ZERO(&rfds); 526 FD_SET(cl->sock, &rfds); 527 FD_ZERO(&efds); 528 FD_SET(cl->sock, &efds); 529 530 /* Are we transferring a file in the background? */ 531 FD_ZERO(&wfds); 532 if ((cl->fileTransfer.fd!=-1) && (cl->fileTransfer.sending==1)) 533 FD_SET(cl->sock, &wfds); 534 535 tv.tv_sec = 60; /* 1 minute */ 536 tv.tv_usec = 0; 537 n = select(cl->sock + 1, &rfds, &wfds, &efds, &tv); 538 if (n < 0) { 539 rfbLogPerror("ReadExact: select"); 540 break; 541 } 542 if (n == 0) /* timeout */ 543 { 544 rfbSendFileTransferChunk(cl); 545 continue; 546 } 547 548 /* We have some space on the transmit queue, send some data */ 549 if (FD_ISSET(cl->sock, &wfds)) 550 rfbSendFileTransferChunk(cl); 551 552 if (FD_ISSET(cl->sock, &rfds) || FD_ISSET(cl->sock, &efds)) 553 rfbProcessClientMessage(cl); 554 } 555 556 /* Get rid of the output thread. */ 557 LOCK(cl->updateMutex); 558 TSIGNAL(cl->updateCond); 559 UNLOCK(cl->updateMutex); 560 IF_PTHREADS(pthread_join(output_thread, NULL)); 561 562 rfbClientConnectionGone(cl); 563 564 return NULL; 565 } 566 567 static void* 568 listenerRun(void *data) 569 { 570 rfbScreenInfoPtr screen=(rfbScreenInfoPtr)data; 571 int client_fd; 572 struct sockaddr_storage peer; 573 rfbClientPtr cl = NULL; 574 socklen_t len; 575 fd_set listen_fds; /* temp file descriptor list for select() */ 576 577 /* TODO: this thread wont die by restarting the server */ 578 /* TODO: HTTP is not handled */ 579 while (1) { 580 client_fd = -1; 581 FD_ZERO(&listen_fds); 582 if(screen->listenSock >= 0) 583 FD_SET(screen->listenSock, &listen_fds); 584 if(screen->listen6Sock >= 0) 585 FD_SET(screen->listen6Sock, &listen_fds); 586 587 if (select(screen->maxFd+1, &listen_fds, NULL, NULL, NULL) == -1) { 588 rfbLogPerror("listenerRun: error in select"); 589 return NULL; 590 } 591 592 /* there is something on the listening sockets, handle new connections */ 593 len = sizeof (peer); 594 if (FD_ISSET(screen->listenSock, &listen_fds)) 595 client_fd = accept(screen->listenSock, (struct sockaddr*)&peer, &len); 596 else if (FD_ISSET(screen->listen6Sock, &listen_fds)) 597 client_fd = accept(screen->listen6Sock, (struct sockaddr*)&peer, &len); 598 599 if(client_fd >= 0) 600 cl = rfbNewClient(screen,client_fd); 601 if (cl && !cl->onHold ) 602 rfbStartOnHoldClient(cl); 603 } 604 return(NULL); 605 } 606 607 void 608 rfbStartOnHoldClient(rfbClientPtr cl) 609 { 610 pthread_create(&cl->client_thread, NULL, clientInput, (void *)cl); 611 } 612 613 #else 614 615 void 616 rfbStartOnHoldClient(rfbClientPtr cl) 617 { 618 cl->onHold = FALSE; 619 } 620 621 #endif 622 623 void 624 rfbRefuseOnHoldClient(rfbClientPtr cl) 625 { 626 rfbCloseClient(cl); 627 rfbClientConnectionGone(cl); 628 } 629 630 static void 631 rfbDefaultKbdAddEvent(rfbBool down, rfbKeySym keySym, rfbClientPtr cl) 632 { 633 } 634 635 void 636 rfbDefaultPtrAddEvent(int buttonMask, int x, int y, rfbClientPtr cl) 637 { 638 rfbClientIteratorPtr iterator; 639 rfbClientPtr other_client; 640 rfbScreenInfoPtr s = cl->screen; 641 642 if (x != s->cursorX || y != s->cursorY) { 643 LOCK(s->cursorMutex); 644 s->cursorX = x; 645 s->cursorY = y; 646 UNLOCK(s->cursorMutex); 647 648 /* The cursor was moved by this client, so don't send CursorPos. */ 649 if (cl->enableCursorPosUpdates) 650 cl->cursorWasMoved = FALSE; 651 652 /* But inform all remaining clients about this cursor movement. */ 653 iterator = rfbGetClientIterator(s); 654 while ((other_client = rfbClientIteratorNext(iterator)) != NULL) { 655 if (other_client != cl && other_client->enableCursorPosUpdates) { 656 other_client->cursorWasMoved = TRUE; 657 } 658 } 659 rfbReleaseClientIterator(iterator); 660 } 661 } 662 663 static void rfbDefaultSetXCutText(char* text, int len, rfbClientPtr cl) 664 { 665 } 666 667 /* TODO: add a nice VNC or RFB cursor */ 668 669 #if defined(WIN32) || defined(sparc) || !defined(NO_STRICT_ANSI) 670 static rfbCursor myCursor = 671 { 672 FALSE, FALSE, FALSE, FALSE, 673 (unsigned char*)"\000\102\044\030\044\102\000", 674 (unsigned char*)"\347\347\176\074\176\347\347", 675 8, 7, 3, 3, 676 0, 0, 0, 677 0xffff, 0xffff, 0xffff, 678 NULL 679 }; 680 #else 681 static rfbCursor myCursor = 682 { 683 cleanup: FALSE, 684 cleanupSource: FALSE, 685 cleanupMask: FALSE, 686 cleanupRichSource: FALSE, 687 source: "\000\102\044\030\044\102\000", 688 mask: "\347\347\176\074\176\347\347", 689 width: 8, height: 7, xhot: 3, yhot: 3, 690 foreRed: 0, foreGreen: 0, foreBlue: 0, 691 backRed: 0xffff, backGreen: 0xffff, backBlue: 0xffff, 692 richSource: NULL 693 }; 694 #endif 695 696 static rfbCursorPtr rfbDefaultGetCursorPtr(rfbClientPtr cl) 697 { 698 return(cl->screen->cursor); 699 } 700 701 /* response is cl->authChallenge vncEncrypted with passwd */ 702 static rfbBool rfbDefaultPasswordCheck(rfbClientPtr cl,const char* response,int len) 703 { 704 int i; 705 char *passwd=rfbDecryptPasswdFromFile(cl->screen->authPasswdData); 706 707 if(!passwd) { 708 rfbErr("Couldn't read password file: %s\n",cl->screen->authPasswdData); 709 return(FALSE); 710 } 711 712 rfbEncryptBytes(cl->authChallenge, passwd); 713 714 /* Lose the password from memory */ 715 for (i = strlen(passwd); i >= 0; i--) { 716 passwd[i] = '\0'; 717 } 718 719 free(passwd); 720 721 if (memcmp(cl->authChallenge, response, len) != 0) { 722 rfbErr("authProcessClientMessage: authentication failed from %s\n", 723 cl->host); 724 return(FALSE); 725 } 726 727 return(TRUE); 728 } 729 730 /* for this method, authPasswdData is really a pointer to an array 731 of char*'s, where the last pointer is 0. */ 732 rfbBool rfbCheckPasswordByList(rfbClientPtr cl,const char* response,int len) 733 { 734 char **passwds; 735 int i=0; 736 737 for(passwds=(char**)cl->screen->authPasswdData;*passwds;passwds++,i++) { 738 uint8_t auth_tmp[CHALLENGESIZE]; 739 memcpy((char *)auth_tmp, (char *)cl->authChallenge, CHALLENGESIZE); 740 rfbEncryptBytes(auth_tmp, *passwds); 741 742 if (memcmp(auth_tmp, response, len) == 0) { 743 if(i>=cl->screen->authPasswdFirstViewOnly) 744 cl->viewOnly=TRUE; 745 return(TRUE); 746 } 747 } 748 749 rfbErr("authProcessClientMessage: authentication failed from %s\n", 750 cl->host); 751 return(FALSE); 752 } 753 754 void rfbDoNothingWithClient(rfbClientPtr cl) 755 { 756 } 757 758 static enum rfbNewClientAction rfbDefaultNewClientHook(rfbClientPtr cl) 759 { 760 return RFB_CLIENT_ACCEPT; 761 } 762 763 /* 764 * Update server's pixel format in screenInfo structure. This 765 * function is called from rfbGetScreen() and rfbNewFramebuffer(). 766 */ 767 768 static void rfbInitServerFormat(rfbScreenInfoPtr screen, int bitsPerSample) 769 { 770 rfbPixelFormat* format=&screen->serverFormat; 771 772 format->bitsPerPixel = screen->bitsPerPixel; 773 format->depth = screen->depth; 774 format->bigEndian = rfbEndianTest?FALSE:TRUE; 775 format->trueColour = TRUE; 776 screen->colourMap.count = 0; 777 screen->colourMap.is16 = 0; 778 screen->colourMap.data.bytes = NULL; 779 780 if (format->bitsPerPixel == 8) { 781 format->redMax = 7; 782 format->greenMax = 7; 783 format->blueMax = 3; 784 format->redShift = 0; 785 format->greenShift = 3; 786 format->blueShift = 6; 787 } else { 788 format->redMax = (1 << bitsPerSample) - 1; 789 format->greenMax = (1 << bitsPerSample) - 1; 790 format->blueMax = (1 << bitsPerSample) - 1; 791 if(rfbEndianTest) { 792 format->redShift = 0; 793 format->greenShift = bitsPerSample; 794 format->blueShift = bitsPerSample * 2; 795 } else { 796 if(format->bitsPerPixel==8*3) { 797 format->redShift = bitsPerSample*2; 798 format->greenShift = bitsPerSample*1; 799 format->blueShift = 0; 800 } else { 801 format->redShift = bitsPerSample*3; 802 format->greenShift = bitsPerSample*2; 803 format->blueShift = bitsPerSample; 804 } 805 } 806 } 807 } 808 809 rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv, 810 int width,int height,int bitsPerSample,int samplesPerPixel, 811 int bytesPerPixel) 812 { 813 rfbScreenInfoPtr screen=calloc(sizeof(rfbScreenInfo),1); 814 815 if (! logMutex_initialized) { 816 INIT_MUTEX(logMutex); 817 logMutex_initialized = 1; 818 } 819 820 821 if(width&3) 822 rfbErr("WARNING: Width (%d) is not a multiple of 4. VncViewer has problems with that.\n",width); 823 824 screen->autoPort=FALSE; 825 screen->clientHead=NULL; 826 screen->pointerClient=NULL; 827 screen->port=5900; 828 screen->ipv6port=5900; 829 screen->socketState=RFB_SOCKET_INIT; 830 831 screen->inetdInitDone = FALSE; 832 screen->inetdSock=-1; 833 834 screen->udpSock=-1; 835 screen->udpSockConnected=FALSE; 836 screen->udpPort=0; 837 screen->udpClient=NULL; 838 839 screen->maxFd=0; 840 screen->listenSock=-1; 841 screen->listen6Sock=-1; 842 843 screen->httpInitDone=FALSE; 844 screen->httpEnableProxyConnect=FALSE; 845 screen->httpPort=0; 846 screen->http6Port=0; 847 screen->httpDir=NULL; 848 screen->httpListenSock=-1; 849 screen->httpListen6Sock=-1; 850 screen->httpSock=-1; 851 852 screen->desktopName = "LibVNCServer"; 853 screen->alwaysShared = FALSE; 854 screen->neverShared = FALSE; 855 screen->dontDisconnect = FALSE; 856 screen->authPasswdData = NULL; 857 screen->authPasswdFirstViewOnly = 1; 858 859 screen->width = width; 860 screen->height = height; 861 screen->bitsPerPixel = screen->depth = 8*bytesPerPixel; 862 863 screen->passwordCheck = rfbDefaultPasswordCheck; 864 865 screen->ignoreSIGPIPE = TRUE; 866 867 /* disable progressive updating per default */ 868 screen->progressiveSliceHeight = 0; 869 870 screen->listenInterface = htonl(INADDR_ANY); 871 872 screen->deferUpdateTime=5; 873 screen->maxRectsPerUpdate=50; 874 875 screen->handleEventsEagerly = FALSE; 876 877 screen->protocolMajorVersion = rfbProtocolMajorVersion; 878 screen->protocolMinorVersion = rfbProtocolMinorVersion; 879 880 screen->permitFileTransfer = FALSE; 881 882 if(!rfbProcessArguments(screen,argc,argv)) { 883 free(screen); 884 return NULL; 885 } 886 887 #ifdef WIN32 888 { 889 DWORD dummy=255; 890 GetComputerName(screen->thisHost,&dummy); 891 } 892 #else 893 gethostname(screen->thisHost, 255); 894 #endif 895 896 screen->paddedWidthInBytes = width*bytesPerPixel; 897 898 /* format */ 899 900 rfbInitServerFormat(screen, bitsPerSample); 901 902 /* cursor */ 903 904 screen->cursorX=screen->cursorY=screen->underCursorBufferLen=0; 905 screen->underCursorBuffer=NULL; 906 screen->dontConvertRichCursorToXCursor = FALSE; 907 screen->cursor = &myCursor; 908 INIT_MUTEX(screen->cursorMutex); 909 910 IF_PTHREADS(screen->backgroundLoop = FALSE); 911 912 /* proc's and hook's */ 913 914 screen->kbdAddEvent = rfbDefaultKbdAddEvent; 915 screen->kbdReleaseAllKeys = rfbDoNothingWithClient; 916 screen->ptrAddEvent = rfbDefaultPtrAddEvent; 917 screen->setXCutText = rfbDefaultSetXCutText; 918 screen->getCursorPtr = rfbDefaultGetCursorPtr; 919 screen->setTranslateFunction = rfbSetTranslateFunction; 920 screen->newClientHook = rfbDefaultNewClientHook; 921 screen->displayHook = NULL; 922 screen->displayFinishedHook = NULL; 923 screen->getKeyboardLedStateHook = NULL; 924 screen->xvpHook = NULL; 925 926 /* initialize client list and iterator mutex */ 927 rfbClientListInit(screen); 928 929 return(screen); 930 } 931 932 /* 933 * Switch to another framebuffer (maybe of different size and color 934 * format). Clients supporting NewFBSize pseudo-encoding will change 935 * their local framebuffer dimensions if necessary. 936 * NOTE: Rich cursor data should be converted to new pixel format by 937 * the caller. 938 */ 939 940 void rfbNewFramebuffer(rfbScreenInfoPtr screen, char *framebuffer, 941 int width, int height, 942 int bitsPerSample, int samplesPerPixel, 943 int bytesPerPixel) 944 { 945 rfbPixelFormat old_format; 946 rfbBool format_changed = FALSE; 947 rfbClientIteratorPtr iterator; 948 rfbClientPtr cl; 949 950 /* Update information in the screenInfo structure */ 951 952 old_format = screen->serverFormat; 953 954 if (width & 3) 955 rfbErr("WARNING: New width (%d) is not a multiple of 4.\n", width); 956 957 screen->width = width; 958 screen->height = height; 959 screen->bitsPerPixel = screen->depth = 8*bytesPerPixel; 960 screen->paddedWidthInBytes = width*bytesPerPixel; 961 962 rfbInitServerFormat(screen, bitsPerSample); 963 964 if (memcmp(&screen->serverFormat, &old_format, 965 sizeof(rfbPixelFormat)) != 0) { 966 format_changed = TRUE; 967 } 968 969 screen->frameBuffer = framebuffer; 970 971 /* Adjust pointer position if necessary */ 972 973 if (screen->cursorX >= width) 974 screen->cursorX = width - 1; 975 if (screen->cursorY >= height) 976 screen->cursorY = height - 1; 977 978 /* For each client: */ 979 iterator = rfbGetClientIterator(screen); 980 while ((cl = rfbClientIteratorNext(iterator)) != NULL) { 981 982 /* Re-install color translation tables if necessary */ 983 984 if (format_changed) 985 screen->setTranslateFunction(cl); 986 987 /* Mark the screen contents as changed, and schedule sending 988 NewFBSize message if supported by this client. */ 989 990 LOCK(cl->updateMutex); 991 sraRgnDestroy(cl->modifiedRegion); 992 cl->modifiedRegion = sraRgnCreateRect(0, 0, width, height); 993 sraRgnMakeEmpty(cl->copyRegion); 994 cl->copyDX = 0; 995 cl->copyDY = 0; 996 997 if (cl->useNewFBSize) 998 cl->newFBSizePending = TRUE; 999 1000 TSIGNAL(cl->updateCond); 1001 UNLOCK(cl->updateMutex); 1002 } 1003 rfbReleaseClientIterator(iterator); 1004 } 1005 1006 /* hang up on all clients and free all reserved memory */ 1007 1008 void rfbScreenCleanup(rfbScreenInfoPtr screen) 1009 { 1010 rfbClientIteratorPtr i=rfbGetClientIterator(screen); 1011 rfbClientPtr cl,cl1=rfbClientIteratorNext(i); 1012 while(cl1) { 1013 cl=rfbClientIteratorNext(i); 1014 rfbClientConnectionGone(cl1); 1015 cl1=cl; 1016 } 1017 rfbReleaseClientIterator(i); 1018 1019 #define FREE_IF(x) if(screen->x) free(screen->x) 1020 FREE_IF(colourMap.data.bytes); 1021 FREE_IF(underCursorBuffer); 1022 TINI_MUTEX(screen->cursorMutex); 1023 if(screen->cursor && screen->cursor->cleanup) 1024 rfbFreeCursor(screen->cursor); 1025 1026 #ifdef LIBVNCSERVER_HAVE_LIBZ 1027 rfbZlibCleanup(screen); 1028 #ifdef LIBVNCSERVER_HAVE_LIBJPEG 1029 rfbTightCleanup(screen); 1030 #endif 1031 1032 /* free all 'scaled' versions of this screen */ 1033 while (screen->scaledScreenNext!=NULL) 1034 { 1035 rfbScreenInfoPtr ptr; 1036 ptr = screen->scaledScreenNext; 1037 screen->scaledScreenNext = ptr->scaledScreenNext; 1038 free(ptr->frameBuffer); 1039 free(ptr); 1040 } 1041 1042 #endif 1043 free(screen); 1044 } 1045 1046 void rfbInitServer(rfbScreenInfoPtr screen) 1047 { 1048 #ifdef WIN32 1049 WSADATA trash; 1050 WSAStartup(MAKEWORD(2,2),&trash); 1051 #endif 1052 rfbInitSockets(screen); 1053 rfbHttpInitSockets(screen); 1054 #ifndef WIN32 1055 if(screen->ignoreSIGPIPE) 1056 signal(SIGPIPE,SIG_IGN); 1057 #endif 1058 } 1059 1060 void rfbShutdownServer(rfbScreenInfoPtr screen,rfbBool disconnectClients) { 1061 if(disconnectClients) { 1062 rfbClientPtr cl; 1063 rfbClientIteratorPtr iter = rfbGetClientIterator(screen); 1064 while( (cl = rfbClientIteratorNext(iter)) ) { 1065 if (cl->sock > -1) { 1066 /* we don't care about maxfd here, because the server goes away */ 1067 rfbCloseClient(cl); 1068 rfbClientConnectionGone(cl); 1069 } 1070 } 1071 rfbReleaseClientIterator(iter); 1072 } 1073 1074 rfbShutdownSockets(screen); 1075 rfbHttpShutdownSockets(screen); 1076 } 1077 1078 #ifndef LIBVNCSERVER_HAVE_GETTIMEOFDAY 1079 #include <fcntl.h> 1080 #include <conio.h> 1081 #include <sys/timeb.h> 1082 1083 void gettimeofday(struct timeval* tv,char* dummy) 1084 { 1085 SYSTEMTIME t; 1086 GetSystemTime(&t); 1087 tv->tv_sec=t.wHour*3600+t.wMinute*60+t.wSecond; 1088 tv->tv_usec=t.wMilliseconds*1000; 1089 } 1090 #endif 1091 1092 rfbBool 1093 rfbProcessEvents(rfbScreenInfoPtr screen,long usec) 1094 { 1095 rfbClientIteratorPtr i; 1096 rfbClientPtr cl,clPrev; 1097 rfbBool result=FALSE; 1098 extern rfbClientIteratorPtr 1099 rfbGetClientIteratorWithClosed(rfbScreenInfoPtr rfbScreen); 1100 1101 if(usec<0) 1102 usec=screen->deferUpdateTime*1000; 1103 1104 rfbCheckFds(screen,usec); 1105 rfbHttpCheckFds(screen); 1106 1107 i = rfbGetClientIteratorWithClosed(screen); 1108 cl=rfbClientIteratorHead(i); 1109 while(cl) { 1110 result = rfbUpdateClient(cl); 1111 clPrev=cl; 1112 cl=rfbClientIteratorNext(i); 1113 if(clPrev->sock==-1) { 1114 rfbClientConnectionGone(clPrev); 1115 result=TRUE; 1116 } 1117 } 1118 rfbReleaseClientIterator(i); 1119 1120 return result; 1121 } 1122 1123 rfbBool 1124 rfbUpdateClient(rfbClientPtr cl) 1125 { 1126 struct timeval tv; 1127 rfbBool result=FALSE; 1128 rfbScreenInfoPtr screen = cl->screen; 1129 1130 if (cl->sock >= 0 && !cl->onHold && FB_UPDATE_PENDING(cl) && 1131 !sraRgnEmpty(cl->requestedRegion)) { 1132 result=TRUE; 1133 if(screen->deferUpdateTime == 0) { 1134 rfbSendFramebufferUpdate(cl,cl->modifiedRegion); 1135 } else if(cl->startDeferring.tv_usec == 0) { 1136 gettimeofday(&cl->startDeferring,NULL); 1137 if(cl->startDeferring.tv_usec == 0) 1138 cl->startDeferring.tv_usec++; 1139 } else { 1140 gettimeofday(&tv,NULL); 1141 if(tv.tv_sec < cl->startDeferring.tv_sec /* at midnight */ 1142 || ((tv.tv_sec-cl->startDeferring.tv_sec)*1000 1143 +(tv.tv_usec-cl->startDeferring.tv_usec)/1000) 1144 > screen->deferUpdateTime) { 1145 cl->startDeferring.tv_usec = 0; 1146 rfbSendFramebufferUpdate(cl,cl->modifiedRegion); 1147 } 1148 } 1149 } 1150 1151 if (!cl->viewOnly && cl->lastPtrX >= 0) { 1152 if(cl->startPtrDeferring.tv_usec == 0) { 1153 gettimeofday(&cl->startPtrDeferring,NULL); 1154 if(cl->startPtrDeferring.tv_usec == 0) 1155 cl->startPtrDeferring.tv_usec++; 1156 } else { 1157 struct timeval tv; 1158 gettimeofday(&tv,NULL); 1159 if(tv.tv_sec < cl->startPtrDeferring.tv_sec /* at midnight */ 1160 || ((tv.tv_sec-cl->startPtrDeferring.tv_sec)*1000 1161 +(tv.tv_usec-cl->startPtrDeferring.tv_usec)/1000) 1162 > cl->screen->deferPtrUpdateTime) { 1163 cl->startPtrDeferring.tv_usec = 0; 1164 cl->screen->ptrAddEvent(cl->lastPtrButtons, 1165 cl->lastPtrX, 1166 cl->lastPtrY, cl); 1167 cl->lastPtrX = -1; 1168 } 1169 } 1170 } 1171 1172 return result; 1173 } 1174 1175 rfbBool rfbIsActive(rfbScreenInfoPtr screenInfo) { 1176 return screenInfo->socketState!=RFB_SOCKET_SHUTDOWN || screenInfo->clientHead!=NULL; 1177 } 1178 1179 void rfbRunEventLoop(rfbScreenInfoPtr screen, long usec, rfbBool runInBackground) 1180 { 1181 if(runInBackground) { 1182 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD 1183 pthread_t listener_thread; 1184 1185 screen->backgroundLoop = TRUE; 1186 1187 pthread_create(&listener_thread, NULL, listenerRun, screen); 1188 return; 1189 #else 1190 rfbErr("Can't run in background, because I don't have PThreads!\n"); 1191 return; 1192 #endif 1193 } 1194 1195 if(usec<0) 1196 usec=screen->deferUpdateTime*1000; 1197 1198 while(rfbIsActive(screen)) 1199 rfbProcessEvents(screen,usec); 1200 } 1201