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@gmx.de> 6 * Original OSXvnc (C) 2001 Dan McGuirk <mcguirk@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 41static int extMutex_initialized = 0; 42static int logMutex_initialized = 0; 43#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD 44static MUTEX(logMutex); 45static MUTEX(extMutex); 46#endif 47 48static int rfbEnableLogging=1; 49 50#ifdef LIBVNCSERVER_WORDS_BIGENDIAN 51char rfbEndianTest = (1==0); 52#else 53char rfbEndianTest = (1==1); 54#endif 55 56/* 57 * Protocol extensions 58 */ 59 60static 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 */ 68void 69rfbRegisterProtocolExtension(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 */ 107void 108rfbUnregisterProtocolExtension(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 146rfbProtocolExtension* rfbGetExtensionIterator() 147{ 148 if (! extMutex_initialized) { 149 INIT_MUTEX(extMutex); 150 extMutex_initialized = 1; 151 } 152 153 LOCK(extMutex); 154 return rfbExtensionHead; 155} 156 157void rfbReleaseExtensionIterator() 158{ 159 UNLOCK(extMutex); 160} 161 162rfbBool 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 181rfbBool 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 202void* 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 222void rfbLogEnable(int enabled) { 223 rfbEnableLogging=enabled; 224} 225 226/* 227 * rfbLog prints a time-stamped message to the log file (stderr). 228 */ 229 230static void 231rfbDefaultLog(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 259rfbLogProc rfbLog=rfbDefaultLog; 260rfbLogProc rfbErr=rfbDefaultLog; 261 262void rfbLogPerror(const char *str) 263{ 264 rfbErr("%s: %s\n", str, strerror(errno)); 265} 266 267void 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 356void 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 385void 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 392void 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 399void 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 415void rfbScaledScreenUpdate(rfbScreenInfoPtr screen, int x1, int y1, int x2, int y2); 416void 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 442static void * 443clientOutput(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 508static void * 509clientInput(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 567static void* 568listenerRun(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 607void 608rfbStartOnHoldClient(rfbClientPtr cl) 609{ 610 pthread_create(&cl->client_thread, NULL, clientInput, (void *)cl); 611} 612 613#else 614 615void 616rfbStartOnHoldClient(rfbClientPtr cl) 617{ 618 cl->onHold = FALSE; 619} 620 621#endif 622 623void 624rfbRefuseOnHoldClient(rfbClientPtr cl) 625{ 626 rfbCloseClient(cl); 627 rfbClientConnectionGone(cl); 628} 629 630static void 631rfbDefaultKbdAddEvent(rfbBool down, rfbKeySym keySym, rfbClientPtr cl) 632{ 633} 634 635void 636rfbDefaultPtrAddEvent(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 663static 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) 670static 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 681static 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 696static rfbCursorPtr rfbDefaultGetCursorPtr(rfbClientPtr cl) 697{ 698 return(cl->screen->cursor); 699} 700 701/* response is cl->authChallenge vncEncrypted with passwd */ 702static 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. */ 732rfbBool 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 754void rfbDoNothingWithClient(rfbClientPtr cl) 755{ 756} 757 758static 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 768static 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 809rfbScreenInfoPtr 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 940void 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 1008void 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 1046void 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 __MINGW32__ 1055 if(screen->ignoreSIGPIPE) 1056 signal(SIGPIPE,SIG_IGN); 1057#endif 1058} 1059 1060void 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 rfbReleaseClientIterator(iter); 1069 } 1070 1071 rfbShutdownSockets(screen); 1072 rfbHttpShutdownSockets(screen); 1073} 1074 1075#ifndef LIBVNCSERVER_HAVE_GETTIMEOFDAY 1076#include <fcntl.h> 1077#include <conio.h> 1078#include <sys/timeb.h> 1079 1080void gettimeofday(struct timeval* tv,char* dummy) 1081{ 1082 SYSTEMTIME t; 1083 GetSystemTime(&t); 1084 tv->tv_sec=t.wHour*3600+t.wMinute*60+t.wSecond; 1085 tv->tv_usec=t.wMilliseconds*1000; 1086} 1087#endif 1088 1089rfbBool 1090rfbProcessEvents(rfbScreenInfoPtr screen,long usec) 1091{ 1092 rfbClientIteratorPtr i; 1093 rfbClientPtr cl,clPrev; 1094 rfbBool result=FALSE; 1095 extern rfbClientIteratorPtr 1096 rfbGetClientIteratorWithClosed(rfbScreenInfoPtr rfbScreen); 1097 1098 if(usec<0) 1099 usec=screen->deferUpdateTime*1000; 1100 1101 rfbCheckFds(screen,usec); 1102 rfbHttpCheckFds(screen); 1103 1104 i = rfbGetClientIteratorWithClosed(screen); 1105 cl=rfbClientIteratorHead(i); 1106 while(cl) { 1107 result = rfbUpdateClient(cl); 1108 clPrev=cl; 1109 cl=rfbClientIteratorNext(i); 1110 if(clPrev->sock==-1) { 1111 rfbClientConnectionGone(clPrev); 1112 result=TRUE; 1113 } 1114 } 1115 rfbReleaseClientIterator(i); 1116 1117 return result; 1118} 1119 1120rfbBool 1121rfbUpdateClient(rfbClientPtr cl) 1122{ 1123 struct timeval tv; 1124 rfbBool result=FALSE; 1125 rfbScreenInfoPtr screen = cl->screen; 1126 1127 if (cl->sock >= 0 && !cl->onHold && FB_UPDATE_PENDING(cl) && 1128 !sraRgnEmpty(cl->requestedRegion)) { 1129 result=TRUE; 1130 if(screen->deferUpdateTime == 0) { 1131 rfbSendFramebufferUpdate(cl,cl->modifiedRegion); 1132 } else if(cl->startDeferring.tv_usec == 0) { 1133 gettimeofday(&cl->startDeferring,NULL); 1134 if(cl->startDeferring.tv_usec == 0) 1135 cl->startDeferring.tv_usec++; 1136 } else { 1137 gettimeofday(&tv,NULL); 1138 if(tv.tv_sec < cl->startDeferring.tv_sec /* at midnight */ 1139 || ((tv.tv_sec-cl->startDeferring.tv_sec)*1000 1140 +(tv.tv_usec-cl->startDeferring.tv_usec)/1000) 1141 > screen->deferUpdateTime) { 1142 cl->startDeferring.tv_usec = 0; 1143 rfbSendFramebufferUpdate(cl,cl->modifiedRegion); 1144 } 1145 } 1146 } 1147 1148 if (!cl->viewOnly && cl->lastPtrX >= 0) { 1149 if(cl->startPtrDeferring.tv_usec == 0) { 1150 gettimeofday(&cl->startPtrDeferring,NULL); 1151 if(cl->startPtrDeferring.tv_usec == 0) 1152 cl->startPtrDeferring.tv_usec++; 1153 } else { 1154 struct timeval tv; 1155 gettimeofday(&tv,NULL); 1156 if(tv.tv_sec < cl->startPtrDeferring.tv_sec /* at midnight */ 1157 || ((tv.tv_sec-cl->startPtrDeferring.tv_sec)*1000 1158 +(tv.tv_usec-cl->startPtrDeferring.tv_usec)/1000) 1159 > cl->screen->deferPtrUpdateTime) { 1160 cl->startPtrDeferring.tv_usec = 0; 1161 cl->screen->ptrAddEvent(cl->lastPtrButtons, 1162 cl->lastPtrX, 1163 cl->lastPtrY, cl); 1164 cl->lastPtrX = -1; 1165 } 1166 } 1167 } 1168 1169 return result; 1170} 1171 1172rfbBool rfbIsActive(rfbScreenInfoPtr screenInfo) { 1173 return screenInfo->socketState!=RFB_SOCKET_SHUTDOWN || screenInfo->clientHead!=NULL; 1174} 1175 1176void rfbRunEventLoop(rfbScreenInfoPtr screen, long usec, rfbBool runInBackground) 1177{ 1178 if(runInBackground) { 1179#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD 1180 pthread_t listener_thread; 1181 1182 screen->backgroundLoop = TRUE; 1183 1184 pthread_create(&listener_thread, NULL, listenerRun, screen); 1185 return; 1186#else 1187 rfbErr("Can't run in background, because I don't have PThreads!\n"); 1188 return; 1189#endif 1190 } 1191 1192 if(usec<0) 1193 usec=screen->deferUpdateTime*1000; 1194 1195 while(rfbIsActive(screen)) 1196 rfbProcessEvents(screen,usec); 1197} 1198