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