Index: trunk/src/VBox/Main/idl/VirtualBox.xidl
===================================================================
--- trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 44903)
+++ trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 44935)
@@ -8922,4 +8922,40 @@
 
   <enum
+    name="GuestSessionStatus"
+    uuid="ac2669da-4624-44f2-85b5-0b0bfb8d8673"
+    >
+    <desc>
+      Guest session statuses.
+    </desc>
+    <const name="Undefined"               value="0">
+      <desc>Guest session is in an undefined state.</desc>
+    </const>
+    <const name="Starting"                value="10">
+      <desc>Guest session is being started.</desc>
+    </const>
+    <const name="Started"                 value="100">
+      <desc>Guest session has been started.</desc>
+    </const>
+    <const name="Terminating"             value="480">
+      <desc>Guest session is being terminated.</desc>
+    </const>
+    <const name="Terminated"              value="500">
+      <desc>Guest session terminated normally.</desc>
+    </const>
+    <const name="TimedOutKilled"          value="512">
+      <desc>Guest session timed out and was killed.</desc>
+    </const>
+    <const name="TimedOutAbnormally"      value="513">
+      <desc>Guest session timed out and was not killed successfully.</desc>
+    </const>
+    <const name="Down"                    value="600">
+      <desc>Service/OS is stopping, guest session was killed.</desc>
+    </const>
+    <const name="Error"                   value="800">
+      <desc>Something went wrong.</desc>
+    </const>
+  </enum>
+
+  <enum
     name="FileSeekType"
     uuid="1b73f4f3-3515-4073-a506-76878d9e2541"
@@ -9232,5 +9268,4 @@
       <desc>Process is in an undefined state.</desc>
     </const>
-
     <const name="Starting"                value="10">
       <desc>Process is being started.</desc>
@@ -9347,5 +9382,5 @@
   <interface
     name="IGuestSession" extends="$unknown"
-    uuid="57eb82a8-822b-42c1-9d1c-5c54bc3d3250"
+    uuid="8490516f-9c2c-49e9-b283-35f3ce463f69"
     wsmap="managed"
     >
@@ -9399,4 +9434,8 @@
         </result>
       </desc>
+    </attribute>
+
+    <attribute name="status" type="GuestSessionStatus" readonly="yes">
+      <desc>Returns the current session status.</desc>
     </attribute>
 
Index: trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h
===================================================================
--- trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h	(revision 44903)
+++ trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h	(revision 44935)
@@ -318,6 +318,35 @@
 
 /**
- * Structure for keeping all the relevant process
- * starting parameters around.
+ * Structure for keeping all the relevant guest session
+ * startup parameters around.
+ */
+class GuestSessionStartupInfo
+{
+public:
+
+    GuestSessionStartupInfo(void)
+        : mIsInternal(false /* Non-internal session */),
+          mOpenTimeoutMS(30 * 1000 /* 30s opening timeout */),
+          mOpenFlags(0 /* No opening flags set */) { }
+
+    /** The session's friendly name. Optional. */
+    Utf8Str                     mName;
+    /** The session's unique ID. Used to encode
+     *  a context ID. */
+    uint32_t                    mID;
+    /** Flag indicating if this is an internal session
+     *  or not. Internal session are not accessible by
+     *  public API clients. */
+    bool                        mIsInternal;
+    /** Timeout (in ms) used for opening the session. */
+    uint32_t                    mOpenTimeoutMS;
+    /** Session opening flags. */
+    uint32_t                    mOpenFlags;
+};
+
+
+/**
+ * Structure for keeping all the relevant guest process
+ * startup parameters around.
  */
 class GuestProcessStartupInfo
@@ -341,5 +370,7 @@
     /** Process priority. */
     ProcessPriority_T           mPriority;
-    /** Process affinity. */
+    /** Process affinity. At the moment we
+     *  only support 64 VCPUs. API and
+     *  guest can do more already!  */
     uint64_t                    mAffinity;
 };
Index: trunk/src/VBox/Main/include/GuestImpl.h
===================================================================
--- trunk/src/VBox/Main/include/GuestImpl.h	(revision 44903)
+++ trunk/src/VBox/Main/include/GuestImpl.h	(revision 44935)
@@ -141,6 +141,5 @@
     Console    *getConsole(void) { return mParent; }
     int         sessionRemove(GuestSession *pSession);
-    int         sessionCreate(const Utf8Str &strUser, const Utf8Str &strPassword, const Utf8Str &strDomain,
-                              const Utf8Str &strSessionName, ComObjPtr<GuestSession> &pGuestSession);
+    int         sessionCreate(const GuestSessionStartupInfo &ssInfo, const GuestCredentials &guestCreds, ComObjPtr<GuestSession> &pGuestSession);
     inline bool sessionExists(uint32_t uSessionID);
 #endif
Index: trunk/src/VBox/Main/include/GuestProcessImpl.h
===================================================================
--- trunk/src/VBox/Main/include/GuestProcessImpl.h	(revision 44903)
+++ trunk/src/VBox/Main/include/GuestProcessImpl.h	(revision 44935)
@@ -105,5 +105,5 @@
     struct Data
     {
-        /** The process start information. */
+        /** The process startup information. */
         GuestProcessStartupInfo  mProcess;
         /** Exit code if process has been terminated. */
Index: trunk/src/VBox/Main/include/GuestSessionImpl.h
===================================================================
--- trunk/src/VBox/Main/include/GuestSessionImpl.h	(revision 44903)
+++ trunk/src/VBox/Main/include/GuestSessionImpl.h	(revision 44935)
@@ -81,5 +81,5 @@
 public:
 
-    int Run(void);
+    int Run(int *pGuestRc);
     int RunAsync(const Utf8Str &strDesc, ComObjPtr<Progress> &pProgress);
     static int taskThread(RTTHREAD Thread, void *pvUser);
@@ -251,5 +251,5 @@
     DECLARE_EMPTY_CTOR_DTOR(GuestSession)
 
-    int     init(Guest *aGuest, ULONG aSessionID, Utf8Str aUser, Utf8Str aPassword, Utf8Str aDomain, Utf8Str aName);
+    int     init(Guest *pGuest, const GuestSessionStartupInfo &ssInfo, const GuestCredentials &guestCreds);
     void    uninit(void);
     HRESULT FinalConstruct(void);
@@ -263,4 +263,5 @@
     STDMETHOD(COMGETTER(Name))(BSTR *aName);
     STDMETHOD(COMGETTER(Id))(ULONG *aId);
+    STDMETHOD(COMGETTER(Status))(GuestSessionStatus_T *aStatus);
     STDMETHOD(COMGETTER(Timeout))(ULONG *aTimeout);
     STDMETHOD(COMSETTER(Timeout))(ULONG aTimeout);
@@ -343,7 +344,11 @@
     const GuestEnvironment &getEnvironment(void);
     Utf8Str                 getName(void);
-    ULONG                   getId(void) { return mData.mId; }
+    ULONG                   getId(void) { return mData.mSession.mID; }
+    static Utf8Str          guestErrorToString(int guestRc);
     int                     onSessionStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData);
-    int                     openSession(uint32_t uFlags, uint32_t uTimeoutMS, int *pGuestRc);
+    int                     openSession(int *pGuestRc);
+    int                     openSessionAsync(void);
+    static DECLCALLBACK(int)
+                            openSessionThread(RTTHREAD Thread, void *pvUser);
     Guest                  *getParent(void) { return mData.mParent; }
     uint32_t                getProtocolVersion(void) { return mData.mProtocolVersion; }
@@ -353,4 +358,5 @@
     inline int              processGetByPID(ULONG uPID, ComObjPtr<GuestProcess> *pProcess);
     int                     sendCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms);
+    static HRESULT          setErrorExternal(VirtualBoxBase *pInterface, int guestRc);
     int                     startTaskAsync(const Utf8Str &strTaskDesc, GuestSessionTask *pTask, ComObjPtr<Progress> &pProgress);
     int                     queryInfo(void);
@@ -361,36 +367,33 @@
     struct Data
     {
+        /** Pointer to the parent (Guest). */
+        Guest                      *mParent;
+        /** The session credentials. */
+        GuestCredentials            mCredentials;
+        /** The session's startup info. */
+        GuestSessionStartupInfo     mSession;
+        /** The session's current status. */
+        GuestSessionStatus_T        mStatus;
+        /** The session's environment block. Can be
+         *  overwritten/extended by ProcessCreate(Ex). */
+        GuestEnvironment            mEnvironment;
+        /** The session callback, needed for communicating
+         *  with the guest. */
+        GuestCtrlCallback           mCallback;
+        /** Directory objects bound to this session. */
+        SessionDirectories          mDirectories;
+        /** File objects bound to this session. */
+        SessionFiles                mFiles;
+        /** Process objects bound to this session. */
+        SessionProcesses            mProcesses;
         /** Guest control protocol version to be used.
          *  Guest Additions < VBox 4.3 have version 1,
          *  any newer version will have version 2. */
-        uint32_t             mProtocolVersion;
-        /** Flag indicating if this is an internal session
-         *  or not. Internal session are not accessible by clients. */
-        bool                 fInternal;
-        /** Pointer to the parent (Guest). */
-        Guest               *mParent;
-        /** The session credentials. */
-        GuestCredentials     mCredentials;
-        /** The (optional) session name. */
-        Utf8Str              mName;
-        /** The session ID. */
-        ULONG                mId;
-        /** The session timeout. Default is 30s. */
-        ULONG                mTimeout;
-        /** The session's environment block. Can be
-         *  overwritten/extended by ProcessCreate(Ex). */
-        GuestEnvironment     mEnvironment;
-        /** The session callback, needed for communicating
-         *  with the guest. */
-        GuestCtrlCallback    mCallback;
-        /** Directory objects bound to this session. */
-        SessionDirectories   mDirectories;
-        /** File objects bound to this session. */
-        SessionFiles         mFiles;
-        /** Process objects bound to this session. */
-        SessionProcesses     mProcesses;
+        uint32_t                    mProtocolVersion;
+        /** Session timeout (in ms). */
+        uint32_t                    mTimeout;
         /** Total number of session objects (processes,
          *  files, ...). */
-        uint32_t             mNumObjects;
+        uint32_t                    mNumObjects;
     } mData;
 };
Index: trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp	(revision 44903)
+++ trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp	(revision 44935)
@@ -142,9 +142,16 @@
     HRESULT hr = S_OK;
 
-    /* Create an anonymous session. This is required to run the Guest Additions
-     * update process with administrative rights. */
+    /*
+     * Create an anonymous session. This is required to run the Guest Additions
+     * update process with administrative rights.
+     */
+    GuestSessionStartupInfo startupInfo;
+    startupInfo.mName = "Updating Guest Additions";
+
+    GuestCredentials guestCreds;
+    RT_ZERO(guestCreds);
+
     ComObjPtr<GuestSession> pSession;
-    int rc = sessionCreate("" /* User */, "" /* Password */, "" /* Domain */,
-                           "Updating Guest Additions" /* Name */, pSession);
+    int rc = sessionCreate(startupInfo, guestCreds, pSession);
     if (RT_FAILURE(rc))
     {
@@ -166,8 +173,11 @@
     {
         Assert(!pSession.isNull());
-        rc = pSession->queryInfo();
+        int guestRc;
+        rc = pSession->openSession(&guestRc);
         if (RT_FAILURE(rc))
         {
-            hr = setError(VBOX_E_IPRT_ERROR, tr("Could not query guest session information: %Rrc"), rc);
+            /** @todo Handle guestRc! */
+
+            hr = setError(VBOX_E_IPRT_ERROR, tr("Could not open guest session: %Rrc"), rc);
         }
         else
@@ -208,4 +218,7 @@
     AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
 
+    LogFlowFunc(("uFunction=%RU32, uContextID=%RU32, uProtocol=%RU32\n",
+                  pCtxCb->uFunction, pCtxCb->uContextID, pCtxCb->uProtocol));
+
     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
 
@@ -260,5 +273,6 @@
             {
                 case GUEST_DISCONNECTED:
-                   break;
+                    rc = pSession->dispatchToThis(pCtxCb, pSvcCb);
+                    break;
 
                 case GUEST_SESSION_NOTIFY:
@@ -310,5 +324,5 @@
                          (GuestSession *)itSessions->second, itSessions->second->getId(), mData.mGuestSessions.size() - 1));
 
-            mData.mGuestSessions.erase(itSessions);
+            mData.mGuestSessions.erase(itSessions++);
 
             rc = VINF_SUCCESS;
@@ -321,6 +335,6 @@
 }
 
-int Guest::sessionCreate(const Utf8Str &strUser, const Utf8Str &strPassword, const Utf8Str &strDomain,
-                         const Utf8Str &strSessionName, ComObjPtr<GuestSession> &pGuestSession)
+int Guest::sessionCreate(const GuestSessionStartupInfo &ssInfo,
+                         const GuestCredentials &guestCreds, ComObjPtr<GuestSession> &pGuestSession)
 {
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
@@ -348,5 +362,5 @@
                 uNewSessionID = 0;
 
-            if (++uTries == UINT32_MAX)
+            if (++uTries == VBOX_GUESTCTRL_MAX_SESSIONS)
                 break; /* Don't try too hard. */
         }
@@ -357,8 +371,26 @@
         if (FAILED(hr)) throw VERR_COM_UNEXPECTED;
 
-        rc = pGuestSession->queryInfo();
-        if (RT_FAILURE(rc)) throw rc;
-        rc = pGuestSession->init(this, uNewSessionID,
-                                 strUser, strPassword, strDomain, strSessionName);
+        /** @todo Use an overloaded copy operator. Later. */
+        GuestSessionStartupInfo startupInfo;
+        startupInfo.mID = uNewSessionID; /* Assign new session ID. */
+        startupInfo.mName = ssInfo.mName;
+        startupInfo.mOpenFlags = ssInfo.mOpenFlags;
+        startupInfo.mOpenTimeoutMS = ssInfo.mOpenTimeoutMS;
+
+        GuestCredentials guestCredentials;
+        if (!guestCreds.mUser.isEmpty())
+        {
+            /** @todo Use an overloaded copy operator. Later. */
+            guestCredentials.mUser = guestCreds.mUser;
+            guestCredentials.mPassword = guestCreds.mPassword;
+            guestCredentials.mDomain = guestCreds.mDomain;
+        }
+        else
+        {
+            /* Internal (annonymous) session. */
+            startupInfo.mIsInternal = true;
+        }
+
+        rc = pGuestSession->init(this, startupInfo, guestCredentials);
         if (RT_FAILURE(rc)) throw rc;
 
@@ -373,37 +405,4 @@
          * involve the main dispatcher to run. */
         alock.release();
-
-        /** @todo Do we need an openSessioAsync() call? This might be
-         *        a problem on webservice calls (= timeouts) if opening the
-         *        guest session takes too long -> Then we also would
-         *        need some session.getStatus() API call! */
-
-        /* Open (create) the session on the guest. */
-        int guestRc;
-        rc = pGuestSession->openSession(0 /* Flags */, 30 * 1000 /* 30s timeout */,
-                                        &guestRc);
-        if (RT_FAILURE(rc))
-        {
-            switch (rc)
-            {
-                case VERR_MAX_PROCS_REACHED:
-                    hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of guest sessions (%ld) reached"),
-                                                        VBOX_GUESTCTRL_MAX_SESSIONS);
-                    break;
-
-                /** @todo Add more errors here. */
-
-                default:
-                    hr = setError(VBOX_E_IPRT_ERROR, tr("Could not create guest session, rc=%Rrc"), rc);
-                    break;
-            }
-
-            /* Remove failed session again. */
-            int rc2 = sessionRemove(pGuestSession);
-            AssertRC(rc2);
-        }
-        else
-            LogFlowFunc(("Created new guest session (pSession=%p, ID=%RU32), now %zu sessions total\n",
-                         (GuestSession *)pGuestSession, uNewSessionID, mData.mGuestSessions.size()));
     }
     catch (int rc2)
@@ -433,5 +432,5 @@
     LogFlowFuncEnter();
 
-    /* Do not allow anonymous sessions (with system rights) with official API. */
+    /* Do not allow anonymous sessions (with system rights) with public API. */
     if (RT_UNLIKELY((aUser) == NULL || *(aUser) == '\0'))
         return setError(E_INVALIDARG, tr("No user name specified"));
@@ -442,8 +441,14 @@
     if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
-    HRESULT hr = S_OK;
+    GuestSessionStartupInfo startupInfo;
+    startupInfo.mName = aSessionName;
+
+    GuestCredentials guestCreds;
+    guestCreds.mUser = aUser;
+    guestCreds.mPassword = aPassword;
+    guestCreds.mDomain = aDomain;
 
     ComObjPtr<GuestSession> pSession;
-    int rc = sessionCreate(aUser, aPassword, aDomain, aSessionName, pSession);
+    int rc = sessionCreate(startupInfo, guestCreds, pSession);
     if (RT_SUCCESS(rc))
     {
@@ -454,8 +459,31 @@
     }
 
+    int guestRc;
+    if (RT_SUCCESS(rc))
+    {
+        /** @todo Do we need to use openSessioAsync() here? Otherwise
+         *        there might be a problem on webservice calls (= timeouts)
+         *        if opening the guest session takes too long -> Use
+         *        the new session.getStatus() API call! */
+
+        /* Open (fork) the session on the guest. */
+        rc = pSession->openSession(&guestRc);
+        if (RT_SUCCESS(rc))
+        {
+            LogFlowFunc(("Created new guest session (pSession=%p), now %zu sessions total\n",
+                         (GuestSession *)pSession, mData.mGuestSessions.size()));
+        }
+    }
+
+    HRESULT hr = S_OK;
+
     if (RT_FAILURE(rc))
     {
         switch (rc)
         {
+            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
+                hr = GuestSession::setErrorExternal(this, guestRc);
+                break;
+
             case VERR_MAX_PROCS_REACHED:
                 hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of guest sessions (%ld) reached"),
@@ -465,6 +493,6 @@
             /** @todo Add more errors here. */
 
-           default:
-                hr = setError(VBOX_E_IPRT_ERROR, tr("Could not create guest session, rc=%Rrc"), rc);
+            default:
+                hr = setError(VBOX_E_IPRT_ERROR, tr("Could not create guest session: %Rrc"), rc);
                 break;
         }
Index: trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp	(revision 44903)
+++ trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp	(revision 44935)
@@ -405,5 +405,5 @@
  *
  * In protocol v1 we don't have the possibility to terminate/kill
- * processes so it can happen that a formerly start process A
+ * processes so it can happen that a formerly started process A
  * (which has the context ID 0 (session=0, process=0, count=0) will
  * send a delayed message to the host if this process has already
@@ -428,7 +428,9 @@
                    ? VINF_SUCCESS : VERR_NOT_FOUND;
         }
+#ifndef DEBUG_andy
         /* This should never happen! */
         AssertReleaseMsg(mData.mPID == uPID, ("Unterminated guest process (PID %RU32) sent data to a newly started process (PID %RU32)\n",
                                               uPID, mData.mPID));
+#endif
     }
 
@@ -1247,5 +1249,5 @@
 
     /* Create callback and add it to the map. */
-    uint32_t uContextID = 0;
+    uint32_t uContextID;
     if (RT_SUCCESS(vrc))
         vrc = callbackAdd(pCallbackTerminate, &uContextID);
@@ -1275,7 +1277,14 @@
         {
             int guestRc = pCallbackTerminate->GetResultCode();
-            LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc));
+            if (RT_SUCCESS(guestRc))
+            {
+                /* Nothing to do here right now. */
+            }
+            else
+                vrc = VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
+
             if (pGuestRc)
                 *pGuestRc = guestRc;
+            LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc));
         }
     }
Index: trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp	(revision 44903)
+++ trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp	(revision 44935)
@@ -44,4 +44,40 @@
 #include <VBox/log.h>
 
+
+/**
+ * Base class representing an internal
+ * asynchronous session task.
+ */
+class GuestSessionTaskInternal
+{
+public:
+
+    GuestSessionTaskInternal(GuestSession *pSession)
+        : mSession(pSession),
+          mRC(VINF_SUCCESS) { }
+
+    virtual ~GuestSessionTaskInternal(void) { }
+
+    int rc(void) const { return mRC; }
+    bool isOk(void) const { return RT_SUCCESS(mRC); }
+    const ComObjPtr<GuestSession> &Session(void) const { return mSession; }
+
+protected:
+
+    const ComObjPtr<GuestSession>    mSession;
+    int                              mRC;
+};
+
+/**
+ * Class for asynchronously opening a guest session.
+ */
+class GuestSessionTaskInternalOpen : public GuestSessionTaskInternal
+{
+public:
+
+    GuestSessionTaskInternalOpen(GuestSession *pSession)
+        : GuestSessionTaskInternal(pSession) { }
+};
+
 // constructor / destructor
 /////////////////////////////////////////////////////////////////////////////
@@ -68,20 +104,16 @@
 /**
  * Initializes a guest session but does *not* open in on the guest side
- * yet. This needs to be done via the openSession() call.
+ * yet. This needs to be done via the openSession() / openSessionAsync calls.
  *
  * @return  IPRT status code.
- * @param   aGuest
- * @param   aSessionID
- * @param   aUser
- * @param   aPassword
- * @param   aDomain
- * @param   aName
+ ** @todo Docs!
  */
-int GuestSession::init(Guest *aGuest, ULONG aSessionID,
-                       Utf8Str aUser, Utf8Str aPassword, Utf8Str aDomain, Utf8Str aName)
-{
-    LogFlowThisFuncEnter();
-
-    AssertPtrReturn(aGuest, VERR_INVALID_POINTER);
+int GuestSession::init(Guest *pGuest, const GuestSessionStartupInfo &ssInfo,
+                       const GuestCredentials &guestCreds)
+{
+    LogFlowThisFunc(("pGuest=%p, ssInfo=%p, guestCreds=%p\n",
+                      pGuest, &ssInfo, &guestCreds));
+
+    AssertPtrReturn(pGuest, VERR_INVALID_POINTER);
 
     /* Enclose the state transition NotReady->InInit->Ready. */
@@ -89,19 +121,33 @@
     AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED);
 
-    mData.mTimeout = 30 * 60 * 1000; /* Session timeout is 30 mins by default. */
-    mData.mParent = aGuest;
-    mData.mId = aSessionID;
-
-    mData.mCredentials.mUser = aUser;
-    mData.mCredentials.mPassword = aPassword;
-    mData.mCredentials.mDomain = aDomain;
-    mData.mName = aName;
+    mData.mParent = pGuest;
+
+    /* Copy over startup info. */
+    /** @todo Use an overloaded copy operator. Later. */
+    mData.mSession.mID = ssInfo.mID;
+    mData.mSession.mIsInternal = ssInfo.mIsInternal;
+    mData.mSession.mName = ssInfo.mName;
+    mData.mSession.mOpenFlags = ssInfo.mOpenFlags;
+    mData.mSession.mOpenTimeoutMS = ssInfo.mOpenTimeoutMS;
+
+    /** @todo Use an overloaded copy operator. Later. */
+    mData.mCredentials.mUser = guestCreds.mUser;
+    mData.mCredentials.mPassword = guestCreds.mPassword;
+    mData.mCredentials.mDomain = guestCreds.mDomain;
+
+    mData.mStatus = GuestSessionStatus_Undefined;
     mData.mNumObjects = 0;
 
-    /* Confirm a successful initialization when it's the case. */
-    autoInitSpan.setSucceeded();
-
-    LogFlowFuncLeaveRC(VINF_SUCCESS);
-    return VINF_SUCCESS;
+    int rc = queryInfo();
+    if (RT_SUCCESS(rc))
+    {
+        /* Confirm a successful initialization when it's the case. */
+        autoInitSpan.setSucceeded();
+    }
+    else
+        autoInitSpan.setFailed();
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
 }
 
@@ -228,5 +274,5 @@
     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    mData.mName.cloneTo(aName);
+    mData.mSession.mName.cloneTo(aName);
 
     LogFlowFuncLeaveRC(S_OK);
@@ -249,5 +295,5 @@
     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    *aId = mData.mId;
+    *aId = mData.mSession.mID;
 
     LogFlowFuncLeaveRC(S_OK);
@@ -256,12 +302,12 @@
 }
 
-STDMETHODIMP GuestSession::COMGETTER(Timeout)(ULONG *aTimeout)
-{
-#ifndef VBOX_WITH_GUEST_CONTROL
-    ReturnComNotImplemented();
-#else
-    LogFlowThisFuncEnter();
-
-    CheckComArgOutPointerValid(aTimeout);
+STDMETHODIMP GuestSession::COMGETTER(Status)(GuestSessionStatus_T *aStatus)
+{
+#ifndef VBOX_WITH_GUEST_CONTROL
+    ReturnComNotImplemented();
+#else
+    LogFlowThisFuncEnter();
+
+    CheckComArgOutPointerValid(aStatus);
 
     AutoCaller autoCaller(this);
@@ -270,5 +316,5 @@
     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    *aTimeout = mData.mTimeout;
+    *aStatus = mData.mStatus;
 
     LogFlowFuncLeaveRC(S_OK);
@@ -277,17 +323,19 @@
 }
 
-STDMETHODIMP GuestSession::COMSETTER(Timeout)(ULONG aTimeout)
-{
-#ifndef VBOX_WITH_GUEST_CONTROL
-    ReturnComNotImplemented();
-#else
-    LogFlowThisFuncEnter();
-
-    AutoCaller autoCaller(this);
-    if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    mData.mTimeout = aTimeout;
+STDMETHODIMP GuestSession::COMGETTER(Timeout)(ULONG *aTimeout)
+{
+#ifndef VBOX_WITH_GUEST_CONTROL
+    ReturnComNotImplemented();
+#else
+    LogFlowThisFuncEnter();
+
+    CheckComArgOutPointerValid(aTimeout);
+
+    AutoCaller autoCaller(this);
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    *aTimeout = mData.mTimeout;
 
     LogFlowFuncLeaveRC(S_OK);
@@ -296,4 +344,23 @@
 }
 
+STDMETHODIMP GuestSession::COMSETTER(Timeout)(ULONG aTimeout)
+{
+#ifndef VBOX_WITH_GUEST_CONTROL
+    ReturnComNotImplemented();
+#else
+    LogFlowThisFuncEnter();
+
+    AutoCaller autoCaller(this);
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    mData.mTimeout = aTimeout;
+
+    LogFlowFuncLeaveRC(S_OK);
+    return S_OK;
+#endif /* VBOX_WITH_GUEST_CONTROL */
+}
+
 STDMETHODIMP GuestSession::COMGETTER(Environment)(ComSafeArrayOut(BSTR, aEnvironment))
 {
@@ -311,5 +378,6 @@
 
     size_t cEnvVars = mData.mEnvironment.Size();
-    LogFlowThisFunc(("%s cEnvVars=%RU32\n", mData.mName.c_str(), cEnvVars));
+    LogFlowThisFunc(("[%s]: cEnvVars=%RU32\n",
+                     mData.mSession.mName.c_str(), cEnvVars));
     com::SafeArray<BSTR> environment(cEnvVars);
 
@@ -431,7 +499,9 @@
     if (mData.mProtocolVersion < 2)
     {
-        LogFlowThisFunc(("Installed Guest Additions don't support closing separate sessions\n"));
+        LogFlowThisFunc(("Installed Guest Additions don't support closing dedicated sessions, skipping\n"));
         return VINF_SUCCESS;
     }
+
+    /** @todo uFlags validation. */
 
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
@@ -446,5 +516,9 @@
     if (RT_SUCCESS(vrc))
     {
-        uint32_t uContextID = VBOX_GUESTCTRL_CONTEXTID_MAKE(mData.mId, 0 /* Object */, 0 /* Count */);
+        /* The context ID only contains this session's ID; all other
+         * parameters like object and the count itself are not needed
+         * and therefore 0. */
+        uint32_t uContextID = VBOX_GUESTCTRL_CONTEXTID_MAKE(mData.mSession.mID /* Session ID */,
+                                                            0 /* Object */, 0 /* Count */);
 
         VBOXHGCMSVCPARM paParms[4];
@@ -452,5 +526,5 @@
         int i = 0;
         paParms[i++].setUInt32(uContextID);
-        paParms[i++].setUInt32(0 /* Flags, unused. */);
+        paParms[i++].setUInt32(uFlags);
 
         vrc = sendCommand(HOST_SESSION_CLOSE, i, paParms);
@@ -468,10 +542,15 @@
         {
             int guestRc = mData.mCallback.GetResultCode();
+            if (RT_SUCCESS(guestRc))
+            {
+                /* Nothing to do here right now. */
+            }
+            else
+                vrc = VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
+
             if (pGuestRc)
                 *pGuestRc = guestRc;
             LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc));
         }
-        else
-            vrc = VERR_TIMEOUT;
     }
 
@@ -499,5 +578,5 @@
             Assert(mData.mDirectories.size());
             LogFlowFunc(("Removing directory \"%s\" (Session: %RU32) (now total %ld directories)\n",
-                         Utf8Str(strName).c_str(), mData.mId, mData.mDirectories.size() - 1));
+                         Utf8Str(strName).c_str(), mData.mSession.mID, mData.mDirectories.size() - 1));
 
             mData.mDirectories.erase(itDirs);
@@ -637,5 +716,5 @@
 
     LogFlowFunc(("Added new directory \"%s\" (Session: %RU32)\n",
-                 strPath.c_str(), mData.mId));
+                 strPath.c_str(), mData.mSession.mID));
 
     LogFlowFuncLeaveRC(vrc);
@@ -721,5 +800,5 @@
 #ifdef DEBUG
     LogFlowThisFunc(("ID=%RU32, uContextID=%RU32, uFunction=%RU32, pSvcCb=%p\n",
-                     mData.mId, pCbCtx->uContextID, pCbCtx->uFunction, pSvcCb));
+                     mData.mSession.mID, pCbCtx->uContextID, pCbCtx->uFunction, pSvcCb));
 #endif
 
@@ -727,4 +806,8 @@
     switch (pCbCtx->uFunction)
     {
+        case GUEST_DISCONNECTED:
+            /** @todo Handle closing all processes. */
+            break;
+
         case GUEST_SESSION_NOTIFY:
         {
@@ -736,4 +819,5 @@
         default:
             /* Silently skip unknown callbacks. */
+            rc = VERR_NOT_SUPPORTED;
             break;
     }
@@ -773,5 +857,5 @@
             Assert(mData.mNumObjects);
             LogFlowThisFunc(("Removing file \"%s\" (Session: %RU32) (now total %ld files, %ld objects)\n",
-                             Utf8Str(strName).c_str(), mData.mId, mData.mFiles.size() - 1, mData.mNumObjects - 1));
+                             Utf8Str(strName).c_str(), mData.mSession.mID, mData.mFiles.size() - 1, mData.mNumObjects - 1));
 #ifdef DEBUG
             ULONG cRefs = pFile->AddRef();
@@ -874,5 +958,5 @@
 
     LogFlowFunc(("Added new file \"%s\" (Session: %RU32) (now total %ld files, %ld objects)\n",
-                 openInfo.mFileName.c_str(), mData.mId, mData.mFiles.size(), mData.mNumObjects));
+                 openInfo.mFileName.c_str(), mData.mSession.mID, mData.mFiles.size(), mData.mNumObjects));
 
     LogFlowFuncLeaveRC(rc);
@@ -957,5 +1041,57 @@
 Utf8Str GuestSession::getName(void)
 {
-    return mData.mName;
+    return mData.mSession.mName;
+}
+
+/* static */
+Utf8Str GuestSession::guestErrorToString(int guestRc)
+{
+    Utf8Str strError;
+
+    /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
+    switch (guestRc)
+    {
+        case VERR_INVALID_VM_HANDLE:
+            strError += Utf8StrFmt(tr("VMM device is not available (is the VM running?)"));
+            break;
+
+        case VERR_HGCM_SERVICE_NOT_FOUND:
+            strError += Utf8StrFmt(tr("The guest execution service is not available"));
+            break;
+
+        case VERR_AUTHENTICATION_FAILURE:
+            strError += Utf8StrFmt(tr("The specified user was not able to logon on guest"));
+            break;
+
+        case VERR_TIMEOUT:
+            strError += Utf8StrFmt(tr("The guest did not respond within time"));
+            break;
+
+        case VERR_CANCELLED:
+            strError += Utf8StrFmt(tr("The session operation was canceled"));
+            break;
+
+        case VERR_PERMISSION_DENIED:
+            strError += Utf8StrFmt(tr("Invalid user/password credentials"));
+            break;
+
+        case VERR_MAX_PROCS_REACHED:
+            strError += Utf8StrFmt(tr("Maximum number of parallel guest processes has been reached"));
+            break;
+
+        case VERR_NOT_EQUAL: /** @todo Imprecise to the user; can mean anything and all. */
+            strError += Utf8StrFmt(tr("Unable to retrieve requested information"));
+            break;
+
+        case VERR_NOT_FOUND:
+            strError += Utf8StrFmt(tr("The guest execution service is not ready (yet)"));
+            break;
+
+        default:
+            strError += Utf8StrFmt("%Rrc", guestRc);
+            break;
+    }
+
+    return strError;
 }
 
@@ -975,10 +1111,41 @@
     pSvcCbData->mpaParms[2].getUInt32(&dataCb.uResult);
 
-    int rcCb = dataCb.uResult; /** @todo uint32_t vs. int. */
-
     LogFlowThisFunc(("ID=%RU32, uType=%RU32, rc=%Rrc, pCallback=%p, pData=%p\n",
-                     mData.mId, dataCb.uType, rcCb, pCallback, pSvcCbData));
+                     mData.mSession.mID, dataCb.uType, dataCb.uResult, pCallback, pSvcCbData));
 
     int vrc = VINF_SUCCESS;
+
+    int guestRc = dataCb.uResult; /** @todo uint32_t vs. int. */
+    switch (dataCb.uType)
+    {
+        case GUEST_SESSION_NOTIFYTYPE_ERROR:
+            mData.mStatus = GuestSessionStatus_Error;
+            break;
+
+        case GUEST_SESSION_NOTIFYTYPE_OPEN:
+            if (RT_FAILURE(guestRc))
+                mData.mStatus = GuestSessionStatus_Started;
+            break;
+
+        case GUEST_SESSION_NOTIFYTYPE_CLOSE:
+            if (RT_FAILURE(guestRc))
+                mData.mStatus = GuestSessionStatus_Terminated;
+            break;
+
+        default:
+            vrc = VERR_NOT_SUPPORTED;
+            break;
+    }
+
+    if (RT_SUCCESS(vrc))
+    {
+        if (RT_FAILURE(guestRc))
+            mData.mStatus = GuestSessionStatus_Error;
+    }
+    else if (vrc == VERR_NOT_SUPPORTED)
+    {
+        /* Also let the callback know. */
+        guestRc = VERR_NOT_SUPPORTED;
+    }
 
     /*
@@ -987,10 +1154,12 @@
     if (pCallback)
     {
-        vrc = pCallback->SetData(&dataCb, sizeof(dataCb));
-
-        int rc2 = pCallback->Signal(rcCb);
-        if (RT_SUCCESS(vrc))
-            vrc = rc2;
-    }
+        int rc2 = pCallback->SetData(&dataCb, sizeof(dataCb));
+        AssertRC(rc2);
+        rc2 = pCallback->Signal(guestRc);
+        AssertRC(rc2);
+    }
+
+    LogFlowThisFunc(("ID=%RU32, guestRc=%Rrc\n",
+                     mData.mSession.mID, guestRc));
 
     LogFlowFuncLeaveRC(vrc);
@@ -998,20 +1167,25 @@
 }
 
-int GuestSession::openSession(uint32_t uFlags, uint32_t uTimeoutMS, int *pGuestRc)
+int GuestSession::openSession(int *pGuestRc)
 {
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    LogFlowThisFunc(("uProtocolVersion=%RU32, uFlags=%x, uTimeoutMS=%RU32\n",
-                     mData.mProtocolVersion, uFlags, uTimeoutMS));
+    LogFlowThisFunc(("uProtocolVersion=%RU32, openFlags=%x, openTimeoutMS=%RU32\n",
+                     mData.mProtocolVersion, mData.mSession.mOpenFlags, mData.mSession.mOpenTimeoutMS));
 
     /* Legacy Guest Additions don't support opening dedicated
-       guest sessions. */
+       guest sessions. Simply return success here. */
     if (mData.mProtocolVersion < 2)
     {
-        LogFlowThisFunc(("Installed Guest Additions don't support opening separate sessions\n"));
+        mData.mStatus = GuestSessionStatus_Started;
+
+        LogFlowThisFunc(("Installed Guest Additions don't support opening dedicated sessions, skipping\n"));
         return VINF_SUCCESS;
     }
 
-    /** @todo uFlags validation. */
+    /** @todo mData.mSession.uFlags validation. */
+
+    /* Set current session status. */
+    mData.mStatus = GuestSessionStatus_Starting;
 
     /* Destroy a pending callback request. */
@@ -1025,5 +1199,6 @@
     {
         uint32_t uContextID =
-            VBOX_GUESTCTRL_CONTEXTID_MAKE(mData.mId, 0 /* Object */, 0 /* Count */);
+            VBOX_GUESTCTRL_CONTEXTID_MAKE(mData.mSession.mID /* Session ID */,
+                                          0 /* Object */, 0 /* Count */);
 
         VBOXHGCMSVCPARM paParms[8];
@@ -1038,5 +1213,5 @@
         paParms[i++].setPointer((void*)mData.mCredentials.mDomain.c_str(),
                                 (ULONG)mData.mCredentials.mDomain.length() + 1);
-        paParms[i++].setUInt32(uFlags);
+        paParms[i++].setUInt32(mData.mSession.mOpenFlags);
 
         vrc = sendCommand(HOST_SESSION_CREATE, i, paParms);
@@ -1049,18 +1224,23 @@
          * Note: Be sure not keeping a AutoRead/WriteLock here.
          */
-        LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", uTimeoutMS));
-        vrc = mData.mCallback.Wait(uTimeoutMS);
+        LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", mData.mSession.mOpenTimeoutMS));
+        vrc = mData.mCallback.Wait(mData.mSession.mOpenTimeoutMS);
         if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */
         {
             int guestRc = mData.mCallback.GetResultCode();
+            if (RT_SUCCESS(guestRc))
+            {
+                /* Nothing to do here right now. */
+            }
+            else
+                vrc = VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
+
             if (pGuestRc)
                 *pGuestRc = guestRc;
             LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc));
         }
-        else
-            vrc = VERR_TIMEOUT;
-    }
-
-    AutoWriteLock awlock(this COMMA_LOCKVAL_SRC_POS);
+    }
+
+    alock.acquire();
 
     /* Destroy callback. */
@@ -1071,4 +1251,57 @@
 }
 
+int GuestSession::openSessionAsync(void)
+{
+    LogFlowThisFuncEnter();
+
+    int vrc;
+
+    try
+    {
+        /* Asynchronously open the session on the guest by kicking off a
+         * worker thread. */
+        std::auto_ptr<GuestSessionTaskInternalOpen> pTask(new GuestSessionTaskInternalOpen(this));
+        AssertReturn(pTask->isOk(), pTask->rc());
+
+        vrc = RTThreadCreate(NULL, GuestSession::openSessionThread,
+                             (void *)pTask.get(), 0,
+                             RTTHREADTYPE_MAIN_WORKER, 0,
+                             "gctlSesOpen");
+        if (RT_SUCCESS(vrc))
+        {
+            /* pTask is now owned by openSessionThread(), so release it. */
+            pTask.release();
+        }
+    }
+    catch(std::bad_alloc &)
+    {
+        vrc = VERR_NO_MEMORY;
+    }
+
+    LogFlowFuncLeaveRC(vrc);
+    return vrc;
+}
+
+/* static */
+DECLCALLBACK(int) GuestSession::openSessionThread(RTTHREAD Thread, void *pvUser)
+{
+    LogFlowFunc(("pvUser=%p\n", pvUser));
+
+    std::auto_ptr<GuestSessionTaskInternalOpen> pTask(static_cast<GuestSessionTaskInternalOpen*>(pvUser));
+    AssertPtr(pTask.get());
+
+    const ComObjPtr<GuestSession> pSession(pTask->Session());
+    Assert(!pSession.isNull());
+
+    AutoCaller autoCaller(pSession);
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    int vrc = pSession->openSession(NULL /* Guest rc, ignored */);
+    /* Nothing to do here anymore. */
+
+    LogFlowFuncLeaveRC(vrc);
+    return vrc;
+}
+
 int GuestSession::processRemoveFromList(GuestProcess *pProcess)
 {
@@ -1097,5 +1330,5 @@
             Assert(mData.mNumObjects);
             LogFlowFunc(("Removing process (Session: %RU32) with process ID=%RU32, guest PID=%RU32 (now total %ld processes, %ld objects)\n",
-                         mData.mId, pCurProc->getObjectID(), uPID, mData.mProcesses.size() - 1, mData.mNumObjects - 1));
+                         mData.mSession.mID, pCurProc->getObjectID(), uPID, mData.mProcesses.size() - 1, mData.mNumObjects - 1));
 
             mData.mProcesses.erase(itProcs);
@@ -1192,5 +1425,5 @@
             uNewProcessID = 0;
 
-        if (++uTries == UINT32_MAX)
+        if (++uTries == VBOX_GUESTCTRL_MAX_OBJECTS)
             break; /* Don't try too hard. */
     }
@@ -1215,5 +1448,5 @@
 
     LogFlowFunc(("Added new process (Session: %RU32) with process ID=%RU32 (now total %ld processes, %ld objects)\n",
-                 mData.mId, uNewProcessID, mData.mProcesses.size(), mData.mNumObjects));
+                 mData.mSession.mID, uNewProcessID, mData.mProcesses.size(), mData.mNumObjects));
 
     return rc;
@@ -1285,4 +1518,13 @@
     LogFlowFuncLeaveRC(vrc);
     return vrc;
+}
+
+/* static */
+HRESULT GuestSession::setErrorExternal(VirtualBoxBase *pInterface, int guestRc)
+{
+    AssertPtr(pInterface);
+    AssertMsg(RT_FAILURE(guestRc), ("Guest rc does not indicate a failure when setting error\n"));
+
+    return pInterface->setError(VBOX_E_IPRT_ERROR, GuestSession::guestErrorToString(guestRc).c_str());
 }
 
@@ -1328,8 +1570,13 @@
 int GuestSession::queryInfo(void)
 {
-#if 1
-    /* Since the new functions were not implemented yet, force Main to use protocol ver 1. */
+#ifndef DEBUG_andy
+    /* Since the new functions are not fully implemented yet, force Main
+       to use protocol ver 1 so far. */
+    mData.mProtocolVersion = 1;
+#else
+ #if 1
+    /* For debugging only: Hardcode version. */
     mData.mProtocolVersion = 2;
-#else
+ #else
     /*
      * Try querying the guest control protocol version running on the guest.
@@ -1351,4 +1598,5 @@
         LogRel((tr("Warning: Guest Additions are older (%ld.%ld) than host capabilities for guest control, please upgrade them. Using protocol version %ld now\n"),
                 VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions), VBOX_FULL_VERSION_GET_MINOR(uVerAdditions), mData.mProtocolVersion));
+ #endif
 #endif
     return VINF_SUCCESS;
@@ -1372,11 +1620,11 @@
     int rc = closeSession(0 /* Flags */, 30 * 1000 /* Timeout */,
                           &guestRc);
-    if (RT_FAILURE(rc))
-    {
-
-    }
+    /* On failure don't return here, instead do all the cleanup
+     * work first and then return an error. */
 
     /* Remove ourselves from the session list. */
-    mData.mParent->sessionRemove(this);
+    int rc2 = mData.mParent->sessionRemove(this);
+    if (RT_SUCCESS(rc))
+        rc = rc2;
 
     /*
@@ -1387,5 +1635,12 @@
     uninit();
 
-    LogFlowFuncLeave();
+    LogFlowFuncLeaveRC(rc);
+    if (RT_FAILURE(rc))
+    {
+        /** @todo Handle guestRc! */
+        return setError(VBOX_E_IPRT_ERROR,
+                        tr("Closing guest session failed with %Rrc\n"), rc);
+    }
+
     return S_OK;
 #endif /* VBOX_WITH_GUEST_CONTROL */
Index: trunk/src/VBox/Main/src-client/GuestSessionImplTasks.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/GuestSessionImplTasks.cpp	(revision 44903)
+++ trunk/src/VBox/Main/src-client/GuestSessionImplTasks.cpp	(revision 44935)
@@ -176,5 +176,5 @@
 }
 
-int SessionTaskOpen::Run(void)
+int SessionTaskOpen::Run(int *pGuestRc)
 {
     LogFlowThisFuncEnter();
@@ -186,6 +186,5 @@
     if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
-    int vrc = pSession->openSession(mFlags, mTimeoutMS,
-                                    NULL /* Guest rc, ignored */);
+    int vrc = pSession->openSession(pGuestRc);
     /* Nothing to do here anymore. */
 
@@ -215,5 +214,5 @@
 
     LogFlowFunc(("pTask=%p\n", task.get()));
-    return task->Run();
+    return task->Run(NULL /* guestRc */);
 }
 
