Return TcpListener pointers rather than objects

It is easier to control object life time and avoid magical socket
duplication by having a single TcpListener object to pass around.
We have to be more careful about deleting the object though.
diff --git a/common/network/TcpSocket.cxx b/common/network/TcpSocket.cxx
index a25ee24..5a8f75d 100644
--- a/common/network/TcpSocket.cxx
+++ b/common/network/TcpSocket.cxx
@@ -118,23 +118,6 @@
 }
 
 
-// -=- Socket duplication help for Windows
-static int dupsocket(int fd)
-{
-#ifdef WIN32
-  int ret;
-  WSAPROTOCOL_INFO info;
-  ret = WSADuplicateSocket(fd, GetCurrentProcessId(), &info);
-  if (ret != 0)
-    throw SocketException("unable to duplicate socket", errorNumber);
-  return WSASocket(info.iAddressFamily, info.iSocketType, info.iProtocol,
-                   &info, 0, 0);
-#else
-  return dup(fd);
-#endif
-}
-
-
 // -=- TcpSocket
 
 TcpSocket::TcpSocket(int sock, bool close)
@@ -411,23 +394,6 @@
   fd = sock;
 }
 
-TcpListener::TcpListener(const TcpListener& other)
-{
-  fd = dupsocket (other.fd);
-  // Hope TcpListener::shutdown(other) doesn't get called...
-}
-
-TcpListener& TcpListener::operator= (const TcpListener& other)
-{
-  if (this != &other)
-  {
-    closesocket (fd);
-    fd = dupsocket (other.fd);
-    // Hope TcpListener::shutdown(other) doesn't get called...
-  }
-  return *this;
-}
-
 TcpListener::TcpListener(const struct sockaddr *listenaddr,
                          socklen_t listenaddrlen)
 {
@@ -570,57 +536,41 @@
 }
 
 
-void network::createLocalTcpListeners(std::list<TcpListener> *listeners,
+void network::createLocalTcpListeners(std::list<TcpListener*> *listeners,
                                       int port)
 {
-  std::list<TcpListener> new_listeners;
-  vnc_sockaddr_t sa;
+  struct addrinfo ai[2];
+  vnc_sockaddr_t sa[2];
 
-  initSockets();
+  memset(ai, 0, sizeof(ai));
+  memset(sa, 0, sizeof(sa));
 
-  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;
-    }
-  }
-  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;
-    }
-  }
+  sa[0].u.sin.sin_family = AF_INET;
+  sa[0].u.sin.sin_port = htons (port);
+  sa[0].u.sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
 
-  if (new_listeners.empty ())
-    throw SocketException("createLocalTcpListeners: no addresses available",
-                          EADDRNOTAVAIL);
+  ai[0].ai_family = sa[0].u.sin.sin_family;
+  ai[0].ai_addr = &sa[0].u.sa;
+  ai[0].ai_addrlen = sizeof(sa[0].u.sin);
+  ai[0].ai_next = &ai[1];
 
-  listeners->splice (listeners->end(), new_listeners);
+  sa[1].u.sin6.sin6_family = AF_INET6;
+  sa[1].u.sin6.sin6_port = htons (port);
+  sa[1].u.sin6.sin6_addr = in6addr_loopback;
+
+  ai[1].ai_family = sa[1].u.sin6.sin6_family;
+  ai[1].ai_addr = &sa[1].u.sa;
+  ai[1].ai_addrlen = sizeof(sa[1].u.sin6);
+  ai[1].ai_next = NULL;
+
+  createTcpListeners(listeners, ai);
 }
 
-void network::createTcpListeners(std::list<TcpListener> *listeners,
+void network::createTcpListeners(std::list<TcpListener*> *listeners,
                                  const char *addr,
                                  int port)
 {
-  std::list<TcpListener> new_listeners;
-
-  struct addrinfo *ai, *current, hints;
+  struct addrinfo *ai, hints;
   char service[16];
   int result;
 
@@ -640,6 +590,22 @@
     throw rdr::Exception("unable to resolve listening address: %s",
                          gai_strerror(result));
 
+  try {
+    createTcpListeners(listeners, ai);
+  } catch(...) {
+    freeaddrinfo(ai);
+    throw;
+  }
+}
+
+void network::createTcpListeners(std::list<TcpListener*> *listeners,
+                                 const struct addrinfo *ai)
+{
+  const struct addrinfo *current;
+  std::list<TcpListener*> new_listeners;
+
+  initSockets();
+
   for (current = ai; current != NULL; current = current->ai_next) {
     switch (current->ai_family) {
     case AF_INET:
@@ -657,19 +623,21 @@
     }
 
     try {
-      new_listeners.push_back(TcpListener (current->ai_addr,
-                                           current->ai_addrlen));
+      new_listeners.push_back(new 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);
+        while (!new_listeners.empty()) {
+          delete new_listeners.back();
+          new_listeners.pop_back();
+        }
         throw;
       }
     }
   }
-  freeaddrinfo(ai);
 
   if (new_listeners.empty ())
     throw SocketException("createTcpListeners: no addresses available",
diff --git a/common/network/TcpSocket.h b/common/network/TcpSocket.h
index 979cd4b..02f04c9 100644
--- a/common/network/TcpSocket.h
+++ b/common/network/TcpSocket.h
@@ -76,8 +76,6 @@
   public:
     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();
@@ -87,11 +85,13 @@
     int getMyPort();
   };
 
-  void createLocalTcpListeners(std::list<TcpListener> *listeners,
+  void createLocalTcpListeners(std::list<TcpListener*> *listeners,
                                int port);
-  void createTcpListeners(std::list<TcpListener> *listeners,
+  void createTcpListeners(std::list<TcpListener*> *listeners,
                           const char *addr,
                           int port);
+  void createTcpListeners(std::list<TcpListener*> *listeners,
+                          const struct addrinfo *ai);
 
   typedef struct vnc_sockaddr {
     union {
diff --git a/unix/x0vncserver/x0vncserver.cxx b/unix/x0vncserver/x0vncserver.cxx
index 2d9a066..6b5d479 100644
--- a/unix/x0vncserver/x0vncserver.cxx
+++ b/unix/x0vncserver/x0vncserver.cxx
@@ -477,7 +477,7 @@
   signal(SIGINT, CleanupSignalHandler);
   signal(SIGTERM, CleanupSignalHandler);
 
-  std::list<TcpListener> listeners;
+  std::list<TcpListener*> listeners;
 
   try {
     TXWindow::init(dpy,"x0vncserver");
@@ -499,10 +499,10 @@
     const char *hostsData = hostsFile.getData();
     FileTcpFilter fileTcpFilter(hostsData);
     if (strlen(hostsData) != 0)
-      for (std::list<TcpListener>::iterator i = listeners.begin();
+      for (std::list<TcpListener*>::iterator i = listeners.begin();
            i != listeners.end();
            i++)
-        (*i).setFilter(&fileTcpFilter);
+        (*i)->setFilter(&fileTcpFilter);
     delete[] hostsData;
 
     PollingScheduler sched((int)pollingCycle, (int)maxProcessorUsage);
@@ -518,10 +518,10 @@
 
       FD_ZERO(&rfds);
       FD_SET(ConnectionNumber(dpy), &rfds);
-      for (std::list<TcpListener>::iterator i = listeners.begin();
+      for (std::list<TcpListener*>::iterator i = listeners.begin();
            i != listeners.end();
            i++)
-        FD_SET((*i).getFd(), &rfds);
+        FD_SET((*i)->getFd(), &rfds);
 
       server.getSockets(&sockets);
       int clients_connected = 0;
@@ -567,11 +567,11 @@
       }
 
       // Accept new VNC connections
-      for (std::list<TcpListener>::iterator i = listeners.begin();
+      for (std::list<TcpListener*>::iterator i = listeners.begin();
            i != listeners.end();
            i++) {
-        if (FD_ISSET((*i).getFd(), &rfds)) {
-          Socket* sock = (*i).accept();
+        if (FD_ISSET((*i)->getFd(), &rfds)) {
+          Socket* sock = (*i)->accept();
           if (sock) {
             server.addSocket(sock);
           } else {
diff --git a/unix/xserver/hw/vnc/RFBGlue.cc b/unix/xserver/hw/vnc/RFBGlue.cc
index a150792..9a014f1 100644
--- a/unix/xserver/hw/vnc/RFBGlue.cc
+++ b/unix/xserver/hw/vnc/RFBGlue.cc
@@ -190,9 +190,12 @@
 {
   try {
     // Attempt to create TCPListeners on that port.
-    // They go out of scope immediately and are destroyed.
-    std::list<network::TcpListener> dummy;
+    std::list<network::TcpListener*> dummy;
     network::createTcpListeners (&dummy, 0, port);
+    while (!dummy.empty()) {
+      delete dummy.back();
+      dummy.pop_back();
+    }
   } catch (rdr::Exception& e) {
     return 1;
   }
diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc
index 165afbb..9b91d9a 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.cc
+++ b/unix/xserver/hw/vnc/XserverDesktop.cc
@@ -91,8 +91,8 @@
 
 
 XserverDesktop::XserverDesktop(int screenIndex_,
-                               std::list<network::TcpListener> listeners_,
-                               std::list<network::TcpListener> httpListeners_,
+                               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)
@@ -114,6 +114,14 @@
 
 XserverDesktop::~XserverDesktop()
 {
+  while (!listeners.empty()) {
+    delete listeners.back();
+    listeners.pop_back();
+  }
+  while (!httpListeners.empty()) {
+    delete httpListeners.back();
+    httpListeners.pop_back();
+  }
   if (!directFbptr)
     delete [] data;
   delete httpServer;
@@ -222,7 +230,7 @@
   }
   if (strcmp(varName, "$PORT") == 0) {
     char* str = new char[10];
-    sprintf(str, "%d", listeners.empty () ? 0 : (*listeners.begin ()).getMyPort());
+    sprintf(str, "%d", listeners.empty () ? 0 : (*listeners.begin ())->getMyPort());
     return str;
   }
   if (strcmp(varName, "$WIDTH") == 0) {
@@ -393,14 +401,14 @@
 
     // Add all sockets we want read events for, after purging
     // any closed sockets.
-    for (std::list<network::TcpListener>::iterator i = listeners.begin();
+    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();
+      FD_SET((*i)->getFd(), fds);
+    for (std::list<network::TcpListener*>::iterator i = httpListeners.begin();
          i != httpListeners.end();
          i++)
-      FD_SET((*i).getFd(), fds);
+      FD_SET((*i)->getFd(), fds);
 
     std::list<Socket*> sockets;
     std::list<Socket*>::iterator i;
@@ -456,24 +464,24 @@
     // First check for file descriptors with something to do
     if (nfds >= 1) {
 
-      for (std::list<network::TcpListener>::iterator i = listeners.begin();
+      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();
+        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());
         }
       }
 
-      for (std::list<network::TcpListener>::iterator i = httpListeners.begin();
+      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();
+        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());
diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h
index 6909a76..c069028 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.h
+++ b/unix/xserver/hw/vnc/XserverDesktop.h
@@ -51,8 +51,8 @@
 public:
 
   XserverDesktop(int screenIndex,
-                 std::list<network::TcpListener> listeners_,
-                 std::list<network::TcpListener> httpListeners_,
+                 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();
@@ -113,8 +113,8 @@
   int screenIndex;
   rfb::VNCServerST* server;
   rfb::HTTPServer* httpServer;
-  std::list<network::TcpListener> listeners;
-  std::list<network::TcpListener> httpListeners;
+  std::list<network::TcpListener*> listeners;
+  std::list<network::TcpListener*> httpListeners;
   bool deferredUpdateTimerSet;
   bool directFbptr;
   struct timeval dixTimeout;
diff --git a/unix/xserver/hw/vnc/vncExtInit.cc b/unix/xserver/hw/vnc/vncExtInit.cc
index d9f989a..0ae55b6 100644
--- a/unix/xserver/hw/vnc/vncExtInit.cc
+++ b/unix/xserver/hw/vnc/vncExtInit.cc
@@ -134,13 +134,13 @@
     for (int scr = 0; scr < vncGetScreenCount(); scr++) {
 
       if (!desktop[scr]) {
-        std::list<network::TcpListener> listeners;
-        std::list<network::TcpListener> httpListeners;
+        std::list<network::TcpListener*> listeners;
+        std::list<network::TcpListener*> httpListeners;
         if (scr == 0 && vncInetdSock != -1) {
           if (network::TcpSocket::isSocket(vncInetdSock) &&
               !network::TcpSocket::isConnected(vncInetdSock))
           {
-            listeners.push_back (network::TcpListener(vncInetdSock));
+            listeners.push_back(new network::TcpListener(vncInetdSock));
             vlog.info("inetd wait");
           }
         } else {
diff --git a/vncviewer/vncviewer.cxx b/vncviewer/vncviewer.cxx
index 230cc25..a2bc029 100644
--- a/vncviewer/vncviewer.cxx
+++ b/vncviewer/vncviewer.cxx
@@ -525,7 +525,7 @@
 #endif
 
   if (listenMode) {
-    std::list<TcpListener> listeners;
+    std::list<TcpListener*> listeners;
     try {
       int port = 5500;
       if (isdigit(vncServerName[0]))
@@ -539,10 +539,10 @@
       while (sock == NULL) {
         fd_set rfds;
         FD_ZERO(&rfds);
-        for (std::list<TcpListener>::iterator i = listeners.begin();
+        for (std::list<TcpListener*>::iterator i = listeners.begin();
              i != listeners.end();
              i++)
-          FD_SET((*i).getFd(), &rfds);
+          FD_SET((*i)->getFd(), &rfds);
 
         int n = select(FD_SETSIZE, &rfds, 0, 0, 0);
         if (n < 0) {
@@ -554,11 +554,11 @@
           }
         }
 
-        for (std::list<TcpListener>::iterator i = listeners.begin ();
+        for (std::list<TcpListener*>::iterator i = listeners.begin ();
              i != listeners.end();
              i++)
-          if (FD_ISSET((*i).getFd(), &rfds)) {
-            sock = (*i).accept();
+          if (FD_ISSET((*i)->getFd(), &rfds)) {
+            sock = (*i)->accept();
             if (sock)
               /* Got a connection */
               break;
@@ -571,6 +571,10 @@
       return 1; 
     }
 
+    while (!listeners.empty()) {
+      delete listeners.back();
+      listeners.pop_back();
+    }
   } else {
     if (vncServerName[0] == '\0') {
       ServerDialog::run(defaultServerName, vncServerName);
diff --git a/win/winvnc/ManagedListener.cxx b/win/winvnc/ManagedListener.cxx
index 25d8dc0..b80f5a1 100644
--- a/win/winvnc/ManagedListener.cxx
+++ b/win/winvnc/ManagedListener.cxx
@@ -31,9 +31,9 @@
 
 ManagedListener::~ManagedListener() {
   if (!sockets.empty()) {
-    std::list<network::TcpListener>::iterator iter;
+    std::list<network::TcpListener*>::iterator iter;
     for (iter = sockets.begin(); iter != sockets.end(); ++iter)
-      manager->remListener(&*iter);
+      manager->remListener(*iter);
     sockets.clear();
   }
   delete filter;
@@ -62,9 +62,9 @@
   delete filter;
   filter = new network::TcpFilter(filterStr);
   if (!sockets.empty() && !localOnly) {
-    std::list<network::TcpListener>::iterator iter;
+    std::list<network::TcpListener*>::iterator iter;
     for (iter = sockets.begin(); iter != sockets.end(); ++iter)
-      iter->setFilter(filter);
+      (*iter)->setFilter(filter);
   }
 }
 
@@ -80,10 +80,10 @@
 }
 
 void ManagedListener::refresh() {
-  std::list<network::TcpListener>::iterator iter;
+  std::list<network::TcpListener*>::iterator iter;
   if (!sockets.empty()) {
     for (iter = sockets.begin(); iter != sockets.end(); ++iter)
-      manager->remListener(&*iter);
+      manager->remListener(*iter);
     sockets.clear();
   }
   if (!server)
@@ -101,11 +101,11 @@
   if (!sockets.empty()) {
     if (!localOnly) {
       for (iter = sockets.begin(); iter != sockets.end(); ++iter)
-        iter->setFilter(filter);
+        (*iter)->setFilter(filter);
     }
     try {
       for (iter = sockets.begin(); iter != sockets.end(); ++iter)
-        manager->addListener(&*iter, server, addrChangeNotifier);
+        manager->addListener(*iter, server, addrChangeNotifier);
     } catch (...) {
       // FIXME: Should unwind what we've added
       sockets.clear();
diff --git a/win/winvnc/ManagedListener.h b/win/winvnc/ManagedListener.h
index 1c7099f..e8d3c89 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::TcpListener*> sockets;
     network::TcpFilter* filter;
     rfb::win32::SocketManager* manager;
     rfb::win32::SocketManager::AddressChangeNotifier* addrChangeNotifier;