Merge branch 'unix' of https://github.com/CendioOssman/tigervnc
diff --git a/common/network/CMakeLists.txt b/common/network/CMakeLists.txt
index b624c8e..d00ca45 100644
--- a/common/network/CMakeLists.txt
+++ b/common/network/CMakeLists.txt
@@ -1,8 +1,15 @@
 include_directories(${CMAKE_SOURCE_DIR}/common)
 
-add_library(network STATIC
+set(NETWORK_SOURCES
+  Socket.cxx
   TcpSocket.cxx)
 
+if(NOT WIN32)
+  set(NETWORK_SOURCES ${NETWORK_SOURCES} UnixSocket.cxx)
+endif()
+
+add_library(network STATIC ${NETWORK_SOURCES})
+
 if(WIN32)
 	target_link_libraries(network ws2_32)
 endif()
diff --git a/common/network/Socket.cxx b/common/network/Socket.cxx
new file mode 100644
index 0000000..9dd8bfe
--- /dev/null
+++ b/common/network/Socket.cxx
@@ -0,0 +1,183 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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
+
+#ifdef WIN32
+//#include <io.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#define errorNumber WSAGetLastError()
+#else
+#define errorNumber errno
+#define closesocket close
+#include <sys/socket.h>
+#endif
+
+#include <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <network/Socket.h>
+
+using namespace network;
+
+// -=- Socket initialisation
+static bool socketsInitialised = false;
+void network::initSockets() {
+  if (socketsInitialised)
+    return;
+#ifdef WIN32
+  WORD requiredVersion = MAKEWORD(2,0);
+  WSADATA initResult;
+  
+  if (WSAStartup(requiredVersion, &initResult) != 0)
+    throw SocketException("unable to initialise Winsock2", errorNumber);
+#else
+  signal(SIGPIPE, SIG_IGN);
+#endif
+  socketsInitialised = true;
+}
+
+bool network::isSocketListening(int sock)
+{
+  int listening = 0;
+  socklen_t listening_size = sizeof(listening);
+  if (getsockopt(sock, SOL_SOCKET, SO_ACCEPTCONN,
+                 (char *)&listening, &listening_size) < 0)
+    return false;
+  return listening != 0;
+}
+
+Socket::Socket(int fd)
+  : instream(0), outstream(0),
+    isShutdown_(false), queryConnection(false)
+{
+  initSockets();
+  setFd(fd);
+}
+
+Socket::Socket()
+  : instream(0), outstream(0),
+    isShutdown_(false), queryConnection(false)
+{
+  initSockets();
+}
+
+Socket::~Socket()
+{
+  if (instream && outstream)
+    closesocket(getFd());
+  delete instream;
+  delete outstream;
+}
+
+// if shutdown() is overridden then the override MUST call on to here
+void Socket::shutdown()
+{
+  isShutdown_ = true;
+  ::shutdown(getFd(), 2);
+}
+
+bool Socket::isShutdown() const
+{
+  return isShutdown_;
+}
+
+// Was there a "?" in the ConnectionFilter used to accept this Socket?
+void Socket::setRequiresQuery()
+{
+  queryConnection = true;
+}
+
+bool Socket::requiresQuery() const
+{
+  return queryConnection;
+}
+
+void Socket::setFd(int fd)
+{
+#ifndef WIN32
+  // - By default, close the socket on exec()
+  fcntl(fd, F_SETFD, FD_CLOEXEC);
+#endif
+
+  instream = new rdr::FdInStream(fd);
+  outstream = new rdr::FdOutStream(fd);
+  isShutdown_ = false;
+}
+
+SocketListener::SocketListener(int fd)
+  : fd(fd), filter(0)
+{
+  initSockets();
+}
+
+SocketListener::SocketListener()
+  : fd(-1), filter(0)
+{
+  initSockets();
+}
+
+SocketListener::~SocketListener()
+{
+  if (fd != -1)
+    closesocket(fd);
+}
+
+void SocketListener::shutdown()
+{
+#ifdef WIN32
+  closesocket(fd);
+  fd = -1;
+#else
+  ::shutdown(fd, 2);
+#endif
+}
+
+Socket* SocketListener::accept() {
+  int new_sock = -1;
+
+  // Accept an incoming connection
+  if ((new_sock = ::accept(fd, 0, 0)) < 0)
+    throw SocketException("unable to accept new connection", errorNumber);
+
+  // Create the socket object & check connection is allowed
+  Socket* s = createSocket(new_sock);
+  if (filter && !filter->verifyConnection(s)) {
+    delete s;
+    return NULL;
+  }
+
+  return s;
+}
+
+void SocketListener::listen(int sock)
+{
+  // - Set it to be a listening socket
+  if (::listen(sock, 5) < 0) {
+    int e = errorNumber;
+    closesocket(sock);
+    throw SocketException("unable to set socket to listening mode", e);
+  }
+
+  fd = sock;
+}
diff --git a/common/network/Socket.h b/common/network/Socket.h
index 7a30cac..bfda8a5 100644
--- a/common/network/Socket.h
+++ b/common/network/Socket.h
@@ -30,52 +30,40 @@
 
 namespace network {
 
+  void initSockets();
+
+  bool isSocketListening(int sock);
+
   class Socket {
   public:
-    Socket(int fd)
-      : instream(new rdr::FdInStream(fd)),
-      outstream(new rdr::FdOutStream(fd)),
-      ownStreams(true), isShutdown_(false),
-      queryConnection(false) {}
-    virtual ~Socket() {
-      if (ownStreams) {
-        delete instream;
-        delete outstream;
-      }
-    }
+    Socket(int fd);
+    virtual ~Socket();
+
     rdr::FdInStream &inStream() {return *instream;}
     rdr::FdOutStream &outStream() {return *outstream;}
     int getFd() {return outstream->getFd();}
 
-    // if shutdown() is overridden then the override MUST call on to here
-    virtual void shutdown() {isShutdown_ = true;}
-    bool isShutdown() const {return isShutdown_;}
-    virtual bool cork(bool enable) = 0;
+    void shutdown();
+    bool isShutdown() const;
 
-    // information about this end of the socket
-    virtual int getMyPort() = 0;
+    virtual bool cork(bool enable) = 0;
 
     // information about the remote end of the socket
     virtual char* getPeerAddress() = 0; // a string e.g. "192.168.0.1"
-    virtual int getPeerPort() = 0;
     virtual char* getPeerEndpoint() = 0; // <address>::<port>
 
-    // Is the remote end on the same machine?
-    virtual bool sameMachine() = 0;
-
     // Was there a "?" in the ConnectionFilter used to accept this Socket?
-    void setRequiresQuery() {queryConnection = true;}
-    bool requiresQuery() const {return queryConnection;}
+    void setRequiresQuery();
+    bool requiresQuery() const;
 
   protected:
-    Socket() : instream(0), outstream(0), ownStreams(false),
-      isShutdown_(false), queryConnection(false) {}
-    Socket(rdr::FdInStream* i, rdr::FdOutStream* o, bool own)
-      : instream(i), outstream(o), ownStreams(own),
-      isShutdown_(false), queryConnection(false) {}
+    Socket();
+
+    void setFd(int fd);
+
+  private:
     rdr::FdInStream* instream;
     rdr::FdOutStream* outstream;
-    bool ownStreams;
     bool isShutdown_;
     bool queryConnection;
   };
@@ -88,20 +76,32 @@
 
   class SocketListener {
   public:
-    SocketListener() : fd(0), filter(0) {}
-    virtual ~SocketListener() {}
+    SocketListener(int fd);
+    virtual ~SocketListener();
 
     // shutdown() stops the socket from accepting further connections
-    virtual void shutdown() = 0;
+    void shutdown();
 
     // accept() returns a new Socket object if there is a connection
     // attempt in progress AND if the connection passes the filter
     // if one is installed.  Otherwise, returns 0.
-    virtual Socket* accept() = 0;
+    Socket* accept();
+
+    virtual int getMyPort() = 0;
 
     // setFilter() applies the specified filter to all new connections
     void setFilter(ConnectionFilter* f) {filter = f;}
     int getFd() {return fd;}
+
+  protected:
+    SocketListener();
+
+    void listen(int fd);
+
+    // createSocket() should create a new socket of the correct class
+    // for the given file descriptor
+    virtual Socket* createSocket(int fd) = 0;
+
   protected:
     int fd;
     ConnectionFilter* filter;
diff --git a/common/network/TcpSocket.cxx b/common/network/TcpSocket.cxx
index 9603c38..51d77c7 100644
--- a/common/network/TcpSocket.cxx
+++ b/common/network/TcpSocket.cxx
@@ -28,21 +28,17 @@
 #else
 #define errorNumber errno
 #define closesocket close
-#include <sys/types.h>
 #include <sys/socket.h>
 #include <arpa/inet.h>
 #include <netinet/tcp.h>
 #include <netdb.h>
 #include <errno.h>
-#include <string.h>
-#include <signal.h>
-#include <fcntl.h>
 #endif
 
 #include <stdlib.h>
 #include <unistd.h>
+
 #include <network/TcpSocket.h>
-#include <rfb/util.h>
 #include <rfb/LogWriter.h>
 #include <rfb/Configuration.h>
 
@@ -99,40 +95,35 @@
   return ntohs(addr.sin_port);
 }
 
+int network::getSockPort(int sock)
+{
+  vnc_sockaddr_t sa;
+  socklen_t sa_size = sizeof(sa);
+  if (getsockname(sock, &sa.u.sa, &sa_size) < 0)
+    return 0;
 
-// -=- Socket initialisation
-static bool socketsInitialised = false;
-static void initSockets() {
-  if (socketsInitialised)
-    return;
-#ifdef WIN32
-  WORD requiredVersion = MAKEWORD(2,0);
-  WSADATA initResult;
-  
-  if (WSAStartup(requiredVersion, &initResult) != 0)
-    throw SocketException("unable to initialise Winsock2", errorNumber);
-#else
-  signal(SIGPIPE, SIG_IGN);
-#endif
-  socketsInitialised = true;
+  switch (sa.u.sa.sa_family) {
+  case AF_INET6:
+    return ntohs(sa.u.sin6.sin6_port);
+  default:
+    return ntohs(sa.u.sin.sin_port);
+  }
 }
 
-
 // -=- TcpSocket
 
-TcpSocket::TcpSocket(int sock, bool close)
-  : Socket(new FdInStream(sock), new FdOutStream(sock), true), closeFd(close)
+TcpSocket::TcpSocket(int sock) : Socket(sock)
 {
+  // Disable Nagle's algorithm, to reduce latency
+  enableNagles(false);
 }
 
 TcpSocket::TcpSocket(const char *host, int port)
-  : closeFd(true)
 {
   int sock, err, result;
   struct addrinfo *ai, *current, hints;
 
   // - Create a socket
-  initSockets();
 
   memset(&hints, 0, sizeof(struct addrinfo));
   hints.ai_family = AF_UNSPEC;
@@ -214,27 +205,11 @@
       throw SocketException("unable connect to socket", err);
   }
 
-#ifndef WIN32
-  // - By default, close the socket on exec()
-  fcntl(sock, F_SETFD, FD_CLOEXEC);
-#endif
+  // Take proper ownership of the socket
+  setFd(sock);
 
   // Disable Nagle's algorithm, to reduce latency
-  enableNagles(sock, false);
-
-  // Create the input and output streams
-  instream = new FdInStream(sock);
-  outstream = new FdOutStream(sock);
-  ownStreams = true;
-}
-
-TcpSocket::~TcpSocket() {
-  if (closeFd)
-    closesocket(getFd());
-}
-
-int TcpSocket::getMyPort() {
-  return getSockPort(getFd());
+  enableNagles(false);
 }
 
 char* TcpSocket::getPeerAddress() {
@@ -281,25 +256,20 @@
   return rfb::strDup("");
 }
 
-int TcpSocket::getPeerPort() {
+char* TcpSocket::getPeerEndpoint() {
+  rfb::CharArray address; address.buf = getPeerAddress();
   vnc_sockaddr_t sa;
   socklen_t sa_size = sizeof(sa);
+  int port;
 
   getpeername(getFd(), &sa.u.sa, &sa_size);
 
-  switch (sa.u.sa.sa_family) {
-  case AF_INET6:
-    return ntohs(sa.u.sin6.sin6_port);
-  case AF_INET:
-    return ntohs(sa.u.sin.sin_port);
-  default:
-    return 0;
-  }
-}
-
-char* TcpSocket::getPeerEndpoint() {
-  rfb::CharArray address; address.buf = getPeerAddress();
-  int port = getPeerPort();
+  if (sa.u.sa.sa_family == AF_INET6)
+    port = ntohs(sa.u.sin6.sin6_port);
+  else if (sa.u.sa.sa_family == AF_INET)
+    port = ntohs(sa.u.sin.sin_port);
+  else
+    port = 0;
 
   int buflen = strlen(address.buf) + 32;
   char* buffer = new char[buflen];
@@ -307,40 +277,9 @@
   return buffer;
 }
 
-bool TcpSocket::sameMachine() {
-  vnc_sockaddr_t peeraddr, myaddr;
-  socklen_t addrlen;
-
-  addrlen = sizeof(peeraddr);
-  if (getpeername(getFd(), &peeraddr.u.sa, &addrlen) < 0)
-      throw SocketException ("unable to get peer address", errorNumber);
-
-  addrlen = sizeof(myaddr); /* need to reset, since getpeername overwrote */
-  if (getsockname(getFd(), &myaddr.u.sa, &addrlen) < 0)
-      throw SocketException ("unable to get my address", errorNumber);
-
-  if (peeraddr.u.sa.sa_family != myaddr.u.sa.sa_family)
-      return false;
-
-  if (peeraddr.u.sa.sa_family == AF_INET6)
-      return IN6_ARE_ADDR_EQUAL(&peeraddr.u.sin6.sin6_addr,
-                                &myaddr.u.sin6.sin6_addr);
-  if (peeraddr.u.sa.sa_family == AF_INET)
-    return (peeraddr.u.sin.sin_addr.s_addr == myaddr.u.sin.sin_addr.s_addr);
-
-  // No idea what this is. Assume we're on different machines.
-  return false;
-}
-
-void TcpSocket::shutdown()
-{
-  Socket::shutdown();
-  ::shutdown(getFd(), 2);
-}
-
-bool TcpSocket::enableNagles(int sock, bool enable) {
+bool TcpSocket::enableNagles(bool enable) {
   int one = enable ? 0 : 1;
-  if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+  if (setsockopt(getFd(), IPPROTO_TCP, TCP_NODELAY,
                  (char *)&one, sizeof(one)) < 0) {
     int e = errorNumber;
     vlog.error("unable to setsockopt TCP_NODELAY: %d", e);
@@ -360,34 +299,8 @@
 #endif
 }
 
-bool TcpSocket::isListening(int sock)
+TcpListener::TcpListener(int sock) : SocketListener(sock)
 {
-  int listening = 0;
-  socklen_t listening_size = sizeof(listening);
-  if (getsockopt(sock, SOL_SOCKET, SO_ACCEPTCONN,
-                 (char *)&listening, &listening_size) < 0)
-    return false;
-  return listening != 0;
-}
-
-int TcpSocket::getSockPort(int sock)
-{
-  vnc_sockaddr_t sa;
-  socklen_t sa_size = sizeof(sa);
-  if (getsockname(sock, &sa.u.sa, &sa_size) < 0)
-    return 0;
-
-  switch (sa.u.sa.sa_family) {
-  case AF_INET6:
-    return ntohs(sa.u.sin6.sin6_port);
-  default:
-    return ntohs(sa.u.sin.sin_port);
-  }
-}
-
-TcpListener::TcpListener(int sock)
-{
-  fd = sock;
 }
 
 TcpListener::TcpListener(const struct sockaddr *listenaddr,
@@ -397,8 +310,6 @@
   vnc_sockaddr_t sa;
   int sock;
 
-  initSockets();
-
   if ((sock = socket (listenaddr->sa_family, SOCK_STREAM, 0)) < 0)
     throw SocketException("unable to create listening socket", errorNumber);
 
@@ -436,53 +347,11 @@
     throw SocketException("failed to bind socket", e);
   }
 
-  // - Set it to be a listening socket
-  if (listen(sock, 5) < 0) {
-    int e = errorNumber;
-    closesocket(sock);
-    throw SocketException("unable to set socket to listening mode", e);
-  }
-
-  fd = sock;
+  listen(sock);
 }
 
-TcpListener::~TcpListener() {
-  closesocket(fd);
-}
-
-void TcpListener::shutdown()
-{
-#ifdef WIN32
-  closesocket(getFd());
-#else
-  ::shutdown(getFd(), 2);
-#endif
-}
-
-
-Socket*
-TcpListener::accept() {
-  int new_sock = -1;
-
-  // Accept an incoming connection
-  if ((new_sock = ::accept(fd, 0, 0)) < 0)
-    throw SocketException("unable to accept new connection", errorNumber);
-
-#ifndef WIN32
-  // - By default, close the socket on exec()
-  fcntl(new_sock, F_SETFD, FD_CLOEXEC);
-#endif
-
-  // Disable Nagle's algorithm, to reduce latency
-  TcpSocket::enableNagles(new_sock, false);
-
-  // Create the socket object & check connection is allowed
-  TcpSocket* s = new TcpSocket(new_sock);
-  if (filter && !filter->verifyConnection(s)) {
-    delete s;
-    return 0;
-  }
-  return s;
+Socket* TcpListener::createSocket(int fd) {
+  return new TcpSocket(fd);
 }
 
 void TcpListener::getMyAddresses(std::list<char*>* result) {
@@ -528,11 +397,11 @@
 }
 
 int TcpListener::getMyPort() {
-  return TcpSocket::getSockPort(getFd());
+  return getSockPort(getFd());
 }
 
 
-void network::createLocalTcpListeners(std::list<TcpListener*> *listeners,
+void network::createLocalTcpListeners(std::list<SocketListener*> *listeners,
                                       int port)
 {
   struct addrinfo ai[2];
@@ -562,7 +431,7 @@
   createTcpListeners(listeners, ai);
 }
 
-void network::createTcpListeners(std::list<TcpListener*> *listeners,
+void network::createTcpListeners(std::list<SocketListener*> *listeners,
                                  const char *addr,
                                  int port)
 {
@@ -594,11 +463,11 @@
   }
 }
 
-void network::createTcpListeners(std::list<TcpListener*> *listeners,
+void network::createTcpListeners(std::list<SocketListener*> *listeners,
                                  const struct addrinfo *ai)
 {
   const struct addrinfo *current;
-  std::list<TcpListener*> new_listeners;
+  std::list<SocketListener*> new_listeners;
 
   initSockets();
 
diff --git a/common/network/TcpSocket.h b/common/network/TcpSocket.h
index c1b142f..eb6c095 100644
--- a/common/network/TcpSocket.h
+++ b/common/network/TcpSocket.h
@@ -48,48 +48,41 @@
   /* Tunnelling support. */
   int findFreeTcpPort (void);
 
+  int getSockPort(int sock);
+
   class TcpSocket : public Socket {
   public:
-    TcpSocket(int sock, bool close=true);
+    TcpSocket(int sock);
     TcpSocket(const char *name, int port);
-    virtual ~TcpSocket();
-
-    virtual int getMyPort();
 
     virtual char* getPeerAddress();
-    virtual int getPeerPort();
     virtual char* getPeerEndpoint();
-    virtual bool sameMachine();
 
-    virtual void shutdown();
     virtual bool cork(bool enable);
 
-    static bool enableNagles(int sock, bool enable);
-    static bool isListening(int sock);
-    static int getSockPort(int sock);
-  private:
-    bool closeFd;
+  protected:
+    bool enableNagles(bool enable);
   };
 
   class TcpListener : public SocketListener {
   public:
     TcpListener(const struct sockaddr *listenaddr, socklen_t listenaddrlen);
     TcpListener(int sock);
-    virtual ~TcpListener();
 
-    virtual void shutdown();
-    virtual Socket* accept();
+    virtual int getMyPort();
 
     static void getMyAddresses(std::list<char*>* result);
-    int getMyPort();
+
+  protected:
+    virtual Socket* createSocket(int fd);
   };
 
-  void createLocalTcpListeners(std::list<TcpListener*> *listeners,
+  void createLocalTcpListeners(std::list<SocketListener*> *listeners,
                                int port);
-  void createTcpListeners(std::list<TcpListener*> *listeners,
+  void createTcpListeners(std::list<SocketListener*> *listeners,
                           const char *addr,
                           int port);
-  void createTcpListeners(std::list<TcpListener*> *listeners,
+  void createTcpListeners(std::list<SocketListener*> *listeners,
                           const struct addrinfo *ai);
 
   typedef struct vnc_sockaddr {
diff --git a/common/network/UnixSocket.cxx b/common/network/UnixSocket.cxx
new file mode 100644
index 0000000..bfabc14
--- /dev/null
+++ b/common/network/UnixSocket.cxx
@@ -0,0 +1,171 @@
+/* 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/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+#include <network/UnixSocket.h>
+#include <rfb/LogWriter.h>
+
+using namespace network;
+using namespace rdr;
+
+static rfb::LogWriter vlog("UnixSocket");
+
+// -=- UnixSocket
+
+UnixSocket::UnixSocket(int sock) : Socket(sock)
+{
+}
+
+UnixSocket::UnixSocket(const char *path)
+{
+  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
+  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);
+
+  setFd(sock);
+}
+
+char* UnixSocket::getPeerAddress() {
+  struct sockaddr_un addr;
+  socklen_t salen;
+
+  // AF_UNIX only has a single address (the server side).
+  // Unfortunately we don't know which end we are, so we'll have to
+  // test a bit.
+
+  salen = sizeof(addr);
+  if (getpeername(getFd(), (struct sockaddr *)&addr, &salen) != 0) {
+    vlog.error("unable to get peer name for socket");
+    return rfb::strDup("");
+  }
+
+  if (salen > offsetof(struct sockaddr_un, sun_path))
+    return rfb::strDup(addr.sun_path);
+
+  salen = sizeof(addr);
+  if (getsockname(getFd(), (struct sockaddr *)&addr, &salen) != 0) {
+    vlog.error("unable to get local name for socket");
+    return rfb::strDup("");
+  }
+
+  if (salen > offsetof(struct sockaddr_un, sun_path))
+    return rfb::strDup(addr.sun_path);
+
+  // socketpair() will create unnamed sockets
+
+  return rfb::strDup("(unnamed UNIX socket)");
+}
+
+char* UnixSocket::getPeerEndpoint() {
+  return getPeerAddress();
+}
+
+bool UnixSocket::cork(bool enable)
+{
+  return true;
+}
+
+UnixListener::UnixListener(const char *path, int mode)
+{
+  struct sockaddr_un addr;
+  mode_t saved_umask;
+  int err, result;
+
+  if (strlen(path) >= sizeof(addr.sun_path))
+    throw SocketException("socket path is too long", ENAMETOOLONG);
+
+  // - Create a socket
+  if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+    throw SocketException("unable to create listening socket", errno);
+
+  // - 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);
+  }
+
+  listen(fd);
+}
+
+UnixListener::~UnixListener()
+{
+  struct sockaddr_un addr;
+  socklen_t salen = sizeof(addr);
+
+  if (getsockname(getFd(), (struct sockaddr *)&addr, &salen) == 0)
+    unlink(addr.sun_path);
+}
+
+Socket* UnixListener::createSocket(int fd) {
+  return new UnixSocket(fd);
+}
+
+int UnixListener::getMyPort() {
+  return 0;
+}
diff --git a/common/network/UnixSocket.h b/common/network/UnixSocket.h
new file mode 100644
index 0000000..1ffca45
--- /dev/null
+++ b/common/network/UnixSocket.h
@@ -0,0 +1,60 @@
+/* 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>
+
+namespace network {
+
+  class UnixSocket : public Socket {
+  public:
+    UnixSocket(int sock);
+    UnixSocket(const char *name);
+
+    virtual char* getPeerAddress();
+    virtual char* getPeerEndpoint();
+
+    virtual bool cork(bool enable);
+  };
+
+  class UnixListener : public SocketListener {
+  public:
+    UnixListener(const char *listenaddr, int mode);
+    virtual ~UnixListener();
+
+    int getMyPort();
+
+  protected:
+    virtual Socket* createSocket(int fd);
+  };
+
+}
+
+#endif // __NETWORK_UNIX_SOCKET_H__
diff --git a/common/rfb/Configuration.cxx b/common/rfb/Configuration.cxx
index 418a0c9..619c4d5 100644
--- a/common/rfb/Configuration.cxx
+++ b/common/rfb/Configuration.cxx
@@ -338,7 +338,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;
diff --git a/unix/x0vncserver/x0vncserver.cxx b/unix/x0vncserver/x0vncserver.cxx
index c8098f7..c08572b 100644
--- a/unix/x0vncserver/x0vncserver.cxx
+++ b/unix/x0vncserver/x0vncserver.cxx
@@ -31,6 +31,7 @@
 #include <rfb/Configuration.h>
 #include <rfb/Timer.h>
 #include <network/TcpSocket.h>
+#include <network/UnixSocket.h>
 
 #include <vncconfig/QueryConnectDialog.h>
 
@@ -58,6 +59,8 @@
                                "CPU time to be consumed", 35);
 StringParameter displayname("display", "The X display", "");
 IntParameter rfbport("rfbport", "TCP port to listen for RFB protocol",5900);
+StringParameter rfbunixpath("rfbunixpath", "Unix socket to listen for RFB protocol", "");
+IntParameter rfbunixmode("rfbunixmode", "Unix socket access mode", 0600);
 IntParameter queryConnectTimeout("QueryConnectTimeout",
                                  "Number of seconds to show the Accept Connection dialog before "
                                  "rejecting the connection",
@@ -291,7 +294,7 @@
   signal(SIGINT, CleanupSignalHandler);
   signal(SIGTERM, CleanupSignalHandler);
 
-  std::list<TcpListener*> listeners;
+  std::list<SocketListener*> listeners;
 
   try {
     TXWindow::init(dpy,"x0vncserver");
@@ -307,13 +310,18 @@
     QueryConnHandler qcHandler(dpy, &server);
     server.setQueryConnectionHandler(&qcHandler);
 
-    createTcpListeners(&listeners, 0, (int)rfbport);
-    vlog.info("Listening on port %d", (int)rfbport);
+    if (rfbunixpath.getValueStr()[0] != '\0') {
+      listeners.push_back(new network::UnixListener(rfbunixpath, rfbunixmode));
+      vlog.info("Listening on %s (mode %04o)", (const char*)rfbunixpath, (int)rfbunixmode);
+    } else {
+      createTcpListeners(&listeners, 0, (int)rfbport);
+      vlog.info("Listening on port %d", (int)rfbport);
+    }
 
     const char *hostsData = hostsFile.getData();
     FileTcpFilter fileTcpFilter(hostsData);
     if (strlen(hostsData) != 0)
-      for (std::list<TcpListener*>::iterator i = listeners.begin();
+      for (std::list<SocketListener*>::iterator i = listeners.begin();
            i != listeners.end();
            i++)
         (*i)->setFilter(&fileTcpFilter);
@@ -335,7 +343,7 @@
       FD_ZERO(&wfds);
 
       FD_SET(ConnectionNumber(dpy), &rfds);
-      for (std::list<TcpListener*>::iterator i = listeners.begin();
+      for (std::list<SocketListener*>::iterator i = listeners.begin();
            i != listeners.end();
            i++)
         FD_SET((*i)->getFd(), &rfds);
@@ -387,7 +395,7 @@
       }
 
       // Accept new VNC connections
-      for (std::list<TcpListener*>::iterator i = listeners.begin();
+      for (std::list<SocketListener*>::iterator i = listeners.begin();
            i != listeners.end();
            i++) {
         if (FD_ISSET((*i)->getFd(), &rfds)) {
diff --git a/unix/x0vncserver/x0vncserver.man b/unix/x0vncserver/x0vncserver.man
index 5c8729e..5dc0b05 100644
--- a/unix/x0vncserver/x0vncserver.man
+++ b/unix/x0vncserver/x0vncserver.man
@@ -66,6 +66,15 @@
 Use IPv6 for incoming and outgoing connections. Default is on.
 .
 .TP
+.B \-rfbunixpath \fIpath\fP
+Specifies the path of a Unix domain socket on which x0vncserver listens for
+connections from viewers, instead of listening on a TCP port.
+.
+.TP
+.B \-rfbunixmode \fImode\fP
+Specifies the mode of the Unix domain socket.  The default is 0600.
+.
+.TP
 .B \-Log \fIlogname\fP:\fIdest\fP:\fIlevel\fP
 Configures the debug log settings.  \fIdest\fP can currently be \fBstderr\fP,
 \fBstdout\fP or \fBsyslog\fP, and \fIlevel\fP is between 0 and 100, 100 meaning
diff --git a/unix/xserver/hw/vnc/RFBGlue.cc b/unix/xserver/hw/vnc/RFBGlue.cc
index c915336..160177b 100644
--- a/unix/xserver/hw/vnc/RFBGlue.cc
+++ b/unix/xserver/hw/vnc/RFBGlue.cc
@@ -192,14 +192,14 @@
 
 int vncGetSocketPort(int fd)
 {
-  return network::TcpSocket::getSockPort(fd);
+  return network::getSockPort(fd);
 }
 
 int vncIsTCPPortUsed(int port)
 {
   try {
     // Attempt to create TCPListeners on that port.
-    std::list<network::TcpListener*> dummy;
+    std::list<network::SocketListener*> dummy;
     network::createTcpListeners (&dummy, 0, port);
     while (!dummy.empty()) {
       delete dummy.back();
diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc
index 080943d..4aac765 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.cc
+++ b/unix/xserver/hw/vnc/XserverDesktop.cc
@@ -32,7 +32,7 @@
 #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>
@@ -107,8 +107,8 @@
 
 
 XserverDesktop::XserverDesktop(int screenIndex_,
-                               std::list<network::TcpListener*> listeners_,
-                               std::list<network::TcpListener*> httpListeners_,
+                               std::list<network::SocketListener*> listeners_,
+                               std::list<network::SocketListener*> httpListeners_,
                                const char* name, const rfb::PixelFormat &pf,
                                int width, int height,
                                void* fbptr, int stride)
@@ -127,13 +127,13 @@
   if (!httpListeners.empty ())
     httpServer = new FileHTTPServer(this);
 
-  for (std::list<TcpListener*>::iterator i = listeners.begin();
+  for (std::list<SocketListener*>::iterator i = listeners.begin();
        i != listeners.end();
        i++) {
     vncSetNotifyFd((*i)->getFd(), screenIndex, true, false);
   }
 
-  for (std::list<TcpListener*>::iterator i = httpListeners.begin();
+  for (std::list<SocketListener*>::iterator i = httpListeners.begin();
        i != httpListeners.end();
        i++) {
     vncSetNotifyFd((*i)->getFd(), screenIndex, true, false);
@@ -386,10 +386,10 @@
 }
 
 bool XserverDesktop::handleListenerEvent(int fd,
-                                         std::list<TcpListener*>* sockets,
+                                         std::list<SocketListener*>* sockets,
                                          SocketServer* sockserv)
 {
-  std::list<TcpListener*>::iterator i;
+  std::list<SocketListener*>::iterator i;
 
   for (i = sockets->begin(); i != sockets->end(); i++) {
     if ((*i)->getFd() == fd)
diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h
index f1c3e3e..f866a4c 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.h
+++ b/unix/xserver/hw/vnc/XserverDesktop.h
@@ -44,7 +44,7 @@
   class VNCServerST;
 }
 
-namespace network { class TcpListener; class Socket; class SocketServer; }
+namespace network { class SocketListener; class Socket; class SocketServer; }
 
 class XserverDesktop : public rfb::SDesktop, public rfb::FullFramePixelBuffer,
                        public rdr::Substitutor,
@@ -53,8 +53,8 @@
 public:
 
   XserverDesktop(int screenIndex,
-                 std::list<network::TcpListener*> listeners_,
-                 std::list<network::TcpListener*> httpListeners_,
+                 std::list<network::SocketListener*> listeners_,
+                 std::list<network::SocketListener*> httpListeners_,
                  const char* name, const rfb::PixelFormat &pf,
                  int width, int height, void* fbptr, int stride);
   virtual ~XserverDesktop();
@@ -109,7 +109,7 @@
 
 protected:
   bool handleListenerEvent(int fd,
-                           std::list<network::TcpListener*>* sockets,
+                           std::list<network::SocketListener*>* sockets,
                            network::SocketServer* sockserv);
   bool handleSocketEvent(int fd,
                          network::SocketServer* sockserv,
@@ -122,8 +122,8 @@
   int screenIndex;
   rfb::VNCServerST* server;
   rfb::HTTPServer* httpServer;
-  std::list<network::TcpListener*> listeners;
-  std::list<network::TcpListener*> httpListeners;
+  std::list<network::SocketListener*> listeners;
+  std::list<network::SocketListener*> httpListeners;
   bool directFbptr;
 
   uint32_t queryConnectId;
diff --git a/unix/xserver/hw/vnc/Xvnc.man b/unix/xserver/hw/vnc/Xvnc.man
index 80b7878..269be9a 100644
--- a/unix/xserver/hw/vnc/Xvnc.man
+++ b/unix/xserver/hw/vnc/Xvnc.man
@@ -91,6 +91,15 @@
 Use IPv6 for incoming and outgoing connections. Default is on.
 .
 .TP
+.B \-rfbunixpath \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 \-rfbunixmode \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 the server. This is
 necessary because the server is single-threaded and sometimes blocks until the
diff --git a/unix/xserver/hw/vnc/vncExt.c b/unix/xserver/hw/vnc/vncExt.c
index f7ba9fa..fd65eab 100644
--- a/unix/xserver/hw/vnc/vncExt.c
+++ b/unix/xserver/hw/vnc/vncExt.c
@@ -585,6 +585,7 @@
 
 static void vncResetProc(ExtensionEntry* extEntry)
 {
+  vncExtensionClose();
 }
 
 static void vncClientStateChange(CallbackListPtr * l, void * d, void * p)
diff --git a/unix/xserver/hw/vnc/vncExtInit.cc b/unix/xserver/hw/vnc/vncExtInit.cc
index 54cca95..d6f6b74 100644
--- a/unix/xserver/hw/vnc/vncExtInit.cc
+++ b/unix/xserver/hw/vnc/vncExtInit.cc
@@ -34,6 +34,7 @@
 #include <rfb/Region.h>
 #include <rfb/ledStates.h>
 #include <network/TcpSocket.h>
+#include <network/UnixSocket.h>
 
 #include "XserverDesktop.h"
 #include "vncExtInit.h"
@@ -79,6 +80,8 @@
 rfb::AliasParameter rfbwait("rfbwait", "Alias for ClientWaitTimeMillis",
                             &rfb::Server::clientWaitTimeMillis);
 rfb::IntParameter rfbport("rfbport", "TCP port to listen for RFB protocol",0);
+rfb::StringParameter rfbunixpath("rfbunixpath", "Unix socket to listen for RFB protocol", "");
+rfb::IntParameter rfbunixmode("rfbunixmode", "Unix socket access mode", 0600);
 rfb::StringParameter desktopName("desktop", "Name of VNC desktop","x11");
 rfb::BoolParameter localhostOnly("localhost",
                                  "Only allow connections from localhost",
@@ -173,14 +176,29 @@
     for (int scr = 0; scr < vncGetScreenCount(); scr++) {
 
       if (!desktop[scr]) {
-        std::list<network::TcpListener*> listeners;
-        std::list<network::TcpListener*> httpListeners;
+        std::list<network::SocketListener*> listeners;
+        std::list<network::SocketListener*> httpListeners;
         if (scr == 0 && vncInetdSock != -1) {
-          if (network::TcpSocket::isListening(vncInetdSock))
+          if (network::isSocketListening(vncInetdSock))
           {
             listeners.push_back(new network::TcpListener(vncInetdSock));
             vlog.info("inetd wait");
           }
+        } else if (rfbunixpath.getValueStr()[0] != '\0') {
+          char path[PATH_MAX];
+          int mode = (int)rfbunixmode;
+
+          if (scr == 0)
+            strncpy(path, rfbunixpath, sizeof(path));
+          else
+            snprintf(path, sizeof(path), "%s.%d",
+                     rfbunixpath.getValueStr(), scr);
+          path[sizeof(path)-1] = '\0';
+
+          listeners.push_back(new network::UnixListener(path, mode));
+
+          vlog.info("Listening for VNC connections on %s (mode %04o)",
+                    path, mode);
         } else {
           const char *addr = interface;
           int port = rfbport;
@@ -244,6 +262,18 @@
   vncRegisterBlockHandlers();
 }
 
+void vncExtensionClose(void)
+{
+  try {
+    for (int scr = 0; scr < vncGetScreenCount(); scr++) {
+      delete desktop[scr];
+      desktop[scr] = NULL;
+    }
+  } catch (rdr::Exception& e) {
+    vncFatalError("vncExtInit: %s",e.str());
+  }
+}
+
 void vncHandleSocketEvent(int fd, int scrIdx, int read, int write)
 {
   desktop[scrIdx]->handleSocketEvent(fd, read, write);
diff --git a/unix/xserver/hw/vnc/vncExtInit.h b/unix/xserver/hw/vnc/vncExtInit.h
index e829434..9414723 100644
--- a/unix/xserver/hw/vnc/vncExtInit.h
+++ b/unix/xserver/hw/vnc/vncExtInit.h
@@ -48,6 +48,7 @@
 extern int vncInetdSock;
 
 void vncExtensionInit(void);
+void vncExtensionClose(void);
 
 void vncHandleSocketEvent(int fd, int scrIdx, int read, int write);
 void vncCallBlockHandlers(int* timeout);
diff --git a/vncviewer/CConn.cxx b/vncviewer/CConn.cxx
index 35d6e23..166597e 100644
--- a/vncviewer/CConn.cxx
+++ b/vncviewer/CConn.cxx
@@ -39,6 +39,9 @@
 #include <rdr/MemInStream.h>
 #include <rdr/MemOutStream.h>
 #include <network/TcpSocket.h>
+#ifndef WIN32
+#include <network/UnixSocket.h>
+#endif
 
 #include <FL/Fl.H>
 #include <FL/fl_ask.H>
@@ -106,10 +109,19 @@
 
   if(sock == NULL) {
     try {
-      getHostAndPort(vncServerName, &serverHost, &serverPort);
+#ifndef WIN32
+      if (strchr(vncServerName, '/') != NULL) {
+        sock = new network::UnixSocket(vncServerName);
+        serverHost = sock->getPeerAddress();
+        vlog.info(_("connected to socket %s"), serverHost);
+      } else
+#endif
+      {
+        getHostAndPort(vncServerName, &serverHost, &serverPort);
 
-      sock = new network::TcpSocket(serverHost, serverPort);
-      vlog.info(_("connected to host %s port %d"), serverHost, serverPort);
+        sock = new network::TcpSocket(serverHost, serverPort);
+        vlog.info(_("connected to host %s port %d"), serverHost, serverPort);
+      }
     } catch (rdr::Exception& e) {
       vlog.error("%s", e.str());
       if (alertOnFatalError)
diff --git a/vncviewer/vncviewer.cxx b/vncviewer/vncviewer.cxx
index e305d79..6c0c738 100644
--- a/vncviewer/vncviewer.cxx
+++ b/vncviewer/vncviewer.cxx
@@ -376,6 +376,18 @@
                                  (strchr(vncServerName, '\\')) != NULL);
 
   if (hasPathSeparator) {
+#ifndef WIN32
+    struct stat sb;
+
+    // This might be a UNIX socket, we need to check
+    if (stat(vncServerName, &sb) == -1) {
+      // Some access problem; let loadViewerParameters() deal with it...
+    } else {
+      if ((sb.st_mode & S_IFMT) == S_IFSOCK)
+        return;
+    }
+#endif
+
     try {
       const char* newServerName;
       newServerName = loadViewerParameters(vncServerName);
@@ -573,7 +585,7 @@
 #endif
 
   if (listenMode) {
-    std::list<TcpListener*> listeners;
+    std::list<SocketListener*> listeners;
     try {
       int port = 5500;
       if (isdigit(vncServerName[0]))
@@ -587,7 +599,7 @@
       while (sock == NULL) {
         fd_set rfds;
         FD_ZERO(&rfds);
-        for (std::list<TcpListener*>::iterator i = listeners.begin();
+        for (std::list<SocketListener*>::iterator i = listeners.begin();
              i != listeners.end();
              i++)
           FD_SET((*i)->getFd(), &rfds);
@@ -602,7 +614,7 @@
           }
         }
 
-        for (std::list<TcpListener*>::iterator i = listeners.begin ();
+        for (std::list<SocketListener*>::iterator i = listeners.begin ();
              i != listeners.end();
              i++)
           if (FD_ISSET((*i)->getFd(), &rfds)) {
diff --git a/win/winvnc/ManagedListener.cxx b/win/winvnc/ManagedListener.cxx
index 9137238..a8c6f25 100644
--- a/win/winvnc/ManagedListener.cxx
+++ b/win/winvnc/ManagedListener.cxx
@@ -31,7 +31,7 @@
 
 ManagedListener::~ManagedListener() {
   if (!sockets.empty()) {
-    std::list<network::TcpListener*>::iterator iter;
+    std::list<network::SocketListener*>::iterator iter;
     for (iter = sockets.begin(); iter != sockets.end(); ++iter)
       manager->remListener(*iter);
     sockets.clear();
@@ -62,7 +62,7 @@
   delete filter;
   filter = new network::TcpFilter(filterStr);
   if (!sockets.empty() && !localOnly) {
-    std::list<network::TcpListener*>::iterator iter;
+    std::list<network::SocketListener*>::iterator iter;
     for (iter = sockets.begin(); iter != sockets.end(); ++iter)
       (*iter)->setFilter(filter);
   }
@@ -80,7 +80,7 @@
 }
 
 void ManagedListener::refresh() {
-  std::list<network::TcpListener*>::iterator iter;
+  std::list<network::SocketListener*>::iterator iter;
   if (!sockets.empty()) {
     for (iter = sockets.begin(); iter != sockets.end(); ++iter)
       manager->remListener(*iter);
@@ -107,7 +107,7 @@
       for (iter = sockets.begin(); iter != sockets.end(); ++iter)
         manager->addListener(*iter, server, addrChangeNotifier);
     } catch (...) {
-      std::list<network::TcpListener*>::iterator iter2;
+      std::list<network::SocketListener*>::iterator iter2;
       for (iter2 = sockets.begin(); iter2 != iter; ++iter2)
         manager->remListener(*iter2);
       for (; iter2 != sockets.end(); ++iter2)
diff --git a/win/winvnc/ManagedListener.h b/win/winvnc/ManagedListener.h
index e8d3c89..39223c7 100644
--- a/win/winvnc/ManagedListener.h
+++ b/win/winvnc/ManagedListener.h
@@ -45,7 +45,7 @@
 
   protected:
     void refresh();
-    std::list<network::TcpListener*> sockets;
+    std::list<network::SocketListener*> sockets;
     network::TcpFilter* filter;
     rfb::win32::SocketManager* manager;
     rfb::win32::SocketManager::AddressChangeNotifier* addrChangeNotifier;