add libvncserver
[presencevnc] / libvnc / libvncserver / main.c
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
41 static int extMutex_initialized = 0;
42 static int logMutex_initialized = 0;
43 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
44 static MUTEX(logMutex);
45 static MUTEX(extMutex);
46 #endif
47
48 static int rfbEnableLogging=1;
49
50 #ifdef LIBVNCSERVER_WORDS_BIGENDIAN
51 char rfbEndianTest = (1==0);
52 #else
53 char rfbEndianTest = (1==1);
54 #endif
55
56 /*
57  * Protocol extensions
58  */
59
60 static rfbProtocolExtension* rfbExtensionHead = NULL;
61
62 /*
63  * This method registers a list of new extensions.  
64  * It avoids same extension getting registered multiple times. 
65  * The order is not preserved if multiple extensions are
66  * registered at one-go.
67  */
68 void
69 rfbRegisterProtocolExtension(rfbProtocolExtension* extension)
70 {
71         rfbProtocolExtension *head = rfbExtensionHead, *next = NULL;
72
73         if(extension == NULL)
74                 return;
75
76         next = extension->next;
77
78         if (! extMutex_initialized) {
79                 INIT_MUTEX(extMutex);
80                 extMutex_initialized = 1;
81         }
82
83         LOCK(extMutex);
84
85         while(head != NULL) {
86                 if(head == extension) {
87                         UNLOCK(extMutex);
88                         rfbRegisterProtocolExtension(next);
89                         return;
90                 }
91
92                 head = head->next;
93         }
94
95         extension->next = rfbExtensionHead;
96         rfbExtensionHead = extension;
97
98         UNLOCK(extMutex);
99         rfbRegisterProtocolExtension(next);
100 }
101
102 /*
103  * This method unregisters a list of extensions.  
104  * These extensions won't be available for any new
105  * client connection. 
106  */
107 void
108 rfbUnregisterProtocolExtension(rfbProtocolExtension* extension)
109 {
110
111         rfbProtocolExtension *cur = NULL, *pre = NULL;
112
113         if(extension == NULL)
114                 return;
115
116         if (! extMutex_initialized) {
117                 INIT_MUTEX(extMutex);
118                 extMutex_initialized = 1;
119         }
120
121         LOCK(extMutex);
122
123         if(rfbExtensionHead == extension) {
124                 rfbExtensionHead = rfbExtensionHead->next;
125                 UNLOCK(extMutex);
126                 rfbUnregisterProtocolExtension(extension->next);
127                 return;
128         }
129
130         cur = pre = rfbExtensionHead;
131
132         while(cur) {
133                 if(cur == extension) {
134                         pre->next = cur->next;
135                         break;
136                 }
137                 pre = cur;
138                 cur = cur->next;
139         }
140
141         UNLOCK(extMutex);
142
143         rfbUnregisterProtocolExtension(extension->next);
144 }
145
146 rfbProtocolExtension* rfbGetExtensionIterator()
147 {
148         LOCK(extMutex);
149         return rfbExtensionHead;
150 }
151
152 void rfbReleaseExtensionIterator()
153 {
154         UNLOCK(extMutex);
155 }
156
157 rfbBool 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
176 rfbBool 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
197 void* 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
217 void rfbLogEnable(int enabled) {
218   rfbEnableLogging=enabled;
219 }
220
221 /*
222  * rfbLog prints a time-stamped message to the log file (stderr).
223  */
224
225 static void
226 rfbDefaultLog(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,buf);
246
247     vfprintf(stderr, format, args);
248     fflush(stderr);
249
250     va_end(args);
251     UNLOCK(logMutex);
252 }
253
254 rfbLogProc rfbLog=rfbDefaultLog;
255 rfbLogProc rfbErr=rfbDefaultLog;
256
257 void rfbLogPerror(const char *str)
258 {
259     rfbErr("%s: %s\n", str, strerror(errno));
260 }
261
262 void 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
351 void 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
380 void 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
387 void 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
394 void 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
410 void rfbScaledScreenUpdate(rfbScreenInfoPtr screen, int x1, int y1, int x2, int y2);
411 void 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
437 static void *
438 clientOutput(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
489 static void *
490 clientInput(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
548 static void*
549 listenerRun(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
572 void 
573 rfbStartOnHoldClient(rfbClientPtr cl)
574 {
575     pthread_create(&cl->client_thread, NULL, clientInput, (void *)cl);
576 }
577
578 #else
579
580 void 
581 rfbStartOnHoldClient(rfbClientPtr cl)
582 {
583         cl->onHold = FALSE;
584 }
585
586 #endif
587
588 void 
589 rfbRefuseOnHoldClient(rfbClientPtr cl)
590 {
591     rfbCloseClient(cl);
592     rfbClientConnectionGone(cl);
593 }
594
595 static void
596 rfbDefaultKbdAddEvent(rfbBool down, rfbKeySym keySym, rfbClientPtr cl)
597 {
598 }
599
600 void
601 rfbDefaultPtrAddEvent(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
628 static 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)
635 static 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
646 static 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
661 static rfbCursorPtr rfbDefaultGetCursorPtr(rfbClientPtr cl)
662 {
663    return(cl->screen->cursor);
664 }
665
666 /* response is cl->authChallenge vncEncrypted with passwd */
667 static 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. */
697 rfbBool 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
719 void rfbDoNothingWithClient(rfbClientPtr cl)
720 {
721 }
722
723 static 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
733 static 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
774 rfbScreenInfoPtr 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
899 void 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
967 void 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
1008 void 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
1022 void 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
1042 void 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
1051 rfbBool
1052 rfbProcessEvents(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
1126 rfbBool rfbIsActive(rfbScreenInfoPtr screenInfo) {
1127   return screenInfo->socketState!=RFB_SOCKET_SHUTDOWN || screenInfo->clientHead!=NULL;
1128 }
1129
1130 void 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 }