~ubuntu-branches/ubuntu/dapper/vino/dapper

« back to all changes in this revision

Viewing changes to server/libvncserver/main.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2004-10-12 19:36:40 UTC
  • Revision ID: james.westby@ubuntu.com-20041012193640-ybetkwuqt7e04dke
Tags: upstream-2.8.1
ImportĀ upstreamĀ versionĀ 2.8.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#include <rfb/rfb.h>
 
14
#include <rfb/rfbregion.h>
 
15
 
 
16
#include <stdarg.h>
 
17
#include <errno.h>
 
18
 
 
19
#ifndef false
 
20
#define false 0
 
21
#define true -1
 
22
#endif
 
23
 
 
24
#ifdef HAVE_SYS_TYPES_H
 
25
#include <sys/types.h>
 
26
#endif
 
27
 
 
28
#ifndef WIN32
 
29
#include <sys/socket.h>
 
30
#include <netinet/in.h>
 
31
#include <unistd.h>
 
32
#endif
 
33
 
 
34
#include <signal.h>
 
35
#include <time.h>
 
36
 
 
37
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
 
38
MUTEX(logMutex);
 
39
#endif
 
40
 
 
41
int rfbEnableLogging=1;
 
42
 
 
43
#ifdef WORDS_BIGENDIAN
 
44
char rfbEndianTest = 0;
 
45
#else
 
46
char rfbEndianTest = -1;
 
47
#endif
 
48
 
 
49
void rfbLogEnable(int enabled) {
 
50
  rfbEnableLogging=enabled;
 
51
}
 
52
 
 
53
/*
 
54
 * rfbLog prints a time-stamped message to the log file (stderr).
 
55
 */
 
56
 
 
57
static void
 
58
rfbDefaultLog(const char *format, ...)
 
59
{
 
60
    va_list args;
 
61
    char buf[256];
 
62
    time_t log_clock;
 
63
 
 
64
    if(!rfbEnableLogging)
 
65
      return;
 
66
 
 
67
    LOCK(logMutex);
 
68
    va_start(args, format);
 
69
 
 
70
    time(&log_clock);
 
71
    strftime(buf, 255, "%d/%m/%Y %X ", localtime(&log_clock));
 
72
    fprintf(stderr,buf);
 
73
 
 
74
    vfprintf(stderr, format, args);
 
75
    fflush(stderr);
 
76
 
 
77
    va_end(args);
 
78
    UNLOCK(logMutex);
 
79
}
 
80
 
 
81
rfbLogProc rfbLog=rfbDefaultLog;
 
82
rfbLogProc rfbErr=rfbDefaultLog;
 
83
 
 
84
void rfbLogPerror(const char *str)
 
85
{
 
86
    rfbErr("%s: %s\n", str, strerror(errno));
 
87
}
 
88
 
 
89
void rfbScheduleCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,int dx,int dy)
 
90
{  
 
91
   rfbClientIteratorPtr iterator;
 
92
   rfbClientPtr cl;
 
93
 
 
94
   iterator=rfbGetClientIterator(rfbScreen);
 
95
   while((cl=rfbClientIteratorNext(iterator))) {
 
96
     LOCK(cl->updateMutex);
 
97
     if(cl->useCopyRect) {
 
98
       sraRegionPtr modifiedRegionBackup;
 
99
       if(!sraRgnEmpty(cl->copyRegion)) {
 
100
          if(cl->copyDX!=dx || cl->copyDY!=dy) {
 
101
             /* if a copyRegion was not yet executed, treat it as a
 
102
              * modifiedRegion. The idea: in this case it could be
 
103
              * source of the new copyRect or modified anyway. */
 
104
             sraRgnOr(cl->modifiedRegion,cl->copyRegion);
 
105
             sraRgnMakeEmpty(cl->copyRegion);
 
106
          } else {
 
107
             /* we have to set the intersection of the source of the copy
 
108
              * and the old copy to modified. */
 
109
             modifiedRegionBackup=sraRgnCreateRgn(copyRegion);
 
110
             sraRgnOffset(modifiedRegionBackup,-dx,-dy);
 
111
             sraRgnAnd(modifiedRegionBackup,cl->copyRegion);
 
112
             sraRgnOr(cl->modifiedRegion,modifiedRegionBackup);
 
113
             sraRgnDestroy(modifiedRegionBackup);
 
114
          }
 
115
       }
 
116
          
 
117
       sraRgnOr(cl->copyRegion,copyRegion);
 
118
       cl->copyDX = dx;
 
119
       cl->copyDY = dy;
 
120
 
 
121
       /* if there were modified regions, which are now copied,
 
122
        * mark them as modified, because the source of these can be overlapped
 
123
        * either by new modified or now copied regions. */
 
124
       modifiedRegionBackup=sraRgnCreateRgn(cl->modifiedRegion);
 
125
       sraRgnOffset(modifiedRegionBackup,dx,dy);
 
126
       sraRgnAnd(modifiedRegionBackup,cl->copyRegion);
 
127
       sraRgnOr(cl->modifiedRegion,modifiedRegionBackup);
 
128
       sraRgnDestroy(modifiedRegionBackup);
 
129
 
 
130
#if 0
 
131
       /* TODO: is this needed? Or does it mess up deferring? */
 
132
       /* while(!sraRgnEmpty(cl->copyRegion)) */ {
 
133
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
 
134
         if(!cl->screen->backgroundLoop)
 
135
#endif
 
136
           {
 
137
             sraRegionPtr updateRegion = sraRgnCreateRgn(cl->modifiedRegion);
 
138
             sraRgnOr(updateRegion,cl->copyRegion);
 
139
             UNLOCK(cl->updateMutex);
 
140
             rfbSendFramebufferUpdate(cl,updateRegion);
 
141
             sraRgnDestroy(updateRegion);
 
142
             continue;
 
143
           }
 
144
       }
 
145
#endif
 
146
     } else {
 
147
       sraRgnOr(cl->modifiedRegion,copyRegion);
 
148
     }
 
149
     TSIGNAL(cl->updateCond);
 
150
     UNLOCK(cl->updateMutex);
 
151
   }
 
152
 
 
153
   rfbReleaseClientIterator(iterator);
 
154
}
 
155
 
 
156
void rfbDoCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,int dx,int dy)
 
157
{
 
158
   sraRectangleIterator* i;
 
159
   sraRect rect;
 
160
   int j,widthInBytes,bpp=rfbScreen->rfbServerFormat.bitsPerPixel/8,
 
161
    rowstride=rfbScreen->paddedWidthInBytes;
 
162
   char *in,*out;
 
163
 
 
164
   /* copy it, really */
 
165
   i = sraRgnGetReverseIterator(copyRegion,dx<0,dy<0);
 
166
   while(sraRgnIteratorNext(i,&rect)) {
 
167
     widthInBytes = (rect.x2-rect.x1)*bpp;
 
168
     out = rfbScreen->frameBuffer+rect.x1*bpp+rect.y1*rowstride;
 
169
     in = rfbScreen->frameBuffer+(rect.x1-dx)*bpp+(rect.y1-dy)*rowstride;
 
170
     if(dy<0)
 
171
       for(j=rect.y1;j<rect.y2;j++,out+=rowstride,in+=rowstride)
 
172
         memmove(out,in,widthInBytes);
 
173
     else {
 
174
       out += rowstride*(rect.y2-rect.y1-1);
 
175
       in += rowstride*(rect.y2-rect.y1-1);
 
176
       for(j=rect.y2-1;j>=rect.y1;j--,out-=rowstride,in-=rowstride)
 
177
         memmove(out,in,widthInBytes);
 
178
     }
 
179
   }
 
180
  
 
181
   rfbScheduleCopyRegion(rfbScreen,copyRegion,dx,dy);
 
182
}
 
183
 
 
184
void rfbDoCopyRect(rfbScreenInfoPtr rfbScreen,int x1,int y1,int x2,int y2,int dx,int dy)
 
185
{
 
186
  sraRegionPtr region = sraRgnCreateRect(x1,y1,x2,y2);
 
187
  rfbDoCopyRegion(rfbScreen,region,dx,dy);
 
188
}
 
189
 
 
190
void rfbScheduleCopyRect(rfbScreenInfoPtr rfbScreen,int x1,int y1,int x2,int y2,int dx,int dy)
 
191
{
 
192
  sraRegionPtr region = sraRgnCreateRect(x1,y1,x2,y2);
 
193
  rfbScheduleCopyRegion(rfbScreen,region,dx,dy);
 
194
}
 
195
 
 
196
void rfbMarkRegionAsModified(rfbScreenInfoPtr rfbScreen,sraRegionPtr modRegion)
 
197
{
 
198
   rfbClientIteratorPtr iterator;
 
199
   rfbClientPtr cl;
 
200
 
 
201
   iterator=rfbGetClientIterator(rfbScreen);
 
202
   while((cl=rfbClientIteratorNext(iterator))) {
 
203
     LOCK(cl->updateMutex);
 
204
     sraRgnOr(cl->modifiedRegion,modRegion);
 
205
     TSIGNAL(cl->updateCond);
 
206
     UNLOCK(cl->updateMutex);
 
207
   }
 
208
 
 
209
   rfbReleaseClientIterator(iterator);
 
210
}
 
211
 
 
212
void rfbMarkRectAsModified(rfbScreenInfoPtr rfbScreen,int x1,int y1,int x2,int y2)
 
213
{
 
214
   sraRegionPtr region;
 
215
   int i;
 
216
 
 
217
   if(x1>x2) { i=x1; x1=x2; x2=i; }
 
218
   if(x1<0) x1=0;
 
219
   if(x2>=rfbScreen->width) x2=rfbScreen->width-1;
 
220
   if(x1==x2) return;
 
221
   
 
222
   if(y1>y2) { i=y1; y1=y2; y2=i; }
 
223
   if(y1<0) y1=0;
 
224
   if(y2>=rfbScreen->height) y2=rfbScreen->height-1;
 
225
   if(y1==y2) return;
 
226
   
 
227
   region = sraRgnCreateRect(x1,y1,x2,y2);
 
228
   rfbMarkRegionAsModified(rfbScreen,region);
 
229
   sraRgnDestroy(region);
 
230
}
 
231
 
 
232
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
 
233
static void *
 
234
clientOutput(void *data)
 
235
{
 
236
    rfbClientPtr cl = (rfbClientPtr)data;
 
237
    rfbBool haveUpdate;
 
238
    sraRegion* updateRegion;
 
239
 
 
240
    while (1) {
 
241
        haveUpdate = false;
 
242
        while (!haveUpdate) {
 
243
            if (cl->sock == -1) {
 
244
                /* Client has disconnected. */
 
245
                return NULL;
 
246
            }
 
247
            LOCK(cl->updateMutex);
 
248
            haveUpdate = FB_UPDATE_PENDING(cl);
 
249
            if(!haveUpdate) {
 
250
                updateRegion = sraRgnCreateRgn(cl->modifiedRegion);
 
251
                haveUpdate = sraRgnAnd(updateRegion,cl->requestedRegion);
 
252
                sraRgnDestroy(updateRegion);
 
253
            }
 
254
            UNLOCK(cl->updateMutex);
 
255
 
 
256
            if (!haveUpdate) {
 
257
                WAIT(cl->updateCond, cl->updateMutex);
 
258
                UNLOCK(cl->updateMutex); /* we really needn't lock now. */
 
259
            }
 
260
        }
 
261
        
 
262
        /* OK, now, to save bandwidth, wait a little while for more
 
263
           updates to come along. */
 
264
        usleep(cl->screen->rfbDeferUpdateTime * 1000);
 
265
 
 
266
        /* Now, get the region we're going to update, and remove
 
267
           it from cl->modifiedRegion _before_ we send the update.
 
268
           That way, if anything that overlaps the region we're sending
 
269
           is updated, we'll be sure to do another update later. */
 
270
        LOCK(cl->updateMutex);
 
271
        updateRegion = sraRgnCreateRgn(cl->modifiedRegion);
 
272
        UNLOCK(cl->updateMutex);
 
273
 
 
274
        /* Now actually send the update. */
 
275
        rfbIncrClientRef(cl);
 
276
        rfbSendFramebufferUpdate(cl, updateRegion);
 
277
        rfbDecrClientRef(cl);
 
278
 
 
279
        sraRgnDestroy(updateRegion);
 
280
    }
 
281
 
 
282
    return NULL;
 
283
}
 
284
 
 
285
static void *
 
286
clientInput(void *data)
 
287
{
 
288
    rfbClientPtr cl = (rfbClientPtr)data;
 
289
    pthread_t output_thread;
 
290
    pthread_create(&output_thread, NULL, clientOutput, (void *)cl);
 
291
 
 
292
    while (1) {
 
293
        rfbProcessClientMessage(cl);
 
294
        if (cl->sock == -1) {
 
295
            /* Client has disconnected. */
 
296
            break;
 
297
        }
 
298
    }
 
299
 
 
300
    /* Get rid of the output thread. */
 
301
    LOCK(cl->updateMutex);
 
302
    TSIGNAL(cl->updateCond);
 
303
    UNLOCK(cl->updateMutex);
 
304
    IF_PTHREADS(pthread_join(output_thread, NULL));
 
305
 
 
306
    rfbClientConnectionGone(cl);
 
307
 
 
308
    return NULL;
 
309
}
 
310
 
 
311
static void*
 
312
listenerRun(void *data)
 
313
{
 
314
    rfbScreenInfoPtr rfbScreen=(rfbScreenInfoPtr)data;
 
315
    int client_fd;
 
316
    struct sockaddr_in peer;
 
317
    rfbClientPtr cl;
 
318
    size_t len;
 
319
 
 
320
    len = sizeof(peer);
 
321
 
 
322
    /* TODO: this thread wont die by restarting the server */
 
323
    while ((client_fd = accept(rfbScreen->rfbListenSock, 
 
324
                               (struct sockaddr*)&peer, &len)) >= 0) {
 
325
        cl = rfbNewClient(rfbScreen,client_fd);
 
326
        len = sizeof(peer);
 
327
 
 
328
        if (cl && !cl->onHold )
 
329
                rfbStartOnHoldClient(cl);
 
330
    }
 
331
    return(NULL);
 
332
}
 
333
 
 
334
void 
 
335
rfbStartOnHoldClient(rfbClientPtr cl)
 
336
{
 
337
    pthread_create(&cl->client_thread, NULL, clientInput, (void *)cl);
 
338
}
 
339
 
 
340
#else
 
341
 
 
342
void 
 
343
rfbStartOnHoldClient(rfbClientPtr cl)
 
344
{
 
345
        cl->onHold = FALSE;
 
346
}
 
347
 
 
348
#endif
 
349
 
 
350
void 
 
351
rfbRefuseOnHoldClient(rfbClientPtr cl)
 
352
{
 
353
    rfbCloseClient(cl);
 
354
    rfbClientConnectionGone(cl);
 
355
}
 
356
 
 
357
void
 
358
defaultPtrAddEvent(int buttonMask, int x, int y, rfbClientPtr cl)
 
359
{
 
360
  rfbSetCursorPosition(cl->screen, cl, x, y);
 
361
}
 
362
 
 
363
/* TODO: add a nice VNC or RFB cursor */
 
364
 
 
365
#if defined(WIN32) || defined(sparc) || !defined(NO_STRICT_ANSI)
 
366
static rfbCursor myCursor = 
 
367
{
 
368
   FALSE, FALSE, FALSE, FALSE,
 
369
   (unsigned char*)"\000\102\044\030\044\102\000",
 
370
   (unsigned char*)"\347\347\176\074\176\347\347",
 
371
   8, 7, 3, 3,
 
372
   0, 0, 0,
 
373
   0xffff, 0xffff, 0xffff,
 
374
   0
 
375
};
 
376
#else
 
377
static rfbCursor myCursor = 
 
378
{
 
379
   cleanup: FALSE,
 
380
   cleanupSource: FALSE,
 
381
   cleanupMask: FALSE,
 
382
   cleanupRichSource: FALSE,
 
383
   source: "\000\102\044\030\044\102\000",
 
384
   mask:   "\347\347\176\074\176\347\347",
 
385
   width: 8, height: 7, xhot: 3, yhot: 3,
 
386
   foreRed: 0, foreGreen: 0, foreBlue: 0,
 
387
   backRed: 0xffff, backGreen: 0xffff, backBlue: 0xffff,
 
388
   richSource: 0
 
389
};
 
390
#endif
 
391
 
 
392
/*
 
393
 * Update server's pixel format in rfbScreenInfo structure. This
 
394
 * function is called from rfbGetScreen() and rfbNewFramebuffer().
 
395
 */
 
396
 
 
397
static void rfbInitServerFormat(rfbScreenInfoPtr rfbScreen, int bitsPerSample)
 
398
{
 
399
   rfbPixelFormat* format=&rfbScreen->rfbServerFormat;
 
400
 
 
401
   format->bitsPerPixel = rfbScreen->bitsPerPixel;
 
402
   format->depth = rfbScreen->depth;
 
403
   format->bigEndian = rfbEndianTest?FALSE:TRUE;
 
404
   format->trueColour = TRUE;
 
405
   rfbScreen->colourMap.count = 0;
 
406
   rfbScreen->colourMap.is16 = 0;
 
407
   rfbScreen->colourMap.data.bytes = NULL;
 
408
 
 
409
   if (format->bitsPerPixel == 8) {
 
410
     format->redMax = 7;
 
411
     format->greenMax = 7;
 
412
     format->blueMax = 3;
 
413
     format->redShift = 0;
 
414
     format->greenShift = 3;
 
415
     format->blueShift = 6;
 
416
   } else {
 
417
     format->redMax = (1 << bitsPerSample) - 1;
 
418
     format->greenMax = (1 << bitsPerSample) - 1;
 
419
     format->blueMax = (1 << bitsPerSample) - 1;
 
420
     if(rfbEndianTest) {
 
421
       format->redShift = 0;
 
422
       format->greenShift = bitsPerSample;
 
423
       format->blueShift = bitsPerSample * 2;
 
424
     } else {
 
425
       if(format->bitsPerPixel==8*3) {
 
426
         format->redShift = bitsPerSample*2;
 
427
         format->greenShift = bitsPerSample*1;
 
428
         format->blueShift = 0;
 
429
       } else {
 
430
         format->redShift = bitsPerSample*3;
 
431
         format->greenShift = bitsPerSample*2;
 
432
         format->blueShift = bitsPerSample;
 
433
       }
 
434
     }
 
435
   }
 
436
}
 
437
 
 
438
rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv,
 
439
 int width,int height,int bitsPerSample,int samplesPerPixel,
 
440
 int bytesPerPixel)
 
441
{
 
442
   rfbScreenInfoPtr rfbScreen=malloc(sizeof(rfbScreenInfo));
 
443
 
 
444
   INIT_MUTEX(logMutex);
 
445
 
 
446
   if(width&3)
 
447
     rfbErr("WARNING: Width (%d) is not a multiple of 4. VncViewer has problems with that.\n",width);
 
448
 
 
449
   rfbScreen->autoPort=FALSE;
 
450
   rfbScreen->rfbClientHead=0;
 
451
   rfbScreen->rfbPort=5900;
 
452
   rfbScreen->socketInitDone=FALSE;
 
453
 
 
454
   rfbScreen->inetdInitDone = FALSE;
 
455
   rfbScreen->inetdSock=-1;
 
456
 
 
457
   rfbScreen->maxFd=0;
 
458
   rfbScreen->rfbListenSock=-1;
 
459
 
 
460
   rfbScreen->desktopName = "LibVNCServer";
 
461
   rfbScreen->rfbAlwaysShared = FALSE;
 
462
   rfbScreen->rfbNeverShared = FALSE;
 
463
   rfbScreen->rfbDontDisconnect = FALSE;
 
464
   
 
465
   rfbScreen->width = width;
 
466
   rfbScreen->height = height;
 
467
   rfbScreen->bitsPerPixel = rfbScreen->depth = 8*bytesPerPixel;
 
468
 
 
469
   rfbScreen->securityTypes[0] = rfbNoAuth;
 
470
   rfbScreen->nSecurityTypes = 0;
 
471
   rfbScreen->authTypes[0] = rfbNoAuth;
 
472
   rfbScreen->nAuthTypes = 0;
 
473
   rfbScreen->passwordCheck = NULL;
 
474
 
 
475
#ifdef WIN32
 
476
   {
 
477
           DWORD dummy=255;
 
478
           GetComputerName(rfbScreen->rfbThisHost,&dummy);
 
479
   }
 
480
#else
 
481
   gethostname(rfbScreen->rfbThisHost, 255);
 
482
#endif
 
483
 
 
484
   rfbScreen->paddedWidthInBytes = width*bytesPerPixel;
 
485
 
 
486
   /* format */
 
487
 
 
488
   rfbInitServerFormat(rfbScreen, bitsPerSample);
 
489
 
 
490
   /* cursor */
 
491
 
 
492
   rfbScreen->cursorX=rfbScreen->cursorY=rfbScreen->underCursorBufferLen=0;
 
493
   rfbScreen->underCursorBuffer=NULL;
 
494
   rfbScreen->cursor = &myCursor;
 
495
   INIT_MUTEX(rfbScreen->cursorMutex);
 
496
 
 
497
   IF_PTHREADS(rfbScreen->backgroundLoop = FALSE);
 
498
 
 
499
   rfbScreen->rfbDeferUpdateTime=5;
 
500
   rfbScreen->maxRectsPerUpdate=50;
 
501
 
 
502
   /* proc's and hook's */
 
503
 
 
504
   rfbScreen->kbdAddEvent = NULL;
 
505
   rfbScreen->ptrAddEvent = defaultPtrAddEvent;
 
506
   rfbScreen->setXCutText = NULL;
 
507
   rfbScreen->newClientHook = NULL;
 
508
   rfbScreen->authenticatedClientHook = NULL;
 
509
 
 
510
   /* initialize client list and iterator mutex */
 
511
   rfbClientListInit(rfbScreen);
 
512
 
 
513
   rfbAuthInitScreen(rfbScreen);
 
514
 
 
515
   return(rfbScreen);
 
516
}
 
517
 
 
518
/*
 
519
 * Switch to another framebuffer (maybe of different size and color
 
520
 * format). Clients supporting NewFBSize pseudo-encoding will change
 
521
 * their local framebuffer dimensions if necessary.
 
522
 * NOTE: Rich cursor data should be converted to new pixel format by
 
523
 * the caller.
 
524
 */
 
525
 
 
526
void rfbNewFramebuffer(rfbScreenInfoPtr rfbScreen, char *framebuffer,
 
527
                       int width, int height,
 
528
                       int bitsPerSample, int samplesPerPixel,
 
529
                       int bytesPerPixel)
 
530
{
 
531
  rfbPixelFormat old_format;
 
532
  rfbBool format_changed = FALSE;
 
533
  rfbClientIteratorPtr iterator;
 
534
  rfbClientPtr cl;
 
535
 
 
536
  /* Update information in the rfbScreenInfo structure */
 
537
 
 
538
  old_format = rfbScreen->rfbServerFormat;
 
539
 
 
540
  if (width & 3)
 
541
    rfbErr("WARNING: New width (%d) is not a multiple of 4.\n", width);
 
542
 
 
543
  rfbScreen->width = width;
 
544
  rfbScreen->height = height;
 
545
  rfbScreen->bitsPerPixel = rfbScreen->depth = 8*bytesPerPixel;
 
546
  rfbScreen->paddedWidthInBytes = width*bytesPerPixel;
 
547
 
 
548
  rfbInitServerFormat(rfbScreen, bitsPerSample);
 
549
 
 
550
  if (memcmp(&rfbScreen->rfbServerFormat, &old_format,
 
551
             sizeof(rfbPixelFormat)) != 0) {
 
552
    format_changed = TRUE;
 
553
  }
 
554
 
 
555
  rfbScreen->frameBuffer = framebuffer;
 
556
 
 
557
  /* Adjust pointer position if necessary */
 
558
 
 
559
  if (rfbScreen->cursorX >= width)
 
560
    rfbScreen->cursorX = width - 1;
 
561
  if (rfbScreen->cursorY >= height)
 
562
    rfbScreen->cursorY = height - 1;
 
563
 
 
564
  /* For each client: */
 
565
  iterator = rfbGetClientIterator(rfbScreen);
 
566
  while ((cl = rfbClientIteratorNext(iterator)) != NULL) {
 
567
 
 
568
    /* Re-install color translation tables if necessary */
 
569
 
 
570
    if (format_changed)
 
571
      rfbSetTranslateFunction(cl);
 
572
 
 
573
    /* Mark the screen contents as changed, and schedule sending
 
574
       NewFBSize message if supported by this client. */
 
575
 
 
576
    LOCK(cl->updateMutex);
 
577
    sraRgnDestroy(cl->modifiedRegion);
 
578
    cl->modifiedRegion = sraRgnCreateRect(0, 0, width, height);
 
579
    sraRgnMakeEmpty(cl->copyRegion);
 
580
    cl->copyDX = 0;
 
581
    cl->copyDY = 0;
 
582
 
 
583
    if (cl->useNewFBSize)
 
584
      cl->newFBSizePending = TRUE;
 
585
 
 
586
    TSIGNAL(cl->updateCond);
 
587
    UNLOCK(cl->updateMutex);
 
588
  }
 
589
  rfbReleaseClientIterator(iterator);
 
590
}
 
591
 
 
592
void rfbScreenCleanup(rfbScreenInfoPtr rfbScreen)
 
593
{
 
594
  rfbClientIteratorPtr i=rfbGetClientIterator(rfbScreen);
 
595
  rfbClientPtr cl,cl1=rfbClientIteratorNext(i);
 
596
  while(cl1) {
 
597
    cl=rfbClientIteratorNext(i);
 
598
    rfbClientConnectionGone(cl1);
 
599
    cl1=cl;
 
600
  }
 
601
  rfbReleaseClientIterator(i);
 
602
 
 
603
  rfbAuthCleanupScreen(rfbScreen);
 
604
    
 
605
  /* TODO: hang up on all clients and free all reserved memory */
 
606
#define FREE_IF(x) if(rfbScreen->x) free(rfbScreen->x)
 
607
  FREE_IF(colourMap.data.bytes);
 
608
  FREE_IF(underCursorBuffer);
 
609
  TINI_MUTEX(rfbScreen->cursorMutex);
 
610
  if(rfbScreen->cursor)
 
611
    rfbFreeCursor(rfbScreen->cursor);
 
612
  free(rfbScreen);
 
613
#ifdef HAVE_LIBJPEG
 
614
  rfbTightCleanup();
 
615
#endif
 
616
}
 
617
 
 
618
void rfbInitServer(rfbScreenInfoPtr rfbScreen)
 
619
{
 
620
#ifdef WIN32
 
621
  WSADATA trash;
 
622
  int i=WSAStartup(MAKEWORD(2,2),&trash);
 
623
#endif
 
624
  rfbInitSockets(rfbScreen);
 
625
}
 
626
 
 
627
#ifndef HAVE_GETTIMEOFDAY
 
628
#include <fcntl.h>
 
629
#include <conio.h>
 
630
#include <sys/timeb.h>
 
631
 
 
632
void gettimeofday(struct timeval* tv,char* dummy)
 
633
{
 
634
   SYSTEMTIME t;
 
635
   GetSystemTime(&t);
 
636
   tv->tv_sec=t.wHour*3600+t.wMinute*60+t.wSecond;
 
637
   tv->tv_usec=t.wMilliseconds*1000;
 
638
}
 
639
#endif
 
640
 
 
641
void
 
642
rfbUpdateClient(rfbClientPtr cl)
 
643
{
 
644
  struct timeval tv;
 
645
  
 
646
  if (cl->sock >= 0 && !cl->onHold && FB_UPDATE_PENDING(cl) &&
 
647
      !sraRgnEmpty(cl->requestedRegion)) {
 
648
    if(cl->screen->rfbDeferUpdateTime == 0) {
 
649
      rfbSendFramebufferUpdate(cl,cl->modifiedRegion);
 
650
    } else if(cl->startDeferring.tv_usec == 0) {
 
651
      gettimeofday(&cl->startDeferring,NULL);
 
652
      if(cl->startDeferring.tv_usec == 0)
 
653
        cl->startDeferring.tv_usec++;
 
654
    } else {
 
655
      gettimeofday(&tv,NULL);
 
656
      if(tv.tv_sec < cl->startDeferring.tv_sec /* at midnight */
 
657
         || ((tv.tv_sec-cl->startDeferring.tv_sec)*1000
 
658
             +(tv.tv_usec-cl->startDeferring.tv_usec)/1000)
 
659
         > cl->screen->rfbDeferUpdateTime) {
 
660
        cl->startDeferring.tv_usec = 0;
 
661
        rfbSendFramebufferUpdate(cl,cl->modifiedRegion);
 
662
      }
 
663
    }
 
664
  }
 
665
}
 
666
 
 
667
void
 
668
rfbProcessEvents(rfbScreenInfoPtr rfbScreen,long usec)
 
669
{
 
670
  rfbClientIteratorPtr i;
 
671
  rfbClientPtr cl,clPrev;
 
672
 
 
673
  if(usec<0)
 
674
    usec=rfbScreen->rfbDeferUpdateTime*1000;
 
675
 
 
676
  rfbCheckFds(rfbScreen,usec);
 
677
 
 
678
  i = rfbGetClientIterator(rfbScreen);
 
679
  cl=rfbClientIteratorHead(i);
 
680
  while(cl) {
 
681
    rfbUpdateClient(cl);
 
682
    clPrev=cl;
 
683
    cl=rfbClientIteratorNext(i);
 
684
    if(clPrev->sock==-1)
 
685
      rfbClientConnectionGone(clPrev);
 
686
  }
 
687
  rfbReleaseClientIterator(i);
 
688
}
 
689
 
 
690
void rfbRunEventLoop(rfbScreenInfoPtr rfbScreen, long usec, rfbBool runInBackground)
 
691
{
 
692
  if(runInBackground) {
 
693
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
 
694
       pthread_t listener_thread;
 
695
 
 
696
       rfbScreen->backgroundLoop = TRUE;
 
697
 
 
698
       pthread_create(&listener_thread, NULL, listenerRun, rfbScreen);
 
699
    return;
 
700
#else
 
701
    rfbErr("Can't run in background, because I don't have PThreads!\n");
 
702
    return;
 
703
#endif
 
704
  }
 
705
 
 
706
  if(usec<0)
 
707
    usec=rfbScreen->rfbDeferUpdateTime*1000;
 
708
 
 
709
  while(1)
 
710
    rfbProcessEvents(rfbScreen,usec);
 
711
}
 
712
 
 
713
static char *
 
714
securityTypeToName(int securityType)
 
715
{
 
716
    switch (securityType) {
 
717
    case rfbNoAuth:
 
718
        return "No Authentication";
 
719
    case rfbVncAuth:
 
720
        return "VNC Authentication";
 
721
#ifdef HAVE_GNUTLS
 
722
    case rfbTLS:
 
723
        return "TLS";
 
724
#endif
 
725
    default:
 
726
        return "unknown";
 
727
    }
 
728
}
 
729
 
 
730
void rfbAddSecurityType(rfbScreenInfoPtr rfbScreen, int securityType)
 
731
{
 
732
    if (rfbScreen->nSecurityTypes >= RFB_MAX_N_SECURITY_TYPES)
 
733
        return;
 
734
 
 
735
    rfbLog("Advertising security type: '%s' (%d)\n",
 
736
           securityTypeToName(securityType), securityType);
 
737
    
 
738
    switch (securityType) {
 
739
    case rfbNoAuth:
 
740
    case rfbVncAuth:
 
741
#ifdef HAVE_GNUTLS
 
742
    case rfbTLS:
 
743
#endif
 
744
        rfbScreen->securityTypes[rfbScreen->nSecurityTypes] = securityType;
 
745
        rfbScreen->nSecurityTypes++;
 
746
        break;
 
747
    default:
 
748
        break;
 
749
    }
 
750
}
 
751
 
 
752
void rfbClearSecurityTypes(rfbScreenInfoPtr rfbScreen)
 
753
{
 
754
    if (rfbScreen->nSecurityTypes > 0) {
 
755
        rfbLog("Clearing securityTypes\n");
 
756
 
 
757
        memset (&rfbScreen->securityTypes, 0, sizeof (rfbScreen->securityTypes));
 
758
        rfbScreen->securityTypes [0] = rfbNoAuth;
 
759
        rfbScreen->nSecurityTypes = 0;
 
760
    }
 
761
}
 
762
 
 
763
static char *
 
764
authTypeToName(int authType)
 
765
{
 
766
    switch (authType) {
 
767
    case rfbNoAuth:
 
768
        return "No Authentication";
 
769
    case rfbVncAuth:
 
770
        return "VNC Authentication";
 
771
    default:
 
772
        return "unknown";
 
773
    }
 
774
}
 
775
 
 
776
void rfbAddAuthType(rfbScreenInfoPtr rfbScreen, int authType)
 
777
{
 
778
    if (rfbScreen->nAuthTypes >= RFB_MAX_N_AUTH_TYPES)
 
779
        return;
 
780
 
 
781
    rfbLog("Advertising authentication type: '%s' (%d)\n",
 
782
           authTypeToName(authType), authType);
 
783
    
 
784
    switch (authType) {
 
785
    case rfbNoAuth:
 
786
    case rfbVncAuth:
 
787
        rfbScreen->authTypes[rfbScreen->nAuthTypes] = authType;
 
788
        rfbScreen->nAuthTypes++;
 
789
        break;
 
790
    default:
 
791
        break;
 
792
    }
 
793
}
 
794
 
 
795
void rfbClearAuthTypes(rfbScreenInfoPtr rfbScreen)
 
796
{
 
797
    if (rfbScreen->nAuthTypes > 0) {
 
798
        rfbLog("Clearing authTypes\n");
 
799
 
 
800
        memset (&rfbScreen->authTypes, 0, sizeof (rfbScreen->authTypes));
 
801
        rfbScreen->authTypes [0] = rfbNoAuth;
 
802
        rfbScreen->nAuthTypes = 0;
 
803
    }
 
804
}