Coverage Report

Created: 2025-07-12 06:07

/src/libvncserver/src/libvncserver/main.c
Line
Count
Source (jump to first uncovered line)
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
0
#define false 0
25
#define true -1
26
#endif
27
28
#ifdef LIBVNCSERVER_HAVE_SYS_TIME_H
29
#include <sys/time.h>
30
#endif
31
32
#ifdef LIBVNCSERVER_HAVE_SYS_TYPES_H
33
#include <sys/types.h>
34
#endif
35
36
#ifdef LIBVNCSERVER_HAVE_FCNTL_H
37
#include <fcntl.h>
38
#endif
39
40
#include <signal.h>
41
#include <time.h>
42
43
static int extMutex_initialized = 0;
44
static int logMutex_initialized = 0;
45
#if defined(LIBVNCSERVER_HAVE_LIBPTHREAD) || defined(LIBVNCSERVER_HAVE_WIN32THREADS)
46
static MUTEX(logMutex);
47
static MUTEX(extMutex);
48
#endif
49
50
static int rfbEnableLogging=1;
51
52
#ifdef LIBVNCSERVER_WORDS_BIGENDIAN
53
char rfbEndianTest = (1==0);
54
#else
55
char rfbEndianTest = (1==1);
56
#endif
57
58
/*
59
 * Protocol extensions
60
 */
61
62
static rfbProtocolExtension* rfbExtensionHead = NULL;
63
64
/*
65
 * This method registers a list of new extensions.  
66
 * It avoids same extension getting registered multiple times. 
67
 * The order is not preserved if multiple extensions are
68
 * registered at one-go.
69
 */
70
void
71
rfbRegisterProtocolExtension(rfbProtocolExtension* extension)
72
0
{
73
0
  rfbProtocolExtension *head = rfbExtensionHead, *next = NULL;
74
75
0
  if(extension == NULL)
76
0
    return;
77
78
0
  next = extension->next;
79
80
0
  if (! extMutex_initialized) {
81
0
    INIT_MUTEX(extMutex);
82
0
    extMutex_initialized = 1;
83
0
  }
84
85
0
  LOCK(extMutex);
86
87
0
  while(head != NULL) {
88
0
    if(head == extension) {
89
0
      UNLOCK(extMutex);
90
0
      rfbRegisterProtocolExtension(next);
91
0
      return;
92
0
    }
93
94
0
    head = head->next;
95
0
  }
96
97
0
  extension->next = rfbExtensionHead;
98
0
  rfbExtensionHead = extension;
99
100
0
  UNLOCK(extMutex);
101
0
  rfbRegisterProtocolExtension(next);
102
0
}
103
104
/*
105
 * This method unregisters a list of extensions.  
106
 * These extensions won't be available for any new
107
 * client connection. 
108
 */
109
void
110
rfbUnregisterProtocolExtension(rfbProtocolExtension* extension)
111
0
{
112
113
0
  rfbProtocolExtension *cur = NULL, *pre = NULL;
114
115
0
  if(extension == NULL)
116
0
    return;
117
118
0
  if (! extMutex_initialized) {
119
0
    INIT_MUTEX(extMutex);
120
0
    extMutex_initialized = 1;
121
0
  }
122
123
0
  LOCK(extMutex);
124
125
0
  if(rfbExtensionHead == extension) {
126
0
    rfbExtensionHead = rfbExtensionHead->next;
127
0
    UNLOCK(extMutex);
128
0
    rfbUnregisterProtocolExtension(extension->next);
129
0
    return;
130
0
  }
131
132
0
  cur = pre = rfbExtensionHead;
133
134
0
  while(cur) {
135
0
    if(cur == extension) {
136
0
      pre->next = cur->next;
137
0
      break;
138
0
    }
139
0
    pre = cur;
140
0
    cur = cur->next;
141
0
  }
142
143
0
  UNLOCK(extMutex);
144
145
0
  rfbUnregisterProtocolExtension(extension->next);
146
0
}
147
148
rfbProtocolExtension* rfbGetExtensionIterator(void)
149
24.7k
{
150
24.7k
  if (! extMutex_initialized) {
151
1
    INIT_MUTEX(extMutex);
152
1
    extMutex_initialized = 1;
153
1
  }
154
155
24.7k
  LOCK(extMutex);
156
24.7k
  return rfbExtensionHead;
157
24.7k
}
158
159
void rfbReleaseExtensionIterator(void)
160
24.7k
{
161
24.7k
  UNLOCK(extMutex);
162
24.7k
}
163
164
rfbBool rfbEnableExtension(rfbClientPtr cl, rfbProtocolExtension* extension,
165
  void* data)
166
0
{
167
0
  rfbExtensionData* extData;
168
169
  /* make sure extension is not yet enabled. */
170
0
  for(extData = cl->extensions; extData; extData = extData->next)
171
0
    if(extData->extension == extension)
172
0
      return FALSE;
173
174
0
  extData = calloc(sizeof(rfbExtensionData),1);
175
0
  if(!extData)
176
0
    return FALSE;
177
0
  extData->extension = extension;
178
0
  extData->data = data;
179
0
  extData->next = cl->extensions;
180
0
  cl->extensions = extData;
181
182
0
  return TRUE;
183
0
}
184
185
rfbBool rfbDisableExtension(rfbClientPtr cl, rfbProtocolExtension* extension)
186
0
{
187
0
  rfbExtensionData* extData;
188
0
  rfbExtensionData* prevData = NULL;
189
190
0
  for(extData = cl->extensions; extData; extData = extData->next) {
191
0
    if(extData->extension == extension) {
192
0
      if(extData->data)
193
0
        free(extData->data);
194
0
      if(prevData == NULL)
195
0
        cl->extensions = extData->next;
196
0
      else
197
0
        prevData->next = extData->next;
198
0
      return TRUE;
199
0
    }
200
0
    prevData = extData;
201
0
  }
202
203
0
  return FALSE;
204
0
}
205
206
void* rfbGetExtensionClientData(rfbClientPtr cl, rfbProtocolExtension* extension)
207
0
{
208
0
    rfbExtensionData* data = cl->extensions;
209
210
0
    while(data && data->extension != extension)
211
0
  data = data->next;
212
213
0
    if(data == NULL) {
214
0
  rfbLog("Extension is not enabled !\n");
215
  /* rfbCloseClient(cl); */
216
0
  return NULL;
217
0
    }
218
219
0
    return data->data;
220
0
}
221
222
/*
223
 * Logging
224
 */
225
226
0
void rfbLogEnable(int enabled) {
227
0
  rfbEnableLogging=enabled;
228
0
}
229
230
/*
231
 * rfbLog prints a time-stamped message to the log file (stderr).
232
 */
233
234
static void
235
rfbDefaultLog(const char *format, ...)
236
139k
{
237
139k
    va_list args;
238
139k
    char buf[256];
239
139k
    time_t log_clock;
240
241
139k
    if(!rfbEnableLogging)
242
0
      return;
243
244
139k
    if (! logMutex_initialized) {
245
0
      INIT_MUTEX(logMutex);
246
0
      logMutex_initialized = 1;
247
0
    }
248
249
139k
    LOCK(logMutex);
250
139k
    va_start(args, format);
251
252
139k
    time(&log_clock);
253
139k
    strftime(buf, 255, "%d/%m/%Y %X ", localtime(&log_clock));
254
139k
    fprintf(stderr, "%s", buf);
255
256
139k
    vfprintf(stderr, format, args);
257
139k
    fflush(stderr);
258
259
139k
    va_end(args);
260
139k
    UNLOCK(logMutex);
261
139k
}
262
263
rfbLogProc rfbLog=rfbDefaultLog;
264
rfbLogProc rfbErr=rfbDefaultLog;
265
266
void rfbLogPerror(const char *str)
267
2.42k
{
268
#ifdef WIN32
269
    wchar_t *s = NULL;
270
    FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 
271
                   NULL, errno, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
272
                   (LPWSTR)&s, 0, NULL);
273
    rfbErr("%s: %S\n", str, s);
274
    LocalFree(s);
275
#else
276
2.42k
    rfbErr("%s: %s\n", str, strerror(errno));
277
2.42k
#endif
278
2.42k
}
279
280
void rfbScheduleCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,int dx,int dy)
281
0
{  
282
0
   rfbClientIteratorPtr iterator;
283
0
   rfbClientPtr cl;
284
285
0
   iterator=rfbGetClientIterator(rfbScreen);
286
0
   while((cl=rfbClientIteratorNext(iterator))) {
287
0
     LOCK(cl->updateMutex);
288
0
     if(cl->useCopyRect) {
289
0
       sraRegionPtr modifiedRegionBackup;
290
0
       if(!sraRgnEmpty(cl->copyRegion)) {
291
0
    if(cl->copyDX!=dx || cl->copyDY!=dy) {
292
       /* if a copyRegion was not yet executed, treat it as a
293
        * modifiedRegion. The idea: in this case it could be
294
        * source of the new copyRect or modified anyway. */
295
0
       sraRgnOr(cl->modifiedRegion,cl->copyRegion);
296
0
       sraRgnMakeEmpty(cl->copyRegion);
297
0
    } else {
298
       /* we have to set the intersection of the source of the copy
299
        * and the old copy to modified. */
300
0
       modifiedRegionBackup=sraRgnCreateRgn(copyRegion);
301
0
       sraRgnOffset(modifiedRegionBackup,-dx,-dy);
302
0
       sraRgnAnd(modifiedRegionBackup,cl->copyRegion);
303
0
       sraRgnOr(cl->modifiedRegion,modifiedRegionBackup);
304
0
       sraRgnDestroy(modifiedRegionBackup);
305
0
    }
306
0
       }
307
    
308
0
       sraRgnOr(cl->copyRegion,copyRegion);
309
0
       cl->copyDX = dx;
310
0
       cl->copyDY = dy;
311
312
       /* if there were modified regions, which are now copied,
313
  * mark them as modified, because the source of these can be overlapped
314
  * either by new modified or now copied regions. */
315
0
       modifiedRegionBackup=sraRgnCreateRgn(cl->modifiedRegion);
316
0
       sraRgnOffset(modifiedRegionBackup,dx,dy);
317
0
       sraRgnAnd(modifiedRegionBackup,cl->copyRegion);
318
0
       sraRgnOr(cl->modifiedRegion,modifiedRegionBackup);
319
0
       sraRgnDestroy(modifiedRegionBackup);
320
321
0
       if(!cl->enableCursorShapeUpdates) {
322
          /*
323
           * n.b. (dx, dy) is the vector pointing in the direction the
324
           * copyrect displacement will take place.  copyRegion is the
325
           * destination rectangle (say), not the source rectangle.
326
           */
327
0
          sraRegionPtr cursorRegion;
328
0
          int x = cl->cursorX - cl->screen->cursor->xhot;
329
0
          int y = cl->cursorY - cl->screen->cursor->yhot;
330
0
          int w = cl->screen->cursor->width;
331
0
          int h = cl->screen->cursor->height;
332
333
0
          cursorRegion = sraRgnCreateRect(x, y, x + w, y + h);
334
0
          sraRgnAnd(cursorRegion, cl->copyRegion);
335
0
          if(!sraRgnEmpty(cursorRegion)) {
336
             /*
337
              * current cursor rect overlaps with the copy region *dest*,
338
              * mark it as modified since we won't copy-rect stuff to it.
339
              */
340
0
             sraRgnOr(cl->modifiedRegion, cursorRegion);
341
0
          }
342
0
          sraRgnDestroy(cursorRegion);
343
344
0
          cursorRegion = sraRgnCreateRect(x, y, x + w, y + h);
345
          /* displace it to check for overlap with copy region source: */
346
0
          sraRgnOffset(cursorRegion, dx, dy);
347
0
          sraRgnAnd(cursorRegion, cl->copyRegion);
348
0
          if(!sraRgnEmpty(cursorRegion)) {
349
             /*
350
              * current cursor rect overlaps with the copy region *source*,
351
              * mark the *displaced* cursorRegion as modified since we
352
              * won't copyrect stuff to it.
353
              */
354
0
             sraRgnOr(cl->modifiedRegion, cursorRegion);
355
0
          }
356
0
          sraRgnDestroy(cursorRegion);
357
0
       }
358
359
0
     } else {
360
0
       sraRgnOr(cl->modifiedRegion,copyRegion);
361
0
     }
362
0
     TSIGNAL(cl->updateCond);
363
0
     UNLOCK(cl->updateMutex);
364
0
   }
365
366
0
   rfbReleaseClientIterator(iterator);
367
0
}
368
369
void rfbDoCopyRegion(rfbScreenInfoPtr screen,sraRegionPtr copyRegion,int dx,int dy)
370
0
{
371
0
   sraRectangleIterator* i;
372
0
   sraRect rect;
373
0
   int j,widthInBytes,bpp=screen->serverFormat.bitsPerPixel/8,
374
0
    rowstride=screen->paddedWidthInBytes;
375
0
   char *in,*out;
376
377
   /* copy it, really */
378
0
   i = sraRgnGetReverseIterator(copyRegion,dx<0,dy<0);
379
0
   while(sraRgnIteratorNext(i,&rect)) {
380
0
     widthInBytes = (rect.x2-rect.x1)*bpp;
381
0
     out = screen->frameBuffer+rect.x1*bpp+rect.y1*rowstride;
382
0
     in = screen->frameBuffer+(rect.x1-dx)*bpp+(rect.y1-dy)*rowstride;
383
0
     if(dy<0)
384
0
       for(j=rect.y1;j<rect.y2;j++,out+=rowstride,in+=rowstride)
385
0
   memmove(out,in,widthInBytes);
386
0
     else {
387
0
       out += rowstride*(rect.y2-rect.y1-1);
388
0
       in += rowstride*(rect.y2-rect.y1-1);
389
0
       for(j=rect.y2-1;j>=rect.y1;j--,out-=rowstride,in-=rowstride)
390
0
   memmove(out,in,widthInBytes);
391
0
     }
392
0
   }
393
0
   sraRgnReleaseIterator(i);
394
  
395
0
   rfbScheduleCopyRegion(screen,copyRegion,dx,dy);
396
0
}
397
398
void rfbDoCopyRect(rfbScreenInfoPtr screen,int x1,int y1,int x2,int y2,int dx,int dy)
399
0
{
400
0
  sraRegionPtr region = sraRgnCreateRect(x1,y1,x2,y2);
401
0
  rfbDoCopyRegion(screen,region,dx,dy);
402
0
  sraRgnDestroy(region);
403
0
}
404
405
void rfbScheduleCopyRect(rfbScreenInfoPtr screen,int x1,int y1,int x2,int y2,int dx,int dy)
406
0
{
407
0
  sraRegionPtr region = sraRgnCreateRect(x1,y1,x2,y2);
408
0
  rfbScheduleCopyRegion(screen,region,dx,dy);
409
0
  sraRgnDestroy(region);
410
0
}
411
412
void rfbMarkRegionAsModified(rfbScreenInfoPtr screen,sraRegionPtr modRegion)
413
0
{
414
0
   rfbClientIteratorPtr iterator;
415
0
   rfbClientPtr cl;
416
417
0
   iterator=rfbGetClientIterator(screen);
418
0
   while((cl=rfbClientIteratorNext(iterator))) {
419
0
     LOCK(cl->updateMutex);
420
0
     sraRgnOr(cl->modifiedRegion,modRegion);
421
0
     TSIGNAL(cl->updateCond);
422
0
     UNLOCK(cl->updateMutex);
423
0
   }
424
425
0
   rfbReleaseClientIterator(iterator);
426
0
}
427
428
void rfbScaledScreenUpdate(rfbScreenInfoPtr screen, int x1, int y1, int x2, int y2);
429
void rfbMarkRectAsModified(rfbScreenInfoPtr screen,int x1,int y1,int x2,int y2)
430
0
{
431
0
   sraRegionPtr region;
432
0
   int i;
433
434
0
   if(x1>x2) { i=x1; x1=x2; x2=i; }
435
0
   if(x1<0) x1=0;
436
0
   if(x2>screen->width) x2=screen->width;
437
0
   if(x1==x2) return;
438
   
439
0
   if(y1>y2) { i=y1; y1=y2; y2=i; }
440
0
   if(y1<0) y1=0;
441
0
   if(y2>screen->height) y2=screen->height;
442
0
   if(y1==y2) return;
443
444
   /* update scaled copies for this rectangle */
445
0
   rfbScaledScreenUpdate(screen,x1,y1,x2,y2);
446
447
0
   region = sraRgnCreateRect(x1,y1,x2,y2);
448
0
   rfbMarkRegionAsModified(screen,region);
449
0
   sraRgnDestroy(region);
450
0
}
451
452
#if defined(LIBVNCSERVER_HAVE_LIBPTHREAD) || defined(LIBVNCSERVER_HAVE_WIN32THREADS)
453
454
static THREAD_ROUTINE_RETURN_TYPE
455
clientOutput(void *data)
456
0
{
457
0
    rfbClientPtr cl = (rfbClientPtr)data;
458
0
    rfbBool haveUpdate;
459
0
    sraRegion* updateRegion;
460
461
0
    while (1) {
462
0
        haveUpdate = false;
463
0
        while (!haveUpdate) {
464
0
    if (cl->sock == RFB_INVALID_SOCKET || cl->state == RFB_SHUTDOWN) {
465
      /* Client has disconnected. */
466
0
      return THREAD_ROUTINE_RETURN_VALUE;
467
0
    }
468
0
    if (cl->state != RFB_NORMAL || cl->onHold) {
469
      /* just sleep until things get normal */
470
0
            THREAD_SLEEP_MS(cl->screen->deferUpdateTime);
471
0
      continue;
472
0
    }
473
474
0
    LOCK(cl->updateMutex);
475
476
0
    if (sraRgnEmpty(cl->requestedRegion)) {
477
0
      ; /* always require a FB Update Request (otherwise can crash.) */
478
0
    } else {
479
0
      haveUpdate = FB_UPDATE_PENDING(cl);
480
0
      if(!haveUpdate) {
481
0
        updateRegion = sraRgnCreateRgn(cl->modifiedRegion);
482
0
        haveUpdate   = sraRgnAnd(updateRegion,cl->requestedRegion);
483
0
        sraRgnDestroy(updateRegion);
484
0
      }
485
0
    }
486
487
0
    if (!haveUpdate) {
488
0
      WAIT(cl->updateCond, cl->updateMutex);
489
0
    }
490
491
0
    UNLOCK(cl->updateMutex);
492
0
        }
493
        
494
        /* OK, now, to save bandwidth, wait a little while for more
495
           updates to come along. */
496
0
  THREAD_SLEEP_MS(cl->screen->deferUpdateTime);
497
498
        /* Now, get the region we're going to update, and remove
499
           it from cl->modifiedRegion _before_ we send the update.
500
           That way, if anything that overlaps the region we're sending
501
           is updated, we'll be sure to do another update later. */
502
0
        LOCK(cl->updateMutex);
503
0
  updateRegion = sraRgnCreateRgn(cl->modifiedRegion);
504
0
        UNLOCK(cl->updateMutex);
505
506
        /* Now actually send the update. */
507
0
  rfbIncrClientRef(cl);
508
0
        LOCK(cl->sendMutex);
509
0
        rfbSendFramebufferUpdate(cl, updateRegion);
510
0
        UNLOCK(cl->sendMutex);
511
0
  rfbDecrClientRef(cl);
512
513
0
  sraRgnDestroy(updateRegion);
514
0
    }
515
516
    /* Not reached. */
517
0
    return THREAD_ROUTINE_RETURN_VALUE;
518
0
}
519
520
static THREAD_ROUTINE_RETURN_TYPE
521
clientInput(void *data)
522
0
{
523
0
    rfbClientPtr cl = (rfbClientPtr)data;
524
0
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
525
0
    pthread_t output_thread;
526
0
    pthread_create(&output_thread, NULL, clientOutput, (void *)cl);
527
#elif defined(LIBVNCSERVER_HAVE_WIN32THREADS)
528
    uintptr_t output_thread = _beginthread(clientOutput, 0, cl);
529
#endif
530
531
0
    while (cl->state != RFB_SHUTDOWN) {
532
0
  fd_set rfds, wfds, efds;
533
0
  struct timeval tv;
534
0
  int n;
535
536
0
  if (cl->sock == RFB_INVALID_SOCKET) {
537
    /* Client has disconnected. */
538
0
            break;
539
0
        }
540
541
0
  FD_ZERO(&rfds);
542
0
  FD_SET(cl->sock, &rfds);
543
0
#ifndef WIN32
544
0
  FD_SET(cl->pipe_notify_client_thread[0], &rfds);
545
0
#endif
546
0
  FD_ZERO(&efds);
547
0
  FD_SET(cl->sock, &efds);
548
549
  /* Are we transferring a file in the background? */
550
0
  FD_ZERO(&wfds);
551
0
  if ((cl->fileTransfer.fd!=-1) && (cl->fileTransfer.sending==1))
552
0
      FD_SET(cl->sock, &wfds);
553
554
0
#ifndef WIN32
555
0
  int nfds = cl->pipe_notify_client_thread[0] > cl->sock ? cl->pipe_notify_client_thread[0] : cl->sock;
556
#else
557
  int nfds = cl->sock;
558
#endif
559
560
0
  tv.tv_sec = 60; /* 1 minute */
561
0
  tv.tv_usec = 0;
562
563
0
  n = select(nfds + 1, &rfds, &wfds, &efds, &tv);
564
565
0
  if (n < 0) {
566
0
      rfbLogPerror("ReadExact: select");
567
0
      break;
568
0
  }
569
0
  if (n == 0) /* timeout */
570
0
  {
571
0
            rfbSendFileTransferChunk(cl);
572
0
      continue;
573
0
        }
574
575
0
#ifndef WIN32
576
0
  if (FD_ISSET(cl->pipe_notify_client_thread[0], &rfds))
577
0
  {
578
      /* Reset the pipe */
579
0
      char buf;
580
0
      while (read(cl->pipe_notify_client_thread[0], &buf, sizeof(buf)) == sizeof(buf));
581
0
      continue; /* Go on with loop */
582
0
  }
583
0
#endif
584
585
        /* We have some space on the transmit queue, send some data */
586
0
        if (FD_ISSET(cl->sock, &wfds))
587
0
            rfbSendFileTransferChunk(cl);
588
589
0
        if (FD_ISSET(cl->sock, &rfds) || FD_ISSET(cl->sock, &efds))
590
0
        {
591
0
#ifdef LIBVNCSERVER_WITH_WEBSOCKETS
592
0
            do {
593
0
                rfbProcessClientMessage(cl);
594
0
            } while (webSocketsHasDataInBuffer(cl));
595
#else
596
            rfbProcessClientMessage(cl);
597
#endif
598
0
        }
599
0
    }
600
601
    /* Get rid of the output thread. */
602
0
    LOCK(cl->updateMutex);
603
0
    TSIGNAL(cl->updateCond);
604
0
    UNLOCK(cl->updateMutex);
605
0
    THREAD_JOIN(output_thread);
606
607
    /* Close client sock */
608
0
    rfbCloseSocket(cl->sock);
609
0
    cl->sock = RFB_INVALID_SOCKET;
610
611
0
    rfbClientConnectionGone(cl);
612
613
0
    return THREAD_ROUTINE_RETURN_VALUE;
614
0
}
615
616
617
static THREAD_ROUTINE_RETURN_TYPE
618
listenerRun(void *data)
619
0
{
620
0
    rfbScreenInfoPtr screen=(rfbScreenInfoPtr)data;
621
0
    int client_fd;
622
0
    struct sockaddr_storage peer;
623
0
    rfbClientPtr cl = NULL;
624
0
    socklen_t len;
625
0
    fd_set listen_fds;  /* temp file descriptor list for select() */
626
0
    struct timeval tv;
627
628
    /*
629
      Only checking socket state here and not using rfbIsActive()
630
      because: When rfbShutdownServer() is called by the client, it runs in
631
      the client-to-server thread's context, resulting in itself calling
632
      its own the pthread_join(), returning immediately, leaving the
633
      client-to-server thread to actually terminate _after_ the listener thread
634
      is terminated, leaving the client list still populated, making rfbIsActive()
635
      return true, not ending the listener, making the join in rfbShutdownServer()
636
      wait forever...
637
    */
638
0
    while (screen->socketState != RFB_SOCKET_SHUTDOWN) {
639
0
        client_fd = -1;
640
0
        cl = NULL;
641
0
        FD_ZERO(&listen_fds);
642
0
  if(screen->listenSock != RFB_INVALID_SOCKET)
643
0
    FD_SET(screen->listenSock, &listen_fds);
644
0
  if(screen->listen6Sock != RFB_INVALID_SOCKET)
645
0
    FD_SET(screen->listen6Sock, &listen_fds);
646
0
#ifndef WIN32
647
0
  FD_SET(screen->pipe_notify_listener_thread[0], &listen_fds);
648
0
  screen->maxFd = rfbMax(screen->maxFd, screen->pipe_notify_listener_thread[0]);
649
0
#endif
650
651
0
        tv.tv_sec = 0;
652
0
  tv.tv_usec = screen->select_timeout_usec;
653
0
        if (select(screen->maxFd+1, &listen_fds, NULL, NULL, &tv) == -1) {
654
0
            rfbLogPerror("listenerRun: error in select");
655
0
            return THREAD_ROUTINE_RETURN_VALUE;
656
0
        }
657
658
0
#ifndef WIN32
659
0
  if (FD_ISSET(screen->pipe_notify_listener_thread[0], &listen_fds))
660
0
  {
661
      /* Reset the pipe */
662
0
      char buf;
663
0
      while (read(screen->pipe_notify_listener_thread[0], &buf, sizeof(buf)) == sizeof(buf));
664
      /* Go on with loop */
665
0
      continue;
666
0
  }
667
0
#endif
668
669
  /* If there is something on the listening sockets, handle new connections */
670
0
  len = sizeof (peer);
671
0
  if (screen->listenSock != RFB_INVALID_SOCKET && FD_ISSET(screen->listenSock, &listen_fds))
672
0
      client_fd = accept(screen->listenSock, (struct sockaddr*)&peer, &len);
673
0
  else if (screen->listen6Sock != RFB_INVALID_SOCKET && FD_ISSET(screen->listen6Sock, &listen_fds))
674
0
      client_fd = accept(screen->listen6Sock, (struct sockaddr*)&peer, &len);
675
676
0
  if(client_fd >= 0)
677
0
    cl = rfbNewClient(screen,client_fd);
678
0
  if (cl && !cl->onHold )
679
0
    rfbStartOnHoldClient(cl);
680
681
        /* handle HTTP  */
682
0
        rfbHttpCheckFds(screen);
683
0
    }
684
0
    return THREAD_ROUTINE_RETURN_VALUE;
685
0
}
686
687
#endif
688
689
void 
690
rfbStartOnHoldClient(rfbClientPtr cl)
691
0
{
692
0
    cl->onHold = FALSE;
693
0
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
694
0
    if(cl->screen->backgroundLoop) {
695
0
#ifndef WIN32
696
0
        if (pipe(cl->pipe_notify_client_thread) == -1) {
697
0
            cl->pipe_notify_client_thread[0] = -1;
698
0
            cl->pipe_notify_client_thread[1] = -1;
699
0
        }
700
0
        fcntl(cl->pipe_notify_client_thread[0], F_SETFL, O_NONBLOCK);
701
0
#endif
702
0
        pthread_create(&cl->client_thread, NULL, clientInput, (void *)cl);
703
0
    }
704
#elif defined(LIBVNCSERVER_HAVE_WIN32THREADS)
705
    if(cl->screen->backgroundLoop) {
706
  cl->client_thread = _beginthread(clientInput, 0, cl);
707
    }
708
#endif
709
0
}
710
711
712
void 
713
rfbRefuseOnHoldClient(rfbClientPtr cl)
714
0
{
715
0
    rfbCloseClient(cl);
716
0
    rfbClientConnectionGone(cl);
717
0
}
718
719
static void
720
rfbDefaultKbdAddEvent(rfbBool down, rfbKeySym keySym, rfbClientPtr cl)
721
297
{
722
297
}
723
724
void
725
rfbDefaultPtrAddEvent(int buttonMask, int x, int y, rfbClientPtr cl)
726
8.86k
{
727
8.86k
  rfbClientIteratorPtr iterator;
728
8.86k
  rfbClientPtr other_client;
729
8.86k
  rfbScreenInfoPtr s = cl->screen;
730
731
8.86k
  if (x != s->cursorX || y != s->cursorY) {
732
7.29k
    LOCK(s->cursorMutex);
733
7.29k
    s->cursorX = x;
734
7.29k
    s->cursorY = y;
735
7.29k
    UNLOCK(s->cursorMutex);
736
737
    /* The cursor was moved by this client, so don't send CursorPos. */
738
7.29k
    if (cl->enableCursorPosUpdates)
739
211
      cl->cursorWasMoved = FALSE;
740
741
    /* But inform all remaining clients about this cursor movement. */
742
7.29k
    iterator = rfbGetClientIterator(s);
743
7.29k
    while ((other_client = rfbClientIteratorNext(iterator)) != NULL) {
744
0
      if (other_client != cl && other_client->enableCursorPosUpdates) {
745
0
  other_client->cursorWasMoved = TRUE;
746
0
      }
747
0
    }
748
7.29k
    rfbReleaseClientIterator(iterator);
749
7.29k
  }
750
8.86k
}
751
752
static void rfbDefaultSetXCutText(char* text, int len, rfbClientPtr cl)
753
709
{
754
709
}
755
756
/* TODO: add a nice VNC or RFB cursor */
757
758
#if defined(WIN32) || defined(sparc) || !defined(NO_STRICT_ANSI)
759
static rfbCursor myCursor = 
760
{
761
   FALSE, FALSE, FALSE, FALSE,
762
   (unsigned char*)"\000\102\044\030\044\102\000",
763
   (unsigned char*)"\347\347\176\074\176\347\347",
764
   8, 7, 3, 3,
765
   0, 0, 0,
766
   0xffff, 0xffff, 0xffff,
767
   NULL
768
};
769
#else
770
static rfbCursor myCursor = 
771
{
772
   cleanup: FALSE,
773
   cleanupSource: FALSE,
774
   cleanupMask: FALSE,
775
   cleanupRichSource: FALSE,
776
   source: "\000\102\044\030\044\102\000",
777
   mask:   "\347\347\176\074\176\347\347",
778
   width: 8, height: 7, xhot: 3, yhot: 3,
779
   foreRed: 0, foreGreen: 0, foreBlue: 0,
780
   backRed: 0xffff, backGreen: 0xffff, backBlue: 0xffff,
781
   richSource: NULL
782
};
783
#endif
784
785
static rfbCursorPtr rfbDefaultGetCursorPtr(rfbClientPtr cl)
786
0
{
787
0
   return(cl->screen->cursor);
788
0
}
789
790
/* response is cl->authChallenge vncEncrypted with passwd */
791
static rfbBool rfbDefaultPasswordCheck(rfbClientPtr cl,const char* response,int len)
792
0
{
793
0
  int i;
794
0
  char *passwd=rfbDecryptPasswdFromFile(cl->screen->authPasswdData);
795
796
0
  if(!passwd) {
797
0
    rfbErr("Couldn't read password file: %s\n",cl->screen->authPasswdData);
798
0
    return(FALSE);
799
0
  }
800
801
0
  rfbEncryptBytes(cl->authChallenge, passwd);
802
803
  /* Lose the password from memory */
804
0
  for (i = strlen(passwd); i >= 0; i--) {
805
0
    passwd[i] = '\0';
806
0
  }
807
808
0
  free(passwd);
809
810
0
  if (memcmp(cl->authChallenge, response, len) != 0) {
811
0
    rfbErr("authProcessClientMessage: authentication failed from %s\n",
812
0
     cl->host);
813
0
    return(FALSE);
814
0
  }
815
816
0
  return(TRUE);
817
0
}
818
819
/* for this method, authPasswdData is really a pointer to an array
820
   of char*'s, where the last pointer is 0. */
821
rfbBool rfbCheckPasswordByList(rfbClientPtr cl,const char* response,int len)
822
0
{
823
0
  char **passwds;
824
0
  int i=0;
825
826
0
  for(passwds=(char**)cl->screen->authPasswdData;*passwds;passwds++,i++) {
827
0
    uint8_t auth_tmp[CHALLENGESIZE];
828
0
    memcpy((char *)auth_tmp, (char *)cl->authChallenge, CHALLENGESIZE);
829
0
    rfbEncryptBytes(auth_tmp, *passwds);
830
831
0
    if (memcmp(auth_tmp, response, len) == 0) {
832
0
      if(i>=cl->screen->authPasswdFirstViewOnly)
833
0
  cl->viewOnly=TRUE;
834
0
      return(TRUE);
835
0
    }
836
0
  }
837
838
0
  rfbErr("authProcessClientMessage: authentication failed from %s\n",
839
0
   cl->host);
840
0
  return(FALSE);
841
0
}
842
843
void rfbDoNothingWithClient(rfbClientPtr cl)
844
2.42k
{
845
2.42k
}
846
847
static enum rfbNewClientAction rfbDefaultNewClientHook(rfbClientPtr cl)
848
2.42k
{
849
2.42k
  return RFB_CLIENT_ACCEPT;
850
2.42k
}
851
852
static int rfbDefaultNumberOfExtDesktopScreens(rfbClientPtr cl)
853
0
{
854
0
    return 1;
855
0
}
856
857
static rfbBool rfbDefaultGetExtDesktopScreen(int seqnumber, rfbExtDesktopScreen* s, rfbClientPtr cl)
858
0
{
859
0
    if (seqnumber != 0)
860
0
        return FALSE;
861
862
    /* Populate the provided rfbExtDesktopScreen structure */
863
0
    s->id = 1;
864
0
    s->width = cl->scaledScreen->width;
865
0
    s->height = cl->scaledScreen->height;
866
0
    s->x = 0;
867
0
    s->y = 0;
868
0
    s->flags = 0;
869
870
0
    return TRUE;
871
0
}
872
873
static int rfbDefaultSetDesktopSize(int width, int height, int numScreens, rfbExtDesktopScreen* extDesktopScreens, rfbClientPtr cl)
874
207
{
875
207
    return rfbExtDesktopSize_ResizeProhibited;
876
207
}
877
878
/*
879
 * Update server's pixel format in screenInfo structure. This
880
 * function is called from rfbGetScreen() and rfbNewFramebuffer().
881
 */
882
883
static void rfbInitServerFormat(rfbScreenInfoPtr screen, int bitsPerSample)
884
1
{
885
1
   rfbPixelFormat* format=&screen->serverFormat;
886
887
1
   format->bitsPerPixel = screen->bitsPerPixel;
888
1
   format->depth = screen->depth;
889
1
   format->bigEndian = rfbEndianTest?FALSE:TRUE;
890
1
   format->trueColour = TRUE;
891
1
   screen->colourMap.count = 0;
892
1
   screen->colourMap.is16 = 0;
893
1
   screen->colourMap.data.bytes = NULL;
894
895
1
   if (format->bitsPerPixel == 8) {
896
0
     format->redMax = 7;
897
0
     format->greenMax = 7;
898
0
     format->blueMax = 3;
899
0
     format->redShift = 0;
900
0
     format->greenShift = 3;
901
0
     format->blueShift = 6;
902
1
   } else {
903
1
     format->redMax = (1 << bitsPerSample) - 1;
904
1
     format->greenMax = (1 << bitsPerSample) - 1;
905
1
     format->blueMax = (1 << bitsPerSample) - 1;
906
1
     if(rfbEndianTest) {
907
1
       format->redShift = 0;
908
1
       format->greenShift = bitsPerSample;
909
1
       format->blueShift = bitsPerSample * 2;
910
1
     } else {
911
0
       if(format->bitsPerPixel==8*3) {
912
0
   format->redShift = bitsPerSample*2;
913
0
   format->greenShift = bitsPerSample*1;
914
0
   format->blueShift = 0;
915
0
       } else {
916
0
   format->redShift = bitsPerSample*3;
917
0
   format->greenShift = bitsPerSample*2;
918
0
   format->blueShift = bitsPerSample;
919
0
       }
920
0
     }
921
1
   }
922
1
}
923
924
rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv,
925
 int width,int height,int bitsPerSample,int samplesPerPixel,
926
 int bytesPerPixel)
927
1
{
928
1
   rfbScreenInfoPtr screen=calloc(sizeof(rfbScreenInfo),1);
929
1
   if (!screen)
930
0
       return NULL;
931
932
1
   if (! logMutex_initialized) {
933
1
     INIT_MUTEX(logMutex);
934
1
     logMutex_initialized = 1;
935
1
   }
936
937
938
1
   if(width&3)
939
0
     rfbErr("WARNING: Width (%d) is not a multiple of 4. VncViewer has problems with that.\n",width);
940
941
1
   screen->autoPort=FALSE;
942
1
   screen->clientHead=NULL;
943
1
   screen->pointerClient=NULL;
944
1
   screen->port=5900;
945
1
   screen->ipv6port=5900;
946
1
   screen->socketState=RFB_SOCKET_INIT;
947
948
1
   screen->inetdInitDone = FALSE;
949
1
   screen->inetdSock=RFB_INVALID_SOCKET;
950
951
1
   screen->udpSock=RFB_INVALID_SOCKET;
952
1
   screen->udpSockConnected=FALSE;
953
1
   screen->udpPort=0;
954
1
   screen->udpClient=NULL;
955
956
1
   screen->maxFd=0;
957
1
   screen->listenSock=RFB_INVALID_SOCKET;
958
1
   screen->listen6Sock=RFB_INVALID_SOCKET;
959
1
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
960
1
   screen->pipe_notify_listener_thread[0] = -1;
961
1
   screen->pipe_notify_listener_thread[1] = -1;
962
1
#endif
963
964
1
   screen->fdQuota = 0.5;
965
966
1
   screen->httpInitDone=FALSE;
967
1
   screen->httpEnableProxyConnect=FALSE;
968
1
   screen->httpPort=0;
969
1
   screen->http6Port=0;
970
1
   screen->httpDir=NULL;
971
1
   screen->httpListenSock=RFB_INVALID_SOCKET;
972
1
   screen->httpListen6Sock=RFB_INVALID_SOCKET;
973
1
   screen->httpSock=RFB_INVALID_SOCKET;
974
975
1
   screen->desktopName = "LibVNCServer";
976
1
   screen->alwaysShared = FALSE;
977
1
   screen->neverShared = FALSE;
978
1
   screen->dontDisconnect = FALSE;
979
1
   screen->authPasswdData = NULL;
980
1
   screen->authPasswdFirstViewOnly = 1;
981
   
982
1
   screen->width = width;
983
1
   screen->height = height;
984
1
   screen->bitsPerPixel = screen->depth = 8*bytesPerPixel;
985
986
1
   screen->passwordCheck = rfbDefaultPasswordCheck;
987
988
1
   screen->ignoreSIGPIPE = TRUE;
989
990
   /* disable progressive updating per default */
991
1
   screen->progressiveSliceHeight = 0;
992
993
1
   screen->listenInterface = htonl(INADDR_ANY);
994
995
1
   screen->deferUpdateTime=5;
996
1
   screen->maxRectsPerUpdate=50;
997
998
1
   screen->handleEventsEagerly = FALSE;
999
1000
1
   screen->protocolMajorVersion = rfbProtocolMajorVersion;
1001
1
   screen->protocolMinorVersion = rfbProtocolMinorVersion;
1002
1003
1
   screen->permitFileTransfer = FALSE;
1004
1005
1
   if(!rfbProcessArguments(screen,argc,argv)) {
1006
0
     free(screen);
1007
0
     return NULL;
1008
0
   }
1009
1010
#ifdef WIN32
1011
   {
1012
     DWORD dummy=255;
1013
     GetComputerName(screen->thisHost,&dummy);
1014
   }
1015
#else
1016
1
   gethostname(screen->thisHost, 255);
1017
1
#endif
1018
1019
1
   screen->paddedWidthInBytes = width*bytesPerPixel;
1020
1021
   /* format */
1022
1023
1
   rfbInitServerFormat(screen, bitsPerSample);
1024
1025
   /* cursor */
1026
1027
1
   screen->cursorX=screen->cursorY=screen->underCursorBufferLen=0;
1028
1
   screen->underCursorBuffer=NULL;
1029
1
   screen->dontConvertRichCursorToXCursor = FALSE;
1030
1
   screen->cursor = &myCursor;
1031
1
   INIT_MUTEX(screen->cursorMutex);
1032
1033
1
#if defined(LIBVNCSERVER_HAVE_LIBPTHREAD) || defined(LIBVNCSERVER_HAVE_WIN32THREADS)
1034
1
   screen->backgroundLoop = FALSE;
1035
1
#endif
1036
1037
   /* proc's and hook's */
1038
1039
1
   screen->kbdAddEvent = rfbDefaultKbdAddEvent;
1040
1
   screen->kbdReleaseAllKeys = rfbDoNothingWithClient;
1041
1
   screen->ptrAddEvent = rfbDefaultPtrAddEvent;
1042
1
   screen->setXCutText = rfbDefaultSetXCutText;
1043
1
#ifdef LIBVNCSERVER_HAVE_LIBZ
1044
1
   screen->setXCutTextUTF8 = NULL;
1045
1
#endif
1046
1
   screen->getCursorPtr = rfbDefaultGetCursorPtr;
1047
1
   screen->setTranslateFunction = rfbSetTranslateFunction;
1048
1
   screen->newClientHook = rfbDefaultNewClientHook;
1049
1
   screen->displayHook = NULL;
1050
1
   screen->displayFinishedHook = NULL;
1051
1
   screen->getKeyboardLedStateHook = NULL;
1052
1
   screen->xvpHook = NULL;
1053
1
   screen->setDesktopSizeHook = rfbDefaultSetDesktopSize;
1054
1
   screen->numberOfExtDesktopScreensHook = rfbDefaultNumberOfExtDesktopScreens;
1055
1
   screen->getExtDesktopScreenHook = rfbDefaultGetExtDesktopScreen;
1056
1057
   /* initialize client list and iterator mutex */
1058
1
   rfbClientListInit(screen);
1059
1060
1
   return(screen);
1061
1
}
1062
1063
/*
1064
 * Switch to another framebuffer (maybe of different size and color
1065
 * format). Clients supporting NewFBSize pseudo-encoding will change
1066
 * their local framebuffer dimensions if necessary.
1067
 * NOTE: Rich cursor data should be converted to new pixel format by
1068
 * the caller.
1069
 */
1070
1071
void rfbNewFramebuffer(rfbScreenInfoPtr screen, char *framebuffer,
1072
                       int width, int height,
1073
                       int bitsPerSample, int samplesPerPixel,
1074
                       int bytesPerPixel)
1075
0
{
1076
0
  rfbPixelFormat old_format;
1077
0
  rfbBool format_changed = FALSE;
1078
0
  rfbClientIteratorPtr iterator;
1079
0
  rfbClientPtr cl;
1080
1081
  /* Lock out client reads. */
1082
0
  iterator = rfbGetClientIterator(screen);
1083
0
  while ((cl = rfbClientIteratorNext(iterator))) {
1084
0
      LOCK(cl->sendMutex);
1085
0
  }
1086
0
  rfbReleaseClientIterator(iterator);
1087
1088
  /* Prevent cursor drawing into framebuffer */
1089
0
  LOCK(screen->cursorMutex);
1090
1091
  /* Update information in the screenInfo structure */
1092
1093
0
  old_format = screen->serverFormat;
1094
1095
0
  if (width & 3)
1096
0
    rfbErr("WARNING: New width (%d) is not a multiple of 4.\n", width);
1097
1098
0
  screen->width = width;
1099
0
  screen->height = height;
1100
0
  screen->bitsPerPixel = screen->depth = 8*bytesPerPixel;
1101
0
  screen->paddedWidthInBytes = width*bytesPerPixel;
1102
1103
0
  rfbInitServerFormat(screen, bitsPerSample);
1104
1105
0
  if (memcmp(&screen->serverFormat, &old_format,
1106
0
             sizeof(rfbPixelFormat)) != 0) {
1107
0
    format_changed = TRUE;
1108
0
  }
1109
1110
0
  screen->frameBuffer = framebuffer;
1111
1112
  /* Adjust pointer position if necessary */
1113
1114
0
  if (screen->cursorX >= width)
1115
0
    screen->cursorX = width - 1;
1116
0
  if (screen->cursorY >= height)
1117
0
    screen->cursorY = height - 1;
1118
1119
  /* For each client: */
1120
0
  iterator = rfbGetClientIterator(screen);
1121
0
  while ((cl = rfbClientIteratorNext(iterator)) != NULL) {
1122
1123
    /* Re-install color translation tables if necessary */
1124
1125
0
    if (format_changed)
1126
0
      screen->setTranslateFunction(cl);
1127
1128
    /* Mark the screen contents as changed, and schedule sending
1129
       NewFBSize message if supported by this client. */
1130
1131
0
    LOCK(cl->updateMutex);
1132
0
    sraRgnDestroy(cl->modifiedRegion);
1133
0
    cl->modifiedRegion = sraRgnCreateRect(0, 0, width, height);
1134
0
    sraRgnMakeEmpty(cl->copyRegion);
1135
0
    cl->copyDX = 0;
1136
0
    cl->copyDY = 0;
1137
1138
0
    if (cl->useNewFBSize)
1139
0
      cl->newFBSizePending = TRUE;
1140
1141
0
    TSIGNAL(cl->updateCond);
1142
0
    UNLOCK(cl->updateMutex);
1143
1144
    /* Swapping frame buffers finished, re-enable client reads. */
1145
0
    UNLOCK(cl->sendMutex);
1146
0
  }
1147
0
  rfbReleaseClientIterator(iterator);
1148
1149
  /* Re-enable cursor drawing into framebuffer */
1150
0
  UNLOCK(screen->cursorMutex);
1151
0
}
1152
1153
/* hang up on all clients and free all reserved memory */
1154
1155
void rfbScreenCleanup(rfbScreenInfoPtr screen)
1156
0
{
1157
0
  rfbClientIteratorPtr i=rfbGetClientIterator(screen);
1158
0
  rfbClientPtr nextCl,currentCl=rfbClientIteratorNext(i);
1159
0
  while(currentCl) {
1160
0
    nextCl=rfbClientIteratorNext(i);
1161
0
    rfbClientConnectionGone(currentCl);
1162
0
    currentCl=nextCl;
1163
0
  }
1164
0
  rfbReleaseClientIterator(i);
1165
    
1166
0
#define FREE_SCREEN_MEMBER(member) free(screen->member)
1167
0
  FREE_SCREEN_MEMBER(colourMap.data.bytes);
1168
0
  FREE_SCREEN_MEMBER(underCursorBuffer);
1169
0
  TINI_MUTEX(screen->cursorMutex);
1170
1171
0
  if(screen->cursor != &myCursor)
1172
0
      rfbFreeCursor(screen->cursor);
1173
1174
0
#ifdef LIBVNCSERVER_HAVE_LIBZ
1175
1176
  /* free all 'scaled' versions of this screen */
1177
0
  while (screen->scaledScreenNext!=NULL)
1178
0
  {
1179
0
      rfbScreenInfoPtr ptr;
1180
0
      ptr = screen->scaledScreenNext;
1181
0
      screen->scaledScreenNext = ptr->scaledScreenNext;
1182
0
      free(ptr->frameBuffer);
1183
0
      free(ptr);
1184
0
  }
1185
1186
0
#endif
1187
0
  free(screen);
1188
0
}
1189
1190
void rfbInitServer(rfbScreenInfoPtr screen)
1191
1
{
1192
1
  rfbInitSockets(screen);
1193
1
  rfbHttpInitSockets(screen);
1194
1
#ifndef WIN32
1195
1
  if(screen->ignoreSIGPIPE)
1196
1
    signal(SIGPIPE,SIG_IGN);
1197
1
#endif
1198
1
}
1199
1200
0
void rfbShutdownServer(rfbScreenInfoPtr screen,rfbBool disconnectClients) {
1201
0
  if(disconnectClients) {
1202
0
    rfbClientIteratorPtr iter = rfbGetClientIterator(screen);
1203
0
    rfbClientPtr nextCl, currentCl = rfbClientIteratorNext(iter);
1204
1205
0
    while(currentCl) {
1206
0
      nextCl = rfbClientIteratorNext(iter);
1207
0
      if (currentCl->sock != RFB_INVALID_SOCKET) {
1208
        /* we don't care about maxfd here, because the server goes away */
1209
0
        rfbCloseClient(currentCl);
1210
0
      }
1211
1212
0
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
1213
0
    if(currentCl->screen->backgroundLoop) {
1214
      /* Wait for threads to finish. The thread has already been pipe-notified by rfbCloseClient() */
1215
0
      pthread_join(currentCl->client_thread, NULL);
1216
0
    } else {
1217
      /*
1218
  In threaded mode, rfbClientConnectionGone() is called by the client-to-server thread.
1219
  Only need to call this here for non-threaded mode.
1220
      */
1221
0
      rfbClientConnectionGone(currentCl);
1222
0
    }
1223
#else
1224
      rfbClientConnectionGone(currentCl);
1225
#endif
1226
1227
0
      currentCl = nextCl;
1228
0
    }
1229
1230
0
    rfbReleaseClientIterator(iter);
1231
0
  }
1232
1233
0
  rfbHttpShutdownSockets(screen);
1234
0
  rfbShutdownSockets(screen);
1235
1236
0
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
1237
0
  if (screen->backgroundLoop) {
1238
      /*
1239
  Notify the listener thread. This simply writes a NULL byte to the notify pipe in order to get past the select()
1240
  in listenerRun, the loop in there will then break because the rfbShutdownSockets() above has set screen->socketState.
1241
      */
1242
0
      write(screen->pipe_notify_listener_thread[1], "\x00", 1);
1243
      /* And wait for it to finish. */
1244
0
      pthread_join(screen->listener_thread, NULL);
1245
      /* Now we can close the pipe */
1246
0
      close(screen->pipe_notify_listener_thread[0]);
1247
0
      close(screen->pipe_notify_listener_thread[1]);
1248
0
  }
1249
0
#endif
1250
0
}
1251
1252
#if !defined LIBVNCSERVER_HAVE_GETTIMEOFDAY && defined WIN32
1253
#include <fcntl.h>
1254
#include <conio.h>
1255
#include <sys/timeb.h>
1256
1257
static void gettimeofday(struct timeval* tv,char* dummy)
1258
{
1259
   SYSTEMTIME t;
1260
   GetSystemTime(&t);
1261
   tv->tv_sec=t.wHour*3600+t.wMinute*60+t.wSecond;
1262
   tv->tv_usec=t.wMilliseconds*1000;
1263
}
1264
#endif
1265
1266
rfbBool
1267
rfbProcessEvents(rfbScreenInfoPtr screen,long usec)
1268
0
{
1269
0
  rfbClientIteratorPtr i;
1270
0
  rfbClientPtr cl,clPrev;
1271
0
  rfbBool result=FALSE;
1272
0
  extern rfbClientIteratorPtr
1273
0
    rfbGetClientIteratorWithClosed(rfbScreenInfoPtr rfbScreen);
1274
1275
0
  if(usec<0)
1276
0
    usec=screen->deferUpdateTime*1000;
1277
1278
0
  rfbCheckFds(screen,usec);
1279
0
  rfbHttpCheckFds(screen);
1280
1281
0
  i = rfbGetClientIteratorWithClosed(screen);
1282
0
  cl=rfbClientIteratorHead(i);
1283
0
  while(cl) {
1284
0
    result = rfbUpdateClient(cl);
1285
0
    clPrev=cl;
1286
0
    cl=rfbClientIteratorNext(i);
1287
0
    if(clPrev->sock==RFB_INVALID_SOCKET) {
1288
0
      rfbClientConnectionGone(clPrev);
1289
0
      result=TRUE;
1290
0
    }
1291
0
  }
1292
0
  rfbReleaseClientIterator(i);
1293
1294
0
  return result;
1295
0
}
1296
1297
rfbBool
1298
rfbUpdateClient(rfbClientPtr cl)
1299
0
{
1300
0
  struct timeval tv;
1301
0
  rfbBool result=FALSE;
1302
0
  rfbScreenInfoPtr screen = cl->screen;
1303
1304
0
  if (cl->sock != RFB_INVALID_SOCKET && !cl->onHold && FB_UPDATE_PENDING(cl) &&
1305
0
        !sraRgnEmpty(cl->requestedRegion)) {
1306
0
      result=TRUE;
1307
0
      if(screen->deferUpdateTime == 0) {
1308
0
          rfbSendFramebufferUpdate(cl,cl->modifiedRegion);
1309
0
      } else if(cl->startDeferring.tv_usec == 0) {
1310
0
        gettimeofday(&cl->startDeferring,NULL);
1311
0
        if(cl->startDeferring.tv_usec == 0)
1312
0
          cl->startDeferring.tv_usec++;
1313
0
      } else {
1314
0
        gettimeofday(&tv,NULL);
1315
0
        if(tv.tv_sec < cl->startDeferring.tv_sec /* at midnight */
1316
0
           || ((tv.tv_sec-cl->startDeferring.tv_sec)*1000
1317
0
               +(tv.tv_usec-cl->startDeferring.tv_usec)/1000)
1318
0
             > screen->deferUpdateTime) {
1319
0
          cl->startDeferring.tv_usec = 0;
1320
0
          rfbSendFramebufferUpdate(cl,cl->modifiedRegion);
1321
0
        }
1322
0
      }
1323
0
    }
1324
1325
0
    if (!cl->viewOnly && cl->lastPtrX >= 0) {
1326
0
      if(cl->startPtrDeferring.tv_usec == 0) {
1327
0
        gettimeofday(&cl->startPtrDeferring,NULL);
1328
0
        if(cl->startPtrDeferring.tv_usec == 0)
1329
0
          cl->startPtrDeferring.tv_usec++;
1330
0
      } else {
1331
0
        struct timeval tv;
1332
0
        gettimeofday(&tv,NULL);
1333
0
        if(tv.tv_sec < cl->startPtrDeferring.tv_sec /* at midnight */
1334
0
           || ((tv.tv_sec-cl->startPtrDeferring.tv_sec)*1000
1335
0
           +(tv.tv_usec-cl->startPtrDeferring.tv_usec)/1000)
1336
0
           > cl->screen->deferPtrUpdateTime) {
1337
0
          cl->startPtrDeferring.tv_usec = 0;
1338
0
          cl->screen->ptrAddEvent(cl->lastPtrButtons,
1339
0
                                  cl->lastPtrX,
1340
0
                                  cl->lastPtrY, cl);
1341
0
          cl->lastPtrX = -1;
1342
0
        }
1343
0
      }
1344
0
    }
1345
1346
0
    return result;
1347
0
}
1348
1349
0
rfbBool rfbIsActive(rfbScreenInfoPtr screenInfo) {
1350
0
  return screenInfo->socketState!=RFB_SOCKET_SHUTDOWN || screenInfo->clientHead!=NULL;
1351
0
}
1352
1353
void rfbRunEventLoop(rfbScreenInfoPtr screen, long usec, rfbBool runInBackground)
1354
0
{
1355
0
  if(usec<0)
1356
0
    usec=screen->deferUpdateTime*1000;
1357
1358
0
  screen->select_timeout_usec = usec;
1359
1360
0
  if(runInBackground) {
1361
0
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
1362
0
       screen->backgroundLoop = TRUE;
1363
0
#ifndef WIN32
1364
0
        if (pipe(screen->pipe_notify_listener_thread) == -1) {
1365
0
            screen->pipe_notify_listener_thread[0] = -1;
1366
0
            screen->pipe_notify_listener_thread[1] = -1;
1367
0
        }
1368
0
        fcntl(screen->pipe_notify_listener_thread[0], F_SETFL, O_NONBLOCK);
1369
0
#endif
1370
0
       pthread_create(&screen->listener_thread, NULL, listenerRun, screen);
1371
0
    return;
1372
#elif defined(LIBVNCSERVER_HAVE_WIN32THREADS)
1373
       screen->backgroundLoop = TRUE;
1374
       screen->listener_thread = _beginthread(listenerRun, 0, screen);
1375
       return;
1376
#else
1377
    rfbErr("Can't run in background, because I don't have PThreads!\n");
1378
    return;
1379
#endif
1380
0
  }
1381
1382
0
  while(rfbIsActive(screen))
1383
0
    rfbProcessEvents(screen,usec);
1384
0
}