示例#1
0
文件: tftp.c 项目: ryenus/vbox
DECLINLINE(int) tftpSessionEvaluateOptions(PNATState pData, PTFTPSESSION pTftpSession)
{
    int rc = VINF_SUCCESS;
    RTFILE hSessionFile;
    uint64_t cbSessionFile = 0;
    LogFlowFunc(("pTftpSession:%p\n", pTftpSession));

    rc = pftpSessionOpenFile(pData, pTftpSession, &hSessionFile);
    if (RT_FAILURE(rc))
    {
        LogFlowFuncLeave();
        return rc;
    }

    rc = RTFileGetSize(hSessionFile, &cbSessionFile);
    RTFileClose(hSessionFile);
    if (RT_FAILURE(rc))
    {
        LogFlowFuncLeave();
        return rc;
    }

    if (pTftpSession->OptionTSize.fRequested)
    {
       pTftpSession->OptionTSize.u64Value = cbSessionFile;
    }
    if (   !pTftpSession->OptionBlkSize.u64Value
        && !pTftpSession->OptionBlkSize.fRequested)
    {
        pTftpSession->OptionBlkSize.u64Value = 1428;
    }
    LogFlowFuncLeaveRC(rc);
    return rc;
}
示例#2
0
文件: tftp.c 项目: ryenus/vbox
DECLINLINE(void) tftpProcessRRQ(PNATState pData, PCTFTPIPHDR pTftpIpHeader, int pktlen)
{
    PTFTPSESSION pTftpSession = NULL;
    uint8_t *pu8Payload = NULL;
    int     cbPayload = 0;
    size_t cbFileName = 0;
    int rc = VINF_SUCCESS;

    AssertPtrReturnVoid(pTftpIpHeader);
    AssertPtrReturnVoid(pData);
    AssertReturnVoid(pktlen > sizeof(TFTPIPHDR));
    LogFlowFunc(("ENTER: pTftpIpHeader:%p, pktlen:%d\n", pTftpIpHeader, pktlen));

    rc = tftpAllocateSession(pData, pTftpIpHeader, &pTftpSession);
    if (   RT_FAILURE(rc)
        || pTftpSession == NULL)
    {
        LogFlowFuncLeave();
        return;
    }

    pu8Payload = (uint8_t *)&pTftpIpHeader->Core;
    cbPayload = pktlen - sizeof(TFTPIPHDR);

    cbFileName = RTStrNLen((char *)pu8Payload, cbPayload);
    /* We assume that file name should finish with '\0' and shouldn't bigger
     *  than buffer for name storage.
     */
    AssertReturnVoid(   cbFileName < cbPayload
                     && cbFileName < TFTP_FILENAME_MAX /* current limit in tftp session handle */
                     && cbFileName);

    /* Dont't bother with rest processing in case of invalid access */
    if (RT_FAILURE(tftpSecurityFilenameCheck(pData, pTftpSession)))
    {
        tftpSendError(pData, pTftpSession, 2, "Access violation", pTftpIpHeader);
        LogFlowFuncLeave();
        return;
    }



    if (RT_UNLIKELY(!tftpIsSupportedTransferMode(pTftpSession)))
    {
        tftpSendError(pData, pTftpSession, 4, "Unsupported transfer mode", pTftpIpHeader);
        LogFlowFuncLeave();
        return;
    }


    tftpSendOACK(pData, pTftpSession, pTftpIpHeader);
    LogFlowFuncLeave();
    return;
}
示例#3
0
文件: tftp.c 项目: ryenus/vbox
DECLINLINE(int) tftpSendError(PNATState pData,
                              PTFTPSESSION pTftpSession,
                              uint16_t errorcode,
                              const char *msg,
                              PCTFTPIPHDR pcTftpIpHeaderRecv)
{
    struct mbuf *m = NULL;
    PTFTPIPHDR pTftpIpHeader = NULL;

    LogFlowFunc(("ENTER: errorcode: %RX16, msg: %s\n", errorcode, msg));
    m = slirpTftpMbufAlloc(pData);
    if (!m)
    {
        LogFlowFunc(("LEAVE: Can't allocate mbuf\n"));
        return -1;
    }

    m->m_data += if_maxlinkhdr;
    m->m_len = sizeof(TFTPIPHDR)
             + strlen(msg) + 1; /* ending zero */
    m->m_pkthdr.header = mtod(m, void *);
    pTftpIpHeader = mtod(m, PTFTPIPHDR);

    pTftpIpHeader->u16TftpOpType = RT_H2N_U16_C(TFTP_ERROR);
    pTftpIpHeader->Core.u16TftpOpCode = RT_H2N_U16(errorcode);

    m_copyback(pData, m, sizeof(TFTPIPHDR), strlen(msg) + 1 /* copy ending zerro*/, (c_caddr_t)msg);

    tftpSend(pData, pTftpSession, m, pcTftpIpHeaderRecv);

    tftpSessionTerminate(pTftpSession);

    LogFlowFuncLeave();
    return 0;
}
/**
 * @interface_method_impl{FNPDMDRVREQHANDLERR0}
 */
PDMBOTHCBDECL(int) drvR0HostParallelReqHandler(PPDMDRVINS pDrvIns, uint32_t uOperation, uint64_t u64Arg)
{
    int rc;

    LogFlowFuncEnter();
    /* I have included break after each case. Need to work on this. */
    switch ((DRVHOSTPARALLELR0OP)uOperation)
    {
        case DRVHOSTPARALLELR0OP_READ:
            rc = drvR0HostParallelReqRead(pDrvIns, u64Arg);
            break;
        case DRVHOSTPARALLELR0OP_READSTATUS:
            rc = drvR0HostParallelReqReadStatus(pDrvIns, u64Arg);
            break;
        case DRVHOSTPARALLELR0OP_READCONTROL:
            rc = drvR0HostParallelReqReadControl(pDrvIns, u64Arg);
            break;
        case DRVHOSTPARALLELR0OP_WRITE:
            rc = drvR0HostParallelReqWrite(pDrvIns, u64Arg);
            break;
        case DRVHOSTPARALLELR0OP_WRITECONTROL:
            rc = drvR0HostParallelReqWriteControl(pDrvIns, u64Arg);
            break;
        case DRVHOSTPARALLELR0OP_SETPORTDIRECTION:
            rc = drvR0HostParallelReqSetPortDir(pDrvIns, u64Arg);
            break;
        default:        /* not supported */
            rc = VERR_NOT_SUPPORTED;
    }
    LogFlowFuncLeave();
    return rc;
}
示例#5
0
/**
 * Handle the 'create' action.
 *
 * @returns 0 or 1.
 * @param   argc    The action argument count.
 * @param   argv    The action argument vector.
 */
static int supSvcWinRunIt(int argc, char **argv)
{
    LogFlowFuncEnter();

    /*
     * Initialize release logging.
     */
    /** @todo release logging of the system-wide service. */

    /*
     * Parse the arguments.
     */
    static const RTOPTIONDEF s_aOptions[] =
    {
        { "--dummy", 'd', RTGETOPT_REQ_NOTHING }
    };
    int iArg = 0;
    int ch;
    RTGETOPTUNION Value;
    while ((ch = RTGetOpt(argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), &iArg, &Value)))
        switch (ch)
        {
            default:    return supSvcDisplayGetOptError("runit", ch, argc, argv, iArg, &Value);
        }
    if (iArg != argc)
        return supSvcDisplayTooManyArgsError("runit", argc, argv, iArg);

    /*
     * Register the service with the service control manager
     * and start dispatching requests from it (all done by the API).
     */
    static SERVICE_TABLE_ENTRY const s_aServiceStartTable[] =
    {
        { SUPSVC_SERVICE_NAME, supSvcWinServiceMain },
        { NULL, NULL}
    };
    if (StartServiceCtrlDispatcher(&s_aServiceStartTable[0]))
    {
        LogFlowFuncLeave();
        return 0; /* told to quit, so quit. */
    }

    DWORD err = GetLastError();
    switch (err)
    {
        case ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
            supSvcDisplayError("Cannot run a service from the command line. Use the 'start' action to start it the right way.\n");
            break;
        default:
            supSvcLogError("StartServiceCtrlDispatcher failed, err=%d", err);
            break;
    }
    return 1;
}
示例#6
0
/** VM IPC mutex holder thread */
DECLCALLBACK(int) IPCMutexHolderThread (RTTHREAD Thread, void *pvUser)
{
    LogFlowFuncEnter();

    Assert (pvUser);
    void **data = (void **) pvUser;

    Utf8Str ipcId = (BSTR)data[0];
    RTSEMEVENT finishSem = (RTSEMEVENT)data[1];

    LogFlowFunc (("ipcId='%s', finishSem=%p\n", ipcId.raw(), finishSem));

    HMTX ipcMutex = NULLHANDLE;
    APIRET arc = ::DosOpenMutexSem ((PSZ) ipcId.raw(), &ipcMutex);
    AssertMsg (arc == NO_ERROR, ("cannot open IPC mutex, arc=%ld\n", arc));

    if (arc == NO_ERROR)
    {
        /* grab the mutex */
        LogFlowFunc (("grabbing IPC mutex...\n"));
        arc = ::DosRequestMutexSem (ipcMutex, SEM_IMMEDIATE_RETURN);
        AssertMsg (arc == NO_ERROR, ("cannot grab IPC mutex, arc=%ld\n", arc));
        if (arc == NO_ERROR)
        {
            /* store the answer */
            data[2] = (void*)true;
            /* signal we're done */
            int vrc = RTThreadUserSignal (Thread);
            AssertRC(vrc);

            /* wait until we're signaled to release the IPC mutex */
            LogFlowFunc (("waiting for termination signal..\n"));
            vrc = RTSemEventWait (finishSem, RT_INDEFINITE_WAIT);
            Assert (arc == ERROR_INTERRUPT || ERROR_TIMEOUT);

            /* release the IPC mutex */
            LogFlowFunc (("releasing IPC mutex...\n"));
            arc = ::DosReleaseMutexSem (ipcMutex);
            AssertMsg (arc == NO_ERROR, ("cannot release mutex, arc=%ld\n", arc));
        }

        ::DosCloseMutexSem (ipcMutex);
    }

    /* store the answer */
    data[1] = (void*)false;
    /* signal we're done */
    int vrc = RTThreadUserSignal (Thread);
    AssertRC(vrc);

    LogFlowFuncLeave();

    return 0;
}
/**
 * forcible ask for send packet on the "wire"
 */
void VBoxNetBaseService::flushWire()
{
    INTNETIFSENDREQ SendReq;
    SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
    SendReq.Hdr.cbReq    = sizeof(SendReq);
    SendReq.pSession     = m->m_pSession;
    SendReq.hIf          = m->m_hIf;
    int rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_SEND, 0, &SendReq.Hdr);
    AssertRCReturnVoid(rc);
    LogFlowFuncLeave();
}
示例#8
0
HRESULT VFSExplorer::i_deleteS3(TaskVFSExplorer *aTask)
{
    LogFlowFuncEnter();

    AutoCaller autoCaller(this);
    if (FAILED(autoCaller.rc())) return autoCaller.rc();

    AutoWriteLock appLock(this COMMA_LOCKVAL_SRC_POS);

    HRESULT rc = S_OK;

    RTS3 hS3 = NULL;
    float fPercentStep = 100.0f / aTask->filenames.size();
    try
    {
        int vrc = RTS3Create(&hS3, m->strUsername.c_str(), m->strPassword.c_str(),
                             m->strHostname.c_str(), "virtualbox-agent/" VBOX_VERSION_STRING);
        if (RT_FAILURE(vrc))
            throw setError(E_FAIL, tr ("Can't open S3 storage service (%Rrc)"), vrc);

        RTS3SetProgressCallback(hS3, VFSExplorer::TaskVFSExplorer::uploadProgress, &aTask);

        std::list<Utf8Str>::const_iterator it;
        size_t i = 0;
        for (it = aTask->filenames.begin();
             it != aTask->filenames.end();
             ++it, ++i)
        {
            vrc = RTS3DeleteKey(hS3, m->strBucket.c_str(), (*it).c_str());
            if (RT_FAILURE(vrc))
                throw setError(VBOX_E_FILE_ERROR, tr ("Can't delete file '%s' (%Rrc)"), (*it).c_str(), vrc);
            if (aTask->progress)
                aTask->progress->SetCurrentOperationProgress((ULONG)(fPercentStep * i));
        }
    }
    catch(HRESULT aRC)
    {
        rc = aRC;
    }

    aTask->rc = rc;

    if (hS3 != NULL)
        RTS3Destroy(hS3);

    if (!aTask->progress.isNull())
        aTask->progress->i_notifyComplete(rc);

    LogFlowFunc(("rc=%Rhrc\n", rc));
    LogFlowFuncLeave();

    return VINF_SUCCESS;
}
/**
 * Issued by the guest when a guest user changed its state.
 *
 * @return  IPRT status code.
 * @param   aUser               Guest user name.
 * @param   aDomain             Domain of guest user account. Optional.
 * @param   enmState            New state to indicate.
 * @param   pbDetails           Pointer to state details. Optional.
 * @param   cbDetails           Size (in bytes) of state details. Pass 0 if not used.
 */
void Guest::i_onUserStateChange(Bstr aUser, Bstr aDomain, VBoxGuestUserState enmState,
                                const uint8_t *pbDetails, uint32_t cbDetails)
{
    LogFlowThisFunc(("\n"));

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

    Bstr strDetails; /** @todo Implement state details here. */

    fireGuestUserStateChangedEvent(mEventSource, aUser.raw(), aDomain.raw(),
                                   (GuestUserState_T)enmState, strDetails.raw());
    LogFlowFuncLeave();
}
    /**
     * Implementation code for the "create base" task.
     * Used as function for execution from a standalone thread.
     */
    void handler()
    {
        LogFlowFuncEnter();
        try
        {
            mRC = executeTask(); /* (destructor picks up mRC, see above) */
            LogFlowFunc(("rc=%Rhrc\n", mRC));
        }
        catch (...)
        {
            LogRel(("Some exception in the function MediumIO::StreamTask:handler()\n"));
        }

        LogFlowFuncLeave();
    }
/*
 * remque and free a socket, clobber cache
 */
void
sofree(PNATState pData, struct socket *so)
{
    LogFlowFunc(("ENTER:%R[natsock]\n", so));
    /*
     * We should not remove socket when polling routine do the polling
     * instead we mark it for deletion.
     */
    if (so->fUnderPolling)
    {
        so->fShouldBeRemoved = 1;
        LogFlowFunc(("LEAVE:%R[natsock] postponed deletion\n", so));
        return;
    }
    /**
     * Check that we don't freeng socket with tcbcb
     */
    Assert(!sototcpcb(so));
    /* udp checks */
    Assert(!so->so_timeout);
    Assert(!so->so_timeout_arg);
    if (so == tcp_last_so)
        tcp_last_so = &tcb;
    else if (so == udp_last_so)
        udp_last_so = &udb;

    /* check if mbuf haven't been already freed  */
    if (so->so_m != NULL)
    {
        m_freem(pData, so->so_m);
        so->so_m = NULL;
    }

    if (so->so_ohdr != NULL)
    {
        RTMemFree(so->so_ohdr);
        so->so_ohdr = NULL;
    }

    if (so->so_next && so->so_prev)
    {
        remque(pData, so);  /* crashes if so is not in a queue */
        NSOCK_DEC();
    }

    RTMemFree(so);
    LogFlowFuncLeave();
}
示例#12
0
/* static */
DECLCALLBACK(int) VFSExplorer::TaskVFSExplorer::taskThread(RTTHREAD /* aThread */, void *pvUser)
{
    std::auto_ptr<TaskVFSExplorer> task(static_cast<TaskVFSExplorer*>(pvUser));
    AssertReturn(task.get(), VERR_GENERAL_FAILURE);

    VFSExplorer *pVFSExplorer = task->pVFSExplorer;

    LogFlowFuncEnter();
    LogFlowFunc(("VFSExplorer %p\n", pVFSExplorer));

    HRESULT rc = S_OK;

    switch(task->taskType)
    {
        case TaskVFSExplorer::Update:
        {
            if (pVFSExplorer->m->storageType == VFSType_File)
                rc = pVFSExplorer->i_updateFS(task.get());
            else if (pVFSExplorer->m->storageType == VFSType_S3)
#ifdef VBOX_WITH_S3
                rc = pVFSExplorer->i_updateS3(task.get());
#else
                rc = VERR_NOT_IMPLEMENTED;
#endif
            break;
        }
        case TaskVFSExplorer::Delete:
        {
            if (pVFSExplorer->m->storageType == VFSType_File)
                rc = pVFSExplorer->i_deleteFS(task.get());
            else if (pVFSExplorer->m->storageType == VFSType_S3)
#ifdef VBOX_WITH_S3
                rc = pVFSExplorer->i_deleteS3(task.get());
#else
                rc = VERR_NOT_IMPLEMENTED;
#endif
            break;
        }
        default:
            AssertMsgFailed(("Invalid task type %u specified!\n", task->taskType));
            break;
    }

    LogFlowFunc(("rc=%Rhrc\n", rc)); NOREF(rc);
    LogFlowFuncLeave();

    return VINF_SUCCESS;
}
示例#13
0
/**
 * Uninitializes the instance and sets the ready flag to FALSE.
 * Called either from FinalRelease() or by the parent when it gets destroyed.
 */
void Guest::uninit()
{
    LogFlowThisFunc(("\n"));

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

    /* Destroy stat update timer */
    int vrc = RTTimerLRDestroy(mStatTimer);
    AssertMsgRC(vrc, ("Failed to create guest statistics update timer(%Rra)\n", vrc));
    mStatTimer = NULL;
    mMagic     = 0;

#ifdef VBOX_WITH_GUEST_CONTROL
    LogFlowThisFunc(("Closing sessions (%RU64 total)\n",
                     mData.mGuestSessions.size()));
    GuestSessions::iterator itSessions = mData.mGuestSessions.begin();
    while (itSessions != mData.mGuestSessions.end())
    {
#ifdef DEBUG
        ULONG cRefs = itSessions->second->AddRef();
        LogFlowThisFunc(("pSession=%p, cRefs=%RU32\n", (GuestSession *)itSessions->second, cRefs > 0 ? cRefs - 1 : 0));
        itSessions->second->Release();
#endif
        itSessions->second->uninit();
        itSessions++;
    }
    mData.mGuestSessions.clear();
#endif

#ifdef VBOX_WITH_DRAG_AND_DROP
    if (m_pGuestDnD)
    {
        delete m_pGuestDnD;
        m_pGuestDnD = NULL;
    }
#endif

#ifdef VBOX_WITH_GUEST_CONTROL
    unconst(mEventSource).setNull();
#endif
    unconst(mParent) = NULL;

    LogFlowFuncLeave();
}
示例#14
0
VBoxNetLwipNAT::VBoxNetLwipNAT(SOCKET icmpsock4, SOCKET icmpsock6) : VBoxNetBaseService("VBoxNetNAT", "nat-network")
{
    LogFlowFuncEnter();

    m_ProxyOptions.ipv6_enabled = 0;
    m_ProxyOptions.ipv6_defroute = 0;
    m_ProxyOptions.icmpsock4 = icmpsock4;
    m_ProxyOptions.icmpsock6 = icmpsock6;
    m_ProxyOptions.tftp_root = NULL;
    m_ProxyOptions.src4 = NULL;
    m_ProxyOptions.src6 = NULL;
    RT_ZERO(m_src4);
    RT_ZERO(m_src6);
    m_src4.sin_family = AF_INET;
    m_src6.sin6_family = AF_INET6;
#if HAVE_SA_LEN
    m_src4.sin_len = sizeof(m_src4);
    m_src6.sin6_len = sizeof(m_src6);
#endif
    m_ProxyOptions.nameservers = NULL;

    m_LwipNetIf.name[0] = 'N';
    m_LwipNetIf.name[1] = 'T';

    RTMAC mac;
    mac.au8[0] = 0x52;
    mac.au8[1] = 0x54;
    mac.au8[2] = 0;
    mac.au8[3] = 0x12;
    mac.au8[4] = 0x35;
    mac.au8[5] = 0;
    setMacAddress(mac);

    RTNETADDRIPV4 address;
    address.u     = RT_MAKE_U32_FROM_U8( 10,  0,  2,  2); // NB: big-endian
    setIpv4Address(address);

    address.u     = RT_H2N_U32_C(0xffffff00);
    setIpv4Netmask(address);

    fDontLoadRulesOnStartup = false;

    for(unsigned int i = 0; i < RT_ELEMENTS(g_aGetOptDef); ++i)
        addCommandLineOption(&g_aGetOptDef[i]);

    LogFlowFuncLeave();
}
示例#15
0
/** VM IPC mutex holder thread */
DECLCALLBACK(int) IPCMutexHolderThread (RTTHREAD Thread, void *pvUser)
{
    LogFlowFuncEnter();

    Assert (pvUser);
    void **data = (void **) pvUser;

    BSTR sessionId = (BSTR)data[0];
    HANDLE initDoneSem = (HANDLE)data[1];

    HANDLE ipcMutex = ::OpenMutex (MUTEX_ALL_ACCESS, FALSE, sessionId);
    AssertMsg (ipcMutex, ("cannot open IPC mutex, err=%d\n", ::GetLastError()));

    if (ipcMutex)
    {
        /* grab the mutex */
        DWORD wrc = ::WaitForSingleObject (ipcMutex, 0);
        AssertMsg (wrc == WAIT_OBJECT_0, ("cannot grab IPC mutex, err=%d\n", wrc));
        if (wrc == WAIT_OBJECT_0)
        {
            HANDLE finishSem = ::CreateEvent (NULL, FALSE, FALSE, NULL);
            AssertMsg (finishSem, ("cannot create event sem, err=%d\n", ::GetLastError()));
            if (finishSem)
            {
                data[2] = (void*)finishSem;
                /* signal we're done with init */
                ::SetEvent (initDoneSem);
                /* wait until we're signaled to release the IPC mutex */
                ::WaitForSingleObject (finishSem, INFINITE);
                /* release the IPC mutex */
                LogFlow (("IPCMutexHolderThread(): releasing IPC mutex...\n"));
                BOOL success = ::ReleaseMutex (ipcMutex);
                AssertMsg (success, ("cannot release mutex, err=%d\n", ::GetLastError()));
                ::CloseHandle (ipcMutex);
                ::CloseHandle (finishSem);
            }
        }
    }

    /* signal we're done */
    ::SetEvent (initDoneSem);

    LogFlowFuncLeave();

    return 0;
}
示例#16
0
HRESULT VFSExplorer::i_deleteFS(TaskVFSExplorer *aTask)
{
    LogFlowFuncEnter();

    AutoCaller autoCaller(this);
    if (FAILED(autoCaller.rc())) return autoCaller.rc();

    AutoWriteLock appLock(this COMMA_LOCKVAL_SRC_POS);

    HRESULT rc = S_OK;

    float fPercentStep = 100.0f / aTask->filenames.size();
    try
    {
        char szPath[RTPATH_MAX];
        std::list<Utf8Str>::const_iterator it;
        size_t i = 0;
        for (it = aTask->filenames.begin();
             it != aTask->filenames.end();
             ++it, ++i)
        {
            int vrc = RTPathJoin(szPath, sizeof(szPath), m->strPath.c_str(), (*it).c_str());
            if (RT_FAILURE(vrc))
                throw setError(E_FAIL, tr("Internal Error (%Rrc)"), vrc);
            vrc = RTFileDelete(szPath);
            if (RT_FAILURE(vrc))
                throw setError(VBOX_E_FILE_ERROR, tr("Can't delete file '%s' (%Rrc)"), szPath, vrc);
            if (aTask->progress)
                aTask->progress->SetCurrentOperationProgress((ULONG)(fPercentStep * i));
        }
    }
    catch(HRESULT aRC)
    {
        rc = aRC;
    }

    aTask->rc = rc;

    if (!aTask->progress.isNull())
        aTask->progress->i_notifyComplete(rc);

    LogFlowFunc(("rc=%Rhrc\n", rc));
    LogFlowFuncLeave();

    return VINF_SUCCESS;
}
示例#17
0
static UINT32 VBoxWriteNVRAMDoOp(UINT32 u32Operation)
{
    UINT32 u32Rc;
    LogFlowFuncEnter();
    LogFlowFuncMarkVar(u32Operation, "%x");
    VBoxWriteNVRAMU32Param(EFI_VM_VARIABLE_OP_START, u32Operation);

    while ((u32Rc = ASMInU32(EFI_VARIABLE_OP)) == EFI_VARIABLE_OP_STATUS_BSY)
    {
#if 0
        MicroSecondDelay (400);
#endif
        /* @todo: sleep here. bird: won't ever happen, so don't bother. */
    }
    LogFlowFuncMarkVar(u32Rc, "%x");
    LogFlowFuncLeave();
    return u32Rc;
}
示例#18
0
/**
 * Stops and destroys the services.
 */
void supSvcStopAndDestroyServices(void)
{
    LogFlowFuncEnter();

    /*
     * Stop and destroy the service in reverse of start order.
     */
    unsigned i = RT_ELEMENTS(g_aServices);
    while (i-- > 0)
        if (g_aServices[i].enmState != kSupSvcServiceState_NotCreated)
        {
            g_aServices[i].pfnStopAndDestroy(g_aServices[i].pvInstance,
                                             g_aServices[i].enmState == kSupSvcServiceState_Running);
            g_aServices[i].pvInstance = NULL;
            g_aServices[i].enmState = kSupSvcServiceState_NotCreated;
        }

    LogFlowFuncLeave();
}
示例#19
0
/**
 * Sort a list of USB devices.
 *
 * @returns Pointer to the head of the sorted doubly linked list.
 * @param   aDevices        Head pointer (can be both singly and doubly linked list).
 */
static PUSBDEVICE sortDevices(PUSBDEVICE pDevices)
{
    PUSBDEVICE pHead = NULL;
    PUSBDEVICE pTail = NULL;
    while (pDevices)
    {
        /* unlink head */
        PUSBDEVICE pDev = pDevices;
        pDevices = pDev->pNext;
        if (pDevices)
            pDevices->pPrev = NULL;

        /* find location. */
        PUSBDEVICE pCur = pTail;
        while (     pCur
               &&   HostUSBDevice::compare(pCur, pDev) > 0)
            pCur = pCur->pPrev;

        /* insert (after pCur) */
        pDev->pPrev = pCur;
        if (pCur)
        {
            pDev->pNext = pCur->pNext;
            pCur->pNext = pDev;
            if (pDev->pNext)
                pDev->pNext->pPrev = pDev;
            else
                pTail = pDev;
        }
        else
        {
            pDev->pNext = pHead;
            if (pHead)
                pHead->pPrev = pDev;
            else
                pTail = pDev;
            pHead = pDev;
        }
    }

    LogFlowFuncLeave();
    return pHead;
}
示例#20
0
文件: tftp.c 项目: ryenus/vbox
DECLINLINE(int) tftpSendOACK(PNATState pData,
                          PTFTPSESSION pTftpSession,
                          PCTFTPIPHDR pcTftpIpHeaderRecv)
{
    struct mbuf *m;
    PTFTPIPHDR pTftpIpHeader;
    int rc = VINF_SUCCESS;

    rc = tftpSessionEvaluateOptions(pData, pTftpSession);
    if (RT_FAILURE(rc))
    {
        tftpSendError(pData, pTftpSession, 2, "Internal Error (blksize evaluation)", pcTftpIpHeaderRecv);
        LogFlowFuncLeave();
        return -1;
    }

    m = slirpTftpMbufAlloc(pData);
    if (!m)
        return -1;



    m->m_data += if_maxlinkhdr;
    m->m_pkthdr.header = mtod(m, void *);
    pTftpIpHeader = mtod(m, PTFTPIPHDR);
    m->m_len = sizeof(TFTPIPHDR) - sizeof(uint16_t); /* no u16TftpOpCode */

    pTftpIpHeader->u16TftpOpType = RT_H2N_U16_C(TFTP_OACK);

    if (pTftpSession->OptionBlkSize.fRequested)
    {
        if (pTftpSession->OptionBlkSize.u64Value > UINT16_MAX)
            rc = VERR_INVALID_PARAMETER;
        else
            rc = tftpAddOptionToOACK(pData, m, "blksize", pTftpSession->OptionBlkSize.u64Value);
    }
    if (   RT_SUCCESS(rc)
        && pTftpSession->OptionTSize.fRequested)
        rc = tftpAddOptionToOACK(pData, m, "tsize", pTftpSession->OptionTSize.u64Value);

    rc = tftpSend(pData, pTftpSession, m, pcTftpIpHeaderRecv);
    return RT_SUCCESS(rc) ? 0 : -1;
}
/* static */
DECLCALLBACK(int) GuestTask::taskThread(RTTHREAD /* aThread */, void *pvUser)
{
    std::auto_ptr<GuestTask> task(static_cast<GuestTask*>(pvUser));
    AssertReturn(task.get(), VERR_GENERAL_FAILURE);

    ComObjPtr<Guest> pGuest = task->pGuest;

    LogFlowFuncEnter();

    HRESULT rc = S_OK;

    switch (task->taskType)
    {
#ifdef VBOX_WITH_GUEST_CONTROL
        case TaskType_CopyFileToGuest:
        {
            rc = pGuest->taskCopyFileToGuest(task.get());
            break;
        }
        case TaskType_CopyFileFromGuest:
        {
            rc = pGuest->taskCopyFileFromGuest(task.get());
            break;
        }
        case TaskType_UpdateGuestAdditions:
        {
            rc = pGuest->taskUpdateGuestAdditions(task.get());
            break;
        }
#endif
        default:
            AssertMsgFailed(("Invalid task type %u specified!\n", task->taskType));
            break;
    }

    LogFlowFunc(("rc=%Rhrc\n", rc));
    LogFlowFuncLeave();

    return VINF_SUCCESS;
}
示例#22
0
文件: main.cpp 项目: miguelinux/vbox
extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char ** /*envp*/)
{
#ifdef RT_OS_WINDOWS
    ATL::CComModule _Module; /* Required internally by ATL (constructor records instance in global variable). */
#endif

    /* Failed result initially: */
    int iResultCode = 1;

    /* Start logging: */
    LogFlowFuncEnter();

    /* Simulate try-catch block: */
    do
    {
#ifdef VBOX_WS_MAC
        /* Hide setuid root from AppKit: */
        HideSetUidRootFromAppKit();
#endif /* VBOX_WS_MAC */

#ifdef VBOX_WS_X11
        /* Make sure multi-threaded environment is safe: */
        if (!MakeSureMultiThreadingIsSafe())
            break;
#endif /* VBOX_WS_X11 */

        /* Console help preprocessing: */
        bool fHelpShown = false;
        for (int i = 0; i < argc; ++i)
        {
            if (   !strcmp(argv[i], "-h")
                || !strcmp(argv[i], "-?")
                || !strcmp(argv[i], "-help")
                || !strcmp(argv[i], "--help"))
            {
                fHelpShown = true;
                ShowHelp();
                break;
            }
        }
        if (fHelpShown)
        {
            iResultCode = 0;
            break;
        }

#ifdef VBOX_WITH_HARDENING
        /* Make sure the image verification code works: */
        SUPR3HardenedVerifyInit();
#endif /* VBOX_WITH_HARDENING */

#ifdef VBOX_WS_MAC
        /* Apply font fixes (before QApplication get created and instantiated font-hints): */
        switch (VBoxGlobal::determineOsRelease())
        {
            case MacOSXRelease_Mavericks: QFont::insertSubstitution(".Lucida Grande UI", "Lucida Grande"); break;
            case MacOSXRelease_Yosemite:  QFont::insertSubstitution(".Helvetica Neue DeskInterface", "Helvetica Neue"); break;
            case MacOSXRelease_ElCapitan: QFont::insertSubstitution(".SF NS Text", "Helvetica Neue"); break;
            default: break;
        }

        /* Instantiate own NSApplication before QApplication do it for us: */
        UICocoaApplication::instance();
#endif /* VBOX_WS_MAC */

#ifdef VBOX_WS_X11
# if defined(RT_OS_LINUX) && defined(DEBUG)
        /* Install signal handler to backtrace the call stack: */
        InstallSignalHandler();
# endif /* RT_OS_LINUX && DEBUG */
#endif /* VBOX_WS_X11 */

#if QT_VERSION >= 0x050000
        /* Install Qt console message handler: */
        qInstallMessageHandler(QtMessageOutput);
#else /* QT_VERSION < 0x050000 */
        /* Install Qt console message handler: */
        qInstallMsgHandler(QtMessageOutput);
#endif /* QT_VERSION < 0x050000 */

        /* Create application: */
        QApplication a(argc, argv);

#ifdef VBOX_WS_WIN
        /* Drag in the sound drivers and DLLs early to get rid of the delay taking
         * place when the main menu bar (or any action from that menu bar) is
         * activated for the first time. This delay is especially annoying if it
         * happens when the VM is executing in real mode (which gives 100% CPU
         * load and slows down the load process that happens on the main GUI
         * thread to several seconds). */
        PlaySound(NULL, NULL, 0);
#endif /* VBOX_WS_WIN */

#ifdef VBOX_WS_MAC
# ifdef VBOX_GUI_WITH_HIDPI
        /* Enable HiDPI icons.
         * For this we require a patched version of Qt 4.x with
         * the changes from https://codereview.qt-project.org/#change,54636 applied. */
        a.setAttribute(Qt::AA_UseHighDpiPixmaps);
# endif /* VBOX_GUI_WITH_HIDPI */

        /* Disable menu icons on MacOS X host: */
        ::darwinDisableIconsInMenus();
#endif /* VBOX_WS_MAC */

#ifdef VBOX_WS_X11
        /* Make all widget native.
         * We did it to avoid various Qt crashes while testing widget attributes or acquiring winIds.
         * Yes, we aware of note that alien widgets faster to draw but the only widget we need to be fast
         * is viewport of VM which was always native since we are using his id for 3D service needs. */
        a.setAttribute(Qt::AA_NativeWindows);

# ifdef Q_OS_SOLARIS
#  if QT_VERSION < 0x050000
        /* Use plastique look&feel for Solaris instead of the default motif (Qt 4.7.x): */
        QApplication::setStyle(new QPlastiqueStyle);
#  else /* QT_VERSION >= 0x050000 */
	a.setStyle("fusion");
#  endif /* QT_VERSION >= 0x050000 */
# endif /* Q_OS_SOLARIS */

# ifndef Q_OS_SOLARIS
        /* Apply font fixes (after QApplication get created and instantiated font-family): */
        QFontDatabase fontDataBase;
        QString currentFamily(QApplication::font().family());
        bool isCurrentScaleable = fontDataBase.isScalable(currentFamily);
        QString subFamily(QFont::substitute(currentFamily));
        bool isSubScaleable = fontDataBase.isScalable(subFamily);
        if (isCurrentScaleable && !isSubScaleable)
#  if QT_VERSION >= 0x050000
            QFont::removeSubstitutions(currentFamily);
#  else /* QT_VERSION < 0x050000 */
            QFont::removeSubstitution(currentFamily);
#  endif /* QT_VERSION < 0x050000 */
# endif /* !Q_OS_SOLARIS */

        /* Qt version check (major.minor are sensitive, fix number is ignored): */
        if (VBoxGlobal::qtRTVersion() < (VBoxGlobal::qtCTVersion() & 0xFFFF00))
        {
            QString strMsg = QApplication::tr("Executable <b>%1</b> requires Qt %2.x, found Qt %3.")
                                              .arg(qAppName())
                                              .arg(VBoxGlobal::qtCTVersionString().section('.', 0, 1))
                                              .arg(VBoxGlobal::qtRTVersionString());
            QMessageBox::critical(0, QApplication::tr("Incompatible Qt Library Error"),
                                  strMsg, QMessageBox::Abort, 0);
            qFatal("%s", strMsg.toUtf8().constData());
            break;
        }
#endif /* VBOX_WS_X11 */

        /* Create modal-window manager: */
        UIModalWindowManager::create();

        /* Create global UI instance: */
        VBoxGlobal::create();

        /* Simulate try-catch block: */
        do
        {
            /* Exit if VBoxGlobal is not valid: */
            if (!vboxGlobal().isValid())
                break;

            /* Exit if VBoxGlobal pre-processed arguments: */
            if (vboxGlobal().processArgs())
                break;

            /* For Runtime UI: */
            if (vboxGlobal().isVMConsoleProcess())
            {
                /* Prevent application from exiting when all window(s) closed: */
                qApp->setQuitOnLastWindowClosed(false);
            }

            /* Request to Show UI _after_ QApplication started: */
            QMetaObject::invokeMethod(&vboxGlobal(), "showUI", Qt::QueuedConnection);

            /* Start application: */
            iResultCode = a.exec();
        }
        while (0);

        /* Destroy global UI instance: */
        VBoxGlobal::destroy();

        /* Destroy modal-window manager: */
        UIModalWindowManager::destroy();
    }
    while (0);

    /* Finish logging: */
    LogFlowFunc(("rc=%d\n", iResultCode));
    LogFlowFuncLeave();

    /* Return result: */
    return iResultCode;
}
示例#23
0
extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char ** /*envp*/)
{
    /* Start logging: */
    LogFlowFuncEnter();

    /* Failed result initially: */
    int iResultCode = 1;

#ifdef Q_WS_X11
    if (!VBoxXInitThreads())
        return 1;
#endif

    /* Simulate try-catch block: */
    do
    {
#ifdef RT_OS_DARWIN
        ShutUpAppKit();
#endif /* RT_OS_DARWIN */

        /* Console help preprocessing: */
        bool fHelpShown = false;
        for (int i = 0; i < argc; ++i)
        {
            if (   !strcmp(argv[i], "-h")
                || !strcmp(argv[i], "-?")
                || !strcmp(argv[i], "-help")
                || !strcmp(argv[i], "--help"))
            {
                showHelp();
                fHelpShown = true;
                break;
            }
        }
        if (fHelpShown)
        {
            iResultCode = 0;
            break;
        }

#if defined(DEBUG) && defined(Q_WS_X11) && defined(RT_OS_LINUX)
        /* Install our signal handler to backtrace the call stack: */
        struct sigaction sa;
        sa.sa_sigaction = bt_sighandler;
        sigemptyset(&sa.sa_mask);
        sa.sa_flags = SA_RESTART | SA_SIGINFO;
        sigaction(SIGSEGV, &sa, NULL);
        sigaction(SIGBUS, &sa, NULL);
        sigaction(SIGUSR1, &sa, NULL);
#endif

#ifdef Q_WS_MAC
        /* Mavericks font fix: */
        if (VBoxGlobal::osRelease() == MacOSXRelease_Mavericks)
            QFont::insertSubstitution(".Lucida Grande UI", "Lucida Grande");
# ifdef QT_MAC_USE_COCOA
        /* Instantiate our NSApplication derivative before QApplication
         * forces NSApplication to be instantiated. */
        UICocoaApplication::instance();
# endif /* QT_MAC_USE_COCOA */
#endif /* Q_WS_MAC */

        /* Install Qt console message handler: */
        qInstallMsgHandler(QtMessageOutput);

#ifdef Q_WS_X11
        /* Qt has a complex algorithm for selecting the right visual which
         * doesn't always seem to work. So we naively choose a visual - the
         * default one - ourselves and pass that to Qt. This means that we
         * also have to open the display ourselves.
         * We check the Qt parameter list and handle Qt's -display argument
         * ourselves, since we open the display connection. We also check the
         * to see if the user has passed Qt's -visual parameter, and if so we
         * assume that the user wants Qt to handle visual selection after all,
         * and don't supply a visual. */
        char *pszDisplay = NULL;
        bool useDefaultVisual = true;
        for (int i = 0; i < argc; ++i)
        {
            if (!::strcmp(argv[i], "-display") && (i + 1 < argc))
            /* What if it isn't? Rely on QApplication to complain? */
            {
                pszDisplay = argv[i + 1];
                ++i;
            }
            else if (!::strcmp(argv[i], "-visual"))
                useDefaultVisual = false;
        }
        Display *pDisplay = XOpenDisplay(pszDisplay);
        if (!pDisplay)
        {
            RTPrintf(pszDisplay ? "Failed to open the X11 display \"%s\"!\n"
                                : "Failed to open the X11 display!\n",
                     pszDisplay);
            break;
        }
        Visual *pVisual =   useDefaultVisual
                          ? DefaultVisual(pDisplay, DefaultScreen(pDisplay))
                          : NULL;
        /* Now create the application object: */
        QApplication a(pDisplay, argc, argv, (Qt::HANDLE)pVisual);
#else /* Q_WS_X11 */
        QApplication a(argc, argv);
#endif /* Q_WS_X11 */

#ifdef Q_OS_SOLARIS
        /* Use plastique look&feel for Solaris instead of the default motif (Qt 4.7.x): */
        QApplication::setStyle(new QPlastiqueStyle);
#endif /* Q_OS_SOLARIS */

#ifdef Q_WS_X11
        /* This patch is not used for now on Solaris & OpenSolaris because
         * there is no anti-aliasing enabled by default, Qt4 to be rebuilt. */
# ifndef Q_OS_SOLARIS
        /* Cause Qt4 has the conflict with fontconfig application as a result
         * sometimes substituting some fonts with non scaleable-anti-aliased
         * bitmap font we are reseting substitutes for the current application
         * font family if it is non scaleable-anti-aliased. */
        QFontDatabase fontDataBase;

        QString currentFamily(QApplication::font().family());
        bool isCurrentScaleable = fontDataBase.isScalable(currentFamily);

        QString subFamily(QFont::substitute(currentFamily));
        bool isSubScaleable = fontDataBase.isScalable(subFamily);

        if (isCurrentScaleable && !isSubScaleable)
            QFont::removeSubstitution(currentFamily);
# endif /* Q_OS_SOLARIS */
#endif /* Q_WS_X11 */

#ifdef Q_WS_WIN
        /* Drag in the sound drivers and DLLs early to get rid of the delay taking
         * place when the main menu bar (or any action from that menu bar) is
         * activated for the first time. This delay is especially annoying if it
         * happens when the VM is executing in real mode (which gives 100% CPU
         * load and slows down the load process that happens on the main GUI
         * thread to several seconds). */
        PlaySound(NULL, NULL, 0);
#endif /* Q_WS_WIN */

#ifdef Q_WS_MAC
        /* Disable menu icons on MacOS X host: */
        ::darwinDisableIconsInMenus();
#endif /* Q_WS_MAC */

#ifdef Q_WS_X11
        /* Qt version check (major.minor are sensitive, fix number is ignored): */
        if (VBoxGlobal::qtRTVersion() < (VBoxGlobal::qtCTVersion() & 0xFFFF00))
        {
            QString strMsg = QApplication::tr("Executable <b>%1</b> requires Qt %2.x, found Qt %3.")
                                              .arg(qAppName())
                                              .arg(VBoxGlobal::qtCTVersionString().section('.', 0, 1))
                                              .arg(VBoxGlobal::qtRTVersionString());
            QMessageBox::critical(0, QApplication::tr("Incompatible Qt Library Error"),
                                  strMsg, QMessageBox::Abort, 0);
            qFatal("%s", strMsg.toAscii().constData());
            break;
        }
#endif /* Q_WS_X11 */

        /* Create modal-window manager: */
        UIModalWindowManager::create();

        /* Create global UI instance: */
        VBoxGlobal::create();

        /* Simulate try-catch block: */
        do
        {
            /* Exit if VBoxGlobal is not valid: */
            if (!vboxGlobal().isValid())
                break;

            /* Exit if VBoxGlobal was able to pre-process arguments: */
            if (vboxGlobal().processArgs())
                break;

#ifdef RT_OS_LINUX
            /* Make sure no wrong USB mounted: */
            VBoxGlobal::checkForWrongUSBMounted();
#endif /* RT_OS_LINUX */

            /* Load application settings: */
            VBoxGlobalSettings settings = vboxGlobal().settings();

            /* VM console process: */
            if (vboxGlobal().isVMConsoleProcess())
            {
                /* Make sure VM is started: */
                if (!vboxGlobal().startMachine(vboxGlobal().managedVMUuid()))
                    break;

                /* Start application: */
                iResultCode = a.exec();
            }
            /* VM selector process: */
            else
            {
                /* Make sure VM selector is permitted: */
                if (settings.isFeatureActive("noSelector"))
                {
                    msgCenter().cannotStartSelector();
                    break;
                }

#ifdef VBOX_BLEEDING_EDGE
                msgCenter().showBEBWarning();
#else /* VBOX_BLEEDING_EDGE */
# ifndef DEBUG
                /* Check for BETA version: */
                QString vboxVersion(vboxGlobal().virtualBox().GetVersion());
                if (vboxVersion.contains("BETA"))
                {
                    /* Allow to prevent this message: */
                    QString str = vboxGlobal().virtualBox().GetExtraData(GUI_PreventBetaWarning);
                    if (str != vboxVersion)
                        msgCenter().showBETAWarning();
                }
# endif /* !DEBUG */
#endif /* !VBOX_BLEEDING_EDGE*/

                /* Create/show selector window: */
                vboxGlobal().selectorWnd().show();

                /* Start application: */
                iResultCode = a.exec();
            }
        }
        while (0);

        /* Destroy global UI instance: */
        VBoxGlobal::destroy();

        /* Destroy modal-window manager: */
        UIModalWindowManager::destroy();
    }
    while (0);

    /* Finish logging: */
    LogFlowFunc(("rc=%d\n", iResultCode));
    LogFlowFuncLeave();

    /* Return result: */
    return iResultCode;
}
示例#24
0
/* m->m_data  points at ip packet header
 * m->m_len   length ip packet
 * ip->ip_len length data (IPDU)
 */
void
udp_input(PNATState pData, register struct mbuf *m, int iphlen)
{
    register struct ip *ip;
    register struct udphdr *uh;
    int len;
    struct ip save_ip;
    struct socket *so;
    int ret;
    int ttl, tos;

    LogFlowFunc(("ENTER: m = %p, iphlen = %d\n", m, iphlen));
    ip = mtod(m, struct ip *);
    Log2(("%RTnaipv4 iphlen = %d\n", ip->ip_dst, iphlen));

    udpstat.udps_ipackets++;

    /*
     * Strip IP options, if any; should skip this,
     * make available to user, and use on returned packets,
     * but we don't yet have a way to check the checksum
     * with options still present.
     */
    if (iphlen > sizeof(struct ip))
    {
        ip_stripoptions(m, (struct mbuf *)0);
        iphlen = sizeof(struct ip);
    }

    /*
     * Get IP and UDP header together in first mbuf.
     */
    ip = mtod(m, struct ip *);
    uh = (struct udphdr *)((caddr_t)ip + iphlen);

    /*
     * Make mbuf data length reflect UDP length.
     * If not enough data to reflect UDP length, drop.
     */
    len = RT_N2H_U16((u_int16_t)uh->uh_ulen);
    Assert(ip->ip_len + iphlen == (ssize_t)m_length(m, NULL));

    if (ip->ip_len != len)
    {
        if (len > ip->ip_len)
        {
            udpstat.udps_badlen++;
            Log3(("NAT: IP(id: %hd) has bad size\n", ip->ip_id));
            goto bad_free_mbuf;
        }
        m_adj(m, len - ip->ip_len);
        ip->ip_len = len;
    }

    /*
     * Save a copy of the IP header in case we want restore it
     * for sending an ICMP error message in response.
     */
    save_ip = *ip;
    save_ip.ip_len+= iphlen;         /* tcp_input subtracts this */

    /*
     * Checksum extended UDP header and data.
     */
    if (udpcksum && uh->uh_sum)
    {
        memset(((struct ipovly *)ip)->ih_x1, 0, 9);
        ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
#if 0
        /* keep uh_sum for ICMP reply */
        uh->uh_sum = cksum(m, len + sizeof (struct ip));
        if (uh->uh_sum)
        {

#endif
            if (cksum(m, len + iphlen))
            {
                udpstat.udps_badsum++;
                Log3(("NAT: IP(id: %hd) has bad (udp) cksum\n", ip->ip_id));
                goto bad_free_mbuf;
            }
        }
#if 0
    }
#endif

    /*
     *  handle DHCP/BOOTP
     */
    if (uh->uh_dport == RT_H2N_U16_C(BOOTP_SERVER))
    {
        bootp_input(pData, m);
        goto done_free_mbuf;
    }

    LogFunc(("uh src: %RTnaipv4:%d, dst: %RTnaipv4:%d\n",
             ip->ip_src.s_addr, RT_N2H_U16(uh->uh_sport),
             ip->ip_dst.s_addr, RT_N2H_U16(uh->uh_dport)));

    /*
     * handle DNS host resolver without creating a socket
     */
    if (   pData->fUseHostResolver
        && uh->uh_dport == RT_H2N_U16_C(53)
        && CTL_CHECK(ip->ip_dst.s_addr, CTL_DNS))
    {
        struct sockaddr_in dst, src;

        src.sin_addr.s_addr = ip->ip_dst.s_addr;
        src.sin_port = uh->uh_dport;
        dst.sin_addr.s_addr = ip->ip_src.s_addr;
        dst.sin_port = uh->uh_sport;

        m_adj(m, sizeof(struct udpiphdr));

        m = hostresolver(pData, m, ip->ip_src.s_addr, uh->uh_sport);
        if (m == NULL)
            goto done_free_mbuf;

        slirpMbufTagService(pData, m, CTL_DNS);

        udp_output2(pData, NULL, m, &src, &dst, IPTOS_LOWDELAY);
        LogFlowFuncLeave();
        return;
    }

    /*
     *  handle TFTP
     */
    if (   uh->uh_dport == RT_H2N_U16_C(TFTP_SERVER)
        && CTL_CHECK(ip->ip_dst.s_addr, CTL_TFTP))
    {
        if (pData->pvTftpSessions)
            slirpTftpInput(pData, m);
        goto done_free_mbuf;
    }

    /*
     * XXX: DNS proxy currently relies on the fact that each socket
     * only serves one request.
     */
    if (   pData->fUseDnsProxy
        && CTL_CHECK(ip->ip_dst.s_addr, CTL_DNS)
        && (uh->uh_dport == RT_H2N_U16_C(53)))
    {
        so = NULL;
        goto new_socket;
    }

    /*
     * Locate pcb for datagram.
     */
    so = udp_last_so;
    if (   so->so_lport != uh->uh_sport
        || so->so_laddr.s_addr != ip->ip_src.s_addr)
    {
        struct socket *tmp;

        for (tmp = udb.so_next; tmp != &udb; tmp = tmp->so_next)
        {
            if (   tmp->so_lport        == uh->uh_sport
                && tmp->so_laddr.s_addr == ip->ip_src.s_addr)
            {
                so = tmp;
                break;
            }
        }
        if (tmp == &udb)
            so = NULL;
        else
        {
            udpstat.udpps_pcbcachemiss++;
            udp_last_so = so;
        }
    }

  new_socket:
    if (so == NULL)
    {
        /*
         * If there's no socket for this packet,
         * create one
         */
        if ((so = socreate()) == NULL)
        {
            Log2(("NAT: IP(id: %hd) failed to create socket\n", ip->ip_id));
            goto bad_free_mbuf;
        }

        /*
         * Setup fields
         */
        so->so_laddr = ip->ip_src;
        so->so_lport = uh->uh_sport;
        so->so_iptos = ip->ip_tos;

        if (udp_attach(pData, so) <= 0)
        {
            Log2(("NAT: IP(id: %hd) udp_attach errno = %d (%s)\n",
                        ip->ip_id, errno, strerror(errno)));
            sofree(pData, so);
            goto bad_free_mbuf;
        }

        /* udp_last_so = so; */
        /*
         * XXXXX Here, check if it's in udpexec_list,
         * and if it is, do the fork_exec() etc.
         */
    }

    so->so_faddr = ip->ip_dst;   /* XXX */
    so->so_fport = uh->uh_dport; /* XXX */
    Assert(so->so_type == IPPROTO_UDP);

    /*
     * DNS proxy
     */
    if (   pData->fUseDnsProxy
        && CTL_CHECK(ip->ip_dst.s_addr, CTL_DNS)
        && (uh->uh_dport == RT_H2N_U16_C(53)))
    {
        dnsproxy_query(pData, so, m, iphlen);
        goto done_free_mbuf;
    }

    iphlen += sizeof(struct udphdr);
    m->m_len -= iphlen;
    m->m_data += iphlen;

    ttl = ip->ip_ttl = save_ip.ip_ttl;
    if (ttl != so->so_sottl) {
        ret = setsockopt(so->s, IPPROTO_IP, IP_TTL,
                         (char *)&ttl, sizeof(ttl));
        if (RT_LIKELY(ret == 0))
            so->so_sottl = ttl;
    }

    tos = save_ip.ip_tos;
    if (tos != so->so_sotos) {
        ret = setsockopt(so->s, IPPROTO_IP, IP_TOS,
                         (char *)&tos, sizeof(tos));
        if (RT_LIKELY(ret == 0))
            so->so_sotos = tos;
    }

    {
        /*
         * Different OSes have different socket options for DF.  We
         * can't use IP_HDRINCL here as it's only valid for SOCK_RAW.
         */
#     define USE_DF_OPTION(_Optname) \
        const int dfopt = _Optname
#if   defined(IP_MTU_DISCOVER)
        USE_DF_OPTION(IP_MTU_DISCOVER);
#elif defined(IP_DONTFRAG)      /* Solaris 11+, FreeBSD */
        USE_DF_OPTION(IP_DONTFRAG);
#elif defined(IP_DONTFRAGMENT)  /* Windows */
        USE_DF_OPTION(IP_DONTFRAGMENT);
#else
        USE_DF_OPTION(0);
#endif
        if (dfopt) {
            int df = (save_ip.ip_off & IP_DF) != 0;
#if defined(IP_MTU_DISCOVER)
            df = df ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
#endif
            if (df != so->so_sodf) {
                ret = setsockopt(so->s, IPPROTO_IP, dfopt,
                                 (char *)&df, sizeof(df));
                if (RT_LIKELY(ret == 0))
                    so->so_sodf = df;
            }
        }
    }

    if (   sosendto(pData, so, m) == -1
        && (   !soIgnorableErrorCode(errno)
            && errno != ENOTCONN))
    {
        m->m_len += iphlen;
        m->m_data -= iphlen;
        *ip = save_ip;
        Log2(("NAT: UDP tx errno = %d (%s) on sent to %RTnaipv4\n",
              errno, strerror(errno), ip->ip_dst));
        icmp_error(pData, m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno));
        so->so_m = NULL;
        LogFlowFuncLeave();
        return;
    }

    if (so->so_m)
        m_freem(pData, so->so_m);   /* used for ICMP if error on sorecvfrom */

    /* restore the orig mbuf packet */
    m->m_len += iphlen;
    m->m_data -= iphlen;
    *ip = save_ip;
    so->so_m = m;         /* ICMP backup */
    LogFlowFuncLeave();
    return;

bad_free_mbuf:
    Log2(("NAT: UDP(id: %hd) datagram to %RTnaipv4 with size(%d) claimed as bad\n",
        ip->ip_id, &ip->ip_dst, ip->ip_len));

done_free_mbuf:
    /* some services like bootp(built-in), dns(buildt-in) and dhcp don't need sockets
     * and create new m'buffers to send them to guest, so we'll free their incomming
     * buffers here.
     */
    if (m != NULL)
        m_freem(pData, m);
    LogFlowFuncLeave();
    return;
}
extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char ** /*envp*/)
{
    /* Start logging: */
    LogFlowFuncEnter();

    /* Failed result initially: */
    int iResultCode = 1;

#ifdef Q_WS_X11
    if (!VBoxXInitThreads())
        return 1;
#endif /* Q_WS_X11 */

    /* Simulate try-catch block: */
    do
    {
#ifdef RT_OS_DARWIN
        ShutUpAppKit();
#endif /* RT_OS_DARWIN */

        /* Console help preprocessing: */
        bool fHelpShown = false;
        for (int i = 0; i < argc; ++i)
        {
            if (   !strcmp(argv[i], "-h")
                || !strcmp(argv[i], "-?")
                || !strcmp(argv[i], "-help")
                || !strcmp(argv[i], "--help"))
            {
                showHelp();
                fHelpShown = true;
                break;
            }
        }
        if (fHelpShown)
        {
            iResultCode = 0;
            break;
        }

#if defined(DEBUG) && defined(Q_WS_X11) && defined(RT_OS_LINUX)
        /* Install our signal handler to backtrace the call stack: */
        struct sigaction sa;
        sa.sa_sigaction = bt_sighandler;
        sigemptyset(&sa.sa_mask);
        sa.sa_flags = SA_RESTART | SA_SIGINFO;
        sigaction(SIGSEGV, &sa, NULL);
        sigaction(SIGBUS, &sa, NULL);
        sigaction(SIGUSR1, &sa, NULL);
#endif

#ifdef VBOX_WITH_HARDENING
        /* Make sure the image verification code works (VBoxDbg.dll and other plugins). */
        SUPR3HardenedVerifyInit();
#endif

#ifdef Q_WS_MAC
        /* Font fixes: */
        switch (VBoxGlobal::osRelease())
        {
            case MacOSXRelease_Mavericks: QFont::insertSubstitution(".Lucida Grande UI", "Lucida Grande"); break;
            case MacOSXRelease_Yosemite:  QFont::insertSubstitution(".Helvetica Neue DeskInterface", "Helvetica Neue"); break;
            default: break;
        }
# ifdef QT_MAC_USE_COCOA
        /* Instantiate our NSApplication derivative before QApplication
         * forces NSApplication to be instantiated. */
        UICocoaApplication::instance();
# endif /* QT_MAC_USE_COCOA */
#endif /* Q_WS_MAC */

        /* Install Qt console message handler: */
        qInstallMsgHandler(QtMessageOutput);

        /* Create application: */
        QApplication a(argc, argv);

#ifdef Q_WS_X11
        /* To avoid various Qt crashes
         * when testing widget attributes or acquiring winIds
         * we decided to make our widgets native under x11 hosts.
         * Yes, we aware of note that alien widgets faster to draw
         * but the only widget we need to be fast - viewport of VM
         * was always native since we are using his id for 3d service needs. */
        a.setAttribute(Qt::AA_NativeWindows);
#endif /* Q_WS_X11 */

#ifdef Q_WS_MAC
# ifdef VBOX_GUI_WITH_HIDPI
        /* Enable HiDPI icons. For this we require a patched version of Qt 4.x with
         * the changes from https://codereview.qt-project.org/#change,54636 applied. */
        qApp->setAttribute(Qt::AA_UseHighDpiPixmaps);
# endif /* VBOX_GUI_WITH_HIDPI */
#endif /* Q_WS_MAC */

#ifdef Q_OS_SOLARIS
        /* Use plastique look&feel for Solaris instead of the default motif (Qt 4.7.x): */
        QApplication::setStyle(new QPlastiqueStyle);
#endif /* Q_OS_SOLARIS */

#ifdef Q_WS_X11
        /* This patch is not used for now on Solaris & OpenSolaris because
         * there is no anti-aliasing enabled by default, Qt4 to be rebuilt. */
# ifndef Q_OS_SOLARIS
        /* Cause Qt4 has the conflict with fontconfig application as a result
         * sometimes substituting some fonts with non scaleable-anti-aliased
         * bitmap font we are reseting substitutes for the current application
         * font family if it is non scaleable-anti-aliased. */
        QFontDatabase fontDataBase;

        QString currentFamily(QApplication::font().family());
        bool isCurrentScaleable = fontDataBase.isScalable(currentFamily);

        QString subFamily(QFont::substitute(currentFamily));
        bool isSubScaleable = fontDataBase.isScalable(subFamily);

        if (isCurrentScaleable && !isSubScaleable)
            QFont::removeSubstitution(currentFamily);
# endif /* Q_OS_SOLARIS */
#endif /* Q_WS_X11 */

#ifdef Q_WS_WIN
        /* Drag in the sound drivers and DLLs early to get rid of the delay taking
         * place when the main menu bar (or any action from that menu bar) is
         * activated for the first time. This delay is especially annoying if it
         * happens when the VM is executing in real mode (which gives 100% CPU
         * load and slows down the load process that happens on the main GUI
         * thread to several seconds). */
        PlaySound(NULL, NULL, 0);
#endif /* Q_WS_WIN */

#ifdef Q_WS_MAC
        /* Disable menu icons on MacOS X host: */
        ::darwinDisableIconsInMenus();
#endif /* Q_WS_MAC */

#ifdef Q_WS_X11
        /* Qt version check (major.minor are sensitive, fix number is ignored): */
        if (VBoxGlobal::qtRTVersion() < (VBoxGlobal::qtCTVersion() & 0xFFFF00))
        {
            QString strMsg = QApplication::tr("Executable <b>%1</b> requires Qt %2.x, found Qt %3.")
                                              .arg(qAppName())
                                              .arg(VBoxGlobal::qtCTVersionString().section('.', 0, 1))
                                              .arg(VBoxGlobal::qtRTVersionString());
            QMessageBox::critical(0, QApplication::tr("Incompatible Qt Library Error"),
                                  strMsg, QMessageBox::Abort, 0);
            qFatal("%s", strMsg.toUtf8().constData());
            break;
        }
#endif /* Q_WS_X11 */

        /* Create modal-window manager: */
        UIModalWindowManager::create();

        /* Create global UI instance: */
        VBoxGlobal::create();

        /* Simulate try-catch block: */
        do
        {
            /* Exit if VBoxGlobal is not valid: */
            if (!vboxGlobal().isValid())
                break;

            /* Exit if VBoxGlobal was able to pre-process arguments: */
            if (vboxGlobal().processArgs())
                break;

#ifdef RT_OS_LINUX
            /* Make sure no wrong USB mounted: */
            VBoxGlobal::checkForWrongUSBMounted();
#endif /* RT_OS_LINUX */

            /* Load application settings: */
            VBoxGlobalSettings settings = vboxGlobal().settings();

            /* VM console process: */
            if (vboxGlobal().isVMConsoleProcess())
            {
                /* Make sure VM is started: */
                if (!UIMachine::startMachine(vboxGlobal().managedVMUuid()))
                    break;

                /* Start application: */
                iResultCode = a.exec();
            }
            /* VM selector process: */
            else
            {
                /* Make sure VM selector is permitted: */
                if (settings.isFeatureActive("noSelector"))
                {
                    msgCenter().cannotStartSelector();
                    break;
                }

#ifdef VBOX_BLEEDING_EDGE
                msgCenter().showExperimentalBuildWarning();
#else /* VBOX_BLEEDING_EDGE */
# ifndef DEBUG
                /* Check for BETA version: */
                const QString vboxVersion(vboxGlobal().virtualBox().GetVersion());
                if (   vboxVersion.contains("BETA")
                    && gEDataManager->preventBetaBuildWarningForVersion() != vboxVersion)
                    msgCenter().showBetaBuildWarning();
# endif /* !DEBUG */
#endif /* !VBOX_BLEEDING_EDGE*/

                /* Create/show selector window: */
                vboxGlobal().selectorWnd().show();

                /* Start application: */
                iResultCode = a.exec();
            }
        }
        while (0);

        /* Destroy global UI instance: */
        VBoxGlobal::destroy();

        /* Destroy modal-window manager: */
        UIModalWindowManager::destroy();
    }
    while (0);

    /* Finish logging: */
    LogFlowFunc(("rc=%d\n", iResultCode));
    LogFlowFuncLeave();

    /* Return result: */
    return iResultCode;
}
/*static*/
DECLCALLBACK(int) VirtualBox::ClientWatcher::worker(RTTHREAD /* thread */, void *pvUser)
{
    LogFlowFuncEnter();

    VirtualBox::ClientWatcher *that = (VirtualBox::ClientWatcher *)pvUser;
    Assert(that);

    typedef std::vector<ComObjPtr<Machine> > MachineVector;
    typedef std::vector<ComObjPtr<SessionMachine> > SessionMachineVector;

    SessionMachineVector machines;
    MachineVector spawnedMachines;

    size_t cnt = 0;
    size_t cntSpawned = 0;

    VirtualBoxBase::initializeComForThread();

#if defined(RT_OS_WINDOWS)

    /// @todo (dmik) processes reaping!

    HANDLE handles[MAXIMUM_WAIT_OBJECTS];
    handles[0] = that->mUpdateReq;

    do
    {
        AutoCaller autoCaller(that->mVirtualBox);
        /* VirtualBox has been early uninitialized, terminate */
        if (!autoCaller.isOk())
            break;

        do
        {
            /* release the caller to let uninit() ever proceed */
            autoCaller.release();

            DWORD rc = ::WaitForMultipleObjects((DWORD)(1 + cnt + cntSpawned),
                                                handles,
                                                FALSE,
                                                INFINITE);

            /* Restore the caller before using VirtualBox. If it fails, this
             * means VirtualBox is being uninitialized and we must terminate. */
            autoCaller.add();
            if (!autoCaller.isOk())
                break;

            bool update = false;

            if (rc == WAIT_OBJECT_0)
            {
                /* update event is signaled */
                update = true;
            }
            else if (rc > WAIT_OBJECT_0 && rc <= (WAIT_OBJECT_0 + cnt))
            {
                /* machine mutex is released */
                (machines[rc - WAIT_OBJECT_0 - 1])->i_checkForDeath();
                update = true;
            }
            else if (rc > WAIT_ABANDONED_0 && rc <= (WAIT_ABANDONED_0 + cnt))
            {
                /* machine mutex is abandoned due to client process termination */
                (machines[rc - WAIT_ABANDONED_0 - 1])->i_checkForDeath();
                update = true;
            }
            else if (rc > WAIT_OBJECT_0 + cnt && rc <= (WAIT_OBJECT_0 + cntSpawned))
            {
                /* spawned VM process has terminated (normally or abnormally) */
                (spawnedMachines[rc - WAIT_OBJECT_0 - cnt - 1])->
                    i_checkForSpawnFailure();
                update = true;
            }

            if (update)
            {
                /* close old process handles */
                for (size_t i = 1 + cnt; i < 1 + cnt + cntSpawned; ++i)
                    CloseHandle(handles[i]);

                // get reference to the machines list in VirtualBox
                VirtualBox::MachinesOList &allMachines = that->mVirtualBox->i_getMachinesList();

                // lock the machines list for reading
                AutoReadLock thatLock(allMachines.getLockHandle() COMMA_LOCKVAL_SRC_POS);

                /* obtain a new set of opened machines */
                cnt = 0;
                machines.clear();

                for (MachinesOList::iterator it = allMachines.begin();
                     it != allMachines.end();
                     ++it)
                {
                    /// @todo handle situations with more than 64 objects
                    AssertMsgBreak((1 + cnt) <= MAXIMUM_WAIT_OBJECTS,
                                   ("MAXIMUM_WAIT_OBJECTS reached"));

                    ComObjPtr<SessionMachine> sm;
                    if ((*it)->i_isSessionOpenOrClosing(sm))
                    {
                        AutoCaller smCaller(sm);
                        if (smCaller.isOk())
                        {
                            AutoReadLock smLock(sm COMMA_LOCKVAL_SRC_POS);
                            Machine::ClientToken *ct = sm->i_getClientToken();
                            if (ct)
                            {
                                HANDLE ipcSem = ct->getToken();
                                machines.push_back(sm);
                                handles[1 + cnt] = ipcSem;
                                ++cnt;
                            }
                        }
                    }
                }

                LogFlowFunc(("UPDATE: direct session count = %d\n", cnt));

                /* obtain a new set of spawned machines */
                cntSpawned = 0;
                spawnedMachines.clear();

                for (MachinesOList::iterator it = allMachines.begin();
                     it != allMachines.end();
                     ++it)
                {
                    /// @todo handle situations with more than 64 objects
                    AssertMsgBreak((1 + cnt + cntSpawned) <= MAXIMUM_WAIT_OBJECTS,
                                   ("MAXIMUM_WAIT_OBJECTS reached"));

                    if ((*it)->i_isSessionSpawning())
                    {
                        ULONG pid;
                        HRESULT hrc = (*it)->COMGETTER(SessionPID)(&pid);
                        if (SUCCEEDED(hrc))
                        {
                            HANDLE ph = OpenProcess(SYNCHRONIZE, FALSE, pid);
                            AssertMsg(ph != NULL, ("OpenProcess (pid=%d) failed with %d\n",
                                                   pid, GetLastError()));
                            if (ph != NULL)
                            {
                                spawnedMachines.push_back(*it);
                                handles[1 + cnt + cntSpawned] = ph;
                                ++cntSpawned;
                            }
                        }
                    }
                }

                LogFlowFunc(("UPDATE: spawned session count = %d\n", cntSpawned));

                // machines lock unwinds here
            }
        }
        while (true);
    }
    while (0);

    /* close old process handles */
    for (size_t i = 1 + cnt; i < 1 + cnt + cntSpawned; ++i)
        CloseHandle(handles[i]);

    /* release sets of machines if any */
    machines.clear();
    spawnedMachines.clear();

    ::CoUninitialize();

#elif defined(RT_OS_OS2)

    /// @todo (dmik) processes reaping!

    /* according to PMREF, 64 is the maximum for the muxwait list */
    SEMRECORD handles[64];

    HMUX muxSem = NULLHANDLE;

    do
    {
        AutoCaller autoCaller(that->mVirtualBox);
        /* VirtualBox has been early uninitialized, terminate */
        if (!autoCaller.isOk())
            break;

        do
        {
            /* release the caller to let uninit() ever proceed */
            autoCaller.release();

            int vrc = RTSemEventWait(that->mUpdateReq, 500);

            /* Restore the caller before using VirtualBox. If it fails, this
             * means VirtualBox is being uninitialized and we must terminate. */
            autoCaller.add();
            if (!autoCaller.isOk())
                break;

            bool update = false;
            bool updateSpawned = false;

            if (RT_SUCCESS(vrc))
            {
                /* update event is signaled */
                update = true;
                updateSpawned = true;
            }
            else
            {
                AssertMsg(vrc == VERR_TIMEOUT || vrc == VERR_INTERRUPTED,
                          ("RTSemEventWait returned %Rrc\n", vrc));

                /* are there any mutexes? */
                if (cnt > 0)
                {
                    /* figure out what's going on with machines */

                    unsigned long semId = 0;
                    APIRET arc = ::DosWaitMuxWaitSem(muxSem,
                                                     SEM_IMMEDIATE_RETURN, &semId);

                    if (arc == NO_ERROR)
                    {
                        /* machine mutex is normally released */
                        Assert(semId >= 0 && semId < cnt);
                        if (semId >= 0 && semId < cnt)
                        {
#if 0//def DEBUG
                            {
                                AutoReadLock machineLock(machines[semId] COMMA_LOCKVAL_SRC_POS);
                                LogFlowFunc(("released mutex: machine='%ls'\n",
                                             machines[semId]->name().raw()));
                            }
#endif
                            machines[semId]->i_checkForDeath();
                        }
                        update = true;
                    }
                    else if (arc == ERROR_SEM_OWNER_DIED)
                    {
                        /* machine mutex is abandoned due to client process
                         * termination; find which mutex is in the Owner Died
                         * state */
                        for (size_t i = 0; i < cnt; ++i)
                        {
                            PID pid; TID tid;
                            unsigned long reqCnt;
                            arc = DosQueryMutexSem((HMTX)handles[i].hsemCur, &pid, &tid, &reqCnt);
                            if (arc == ERROR_SEM_OWNER_DIED)
                            {
                                /* close the dead mutex as asked by PMREF */
                                ::DosCloseMutexSem((HMTX)handles[i].hsemCur);

                                Assert(i >= 0 && i < cnt);
                                if (i >= 0 && i < cnt)
                                {
#if 0//def DEBUG
                                    {
                                        AutoReadLock machineLock(machines[semId] COMMA_LOCKVAL_SRC_POS);
                                        LogFlowFunc(("mutex owner dead: machine='%ls'\n",
                                                     machines[i]->name().raw()));
                                    }
#endif
                                    machines[i]->i_checkForDeath();
                                }
                            }
                        }
                        update = true;
                    }
                    else
                        AssertMsg(arc == ERROR_INTERRUPT || arc == ERROR_TIMEOUT,
                                  ("DosWaitMuxWaitSem returned %d\n", arc));
                }

                /* are there any spawning sessions? */
                if (cntSpawned > 0)
                {
                    for (size_t i = 0; i < cntSpawned; ++i)
                        updateSpawned |= (spawnedMachines[i])->
                            i_checkForSpawnFailure();
                }
            }

            if (update || updateSpawned)
            {
                // get reference to the machines list in VirtualBox
                VirtualBox::MachinesOList &allMachines = that->mVirtualBox->i_getMachinesList();

                // lock the machines list for reading
                AutoReadLock thatLock(allMachines.getLockHandle() COMMA_LOCKVAL_SRC_POS);

                if (update)
                {
                    /* close the old muxsem */
                    if (muxSem != NULLHANDLE)
                        ::DosCloseMuxWaitSem(muxSem);

                    /* obtain a new set of opened machines */
                    cnt = 0;
                    machines.clear();

                    for (MachinesOList::iterator it = allMachines.begin();
                         it != allMachines.end(); ++it)
                    {
                        /// @todo handle situations with more than 64 objects
                        AssertMsg(cnt <= 64 /* according to PMREF */,
                                  ("maximum of 64 mutex semaphores reached (%d)",
                                   cnt));

                        ComObjPtr<SessionMachine> sm;
                        if ((*it)->i_isSessionOpenOrClosing(sm))
                        {
                            AutoCaller smCaller(sm);
                            if (smCaller.isOk())
                            {
                                AutoReadLock smLock(sm COMMA_LOCKVAL_SRC_POS);
                                ClientToken *ct = sm->i_getClientToken();
                                if (ct)
                                {
                                    HMTX ipcSem = ct->getToken();
                                    machines.push_back(sm);
                                    handles[cnt].hsemCur = (HSEM)ipcSem;
                                    handles[cnt].ulUser = cnt;
                                    ++cnt;
                                }
                            }
                        }
                    }

                    LogFlowFunc(("UPDATE: direct session count = %d\n", cnt));

                    if (cnt > 0)
                    {
                        /* create a new muxsem */
                        APIRET arc = ::DosCreateMuxWaitSem(NULL, &muxSem, cnt,
                                                           handles,
                                                           DCMW_WAIT_ANY);
                        AssertMsg(arc == NO_ERROR,
                                  ("DosCreateMuxWaitSem returned %d\n", arc));
                        NOREF(arc);
                    }
                }

                if (updateSpawned)
                {
                    /* obtain a new set of spawned machines */
                    spawnedMachines.clear();

                    for (MachinesOList::iterator it = allMachines.begin();
                         it != allMachines.end(); ++it)
                    {
                        if ((*it)->i_isSessionSpawning())
                            spawnedMachines.push_back(*it);
                    }

                    cntSpawned = spawnedMachines.size();
                    LogFlowFunc(("UPDATE: spawned session count = %d\n", cntSpawned));
                }
            }
        }
        while (true);
    }
    while (0);

    /* close the muxsem */
    if (muxSem != NULLHANDLE)
        ::DosCloseMuxWaitSem(muxSem);

    /* release sets of machines if any */
    machines.clear();
    spawnedMachines.clear();

#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)

    bool update = false;
    bool updateSpawned = false;

    do
    {
        AutoCaller autoCaller(that->mVirtualBox);
        if (!autoCaller.isOk())
            break;

        do
        {
            /* release the caller to let uninit() ever proceed */
            autoCaller.release();

            /* determine wait timeout adaptively: after updating information
             * relevant to the client watcher, check a few times more
             * frequently. This ensures good reaction time when the signalling
             * has to be done a bit before the actual change for technical
             * reasons, and saves CPU cycles when no activities are expected. */
            RTMSINTERVAL cMillies;
            {
                uint8_t uOld, uNew;
                do
                {
                    uOld = ASMAtomicUoReadU8(&that->mUpdateAdaptCtr);
                    uNew = uOld ? uOld - 1 : uOld;
                } while (!ASMAtomicCmpXchgU8(&that->mUpdateAdaptCtr, uNew, uOld));
                Assert(uOld <= RT_ELEMENTS(s_aUpdateTimeoutSteps) - 1);
                cMillies = s_aUpdateTimeoutSteps[uOld];
            }

            int rc = RTSemEventWait(that->mUpdateReq, cMillies);

            /*
             *  Restore the caller before using VirtualBox. If it fails, this
             *  means VirtualBox is being uninitialized and we must terminate.
             */
            autoCaller.add();
            if (!autoCaller.isOk())
                break;

            if (RT_SUCCESS(rc) || update || updateSpawned)
            {
                /* RT_SUCCESS(rc) means an update event is signaled */

                // get reference to the machines list in VirtualBox
                VirtualBox::MachinesOList &allMachines = that->mVirtualBox->i_getMachinesList();

                // lock the machines list for reading
                AutoReadLock thatLock(allMachines.getLockHandle() COMMA_LOCKVAL_SRC_POS);

                if (RT_SUCCESS(rc) || update)
                {
                    /* obtain a new set of opened machines */
                    machines.clear();

                    for (MachinesOList::iterator it = allMachines.begin();
                         it != allMachines.end();
                         ++it)
                    {
                        ComObjPtr<SessionMachine> sm;
                        if ((*it)->i_isSessionOpenOrClosing(sm))
                            machines.push_back(sm);
                    }

                    cnt = machines.size();
                    LogFlowFunc(("UPDATE: direct session count = %d\n", cnt));
                }

                if (RT_SUCCESS(rc) || updateSpawned)
                {
                    /* obtain a new set of spawned machines */
                    spawnedMachines.clear();

                    for (MachinesOList::iterator it = allMachines.begin();
                         it != allMachines.end();
                         ++it)
                    {
                        if ((*it)->i_isSessionSpawning())
                            spawnedMachines.push_back(*it);
                    }

                    cntSpawned = spawnedMachines.size();
                    LogFlowFunc(("UPDATE: spawned session count = %d\n", cntSpawned));
                }

                // machines lock unwinds here
            }

            update = false;
            for (size_t i = 0; i < cnt; ++i)
                update |= (machines[i])->i_checkForDeath();

            updateSpawned = false;
            for (size_t i = 0; i < cntSpawned; ++i)
                updateSpawned |= (spawnedMachines[i])->i_checkForSpawnFailure();

            /* reap child processes */
            {
                AutoWriteLock alock(that->mLock COMMA_LOCKVAL_SRC_POS);
                if (that->mProcesses.size())
                {
                    LogFlowFunc(("UPDATE: child process count = %d\n",
                                 that->mProcesses.size()));
                    VirtualBox::ClientWatcher::ProcessList::iterator it = that->mProcesses.begin();
                    while (it != that->mProcesses.end())
                    {
                        RTPROCESS pid = *it;
                        RTPROCSTATUS status;
                        int vrc = ::RTProcWait(pid, RTPROCWAIT_FLAGS_NOBLOCK, &status);
                        if (vrc == VINF_SUCCESS)
                        {
                            if (   status.enmReason != RTPROCEXITREASON_NORMAL
                                || status.iStatus   != RTEXITCODE_SUCCESS)
                            {
                                switch (status.enmReason)
                                {
                                    default:
                                    case RTPROCEXITREASON_NORMAL:
                                        LogRel(("Reaper: Pid %d (%x) exited normally: %d (%#x)\n",
                                                pid, pid, status.iStatus, status.iStatus));
                                        break;
                                    case RTPROCEXITREASON_ABEND:
                                        LogRel(("Reaper: Pid %d (%x) abended: %d (%#x)\n",
                                                pid, pid, status.iStatus, status.iStatus));
                                        break;
                                    case RTPROCEXITREASON_SIGNAL:
                                        LogRel(("Reaper: Pid %d (%x) was signalled: %d (%#x)\n",
                                                pid, pid, status.iStatus, status.iStatus));
                                        break;
                                }
                            }
                            else
                                LogFlowFunc(("pid %d (%x) was reaped, status=%d, reason=%d\n",
                                             pid, pid, status.iStatus,
                                             status.enmReason));
                            it = that->mProcesses.erase(it);
                        }
                        else
                        {
                            LogFlowFunc(("pid %d (%x) was NOT reaped, vrc=%Rrc\n",
                                         pid, pid, vrc));
                            if (vrc != VERR_PROCESS_RUNNING)
                            {
                                /* remove the process if it is not already running */
                                it = that->mProcesses.erase(it);
                            }
                            else
                                ++it;
                        }
                    }
                }
            }
        }
        while (true);
    }
    while (0);

    /* release sets of machines if any */
    machines.clear();
    spawnedMachines.clear();

#elif defined(VBOX_WITH_GENERIC_SESSION_WATCHER)

    bool updateSpawned = false;

    do
    {
        AutoCaller autoCaller(that->mVirtualBox);
        if (!autoCaller.isOk())
            break;

        do
        {
            /* release the caller to let uninit() ever proceed */
            autoCaller.release();

            /* determine wait timeout adaptively: after updating information
             * relevant to the client watcher, check a few times more
             * frequently. This ensures good reaction time when the signalling
             * has to be done a bit before the actual change for technical
             * reasons, and saves CPU cycles when no activities are expected. */
            RTMSINTERVAL cMillies;
            {
                uint8_t uOld, uNew;
                do
                {
                    uOld = ASMAtomicUoReadU8(&that->mUpdateAdaptCtr);
                    uNew = uOld ? uOld - 1 : uOld;
                } while (!ASMAtomicCmpXchgU8(&that->mUpdateAdaptCtr, uNew, uOld));
                Assert(uOld <= RT_ELEMENTS(s_aUpdateTimeoutSteps) - 1);
                cMillies = s_aUpdateTimeoutSteps[uOld];
            }

            int rc = RTSemEventWait(that->mUpdateReq, cMillies);

            /*
             *  Restore the caller before using VirtualBox. If it fails, this
             *  means VirtualBox is being uninitialized and we must terminate.
             */
            autoCaller.add();
            if (!autoCaller.isOk())
                break;

            /** @todo this quite big effort for catching machines in spawning
             * state which can't be caught by the token mechanism (as the token
             * can't be in the other process yet) could be eliminated if the
             * reaping is made smarter, having cross-reference information
             * from the pid to the corresponding machine object. Both cases do
             * more or less the same thing anyway. */
            if (RT_SUCCESS(rc) || updateSpawned)
            {
                /* RT_SUCCESS(rc) means an update event is signaled */

                // get reference to the machines list in VirtualBox
                VirtualBox::MachinesOList &allMachines = that->mVirtualBox->i_getMachinesList();

                // lock the machines list for reading
                AutoReadLock thatLock(allMachines.getLockHandle() COMMA_LOCKVAL_SRC_POS);

                if (RT_SUCCESS(rc) || updateSpawned)
                {
                    /* obtain a new set of spawned machines */
                    spawnedMachines.clear();

                    for (MachinesOList::iterator it = allMachines.begin();
                         it != allMachines.end();
                         ++it)
                    {
                        if ((*it)->i_isSessionSpawning())
                            spawnedMachines.push_back(*it);
                    }

                    cntSpawned = spawnedMachines.size();
                    LogFlowFunc(("UPDATE: spawned session count = %d\n", cntSpawned));
                }

                NOREF(cnt);
                // machines lock unwinds here
            }

            updateSpawned = false;
            for (size_t i = 0; i < cntSpawned; ++i)
                updateSpawned |= (spawnedMachines[i])->i_checkForSpawnFailure();

            /* reap child processes */
            {
                AutoWriteLock alock(that->mLock COMMA_LOCKVAL_SRC_POS);
                if (that->mProcesses.size())
                {
                    LogFlowFunc(("UPDATE: child process count = %d\n",
                                 that->mProcesses.size()));
                    VirtualBox::ClientWatcher::ProcessList::iterator it = that->mProcesses.begin();
                    while (it != that->mProcesses.end())
                    {
                        RTPROCESS pid = *it;
                        RTPROCSTATUS status;
                        int vrc = ::RTProcWait(pid, RTPROCWAIT_FLAGS_NOBLOCK, &status);
                        if (vrc == VINF_SUCCESS)
                        {
                            if (   status.enmReason != RTPROCEXITREASON_NORMAL
                                || status.iStatus   != RTEXITCODE_SUCCESS)
                            {
                                switch (status.enmReason)
                                {
                                    default:
                                    case RTPROCEXITREASON_NORMAL:
                                        LogRel(("Reaper: Pid %d (%x) exited normally: %d (%#x)\n",
                                                pid, pid, status.iStatus, status.iStatus));
                                        break;
                                    case RTPROCEXITREASON_ABEND:
                                        LogRel(("Reaper: Pid %d (%x) abended: %d (%#x)\n",
                                                pid, pid, status.iStatus, status.iStatus));
                                        break;
                                    case RTPROCEXITREASON_SIGNAL:
                                        LogRel(("Reaper: Pid %d (%x) was signalled: %d (%#x)\n",
                                                pid, pid, status.iStatus, status.iStatus));
                                        break;
                                }
                            }
                            else
                                LogFlowFunc(("pid %d (%x) was reaped, status=%d, reason=%d\n",
                                             pid, pid, status.iStatus,
                                             status.enmReason));
                            it = that->mProcesses.erase(it);
                        }
                        else
                        {
                            LogFlowFunc(("pid %d (%x) was NOT reaped, vrc=%Rrc\n",
                                         pid, pid, vrc));
                            if (vrc != VERR_PROCESS_RUNNING)
                            {
                                /* remove the process if it is not already running */
                                it = that->mProcesses.erase(it);
                            }
                            else
                                ++it;
                        }
                    }
                }
            }
        }
        while (true);
    }
    while (0);

    /* release sets of machines if any */
    machines.clear();
    spawnedMachines.clear();

#else
# error "Port me!"
#endif

    VirtualBoxBase::uninitializeComForThread();

    LogFlowFuncLeave();
    return 0;
}
示例#27
0
/**
 * Windows Service Main.
 *
 * This is invoked when the service is started and should not return until
 * the service has been stopped.
 *
 * @param   cArgs           Argument count.
 * @param   papszArgs       Argument vector.
 */
static VOID WINAPI supSvcWinServiceMain(DWORD cArgs, LPSTR *papszArgs)
{
    LogFlowFuncEnter();

    /*
     * Register the control handler function for the service and report to SCM.
     */
    Assert(g_u32SupSvcWinStatus == SERVICE_STOPPED);
    g_hSupSvcWinCtrlHandler = RegisterServiceCtrlHandlerEx(SUPSVC_SERVICE_NAME, supSvcWinServiceCtrlHandlerEx, NULL);
    if (g_hSupSvcWinCtrlHandler)
    {
        DWORD err = ERROR_GEN_FAILURE;
        if (supSvcWinSetServiceStatus(SERVICE_START_PENDING, 3000, NO_ERROR))
        {
            /*
             * Parse arguments.
             */
            static const RTOPTIONDEF s_aOptions[] =
            {
                { "--dummy", 'd', RTGETOPT_REQ_NOTHING }
            };
            int iArg = 1; /* the first arg is the service name */
            int ch;
            int rc = 0;
            RTGETOPTUNION Value;
            while (   !rc
                   && (ch = RTGetOpt(cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), &iArg, &Value)))
                switch (ch)
                {
                    default:    rc = supSvcLogGetOptError("main", ch, cArgs, papszArgs, iArg, &Value); break;
                }
            if (iArg != cArgs)
                rc = supSvcLogTooManyArgsError("main", cArgs, papszArgs, iArg);
            if (!rc)
            {
                /*
                 * Create the event semaphore we'll be waiting on and
                 * then instantiate the actual services.
                 */
                int rc = RTSemEventMultiCreate(&g_hSupSvcWinEvent);
                if (RT_SUCCESS(rc))
                {
                    rc = supSvcCreateAndStartServices();
                    if (RT_SUCCESS(rc))
                    {
                        /*
                         * Update the status and enter the work loop.
                         *
                         * The work loop is just a dummy wait here as the services run
                         * in independent threads.
                         */
                        if (supSvcWinSetServiceStatus(SERVICE_RUNNING, 0, 0))
                        {
                            LogFlow(("supSvcWinServiceMain: calling RTSemEventMultiWait\n"));
                            rc = RTSemEventMultiWait(g_hSupSvcWinEvent, RT_INDEFINITE_WAIT);
                            if (RT_SUCCESS(rc))
                            {
                                LogFlow(("supSvcWinServiceMain: woke up\n"));
                                err = NO_ERROR;
                            }
                            else
                                supSvcLogError("RTSemEventWait failed, rc=%Rrc", rc);
                        }
                        else
                        {
                            err = GetLastError();
                            supSvcLogError("SetServiceStatus failed, err=%d", err);
                        }

                        /*
                         * Destroy the service instances, stopping them if
                         * they're still running (weird failure cause).
                         */
                        supSvcStopAndDestroyServices();
                    }

                    RTSemEventMultiDestroy(g_hSupSvcWinEvent);
                    g_hSupSvcWinEvent = NIL_RTSEMEVENTMULTI;
                }
                else
                    supSvcLogError("RTSemEventMultiCreate failed, rc=%Rrc", rc);
            }
            /* else: bad args */
        }
        else
        {
            err = GetLastError();
            supSvcLogError("SetServiceStatus failed, err=%d", err);
        }
        supSvcWinSetServiceStatus(SERVICE_STOPPED, 0, err);
    }
    else
        supSvcLogError("RegisterServiceCtrlHandlerEx failed, err=%d", GetLastError());
    LogFlowFuncLeave();
}
示例#28
0
extern "C" DECLEXPORT(int) TrustedMain (int argc, char **argv, char ** /*envp*/)
{
    LogFlowFuncEnter();
# if defined(RT_OS_DARWIN)
    ShutUpAppKit();
# endif

    for (int i=0; i<argc; i++)
        if (   !strcmp(argv[i], "-h")
            || !strcmp(argv[i], "-?")
            || !strcmp(argv[i], "-help")
            || !strcmp(argv[i], "--help"))
        {
            showHelp();
            return 0;
        }

#if defined(DEBUG) && defined(Q_WS_X11) && defined(RT_OS_LINUX)
    /* install our signal handler to backtrace the call stack */
    struct sigaction sa;
    sa.sa_sigaction = bt_sighandler;
    sigemptyset (&sa.sa_mask);
    sa.sa_flags = SA_RESTART | SA_SIGINFO;
    sigaction (SIGSEGV, &sa, NULL);
    sigaction (SIGBUS, &sa, NULL);
    sigaction (SIGUSR1, &sa, NULL);
#endif

#ifdef QT_MAC_USE_COCOA
    /* Instantiate our NSApplication derivative before QApplication
     * forces NSApplication to be instantiated. */
    UICocoaApplication::instance();
#endif

    qInstallMsgHandler (QtMessageOutput);

    int rc = 1; /* failure */

    /* scope the QApplication variable */
    {
#ifdef Q_WS_X11
        /* Qt has a complex algorithm for selecting the right visual which
         * doesn't always seem to work.  So we naively choose a visual - the
         * default one - ourselves and pass that to Qt.  This means that we
         * also have to open the display ourselves.
         * We check the Qt parameter list and handle Qt's -display argument
         * ourselves, since we open the display connection.  We also check the
         * to see if the user has passed Qt's -visual parameter, and if so we
         * assume that the user wants Qt to handle visual selection after all,
         * and don't supply a visual. */
        char *pszDisplay = NULL;
        bool useDefaultVisual = true;
        for (int i = 0; i < argc; ++i)
        {
            if (!::strcmp(argv[i], "-display") && (i + 1 < argc))
            /* What if it isn't?  Rely on QApplication to complain? */
            {
                pszDisplay = argv[i + 1];
                ++i;
            }
            else if (!::strcmp(argv[i], "-visual"))
                useDefaultVisual = false;
        }
        Display *pDisplay = XOpenDisplay(pszDisplay);
        if (!pDisplay)
        {
            RTPrintf(pszDisplay ? "Failed to open the X11 display \"%s\"!\n"
                                : "Failed to open the X11 display!\n",
                     pszDisplay);
            return 0;
        }
        Visual *pVisual =   useDefaultVisual
                          ? DefaultVisual(pDisplay, DefaultScreen(pDisplay))
                          : NULL;
        /* Now create the application object */
        QApplication a (pDisplay, argc, argv, (Qt::HANDLE) pVisual);
#else /* Q_WS_X11 */
        QApplication a (argc, argv);
#endif /* Q_WS_X11 */

        /* Qt4.3 version has the QProcess bug which freezing the application
         * for 30 seconds. This bug is internally used at initialization of
         * Cleanlooks style. So we have to change this style to another one.
         * See http://trolltech.com/developer/task-tracker/index_html?id=179200&method=entry
         * for details. */
        if (VBoxGlobal::qtRTVersionString().startsWith ("4.3") &&
            qobject_cast <QCleanlooksStyle*> (QApplication::style()))
            QApplication::setStyle (new QPlastiqueStyle);

#ifdef Q_OS_SOLARIS
        /* Use plastique look 'n feel for Solaris instead of the default motif (Qt 4.7.x) */
        QApplication::setStyle (new QPlastiqueStyle);
#endif

#ifdef Q_WS_X11
        /* This patch is not used for now on Solaris & OpenSolaris because
         * there is no anti-aliasing enabled by default, Qt4 to be rebuilt. */
#ifndef Q_OS_SOLARIS
        /* Cause Qt4 has the conflict with fontconfig application as a result
         * sometimes substituting some fonts with non scaleable-anti-aliased
         * bitmap font we are reseting substitutes for the current application
         * font family if it is non scaleable-anti-aliased. */
        QFontDatabase fontDataBase;

        QString currentFamily (QApplication::font().family());
        bool isCurrentScaleable = fontDataBase.isScalable (currentFamily);

        /*
        LogFlowFunc (("Font: Current family is '%s'. It is %s.\n",
            currentFamily.toLatin1().constData(),
            isCurrentScaleable ? "scalable" : "not scalable"));
        QStringList subFamilies (QFont::substitutes (currentFamily));
        foreach (QString sub, subFamilies)
        {
            bool isSubScalable = fontDataBase.isScalable (sub);
            LogFlowFunc (("Font: Substitute family is '%s'. It is %s.\n",
                sub.toLatin1().constData(),
                isSubScalable ? "scalable" : "not scalable"));
        }
        */

        QString subFamily (QFont::substitute (currentFamily));
        bool isSubScaleable = fontDataBase.isScalable (subFamily);

        if (isCurrentScaleable && !isSubScaleable)
            QFont::removeSubstitution (currentFamily);
#endif /* Q_OS_SOLARIS */
#endif

#ifdef Q_WS_WIN
        /* Drag in the sound drivers and DLLs early to get rid of the delay taking
         * place when the main menu bar (or any action from that menu bar) is
         * activated for the first time. This delay is especially annoying if it
         * happens when the VM is executing in real mode (which gives 100% CPU
         * load and slows down the load process that happens on the main GUI
         * thread to several seconds). */
        PlaySound (NULL, NULL, 0);
#endif

#ifdef Q_WS_MAC
        ::darwinDisableIconsInMenus();
#endif /* Q_WS_MAC */

#ifdef Q_WS_X11
        /* version check (major.minor are sensitive, fix number is ignored) */
        if (VBoxGlobal::qtRTVersion() < (VBoxGlobal::qtCTVersion() & 0xFFFF00))
        {
            QString msg =
                QApplication::tr ("Executable <b>%1</b> requires Qt %2.x, found Qt %3.")
                                  .arg (qAppName())
                                  .arg (VBoxGlobal::qtCTVersionString().section ('.', 0, 1))
                                  .arg (VBoxGlobal::qtRTVersionString());
            QMessageBox::critical (
                0, QApplication::tr ("Incompatible Qt Library Error"),
                msg, QMessageBox::Abort, 0);
            qFatal ("%s", msg.toAscii().constData());
        }
#endif

        /* load a translation based on the current locale */
        VBoxGlobal::loadLanguage();

        do
        {
            if (!vboxGlobal().isValid())
                break;


            if (vboxGlobal().processArgs())
                return 0;

            msgCenter().checkForMountedWrongUSB();

            VBoxGlobalSettings settings = vboxGlobal().settings();
            /* Process known keys */
            bool noSelector = settings.isFeatureActive ("noSelector");

            if (vboxGlobal().isVMConsoleProcess())
            {
#ifdef VBOX_GUI_WITH_SYSTRAY
                if (vboxGlobal().trayIconInstall())
                {
                    /* Nothing to do here yet. */
                }
#endif
                if (vboxGlobal().startMachine (vboxGlobal().managedVMUuid()))
                {
                    vboxGlobal().setMainWindow (vboxGlobal().vmWindow());
                    rc = a.exec();
                }
            }
            else if (noSelector)
            {
                msgCenter().cannotRunInSelectorMode();
            }
            else
            {
#ifdef VBOX_BLEEDING_EDGE
                msgCenter().showBEBWarning();
#else
# ifndef DEBUG
                /* Check for BETA version */
                QString vboxVersion (vboxGlobal().virtualBox().GetVersion());
                if (vboxVersion.contains ("BETA"))
                {
                    /* Allow to prevent this message */
                    QString str = vboxGlobal().virtualBox().
                        GetExtraData(GUI_PreventBetaWarning);
                    if (str != vboxVersion)
                        msgCenter().showBETAWarning();
                }
# endif
#endif

                vboxGlobal().setMainWindow (&vboxGlobal().selectorWnd());
#ifdef VBOX_GUI_WITH_SYSTRAY
                if (vboxGlobal().trayIconInstall())
                {
                    /* Nothing to do here yet. */
                }

                if (false == vboxGlobal().isTrayMenu())
                {
#endif
                    vboxGlobal().selectorWnd().show();
#ifdef VBOX_WITH_REGISTRATION_REQUEST
                    vboxGlobal().showRegistrationDialog (false /* aForce */);
#endif
#ifdef VBOX_GUI_WITH_SYSTRAY
                }

                do
                {
#endif
                    rc = a.exec();
#ifdef VBOX_GUI_WITH_SYSTRAY
                } while (vboxGlobal().isTrayMenu());
#endif
            }
        }
        while (0);
    }

    LogFlowFunc (("rc=%d\n", rc));
    LogFlowFuncLeave();

    return rc;
}
HRESULT Guest::taskUpdateGuestAdditions(GuestTask *aTask)
{
    LogFlowFuncEnter();

    AutoCaller autoCaller(this);
    if (FAILED(autoCaller.rc())) return autoCaller.rc();

    /*
     * Do *not* take a write lock here since we don't (and won't)
     * touch any class-specific data (of IGuest) here - only the member functions
     * which get called here can do that.
     */

    HRESULT rc = S_OK;
    BOOL fCompleted;
    BOOL fCanceled;

    try
    {
        ComObjPtr<Guest> pGuest = aTask->pGuest;

        aTask->pProgress->SetCurrentOperationProgress(10);

        /*
         * Determine guest OS type and the required installer image.
         * At the moment only Windows guests are supported.
         */
        Utf8Str installerImage;
        Bstr osTypeId;
        if (   SUCCEEDED(pGuest->COMGETTER(OSTypeId(osTypeId.asOutParam())))
            && !osTypeId.isEmpty())
        {
            Utf8Str osTypeIdUtf8(osTypeId); /* Needed for .contains(). */
            if (   osTypeIdUtf8.contains("Microsoft", Utf8Str::CaseInsensitive)
                || osTypeIdUtf8.contains("Windows", Utf8Str::CaseInsensitive))
            {
                if (osTypeIdUtf8.contains("64", Utf8Str::CaseInsensitive))
                    installerImage = "VBOXWINDOWSADDITIONS_AMD64.EXE";
                else
                    installerImage = "VBOXWINDOWSADDITIONS_X86.EXE";
                /* Since the installers are located in the root directory,
                 * no further path processing needs to be done (yet). */
            }
            else /* Everything else is not supported (yet). */
                throw GuestTask::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->pProgress,
                                                      Guest::tr("Detected guest OS (%s) does not support automatic Guest Additions updating, please update manually"),
                                                      osTypeIdUtf8.c_str());
        }
        else
            throw GuestTask::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->pProgress,
                                                  Guest::tr("Could not detected guest OS type/version, please update manually"));
        Assert(!installerImage.isEmpty());

        /*
         * Try to open the .ISO file and locate the specified installer.
         */
        RTISOFSFILE iso;
        int vrc = RTIsoFsOpen(&iso, aTask->strSource.c_str());
        if (RT_FAILURE(vrc))
        {
            rc = GuestTask::setProgressErrorInfo(VBOX_E_FILE_ERROR, aTask->pProgress,
                                                 Guest::tr("Invalid installation medium detected: \"%s\""),
                                                 aTask->strSource.c_str());
        }
        else
        {
            uint32_t cbOffset;
            size_t cbLength;
            vrc = RTIsoFsGetFileInfo(&iso, installerImage.c_str(), &cbOffset, &cbLength);
            if (   RT_SUCCESS(vrc)
                && cbOffset
                && cbLength)
            {
                vrc = RTFileSeek(iso.file, cbOffset, RTFILE_SEEK_BEGIN, NULL);
                if (RT_FAILURE(vrc))
                    rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress,
                                                         Guest::tr("Could not seek to setup file on installation medium \"%s\" (%Rrc)"),
                                                         aTask->strSource.c_str(), vrc);
            }
            else
            {
                switch (vrc)
                {
                    case VERR_FILE_NOT_FOUND:
                        rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress,
                                                             Guest::tr("Setup file was not found on installation medium \"%s\""),
                                                             aTask->strSource.c_str());
                        break;

                    default:
                        rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress,
                                                             Guest::tr("An unknown error (%Rrc) occured while retrieving information of setup file on installation medium \"%s\""),
                                                             vrc, aTask->strSource.c_str());
                        break;
                }
            }

            /* Specify the ouput path on the guest side. */
            Utf8Str strInstallerPath = "%TEMP%\\VBoxWindowsAdditions.exe";

            if (RT_SUCCESS(vrc))
            {
                /* Okay, we're ready to start our copy routine on the guest! */
                aTask->pProgress->SetCurrentOperationProgress(15);

                /* Prepare command line args. */
                com::SafeArray<IN_BSTR> args;
                com::SafeArray<IN_BSTR> env;

                args.push_back(Bstr("--output").raw());               /* We want to write a file ... */
                args.push_back(Bstr(strInstallerPath.c_str()).raw()); /* ... with this path. */

                if (SUCCEEDED(rc))
                {
                    ComPtr<IProgress> progressCat;
                    ULONG uPID;

                    /*
                     * Start built-in "vbox_cat" tool (inside VBoxService) to
                     * copy over/pipe the data into a file on the guest (with
                     * system rights, no username/password specified).
                     */
                    rc = pGuest->executeProcessInternal(Bstr(VBOXSERVICE_TOOL_CAT).raw(),
                                                          ExecuteProcessFlag_Hidden
                                                        | ExecuteProcessFlag_WaitForProcessStartOnly,
                                                        ComSafeArrayAsInParam(args),
                                                        ComSafeArrayAsInParam(env),
                                                        Bstr("").raw() /* Username. */,
                                                        Bstr("").raw() /* Password */,
                                                        5 * 1000 /* Wait 5s for getting the process started. */,
                                                        &uPID, progressCat.asOutParam(), &vrc);
                    if (FAILED(rc))
                    {
                        /* Errors which return VBOX_E_NOT_SUPPORTED can be safely skipped by the caller
                         * to silently fall back to "normal" (old) .ISO mounting. */

                        /* Due to a very limited COM error range we use vrc for a more detailed error
                         * lookup to figure out what went wrong. */
                        switch (vrc)
                        {
                            /* Guest execution service is not (yet) ready. This basically means that either VBoxService
                             * is not running (yet) or that the Guest Additions are too old (because VBoxService does not
                             * support the guest execution feature in this version). */
                            case VERR_NOT_FOUND:
                                LogRel(("Guest Additions seem not to be installed yet\n"));
                                rc = GuestTask::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->pProgress,
                                                                     Guest::tr("Guest Additions seem not to be installed or are not ready to update yet"));
                                break;

                            /* Getting back a VERR_INVALID_PARAMETER indicates that the installed Guest Additions are supporting the guest
                             * execution but not the built-in "vbox_cat" tool of VBoxService (< 4.0). */
                            case VERR_INVALID_PARAMETER:
                                LogRel(("Guest Additions are installed but don't supported automatic updating\n"));
                                rc = GuestTask::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->pProgress,
                                                                     Guest::tr("Installed Guest Additions do not support automatic updating"));
                                break;

                            case VERR_TIMEOUT:
                                LogRel(("Guest was unable to start copying the Guest Additions setup within time\n"));
                                rc = GuestTask::setProgressErrorInfo(E_FAIL, aTask->pProgress,
                                                                     Guest::tr("Guest was unable to start copying the Guest Additions setup within time"));
                                break;

                            default:
                                rc = GuestTask::setProgressErrorInfo(E_FAIL, aTask->pProgress,
                                                                     Guest::tr("Error copying Guest Additions setup file to guest path \"%s\" (%Rrc)"),
                                                                     strInstallerPath.c_str(), vrc);
                                break;
                        }
                    }
                    else
                    {
                        LogRel(("Automatic update of Guest Additions started, using \"%s\"\n", aTask->strSource.c_str()));
                        LogRel(("Copying Guest Additions installer \"%s\" to \"%s\" on guest ...\n",
                                installerImage.c_str(), strInstallerPath.c_str()));
                        aTask->pProgress->SetCurrentOperationProgress(20);

                        /* Wait for process to exit ... */
                        SafeArray<BYTE> aInputData(_64K);
                        while (   SUCCEEDED(progressCat->COMGETTER(Completed(&fCompleted)))
                               && !fCompleted)
                        {
                            size_t cbRead;
                            /* cbLength contains remaining bytes of our installer file
                             * opened above to read. */
                            size_t cbToRead = RT_MIN(cbLength, _64K);
                            if (cbToRead)
                            {
                                vrc = RTFileRead(iso.file, (uint8_t*)aInputData.raw(), cbToRead, &cbRead);
                                if (   cbRead
                                    && RT_SUCCESS(vrc))
                                {
                                    /* Resize buffer to reflect amount we just have read. */
                                    if (cbRead > 0)
                                        aInputData.resize(cbRead);

                                    /* Did we reach the end of the content we want to transfer (last chunk)? */
                                    ULONG uFlags = ProcessInputFlag_None;
                                    if (   (cbRead < _64K)
                                        /* Did we reach the last block which is exactly _64K? */
                                        || (cbToRead - cbRead == 0)
                                        /* ... or does the user want to cancel? */
                                        || (   SUCCEEDED(aTask->pProgress->COMGETTER(Canceled(&fCanceled)))
                                            && fCanceled)
                                       )
                                    {
                                        uFlags |= ProcessInputFlag_EndOfFile;
                                    }

                                    /* Transfer the current chunk ... */
                                #ifdef DEBUG_andy
                                    LogRel(("Copying Guest Additions (%u bytes left) ...\n", cbLength));
                                #endif
                                    ULONG uBytesWritten;
                                    rc = pGuest->SetProcessInput(uPID, uFlags,
                                                                 10 * 1000 /* Wait 10s for getting the input data transfered. */,
                                                                 ComSafeArrayAsInParam(aInputData), &uBytesWritten);
                                    if (FAILED(rc))
                                    {
                                        rc = GuestTask::setProgressErrorInfo(rc, aTask->pProgress, pGuest);
                                        break;
                                    }

                                    /* If task was canceled above also cancel the process execution. */
                                    if (fCanceled)
                                        progressCat->Cancel();

                                #ifdef DEBUG_andy
                                    LogRel(("Copying Guest Additions (%u bytes written) ...\n", uBytesWritten));
                                #endif
                                    Assert(cbLength >= uBytesWritten);
                                    cbLength -= uBytesWritten;
                                }
                                else if (RT_FAILURE(vrc))
                                {
                                    rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress,
                                                                         Guest::tr("Error while reading setup file \"%s\" (To read: %u, Size: %u) from installation medium (%Rrc)"),
                                                                         installerImage.c_str(), cbToRead, cbLength, vrc);
                                }
                            }

                            /* Internal progress canceled? */
                            if (   SUCCEEDED(progressCat->COMGETTER(Canceled(&fCanceled)))
                                && fCanceled)
                            {
                                aTask->pProgress->Cancel();
                                break;
                            }
                        }
                    }
                }
            }
            RTIsoFsClose(&iso);

            if (   SUCCEEDED(rc)
                && (   SUCCEEDED(aTask->pProgress->COMGETTER(Canceled(&fCanceled)))
                    && !fCanceled
                   )
               )
            {
                /*
                 * Installer was transferred successfully, so let's start it
                 * (with system rights).
                 */
                LogRel(("Preparing to execute Guest Additions update ...\n"));
                aTask->pProgress->SetCurrentOperationProgress(66);

                /* Prepare command line args for installer. */
                com::SafeArray<IN_BSTR> installerArgs;
                com::SafeArray<IN_BSTR> installerEnv;

                /** @todo Only Windows! */
                installerArgs.push_back(Bstr(strInstallerPath).raw()); /* The actual (internal) installer image (as argv[0]). */
                /* Note that starting at Windows Vista the lovely session 0 separation applies:
                 * This means that if we run an application with the profile/security context
                 * of VBoxService (system rights!) we're not able to show any UI. */
                installerArgs.push_back(Bstr("/S").raw());      /* We want to install in silent mode. */
                installerArgs.push_back(Bstr("/l").raw());      /* ... and logging enabled. */
                /* Don't quit VBoxService during upgrade because it still is used for this
                 * piece of code we're in right now (that is, here!) ... */
                installerArgs.push_back(Bstr("/no_vboxservice_exit").raw());
                /* Tell the installer to report its current installation status
                 * using a running VBoxTray instance via balloon messages in the
                 * Windows taskbar. */
                installerArgs.push_back(Bstr("/post_installstatus").raw());

                /*
                 * Start the just copied over installer with system rights
                 * in silent mode on the guest. Don't use the hidden flag since there
                 * may be pop ups the user has to process.
                 */
                ComPtr<IProgress> progressInstaller;
                ULONG uPID;
                rc = pGuest->executeProcessInternal(Bstr(strInstallerPath).raw(),
                                                    ExecuteProcessFlag_WaitForProcessStartOnly,
                                                    ComSafeArrayAsInParam(installerArgs),
                                                    ComSafeArrayAsInParam(installerEnv),
                                                    Bstr("").raw() /* Username */,
                                                    Bstr("").raw() /* Password */,
                                                    10 * 1000 /* Wait 10s for getting the process started */,
                                                    &uPID, progressInstaller.asOutParam(), &vrc);
                if (SUCCEEDED(rc))
                {
                    LogRel(("Guest Additions update is running ...\n"));

                    /* If the caller does not want to wait for out guest update process to end,
                     * complete the progress object now so that the caller can do other work. */
                    if (aTask->uFlags & AdditionsUpdateFlag_WaitForUpdateStartOnly)
                        aTask->pProgress->notifyComplete(S_OK);
                    else
                        aTask->pProgress->SetCurrentOperationProgress(70);

                    /* Wait until the Guest Additions installer finishes ... */
                    while (   SUCCEEDED(progressInstaller->COMGETTER(Completed(&fCompleted)))
                           && !fCompleted)
                    {
                        if (   SUCCEEDED(aTask->pProgress->COMGETTER(Canceled(&fCanceled)))
                            && fCanceled)
                        {
                            progressInstaller->Cancel();
                            break;
                        }
                        /* Progress canceled by Main API? */
                        if (   SUCCEEDED(progressInstaller->COMGETTER(Canceled(&fCanceled)))
                            && fCanceled)
                        {
                            break;
                        }
                        RTThreadSleep(100);
                    }

                    ExecuteProcessStatus_T retStatus;
                    ULONG uRetExitCode, uRetFlags;
                    rc = pGuest->GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &retStatus);
                    if (SUCCEEDED(rc))
                    {
                        if (fCompleted)
                        {
                            if (uRetExitCode == 0)
                            {
                                LogRel(("Guest Additions update successful!\n"));
                                if (   SUCCEEDED(aTask->pProgress->COMGETTER(Completed(&fCompleted)))
                                    && !fCompleted)
                                    aTask->pProgress->notifyComplete(S_OK);
                            }
                            else
                            {
                                LogRel(("Guest Additions update failed (Exit code=%u, Status=%u, Flags=%u)\n",
                                        uRetExitCode, retStatus, uRetFlags));
                                rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress,
                                                                     Guest::tr("Guest Additions update failed with exit code=%u (status=%u, flags=%u)"),
                                                                     uRetExitCode, retStatus, uRetFlags);
                            }
                        }
                        else if (   SUCCEEDED(progressInstaller->COMGETTER(Canceled(&fCanceled)))
                                 && fCanceled)
                        {
                            LogRel(("Guest Additions update was canceled\n"));
                            rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress,
                                                                 Guest::tr("Guest Additions update was canceled by the guest with exit code=%u (status=%u, flags=%u)"),
                                                                 uRetExitCode, retStatus, uRetFlags);
                        }
                        else
                        {
                            LogRel(("Guest Additions update was canceled by the user\n"));
                        }
                    }
                    else
                        rc = GuestTask::setProgressErrorInfo(rc, aTask->pProgress, pGuest);
                }
                else
                    rc = GuestTask::setProgressErrorInfo(rc, aTask->pProgress, pGuest);
            }
        }
    }
    catch (HRESULT aRC)
    {
        rc = aRC;
    }

    /* Clean up */
    aTask->rc = rc;

    LogFlowFunc(("rc=%Rhrc\n", rc));
    LogFlowFuncLeave();

    return VINF_SUCCESS;
}
示例#30
0
/**
 *  VirtualBox component constructor.
 *
 *  This constructor is responsible for starting the VirtualBox server
 *  process, connecting to it, and redirecting the constructor request to the
 *  VirtualBox component defined on the server.
 */
static NS_IMETHODIMP
VirtualBoxConstructor(nsISupports *aOuter, REFNSIID aIID,
                      void **aResult)
{
    LogFlowFuncEnter();

    nsresult rc = NS_OK;
    int vrc = VINF_SUCCESS;

    do
    {
        *aResult = NULL;
        if (NULL != aOuter)
        {
            rc = NS_ERROR_NO_AGGREGATION;
            break;
        }

        if (!IsVBoxSVCPathSet)
        {
            /* Get the directory containing XPCOM components -- the VBoxSVC
             * executable is expected in the parent directory. */
            nsCOMPtr<nsIProperties> dirServ = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rc);
            if (NS_SUCCEEDED(rc))
            {
                nsCOMPtr<nsIFile> componentDir;
                rc = dirServ->Get(NS_XPCOM_COMPONENT_DIR,
                                  NS_GET_IID(nsIFile), getter_AddRefs(componentDir));

                if (NS_SUCCEEDED(rc))
                {
                    nsCAutoString path;
                    componentDir->GetNativePath(path);

                    LogFlowFunc(("component directory = \"%s\"\n", path.get()));
                    AssertBreakStmt(path.Length() + strlen(VBoxSVC_exe) < RTPATH_MAX,
                                    rc = NS_ERROR_FAILURE);

#if defined(RT_OS_SOLARIS) && defined(VBOX_WITH_HARDENING)
                    char achKernArch[128];
                    int cbKernArch = sysinfo(SI_ARCHITECTURE_K, achKernArch, sizeof(achKernArch));
                    if (cbKernArch > 0)
                    {
                        sprintf(VBoxSVCPath, "/opt/VirtualBox/%s%s", achKernArch, VBoxSVC_exe);
                        IsVBoxSVCPathSet = true;
                    }
                    else
                        rc = NS_ERROR_UNEXPECTED;
#else
                    strcpy(VBoxSVCPath, path.get());
                    RTPathStripFilename(VBoxSVCPath);
                    strcat(VBoxSVCPath, VBoxSVC_exe);

                    IsVBoxSVCPathSet = true;
#endif
                }
            }
            if (NS_FAILED(rc))
                break;
        }

        nsCOMPtr<ipcIService> ipcServ = do_GetService(IPC_SERVICE_CONTRACTID, &rc);
        if (NS_FAILED(rc))
            break;

        /* connect to the VBoxSVC server process */

        bool startedOnce = false;
        unsigned timeLeft = VBoxSVC_Timeout;

        do
        {
            LogFlowFunc(("Resolving server name \"%s\"...\n", VBOXSVC_IPC_NAME));

            PRUint32 serverID = 0;
            rc = ipcServ->ResolveClientName(VBOXSVC_IPC_NAME, &serverID);
            if (NS_FAILED(rc))
            {
                LogFlowFunc(("Starting server \"%s\"...\n", VBoxSVCPath));

                startedOnce = true;

                rc = vboxsvcSpawnDaemon();
                if (NS_FAILED(rc))
                    break;

                /* wait for the server process to establish a connection */
                do
                {
                    RTThreadSleep(VBoxSVC_WaitSlice);
                    rc = ipcServ->ResolveClientName(VBOXSVC_IPC_NAME, &serverID);
                    if (NS_SUCCEEDED(rc))
                        break;
                    if (timeLeft <= VBoxSVC_WaitSlice)
                    {
                        timeLeft = 0;
                        break;
                    }
                    timeLeft -= VBoxSVC_WaitSlice;
                }
                while (1);

                if (!timeLeft)
                {
                    rc = IPC_ERROR_WOULD_BLOCK;
                    break;
                }
            }

            LogFlowFunc(("Connecting to server (ID=%d)...\n", serverID));

            nsCOMPtr<ipcIDConnectService> dconServ =
                do_GetService(IPC_DCONNECTSERVICE_CONTRACTID, &rc);
            if (NS_FAILED(rc))
                break;

            rc = dconServ->CreateInstance(serverID,
                                          CLSID_VirtualBox,
                                          aIID, aResult);
            if (NS_SUCCEEDED(rc))
                break;

            LogFlowFunc(("Failed to connect (rc=%Rhrc (%#08x))\n", rc, rc));

            /* It's possible that the server gets shut down after we
             * successfully resolve the server name but before it
             * receives our CreateInstance() request. So, check for the
             * name again, and restart the cycle if it fails. */
            if (!startedOnce)
            {
                nsresult rc2 =
                    ipcServ->ResolveClientName(VBOXSVC_IPC_NAME, &serverID);
                if (NS_SUCCEEDED(rc2))
                    break;

                LogFlowFunc(("Server seems to have terminated before receiving our request. Will try again.\n"));
            }
            else
                break;
        }
        while (1);
    }
    while (0);

    LogFlowFunc(("rc=%Rhrc (%#08x), vrc=%Rrc\n", rc, rc, vrc));
    LogFlowFuncLeave();

    return rc;
}