Пример #1
0
/**
 * Uninitializes the instance and sets the ready flag to FALSE.
 * Called either from FinalRelease() or by the parent when it gets destroyed.
 */
void MediumLockToken::uninit()
{
    LogFlowThisFunc(("\n"));

    /* Enclose the state transition Ready->InUninit->NotReady */
    AutoUninitSpan autoUninitSpan(this);
    if (autoUninitSpan.uninitDone())
        return;

    /* Release the appropriate lock, check is paranoia */
    if (!m.pMedium.isNull())
    {
        if (m.fWrite)
        {
            HRESULT rc = m.pMedium->unlockWrite(NULL);
            AssertComRC(rc);
        }
        else
        {
            HRESULT rc = m.pMedium->unlockRead(NULL);
            AssertComRC(rc);
        }
        m.pMedium.setNull();
    }
}
/**
 *  Initializes itself by fetching error information from the given error info
 *  object.
 */
HRESULT VirtualBoxErrorInfo::init(nsIException *aInfo)
{
    AssertReturn(aInfo, E_FAIL);

    HRESULT rc = S_OK;

    /* We don't return a failure if talking to nsIException fails below to
     * protect ourselves from bad nsIException implementations (the
     * corresponding fields will simply remain null in this case). */

    rc = aInfo->GetResult(&m_resultCode);
    AssertComRC(rc);

    char *pszMsg;             /* No Utf8Str.asOutParam, different allocator! */
    rc = aInfo->GetMessage(&pszMsg);
    AssertComRC(rc);
    if (NS_SUCCEEDED(rc))
    {
        m_strText = pszMsg;
        nsMemory::Free(pszMsg);
    }
    else
        m_strText.setNull();

    return S_OK;
}
Пример #3
0
/**
 *  Initializes itself by fetching error information from the given error info
 *  object.
 */
HRESULT VirtualBoxErrorInfo::init(IErrorInfo *aInfo)
{
    AssertReturn(aInfo, E_FAIL);

    HRESULT rc = S_OK;

    /* We don't return a failure if talking to IErrorInfo fails below to
     * protect ourselves from bad IErrorInfo implementations (the
     * corresponding fields will simply remain null in this case). */

    m_resultCode = S_OK;
    m_resultDetail = 0;
    rc = aInfo->GetGUID(m_IID.asOutParam());
    AssertComRC(rc);
    Bstr bstrComponent;
    rc = aInfo->GetSource(bstrComponent.asOutParam());
    AssertComRC(rc);
    m_strComponent = bstrComponent;
    Bstr bstrText;
    rc = aInfo->GetDescription(bstrText.asOutParam());
    AssertComRC(rc);
    m_strText = bstrText;

    return S_OK;
}
Пример #4
0
HRESULT MediumLockListMap::Lock()
{
    if (mIsLocked)
        return S_OK;
    HRESULT rc = S_OK;
    for (MediumLockListMap::Base::const_iterator it = mMediumLocks.begin();
         it != mMediumLocks.end();
         it++)
    {
        rc = it->second->Lock();
        if (FAILED(rc))
        {
            for (MediumLockListMap::Base::const_iterator it2 = mMediumLocks.begin();
                 it2 != it;
                 it2++)
            {
                HRESULT rc2 = it2->second->Unlock();
                AssertComRC(rc2);
            }
            break;
        }
    }
    if (SUCCEEDED(rc))
        mIsLocked = true;
    return rc;
}
Пример #5
0
/**
 * Performs the required actions when a device has been added.
 *
 * This means things like running filters and subsequent capturing and
 * VM attaching. This may result in IPC and temporary lock abandonment.
 *
 * @param   aDevice     The device in question.
 * @param   aUSBDevice  The USB device structure.
 */
void USBProxyService::deviceAdded(ComObjPtr<HostUSBDevice> &aDevice,
                                  SessionMachinesList &llOpenedMachines,
                                  PUSBDEVICE aUSBDevice)
{
    /*
     * Validate preconditions.
     */
    AssertReturnVoid(!isWriteLockOnCurrentThread());
    AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread());
    AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
    LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid}\n",
                     (HostUSBDevice *)aDevice,
                     aDevice->getName().c_str(),
                     aDevice->getStateName(),
                     aDevice->getId().raw()));

    /*
     * Run filters on the device.
     */
    if (aDevice->isCapturableOrHeld())
    {
        devLock.release();
        HRESULT rc = runAllFiltersOnDevice(aDevice, llOpenedMachines, NULL /* aIgnoreMachine */);
        AssertComRC(rc);
    }

    NOREF(aUSBDevice);
}
Пример #6
0
/**
 *  Uninitializes the Session object.
 *
 *  @note Locks this object for writing.
 */
void Session::uninit()
{
    LogFlowThisFuncEnter();

    /* Enclose the state transition Ready->InUninit->NotReady */
    AutoUninitSpan autoUninitSpan(this);
    if (autoUninitSpan.uninitDone())
    {
        LogFlowThisFunc(("Already uninitialized.\n"));
        LogFlowThisFuncLeave();
        return;
    }

    /* close() needs write lock */
    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

    if (mState != SessionState_Unlocked)
    {
        Assert(mState == SessionState_Locked ||
               mState == SessionState_Spawning);

        HRESULT rc = unlockMachine(true /* aFinalRelease */, false /* aFromServer */);
        AssertComRC(rc);
    }

    LogFlowThisFuncLeave();
}
Пример #7
0
/**
 * Handle a device which state changed in some significant way.
 *
 * This means things like running filters and subsequent capturing and
 * VM attaching. This may result in IPC and temporary lock abandonment.
 *
 * @param   aDevice         The device.
 * @param   pllOpenedMachines list of running session machines (VirtualBox::getOpenedMachines()); if NULL, we don't run filters
 * @param   aIgnoreMachine  Machine to ignore when running filters.
 */
void USBProxyService::deviceChanged(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList *pllOpenedMachines, SessionMachine *aIgnoreMachine)
{
    /*
     * Validate preconditions.
     */
    AssertReturnVoid(!isWriteLockOnCurrentThread());
    AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread());
    AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
    LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid} aRunFilters=%RTbool aIgnoreMachine=%p\n",
                     (HostUSBDevice *)aDevice,
                     aDevice->getName().c_str(),
                     aDevice->getStateName(),
                     aDevice->getId().raw(),
                     (pllOpenedMachines != NULL),       // used to be "bool aRunFilters"
                     aIgnoreMachine));
    devLock.release();

    /*
     * Run filters if requested to do so.
     */
    if (pllOpenedMachines)
    {
        HRESULT rc = runAllFiltersOnDevice(aDevice, *pllOpenedMachines, aIgnoreMachine);
        AssertComRC(rc);
    }
}
Пример #8
0
HRESULT MediumLockList::Lock(bool fSkipOverLockedMedia /* = false */)
{
    if (mIsLocked)
        return S_OK;
    HRESULT rc = S_OK;
    for (MediumLockList::Base::iterator it = mMediumLocks.begin();
         it != mMediumLocks.end();
         it++)
    {
        rc = it->Lock(fSkipOverLockedMedia);
        if (FAILED(rc))
        {
            for (MediumLockList::Base::iterator it2 = mMediumLocks.begin();
                 it2 != it;
                 it2++)
            {
                HRESULT rc2 = it2->Unlock();
                AssertComRC(rc2);
            }
            break;
        }
    }
    if (SUCCEEDED(rc))
        mIsLocked = true;
    return rc;
}
Пример #9
0
HRESULT ErrorInfoKeeper::restore()
{
    if (mForgot)
        return S_OK;

    HRESULT rc = S_OK;

#if !defined(VBOX_WITH_XPCOM)

    ComPtr<IErrorInfo> err;
    if (!mErrorInfo.isNull())
    {
        rc = mErrorInfo.queryInterfaceTo(err.asOutParam());
        AssertComRC(rc);
    }
    rc = ::SetErrorInfo(0, err);

#else // defined(VBOX_WITH_XPCOM)

    nsCOMPtr <nsIExceptionService> es;
    es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rc);
    if (NS_SUCCEEDED(rc))
    {
        nsCOMPtr <nsIExceptionManager> em;
        rc = es->GetCurrentExceptionManager(getter_AddRefs(em));
        if (NS_SUCCEEDED(rc))
        {
            ComPtr<nsIException> ex;
            if (!mErrorInfo.isNull())
            {
                rc = mErrorInfo.queryInterfaceTo(ex.asOutParam());
                AssertComRC(rc);
            }
            rc = em->SetCurrentException(ex);
        }
    }

#endif // defined(VBOX_WITH_XPCOM)

    if (SUCCEEDED(rc))
    {
        mErrorInfo.setNull();
        mForgot = true;
    }

    return rc;
}
Пример #10
0
/**
 *  Constructs an event queue for the current thread.
 *
 *  Currently, there can be only one event queue per thread, so if an event
 *  queue for the current thread already exists, this object is simply attached
 *  to the existing event queue.
 */
EventQueue::EventQueue()
{
#ifndef VBOX_WITH_XPCOM

    mThreadId = GetCurrentThreadId();
    // force the system to create the message queue for the current thread
    MSG msg;
    PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);

    if (!DuplicateHandle(GetCurrentProcess(),
                         GetCurrentThread(),
                         GetCurrentProcess(),
                         &mhThread,
                         0 /*dwDesiredAccess*/,
                         FALSE /*bInheritHandle*/,
                         DUPLICATE_SAME_ACCESS))
      mhThread = INVALID_HANDLE_VALUE;

#else // VBOX_WITH_XPCOM

    mEQCreated = false;
    mInterrupted = false;

    // Here we reference the global nsIEventQueueService instance and hold it
    // until we're destroyed. This is necessary to keep NS_ShutdownXPCOM() away
    // from calling StopAcceptingEvents() on all event queues upon destruction of
    // nsIEventQueueService, and makes sense when, for some reason, this happens
    // *before* we're able to send a NULL event to stop our event handler thread
    // when doing unexpected cleanup caused indirectly by NS_ShutdownXPCOM()
    // that is performing a global cleanup of everything. A good example of such
    // situation is when NS_ShutdownXPCOM() is called while the VirtualBox component
    // is still alive (because it is still referenced): eventually, it results in
    // a VirtualBox::uninit() call from where it is already not possible to post
    // NULL to the event thread (because it stopped accepting events).

    nsresult rc = NS_GetEventQueueService(getter_AddRefs(mEventQService));

    if (NS_SUCCEEDED(rc))
    {
        rc = mEventQService->GetThreadEventQueue(NS_CURRENT_THREAD,
                                                 getter_AddRefs(mEventQ));
        if (rc == NS_ERROR_NOT_AVAILABLE)
        {
            rc = mEventQService->CreateThreadEventQueue();
            if (NS_SUCCEEDED(rc))
            {
                mEQCreated = true;
                rc = mEventQService->GetThreadEventQueue(NS_CURRENT_THREAD,
                                                         getter_AddRefs(mEventQ));
            }
        }
    }
    AssertComRC(rc);

#endif // VBOX_WITH_XPCOM
}
bool GuestDnDResponse::isProgressCanceled(void) const
{
    BOOL fCanceled;
    if (!m_progress.isNull())
    {
        HRESULT hr = m_progress->COMGETTER(Canceled)(&fCanceled);
        AssertComRC(hr);
    }
    else
        fCanceled = TRUE;

    return RT_BOOL(fCanceled);
}
Пример #12
0
/**
 * Marks the operation as complete and attaches full error info.
 *
 * See VirtualBoxBase::setError(HRESULT, const GUID &, const wchar_t
 * *, const char *, ...) for more info.
 *
 * @param aResultCode   Operation result (error) code, must not be S_OK.
 * @param aIID          IID of the interface that defines the error.
 * @param aComponent    Name of the component that generates the error.
 * @param aText         Error message (must not be null), an RTStrPrintf-like
 *                      format string in UTF-8 encoding.
 * @param va            List of arguments for the format string.
 */
HRESULT Progress::i_notifyCompleteV(HRESULT aResultCode,
                                    const GUID &aIID,
                                    const char *pcszComponent,
                                    const char *aText,
                                    va_list va)
{
    Utf8Str text(aText, va);

    AutoCaller autoCaller(this);
    AssertComRCReturnRC(autoCaller.rc());

    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

    AssertReturn(mCompleted == FALSE, E_FAIL);

    if (mCanceled && SUCCEEDED(aResultCode))
        aResultCode = E_FAIL;

    mCompleted = TRUE;
    mResultCode = aResultCode;

    AssertReturn(FAILED(aResultCode), E_FAIL);

    ComObjPtr<VirtualBoxErrorInfo> errorInfo;
    HRESULT rc = errorInfo.createObject();
    AssertComRC(rc);
    if (SUCCEEDED(rc))
    {
        errorInfo->init(aResultCode, aIID, pcszComponent, text);
        errorInfo.queryInterfaceTo(mErrorInfo.asOutParam());
    }

#if !defined VBOX_COM_INPROC
    /* remove from the global collection of pending progress operations */
    if (mParent)
        mParent->i_removeProgress(mId.ref());
#endif

    /* wake up all waiting threads */
    if (mWaitersCount > 0)
        RTSemEventMultiSignal(mCompletedSem);

    return rc;
}
Пример #13
0
/**
 *  Unlocks a machine associated with the current session.
 *
 *  @param aFinalRelease    called as a result of FinalRelease()
 *  @param aFromServer      called as a result of Uninitialize()
 *
 *  @note To be called only from #uninit(), #UnlockMachine() or #Uninitialize().
 *  @note Locks this object for writing.
 */
HRESULT Session::unlockMachine(bool aFinalRelease, bool aFromServer)
{
    LogFlowThisFuncEnter();
    LogFlowThisFunc(("aFinalRelease=%d, isFromServer=%d\n",
                      aFinalRelease, aFromServer));

    AutoCaller autoCaller(this);
    AssertComRCReturnRC(autoCaller.rc());

    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

    LogFlowThisFunc(("mState=%s, mType=%d\n", Global::stringifySessionState(mState), mType));

    if (mState != SessionState_Locked)
    {
        Assert(mState == SessionState_Spawning);

        /* The session object is going to be uninitialized before it has been
         * assigned a direct console of the machine the client requested to open
         * a remote session to using IVirtualBox:: openRemoteSession(). It is OK
         * only if this close request comes from the server (for example, it
         * detected that the VM process it started terminated before opening a
         * direct session). Otherwise, it means that the client is too fast and
         * trying to close the session before waiting for the progress object it
         * got from IVirtualBox:: openRemoteSession() to complete, so assert. */
        Assert(aFromServer);

        mState = SessionState_Unlocked;
        mType = SessionType_Null;

        Assert(!mClientTokenHolder);

        LogFlowThisFuncLeave();
        return S_OK;
    }

    /* go to the closing state */
    mState = SessionState_Unlocking;

    if (mType == SessionType_WriteLock)
    {
        if (!mConsole.isNull())
        {
            mConsole->uninit();
            mConsole.setNull();
        }
    }
    else
    {
        mRemoteMachine.setNull();
        mRemoteConsole.setNull();
    }

    ComPtr<IProgress> progress;

    if (!aFinalRelease && !aFromServer)
    {
        /*
         *  We trigger OnSessionEnd() only when the session closes itself using
         *  Close(). Note that if isFinalRelease = TRUE here, this means that
         *  the client process has already initialized the termination procedure
         *  without issuing Close() and the IPC channel is no more operational --
         *  so we cannot call the server's method (it will definitely fail). The
         *  server will instead simply detect the abnormal client death (since
         *  OnSessionEnd() is not called) and reset the machine state to Aborted.
         */

        /*
         *  while waiting for OnSessionEnd() to complete one of our methods
         *  can be called by the server (for example, Uninitialize(), if the
         *  direct session has initiated a closure just a bit before us) so
         *  we need to release the lock to avoid deadlocks. The state is already
         *  SessionState_Closing here, so it's safe.
         */
        alock.release();

        LogFlowThisFunc(("Calling mControl->OnSessionEnd()...\n"));
        HRESULT rc = mControl->OnSessionEnd(this, progress.asOutParam());
        LogFlowThisFunc(("mControl->OnSessionEnd()=%08X\n", rc));

        alock.acquire();

        /*
         *  If we get E_UNEXPECTED this means that the direct session has already
         *  been closed, we're just too late with our notification and nothing more
         *
         *  bird: Seems E_ACCESSDENIED is what gets returned these days; see
         *        VirtualBoxBase::addCaller.
         */
        if (mType != SessionType_WriteLock && (rc == E_UNEXPECTED || rc == E_ACCESSDENIED))
            rc = S_OK;

#ifndef DEBUG_bird /* I don't want clients crashing on me just because VBoxSVC went belly up. */
        AssertComRC(rc);
#endif
    }

    mControl.setNull();

    if (mType == SessionType_WriteLock)
    {
        if (mClientTokenHolder)
        {
            delete mClientTokenHolder;
            mClientTokenHolder = NULL;
        }

        if (!aFinalRelease && !aFromServer)
        {
            /*
             *  Wait for the server to grab the semaphore and destroy the session
             *  machine (allowing us to open a new session with the same machine
             *  once this method returns)
             */
            Assert(!!progress);
            if (progress)
                progress->WaitForCompletion(-1);
        }
    }

    mState = SessionState_Unlocked;
    mType = SessionType_Null;

    /* release the VirtualBox instance as the very last step */
    mVirtualBox.setNull();

    LogFlowThisFuncLeave();
    return S_OK;
}
Пример #14
0
/**
 * Process any relevant changes in the attached USB devices.
 *
 * Except for the first call, this is always running on the service thread.
 */
void USBProxyService::processChanges(void)
{
    LogFlowThisFunc(("\n"));

    /*
     * Get the sorted list of USB devices.
     */
    PUSBDEVICE pDevices = getDevices();
    pDevices = sortDevices(pDevices);

    // get a list of all running machines while we're outside the lock
    // (getOpenedMachines requests higher priority locks)
    SessionMachinesList llOpenedMachines;
    mHost->parent()->getOpenedMachines(llOpenedMachines);

    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

    /*
     * Compare previous list with the new list of devices
     * and merge in any changes while notifying Host.
     */
    HostUSBDeviceList::iterator it = this->mDevices.begin();
    while (    it != mDevices.end()
            || pDevices)
    {
        ComObjPtr<HostUSBDevice> pHostDevice;

        if (it != mDevices.end())
            pHostDevice = *it;

        /*
         * Assert that the object is still alive (we still reference it in
         * the collection and we're the only one who calls uninit() on it.
         */
        AutoCaller devCaller(pHostDevice.isNull() ? NULL : pHostDevice);
        AssertComRC(devCaller.rc());

        /*
         * Lock the device object since we will read/write its
         * properties. All Host callbacks also imply the object is locked.
         */
        AutoWriteLock devLock(pHostDevice.isNull() ? NULL : pHostDevice
                              COMMA_LOCKVAL_SRC_POS);

        /*
         * Compare.
         */
        int iDiff;
        if (pHostDevice.isNull())
            iDiff = 1;
        else
        {
            if (!pDevices)
                iDiff = -1;
            else
                iDiff = pHostDevice->compare(pDevices);
        }
        if (!iDiff)
        {
            /*
             * The device still there, update the state and move on. The PUSBDEVICE
             * structure is eaten by updateDeviceState / HostUSBDevice::updateState().
             */
            PUSBDEVICE pCur = pDevices;
            pDevices = pDevices->pNext;
            pCur->pPrev = pCur->pNext = NULL;

            bool fRunFilters = false;
            SessionMachine *pIgnoreMachine = NULL;
            devLock.release();
            alock.release();
            if (updateDeviceState(pHostDevice, pCur, &fRunFilters, &pIgnoreMachine))
                deviceChanged(pHostDevice,
                              (fRunFilters ? &llOpenedMachines : NULL),
                              pIgnoreMachine);
            alock.acquire();
            it++;
        }
        else
        {
            if (iDiff > 0)
            {
                /*
                 * Head of pDevices was attached.
                 */
                PUSBDEVICE pNew = pDevices;
                pDevices = pDevices->pNext;
                pNew->pPrev = pNew->pNext = NULL;

                ComObjPtr<HostUSBDevice> NewObj;
                NewObj.createObject();
                NewObj->init(pNew, this);
                Log(("USBProxyService::processChanges: attached %p {%s} %s / %p:{.idVendor=%#06x, .idProduct=%#06x, .pszProduct=\"%s\", .pszManufacturer=\"%s\"}\n",
                     (HostUSBDevice *)NewObj,
                     NewObj->getName().c_str(),
                     NewObj->getStateName(),
                     pNew,
                     pNew->idVendor,
                     pNew->idProduct,
                     pNew->pszProduct,
                     pNew->pszManufacturer));

                mDevices.insert(it, NewObj);

                devLock.release();
                alock.release();
                deviceAdded(NewObj, llOpenedMachines, pNew);
                alock.acquire();
            }
            else
            {
                /*
                 * Check if the device was actually detached or logically detached
                 * as the result of a re-enumeration.
                 */
                if (!pHostDevice->wasActuallyDetached())
                    it++;
                else
                {
                    it = mDevices.erase(it);
                    devLock.release();
                    alock.release();
                    deviceRemoved(pHostDevice);
                    Log(("USBProxyService::processChanges: detached %p {%s}\n",
                         (HostUSBDevice *)pHostDevice,
                         pHostDevice->getName().c_str()));

                    /* from now on, the object is no more valid,
                     * uninitialize to avoid abuse */
                    devCaller.release();
                    pHostDevice->uninit();
                    alock.acquire();
                }
            }
        }
    } /* while */

    LogFlowThisFunc(("returns void\n"));
}
Пример #15
0
/**
 * Called to copy over the progress information from @a pOtherProgress.
 *
 * @param   pOtherProgress  The source of the information.
 * @param   fEarly          Early copy.
 *
 * @note    The caller owns the write lock and as cleared mptrOtherProgress
 *          already (or we might recurse forever)!
 */
void ProgressProxy::copyProgressInfo(IProgress *pOtherProgress, bool fEarly)
{
    HRESULT hrc;
    LogFlowThisFunc(("\n"));

    NOREF(fEarly);

    /*
     * No point in doing this if the progress object was canceled already.
     */
    if (!mCanceled)
    {
        /* Detect if the other progress object was canceled. */
        BOOL fCanceled;
        hrc = pOtherProgress->COMGETTER(Canceled)(&fCanceled);
        if (FAILED(hrc))
            fCanceled = FALSE;
        if (fCanceled)
        {
            LogFlowThisFunc(("Canceled\n"));
            mCanceled = TRUE;
            if (m_pfnCancelCallback)
                m_pfnCancelCallback(m_pvCancelUserArg);
        }
        else
        {
            /* Has it completed? */
            BOOL fCompleted;
            hrc = pOtherProgress->COMGETTER(Completed)(&fCompleted);
            if (FAILED(hrc))
                fCompleted = TRUE;
            Assert(fCompleted || fEarly);
            if (fCompleted)
            {
                /* Check the result. */
                LONG hrcResult;
                hrc = pOtherProgress->COMGETTER(ResultCode)(&hrcResult);
                if (FAILED(hrc))
                    hrcResult = hrc;
                if (SUCCEEDED((HRESULT)hrcResult))
                    LogFlowThisFunc(("Succeeded\n"));
                else
                {
                    /* Get the error information. */
                    ComPtr<IVirtualBoxErrorInfo> ptrErrorInfo;
                    hrc = pOtherProgress->COMGETTER(ErrorInfo)(ptrErrorInfo.asOutParam());
                    if (SUCCEEDED(hrc) && !ptrErrorInfo.isNull())
                    {
                        Bstr bstrIID;
                        hrc = ptrErrorInfo->COMGETTER(InterfaceID)(bstrIID.asOutParam()); AssertComRC(hrc);
                        if (FAILED(hrc))
                            bstrIID.setNull();

                        Bstr bstrComponent;
                        hrc = ptrErrorInfo->COMGETTER(Component)(bstrComponent.asOutParam()); AssertComRC(hrc);
                        if (FAILED(hrc))
                            bstrComponent = "failed";

                        Bstr bstrText;
                        hrc = ptrErrorInfo->COMGETTER(Text)(bstrText.asOutParam()); AssertComRC(hrc);
                        if (FAILED(hrc))
                            bstrText = "<failed>";

                        Utf8Str strText(bstrText);
                        LogFlowThisFunc(("Got ErrorInfo(%s); hrcResult=%Rhrc\n", strText.c_str(), hrcResult));
                        Progress::notifyComplete((HRESULT)hrcResult,
                                                 Guid(bstrIID).ref(),
                                                 Utf8Str(bstrComponent).c_str(),
                                                 "%s", strText.c_str());
                    }
                    else
                    {
                        LogFlowThisFunc(("ErrorInfo failed with hrc=%Rhrc; hrcResult=%Rhrc\n", hrc, hrcResult));
                        Progress::notifyComplete((HRESULT)hrcResult,
                                                 COM_IIDOF(IProgress),
                                                 "ProgressProxy",
                                                 tr("No error info"));
                    }
                }
            }
            else
                LogFlowThisFunc(("Not completed\n"));
        }
    }
    else
        LogFlowThisFunc(("Already canceled\n"));

    /*
     * Did cancelable state change (point of no return)?
     */
    if (mCancelable && !mCompleted && !mCanceled)
    {
        BOOL fCancelable;
        hrc = pOtherProgress->COMGETTER(Cancelable)(&fCancelable); AssertComRC(hrc);
        if (SUCCEEDED(hrc) && !fCancelable)
        {
            LogFlowThisFunc(("point-of-no-return reached\n"));
            mCancelable = FALSE;
        }
    }
}
int GuestDnDResponse::setProgress(unsigned uPercentage,
                                  uint32_t uStatus,
                                  int rcOp /* = VINF_SUCCESS */, const Utf8Str &strMsg /* = "" */)
{
    LogFlowFunc(("uStatus=%RU32, uPercentage=%RU32, rcOp=%Rrc, strMsg=%s\n",
                 uStatus, uPercentage, rcOp, strMsg.c_str()));

    int rc = VINF_SUCCESS;
    if (!m_progress.isNull())
    {
        BOOL fCompleted;
        HRESULT hr = m_progress->COMGETTER(Completed)(&fCompleted);
        AssertComRC(hr);

        BOOL fCanceled;
        hr = m_progress->COMGETTER(Canceled)(&fCanceled);
        AssertComRC(hr);

        LogFlowFunc(("Current: fCompleted=%RTbool, fCanceled=%RTbool\n", fCompleted, fCanceled));

        if (!fCompleted)
        {
            switch (uStatus)
            {
                case DragAndDropSvc::DND_PROGRESS_ERROR:
                {
                    hr = m_progress->i_notifyComplete(VBOX_E_IPRT_ERROR,
                                                      COM_IIDOF(IGuest),
                                                      m_parent->getComponentName(), strMsg.c_str());
                    reset();
                    break;
                }

                case DragAndDropSvc::DND_PROGRESS_CANCELLED:
                {
                    hr = m_progress->i_notifyComplete(S_OK);
                    AssertComRC(hr);

                    reset();
                    break;
                }

                case DragAndDropSvc::DND_PROGRESS_RUNNING:
                case DragAndDropSvc::DND_PROGRESS_COMPLETE:
                {
                    if (!fCanceled)
                    {
                        hr = m_progress->SetCurrentOperationProgress(uPercentage);
                        AssertComRC(hr);
                        if (   uStatus     == DragAndDropSvc::DND_PROGRESS_COMPLETE
                            || uPercentage >= 100)
                        {
                            hr = m_progress->i_notifyComplete(S_OK);
                            AssertComRC(hr);
                        }
                    }
                    break;
                }

                default:
                    break;
            }
        }

        hr = m_progress->COMGETTER(Completed)(&fCompleted);
        AssertComRC(hr);
        hr = m_progress->COMGETTER(Canceled)(&fCanceled);
        AssertComRC(hr);

        LogFlowFunc(("New: fCompleted=%RTbool, fCanceled=%RTbool\n", fCompleted, fCanceled));
    }

    LogFlowFuncLeaveRC(rc);
    return rc;
}
Пример #17
0
void ErrorInfo::init(bool aKeepObj /* = false */)
{
    HRESULT rc = E_FAIL;

#if !defined(VBOX_WITH_XPCOM)

    ComPtr<IErrorInfo> err;
    rc = ::GetErrorInfo(0, err.asOutParam());
    if (rc == S_OK && err)
    {
        if (aKeepObj)
            mErrorInfo = err;

        ComPtr<IVirtualBoxErrorInfo> info;
        rc = err.queryInterfaceTo(info.asOutParam());
        if (SUCCEEDED(rc) && info)
            init(info);

        if (!mIsFullAvailable)
        {
            bool gotSomething = false;

            rc = err->GetGUID(mInterfaceID.asOutParam());
            gotSomething |= SUCCEEDED(rc);
            if (SUCCEEDED(rc))
                GetInterfaceNameByIID(mInterfaceID.ref(), mInterfaceName.asOutParam());

            rc = err->GetSource(mComponent.asOutParam());
            gotSomething |= SUCCEEDED(rc);

            rc = err->GetDescription(mText.asOutParam());
            gotSomething |= SUCCEEDED(rc);

            if (gotSomething)
                mIsBasicAvailable = true;

            AssertMsg(gotSomething, ("Nothing to fetch!\n"));
        }
    }

#else // defined(VBOX_WITH_XPCOM)

    nsCOMPtr<nsIExceptionService> es;
    es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rc);
    if (NS_SUCCEEDED(rc))
    {
        nsCOMPtr<nsIExceptionManager> em;
        rc = es->GetCurrentExceptionManager(getter_AddRefs(em));
        if (NS_SUCCEEDED(rc))
        {
            ComPtr<nsIException> ex;
            rc = em->GetCurrentException(ex.asOutParam());
            if (NS_SUCCEEDED(rc) && ex)
            {
                if (aKeepObj)
                    mErrorInfo = ex;

                ComPtr<IVirtualBoxErrorInfo> info;
                rc = ex.queryInterfaceTo(info.asOutParam());
                if (NS_SUCCEEDED(rc) && info)
                    init(info);

                if (!mIsFullAvailable)
                {
                    bool gotSomething = false;

                    rc = ex->GetResult(&mResultCode);
                    gotSomething |= NS_SUCCEEDED(rc);

                    char *pszMsg;
                    rc = ex->GetMessage(&pszMsg);
                    gotSomething |= NS_SUCCEEDED(rc);
                    if (NS_SUCCEEDED(rc))
                    {
                        mText = Bstr(pszMsg);
                        nsMemory::Free(pszMsg);
                    }

                    if (gotSomething)
                        mIsBasicAvailable = true;

                    AssertMsg(gotSomething, ("Nothing to fetch!\n"));
                }

                // set the exception to NULL (to emulate Win32 behavior)
                em->SetCurrentException(NULL);

                rc = NS_OK;
            }
        }
    }
    /* Ignore failure when called after nsComponentManagerImpl::Shutdown(). */
    else if (rc == NS_ERROR_UNEXPECTED)
        rc = NS_OK;

    AssertComRC(rc);

#endif // defined(VBOX_WITH_XPCOM)
}
int NetworkManager::processParameterReqList(const Client& client, const uint8_t *pu8ReqList,
                                            int cReqList, std::vector<RawOption>& extra)
{
    int rc;

    const Lease l = client.lease();

    const NetworkConfigEntity *pNetCfg = l.getConfig();

    /*
     * XXX: Brute-force.  Unfortunately, there's no notification event
     * for changes.  Should at least cache the options for a short
     * time, enough to last discover/offer/request/ack cycle.
     */
    typedef std::map< int, std::pair<std::string, int> > DhcpOptionMap;
    DhcpOptionMap OptMap;

    if (!m->m_DhcpServer.isNull())
    {
        com::SafeArray<BSTR> strings;
        com::Bstr str;
        HRESULT hrc;
        int OptCode, OptEncoding;
        char *pszOptText;

        strings.setNull();
        hrc = m->m_DhcpServer->COMGETTER(GlobalOptions)(ComSafeArrayAsOutParam(strings));
        AssertComRC(hrc);
        for (size_t i = 0; i < strings.size(); ++i)
        {
            com::Utf8Str encoded(strings[i]);
            rc = parseDhcpOptionText(encoded.c_str(),
                                     &OptCode, &pszOptText, &OptEncoding);
            if (!RT_SUCCESS(rc))
                continue;

            OptMap[OptCode] = std::make_pair(pszOptText, OptEncoding);
        }

        const RTMAC &mac = client.getMacAddress();
        char strMac[6*2+1] = "";
        RTStrPrintf(strMac, sizeof(strMac), "%02x%02x%02x%02x%02x%02x",
                    mac.au8[0], mac.au8[1], mac.au8[2],
                    mac.au8[3], mac.au8[4], mac.au8[5]);

        strings.setNull();
        hrc = m->m_DhcpServer->GetMacOptions(com::Bstr(strMac).raw(),
                                             ComSafeArrayAsOutParam(strings));
        AssertComRC(hrc);
        for (size_t i = 0; i < strings.size(); ++i)
        {
            com::Utf8Str text(strings[i]);
            rc = parseDhcpOptionText(text.c_str(),
                                     &OptCode, &pszOptText, &OptEncoding);
            if (!RT_SUCCESS(rc))
                continue;

            OptMap[OptCode] = std::make_pair(pszOptText, OptEncoding);
        }
    }

    /* request parameter list */
    RawOption opt;
    bool fIgnore;
    uint8_t u8Req;
    for (int idxParam = 0; idxParam < cReqList; ++idxParam)
    {
        fIgnore = false;
        RT_ZERO(opt);
        u8Req = opt.u8OptId = pu8ReqList[idxParam];

        switch(u8Req)
        {
            case RTNET_DHCP_OPT_SUBNET_MASK:
                ((PRTNETADDRIPV4)opt.au8RawOpt)->u = pNetCfg->netmask().u;
                opt.cbRawOpt = sizeof(RTNETADDRIPV4);

                break;

            case RTNET_DHCP_OPT_ROUTERS:
            case RTNET_DHCP_OPT_DNS:
                {
                    const Ipv4AddressContainer lst =
                      g_ConfigurationManager->getAddressList(u8Req);
                    PRTNETADDRIPV4 pAddresses = (PRTNETADDRIPV4)&opt.au8RawOpt[0];

                    for (Ipv4AddressConstIterator it = lst.begin();
                         it != lst.end();
                         ++it)
                    {
                        *pAddresses = (*it);
                        pAddresses++;
                        opt.cbRawOpt += sizeof(RTNETADDRIPV4);
                    }

                    if (lst.empty())
                        fIgnore = true;
                }
                break;
            case RTNET_DHCP_OPT_DOMAIN_NAME:
                {
                    std::string domainName = g_ConfigurationManager->getString(u8Req);
                    if (domainName == g_ConfigurationManager->m_noString)
                    {
                        fIgnore = true;
                        break;
                    }

                    char *pszDomainName = (char *)&opt.au8RawOpt[0];

                    strcpy(pszDomainName, domainName.c_str());
                    opt.cbRawOpt = domainName.length();
                }
                break;
            default:
                {
                    DhcpOptionMap::const_iterator it = OptMap.find((int)u8Req);
                    if (it == OptMap.end())
                    {
                        Log(("opt: %d is ignored\n", u8Req));
                        fIgnore = true;
                    }
                    else
                    {
                        std::string OptText((*it).second.first);
                        int OptEncoding((*it).second.second);

                        rc = fillDhcpOption(opt, OptText, OptEncoding);
                        if (!RT_SUCCESS(rc))
                        {
                            fIgnore = true;
                            break;
                        }
                    }
                }
                break;
        }

        if (!fIgnore)
            extra.push_back(opt);

    }

    return VINF_SUCCESS;
}
Пример #19
0
HRESULT Shutdown()
{
    HRESULT rc = S_OK;

#if !defined(VBOX_WITH_XPCOM)

    /* EventQueue::uninit reference counting fun. */
    RTTHREAD hSelf = RTThreadSelf();
    if (    hSelf == gCOMMainThread
        &&  hSelf != NIL_RTTHREAD)
    {
        if (-- gCOMMainInitCount == 0)
        {
            EventQueue::uninit();
            ASMAtomicWriteHandle(&gCOMMainThread, NIL_RTTHREAD);
        }
    }

    CoUninitialize();

#else /* !defined (VBOX_WITH_XPCOM) */

    nsCOMPtr<nsIEventQueue> eventQ;
    rc = NS_GetMainEventQ(getter_AddRefs(eventQ));

    if (NS_SUCCEEDED(rc) || rc == NS_ERROR_NOT_AVAILABLE)
    {
        /* NS_ERROR_NOT_AVAILABLE seems to mean that
         * nsIEventQueue::StopAcceptingEvents() has been called (see
         * nsEventQueueService.cpp). We hope that this error code always means
         * just that in this case and assume that we're on the main thread
         * (it's a kind of unexpected behavior if a non-main thread ever calls
         * StopAcceptingEvents() on the main event queue). */

        PRBool isOnMainThread = PR_FALSE;
        if (NS_SUCCEEDED(rc))
        {
            rc = eventQ->IsOnCurrentThread(&isOnMainThread);
            eventQ = nsnull; /* early release before shutdown */
        }
        else
        {
            isOnMainThread = PR_TRUE;
            rc = NS_OK;
        }

        if (NS_SUCCEEDED(rc) && isOnMainThread)
        {
            /* only the main thread needs to uninitialize XPCOM and only if
             * init counter drops to zero */
            if (--gXPCOMInitCount == 0)
            {
                EventQueue::uninit();
                rc = NS_ShutdownXPCOM(nsnull);

                /* This is a thread initialized XPCOM and set gIsXPCOMInitialized to
                 * true. Reset it back to false. */
                bool wasInited = ASMAtomicXchgBool(&gIsXPCOMInitialized, false);
                Assert(wasInited == true);
                NOREF(wasInited);

# if defined (XPCOM_GLUE)
                XPCOMGlueShutdown();
# endif
            }
        }
    }

#endif /* !defined(VBOX_WITH_XPCOM) */

    AssertComRC(rc);

    return rc;
}
Пример #20
0
/**
 * Initializes the COM runtime.
 *
 * This method must be called on each thread of the client application that
 * wants to access COM facilities. The initialization must be performed before
 * calling any other COM method or attempting to instantiate COM objects.
 *
 * On platforms using XPCOM, this method uses the following scheme to search for
 * XPCOM runtime:
 *
 * 1. If the VBOX_APP_HOME environment variable is set, the path it specifies
 *    is used to search XPCOM libraries and components. If this method fails to
 *    initialize XPCOM runtime using this path, it will immediately return a
 *    failure and will NOT check for other paths as described below.
 *
 * 2. If VBOX_APP_HOME is not set, this methods tries the following paths in the
 *    given order:
 *
 *    a) Compiled-in application data directory (as returned by
 *       RTPathAppPrivateArch())
 *    b) "/usr/lib/virtualbox" (Linux only)
 *    c) "/opt/VirtualBox" (Linux only)
 *
 *    The first path for which the initialization succeeds will be used.
 *
 * On MS COM platforms, the COM runtime is provided by the system and does not
 * need to be searched for.
 *
 * Once the COM subsystem is no longer necessary on a given thread, Shutdown()
 * must be called to free resources allocated for it. Note that a thread may
 * call Initialize() several times but for each of tese calls there must be a
 * corresponding Shutdown() call.
 *
 * @return S_OK on success and a COM result code in case of failure.
 */
HRESULT Initialize(bool fGui)
{
    HRESULT rc = E_FAIL;

#if !defined(VBOX_WITH_XPCOM)

    /*
     * We initialize COM in GUI thread in STA, to be compliant with QT and
     * OLE requirments (for example to allow D&D), while other threads
     * initialized in regular MTA. To allow fast proxyless access from
     * GUI thread to COM objects, we explicitly provide our COM objects
     * with free threaded marshaller.
     * !!!!! Please think twice before touching this code !!!!!
     */
    DWORD flags = fGui ?
                  COINIT_APARTMENTTHREADED
                | COINIT_SPEED_OVER_MEMORY
                :
                  COINIT_MULTITHREADED
                | COINIT_DISABLE_OLE1DDE
                | COINIT_SPEED_OVER_MEMORY;

    rc = CoInitializeEx(NULL, flags);

    /* the overall result must be either S_OK or S_FALSE (S_FALSE means
     * "already initialized using the same apartment model") */
    AssertMsg(rc == S_OK || rc == S_FALSE, ("rc=%08X\n", rc));

    /* To be flow compatible with the XPCOM case, we return here if this isn't
     * the main thread or if it isn't its first initialization call.
     * Note! CoInitializeEx and CoUninitialize does it's own reference
     *       counting, so this exercise is entirely for the EventQueue init. */
    bool fRc;
    RTTHREAD hSelf = RTThreadSelf();
    if (hSelf != NIL_RTTHREAD)
        ASMAtomicCmpXchgHandle(&gCOMMainThread, hSelf, NIL_RTTHREAD, fRc);
    else
        fRc = false;

    if (fGui)
        Assert(RTThreadIsMain(hSelf));

    if (!fRc)
    {
        if (   gCOMMainThread == hSelf
            && SUCCEEDED(rc))
            gCOMMainInitCount++;

        AssertComRC(rc);
        return rc;
    }
    Assert(RTThreadIsMain(hSelf));

    /* this is the first main thread initialization */
    Assert(gCOMMainInitCount == 0);
    if (SUCCEEDED(rc))
        gCOMMainInitCount = 1;

#else /* !defined (VBOX_WITH_XPCOM) */

    /* Unused here */
    NOREF(fGui);

    if (ASMAtomicXchgBool(&gIsXPCOMInitialized, true) == true)
    {
        /* XPCOM is already initialized on the main thread, no special
         * initialization is necessary on additional threads. Just increase
         * the init counter if it's a main thread again (to correctly support
         * nested calls to Initialize()/Shutdown() for compatibility with
         * Win32). */

        nsCOMPtr<nsIEventQueue> eventQ;
        rc = NS_GetMainEventQ(getter_AddRefs(eventQ));

        if (NS_SUCCEEDED(rc))
        {
            PRBool isOnMainThread = PR_FALSE;
            rc = eventQ->IsOnCurrentThread(&isOnMainThread);
            if (NS_SUCCEEDED(rc) && isOnMainThread)
                ++gXPCOMInitCount;
        }

        AssertComRC(rc);
        return rc;
    }
    Assert(RTThreadIsMain(RTThreadSelf()));

    /* this is the first initialization */
    gXPCOMInitCount = 1;
    bool const fInitEventQueues = true;

    /* prepare paths for registry files */
    char szCompReg[RTPATH_MAX];
    char szXptiDat[RTPATH_MAX];

    int vrc = GetVBoxUserHomeDirectory(szCompReg, sizeof(szCompReg));
    AssertRCReturn(vrc, NS_ERROR_FAILURE);
    strcpy(szXptiDat, szCompReg);

    vrc = RTPathAppend(szCompReg, sizeof(szCompReg), "compreg.dat");
    AssertRCReturn(vrc, NS_ERROR_FAILURE);
    vrc = RTPathAppend(szXptiDat, sizeof(szXptiDat), "xpti.dat");
    AssertRCReturn(vrc, NS_ERROR_FAILURE);

    LogFlowFunc(("component registry  : \"%s\"\n", szCompReg));
    LogFlowFunc(("XPTI data file      : \"%s\"\n", szXptiDat));

#if defined (XPCOM_GLUE)
    XPCOMGlueStartup(nsnull);
#endif

    static const char *kAppPathsToProbe[] =
    {
        NULL, /* 0: will use VBOX_APP_HOME */
        NULL, /* 1: will try RTPathAppPrivateArch() */
#ifdef RT_OS_LINUX
        "/usr/lib/virtualbox",
        "/opt/VirtualBox",
#elif RT_OS_SOLARIS
        "/opt/VirtualBox/amd64",
        "/opt/VirtualBox/i386",
#elif RT_OS_DARWIN
        "/Application/VirtualBox.app/Contents/MacOS",
#endif
    };

    /* Find out the directory where VirtualBox binaries are located */
    for (size_t i = 0; i < RT_ELEMENTS(kAppPathsToProbe); ++ i)
    {
        char szAppHomeDir[RTPATH_MAX];

        if (i == 0)
        {
            /* Use VBOX_APP_HOME if present */
            vrc = RTEnvGetEx(RTENV_DEFAULT, "VBOX_APP_HOME", szAppHomeDir, sizeof(szAppHomeDir), NULL);
            if (vrc == VERR_ENV_VAR_NOT_FOUND)
                continue;
            AssertRC(vrc);
        }
        else if (i == 1)
        {
            /* Use RTPathAppPrivateArch() first */
            vrc = RTPathAppPrivateArch(szAppHomeDir, sizeof(szAppHomeDir));
            AssertRC(vrc);
        }
        else
        {
            /* Iterate over all other paths */
            szAppHomeDir[RTPATH_MAX - 1] = '\0';
            strncpy(szAppHomeDir, kAppPathsToProbe[i], RTPATH_MAX - 1);
            vrc = VINF_SUCCESS;
        }
        if (RT_FAILURE(vrc))
        {
            rc = NS_ERROR_FAILURE;
            continue;
        }

        char szCompDir[RTPATH_MAX];
        vrc = RTPathAppend(strcpy(szCompDir, szAppHomeDir), sizeof(szCompDir), "components");
        if (RT_FAILURE(vrc))
        {
            rc = NS_ERROR_FAILURE;
            continue;
        }
        LogFlowFunc(("component directory : \"%s\"\n", szCompDir));

        nsCOMPtr<DirectoryServiceProvider> dsProv;
        dsProv = new DirectoryServiceProvider();
        if (dsProv)
            rc = dsProv->init(szCompReg, szXptiDat, szCompDir, szAppHomeDir);
        else
            rc = NS_ERROR_OUT_OF_MEMORY;
        if (NS_FAILED(rc))
            break;

        /* Setup the application path for NS_InitXPCOM2. Note that we properly
         * answer the NS_XPCOM_CURRENT_PROCESS_DIR query in our directory
         * service provider but it seems to be activated after the directory
         * service is used for the first time (see the source NS_InitXPCOM2). So
         * use the same value here to be on the safe side. */
        nsCOMPtr <nsIFile> appDir;
        {
            char *appDirCP = NULL;
            vrc = RTStrUtf8ToCurrentCP(&appDirCP, szAppHomeDir);
            if (RT_SUCCESS(vrc))
            {
                nsCOMPtr<nsILocalFile> file;
                rc = NS_NewNativeLocalFile(nsEmbedCString(appDirCP),
                                           PR_FALSE, getter_AddRefs(file));
                if (NS_SUCCEEDED(rc))
                    appDir = do_QueryInterface(file, &rc);

                RTStrFree(appDirCP);
            }
            else
                rc = NS_ERROR_FAILURE;
        }
        if (NS_FAILED(rc))
            break;

        /* Set VBOX_XPCOM_HOME to the same app path to make XPCOM sources that
         * still use it instead of the directory service happy */
        vrc = RTEnvSetEx(RTENV_DEFAULT, "VBOX_XPCOM_HOME", szAppHomeDir);
        AssertRC(vrc);

        /* Finally, initialize XPCOM */
        {
            nsCOMPtr<nsIServiceManager> serviceManager;
            rc = NS_InitXPCOM2(getter_AddRefs(serviceManager), appDir, dsProv);
            if (NS_SUCCEEDED(rc))
            {
                nsCOMPtr<nsIComponentRegistrar> registrar =
                    do_QueryInterface(serviceManager, &rc);
                if (NS_SUCCEEDED(rc))
                {
                    rc = registrar->AutoRegister(nsnull);
                    if (NS_SUCCEEDED(rc))
                    {
                        /* We succeeded, stop probing paths */
                        LogFlowFunc(("Succeeded.\n"));
                        break;
                    }
                }
            }
        }

        /* clean up before the new try */
        rc = NS_ShutdownXPCOM(nsnull);

        if (i == 0)
        {
            /* We failed with VBOX_APP_HOME, don't probe other paths */
            break;
        }
    }

#endif /* !defined (VBOX_WITH_XPCOM) */

    // for both COM and XPCOM, we only get here if this is the main thread;
    // only then initialize the autolock system (AutoLock.cpp)
    Assert(RTThreadIsMain(RTThreadSelf()));
    util::InitAutoLockSystem();

    AssertComRC(rc);

    /*
     * Init the main event queue (ASSUMES it cannot fail).
     */
    if (SUCCEEDED(rc))
        EventQueue::init();

    return rc;
}