PageRenderTime 83ms CodeModel.GetById 15ms app.highlight 60ms RepoModel.GetById 1ms app.codeStats 0ms

/apps/desktop/libvncserver/main.c

http://ftk.googlecode.com/
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}