Index: trunk/src/VBox/Main/webservice/vboxweb.cpp
===================================================================
--- trunk/src/VBox/Main/webservice/vboxweb.cpp	(revision 104178)
+++ trunk/src/VBox/Main/webservice/vboxweb.cpp	(revision 104205)
@@ -140,5 +140,5 @@
 static const char       *g_pcszBindToHost = NULL;       // host; NULL = localhost
 static unsigned int     g_uBindToPort = 18083;          // port
-static unsigned int     g_uBacklog = 100;               // backlog = max queue size for requests
+static unsigned int     g_uBacklog = 100;               // backlog = max queue size for connections
 
 #ifdef WITH_OPENSSL
@@ -307,5 +307,5 @@
 
             case 'k':
-                pcszDescr = "Maximum number of requests before a socket will be closed (100).";
+                pcszDescr = "Maximum number of requests before a connection will be closed (100).";
                 break;
 
@@ -362,28 +362,11 @@
      * @param u Thread number. (So we can count from 1 and be readable.)
      * @param q SoapQ instance which has the queue to process.
-     * @param soap struct soap instance from main() which we copy here.
      */
     SoapThread(size_t u,
-               SoapQ &q,
-               const struct soap *soap)
+               SoapQ &q)
         : m_u(u),
-          m_strThread(com::Utf8StrFmt("SQW%02d", m_u)),
           m_pQ(&q)
     {
-        // make a copy of the soap struct for the new thread
-        m_soap = soap_copy(soap);
-        m_soap->fget = fnHttpGet;
-
-        /* The soap.max_keep_alive value can be set to the maximum keep-alive calls allowed,
-         * which is important to avoid a client from holding a thread indefinitely.
-         * http://www.cs.fsu.edu/~engelen/soapdoc2.html#sec:keepalive
-         *
-         * Strings with 8-bit content can hold ASCII (default) or UTF8. The latter is
-         * possible by enabling the SOAP_C_UTFSTRING flag.
-         */
-        soap_set_omode(m_soap, SOAP_IO_KEEPALIVE | SOAP_C_UTFSTRING);
-        soap_set_imode(m_soap, SOAP_IO_KEEPALIVE | SOAP_C_UTFSTRING);
-        m_soap->max_keep_alive = g_cMaxKeepAlive;
-
+         m_strThread = com::Utf8StrFmt("SQW%02d", m_u);
         int vrc = RTThreadCreate(&m_pThread,
                                  fntWrapper,
@@ -432,5 +415,4 @@
     com::Utf8Str    m_strThread;    // thread name ("SoapQWrkXX")
     SoapQ           *m_pQ;          // the single SOAP queue that all the threads service
-    struct soap     *m_soap;        // copy of the soap structure for this thread (from soap_copy())
     RTTHREAD        m_pThread;      // IPRT thread struct for this thread
 };
@@ -447,9 +429,7 @@
     /**
      * Constructor. Creates the soap queue.
-     * @param pSoap
      */
-    SoapQ(const struct soap *pSoap)
-        : m_soap(pSoap),
-          m_mutex(util::LOCKCLASS_OBJECTSTATE),     // lowest lock order, no other may be held while this is held
+    SoapQ()
+        : m_mutex(util::LOCKCLASS_OBJECTSTATE),     // lowest lock order, no other may be held while this is held
           m_cIdleThreads(0)
     {
@@ -475,14 +455,27 @@
 
         RTSemEventMultiDestroy(m_event);
+
+        while (!m_llSocketsQ.empty())
+        {
+            struct soap *pSoap = m_llSocketsQ.front();
+            m_llSocketsQ.pop_front();
+
+            if (pSoap == NULL || !soap_valid_socket(pSoap->socket))
+                continue;
+
+            soap_destroy(pSoap); // clean up class instances
+            soap_end(pSoap); // clean up everything and close socket
+            soap_free(pSoap); // free soap connection
+        }
     }
 
     /**
-     * Adds the given socket to the SOAP queue and posts the
+     * Adds the given soap connection to the SOAP queue and posts the
      * member event sem to wake up the workers. Called on the main thread
-     * whenever a socket has work to do. Creates a new SOAP thread on the
+     * whenever a connection comes in. Creates a new SOAP thread on the
      * first call or when all existing threads are busy.
-     * @param s Socket from soap_accept() which has work to do.
+     * @param pSoap connection
      */
-    size_t add(SOAP_SOCKET s)
+    size_t add(const struct soap *pSoap)
     {
         size_t cItems;
@@ -497,6 +490,5 @@
         {
             SoapThread *pst = new SoapThread(m_llAllThreads.size() + 1,
-                                             *this,
-                                             m_soap);
+                                             *this);
             m_llAllThreads.push_back(pst);
             util::AutoWriteLock thrLock(g_pThreadsLockHandle COMMA_LOCKVAL_SRC_POS);
@@ -505,7 +497,7 @@
         }
 
-        // enqueue the socket of this connection and post eventsem so that
-        // one of the threads (possibly the one just created) can pick it up
-        m_llSocketsQ.push_back(s);
+        // enqueue this connection and post eventsem so that one of the threads
+        // (possibly the one just created) can pick it up
+        m_llSocketsQ.push_back(soap_copy(pSoap));
         cItems = m_llSocketsQ.size();
         qlock.release();
@@ -519,5 +511,5 @@
     /**
      * Blocks the current thread until work comes in; then returns
-     * the SOAP socket which has work to do. This reduces m_cIdleThreads
+     * the SOAP connection which has work to do. This reduces m_cIdleThreads
      * by one, and the caller MUST call done() when it's done processing.
      * Called from the worker threads.
@@ -526,5 +518,5 @@
      * @return
      */
-    SOAP_SOCKET get(size_t &cIdleThreads, size_t &cThreads)
+    struct soap *get(size_t &cIdleThreads, size_t &cThreads)
     {
         while (g_fKeepRunning)
@@ -539,5 +531,5 @@
             if (!m_llSocketsQ.empty())
             {
-                SOAP_SOCKET socket = m_llSocketsQ.front();
+                struct soap *pSoap = m_llSocketsQ.front();
                 m_llSocketsQ.pop_front();
                 cIdleThreads = --m_cIdleThreads;
@@ -552,10 +544,10 @@
                 qlock.release();
 
-                return socket;
+                return pSoap;
             }
 
             // nothing to do: keep looping
         }
-        return SOAP_INVALID_SOCKET;
+        return NULL;
     }
 
@@ -572,5 +564,5 @@
     /**
      * To be called by a worker thread when signing off, i.e. no longer
-     * willing to process requests.
+     * willing to process SOAP connections.
      */
     void signoff(SoapThread *th)
@@ -588,6 +580,4 @@
     }
 
-    const struct soap       *m_soap;            // soap structure created by main(), passed to constructor
-
     util::WriteLockHandle   m_mutex;
     RTSEMEVENTMULTI         m_event;            // posted by add(), blocked on by get()
@@ -597,6 +587,6 @@
 
     // A std::list abused as a queue; this contains the actual jobs to do,
-    // each int being a socket from soap_accept()
-    std::list<SOAP_SOCKET>  m_llSocketsQ;
+    // each entry being a connection from soap_accept() passed through SoapQ::add.
+    std::list<struct soap *>  m_llSocketsQ;
 };
 
@@ -604,6 +594,6 @@
  * Thread function for each of the SOAP queue worker threads. This keeps
  * running, blocks on the event semaphore in SoapThread.SoapQ and picks
- * up a socket from the queue therein, which has been put there by
- * beginProcessing().
+ * up a connection from the queue therein, which has been put there by
+ * SoapQ::add().
  */
 void SoapThread::process()
@@ -613,37 +603,52 @@
     while (g_fKeepRunning)
     {
-        // wait for a socket to arrive on the queue
+        // wait for a job to arrive on the queue
         size_t cIdleThreads = 0, cThreads = 0;
-        m_soap->socket = m_pQ->get(cIdleThreads, cThreads);
-
-        if (!soap_valid_socket(m_soap->socket))
+        struct soap *pSoap = m_pQ->get(cIdleThreads, cThreads);
+
+        if (pSoap == NULL || !soap_valid_socket(pSoap->socket))
             continue;
 
+        pSoap->fget = fnHttpGet;
+
+        /* The soap.max_keep_alive value can be set to the maximum keep-alive calls allowed,
+         * which is important to avoid a client from holding a thread indefinitely.
+         * http://www.cs.fsu.edu/~engelen/soapdoc2.html#sec:keepalive
+         *
+         * Strings with 8-bit content can hold ASCII (default) or UTF8. The latter is
+         * possible by enabling the SOAP_C_UTFSTRING flag.
+         */
+        soap_set_omode(pSoap, SOAP_IO_KEEPALIVE | SOAP_C_UTFSTRING);
+        soap_set_imode(pSoap, SOAP_IO_KEEPALIVE | SOAP_C_UTFSTRING);
+        pSoap->max_keep_alive = g_cMaxKeepAlive;
+
         LogRel(("Processing connection from IP=%RTnaipv4 socket=%d (%d out of %d threads idle)\n",
-                RT_H2N_U32(m_soap->ip), m_soap->socket, cIdleThreads, cThreads));
+                RT_H2N_U32(pSoap->ip), pSoap->socket, cIdleThreads, cThreads));
 
         // Ensure that we don't get stuck indefinitely for connections using
         // keepalive, otherwise stale connections tie up worker threads.
-        m_soap->send_timeout = 60;
-        m_soap->recv_timeout = 60;
+        pSoap->send_timeout = 60;
+        pSoap->recv_timeout = 60;
         // Limit the maximum SOAP request size to a generous amount, just to
         // be on the safe side (SOAP is quite wordy when representing arrays,
         // and some API uses need to deal with large arrays). Good that binary
         // data is no longer represented by byte arrays...
-        m_soap->recv_maxlength = _16M;
+        pSoap->recv_maxlength = _16M;
         // process the request; this goes into the COM code in methodmaps.cpp
+
         do {
 #ifdef WITH_OPENSSL
-            if (g_fSSL && soap_ssl_accept(m_soap))
+            if (g_fSSL && soap_ssl_accept(pSoap))
             {
-                WebLogSoapError(m_soap);
+                WebLogSoapError(pSoap);
                 break;
             }
 #endif /* WITH_OPENSSL */
-            soap_serve(m_soap);
+            soap_serve(pSoap);
         } while (0);
 
-        soap_destroy(m_soap); // clean up class instances
-        soap_end(m_soap); // clean up everything and close socket
+        soap_destroy(pSoap); // clean up class instances
+        soap_end(pSoap); // clean up everything and close connection
+        soap_free(pSoap); // free soap connection
 
         // tell the queue we're idle again
@@ -909,4 +914,5 @@
 #endif /* WITH_OPENSSL */
 
+    soap.accept_timeout = 60;
     soap.bind_flags |= SO_REUSEADDR;
             // avoid EADDRINUSE on bind()
@@ -916,5 +922,5 @@
                   g_pcszBindToHost ? g_pcszBindToHost : "localhost",    // safe default host
                   g_uBindToPort,    // port
-                  g_uBacklog);      // backlog = max queue size for requests
+                  g_uBacklog);      // backlog = max queue size for connections
     if (m == SOAP_INVALID_SOCKET)
         WebLogSoapError(&soap);
@@ -931,53 +937,21 @@
 
         // initialize thread queue, mutex and eventsem
-        g_pSoapQ = new SoapQ(&soap);
+        g_pSoapQ = new SoapQ();
 
         uint64_t cAccepted = 1;
         while (g_fKeepRunning)
         {
-            struct timeval timeout;
-            fd_set ReadFds, WriteFds, XcptFds;
-            int rv;
-            for (;;)
-            {
-                timeout.tv_sec = 60;
-                timeout.tv_usec = 0;
-                FD_ZERO(&ReadFds);
-                FD_SET(soap.master, &ReadFds);
-                FD_ZERO(&WriteFds);
-                FD_SET(soap.master, &WriteFds);
-                FD_ZERO(&XcptFds);
-                FD_SET(soap.master, &XcptFds);
-                rv = select((int)soap.master + 1, &ReadFds, &WriteFds, &XcptFds, &timeout);
-                if (rv > 0)
-                    break; // work is waiting
-                if (rv == 0)
-                    continue; // timeout, not necessary to bother gsoap
-                // r < 0, errno
-#if GSOAP_VERSION >= 208103
-                if (soap_socket_errno == SOAP_EINTR)
-#else
-                if (soap_socket_errno(soap.master) == SOAP_EINTR)
-#endif
-                    rv = 0; // re-check if we should terminate
-                break;
-            }
-            if (rv == 0)
-                continue;
-
-            // call gSOAP to handle incoming SOAP connection
-            soap.accept_timeout = -1; // 1usec timeout, actual waiting is above
             s = soap_accept(&soap);
             if (!soap_valid_socket(s))
             {
-                if (soap.errnum)
+                if (soap.errnum != SOAP_EINTR)
                     WebLogSoapError(&soap);
                 continue;
             }
 
-            // add the socket to the queue and tell worker threads to
+            // add the connection to the queue and tell worker threads to
             // pick up the job
-            size_t cItemsOnQ = g_pSoapQ->add(s);
-            LogRel(("Request %llu on socket %d queued for processing (%d items on Q)\n", cAccepted, s, cItemsOnQ));
+            size_t cItemsOnQ = g_pSoapQ->add(&soap);
+            LogRel(("Connection %llu on socket %d queued for processing (%d items on Q)\n", cAccepted, s, cItemsOnQ));
             cAccepted++;
         }
@@ -986,8 +960,5 @@
         g_pSoapQ = NULL;
 
-        LogRel(("ending SOAP request handling\n"));
-
-        delete g_pSoapQ;
-        g_pSoapQ = NULL;
+        LogRel(("Ending SOAP connection handling\n"));
 
     }
@@ -1002,5 +973,5 @@
 /**
  * Thread function for the "queue pumper" thread started from main(). This implements
- * the loop that takes SOAP calls from HTTP and serves them by handing sockets to the
+ * the loop that takes SOAP calls from HTTP and serves them by handing connections to the
  * SOAP queue worker threads.
  */
