[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