diff --git a/ChangeLog.md b/ChangeLog.md index ad8769ac5..3282540ca 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -18,6 +18,21 @@ VirtualGL, although the performance will be better with VirtualGL. Refer to the description of the `-drinode` option in the Xvnc man page for more details. +3.1.2 +===== + +### Significant changes relative to 3.1.1: + +1. The TurboVNC Server now assigns an ordinal ID to every VNC viewer after the +viewer successfully connects, and the viewer's ID is reported in the TurboVNC +session log along with the IP address from which the viewer connection +originated. This makes it easier to distinguish log entries related to a +specific viewer, especially when using SSH tunneling (which makes it appear as +if all viewer connections originate from the loopback IP address.) The +TurboVNC Server now also logs the total number of simultaneously connected +viewers. + + 3.1.1 ===== diff --git a/unix/Xvnc/programs/Xserver/hw/vnc/auth.c b/unix/Xvnc/programs/Xserver/hw/vnc/auth.c index 86c275d86..bff5606e9 100644 --- a/unix/Xvnc/programs/Xserver/hw/vnc/auth.c +++ b/unix/Xvnc/programs/Xserver/hw/vnc/auth.c @@ -4,7 +4,7 @@ * This file implements authentication when setting up an RFB connection. */ -/* Copyright (C) 2010, 2012-2022 D. R. Commander. All Rights Reserved. +/* Copyright (C) 2010, 2012-2022, 2024 D. R. Commander. All Rights Reserved. * Copyright (C) 2010 University Corporation for Atmospheric Research. * All Rights Reserved. * Copyright (C) 2003-2006 Constantin Kaplinsky. All Rights Reserved. @@ -1354,12 +1354,14 @@ static Bool CheckResponse(rfbClientPtr cl, int numPasswords, memset(passwdViewOnly, 0, MAXPWLEN + 1); if (memcmp(encryptedChallenge1, response, CHALLENGESIZE) == 0) { - rfbLog("Full-control authentication enabled for %s\n", cl->host); + rfbLog("Full-control authentication enabled for Client %d (%s)\n", cl->id, + cl->host); ok = TRUE; cl->viewOnly = FALSE; } else if (memcmp(encryptedChallenge2, response, CHALLENGESIZE) == 0) { - rfbLog("View-only authentication enabled for %s\n", cl->host); + rfbLog("View-only authentication enabled for Client %d (%s)\n", cl->id, + cl->host); ok = TRUE; cl->viewOnly = TRUE; } @@ -1441,7 +1443,7 @@ void rfbVncAuthProcessResponse(rfbClientPtr cl) for (otherCl = rfbClientHead; otherCl; otherCl = otherCl->next) { if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) { rfbLog("-dontdisconnect: Not shared & existing client\n"); - rfbLog(" refusing new client %s\n", cl->host); + rfbLog(" refusing new client %d (%s)\n", cl->id, cl->host); rfbClientAuthFailed(cl, "Authentication failed. The server is already in use."); return; } @@ -1449,8 +1451,8 @@ void rfbVncAuthProcessResponse(rfbClientPtr cl) } rfbClientAuthSucceeded(cl, rfbAuthVNC); } else { - rfbLog("rfbVncAuthProcessResponse: authentication failed from %s\n", - cl->host); + rfbLog("rfbVncAuthProcessResponse: authentication failed from Client %d (%s)\n", + cl->id, cl->host); if (rfbAuthConsiderBlocking(cl->host)) rfbClientAuthFailed(cl, "Authentication failed. Client temporarily blocked"); else diff --git a/unix/Xvnc/programs/Xserver/hw/vnc/authpam.c b/unix/Xvnc/programs/Xserver/hw/vnc/authpam.c index c36fa989c..1f030a0b9 100644 --- a/unix/Xvnc/programs/Xserver/hw/vnc/authpam.c +++ b/unix/Xvnc/programs/Xserver/hw/vnc/authpam.c @@ -2,7 +2,8 @@ * authpam.c - deal with PAM authentication. */ -/* Copyright (C) 2015, 2017-2018, 2020 D. R. Commander. All Rights Reserved. +/* Copyright (C) 2015, 2017-2018, 2020, 2024 D. R. Commander. + * All Rights Reserved. * Copyright (C) 2020 Andrew Yoder. All Rights Reserved. * Copyright (C) 2010 University Corporation for Atmospheric Research. * All Rights Reserved. @@ -153,7 +154,7 @@ Bool rfbPAMAuthenticate(rfbClientPtr cl, const char *svc, const char *user, rfbLog("PAMAuthenticate: pam_open_session: %s\n", pam_strerror(pamHandle, authStatus)); } else { - rfbLog("Opened PAM session for client %s\n", cl->host); + rfbLog("Opened PAM session for Client %d (%s)\n", cl->id, cl->host); } } } @@ -212,7 +213,7 @@ void rfbPAMEnd(rfbClientPtr cl) if ((r = pam_end(cl->pamHandle, PAM_SUCCESS)) != PAM_SUCCESS) rfbLog("PAMEnd: pam_end: %s\n", pam_strerror(cl->pamHandle, r)); - rfbLog("Closed PAM session for client %s\n", cl->host); + rfbLog("Closed PAM session for Client %d (%s)\n", cl->id, cl->host); cl->pamHandle = 0; } } diff --git a/unix/Xvnc/programs/Xserver/hw/vnc/rfb.h b/unix/Xvnc/programs/Xserver/hw/vnc/rfb.h index 4b272a4f1..9e982acae 100644 --- a/unix/Xvnc/programs/Xserver/hw/vnc/rfb.h +++ b/unix/Xvnc/programs/Xserver/hw/vnc/rfb.h @@ -263,7 +263,7 @@ typedef struct rfbClientRec { int sock; char *host; - char *login; + int id; int protocol_minor_ver; /* RFB protocol minor version in use */ Bool protocol_tightvnc; /* TightVNC protocol extensions enabled */ @@ -981,6 +981,7 @@ extern Bool rfbGIIDebug; extern int rfbInterframe; extern int rfbMaxClipboard; extern Bool rfbVirtualTablet; +extern int rfbClientNumber; /* Multithreading params specified on the command line or in the environment */ extern Bool rfbMT; @@ -992,6 +993,7 @@ extern char *rfbCaptureFile; rfbLog(m" %d, %d %d x %d\n", (r).extents.x1, (r).extents.y1, \ (r).extents.x2 - (r).extents.x1, (r).extents.y2 - (r).extents.y1) +extern int rfbClientCount(void); extern void rfbNewClientConnection(int sock); extern rfbClientPtr rfbReverseConnection(char *host, int port, int id); extern void rfbClientConnectionGone(rfbClientPtr cl); diff --git a/unix/Xvnc/programs/Xserver/hw/vnc/rfbserver.c b/unix/Xvnc/programs/Xserver/hw/vnc/rfbserver.c index cfde75391..bdbb79b35 100644 --- a/unix/Xvnc/programs/Xserver/hw/vnc/rfbserver.c +++ b/unix/Xvnc/programs/Xserver/hw/vnc/rfbserver.c @@ -2,7 +2,7 @@ * rfbserver.c - deal with server-side of the RFB protocol. */ -/* Copyright (C) 2009-2022 D. R. Commander. All Rights Reserved. +/* Copyright (C) 2009-2022, 2024 D. R. Commander. All Rights Reserved. * Copyright (C) 2015-2017, 2020-2021 Pierre Ossman for Cendio AB. * All Rights Reserved. * Copyright (C) 2021 AnatoScope SA. All Rights Reserved. @@ -78,6 +78,7 @@ Bool rfbGIIDebug = FALSE; int rfbMaxWidth = MAXSHORT, rfbMaxHeight = MAXSHORT; int rfbMaxClipboard = MAX_CUTTEXT_LEN; Bool rfbVirtualTablet = FALSE; +int rfbClientNumber = 1; #if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__) Bool rfbMT = TRUE; #else @@ -99,6 +100,17 @@ static Bool rfbSendQEMUExtKeyEventRect(rfbClientPtr cl); static Bool rfbSendLEDState(rfbClientPtr cl); +int rfbClientCount(void) +{ + rfbClientPtr cl; + int count = 0; + + for (cl = rfbClientHead; cl; cl = cl->next) + count++; + return count; +} + + /* * Session capture */ @@ -375,6 +387,7 @@ static rfbClientPtr rfbNewClient(int sock) cl->sock = sock; getpeername(sock, &addr.u.sa, &addrlen); cl->host = strdup(sockaddr_string(&addr, addrStr, INET6_ADDRSTRLEN)); + cl->id = rfbClientNumber++; /* Dispatch client input to rfbProcessClientProtocolVersion(). */ cl->state = RFB_PROTOCOL_VERSION; @@ -533,12 +546,7 @@ void rfbClientConnectionGone(rfbClientPtr cl) #ifdef XVNC_AuthPAM rfbPAMEnd(cl); #endif - if (cl->login != NULL) { - rfbLog("Client %s (%s) gone\n", cl->login, cl->host); - free(cl->login); - } else { - rfbLog("Client %s gone\n", cl->host); - } + rfbLog("Client %d (%s) gone\n", cl->id, cl->host); free(cl->host); ShutdownTightThreads(); @@ -597,6 +605,8 @@ void rfbClientConnectionGone(rfbClientPtr cl) free(cl); + rfbLog("Number of connected clients: %d\n", rfbClientCount()); + if (rfbClientHead == NULL && rfbIdleTimeout > 0) IdleTimerSet(); } @@ -763,8 +773,9 @@ static void rfbProcessClientInitMessage(rfbClientPtr cl) for (otherCl = rfbClientHead; otherCl; otherCl = otherCl->next) { if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) { rfbLog("-dontdisconnect: Not shared & existing client\n"); - rfbLog(" refusing new client %s\n", cl->host); + rfbLog(" refusing new client %d (%s)\n", cl->id, cl->host); rfbCloseClient(cl); + rfbClientNumber--; return; } } @@ -772,13 +783,15 @@ static void rfbProcessClientInitMessage(rfbClientPtr cl) for (otherCl = rfbClientHead; otherCl; otherCl = nextCl) { nextCl = otherCl->next; if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) { - rfbLog("Not shared - closing connection to client %s\n", - otherCl->host); + rfbLog("Not shared - closing connection to Client %d (%s)\n", + otherCl->id, otherCl->host); rfbCloseClient(otherCl); } } } } + + rfbLog("Number of connected clients: %d\n", rfbClientCount()); } @@ -949,55 +962,63 @@ static void rfbProcessClientNormalMessage(rfbClientPtr cl) case rfbEncodingRaw: if (cl->preferredEncoding == -1) { cl->preferredEncoding = enc; - rfbLog("Using raw encoding for client %s\n", cl->host); + rfbLog("Using raw encoding for Client %d (%s)\n", cl->id, + cl->host); } break; case rfbEncodingRRE: if (cl->preferredEncoding == -1) { cl->preferredEncoding = enc; - rfbLog("Using rre encoding for client %s\n", cl->host); + rfbLog("Using rre encoding for Client %d (%s)\n", cl->id, + cl->host); } break; case rfbEncodingCoRRE: if (cl->preferredEncoding == -1) { cl->preferredEncoding = enc; - rfbLog("Using CoRRE encoding for client %s\n", cl->host); + rfbLog("Using CoRRE encoding for Client %d (%s)\n", cl->id, + cl->host); } break; case rfbEncodingHextile: if (cl->preferredEncoding == -1) { cl->preferredEncoding = enc; - rfbLog("Using hextile encoding for client %s\n", cl->host); + rfbLog("Using hextile encoding for Client %d (%s)\n", cl->id, + cl->host); } break; case rfbEncodingZlib: if (cl->preferredEncoding == -1) { cl->preferredEncoding = enc; - rfbLog("Using zlib encoding for client %s\n", cl->host); + rfbLog("Using zlib encoding for Client %d (%s)\n", cl->id, + cl->host); } break; case rfbEncodingZRLE: if (cl->preferredEncoding == -1) { cl->preferredEncoding = enc; - rfbLog("Using ZRLE encoding for client %s\n", cl->host); + rfbLog("Using ZRLE encoding for Client %d (%s)\n", cl->id, + cl->host); } break; case rfbEncodingZYWRLE: if (cl->preferredEncoding == -1) { cl->preferredEncoding = enc; - rfbLog("Using ZYWRLE encoding for client %s\n", cl->host); + rfbLog("Using ZYWRLE encoding for Client %d (%s)\n", cl->id, + cl->host); } break; case rfbEncodingTight: if (cl->preferredEncoding == -1) { cl->preferredEncoding = enc; - rfbLog("Using tight encoding for client %s\n", cl->host); + rfbLog("Using tight encoding for Client %d (%s)\n", cl->id, + cl->host); } break; case rfbEncodingXCursor: if (!cl->enableCursorShapeUpdates) { - rfbLog("Enabling X-style cursor updates for client %s\n", - cl->host); + rfbLog("Enabling X-style cursor updates for Client %d (%s)\n", + cl->id, cl->host); cl->enableCursorShapeUpdates = TRUE; cl->useRichCursorEncoding = FALSE; cl->cursorWasChanged = TRUE; @@ -1005,8 +1026,8 @@ static void rfbProcessClientNormalMessage(rfbClientPtr cl) break; case rfbEncodingRichCursor: if (!cl->enableCursorShapeUpdates) { - rfbLog("Enabling full-color cursor updates for client %s\n", - cl->host); + rfbLog("Enabling full-color cursor updates for Client %d (%s)\n", + cl->id, cl->host); cl->enableCursorShapeUpdates = TRUE; cl->useRichCursorEncoding = TRUE; cl->cursorWasChanged = TRUE; @@ -1014,8 +1035,8 @@ static void rfbProcessClientNormalMessage(rfbClientPtr cl) break; case rfbEncodingPointerPos: if (!cl->enableCursorPosUpdates) { - rfbLog("Enabling cursor position updates for client %s\n", - cl->host); + rfbLog("Enabling cursor position updates for Client %d (%s)\n", + cl->id, cl->host); cl->enableCursorPosUpdates = TRUE; cl->cursorWasMoved = TRUE; cl->cursorX = -1; @@ -1024,37 +1045,37 @@ static void rfbProcessClientNormalMessage(rfbClientPtr cl) break; case rfbEncodingLastRect: if (!cl->enableLastRectEncoding) { - rfbLog("Enabling LastRect protocol extension for client %s\n", - cl->host); + rfbLog("Enabling LastRect protocol extension for Client %d (%s)\n", + cl->id, cl->host); cl->enableLastRectEncoding = TRUE; } break; case rfbEncodingExtendedClipboard: if (!cl->enableExtClipboard) { - rfbLog("Enabling Extended Clipboard protocol extension for client %s\n", - cl->host); + rfbLog("Enabling Extended Clipboard protocol extension for Client %d (%s)\n", + cl->id, cl->host); cl->enableExtClipboard = TRUE; } break; case rfbEncodingFence: if (!cl->enableFence) { - rfbLog("Enabling Fence protocol extension for client %s\n", - cl->host); + rfbLog("Enabling Fence protocol extension for Client %d (%s)\n", + cl->id, cl->host); cl->enableFence = TRUE; } break; case rfbEncodingContinuousUpdates: if (!cl->enableCU) { - rfbLog("Enabling Continuous Updates protocol extension for client %s\n", - cl->host); + rfbLog("Enabling Continuous Updates protocol extension for Client %d (%s)\n", + cl->id, cl->host); cl->enableCU = TRUE; } break; case rfbEncodingNewFBSize: if (!cl->enableDesktopSize) { if (!rfbAuthDisableRemoteResize) { - rfbLog("Enabling Desktop Size protocol extension for client %s\n", - cl->host); + rfbLog("Enabling Desktop Size protocol extension for Client %d (%s)\n", + cl->id, cl->host); cl->enableDesktopSize = TRUE; } else rfbLog("WARNING: Remote desktop resizing disabled per system policy.\n"); @@ -1063,8 +1084,8 @@ static void rfbProcessClientNormalMessage(rfbClientPtr cl) case rfbEncodingExtendedDesktopSize: if (!cl->enableExtDesktopSize) { if (!rfbAuthDisableRemoteResize) { - rfbLog("Enabling Extended Desktop Size protocol extension for client %s\n", - cl->host); + rfbLog("Enabling Extended Desktop Size protocol extension for Client %d (%s)\n", + cl->id, cl->host); cl->enableExtDesktopSize = TRUE; } else rfbLog("WARNING: Remote desktop resizing disabled per system policy.\n"); @@ -1072,25 +1093,29 @@ static void rfbProcessClientNormalMessage(rfbClientPtr cl) break; case rfbEncodingGII: if (!cl->enableGII) { - rfbLog("Enabling GII protocol extension for client %s\n", cl->host); + rfbLog("Enabling GII protocol extension for Client %d (%s)\n", + cl->id, cl->host); cl->enableGII = TRUE; } break; case rfbEncodingQEMUExtendedKeyEvent: if (!cl->enableQEMUExtKeyEvent && enableQEMUExtKeyEvent) { - rfbLog("Enabling QEMU Extended Key Event protocol extension for client %s\n", cl->host); + rfbLog("Enabling QEMU Extended Key Event protocol extension for Client %d (%s)\n", + cl->id, cl->host); cl->enableQEMUExtKeyEvent = TRUE; } break; case rfbEncodingQEMULEDState: if (!cl->enableQEMULEDState && enableQEMUExtKeyEvent) { - rfbLog("Enabling QEMU LED State protocol extension for client %s\n", cl->host); + rfbLog("Enabling QEMU LED State protocol extension for Client %d (%s)\n", + cl->id, cl->host); cl->enableQEMULEDState = TRUE; } break; case rfbEncodingVMwareLEDState: if (!cl->enableVMwareLEDState && enableQEMUExtKeyEvent) { - rfbLog("Enabling VMware LED State protocol extension for client %s\n", cl->host); + rfbLog("Enabling VMware LED State protocol extension for Client %d (%s)\n", + cl->id, cl->host); cl->enableVMwareLEDState = TRUE; } break; @@ -1102,8 +1127,8 @@ static void rfbProcessClientNormalMessage(rfbClientPtr cl) if (cl->preferredEncoding == rfbEncodingTight) logTightCompressLevel = TRUE; else - rfbLog("Using compression level %d for client %s\n", - cl->tightCompressLevel, cl->host); + rfbLog("Using compression level %d for Client %d (%s)\n", + cl->tightCompressLevel, cl->id, cl->host); if (rfbInterframe == -1) { if (cl->tightCompressLevel >= 5) { if (!InterframeOn(cl)) { @@ -1116,24 +1141,25 @@ static void rfbProcessClientNormalMessage(rfbClientPtr cl) } else if (enc >= (CARD32)rfbEncodingSubsamp1X && enc <= (CARD32)rfbEncodingSubsampGray) { cl->tightSubsampLevel = enc & 0xFF; - rfbLog("Using JPEG subsampling %d for client %s\n", - cl->tightSubsampLevel, cl->host); + rfbLog("Using JPEG subsampling %d for Client %d (%s)\n", + cl->tightSubsampLevel, cl->id, cl->host); } else if (enc >= (CARD32)rfbEncodingQualityLevel0 && enc <= (CARD32)rfbEncodingQualityLevel9) { cl->tightQualityLevel = JPEG_QUAL[enc & 0x0F]; cl->tightSubsampLevel = JPEG_SUBSAMP[enc & 0x0F]; cl->imageQualityLevel = enc & 0x0F; if (cl->preferredEncoding == rfbEncodingTight) - rfbLog("Using JPEG subsampling %d, Q%d for client %s\n", - cl->tightSubsampLevel, cl->tightQualityLevel, cl->host); + rfbLog("Using JPEG subsampling %d, Q%d for Client %d (%s)\n", + cl->tightSubsampLevel, cl->tightQualityLevel, cl->id, + cl->host); else - rfbLog("Using image quality level %d for client %s\n", - cl->imageQualityLevel, cl->host); + rfbLog("Using image quality level %d for Client %d (%s)\n", + cl->imageQualityLevel, cl->id, cl->host); } else if (enc >= (CARD32)rfbEncodingFineQualityLevel0 + 1 && enc <= (CARD32)rfbEncodingFineQualityLevel100) { cl->tightQualityLevel = enc & 0xFF; - rfbLog("Using JPEG quality %d for client %s\n", - cl->tightQualityLevel, cl->host); + rfbLog("Using JPEG quality %d for Client %d (%s)\n", + cl->tightQualityLevel, cl->id, cl->host); } else { rfbLog("rfbProcessClientNormalMessage: ignoring unknown encoding %d (%x)\n", (int)enc, (int)enc); @@ -1145,11 +1171,12 @@ static void rfbProcessClientNormalMessage(rfbClientPtr cl) cl->preferredEncoding = rfbEncodingTight; if (cl->preferredEncoding == rfbEncodingTight && logTightCompressLevel) - rfbLog("Using Tight compression level %d for client %s\n", - rfbTightCompressLevel(cl), cl->host); + rfbLog("Using Tight compression level %d for Client %d (%s)\n", + rfbTightCompressLevel(cl), cl->id, cl->host); if (cl->enableCursorPosUpdates && !cl->enableCursorShapeUpdates) { - rfbLog("Disabling cursor position updates for client %s\n", cl->host); + rfbLog("Disabling cursor position updates for Client %d (%s)\n", + cl->id, cl->host); cl->enableCursorPosUpdates = FALSE; } diff --git a/unix/Xvnc/programs/Xserver/hw/vnc/sockets.c b/unix/Xvnc/programs/Xserver/hw/vnc/sockets.c index 247492a11..92ed8558e 100644 --- a/unix/Xvnc/programs/Xserver/hw/vnc/sockets.c +++ b/unix/Xvnc/programs/Xserver/hw/vnc/sockets.c @@ -18,7 +18,7 @@ * not EWOULDBLOCK. */ -/* Copyright (C) 2012-2020, 2022 D. R. Commander. All Rights Reserved. +/* Copyright (C) 2012-2020, 2022, 2024 D. R. Commander. All Rights Reserved. * Copyright (C) 2021 Steffen Kieß * Copyright (C) 2011 Joel Martin * Copyright (C) 2011 Gernot Tenchio @@ -171,7 +171,7 @@ static void rfbSockNotify(int fd, int ready, void *data) socklen_t addrlen = sizeof(struct sockaddr_storage); char addrStr[INET6_ADDRSTRLEN]; const int one = 1; - int sock, numClientConnections = 0; + int sock; rfbClientPtr cl, nextCl; if (rfbListenSock != -1 && fd == rfbListenSock) { @@ -209,9 +209,7 @@ static void rfbSockNotify(int fd, int ready, void *data) } #endif - for (cl = rfbClientHead; cl; cl = cl->next) - numClientConnections++; - if (numClientConnections >= rfbMaxClientConnections) { + if (rfbClientCount() >= rfbMaxClientConnections) { rfbClientRec tempCl; rfbProtocolVersionMsg pv; const char *errMsg = "Connection limit reached"; @@ -236,7 +234,7 @@ static void rfbSockNotify(int fd, int ready, void *data) return; } - rfbLog("Got connection from client %s\n", + rfbLog("Got connection from client (%s)\n", sockaddr_string(&addr, addrStr, INET6_ADDRSTRLEN)); SetNotifyFd(sock, rfbSockNotify, X_NOTIFY_READ, NULL); @@ -317,6 +315,10 @@ void rfbCloseClient(rfbClientPtr cl) { int sock = cl->sock; + /* Reuse the client number if initialization failed. */ + if (cl->state < RFB_NORMAL) + rfbClientNumber--; + #if USETLS if (cl->sslctx) { shutdown(sock, SHUT_RDWR); diff --git a/unix/Xvnc/programs/Xserver/hw/vnc/translate.c b/unix/Xvnc/programs/Xserver/hw/vnc/translate.c index 0293f661b..a6415d013 100644 --- a/unix/Xvnc/programs/Xserver/hw/vnc/translate.c +++ b/unix/Xvnc/programs/Xserver/hw/vnc/translate.c @@ -2,7 +2,7 @@ * translate.c - translate between different pixel formats */ -/* Copyright (C) 2017, 2022 D. R. Commander. All Rights Reserved. +/* Copyright (C) 2017, 2022, 2024 D. R. Commander. All Rights Reserved. * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. * * This is free software; you can redistribute it and/or modify @@ -178,7 +178,7 @@ void rfbTranslateNone(char *table, rfbPixelFormat *in, rfbPixelFormat *out, Bool rfbSetTranslateFunction(rfbClientPtr cl) { - rfbLog("Pixel format for client %s:\n", cl->host); + rfbLog("Pixel format for Client %d (%s):\n", cl->id, cl->host); PrintPixelFormat(&cl->format); /*