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; }
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; }
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; }
/** * 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; }
/** 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(); }
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(); }
/* 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; }
/** * 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(); }
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(); }
/** 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; }
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; }
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; }
/** * 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(); }
/** * 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; }
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; }
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; }
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; }
/* 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; }
/** * 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(); }
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; }
/** * 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; }