6 * Copyright (C) 2002-2003 RealVNC Ltd.
7 * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
9 * This is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This software is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this software; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
27 Copyright (c) 1993 X Consortium
29 Permission is hereby granted, free of charge, to any person obtaining
30 a copy of this software and associated documentation files (the
31 "Software"), to deal in the Software without restriction, including
32 without limitation the rights to use, copy, modify, merge, publish,
33 distribute, sublicense, and/or sell copies of the Software, and to
34 permit persons to whom the Software is furnished to do so, subject to
35 the following conditions:
37 The above copyright notice and this permission notice shall be included
38 in all copies or substantial portions of the Software.
40 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
41 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
42 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
43 IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
44 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
45 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
46 OTHER DEALINGS IN THE SOFTWARE.
48 Except as contained in this notice, the name of the X Consortium shall
49 not be used in advertising or otherwise to promote the sale, use or
50 other dealings in this Software without prior written authorization
51 from the X Consortium.
58 #include <sys/types.h>
59 #include <sys/socket.h>
60 #include <netinet/in.h>
64 #include "X11/Xproto.h"
66 #include "scrnintstr.h"
72 #include "colormapst.h"
75 #include "mipointer.h"
76 #include "dixstruct.h"
77 #include "propertyst.h"
80 #include <sys/param.h>
85 extern Bool cfb16ScreenInit(ScreenPtr, pointer, int, int, int, int, int);
86 extern Bool cfb32ScreenInit(ScreenPtr, pointer, int, int, int, int, int);
88 #define RFB_DEFAULT_WIDTH 640
89 #define RFB_DEFAULT_HEIGHT 480
90 #define RFB_DEFAULT_DEPTH 8
91 #define RFB_DEFAULT_WHITEPIXEL 0
92 #define RFB_DEFAULT_BLACKPIXEL 1
94 rfbScreenInfo rfbScreen;
97 static Bool initOutputCalled = FALSE;
98 static Bool noCursor = FALSE;
99 char *desktopName = "x11";
100 Bool rfbTrace = FALSE;
102 char rfbThisHost[256];
104 Atom VNC_LAST_CLIENT_ID;
106 Atom VNC_DEFER_UPDATE;
108 static HWEventQueueType alwaysCheckForInput[2] = { 0, 1 };
109 static HWEventQueueType *mieqCheckForInput[2];
111 static char primaryOrder[4] = "";
112 static int redBits, greenBits, blueBits;
115 static Bool rfbScreenInit(int index, ScreenPtr pScreen, int argc,
117 static int rfbKeybdProc(DeviceIntPtr pDevice, int onoff);
118 static int rfbMouseProc(DeviceIntPtr pDevice, int onoff);
119 static Bool CheckDisplayNumber(int n);
121 static Bool rfbAlwaysTrue();
122 static char *rfbAllocateFramebufferMemory(rfbScreenInfoPtr prfb);
123 static Bool rfbCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y);
124 static void rfbCrossScreen(ScreenPtr pScreen, Bool entering);
125 static void rfbClientStateChange(CallbackListPtr *, pointer myData,
128 static miPointerScreenFuncRec rfbPointerCursorFuncs = {
136 static char inetdDisplayNumStr[10];
138 extern char buildtime[];
142 * ddxProcessArgument is our first entry point and will be called at the
143 * very start for each argument. It is not called again on server reset.
147 ddxProcessArgument (argc, argv, i)
152 static Bool firstTime = TRUE;
156 rfbScreen.width = RFB_DEFAULT_WIDTH;
157 rfbScreen.height = RFB_DEFAULT_HEIGHT;
158 rfbScreen.depth = RFB_DEFAULT_DEPTH;
159 rfbScreen.blackPixel = RFB_DEFAULT_BLACKPIXEL;
160 rfbScreen.whitePixel = RFB_DEFAULT_WHITEPIXEL;
161 rfbScreen.pfbMemory = NULL;
162 gethostname(rfbThisHost, 255);
166 if (strcasecmp (argv[i], "-geometry") == 0) /* -geometry WxH */
168 if (i + 1 >= argc) UseMsg();
169 if (sscanf(argv[i+1],"%dx%d",
170 &rfbScreen.width,&rfbScreen.height) != 2) {
171 ErrorF("Invalid geometry %s\n", argv[i+1]);
177 if (strcasecmp (argv[i], "-depth") == 0) /* -depth D */
179 if (i + 1 >= argc) UseMsg();
180 rfbScreen.depth = atoi(argv[i+1]);
184 if (strcasecmp (argv[i], "-pixelformat") == 0) {
185 if (i + 1 >= argc) UseMsg();
186 if (sscanf(argv[i+1], "%3s%1d%1d%1d", primaryOrder,
187 &redBits, &greenBits, &blueBits) < 4) {
188 ErrorF("Invalid pixel format %s\n", argv[i+1]);
192 if (strcasecmp(primaryOrder, "bgr") == 0) {
196 } else if (strcasecmp(primaryOrder, "rgb") != 0) {
197 ErrorF("Invalid pixel format %s\n", argv[i+1]);
204 if (strcasecmp (argv[i], "-blackpixel") == 0) { /* -blackpixel n */
205 if (i + 1 >= argc) UseMsg();
206 rfbScreen.blackPixel = atoi(argv[i+1]);
210 if (strcasecmp (argv[i], "-whitepixel") == 0) { /* -whitepixel n */
211 if (i + 1 >= argc) UseMsg();
212 rfbScreen.whitePixel = atoi(argv[i+1]);
216 if (strcasecmp(argv[i], "-rfbport") == 0) { /* -rfbport port */
217 if (i + 1 >= argc) UseMsg();
218 rfbPort = atoi(argv[i+1]);
222 if (strcasecmp(argv[i], "-rfbwait") == 0) { /* -rfbwait ms */
223 if (i + 1 >= argc) UseMsg();
224 rfbMaxClientWait = atoi(argv[i+1]);
228 if (strcasecmp(argv[i], "-nocursor") == 0) {
233 if (strcasecmp(argv[i], "-rfbauth") == 0) { /* -rfbauth passwd-file */
234 if (i + 1 >= argc) UseMsg();
235 rfbAuthPasswdFile = argv[i+1];
239 if (strcasecmp(argv[i], "-httpd") == 0) {
240 if (i + 1 >= argc) UseMsg();
245 if (strcasecmp(argv[i], "-httpport") == 0) {
246 if (i + 1 >= argc) UseMsg();
247 httpPort = atoi(argv[i+1]);
251 if (strcasecmp(argv[i], "-deferupdate") == 0) { /* -deferupdate ms */
252 if (i + 1 >= argc) UseMsg();
253 rfbDeferUpdateTime = atoi(argv[i+1]);
257 if (strcasecmp(argv[i], "-economictranslate") == 0) {
258 rfbEconomicTranslate = TRUE;
262 if (strcasecmp(argv[i], "-maxrects") == 0) {
263 if (i + 1 >= argc) UseMsg();
264 rfbMaxRects = atoi(argv[i+1]);
268 if (strcasecmp(argv[i], "-trace") == 0) {
273 if (strcasecmp(argv[i], "-desktop") == 0) { /* -desktop desktop-name */
274 if (i + 1 >= argc) UseMsg();
275 desktopName = argv[i+1];
279 if (strcasecmp(argv[i], "-alwaysshared") == 0) {
280 rfbAlwaysShared = TRUE;
284 if (strcasecmp(argv[i], "-nevershared") == 0) {
285 rfbNeverShared = TRUE;
289 if (strcasecmp(argv[i], "-dontdisconnect") == 0) {
290 rfbDontDisconnect = TRUE;
294 if (strcasecmp(argv[i], "-localhost") == 0) {
295 rfbLocalhostOnly = TRUE;
299 if (strcasecmp(argv[i], "-inetd") == 0) { /* -inetd */
301 for (n = 1; n < 100; n++) {
302 if (CheckDisplayNumber(n))
307 FatalError("-inetd: couldn't find free display number");
309 sprintf(inetdDisplayNumStr, "%d", n);
310 display = inetdDisplayNumStr;
312 /* fds 0, 1 and 2 (stdin, out and err) are all the same socket to the
313 RFB client. OsInit() closes stdout and stdin, and we don't want
314 stderr to go to the RFB client, so make the client socket 3 and
315 close stderr. OsInit() will redirect stderr logging to an
316 appropriate log file or /dev/null if that doesn't work. */
325 if (inetdSock != -1 && argv[i][0] == ':') {
326 FatalError("can't specify both -inetd and :displaynumber");
334 * InitOutput is called every time the server resets. It should call
335 * AddScreen for each screen (but we only ever have one), and in turn this
336 * will call rfbScreenInit.
340 InitOutput(screenInfo, argc, argv)
341 ScreenInfo *screenInfo;
345 initOutputCalled = TRUE;
347 rfbLog("Xvnc version %s - built %s\n", XVNCRELEASE, buildtime);
348 rfbLog("Copyright (C) 2002-2003 RealVNC Ltd.\n");
349 rfbLog("Copyright (C) 1994-2000 AT&T Laboratories Cambridge.\n");
350 rfbLog("All Rights Reserved.\n");
351 rfbLog("See http://www.realvnc.com for information on VNC\n");
352 rfbLog("Desktop name '%s' (%s:%s)\n",desktopName,rfbThisHost,display);
353 rfbLog("Protocol version supported %d.%d\n", rfbProtocolMajorVersion,
354 rfbProtocolMinorVersion);
356 VNC_LAST_CLIENT_ID = MakeAtom("VNC_LAST_CLIENT_ID",
357 strlen("VNC_LAST_CLIENT_ID"), TRUE);
358 VNC_CONNECT = MakeAtom("VNC_CONNECT", strlen("VNC_CONNECT"), TRUE);
359 VNC_DEFER_UPDATE = MakeAtom("VNC_DEFER_UPDATE",
360 strlen("VNC_DEFER_UPDATE"), TRUE);
366 /* initialize pixmap formats */
368 screenInfo->imageByteOrder = IMAGE_BYTE_ORDER;
369 screenInfo->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT;
370 screenInfo->bitmapScanlinePad = BITMAP_SCANLINE_PAD;
371 screenInfo->bitmapBitOrder = BITMAP_BIT_ORDER;
372 screenInfo->numPixmapFormats = 2;
374 screenInfo->formats[0].depth = 1;
375 screenInfo->formats[0].bitsPerPixel = 1;
376 screenInfo->formats[0].scanlinePad = BITMAP_SCANLINE_PAD;
378 screenInfo->formats[1].depth = rfbScreen.depth;
379 screenInfo->formats[1].bitsPerPixel = rfbBitsPerPixel(rfbScreen.depth);
380 screenInfo->formats[1].scanlinePad = BITMAP_SCANLINE_PAD;
382 rfbGCIndex = AllocateGCPrivateIndex();
383 if (rfbGCIndex < 0) {
384 FatalError("InitOutput: AllocateGCPrivateIndex failed\n");
387 if (!AddCallback(&ClientStateCallback, rfbClientStateChange, NULL)) {
388 rfbLog("InitOutput: AddCallback failed\n");
392 /* initialize screen */
394 if (AddScreen(rfbScreenInit, argc, argv) == -1) {
395 FatalError("Couldn't add screen");
401 rfbScreenInit(index, pScreen, argc, argv)
407 rfbScreenInfoPtr prfb = &rfbScreen;
408 int dpix = 75, dpiy = 75;
412 extern int monitorResolution;
414 if (monitorResolution != 0) {
415 dpix = monitorResolution;
416 dpiy = monitorResolution;
419 prfb->paddedWidthInBytes = PixmapBytePad(prfb->width, prfb->depth);
420 prfb->bitsPerPixel = rfbBitsPerPixel(prfb->depth);
421 pbits = rfbAllocateFramebufferMemory(prfb);
422 if (!pbits) return FALSE;
424 if (prfb->bitsPerPixel > 1) {
425 extern int defaultColorVisualClass;
426 if (defaultColorVisualClass != -1) {
427 cfbSetVisualTypes(prfb->depth, (1 << defaultColorVisualClass), 8);
429 cfbSetVisualTypes(prfb->depth, (1 << TrueColor), 8);
433 switch (prfb->bitsPerPixel)
436 ret = mfbScreenInit(pScreen, pbits, prfb->width, prfb->height,
437 dpix, dpiy, prfb->paddedWidthInBytes * 8);
440 ret = cfbScreenInit(pScreen, pbits, prfb->width, prfb->height,
441 dpix, dpiy, prfb->paddedWidthInBytes);
444 ret = cfb16ScreenInit(pScreen, pbits, prfb->width, prfb->height,
445 dpix, dpiy, prfb->paddedWidthInBytes / 2);
448 ret = cfb32ScreenInit(pScreen, pbits, prfb->width, prfb->height,
449 dpix, dpiy, prfb->paddedWidthInBytes / 4);
455 if (!ret) return FALSE;
457 if (!AllocateGCPrivate(pScreen, rfbGCIndex, sizeof(rfbGCRec))) {
458 FatalError("rfbScreenInit: AllocateGCPrivate failed\n");
461 prfb->cursorIsDrawn = FALSE;
462 prfb->dontSendFramebufferUpdate = FALSE;
464 prfb->CloseScreen = pScreen->CloseScreen;
465 prfb->CreateGC = pScreen->CreateGC;
466 prfb->PaintWindowBackground = pScreen->PaintWindowBackground;
467 prfb->PaintWindowBorder = pScreen->PaintWindowBorder;
468 prfb->CopyWindow = pScreen->CopyWindow;
469 prfb->ClearToBackground = pScreen->ClearToBackground;
470 prfb->RestoreAreas = pScreen->RestoreAreas;
472 pScreen->CloseScreen = rfbCloseScreen;
473 pScreen->CreateGC = rfbCreateGC;
474 pScreen->PaintWindowBackground = rfbPaintWindowBackground;
475 pScreen->PaintWindowBorder = rfbPaintWindowBorder;
476 pScreen->CopyWindow = rfbCopyWindow;
477 pScreen->ClearToBackground = rfbClearToBackground;
478 pScreen->RestoreAreas = rfbRestoreAreas;
480 pScreen->InstallColormap = rfbInstallColormap;
481 pScreen->UninstallColormap = rfbUninstallColormap;
482 pScreen->ListInstalledColormaps = rfbListInstalledColormaps;
483 pScreen->StoreColors = rfbStoreColors;
485 pScreen->SaveScreen = rfbAlwaysTrue;
487 rfbDCInitialize(pScreen, &rfbPointerCursorFuncs);
490 pScreen->DisplayCursor = rfbAlwaysTrue;
491 prfb->cursorIsDrawn = TRUE;
494 pScreen->blackPixel = prfb->blackPixel;
495 pScreen->whitePixel = prfb->whitePixel;
497 for (vis = pScreen->visuals; vis->vid != pScreen->rootVisual; vis++)
501 rfbLog("rfbScreenInit: couldn't find root visual\n");
505 if (strcmp(primaryOrder, "") == 0) {
506 if (prfb->depth == 16) { /* use rgb565 for depth 16 */
507 strcpy(primaryOrder, "rgb");
511 } else if (prfb->depth == 24) { /* use rgb888 for depth 24 */
512 strcpy(primaryOrder, "rgb");
519 if (strcasecmp(primaryOrder, "rgb") == 0) {
521 vis->blueMask = (1 << blueBits) - 1;
522 vis->offsetGreen = blueBits;
523 vis->greenMask = ((1 << greenBits) - 1) << vis->offsetGreen;
524 vis->offsetRed = vis->offsetGreen + greenBits;
525 vis->redMask = ((1 << redBits) - 1) << vis->offsetRed;
526 } else if (strcasecmp(primaryOrder, "bgr") == 0) {
527 rfbLog("BGR format %d %d %d\n", blueBits, greenBits, redBits);
529 vis->redMask = (1 << redBits) - 1;
530 vis->offsetGreen = redBits;
531 vis->greenMask = ((1 << greenBits) - 1) << vis->offsetGreen;
532 vis->offsetBlue = vis->offsetGreen + greenBits;
533 vis->blueMask = ((1 << blueBits) - 1) << vis->offsetBlue;
536 rfbServerFormat.bitsPerPixel = prfb->bitsPerPixel;
537 rfbServerFormat.depth = prfb->depth;
538 rfbServerFormat.bigEndian = !(*(char *)&rfbEndianTest);
539 rfbServerFormat.trueColour = (vis->class == TrueColor);
540 if (rfbServerFormat.trueColour) {
541 rfbServerFormat.redMax = vis->redMask >> vis->offsetRed;
542 rfbServerFormat.greenMax = vis->greenMask >> vis->offsetGreen;
543 rfbServerFormat.blueMax = vis->blueMask >> vis->offsetBlue;
544 rfbServerFormat.redShift = vis->offsetRed;
545 rfbServerFormat.greenShift = vis->offsetGreen;
546 rfbServerFormat.blueShift = vis->offsetBlue;
548 rfbServerFormat.redMax
549 = rfbServerFormat.greenMax = rfbServerFormat.blueMax = 0;
550 rfbServerFormat.redShift
551 = rfbServerFormat.greenShift = rfbServerFormat.blueShift = 0;
554 if (prfb->bitsPerPixel == 1)
556 ret = mfbCreateDefColormap(pScreen);
560 ret = cfbCreateDefColormap(pScreen);
565 } /* end rfbScreenInit */
570 * InitInput is also called every time the server resets. It is called after
571 * InitOutput so we can assume that rfbInitSockets has already been called.
575 InitInput(argc, argv)
580 k = AddInputDevice(rfbKeybdProc, TRUE);
581 p = AddInputDevice(rfbMouseProc, TRUE);
582 RegisterKeyboardDevice(k);
583 RegisterPointerDevice(p);
584 miRegisterPointerDevice(screenInfo.screens[0], p);
585 mieqInit((DevicePtr)k, (DevicePtr)p);
586 mieqCheckForInput[0] = checkForInput[0];
587 mieqCheckForInput[1] = checkForInput[1];
588 SetInputCheck(&alwaysCheckForInput[0], &alwaysCheckForInput[1]);
593 rfbKeybdProc(pDevice, onoff)
594 DeviceIntPtr pDevice;
598 CARD8 modMap[MAP_LENGTH];
599 DevicePtr pDev = (DevicePtr)pDevice;
604 KbdDeviceInit(pDevice, &keySyms, modMap);
605 InitKeyboardDeviceStruct(pDev, &keySyms, modMap,
606 (BellProcPtr)rfbSendBell,
607 (KbdCtrlProcPtr)NoopDDA);
626 rfbMouseProc(pDevice, onoff)
627 DeviceIntPtr pDevice;
631 DevicePtr pDev = (DevicePtr)pDevice;
642 InitPointerDeviceStruct(pDev, map, 5, miPointerGetMotionEvents,
644 miPointerGetMotionBufferSize());
649 PtrDeviceOn(pDevice);
667 LegalModifier(key, pDev)
680 if (*mieqCheckForInput[0] != *mieqCheckForInput[1]) {
681 mieqProcessInputEvents();
687 static Bool CheckDisplayNumber(int n)
691 struct sockaddr_in addr;
693 sock = socket(AF_INET, SOCK_STREAM, 0);
694 addr.sin_family = AF_INET;
695 addr.sin_addr.s_addr = htonl(INADDR_ANY);
696 addr.sin_port = htons(6000+n);
697 if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
703 sprintf(fname, "/tmp/.X%d-lock", n);
704 if (access(fname, F_OK) == 0)
707 sprintf(fname, "/tmp/.X11-unix/X%d", n);
708 if (access(fname, F_OK) == 0)
711 sprintf(fname, "/usr/spool/sockets/X11/%d", n);
712 if (access(fname, F_OK) == 0)
720 rfbRootPropertyChange(PropertyPtr pProp)
722 if ((pProp->propertyName == XA_CUT_BUFFER0) && (pProp->type == XA_STRING)
723 && (pProp->format == 8))
725 rfbGotXCutText(pProp->data, pProp->size);
727 else if ((pProp->propertyName == VNC_CONNECT) && (pProp->type == XA_STRING)
728 && (pProp->format == 8))
730 if (pProp->size == 0) {
731 rfbClientPtr cl, nextCl;
732 rfbLog("VNC_CONNECT message: disconnecting all clients\n");
733 for (cl = rfbClientHead; cl; cl = nextCl) {
735 rfbCloseSock(cl->sock);
741 char *host = (char *)Xalloc(pProp->size+1);
742 memcpy(host, pProp->data, pProp->size);
743 host[pProp->size] = 0;
744 for (i = 0; i < pProp->size; i++) {
745 if (host[i] == ':') {
746 port = atoi(&host[i+1]);
751 cl = rfbReverseConnection(host, port);
757 else if ((pProp->propertyName == VNC_DEFER_UPDATE) &&
758 (pProp->type == XA_STRING) && (pProp->format == 8))
760 char *str = (char *)Xalloc(pProp->size+1);
761 memcpy(str, pProp->data, pProp->size);
762 str[pProp->size] = 0;
763 rfbDeferUpdateTime = atoi(str);
770 rfbBitsPerPixel(depth)
773 if (depth == 1) return 1;
774 else if (depth <= 8) return 8;
775 else if (depth <= 16) return 16;
788 rfbAllocateFramebufferMemory(prfb)
789 rfbScreenInfoPtr prfb;
791 if (prfb->pfbMemory) return prfb->pfbMemory; /* already done */
793 prfb->sizeInBytes = (prfb->paddedWidthInBytes * prfb->height);
795 prfb->pfbMemory = (char *)Xalloc(prfb->sizeInBytes);
797 return prfb->pfbMemory;
802 rfbCursorOffScreen (ppScreen, x, y)
810 rfbCrossScreen (pScreen, entering)
817 rfbClientStateChange(cbl, myData, clt)
818 CallbackListPtr *cbl;
822 dispatchException &= ~DE_RESET; /* hack - force server not to reset */
828 Xfree(rfbScreen.pfbMemory);
829 if (initOutputCalled) {
830 char unixSocketName[256];
831 sprintf(unixSocketName,"/tmp/.X11-unix/X%s",display);
832 unlink(unixSocketName);
833 sprintf(unixSocketName,"/usr/spool/sockets/X11/%s",display);
834 unlink(unixSocketName);
854 #ifdef DDXTIME /* from ServerOSDefines */
861 return(tp.tv_sec * 1000) + (tp.tv_usec / 1000);
868 ErrorF("\nXvnc version %s - built %s\n\n", XVNCRELEASE, buildtime);
869 ErrorF("-geometry WxH set framebuffer width & height\n");
870 ErrorF("-depth D set framebuffer depth\n");
871 ErrorF("-pixelformat format set pixel format (BGRnnn or RGBnnn)\n");
872 ErrorF("-rfbport port TCP port for RFB protocol\n");
873 ErrorF("-rfbwait time max time in ms to wait for RFB client\n");
874 ErrorF("-nocursor don't put up a cursor\n");
875 ErrorF("-rfbauth passwd-file use authentication on RFB protocol\n");
876 ErrorF("-httpd dir serve files via HTTP from here\n");
877 ErrorF("-httpport port port for HTTP\n");
878 ErrorF("-deferupdate time time in ms to defer updates "
880 ErrorF("-economictranslate less memory-hungry translation\n");
881 ErrorF("-maxrects num max number of rectangles in an update "
883 ErrorF("-desktop name VNC desktop name (default x11)\n");
884 ErrorF("-alwaysshared always treat new clients as shared\n");
885 ErrorF("-nevershared never treat new clients as shared\n");
886 ErrorF("-dontdisconnect don't disconnect existing clients when a "
888 " connection comes in (refuse new connection "
890 ErrorF("-localhost only allow connections from localhost\n");
891 ErrorF("-inetd Xvnc is launched by inetd\n");
896 * rfbLog prints a time-stamped message to the log file (stderr).
899 void rfbLog(char *format, ...)
905 va_start(args, format);
908 strftime(buf, 255, "%d/%m/%y %T ", localtime(&clock));
909 fprintf(stderr, buf);
911 vfprintf(stderr, format, args);
917 void rfbLogPerror(char *str)