VBoxServiceControl.cpp revision d4a220c9c1cb851c96d3f7d5c21792a2f8e1a315
a299266cddc1ae14d76d725a660bb278816bc151vboxsync * VBoxServiceControl - Host-driven Guest Control.
a299266cddc1ae14d76d725a660bb278816bc151vboxsync * Copyright (C) 2010 Oracle Corporation
a299266cddc1ae14d76d725a660bb278816bc151vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
a299266cddc1ae14d76d725a660bb278816bc151vboxsync * available from http://www.virtualbox.org. This file is free software;
a299266cddc1ae14d76d725a660bb278816bc151vboxsync * you can redistribute it and/or modify it under the terms of the GNU
a299266cddc1ae14d76d725a660bb278816bc151vboxsync * General Public License (GPL) as published by the Free Software
a299266cddc1ae14d76d725a660bb278816bc151vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a299266cddc1ae14d76d725a660bb278816bc151vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a299266cddc1ae14d76d725a660bb278816bc151vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a299266cddc1ae14d76d725a660bb278816bc151vboxsync/*******************************************************************************
a299266cddc1ae14d76d725a660bb278816bc151vboxsync* Header Files *
a299266cddc1ae14d76d725a660bb278816bc151vboxsync*******************************************************************************/
a299266cddc1ae14d76d725a660bb278816bc151vboxsyncusing namespace guestControl;
a299266cddc1ae14d76d725a660bb278816bc151vboxsync/*******************************************************************************
54dc8e6c81a07ae54c66e27f210609f2ff529760vboxsync* Global Variables *
739c9e0e5fccb99475b8202ead8fc5665b2fa64cvboxsync*******************************************************************************/
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/** The control interval (millseconds). */
a299266cddc1ae14d76d725a660bb278816bc151vboxsync/** The semaphore we're blocking on. */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsyncstatic RTSEMEVENTMULTI g_hControlEvent = NIL_RTSEMEVENTMULTI;
a299266cddc1ae14d76d725a660bb278816bc151vboxsync/** The guest property service client ID. */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync/** List of spawned processes */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync/** @copydoc VBOXSERVICE::pfnPreInit */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsyncstatic DECLCALLBACK(int) VBoxServiceControlPreInit(void)
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync/** @copydoc VBOXSERVICE::pfnOption */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsyncstatic DECLCALLBACK(int) VBoxServiceControlOption(const char **ppszShort, int argc, char **argv, int *pi)
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync /* no short options */;
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync/** @copydoc VBOXSERVICE::pfnInit */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsyncstatic DECLCALLBACK(int) VBoxServiceControlInit(void)
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync * If not specified, find the right interval default.
4bcaf5d320bf0d88910212509c37bdd634e0879evboxsync * Then create the event sem to block on.
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync rc = VbglR3GuestCtrlConnect(&g_GuestControlSvcClientID);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync VBoxServiceVerbose(3, "Control: Service Client ID: %#x\n", g_GuestControlSvcClientID);
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync VBoxServiceError("Control: Failed to connect to the guest control service! Error: %Rrc\n", rc);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync /* Init thread list. */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsyncstatic int VBoxServiceControlHandleCmdStartProcess(uint32_t u32ClientId, uint32_t uNumParms)
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync int rc = VbglR3GuestCtrlExecGetHostCmd(u32ClientId,
b2c35a7024c4c308b429c81b203b3bcbd44ee60cvboxsync /* Command */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync /* Flags */
b2c35a7024c4c308b429c81b203b3bcbd44ee60cvboxsync /* Arguments */
4bcaf5d320bf0d88910212509c37bdd634e0879evboxsync /* Environment */
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync /* Pipes */
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync /* Credentials */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync /* Timelimit */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync VBoxServiceError("Control: Failed to retrieve exec start command! Error: %Rrc\n", rc);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync rc = VBoxServiceControlExecProcess(uContextID, szCmd, uFlags, szArgs, uNumArgs,
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync VBoxServiceVerbose(4, "Control: VBoxServiceControlHandleCmdStartProcess returned with %Rrc\n", rc);
cec3b04587a02f0dc7d0cc679e9a0de19b730e2cvboxsyncstatic int VBoxServiceControlHandleCmdGetOutput(uint32_t u32ClientId, uint32_t uNumParms)
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync int rc = VbglR3GuestCtrlExecGetHostCmdOutput(u32ClientId, uNumParms,
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync VBoxServiceError("Control: Failed to retrieve exec output command! Error: %Rrc\n", rc);
a299266cddc1ae14d76d725a660bb278816bc151vboxsync /* Let's have a look if we have a running process with PID = uPID ... */
a299266cddc1ae14d76d725a660bb278816bc151vboxsync bool bFound = false;
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync RTListForEach(&g_GuestControlExecThreads, pNode, VBOXSERVICECTRLTHREAD, Node)
a299266cddc1ae14d76d725a660bb278816bc151vboxsync && pNode->enmType == VBoxServiceCtrlThreadDataExec)
a299266cddc1ae14d76d725a660bb278816bc151vboxsync PVBOXSERVICECTRLTHREADDATAEXEC pData = (PVBOXSERVICECTRLTHREADDATAEXEC)pNode->pvData;
a299266cddc1ae14d76d725a660bb278816bc151vboxsync PVBOXSERVICECTRLTHREADDATAEXEC pData = (PVBOXSERVICECTRLTHREADDATAEXEC)pNode->pvData;
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync rc = VBoxServiceControlExecReadPipeBufferContent(&pData->stdOut, pBuf, cbSize, &cbRead);
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync /* cbRead now contains actual size. */
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync rc = VbglR3GuestCtrlExecSendOut(u32ClientId, uContextID, uPID, 0 /* handle ID */, 0 /* flags */,
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync VBoxServiceVerbose(4, "Control: VBoxServiceControlHandleCmdGetOutput returned with %Rrc\n", rc);
a299266cddc1ae14d76d725a660bb278816bc151vboxsync/** @copydoc VBOXSERVICE::pfnWorker */
a299266cddc1ae14d76d725a660bb278816bc151vboxsyncDECLCALLBACK(int) VBoxServiceControlWorker(bool volatile *pfShutdown)
a299266cddc1ae14d76d725a660bb278816bc151vboxsync * Tell the control thread that it can continue
a299266cddc1ae14d76d725a660bb278816bc151vboxsync * spawning services.
a299266cddc1ae14d76d725a660bb278816bc151vboxsync * Execution loop.
a8fd9edea57842da84a8bcf265a92eb5e96c9c4bvboxsync VBoxServiceVerbose(4, "Control: Waiting for host msg ...\n");
a8fd9edea57842da84a8bcf265a92eb5e96c9c4bvboxsync rc = VbglR3GuestCtrlGetHostMsg(g_GuestControlSvcClientID, &uMsg, &uNumParms, 1000 /* 1s timeout */);
a299266cddc1ae14d76d725a660bb278816bc151vboxsync VBoxServiceVerbose(3, "Control: Message requires %ld parameters, but only 2 supplied -- retrying request ...\n", uNumParms);
d0445e5c26b62718e727032ae46626f5d5db7ae5vboxsync VBoxServiceVerbose(3, "Control: Wait timed out, waiting for next round ...\n");
a299266cddc1ae14d76d725a660bb278816bc151vboxsync VBoxServiceVerbose(3, "Control: Msg=%u (%u parms) retrieved\n", uMsg, uNumParms);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync rc = VBoxServiceControlHandleCmdStartProcess(g_GuestControlSvcClientID, uNumParms);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync rc = VBoxServiceControlHandleCmdGetOutput(g_GuestControlSvcClientID, uNumParms);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync VBoxServiceVerbose(3, "Control: Unsupported message from host! Msg=%u\n", uMsg);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync /* Don't terminate here; just wait for the next message. */
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync VBoxServiceVerbose(3, "Control: Message was processed with rc=%Rrc\n", rc);
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync * Block for a while.
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync * The event semaphore takes care of ignoring interruptions and it
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync * allows us to implement service wakeup later.
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync int rc2 = RTSemEventMultiWait(g_hControlEvent, g_ControlInterval);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync VBoxServiceError("Control: RTSemEventMultiWait failed; rc2=%Rrc\n", rc2);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync/** @copydoc VBOXSERVICE::pfnStop */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsyncstatic DECLCALLBACK(void) VBoxServiceControlStop(void)
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync /** @todo Later, figure what to do if we're in RTProcWait(). it's a very
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync * annoying call since doesn't support timeouts in the posix world. */
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync/** @copydoc VBOXSERVICE::pfnTerm */
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsyncstatic DECLCALLBACK(void) VBoxServiceControlTerm(void)
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync /* Signal all threads that we want to shutdown. */
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync RTListForEach(&g_GuestControlExecThreads, pNode, VBOXSERVICECTRLTHREAD, Node)
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync /* Wait for threads to shutdown. */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync RTListForEach(&g_GuestControlExecThreads, pNode, VBOXSERVICECTRLTHREAD, Node)
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync int rc2 = RTThreadWait(pNode->Thread, 30 * 1000 /* Wait 30 seconds max. */, NULL);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync VBoxServiceError("Control: Thread failed to stop; rc2=%Rrc\n", rc2);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync /* Destroy thread specific data. */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync VBoxServiceControlExecDestroyThreadData((PVBOXSERVICECTRLTHREADDATAEXEC)pNode->pvData);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync /* Finally destroy thread list. */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync pNode = RTListNodeGetFirst(&g_GuestControlExecThreads, VBOXSERVICECTRLTHREAD, Node);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync PVBOXSERVICECTRLTHREAD pNext = RTListNodeGetNext(&pNode->Node, VBOXSERVICECTRLTHREAD, Node);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync if (pNext && RTListNodeIsLast(&g_GuestControlExecThreads, &pNext->Node))
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync VbglR3GuestCtrlDisconnect(g_GuestControlSvcClientID);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync * The 'vminfo' service description.
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync /* pszName. */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync /* pszDescription. */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync "Host-driven Guest Control",
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync /* pszUsage. */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync "[--control-interval <ms>]"
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync /* pszOptions. */
4bcaf5d320bf0d88910212509c37bdd634e0879evboxsync " --control-interval Specifies the interval at which to check for\n"
4bcaf5d320bf0d88910212509c37bdd634e0879evboxsync " new control commands. The default is 1000 ms.\n"
4bcaf5d320bf0d88910212509c37bdd634e0879evboxsync /* methods */