[Pkg-tigervnc-devel] Some patches for tigervnc 1.1.0 (window resize and unix socket support)

Petter Reinholdtsen pere at hungry.com
Thu May 23 20:19:16 UTC 2013


Hi.

At work we are looking at using xrdp and tigervnc, and got a few
patches we use to make the system more useful.  The patches were not
created by me, but my college Dag-Erling Smørgrav, and I do not really
know the inner working of any of the software involved.  CC to him.

I asked Mike Gabriel what I should do with the patches, and I
suggested I post them here.  The two tigervnc patches are attached.  I
am not quite sure what the patches do, but here is some guesswork:

  tigervnc11-resize.patch

    Improve handling of window resize events.

  tigervnc11-unixsocket.patch

    Add support for talking with tigervnc using unix socket instead of
    IP, and thus removing the need to provide a password when
    connecting to a VNC sessoin on the local host.

-- 
Happy hacking
Petter Reinholdtsen
-------------- next part --------------
--- tigervnc-1.1.0.orig/common/network/CMakeLists.txt	2011-08-09 23:16:40.000000000 +0200
+++ tigervnc-1.1.0/common/network/CMakeLists.txt	2012-10-06 20:50:22.323954919 +0200
@@ -1,4 +1,5 @@
 include_directories(${CMAKE_SOURCE_DIR}/common)
 
 add_library(network STATIC
-  TcpSocket.cxx)
+  TcpSocket.cxx
+  UnixSocket.cxx)
--- tigervnc-1.1.0.orig/common/network/Makefile.am	2011-08-09 23:16:40.000000000 +0200
+++ tigervnc-1.1.0/common/network/Makefile.am	2012-10-06 20:50:22.323954919 +0200
@@ -2,7 +2,7 @@
 
 HDRS = Socket.h TcpSocket.h
 
-libnetwork_la_SOURCES = $(HDRS) TcpSocket.cxx
+libnetwork_la_SOURCES = $(HDRS) TcpSocket.cxx UnixSocket.cxx
 
 libnetwork_la_CPPFLAGS = -I$(top_srcdir)/common
 
--- tigervnc-1.1.0.orig/common/network/Socket.h	2011-08-09 23:16:40.000000000 +0200
+++ tigervnc-1.1.0/common/network/Socket.h	2012-10-06 20:50:22.324954919 +0200
@@ -95,6 +95,8 @@
     // if one is installed.  Otherwise, returns 0.
     virtual Socket* accept() = 0;
 
+    virtual int getMyPort() = 0;
+
     // setFilter() applies the specified filter to all new connections
     void setFilter(ConnectionFilter* f) {filter = f;}
     int getFd() {return fd;}
--- /dev/null	2012-09-20 14:39:17.551000000 +0200
+++ tigervnc-1.1.0/common/network/UnixSocket.cxx	2012-10-06 22:30:17.171973531 +0200
@@ -0,0 +1,233 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (c) 2012 University of Oslo.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <fcntl.h>
+
+#include <stdlib.h>
+#include <network/UnixSocket.h>
+#include <os/net.h>
+#include <rfb/util.h>
+#include <rfb/LogWriter.h>
+
+using namespace network;
+using namespace rdr;
+
+static rfb::LogWriter vlog("UnixSocket");
+
+// -=- Socket initialisation
+static bool socketsInitialised = false;
+static void initSockets() {
+  if (socketsInitialised)
+    return;
+  signal(SIGPIPE, SIG_IGN);
+  socketsInitialised = true;
+}
+
+
+// -=- UnixSocket
+
+UnixSocket::UnixSocket(int sock, bool close)
+  : Socket(new FdInStream(sock), new FdOutStream(sock), true), closeFd(close)
+{
+}
+
+UnixSocket::UnixSocket(const char *path)
+  : closeFd(true)
+{
+  int sock, err, result;
+  sockaddr_un addr;
+  socklen_t salen;
+
+  if (strlen(path) >= sizeof(addr.sun_path))
+    throw SocketException("socket path is too long", ENAMETOOLONG);
+
+  // - Create a socket
+  initSockets();
+  sock = socket(AF_UNIX, SOCK_STREAM, 0);
+  if (sock == -1)
+    throw SocketException("unable to create socket", errno);
+
+  // - Attempt to connect
+  memset(&addr, 0, sizeof(addr));
+  addr.sun_family = AF_UNIX;
+  strcpy(addr.sun_path, path);
+  salen = sizeof(addr);
+  while ((result = connect(sock, (sockaddr *)&addr, salen)) == -1) {
+    err = errno;
+    close(sock);
+    break;
+  }
+
+  if (result == -1)
+    throw SocketException("unable connect to socket", err);
+
+  // - By default, close the socket on exec()
+  fcntl(sock, F_SETFD, FD_CLOEXEC);
+
+  // Create the input and output streams
+  instream = new FdInStream(sock);
+  outstream = new FdOutStream(sock);
+  ownStreams = true;
+}
+
+UnixSocket::~UnixSocket() {
+  if (closeFd)
+    close(getFd());
+}
+
+int UnixSocket::getMyPort() {
+  return 0;
+}
+
+char* UnixSocket::getPeerAddress() {
+  struct sockaddr_un addr;
+  socklen_t salen = sizeof(addr);
+
+  if (getpeername(getFd(), (struct sockaddr *)&addr, &salen) == 0)
+    return rfb::strDup(addr.sun_path);
+  else
+    return rfb::strDup("");
+}
+
+int UnixSocket::getPeerPort() {
+  return 0;
+}
+
+char* UnixSocket::getPeerEndpoint() {
+  return getPeerAddress();
+}
+
+bool UnixSocket::sameMachine() {
+  return true;
+}
+
+void UnixSocket::shutdown()
+{
+  Socket::shutdown();
+  ::shutdown(getFd(), 2);
+}
+
+bool UnixSocket::isSocket(int sock)
+{
+  struct sockaddr_un addr;
+  socklen_t salen = sizeof(addr);
+  return getsockname(sock, (struct sockaddr *)&addr, &salen) >= 0;
+}
+
+bool UnixSocket::isConnected(int sock)
+{
+  struct sockaddr_un addr;
+  socklen_t salen = sizeof(addr);
+  return getpeername(sock, (struct sockaddr *)&addr, &salen) >= 0;
+}
+
+UnixListener::UnixListener(const char *path, int mode,
+			 int sock, bool close_) : closeFd(close_)
+{
+  struct sockaddr_un addr;
+  mode_t saved_umask;
+  int err, result;
+
+  if (sock != -1) {
+    fd = sock;
+    return;
+  }
+
+  if (strlen(path) >= sizeof(addr.sun_path))
+    throw SocketException("socket path is too long", ENAMETOOLONG);
+
+  // - Create a socket
+  initSockets();
+  if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+    throw SocketException("unable to create listening socket", errno);
+
+  // - By default, close the socket on exec()
+  fcntl(sock, F_SETFD, FD_CLOEXEC);
+
+  // - Delete existing socket (ignore result)
+  unlink(path);
+
+  // - Attempt to bind to the requested path
+  memset(&addr, 0, sizeof(addr));
+  addr.sun_family = AF_UNIX;
+  strcpy(addr.sun_path, path);
+  saved_umask = umask(0777);
+  result = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
+  err = errno;
+  umask(saved_umask);
+  if (result < 0) {
+    close(fd);
+    throw SocketException("unable to bind listening socket", err);
+  }
+
+  // - Set socket mode
+  if (chmod(path, mode) < 0) {
+    err = errno;
+    close(fd);
+    throw SocketException("unable to set socket mode", err);
+  }
+
+  // - Set it to be a listening socket
+  if (listen(fd, 5) < 0) {
+    err = errno;
+    close(fd);
+    throw SocketException("unable to set socket to listening mode", err);
+  }
+}
+
+UnixListener::~UnixListener() {
+  if (closeFd) close(fd);
+}
+
+void UnixListener::shutdown()
+{
+  ::shutdown(getFd(), 2);
+}
+
+
+Socket*
+UnixListener::accept() {
+  int new_sock = -1;
+
+  // Accept an incoming connection
+  if ((new_sock = ::accept(fd, 0, 0)) < 0)
+    throw SocketException("unable to accept new connection", errno);
+
+  // - By default, close the socket on exec()
+  fcntl(new_sock, F_SETFD, FD_CLOEXEC);
+
+  // - Create the socket object
+  return new UnixSocket(new_sock);
+}
+
+int UnixListener::getMyPort() {
+  return 0;
+}
--- /dev/null	2012-09-20 14:39:17.551000000 +0200
+++ tigervnc-1.1.0/common/network/UnixSocket.h	2012-10-06 20:50:22.325954919 +0200
@@ -0,0 +1,76 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (c) 2012 University of Oslo.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+// -=- UnixSocket.h - base-class for UNIX stream sockets.
+//     This header also defines the UnixListener class, used
+//     to listen for incoming socket connections over UNIX
+//
+//     NB: Any file descriptors created by the UnixSocket or
+//     UnixListener classes are close-on-exec if the OS supports
+//     it.  UnixSockets initialised with a caller-supplied fd
+//     are NOT set to close-on-exec.
+
+#ifndef __NETWORK_UNIX_SOCKET_H__
+#define __NETWORK_UNIX_SOCKET_H__
+
+#include <network/Socket.h>
+
+#include <list>
+
+namespace network {
+
+   class UnixSocket : public Socket {
+  public:
+    UnixSocket(int sock, bool close=true);
+    UnixSocket(const char *name);
+    virtual ~UnixSocket();
+
+    virtual int getMyPort();
+
+    virtual char* getPeerAddress();
+    virtual int getPeerPort();
+    virtual char* getPeerEndpoint();
+    virtual bool sameMachine();
+
+    virtual void shutdown();
+
+    static bool isSocket(int sock);
+    static bool isConnected(int sock);
+  private:
+    bool closeFd;
+  };
+
+  class UnixListener : public SocketListener {
+  public:
+    UnixListener(const char *listenaddr, int mode,
+		int sock=-1, bool close=true);
+    virtual ~UnixListener();
+
+    virtual void shutdown();
+    virtual Socket* accept();
+
+    int getMyPort();
+
+  private:
+    bool closeFd;
+  };
+
+}
+
+#endif // __NETWORK_UNIX_SOCKET_H__
--- tigervnc-1.1.0.orig/common/rfb/Configuration.cxx	2011-08-09 23:16:44.000000000 +0200
+++ tigervnc-1.1.0/common/rfb/Configuration.cxx	2012-10-06 20:50:22.326954919 +0200
@@ -368,7 +368,7 @@
 IntParameter::setParam(const char* v) {
   if (immutable) return true;
   vlog.debug("set %s(Int) to %s", getName(), v);
-  int i = atoi(v);
+  int i = strtol(v, NULL, 0);
   if (i < minValue || i > maxValue)
     return false;
   value = i;
--- tigervnc-1.1.0.orig/unix/vncviewer/CConn.cxx	2012-10-06 16:35:40.773469213 +0200
+++ tigervnc-1.1.0/unix/vncviewer/CConn.cxx	2012-10-06 20:50:22.327954919 +0200
@@ -36,6 +36,9 @@
 #include <rfb/Password.h>
 #include <rfb/screenTypes.h>
 #include <network/TcpSocket.h>
+#ifndef WIN32
+#include <network/UnixSocket.h>
+#endif
 #include <cassert>
 #include <list>
 #include <string>
@@ -101,6 +104,12 @@
     char* name = sock->getPeerEndpoint();
     vlog.info("Accepted connection from %s", name);
     if (name) free(name);
+#ifndef WIN32
+  } else if (vncServerName && strchr(vncServerName, '/') != NULL) {
+    sock = new network::UnixSocket(vncServerName);
+    serverHost = sock->getPeerAddress();
+    vlog.info("connected to socket %s", serverHost);
+#endif
   } else {
     if (vncServerName) {
       getHostAndPort(vncServerName, &serverHost, &serverPort);
--- tigervnc-1.1.0.orig/unix/xserver/hw/vnc/vncExtInit.cc	2012-10-06 16:35:40.890469244 +0200
+++ tigervnc-1.1.0/unix/xserver/hw/vnc/vncExtInit.cc	2012-10-06 20:50:22.328954919 +0200
@@ -52,6 +52,9 @@
 #undef max
 #undef min
 #include <network/TcpSocket.h>
+#ifndef WIN32
+#include <network/UnixSocket.h>
+#endif
 
 #include "XserverDesktop.h"
 #include "vncHooks.h"
@@ -118,6 +121,10 @@
 rfb::AliasParameter rfbwait("rfbwait", "Alias for ClientWaitTimeMillis",
                             &rfb::Server::clientWaitTimeMillis);
 rfb::IntParameter rfbport("rfbport", "TCP port to listen for RFB protocol",0);
+#ifndef WIN32
+rfb::StringParameter rfbpath("rfbpath", "Unix socket to listen for RFB protocol", "");
+rfb::IntParameter rfbmode("rfbmode", "Unix socket access mode",0600);
+#endif
 rfb::StringParameter desktopName("desktop", "Name of VNC desktop","x11");
 rfb::BoolParameter localhostOnly("localhost",
                                  "Only allow connections from localhost",
@@ -217,7 +224,7 @@
     for (int scr = 0; scr < screenInfo.numScreens; scr++) {
 
       if (!desktop[scr]) {
-        network::TcpListener* listener = 0;
+        network::SocketListener* listener = 0;
         network::TcpListener* httpListener = 0;
         if (scr == 0 && vncInetdSock != -1) {
           if (network::TcpSocket::isSocket(vncInetdSock) &&
@@ -226,9 +233,17 @@
             listener = new network::TcpListener(NULL, 0, 0, vncInetdSock, true);
             vlog.info("inetd wait");
           }
+#ifndef WIN32
+	} else if (rfbpath.getValueStr()[0] != '\0') {
+	  const char *path = rfbpath.getValueStr();
+	  int mode = (int)rfbmode;
+	  vlog.info("using Unix domain socket %s (mode %04o)", path, mode);
+	  listener = new network::UnixListener(path, mode);
+#endif
         } else {
           int port = rfbport;
           if (port == 0) port = 5900 + atoi(display);
+	  vlog.info("using TCP socket on port %d", port);
           port += 1000 * scr;
           listener = new network::TcpListener(listenaddr, port, localhostOnly);
           vlog.info("Listening for VNC connections on %s interface(s), port %d",
--- tigervnc-1.1.0.orig/unix/xserver/hw/vnc/XserverDesktop.cc	2011-08-09 23:16:36.000000000 +0200
+++ tigervnc-1.1.0/unix/xserver/hw/vnc/XserverDesktop.cc	2012-10-06 20:50:22.329954919 +0200
@@ -33,7 +33,7 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <sys/utsname.h>
-#include <network/TcpSocket.h>
+#include <network/Socket.h>
 #include <rfb/Exception.h>
 #include <rfb/VNCServerST.h>
 #include <rfb/HTTPServer.h>
@@ -141,8 +141,8 @@
 
 
 XserverDesktop::XserverDesktop(ScreenPtr pScreen_,
-                               network::TcpListener* listener_,
-                               network::TcpListener* httpListener_,
+                               network::SocketListener* listener_,
+                               network::SocketListener* httpListener_,
                                const char* name, const rfb::PixelFormat &pf,
                                void* fbptr, int stride)
   : pScreen(pScreen_), deferredUpdateTimer(0), dummyTimer(0),
--- tigervnc-1.1.0.orig/unix/xserver/hw/vnc/XserverDesktop.h	2011-08-09 23:16:36.000000000 +0200
+++ tigervnc-1.1.0/unix/xserver/hw/vnc/XserverDesktop.h	2012-10-06 20:50:22.329954919 +0200
@@ -45,15 +45,15 @@
   class VNCServerST;
 }
 
-namespace network { class TcpListener; class Socket; }
+namespace network { class SocketListener; class Socket; }
 
 class XserverDesktop : public rfb::SDesktop, public rfb::FullFramePixelBuffer,
                        public rfb::ColourMap, public rdr::Substitutor,
                        public rfb::VNCServerST::QueryConnectionHandler {
 public:
 
-  XserverDesktop(ScreenPtr pScreen, network::TcpListener* listener,
-                 network::TcpListener* httpListener_,
+  XserverDesktop(ScreenPtr pScreen, network::SocketListener* listener,
+                 network::SocketListener* httpListener_,
                  const char* name, const rfb::PixelFormat &pf,
                  void* fbptr, int stride);
   virtual ~XserverDesktop();
@@ -126,8 +126,8 @@
   OsTimerPtr deferredUpdateTimer, dummyTimer;
   rfb::VNCServerST* server;
   rfb::HTTPServer* httpServer;
-  network::TcpListener* listener;
-  network::TcpListener* httpListener;
+  network::SocketListener* listener;
+  network::SocketListener* httpListener;
   ColormapPtr cmap;
   int stride_;
   bool deferredUpdateTimerSet;
--- tigervnc-1.1.0.orig/unix/xserver/hw/vnc/Xvnc.man	2011-08-09 23:16:36.000000000 +0200
+++ tigervnc-1.1.0/unix/xserver/hw/vnc/Xvnc.man	2012-10-06 20:50:22.330954919 +0200
@@ -92,6 +92,15 @@
 5900 plus the display number.
 
 .TP
+.B \-rfbpath \fIpath\fP
+Specifies the path of a Unix domain socket on which Xvnc listens for
+connections from viewers, instead of listening on a TCP port.
+
+.TP
+.B \-rfbmode \fImode\fP
+Specifies the mode of the Unix domain socket.  The default is 0600.
+
+.TP
 .B \-rfbwait \fItime\fP, \-ClientWaitTimeMillis \fItime\fP
 
 Time in milliseconds to wait for a viewer which is blocking Xvnc.  This is
-------------- next part --------------
--- tigervnc-1.1.0.orig/common/rfb/ConnParams.h	2011-08-09 23:16:44.000000000 +0200
+++ tigervnc-1.1.0/common/rfb/ConnParams.h	2012-10-07 16:30:24.259701593 +0200
@@ -77,6 +77,7 @@
     bool supportsExtendedDesktopSize;
     bool supportsDesktopRename;
     bool supportsLastRect;
+    bool encodingsChanged;
 
     bool supportsSetDesktopSize;
 
--- tigervnc-1.1.0.orig/common/rfb/ConnParams.cxx	2011-08-09 23:16:44.000000000 +0200
+++ tigervnc-1.1.0/common/rfb/ConnParams.cxx	2012-10-07 16:30:24.260701593 +0200
@@ -32,7 +32,7 @@
     supportsLocalCursor(false), supportsLocalXCursor(false),
     supportsDesktopResize(false), supportsExtendedDesktopSize(false),
     supportsDesktopRename(false), supportsLastRect(false),
-    supportsSetDesktopSize(false),
+    supportsSetDesktopSize(false), encodingsChanged(false),
     customCompressLevel(false), compressLevel(6),
     noJpeg(false), qualityLevel(-1), 
     name_(0), nEncodings_(0), encodings_(0),
@@ -132,4 +132,6 @@
     } else if (Encoder::supported(encodings[i]))
       currentEncoding_ = encodings[i];
   }
+
+  encodingsChanged = true;
 }
--- tigervnc-1.1.0.orig/common/rfb/VNCSConnectionST.cxx	2011-08-09 23:16:44.000000000 +0200
+++ tigervnc-1.1.0/common/rfb/VNCSConnectionST.cxx	2012-10-07 16:38:03.453764411 +0200
@@ -117,11 +117,24 @@
       processMsg();
     }
 
+    // If the client sent new encodings and now appears to support
+    // resizing the desktop, immediately fake a desktop resizing event in
+    // case a real one occurred before we knew the client supported them.
+    if (cp.encodingsChanged) {
+      cp.encodingsChanged = false;
+      if (writer()->writeExtendedDesktopSize() ||
+          writer()->writeSetDesktopSize()) {
+        vlog.info("encodings changed, forcing desktop resize");
+        updates.clear();
+        updates.add_changed(server->pb->getRect());
+      }
+    }
+
     // If there were update requests, try to send a framebuffer update.
     // We don't send updates immediately on requests as this way, we
     // give higher priority to user actions such as keyboard and
     // pointer events.
-    if (!requested.is_empty()) {
+    if (writer()->needFakeUpdate() || !requested.is_empty()) {
       writeFramebufferUpdate();
     }
 
@@ -150,6 +163,8 @@
     if (cp.width && cp.height && (server->pb->width() != cp.width ||
                                   server->pb->height() != cp.height))
     {
+      vlog.info("desktop resized from %dx%d to %dx%d", cp.width, cp.height,
+		server->pb->width(), server->pb->height());
       // We need to clip the next update to the new size, but also add any
       // extra bits if it's bigger.  If we wanted to do this exactly, something
       // like the code below would do it, but at the moment we just update the
@@ -174,8 +189,7 @@
         // We should only send EDS to client asking for both
         if (!writer()->writeExtendedDesktopSize()) {
           if (!writer()->writeSetDesktopSize()) {
-            close("Client does not support desktop resize");
-            return;
+            vlog.info("Client does not support desktop resize");
           }
         }
       }
@@ -506,6 +520,11 @@
 
   if (!(accessRights & AccessView)) return;
 
+  if (!incremental) {
+    vlog.debug("full framebuffer update request: %dx%d+%d+%d",
+	       r.width(), r.height(), r.tl.x, r.tl.y);
+  }
+
   SConnection::framebufferUpdateRequest(r, incremental);
 
   // Check that the client isn't sending crappy requests


More information about the Pkg-tigervnc-devel mailing list