Author: Tim Waugh <twaugh@redhat.com>
Subject: Fixed IPv6 support.
Patch-Mainline: Upstream
Git-commit: 892d10a705077083489f0ed4861af123433ff811
Referenes: bnc#952057
Signed-off-by: Michal Srb <msrb@suse.com>

Index: tigervnc-1.4.3/common/network/TcpSocket.cxx
===================================================================
--- tigervnc-1.4.3.orig/common/network/TcpSocket.cxx
+++ tigervnc-1.4.3/common/network/TcpSocket.cxx
@@ -35,7 +35,6 @@
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <netdb.h>
-#include <unistd.h>
 #include <errno.h>
 #include <string.h>
 #include <signal.h>
@@ -43,6 +42,7 @@
 #endif
 
 #include <stdlib.h>
+#include <unistd.h>
 #include <network/TcpSocket.h>
 #include <rfb/util.h>
 #include <rfb/LogWriter.h>
@@ -248,16 +248,17 @@ char* TcpSocket::getPeerAddress() {
     return rfb::strDup("");
   }
 
-#if defined(HAVE_GETADDRINFO) && defined(HAVE_INET_PTON)
+#if defined(HAVE_GETADDRINFO)
   if (sa.u.sa.sa_family == AF_INET6) {
     char buffer[INET6_ADDRSTRLEN + 2];
-    const char *name;
+    int ret;
 
     buffer[0] = '[';
 
-    name = inet_ntop(sa.u.sa.sa_family, &sa.u.sin6.sin6_addr,
-                     buffer + 1, sizeof(buffer) - 2);
-    if (name == NULL) {
+    ret = getnameinfo(&sa.u.sa, sizeof(sa.u.sin6),
+                      buffer + 1, sizeof(buffer) - 2, NULL, 0,
+                      NI_NUMERICHOST);
+    if (ret != 0) {
       vlog.error("unable to convert peer name to a string");
       return rfb::strDup("");
     }
@@ -400,136 +401,77 @@ int TcpSocket::getSockPort(int sock)
   }
 }
 
+TcpListener::TcpListener(int sock)
+{
+  fd = sock;
+}
+
+TcpListener::TcpListener(const TcpListener& other)
+{
+  fd = dup (other.fd);
+  // Hope TcpListener::shutdown(other) doesn't get called...
+}
 
-TcpListener::TcpListener(const char *listenaddr, int port, bool localhostOnly,
-			 int sock, bool close_) : closeFd(close_)
+TcpListener& TcpListener::operator= (const TcpListener& other)
 {
-  if (sock != -1) {
-    fd = sock;
-    return;
+  if (this != &other)
+  {
+    closesocket (fd);
+    fd = dup (other.fd);
+    // Hope TcpListener::shutdown(other) doesn't get called...
   }
+  return *this;
+}
 
-  bool use_ipv6;
-  int af;
-#ifdef HAVE_GETADDRINFO
-  use_ipv6 = true;
-  af = AF_INET6;
-#else
-  use_ipv6 = false;
-  af = AF_INET;
-#endif
+TcpListener::TcpListener(const struct sockaddr *listenaddr,
+                         socklen_t listenaddrlen)
+{
+  int one = 1;
+  vnc_sockaddr_t sa;
+  int sock;
 
   initSockets();
-  if ((fd = socket(af, SOCK_STREAM, 0)) < 0) {
-    // - Socket creation failed
-    if (use_ipv6) {
-      // - Trying to make an IPv6-capable socket failed - try again, IPv4-only
-      use_ipv6 = false;
-      af = AF_INET;
-      fd = socket(af, SOCK_STREAM, 0);
-    }
-    if (fd < 0)
-      throw SocketException("unable to create listening socket", errorNumber);
-  } else {
-    // - Socket creation succeeded
-    if (use_ipv6) {
+
+  if ((sock = socket (listenaddr->sa_family, SOCK_STREAM, 0)) < 0)
+    throw SocketException("unable to create listening socket", errorNumber);
+
+  memcpy (&sa, listenaddr, listenaddrlen);
 #ifdef IPV6_V6ONLY
-      // - We made an IPv6-capable socket, and we need it to do IPv4 too
-      int opt = 0;
-      setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));
-#else
-      vlog.error("IPV6_V6ONLY support is missing. "
-		 "IPv4 clients may not be able to connect.");
-#endif
-    }
+  if (listenaddr->sa_family == AF_INET6) {
+    if (setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&one, sizeof(one)))
+      throw SocketException("unable to set IPV6_V6ONLY", errorNumber);
+  }
+#endif /* defined(IPV6_V6ONLY) */
+
+  if (bind(sock, &sa.u.sa, listenaddrlen) == -1) {
+    closesocket(sock);
+    throw SocketException("failed to bind socket", errorNumber);
   }
 
 #ifndef WIN32
   // - By default, close the socket on exec()
-  fcntl(fd, F_SETFD, FD_CLOEXEC);
+  fcntl(sock, F_SETFD, FD_CLOEXEC);
 
-  int one = 1;
-  if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
-		 (char *)&one, sizeof(one)) < 0) {
+  if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+                 (char *)&one, sizeof(one)) < 0) {
     int e = errorNumber;
-    closesocket(fd);
+    closesocket(sock);
     throw SocketException("unable to create listening socket", e);
   }
 #endif
 
-  // - Bind it to the desired port
-  struct sockaddr_in addr;
-#ifdef HAVE_GETADDRINFO
-  struct sockaddr_in6 addr6;
-#endif
-  struct sockaddr *sa;
-  int sa_len;
-
-#ifdef HAVE_GETADDRINFO
-  if (use_ipv6) {
-    memset(&addr6, 0, (sa_len = sizeof(addr6)));
-    addr6.sin6_family = af;
-    addr6.sin6_port = htons(port);
-
-    if (localhostOnly)
-      addr6.sin6_addr = in6addr_loopback;
-    else if (listenaddr != NULL) {
-#ifdef HAVE_INET_PTON
-      if (inet_pton(AF_INET6, listenaddr, &addr6.sin6_addr) != 1)
-	use_ipv6 = false;
-#else
-      // Unable to parse without inet_pton
-      use_ipv6 = false;
-#endif
-    }
-
-    if (use_ipv6)
-      sa = (struct sockaddr *)&addr6;
-  }
-#endif
-
-  if (!use_ipv6) {
-    memset(&addr, 0, (sa_len = sizeof(addr)));
-    addr.sin_family = af;
-    addr.sin_port = htons(port);
-
-    if (localhostOnly) {
-      addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-    } else if (listenaddr != NULL) {
-#ifdef HAVE_INET_ATON
-      if (inet_aton(listenaddr, &addr.sin_addr) == 0)
-#else
-	/* Some systems (e.g. Windows) do not have inet_aton, sigh */
-	if ((addr.sin_addr.s_addr = inet_addr(listenaddr)) == INADDR_NONE)
-#endif
-	{
-	  closesocket(fd);
-	  throw Exception("invalid network interface address: %s", listenaddr);
-	}
-    } else
-      /* Bind to 0.0.0.0 by default. */
-      addr.sin_addr.s_addr = htonl(INADDR_ANY);
-
-    sa = (struct sockaddr *)&addr;
-  }
-
-  addr.sin_port = htons(port);
-  if (bind(fd, sa, sa_len) < 0) {
-    int e = errorNumber;
-    closesocket(fd);
-    throw SocketException("unable to bind listening socket", e);
-  }
-
   // - Set it to be a listening socket
-  if (listen(fd, 5) < 0) {
+  if (listen(sock, 5) < 0) {
     int e = errorNumber;
-    closesocket(fd);
+    closesocket(sock);
     throw SocketException("unable to set socket to listening mode", e);
   }
+
+  fd = sock;
 }
 
 TcpListener::~TcpListener() {
-  if (closeFd) closesocket(fd);
+  closesocket(fd);
 }
 
 void TcpListener::shutdown()
@@ -567,50 +509,141 @@ TcpListener::accept() {
   return s;
 }
 
-void TcpListener::getMyAddresses(std::list<char*>* result) {
-#if defined(HAVE_GETADDRINFO) && defined(HAVE_INET_PTON)
+int TcpListener::getMyPort() {
+  return TcpSocket::getSockPort(getFd());
+}
+
+
+void network::createLocalTcpListeners(std::list<TcpListener> *listeners,
+                                      int port)
+{
+  std::list<TcpListener> new_listeners;
   vnc_sockaddr_t sa;
+#ifdef HAVE_GETADDRINFO
+  sa.u.sin6.sin6_family = AF_INET6;
+  sa.u.sin6.sin6_port = htons (port);
+  sa.u.sin6.sin6_addr = in6addr_loopback;
+  try {
+    new_listeners.push_back (TcpListener (&sa.u.sa, sizeof (sa.u.sin6)));
+  } catch (SocketException& e) {
+    // Ignore this if it is due to lack of address family support on
+    // the interface or on the system
+    if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT)
+      // Otherwise, report the error
+      throw;
+  }
+#endif /* HAVE_GETADDRINFO */
+  sa.u.sin.sin_family = AF_INET;
+  sa.u.sin.sin_port = htons (port);
+  sa.u.sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+  try {
+    new_listeners.push_back (TcpListener (&sa.u.sa, sizeof (sa.u.sin)));
+  } catch (SocketException& e) {
+    // Ignore this if it is due to lack of address family support on
+    // the interface or on the system
+    if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT)
+      // Otherwise, report the error
+      throw;
+  }
+
+  if (new_listeners.empty ())
+    throw SocketException("createLocalTcpListeners: no addresses available",
+                          EADDRNOTAVAIL);
+
+  listeners->splice (listeners->end(), new_listeners);
+}
+
+void network::createTcpListeners(std::list<TcpListener> *listeners,
+                                 const char *addr,
+                                 int port)
+{
+  std::list<TcpListener> new_listeners;
+
+#ifdef HAVE_GETADDRINFO
   struct addrinfo *ai, *current, hints;
+  char service[16];
 
   memset(&hints, 0, sizeof(struct addrinfo));
+  hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
   hints.ai_family = AF_UNSPEC;
   hints.ai_socktype = SOCK_STREAM;
   hints.ai_canonname = NULL;
   hints.ai_addr = NULL;
   hints.ai_next = NULL;
 
-  if ((getaddrinfo(NULL, NULL, &hints, &ai)) != 0)
-    return;
-
-  for (current= ai; current != NULL; current = current->ai_next) {
-    if (current->ai_family != AF_INET && current->ai_family != AF_INET6)
-      continue;
+  snprintf (service, sizeof (service) - 1, "%d", port);
+  service[sizeof (service) - 1] = '\0';
+  if ((getaddrinfo(addr, service, &hints, &ai)) != 0)
+    throw rdr::SystemException("getaddrinfo", errorNumber);
 
-    char *addr = new char[INET6_ADDRSTRLEN];
-    inet_ntop(current->ai_family, current->ai_addr, addr, INET6_ADDRSTRLEN);
-    result->push_back(addr);
+  for (current = ai; current != NULL; current = current->ai_next) {
+    try {
+      new_listeners.push_back(TcpListener (current->ai_addr,
+                                           current->ai_addrlen));
+    } catch (SocketException& e) {
+      // Ignore this if it is due to lack of address family support on
+      // the interface or on the system
+      if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) {
+        // Otherwise, report the error
+        freeaddrinfo(ai);
+        throw;
+      }
+    }
   }
   freeaddrinfo(ai);
 #else
-  char hostname[HOST_NAME_MAX];
-  if (gethostname(hostname, HOST_NAME_MAX) < 0)
-    throw rdr::SystemException("gethostname", errorNumber);
-  const hostent* addrs = gethostbyname(hostname);
-  if (addrs == 0)
-    throw rdr::SystemException("gethostbyname", errorNumber);
-  if (addrs->h_addrtype != AF_INET)
-    throw rdr::Exception("getMyAddresses: bad family");
-  for (int i=0; addrs->h_addr_list[i] != 0; i++) {
-    const char* addrC = inet_ntoa(*((struct in_addr*)addrs->h_addr_list[i]));
-    char* addr = new char[strlen(addrC)+1];
-    strcpy(addr, addrC);
-    result->push_back(addr);
+  const hostent* addrs;
+  if (addr) {
+    /* Bind to specific address */
+    addrs = gethostbyname(addr);
+    if (addrs == 0)
+      throw rdr::SystemException("gethostbyname", errorNumber);
+    if (addrs->h_addrtype != AF_INET)
+      throw rdr::Exception("createTcpListeners: bad family");
+    for (int i=0; addrs->h_addr_list[i] != 0; i++) {
+      struct sockaddr_in addr;
+      addr.sin_family = AF_INET;
+      memcpy (&addr.sin_addr, addrs->h_addr_list[i], addrs->h_length);
+      addr.sin_port = htons(port);
+      try {
+        new_listeners.push_back(TcpListener ((struct sockaddr*)&addr,
+                                             addrs->h_length));
+      } catch (SocketException& e) {
+        // Ignore this if it is due to lack of address family support
+        // on the interface or on the system
+        if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) {
+          // Otherwise, report the error
+          freeaddrinfo(ai);
+          throw;
+        }
+      }
+    }
+  } else {
+    /* Bind to any address */
+    struct sockaddr_in addr;
+    addr.sin_family = AF_INET;
+    addr.sin_addr.s_addr = htonl(INADDR_ANY);
+    addr.sin_port = htons(port);
+    try {
+      new_listeners.push_back(TcpListener ((struct sockaddr*)&addr,
+                                           sizeof (struct sockaddr_in)));
+    } catch (SocketException& e) {
+      // Ignore this if it is due to lack of address family support on
+      // the interface or on the system
+      if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) {
+        // Otherwise, report the error
+        freeaddrinfo(ai);
+        throw;
+      }
+    }
   }
-#endif /* defined(HAVE_GETADDRINFO) && defined(HAVE_INET_PTON) */
-}
+#endif /* defined(HAVE_GETADDRINFO) */
 
-int TcpListener::getMyPort() {
-  return TcpSocket::getSockPort(getFd());
+  if (new_listeners.empty ())
+    throw SocketException("createTcpListeners: no addresses available",
+                          EADDRNOTAVAIL);
+
+  listeners->splice (listeners->end(), new_listeners);
 }
 
 
Index: tigervnc-1.4.3/common/network/TcpSocket.h
===================================================================
--- tigervnc-1.4.3.orig/common/network/TcpSocket.h
+++ tigervnc-1.4.3/common/network/TcpSocket.h
@@ -29,6 +29,7 @@
 #define __NETWORK_TCP_SOCKET_H__
 
 #include <network/Socket.h>
+#include <sys/socket.h>
 
 #include <list>
 
@@ -66,18 +67,16 @@ namespace network {
 
   class TcpListener : public SocketListener {
   public:
-    TcpListener(const char *listenaddr, int port, bool localhostOnly=false,
-		int sock=-1, bool close=true);
+    TcpListener(const struct sockaddr *listenaddr, socklen_t listenaddrlen);
+    TcpListener(int sock);
+    TcpListener(const TcpListener& other);
+    TcpListener& operator= (const TcpListener& other);
     virtual ~TcpListener();
 
     virtual void shutdown();
     virtual Socket* accept();
 
-    void getMyAddresses(std::list<char*>* addrs);
     int getMyPort();
-
-  private:
-    bool closeFd;
   };
 
   class TcpFilter : public ConnectionFilter {
@@ -99,6 +98,12 @@ namespace network {
     std::list<Pattern> filter;
   };
 
+  void createLocalTcpListeners(std::list<TcpListener> *listeners,
+                               int port);
+  void createTcpListeners(std::list<TcpListener> *listeners,
+                          const char *addr,
+                          int port);
+
 }
 
 #endif // __NETWORK_TCP_SOCKET_H__
Index: tigervnc-1.4.3/unix/x0vncserver/x0vncserver.cxx
===================================================================
--- tigervnc-1.4.3.orig/unix/x0vncserver/x0vncserver.cxx
+++ tigervnc-1.4.3/unix/x0vncserver/x0vncserver.cxx
@@ -475,6 +475,8 @@ int main(int argc, char** argv)
   signal(SIGINT, CleanupSignalHandler);
   signal(SIGTERM, CleanupSignalHandler);
 
+  std::list<TcpListener> listeners;
+
   try {
     TXWindow::init(dpy,"x0vncserver");
     Geometry geo(DisplayWidth(dpy, DefaultScreen(dpy)),
@@ -489,13 +491,16 @@ int main(int argc, char** argv)
     QueryConnHandler qcHandler(dpy, &server);
     server.setQueryConnectionHandler(&qcHandler);
 
-    TcpListener listener(NULL, (int)rfbport);
+    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)
-      listener.setFilter(&fileTcpFilter);
+      for (std::list<TcpListener>::iterator i = listeners.begin();
+           i != listeners.end();
+           i++)
+        (*i).setFilter(&fileTcpFilter);
     delete[] hostsData;
 
     PollingScheduler sched((int)pollingCycle, (int)maxProcessorUsage);
@@ -511,7 +516,11 @@ int main(int argc, char** argv)
 
       FD_ZERO(&rfds);
       FD_SET(ConnectionNumber(dpy), &rfds);
-      FD_SET(listener.getFd(), &rfds);
+      for (std::list<TcpListener>::iterator i = listeners.begin();
+           i != listeners.end();
+           i++)
+        FD_SET((*i).getFd(), &rfds);
+
       server.getSockets(&sockets);
       int clients_connected = 0;
       for (i = sockets.begin(); i != sockets.end(); i++) {
@@ -556,12 +565,16 @@ int main(int argc, char** argv)
       }
 
       // Accept new VNC connections
-      if (FD_ISSET(listener.getFd(), &rfds)) {
-        Socket* sock = listener.accept();
-        if (sock) {
-          server.addSocket(sock);
-        } else {
-          vlog.status("Client connection rejected");
+      for (std::list<TcpListener>::iterator i = listeners.begin();
+           i != listeners.end();
+           i++) {
+        if (FD_ISSET((*i).getFd(), &rfds)) {
+          Socket* sock = (*i).accept();
+          if (sock) {
+            server.addSocket(sock);
+          } else {
+            vlog.status("Client connection rejected");
+          }
         }
       }
 
Index: tigervnc-1.4.3/unix/xserver/hw/vnc/XserverDesktop.cc
===================================================================
--- tigervnc-1.4.3.orig/unix/xserver/hw/vnc/XserverDesktop.cc
+++ tigervnc-1.4.3/unix/xserver/hw/vnc/XserverDesktop.cc
@@ -133,13 +133,13 @@ public:
 
 
 XserverDesktop::XserverDesktop(ScreenPtr pScreen_,
-                               network::TcpListener* listener_,
-                               network::TcpListener* httpListener_,
+                               std::list<network::TcpListener> listeners_,
+                               std::list<network::TcpListener> httpListeners_,
                                const char* name, const rfb::PixelFormat &pf,
                                void* fbptr, int stride)
   : pScreen(pScreen_),
     server(0), httpServer(0),
-    listener(listener_), httpListener(httpListener_),
+    listeners(listeners_), httpListeners(httpListeners_),
     deferredUpdateTimerSet(false),
     grabbing(false), ignoreHooks_(false), directFbptr(true),
     queryConnectId(0)
@@ -150,7 +150,7 @@ XserverDesktop::XserverDesktop(ScreenPtr
   setFramebuffer(pScreen->width, pScreen->height, fbptr, stride);
   server->setQueryConnectionHandler(this);
 
-  if (httpListener)
+  if (!httpListeners.empty ())
     httpServer = new FileHTTPServer(this);
 }
 
@@ -292,7 +292,7 @@ char* XserverDesktop::substitute(const c
   }
   if (strcmp(varName, "$PORT") == 0) {
     char* str = new char[10];
-    sprintf(str, "%d", listener ? listener->getMyPort() : 0);
+    sprintf(str, "%d", listeners.empty () ? 0 : (*listeners.begin ()).getMyPort());
     return str;
   }
   if (strcmp(varName, "$WIDTH") == 0) {
@@ -523,14 +523,18 @@ void XserverDesktop::blockHandler(fd_set
 
     // Add all sockets we want read events for, after purging
     // any closed sockets.
-    if (listener)
-      FD_SET(listener->getFd(), fds);
-    if (httpListener)
-      FD_SET(httpListener->getFd(), fds);
+    for (std::list<network::TcpListener>::iterator i = listeners.begin();
+         i != listeners.end();
+         i++)
+      FD_SET((*i).getFd(), fds);
+    for (std::list<network::TcpListener>::iterator i = httpListeners.begin();
+         i != httpListeners.end();
+         i++)
+      FD_SET((*i).getFd(), fds);
 
     std::list<Socket*> sockets;
-    server->getSockets(&sockets);
     std::list<Socket*>::iterator i;
+    server->getSockets(&sockets);
     for (i = sockets.begin(); i != sockets.end(); i++) {
       int fd = (*i)->getFd();
       if ((*i)->isShutdown()) {
@@ -582,20 +586,24 @@ void XserverDesktop::wakeupHandler(fd_se
     // First check for file descriptors with something to do
     if (nfds >= 1) {
 
-      if (listener) {
-        if (FD_ISSET(listener->getFd(), fds)) {
-          FD_CLR(listener->getFd(), fds);
-          Socket* sock = listener->accept();
+      for (std::list<network::TcpListener>::iterator i = listeners.begin();
+           i != listeners.end();
+           i++) {
+        if (FD_ISSET((*i).getFd(), fds)) {
+          FD_CLR((*i).getFd(), fds);
+          Socket* sock = (*i).accept();
           sock->outStream().setBlocking(false);
           server->addSocket(sock);
           vlog.debug("new client, sock %d",sock->getFd());
         }
       }
 
-      if (httpListener) {
-        if (FD_ISSET(httpListener->getFd(), fds)) {
-          FD_CLR(httpListener->getFd(), fds);
-          Socket* sock = httpListener->accept();
+      for (std::list<network::TcpListener>::iterator i = httpListeners.begin();
+           i != httpListeners.end();
+           i++) {
+        if (FD_ISSET((*i).getFd(), fds)) {
+          FD_CLR((*i).getFd(), fds);
+          Socket* sock = (*i).accept();
           sock->outStream().setBlocking(false);
           httpServer->addSocket(sock);
           vlog.debug("new http client, sock %d",sock->getFd());
Index: tigervnc-1.4.3/unix/xserver/hw/vnc/XserverDesktop.h
===================================================================
--- tigervnc-1.4.3.orig/unix/xserver/hw/vnc/XserverDesktop.h
+++ tigervnc-1.4.3/unix/xserver/hw/vnc/XserverDesktop.h
@@ -58,8 +58,9 @@ class XserverDesktop : public rfb::SDesk
                        public rfb::VNCServerST::QueryConnectionHandler {
 public:
 
-  XserverDesktop(ScreenPtr pScreen, network::TcpListener* listener,
-                 network::TcpListener* httpListener_,
+  XserverDesktop(ScreenPtr pScreen_,
+                 std::list<network::TcpListener> listeners_,
+                 std::list<network::TcpListener> httpListeners_,
                  const char* name, const rfb::PixelFormat &pf,
                  void* fbptr, int stride);
   virtual ~XserverDesktop();
@@ -127,8 +128,8 @@ private:
   ScreenPtr pScreen;
   rfb::VNCServerST* server;
   rfb::HTTPServer* httpServer;
-  network::TcpListener* listener;
-  network::TcpListener* httpListener;
+  std::list<network::TcpListener> listeners;
+  std::list<network::TcpListener> httpListeners;
   bool deferredUpdateTimerSet;
   bool grabbing;
   bool ignoreHooks_;
Index: tigervnc-1.4.3/unix/xserver/hw/vnc/vncExtInit.cc
===================================================================
--- tigervnc-1.4.3.orig/unix/xserver/hw/vnc/vncExtInit.cc
+++ tigervnc-1.4.3/unix/xserver/hw/vnc/vncExtInit.cc
@@ -223,30 +223,38 @@ void vncExtensionInit()
     for (int scr = 0; scr < screenInfo.numScreens; scr++) {
 
       if (!desktop[scr]) {
-        network::TcpListener* listener = 0;
-        network::TcpListener* httpListener = 0;
+        std::list<network::TcpListener> listeners;
+        std::list<network::TcpListener> httpListeners;
         if (scr == 0 && vncInetdSock != -1) {
           if (network::TcpSocket::isSocket(vncInetdSock) &&
               !network::TcpSocket::isConnected(vncInetdSock))
           {
-            listener = new network::TcpListener(NULL, 0, 0, vncInetdSock, true);
+            listeners.push_back (network::TcpListener(vncInetdSock));
             vlog.info("inetd wait");
           }
         } else {
           int port = rfbport;
           if (port == 0) port = 5900 + atoi(display);
           port += 1000 * scr;
-          listener = new network::TcpListener(listenaddr, port, localhostOnly);
+          if (localhostOnly)
+            network::createLocalTcpListeners(&listeners, port);
+          else
+            network::createTcpListeners(&listeners, listenaddr, port);
           vlog.info("Listening for VNC connections on %s interface(s), port %d",
-		    listenaddr == NULL ? "all" : listenaddr, port);
+                    localhostOnly ? "local" : (listenaddr ? listenaddr : "all"),
+                    port);
           CharArray httpDirStr(httpDir.getData());
           if (httpDirStr.buf[0]) {
             port = httpPort;
             if (port == 0) port = 5800 + atoi(display);
             port += 1000 * scr;
-            httpListener = new network::TcpListener(listenaddr, port, localhostOnly);
+            if (localhostOnly)
+              network::createLocalTcpListeners(&httpListeners, port);
+            else
+              network::createTcpListeners(&httpListeners, listenaddr, port);
             vlog.info("Listening for HTTP connections on %s interface(s), port %d",
-		      listenaddr == NULL ? "all" : listenaddr, port);
+                      localhostOnly ? "local" : (listenaddr ? listenaddr : "all"),
+                      port);
           }
         }
 
@@ -254,15 +262,15 @@ void vncExtensionInit()
         PixelFormat pf = vncGetPixelFormat(screenInfo.screens[scr]);
 
         desktop[scr] = new XserverDesktop(screenInfo.screens[scr],
-                                          listener,
-                                          httpListener,
+                                          listeners,
+                                          httpListeners,
                                           desktopNameStr.buf,
                                           pf,
                                           vncFbptr[scr],
                                           vncFbstride[scr]);
         vlog.info("created VNC server for screen %d", scr);
 
-        if (scr == 0 && vncInetdSock != -1 && !listener) {
+        if (scr == 0 && vncInetdSock != -1 && listeners.empty()) {
           network::Socket* sock = new network::TcpSocket(vncInetdSock);
           desktop[scr]->addClient(sock, false);
           vlog.info("added inetd sock");
Index: tigervnc-1.4.3/unix/xserver/hw/vnc/xvnc.cc
===================================================================
--- tigervnc-1.4.3.orig/unix/xserver/hw/vnc/xvnc.cc
+++ tigervnc-1.4.3/unix/xserver/hw/vnc/xvnc.cc
@@ -352,9 +352,12 @@ static
 bool displayNumFree(int num)
 {
     try {
-	network::TcpListener l(NULL, 6000+num);
+        // Attempt to create TCPListeners on that port.
+        // They go out of scope immediately and are destroyed.
+        std::list<network::TcpListener> dummy;
+        network::createTcpListeners (&dummy, 0, 6000 + num);
     } catch (rdr::Exception& e) {
-	return false;
+        return false;
     }
     char file[256];
     sprintf(file, "/tmp/.X%d-lock", num);
Index: tigervnc-1.4.3/vncviewer/vncviewer.cxx
===================================================================
--- tigervnc-1.4.3.orig/vncviewer/vncviewer.cxx
+++ tigervnc-1.4.3/vncviewer/vncviewer.cxx
@@ -488,15 +488,45 @@ int main(int argc, char** argv)
 #endif
 
   if (listenMode) {
+    std::list<TcpListener> listeners;
     try {
       int port = 5500;
       if (isdigit(vncServerName[0]))
         port = atoi(vncServerName);
 
-      TcpListener listener(NULL, port);
+      createTcpListeners(&listeners, 0, port);
 
       vlog.info(_("Listening on port %d\n"), port);
-      sock = listener.accept();   
+
+      /* Wait for a connection */
+      while (sock == NULL) {
+        fd_set rfds;
+        FD_ZERO(&rfds);
+        for (std::list<TcpListener>::iterator i = listeners.begin();
+             i != listeners.end();
+             i++)
+          FD_SET((*i).getFd(), &rfds);
+
+        int n = select(FD_SETSIZE, &rfds, 0, 0, 0);
+        if (n < 0) {
+          if (errno == EINTR) {
+            vlog.debug("Interrupted select() system call");
+            continue;
+          } else {
+            throw rdr::SystemException("select", errno);
+          }
+        }
+
+        for (std::list<TcpListener>::iterator i = listeners.begin ();
+             i != listeners.end();
+             i++)
+          if (FD_ISSET((*i).getFd(), &rfds)) {
+            sock = (*i).accept();
+            if (sock)
+              /* Got a connection */
+              break;
+          }
+      }
     } catch (rdr::Exception& e) {
       vlog.error("%s", e.str());
       fl_alert("%s", e.str());
