Index: /trunk/src/VBox/Main/webservice/vboxweb.cpp
===================================================================
--- /trunk/src/VBox/Main/webservice/vboxweb.cpp	(revision 35453)
+++ /trunk/src/VBox/Main/webservice/vboxweb.cpp	(revision 35454)
@@ -6,5 +6,5 @@
  *      server, to which clients can connect.
  *
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -22,7 +22,9 @@
 // vbox headers
 #include <VBox/com/com.h>
+#include <VBox/com/array.h>
 #include <VBox/com/ErrorInfo.h>
 #include <VBox/com/errorprint.h>
 #include <VBox/com/EventQueue.h>
+#include <VBox/com/listeners.h>
 #include <VBox/VBoxAuth.h>
 #include <VBox/version.h>
@@ -86,4 +88,5 @@
  ****************************************************************************/
 
+ComPtr<IVirtualBoxClient> g_pVirtualBoxClient = NULL;
 ComPtr<IVirtualBox>     g_pVirtualBox = NULL;
 
@@ -98,5 +101,5 @@
 int                     g_iWatchdogCheckInterval = 5;
 
-const char              *g_pcszBindToHost = NULL;       // host; NULL = current machine
+const char              *g_pcszBindToHost = NULL;       // host; NULL = localhost
 unsigned int            g_uBindToPort = 18083;          // port
 unsigned int            g_uBacklog = 100;               // backlog = max queue size for requests
@@ -125,4 +128,7 @@
 // this mutex protects the auth lib and authentication
 util::WriteLockHandle  *g_pAuthLibLockHandle;
+
+// this mutex protects the global VirtualBox reference
+util::RWLockHandle  *g_pVirtualBoxLockHandle;
 
 // this mutex protects all of the below
@@ -472,4 +478,77 @@
 }
 
+/****************************************************************************
+ *
+ * VirtualBoxClient event listener
+ *
+ ****************************************************************************/
+
+class VirtualBoxClientEventListener
+{
+public:
+    VirtualBoxClientEventListener()
+    {
+    }
+
+    virtual ~VirtualBoxClientEventListener()
+    {
+    }
+
+    STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent)
+    {
+        switch (aType)
+        {
+            case VBoxEventType_OnVBoxSVCAvailabilityChanged:
+            {
+                ComPtr<IVBoxSVCAvailabilityChangedEvent> pVSACEv = aEvent;
+                Assert(pVSACEv);
+                BOOL fAvailable = FALSE;
+                pVSACEv->COMGETTER(Available)(&fAvailable);
+                if (!fAvailable)
+                {
+                    WebLog("VBoxSVC became unavailable\n");
+                    {
+                        util::AutoWriteLock vlock(g_pVirtualBoxLockHandle COMMA_LOCKVAL_SRC_POS);
+                        g_pVirtualBox = NULL;
+                    }
+                    {
+                        // we're messing with sessions, so lock them
+                        util::AutoWriteLock lock(g_pSessionsLockHandle COMMA_LOCKVAL_SRC_POS);
+                        WEBDEBUG(("SVC unavailable: deleting %d sessions\n", g_mapSessions.size()));
+
+                        SessionsMap::iterator it = g_mapSessions.begin(),
+                                              itEnd = g_mapSessions.end();
+                        while (it != itEnd)
+                        {
+                            WebServiceSession *pSession = it->second;
+                            WEBDEBUG(("SVC unavailable: Session %llX stale, deleting\n", pSession->getID()));
+                            delete pSession;
+                            it = g_mapSessions.begin();
+                        }
+                    }
+                }
+                else
+                {
+                    WebLog("VBoxSVC became available\n");
+                    util::AutoWriteLock vlock(g_pVirtualBoxLockHandle COMMA_LOCKVAL_SRC_POS);
+                    HRESULT hrc = g_pVirtualBoxClient->COMGETTER(VirtualBox)(g_pVirtualBox.asOutParam());
+                    AssertComRC(hrc);
+                }
+                break;
+            }
+            default:
+                AssertFailed();
+        }
+
+        return S_OK;
+    }
+
+private:
+};
+
+typedef ListenerImpl<VirtualBoxClientEventListener> VirtualBoxClientEventListenerImpl;
+
+VBOX_LISTENER_DECLARE(VirtualBoxClientEventListenerImpl)
+
 /**
  * Implementation for WEBLOG macro defined in vboxweb.h; this prints a message
@@ -561,7 +640,7 @@
     int m, s; // master and slave sockets
     m = soap_bind(&soap,
-                  g_pcszBindToHost,     // host: current machine
-                  g_uBindToPort,     // port
-                  g_uBacklog);     // backlog = max queue size for requests
+                  g_pcszBindToHost ? g_pcszBindToHost : "localhost",    // safe default host
+                  g_uBindToPort,    // port
+                  g_uBacklog);      // backlog = max queue size for requests
     if (m < 0)
         WebLogSoapError(&soap);
@@ -624,5 +703,5 @@
  * @return
  */
-int main(int argc, char* argv[])
+int main(int argc, char *argv[])
 {
     // initialize runtime
@@ -648,5 +727,12 @@
         {
             case 'H':
-                g_pcszBindToHost = ValueUnion.psz;
+                if (!ValueUnion.psz || !*ValueUnion.psz)
+                {
+                    /* Normalize NULL/empty string to NULL, which will be
+                     * interpreted as "localhost" below. */
+                    g_pcszBindToHost = NULL;
+                }
+                else
+                    g_pcszBindToHost = ValueUnion.psz;
                 break;
 
@@ -723,18 +809,8 @@
         return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to initialize COM! hrc=%Rhrc\n", hrc);
 
-    ComPtr<ISession> session;
-
-    hrc = g_pVirtualBox.createLocalObject(CLSID_VirtualBox);
+    hrc = g_pVirtualBoxClient.createInprocObject(CLSID_VirtualBoxClient);
     if (FAILED(hrc))
-        RTMsgError("failed to create the VirtualBox object!");
-    else
-    {
-        hrc = session.createInprocObject(CLSID_Session);
-        if (FAILED(hrc))
-            RTMsgError("failed to create a session object!");
-    }
-
-    if (FAILED(hrc))
-    {
+    {
+        RTMsgError("failed to create the VirtualBoxClient object!");
         com::ErrorInfo info;
         if (!info.isFullAvailable() && !info.isBasicAvailable())
@@ -748,6 +824,25 @@
     }
 
+    hrc = g_pVirtualBoxClient->COMGETTER(VirtualBox)(g_pVirtualBox.asOutParam());
+    if (FAILED(hrc))
+    {
+        RTMsgError("Failed to get VirtualBox object (rc=%Rhrc)!", hrc);
+        return RTEXITCODE_FAILURE;
+    }
+
+    /* VirtualBoxClient events registration. */
+    IEventListener *vboxClientListener = NULL;
+    {
+        ComPtr<IEventSource> pES;
+        CHECK_ERROR(g_pVirtualBoxClient, COMGETTER(EventSource)(pES.asOutParam()));
+        vboxClientListener = new VirtualBoxClientEventListenerImpl();
+        com::SafeArray<VBoxEventType_T> eventTypes;
+        eventTypes.push_back(VBoxEventType_OnVBoxSVCAvailabilityChanged);
+        CHECK_ERROR(pES, RegisterListener(vboxClientListener, ComSafeArrayAsInParam(eventTypes), true));
+    }
+
     // create the global mutexes
     g_pAuthLibLockHandle = new util::WriteLockHandle(util::LOCKCLASS_WEBSERVICE);
+    g_pVirtualBoxLockHandle = new util::RWLockHandle(util::LOCKCLASS_WEBSERVICE);
     g_pSessionsLockHandle = new util::WriteLockHandle(util::LOCKCLASS_WEBSERVICE);
     g_pThreadsLockHandle = new util::RWLockHandle(util::LOCKCLASS_OBJECTSTATE);
@@ -788,4 +883,14 @@
         if (RT_FAILURE(rc))
             RTMsgError("processEventQueue -> %Rrc", rc);
+    }
+
+    /* VirtualBoxClient events unregistration. */
+    if (vboxClientListener)
+    {
+        ComPtr<IEventSource> pES;
+        CHECK_ERROR(g_pVirtualBoxClient, COMGETTER(EventSource)(pES.asOutParam()));
+        if (!pES.isNull())
+            CHECK_ERROR(pES, UnregisterListener(vboxClientListener));
+        vboxClientListener->Release();
     }
 
@@ -1124,7 +1229,16 @@
 
 int WebServiceSession::authenticate(const char *pcszUsername,
-                                    const char *pcszPassword)
+                                    const char *pcszPassword,
+                                    IVirtualBox **ppVirtualBox)
 {
     int rc = VERR_WEB_NOT_AUTHENTICATED;
+    ComPtr<IVirtualBox> pVirtualBox;
+    {
+        util::AutoReadLock vlock(g_pVirtualBoxLockHandle COMMA_LOCKVAL_SRC_POS);
+        pVirtualBox = g_pVirtualBox;
+    }
+    pVirtualBox.queryInterfaceTo(ppVirtualBox);
+    if (pVirtualBox.isNull())
+        return rc;
 
     util::AutoReadLock lock(g_pAuthLibLockHandle COMMA_LOCKVAL_SRC_POS);
@@ -1139,5 +1253,5 @@
         // retrieve authentication library from system properties
         ComPtr<ISystemProperties> systemProperties;
-        g_pVirtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam());
+        pVirtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam());
 
         com::Bstr authLibrary;
@@ -1219,5 +1333,6 @@
             // (and of which IWebsessionManager::getSessionObject returns a managed object reference)
             ComPtr<ISession> session;
-            if (FAILED(rc = session.createInprocObject(CLSID_Session)))
+            rc = g_pVirtualBoxClient->COMGETTER(Session)(session.asOutParam());
+            if (FAILED(rc))
             {
                 WEBDEBUG(("ERROR: cannot create session object!"));
@@ -1538,5 +1653,5 @@
     _vbox__IManagedObjectRef_USCOREgetInterfaceNameResponse *resp)
 {
-    HRESULT rc = SOAP_OK;
+    HRESULT rc = S_OK;
     WEBDEBUG(("-- entering %s\n", __FUNCTION__));
 
@@ -1573,5 +1688,5 @@
     _vbox__IManagedObjectRef_USCOREreleaseResponse *resp)
 {
-    HRESULT rc = SOAP_OK;
+    HRESULT rc = S_OK;
     WEBDEBUG(("-- entering %s\n", __FUNCTION__));
 
@@ -1640,9 +1755,9 @@
  */
 int __vbox__IWebsessionManager_USCORElogon(
-        struct soap*,
+        struct soap *soap,
         _vbox__IWebsessionManager_USCORElogon *req,
         _vbox__IWebsessionManager_USCORElogonResponse *resp)
 {
-    HRESULT rc = SOAP_OK;
+    HRESULT rc = S_OK;
     WEBDEBUG(("-- entering %s\n", __FUNCTION__));
 
@@ -1655,8 +1770,10 @@
         // in the global map automatically
         WebServiceSession *pSession = new WebServiceSession();
+        ComPtr<IVirtualBox> pVirtualBox;
 
         // authenticate the user
         if (!(pSession->authenticate(req->username.c_str(),
-                                     req->password.c_str())))
+                                     req->password.c_str(),
+                                     pVirtualBox.asOutParam())))
         {
             // in the new session, create a managed object reference (MOR) for the
@@ -1664,8 +1781,13 @@
             // that it will be implicitly be included in all future requests of this
             // webservice client
-            ComPtr<IUnknown> p2 = g_pVirtualBox;
+            ComPtr<IUnknown> p2 = pVirtualBox;
+            if (pVirtualBox.isNull() || p2.isNull())
+            {
+                rc = E_FAIL;
+                break;
+            }
             ManagedObjectRef *pRef = new ManagedObjectRef(*pSession,
                                                           p2,                       // IUnknown *pobjUnknown
-                                                          g_pVirtualBox,            // void *pobjInterface
+                                                          pVirtualBox,              // void *pobjInterface
                                                           COM_IIDOF(IVirtualBox),
                                                           g_pcszIVirtualBox);
@@ -1673,4 +1795,6 @@
             WEBDEBUG(("VirtualBox object ref is %s\n", resp->returnval.c_str()));
         }
+        else
+            rc = E_FAIL;
     } while (0);
 
@@ -1690,5 +1814,5 @@
         _vbox__IWebsessionManager_USCOREgetSessionObjectResponse *resp)
 {
-    HRESULT rc = SOAP_OK;
+    HRESULT rc = S_OK;
     WEBDEBUG(("-- entering %s\n", __FUNCTION__));
 
@@ -1723,5 +1847,5 @@
         _vbox__IWebsessionManager_USCORElogoffResponse *resp)
 {
-    HRESULT rc = SOAP_OK;
+    HRESULT rc = S_OK;
     WEBDEBUG(("-- entering %s\n", __FUNCTION__));
 
Index: /trunk/src/VBox/Main/webservice/vboxweb.h
===================================================================
--- /trunk/src/VBox/Main/webservice/vboxweb.h	(revision 35453)
+++ /trunk/src/VBox/Main/webservice/vboxweb.h	(revision 35454)
@@ -3,5 +3,5 @@
  *      header file for "real" web server code.
  *
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -134,5 +134,6 @@
 
         int authenticate(const char *pcszUsername,
-                         const char *pcszPassword);
+                         const char *pcszPassword,
+                         IVirtualBox **ppVirtualBox);
 
         ManagedObjectRef* findRefFromPtr(const IUnknown *pObject);
