]> source.dussan.org Git - tigervnc.git/commitdiff
Fixed IPv6 support.
authorTim Waugh <twaugh@redhat.com>
Wed, 11 Mar 2015 13:12:07 +0000 (13:12 +0000)
committerTim Waugh <twaugh@redhat.com>
Fri, 13 Mar 2015 16:19:50 +0000 (16:19 +0000)
The TcpListener constructor now takes a 'struct sockaddr*' instead of
a string, and the createTcpListeners function creates TcpListener
instances for an address based on the results from getaddrinfo().

The XserverDesktop class now takes a list of TcpListener instances for
each of the RFB and HTTP sockets.

The TcpListener::closeFd member variable is not used and has been
removed.

common/network/TcpSocket.cxx
common/network/TcpSocket.h
unix/x0vncserver/x0vncserver.cxx
unix/xserver/hw/vnc/RFBGlue.cc
unix/xserver/hw/vnc/XserverDesktop.cc
unix/xserver/hw/vnc/XserverDesktop.h
unix/xserver/hw/vnc/vncExtInit.cc
vncviewer/vncviewer.cxx

index 80b26b1cecb22ab930e09284aff8376be9e54e14..188651edc69155e0f5bd5e2ae07fb3bab9c56f89 100644 (file)
@@ -34,7 +34,6 @@
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <netdb.h>
-#include <unistd.h>
 #include <errno.h>
 #include <string.h>
 #include <signal.h>
@@ -42,6 +41,7 @@
 #endif
 
 #include <stdlib.h>
+#include <unistd.h>
 #include <network/TcpSocket.h>
 #include <rfb/util.h>
 #include <rfb/LogWriter.h>
@@ -274,16 +274,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("");
     }
@@ -426,139 +427,77 @@ int TcpSocket::getSockPort(int sock)
   }
 }
 
-static int bindIPv6 (const char *listenaddr,
-                    int port,
-                    bool localhostOnly)
+TcpListener::TcpListener(int sock)
 {
-#ifdef HAVE_GETADDRINFO
-  struct sockaddr_in6 addr6;
-  socklen_t sa_len;
-  int fd;
-
-  if (!UseIPv6)
-    return -1;
-
-  if ((fd = socket(AF_INET6, SOCK_STREAM, 0)) < 0)
-    return -1;
-
-#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, (char *)&opt, sizeof(opt));
-#else
-  vlog.error("IPV6_V6ONLY support is missing. "
-            "IPv4 clients may not be able to connect.");
-#endif
+  fd = sock;
+}
 
-  memset(&addr6, 0, (sa_len = sizeof(addr6)));
-  addr6.sin6_family = AF_INET6;
-  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) {
-      closesocket(fd);
-      return -1;
-    }
-#else
-    // Unable to parse without inet_pton
-    closesocket(fd);
-    return -1;
-#endif
-  }
+TcpListener::TcpListener(const TcpListener& other)
+{
+  fd = dup (other.fd);
+  // Hope TcpListener::shutdown(other) doesn't get called...
+}
 
-  if (bind(fd, (struct sockaddr *) &addr6, sa_len) == -1) {
-    closesocket(fd);
-    return -1;
+TcpListener& TcpListener::operator= (const TcpListener& other)
+{
+  if (this != &other)
+  {
+    closesocket (fd);
+    fd = dup (other.fd);
+    // Hope TcpListener::shutdown(other) doesn't get called...
   }
-
-  return fd;
-#else
-  return -1;
-#endif /* HAVE_GETADDRINFO */
+  return *this;
 }
 
-static int bindIPv4 (const char *listenaddr,
-                    int port,
-                    bool localhostOnly)
+TcpListener::TcpListener(const struct sockaddr *listenaddr,
+                         socklen_t listenaddrlen)
 {
-  struct sockaddr_in addr;
-  socklen_t sa_len;
-  int fd;
-
-  if (!UseIPv4)
-    return -1;
-
-  if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
-    return -1;
+  int one = 1;
+  vnc_sockaddr_t sa;
+  int sock;
 
-  memset(&addr, 0, (sa_len = sizeof(addr)));
-  addr.sin_family = AF_INET;
-  addr.sin_port = htons(port);
+  initSockets();
 
-  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);
+  if ((sock = socket (listenaddr->sa_family, SOCK_STREAM, 0)) < 0)
+    throw SocketException("unable to create listening socket", errorNumber);
 
-  if (bind(fd, (struct sockaddr *) &addr, sa_len) == -1) {
-    closesocket(fd);
-    return -1;
+  memcpy (&sa, listenaddr, listenaddrlen);
+#ifdef IPV6_V6ONLY
+  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) */
 
-  return fd;
-}
-
-TcpListener::TcpListener(const char *listenaddr, int port, bool localhostOnly,
-                        int sock, bool close_) : closeFd(close_)
-{
-  if (sock != -1) {
-    fd = sock;
-    return;
+  if (bind(sock, &sa.u.sa, listenaddrlen) == -1) {
+    closesocket(sock);
+    throw SocketException("failed to bind socket", errorNumber);
   }
 
-  initSockets();
-  if ((fd = bindIPv6 (listenaddr, port, localhostOnly)) < 0)
-    if ((fd = bindIPv4 (listenaddr, port, localhostOnly)) < 0)
-      throw SocketException("unable to create listening 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
 
   // - 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()
@@ -596,46 +535,160 @@ 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
+  if (UseIPv6) {
+    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 */
+  if (UseIPv4) {
+    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;
+  snprintf (service, sizeof (service) - 1, "%d", port);
+  service[sizeof (service) - 1] = '\0';
+  if ((getaddrinfo(addr, service, &hints, &ai)) != 0)
+    throw rdr::SystemException("getaddrinfo", errorNumber);
 
-  for (current= ai; current != NULL; current = current->ai_next) {
-    if (current->ai_family != AF_INET && current->ai_family != AF_INET6)
+  for (current = ai; current != NULL; current = current->ai_next) {
+    switch (current->ai_family) {
+    case AF_INET:
+      if (!UseIPv4)
+        continue;
+      break;
+
+    case AF_INET6:
+      if (!UseIPv6)
+        continue;
+      break;
+
+    default:
       continue;
+    }
 
-    char *addr = new char[INET6_ADDRSTRLEN];
-    inet_ntop(current->ai_family, current->ai_addr, addr, INET6_ADDRSTRLEN);
-    result->push_back(addr);
+    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
-  const hostent* addrs = gethostbyname(0);
-  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 b0bba53beddf196d8d7fd90642b1fee0712f7fca..e62738900c7f7eb3680baaad36bd3788808e0b05 100644 (file)
@@ -29,6 +29,7 @@
 #define __NETWORK_TCP_SOCKET_H__
 
 #include <network/Socket.h>
+#include <sys/socket.h>
 
 #include <list>
 
@@ -66,20 +67,24 @@ 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;
   };
 
+  void createLocalTcpListeners(std::list<TcpListener> *listeners,
+                               int port);
+  void createTcpListeners(std::list<TcpListener> *listeners,
+                          const char *addr,
+                          int port);
+
   class TcpFilter : public ConnectionFilter {
   public:
     TcpFilter(const char* filter);
index a9b328fe9dcc1cf31a22daaece67a370be319269..2d9a06656fcc2810ca3b78701155318ca3a6d554 100644 (file)
@@ -477,6 +477,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)),
@@ -491,13 +493,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);
@@ -513,7 +518,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++) {
@@ -558,12 +567,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 53d5bdb0aafce4d9eafdb40e390f426fbab9c572..19338fc70d79bef436fd9d29227949e5412fb72a 100644 (file)
@@ -187,7 +187,10 @@ int vncGetSocketPort(int fd)
 int vncIsTCPPortUsed(int port)
 {
   try {
-    network::TcpListener l(NULL, port);
+    // 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, port);
   } catch (rdr::Exception& e) {
     return 0;
   }
index 54e09cb57cc3ed262a043c1b19c384757cbfb45e..165afbb64a692fb0e94a03fa8283989b3e9ac0f7 100644 (file)
@@ -91,14 +91,14 @@ public:
 
 
 XserverDesktop::XserverDesktop(int screenIndex_,
-                               network::TcpListener* listener_,
-                               network::TcpListener* httpListener_,
+                               std::list<network::TcpListener> listeners_,
+                               std::list<network::TcpListener> httpListeners_,
                                const char* name, const rfb::PixelFormat &pf,
                                int width, int height,
                                void* fbptr, int stride)
   : screenIndex(screenIndex_),
     server(0), httpServer(0),
-    listener(listener_), httpListener(httpListener_),
+    listeners(listeners_), httpListeners(httpListeners_),
     deferredUpdateTimerSet(false), directFbptr(true),
     queryConnectId(0)
 {
@@ -108,7 +108,7 @@ XserverDesktop::XserverDesktop(int screenIndex_,
   setFramebuffer(width, height, fbptr, stride);
   server->setQueryConnectionHandler(this);
 
-  if (httpListener)
+  if (!httpListeners.empty ())
     httpServer = new FileHTTPServer(this);
 }
 
@@ -222,7 +222,7 @@ char* XserverDesktop::substitute(const char* varName)
   }
   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) {
@@ -393,14 +393,18 @@ void XserverDesktop::readBlockHandler(fd_set* fds, struct timeval ** timeout)
 
     // 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()) {
@@ -452,20 +456,24 @@ void XserverDesktop::readWakeupHandler(fd_set* fds, int nfds)
     // 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 7dcaa29e455042d0321eef77d4eedaa34802abab..6909a766bfcc6927d9cd0b1d11f5979aa01a30f6 100644 (file)
@@ -50,8 +50,9 @@ class XserverDesktop : public rfb::SDesktop, public rfb::FullFramePixelBuffer,
                        public rfb::VNCServerST::QueryConnectionHandler {
 public:
 
-  XserverDesktop(int screenIndex, network::TcpListener* listener,
-                 network::TcpListener* httpListener_,
+  XserverDesktop(int screenIndex,
+                 std::list<network::TcpListener> listeners_,
+                 std::list<network::TcpListener> httpListeners_,
                  const char* name, const rfb::PixelFormat &pf,
                  int width, int height, void* fbptr, int stride);
   virtual ~XserverDesktop();
@@ -112,8 +113,8 @@ private:
   int screenIndex;
   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 directFbptr;
   struct timeval dixTimeout;
index 2277783904fcdd228587fe48a27ffb7a14338b3c..e307e31947068669dcfac5b7010b6a9d969eabe4 100644 (file)
@@ -134,33 +134,44 @@ void vncExtensionInit(void)
     for (int scr = 0; scr < vncGetScreenCount(); 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 {
+          const char *addr = interface;
           int port = rfbport;
           if (port == 0) port = 5900 + atoi(vncGetDisplay());
           port += 1000 * scr;
-          if (strcasecmp(interface, "all") == 0)
-            listener = new network::TcpListener(NULL, port, localhostOnly);
+          if (strcasecmp(addr, "all") == 0)
+            addr = 0;
+          if (localhostOnly)
+            network::createLocalTcpListeners(&listeners, port);
           else
-            listener = new network::TcpListener(interface, port, localhostOnly);
+            network::createTcpListeners(&listeners, addr, port);
+
           vlog.info("Listening for VNC connections on %s interface(s), port %d",
-                    (const char*)interface, port);
+                    localhostOnly ? "local" : (const char*)interface,
+                    port);
+
           CharArray httpDirStr(httpDir.getData());
           if (httpDirStr.buf[0]) {
             port = httpPort;
             if (port == 0) port = 5800 + atoi(vncGetDisplay());
             port += 1000 * scr;
-            httpListener = new network::TcpListener(interface, port, localhostOnly);
+            if (localhostOnly)
+              network::createLocalTcpListeners(&httpListeners, port);
+            else
+              network::createTcpListeners(&httpListeners, addr, port);
+
             vlog.info("Listening for HTTP connections on %s interface(s), port %d",
-                      (const char*)interface, port);
+                      localhostOnly ? "local" : (const char*)interface,
+                      port);
           }
         }
 
@@ -168,8 +179,8 @@ void vncExtensionInit(void)
         PixelFormat pf = vncGetPixelFormat(scr);
 
         desktop[scr] = new XserverDesktop(scr,
-                                          listener,
-                                          httpListener,
+                                          listeners,
+                                          httpListeners,
                                           desktopNameStr.buf,
                                           pf,
                                           vncGetScreenWidth(scr),
@@ -178,7 +189,7 @@ void vncExtensionInit(void)
                                           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 3f51dd3c49c21d783d386c4d218e76d4c9752472..876e9142e9ffb07ea6853755a911c5cea9f48ddd 100644 (file)
@@ -534,15 +534,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());