VBoxServiceControl.cpp revision d4a220c9c1cb851c96d3f7d5c21792a2f8e1a315
a299266cddc1ae14d76d725a660bb278816bc151vboxsync
a299266cddc1ae14d76d725a660bb278816bc151vboxsync/* $Id$ */
a299266cddc1ae14d76d725a660bb278816bc151vboxsync/** @file
a299266cddc1ae14d76d725a660bb278816bc151vboxsync * VBoxServiceControl - Host-driven Guest Control.
a299266cddc1ae14d76d725a660bb278816bc151vboxsync */
a299266cddc1ae14d76d725a660bb278816bc151vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/*
a299266cddc1ae14d76d725a660bb278816bc151vboxsync * Copyright (C) 2010 Oracle Corporation
a299266cddc1ae14d76d725a660bb278816bc151vboxsync *
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
a299266cddc1ae14d76d725a660bb278816bc151vboxsync
a299266cddc1ae14d76d725a660bb278816bc151vboxsync/*******************************************************************************
a299266cddc1ae14d76d725a660bb278816bc151vboxsync* Header Files *
a299266cddc1ae14d76d725a660bb278816bc151vboxsync*******************************************************************************/
a299266cddc1ae14d76d725a660bb278816bc151vboxsync#include <iprt/asm.h>
cec3b04587a02f0dc7d0cc679e9a0de19b730e2cvboxsync#include <iprt/assert.h>
a299266cddc1ae14d76d725a660bb278816bc151vboxsync#include <iprt/getopt.h>
a299266cddc1ae14d76d725a660bb278816bc151vboxsync#include <iprt/mem.h>
a299266cddc1ae14d76d725a660bb278816bc151vboxsync#include <iprt/semaphore.h>
a299266cddc1ae14d76d725a660bb278816bc151vboxsync#include <iprt/thread.h>
a299266cddc1ae14d76d725a660bb278816bc151vboxsync#include <VBox/VBoxGuestLib.h>
a299266cddc1ae14d76d725a660bb278816bc151vboxsync#include <VBox/HostServices/GuestControlSvc.h>
a299266cddc1ae14d76d725a660bb278816bc151vboxsync#include "VBoxServiceInternal.h"
a299266cddc1ae14d76d725a660bb278816bc151vboxsync#include "VBoxServiceUtils.h"
cec3b04587a02f0dc7d0cc679e9a0de19b730e2cvboxsync
a299266cddc1ae14d76d725a660bb278816bc151vboxsyncusing namespace guestControl;
a299266cddc1ae14d76d725a660bb278816bc151vboxsync
a299266cddc1ae14d76d725a660bb278816bc151vboxsync/*******************************************************************************
54dc8e6c81a07ae54c66e27f210609f2ff529760vboxsync* Global Variables *
739c9e0e5fccb99475b8202ead8fc5665b2fa64cvboxsync*******************************************************************************/
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/** The control interval (millseconds). */
a299266cddc1ae14d76d725a660bb278816bc151vboxsyncuint32_t g_ControlInterval = 0;
a299266cddc1ae14d76d725a660bb278816bc151vboxsync/** The semaphore we're blocking on. */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsyncstatic RTSEMEVENTMULTI g_hControlEvent = NIL_RTSEMEVENTMULTI;
a299266cddc1ae14d76d725a660bb278816bc151vboxsync/** The guest property service client ID. */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsyncstatic uint32_t g_GuestControlSvcClientID = 0;
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync/** List of spawned processes */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsyncRTLISTNODE g_GuestControlExecThreads;
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync/** @copydoc VBOXSERVICE::pfnPreInit */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsyncstatic DECLCALLBACK(int) VBoxServiceControlPreInit(void)
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync{
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync return VINF_SUCCESS;
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync}
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync/** @copydoc VBOXSERVICE::pfnOption */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsyncstatic DECLCALLBACK(int) VBoxServiceControlOption(const char **ppszShort, int argc, char **argv, int *pi)
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync{
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync int rc = -1;
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync if (ppszShort)
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync /* no short options */;
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync else if (!strcmp(argv[*pi], "--control-interval"))
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync rc = VBoxServiceArgUInt32(argc, argv, "", pi,
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync &g_ControlInterval, 1, UINT32_MAX - 1);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync return rc;
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync}
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync/** @copydoc VBOXSERVICE::pfnInit */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsyncstatic DECLCALLBACK(int) VBoxServiceControlInit(void)
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync{
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync /*
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync * If not specified, find the right interval default.
4bcaf5d320bf0d88910212509c37bdd634e0879evboxsync * Then create the event sem to block on.
4bcaf5d320bf0d88910212509c37bdd634e0879evboxsync */
cec3b04587a02f0dc7d0cc679e9a0de19b730e2cvboxsync if (!g_ControlInterval)
cec3b04587a02f0dc7d0cc679e9a0de19b730e2cvboxsync g_ControlInterval = 1000;
cec3b04587a02f0dc7d0cc679e9a0de19b730e2cvboxsync
cec3b04587a02f0dc7d0cc679e9a0de19b730e2cvboxsync int rc = RTSemEventMultiCreate(&g_hControlEvent);
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync AssertRCReturn(rc, rc);
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync rc = VbglR3GuestCtrlConnect(&g_GuestControlSvcClientID);
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync if (RT_SUCCESS(rc))
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync VBoxServiceVerbose(3, "Control: Service Client ID: %#x\n", g_GuestControlSvcClientID);
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync else
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync {
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync VBoxServiceError("Control: Failed to connect to the guest control service! Error: %Rrc\n", rc);
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync RTSemEventMultiDestroy(g_hControlEvent);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync g_hControlEvent = NIL_RTSEMEVENTMULTI;
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync }
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync /* Init thread list. */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync RTListInit(&g_GuestControlExecThreads);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync return rc;
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync}
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsyncstatic int VBoxServiceControlHandleCmdStartProcess(uint32_t u32ClientId, uint32_t uNumParms)
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync{
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync uint32_t uContextID;
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync char szCmd[_1K];
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync uint32_t uFlags;
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync char szArgs[_1K];
a299266cddc1ae14d76d725a660bb278816bc151vboxsync uint32_t uNumArgs;
a299266cddc1ae14d76d725a660bb278816bc151vboxsync char szEnv[_64K];
a299266cddc1ae14d76d725a660bb278816bc151vboxsync uint32_t cbEnv = sizeof(szEnv);
54dc8e6c81a07ae54c66e27f210609f2ff529760vboxsync uint32_t uNumEnvVars;
a299266cddc1ae14d76d725a660bb278816bc151vboxsync char szStdIn[_1K];
a299266cddc1ae14d76d725a660bb278816bc151vboxsync char szStdOut[_1K];
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync char szStdErr[_1K];
a299266cddc1ae14d76d725a660bb278816bc151vboxsync char szUser[128];
a299266cddc1ae14d76d725a660bb278816bc151vboxsync char szPassword[128];
a299266cddc1ae14d76d725a660bb278816bc151vboxsync uint32_t uTimeLimitMS;
a299266cddc1ae14d76d725a660bb278816bc151vboxsync
a299266cddc1ae14d76d725a660bb278816bc151vboxsync if (uNumParms != 14)
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync return VERR_INVALID_PARAMETER;
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync int rc = VbglR3GuestCtrlExecGetHostCmd(u32ClientId,
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync uNumParms,
b2c35a7024c4c308b429c81b203b3bcbd44ee60cvboxsync &uContextID,
b2c35a7024c4c308b429c81b203b3bcbd44ee60cvboxsync /* Command */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync szCmd, sizeof(szCmd),
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync /* Flags */
b2c35a7024c4c308b429c81b203b3bcbd44ee60cvboxsync &uFlags,
b2c35a7024c4c308b429c81b203b3bcbd44ee60cvboxsync /* Arguments */
cec3b04587a02f0dc7d0cc679e9a0de19b730e2cvboxsync szArgs, sizeof(szArgs), &uNumArgs,
4bcaf5d320bf0d88910212509c37bdd634e0879evboxsync /* Environment */
cec3b04587a02f0dc7d0cc679e9a0de19b730e2cvboxsync szEnv, &cbEnv, &uNumEnvVars,
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync /* Pipes */
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync szStdIn, sizeof(szStdIn),
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync szStdOut, sizeof(szStdOut),
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync szStdErr, sizeof(szStdErr),
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync /* Credentials */
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync szUser, sizeof(szUser),
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync szPassword, sizeof(szPassword),
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync /* Timelimit */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync &uTimeLimitMS);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync if (RT_FAILURE(rc))
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync {
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync VBoxServiceError("Control: Failed to retrieve exec start command! Error: %Rrc\n", rc);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync }
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync else
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync {
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync rc = VBoxServiceControlExecProcess(uContextID, szCmd, uFlags, szArgs, uNumArgs,
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync szEnv, cbEnv, uNumEnvVars,
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync szStdIn, szStdOut, szStdErr,
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync szUser, szPassword, uTimeLimitMS);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync }
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync VBoxServiceVerbose(4, "Control: VBoxServiceControlHandleCmdStartProcess returned with %Rrc\n", rc);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync return rc;
4bcaf5d320bf0d88910212509c37bdd634e0879evboxsync}
4bcaf5d320bf0d88910212509c37bdd634e0879evboxsync
cec3b04587a02f0dc7d0cc679e9a0de19b730e2cvboxsync
cec3b04587a02f0dc7d0cc679e9a0de19b730e2cvboxsyncstatic int VBoxServiceControlHandleCmdGetOutput(uint32_t u32ClientId, uint32_t uNumParms)
cec3b04587a02f0dc7d0cc679e9a0de19b730e2cvboxsync{
cec3b04587a02f0dc7d0cc679e9a0de19b730e2cvboxsync uint32_t uContextID;
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync uint32_t uPID;
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync uint32_t uHandleID;
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync uint32_t uFlags;
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync int rc = VbglR3GuestCtrlExecGetHostCmdOutput(u32ClientId, uNumParms,
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync &uContextID, &uPID, &uHandleID, &uFlags);
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync if (RT_FAILURE(rc))
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync {
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync VBoxServiceError("Control: Failed to retrieve exec output command! Error: %Rrc\n", rc);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync }
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync else
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync {
a299266cddc1ae14d76d725a660bb278816bc151vboxsync /* Let's have a look if we have a running process with PID = uPID ... */
a299266cddc1ae14d76d725a660bb278816bc151vboxsync PVBOXSERVICECTRLTHREAD pNode;
a299266cddc1ae14d76d725a660bb278816bc151vboxsync bool bFound = false;
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync RTListForEach(&g_GuestControlExecThreads, pNode, VBOXSERVICECTRLTHREAD, Node)
a299266cddc1ae14d76d725a660bb278816bc151vboxsync {
a299266cddc1ae14d76d725a660bb278816bc151vboxsync if ( pNode->fStarted
a299266cddc1ae14d76d725a660bb278816bc151vboxsync && pNode->enmType == VBoxServiceCtrlThreadDataExec)
a299266cddc1ae14d76d725a660bb278816bc151vboxsync {
a299266cddc1ae14d76d725a660bb278816bc151vboxsync PVBOXSERVICECTRLTHREADDATAEXEC pData = (PVBOXSERVICECTRLTHREADDATAEXEC)pNode->pvData;
a299266cddc1ae14d76d725a660bb278816bc151vboxsync if (pData && pData->uPID == uPID)
a299266cddc1ae14d76d725a660bb278816bc151vboxsync {
a299266cddc1ae14d76d725a660bb278816bc151vboxsync bFound = true;
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync break;
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync }
a299266cddc1ae14d76d725a660bb278816bc151vboxsync }
a299266cddc1ae14d76d725a660bb278816bc151vboxsync }
a299266cddc1ae14d76d725a660bb278816bc151vboxsync
a299266cddc1ae14d76d725a660bb278816bc151vboxsync if (bFound)
a299266cddc1ae14d76d725a660bb278816bc151vboxsync {
a299266cddc1ae14d76d725a660bb278816bc151vboxsync PVBOXSERVICECTRLTHREADDATAEXEC pData = (PVBOXSERVICECTRLTHREADDATAEXEC)pNode->pvData;
a299266cddc1ae14d76d725a660bb278816bc151vboxsync AssertPtr(pData);
a299266cddc1ae14d76d725a660bb278816bc151vboxsync
a299266cddc1ae14d76d725a660bb278816bc151vboxsync uint32_t cbSize = _4K;
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync uint32_t cbRead = cbSize;
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync uint8_t *pBuf = (uint8_t*)RTMemAlloc(cbSize);
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync if (pBuf)
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync {
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync rc = VBoxServiceControlExecReadPipeBufferContent(&pData->stdOut, pBuf, cbSize, &cbRead);
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync if (RT_SUCCESS(rc))
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync {
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync AssertPtr(pBuf);
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync /* cbRead now contains actual size. */
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync rc = VbglR3GuestCtrlExecSendOut(u32ClientId, uContextID, uPID, 0 /* handle ID */, 0 /* flags */,
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync pBuf, cbRead);
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync }
a299266cddc1ae14d76d725a660bb278816bc151vboxsync RTMemFree(pBuf);
a299266cddc1ae14d76d725a660bb278816bc151vboxsync }
a299266cddc1ae14d76d725a660bb278816bc151vboxsync else
d0445e5c26b62718e727032ae46626f5d5db7ae5vboxsync rc = VERR_NO_MEMORY;
d0445e5c26b62718e727032ae46626f5d5db7ae5vboxsync }
d0445e5c26b62718e727032ae46626f5d5db7ae5vboxsync else
d0445e5c26b62718e727032ae46626f5d5db7ae5vboxsync rc = VERR_NOT_FOUND; /* PID not found! */
d0445e5c26b62718e727032ae46626f5d5db7ae5vboxsync }
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync VBoxServiceVerbose(4, "Control: VBoxServiceControlHandleCmdGetOutput returned with %Rrc\n", rc);
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync return rc;
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync}
d0445e5c26b62718e727032ae46626f5d5db7ae5vboxsync
d0445e5c26b62718e727032ae46626f5d5db7ae5vboxsync
a299266cddc1ae14d76d725a660bb278816bc151vboxsync/** @copydoc VBOXSERVICE::pfnWorker */
a299266cddc1ae14d76d725a660bb278816bc151vboxsyncDECLCALLBACK(int) VBoxServiceControlWorker(bool volatile *pfShutdown)
a299266cddc1ae14d76d725a660bb278816bc151vboxsync{
a299266cddc1ae14d76d725a660bb278816bc151vboxsync /*
a299266cddc1ae14d76d725a660bb278816bc151vboxsync * Tell the control thread that it can continue
a299266cddc1ae14d76d725a660bb278816bc151vboxsync * spawning services.
a299266cddc1ae14d76d725a660bb278816bc151vboxsync */
a299266cddc1ae14d76d725a660bb278816bc151vboxsync RTThreadUserSignal(RTThreadSelf());
a299266cddc1ae14d76d725a660bb278816bc151vboxsync Assert(g_GuestControlSvcClientID > 0);
0d1ceffcc16b8999752140e739adb27132655ee8vboxsync
a299266cddc1ae14d76d725a660bb278816bc151vboxsync int rc = VINF_SUCCESS;
a299266cddc1ae14d76d725a660bb278816bc151vboxsync
a299266cddc1ae14d76d725a660bb278816bc151vboxsync /*
a299266cddc1ae14d76d725a660bb278816bc151vboxsync * Execution loop.
a8fd9edea57842da84a8bcf265a92eb5e96c9c4bvboxsync *
a8fd9edea57842da84a8bcf265a92eb5e96c9c4bvboxsync * @todo
a8fd9edea57842da84a8bcf265a92eb5e96c9c4bvboxsync */
a8fd9edea57842da84a8bcf265a92eb5e96c9c4bvboxsync for (;;)
a8fd9edea57842da84a8bcf265a92eb5e96c9c4bvboxsync {
a8fd9edea57842da84a8bcf265a92eb5e96c9c4bvboxsync uint32_t uMsg;
a8fd9edea57842da84a8bcf265a92eb5e96c9c4bvboxsync uint32_t uNumParms;
a8fd9edea57842da84a8bcf265a92eb5e96c9c4bvboxsync VBoxServiceVerbose(4, "Control: Waiting for host msg ...\n");
a8fd9edea57842da84a8bcf265a92eb5e96c9c4bvboxsync rc = VbglR3GuestCtrlGetHostMsg(g_GuestControlSvcClientID, &uMsg, &uNumParms, 1000 /* 1s timeout */);
a8fd9edea57842da84a8bcf265a92eb5e96c9c4bvboxsync if (rc == VERR_TOO_MUCH_DATA)
a299266cddc1ae14d76d725a660bb278816bc151vboxsync {
a299266cddc1ae14d76d725a660bb278816bc151vboxsync VBoxServiceVerbose(3, "Control: Message requires %ld parameters, but only 2 supplied -- retrying request ...\n", uNumParms);
a299266cddc1ae14d76d725a660bb278816bc151vboxsync rc = VINF_SUCCESS;
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync }
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync else if (rc == VERR_TIMEOUT)
4a4d802b46dfabbfd36e88822ff7b17421120469vboxsync {
d0445e5c26b62718e727032ae46626f5d5db7ae5vboxsync VBoxServiceVerbose(3, "Control: Wait timed out, waiting for next round ...\n");
a299266cddc1ae14d76d725a660bb278816bc151vboxsync RTThreadSleep(100);
a299266cddc1ae14d76d725a660bb278816bc151vboxsync }
a8fd9edea57842da84a8bcf265a92eb5e96c9c4bvboxsync if (RT_SUCCESS(rc))
a299266cddc1ae14d76d725a660bb278816bc151vboxsync {
a299266cddc1ae14d76d725a660bb278816bc151vboxsync VBoxServiceVerbose(3, "Control: Msg=%u (%u parms) retrieved\n", uMsg, uNumParms);
a299266cddc1ae14d76d725a660bb278816bc151vboxsync switch(uMsg)
a299266cddc1ae14d76d725a660bb278816bc151vboxsync {
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync case GETHOSTMSG_EXEC_START_PROCESS:
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync rc = VBoxServiceControlHandleCmdStartProcess(g_GuestControlSvcClientID, uNumParms);
739c9e0e5fccb99475b8202ead8fc5665b2fa64cvboxsync break;
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync case GETHOSTMSG_EXEC_GET_OUTPUT:
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync rc = VBoxServiceControlHandleCmdGetOutput(g_GuestControlSvcClientID, uNumParms);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync break;
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync default:
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync VBoxServiceVerbose(3, "Control: Unsupported message from host! Msg=%u\n", uMsg);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync /* Don't terminate here; just wait for the next message. */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync break;
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync }
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync if (RT_FAILURE(rc))
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync VBoxServiceVerbose(3, "Control: Message was processed with rc=%Rrc\n", rc);
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync }
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync /*
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync * Block for a while.
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync *
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync * The event semaphore takes care of ignoring interruptions and it
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync * allows us to implement service wakeup later.
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync */
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync if (*pfShutdown)
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync {
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync rc = 0;
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync break;
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync }
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync int rc2 = RTSemEventMultiWait(g_hControlEvent, g_ControlInterval);
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync if (*pfShutdown)
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync {
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync rc = 0;
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync break;
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync }
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync if (rc2 != VERR_TIMEOUT && RT_FAILURE(rc2))
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync {
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync VBoxServiceError("Control: RTSemEventMultiWait failed; rc2=%Rrc\n", rc2);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync rc = rc2;
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync break;
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync }
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync }
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync RTSemEventMultiDestroy(g_hControlEvent);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync g_hControlEvent = NIL_RTSEMEVENTMULTI;
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync return rc;
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync}
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync/** @copydoc VBOXSERVICE::pfnStop */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsyncstatic DECLCALLBACK(void) VBoxServiceControlStop(void)
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync{
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. */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync RTSemEventMultiSignal(g_hControlEvent);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync}
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync/** @copydoc VBOXSERVICE::pfnTerm */
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsyncstatic DECLCALLBACK(void) VBoxServiceControlTerm(void)
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync{
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync /* Signal all threads that we want to shutdown. */
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync PVBOXSERVICECTRLTHREAD pNode;
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync RTListForEach(&g_GuestControlExecThreads, pNode, VBOXSERVICECTRLTHREAD, Node)
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync ASMAtomicXchgBool(&pNode->fShutdown, true);
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync /* Wait for threads to shutdown. */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync RTListForEach(&g_GuestControlExecThreads, pNode, VBOXSERVICECTRLTHREAD, Node)
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync {
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync if (pNode->Thread != NIL_RTTHREAD)
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync {
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync int rc2 = RTThreadWait(pNode->Thread, 30 * 1000 /* Wait 30 seconds max. */, NULL);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync if (RT_FAILURE(rc2))
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync VBoxServiceError("Control: Thread failed to stop; rc2=%Rrc\n", rc2);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync }
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync /* Destroy thread specific data. */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync switch (pNode->enmType)
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync {
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync case VBoxServiceCtrlThreadDataExec:
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync VBoxServiceControlExecDestroyThreadData((PVBOXSERVICECTRLTHREADDATAEXEC)pNode->pvData);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync break;
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync default:
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync break;
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync }
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync }
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync /* Finally destroy thread list. */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync pNode = RTListNodeGetFirst(&g_GuestControlExecThreads, VBOXSERVICECTRLTHREAD, Node);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync while (pNode)
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync {
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync PVBOXSERVICECTRLTHREAD pNext = RTListNodeGetNext(&pNode->Node, VBOXSERVICECTRLTHREAD, Node);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync RTListNodeRemove(&pNode->Node);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync RTMemFree(pNode);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync if (pNext && RTListNodeIsLast(&g_GuestControlExecThreads, &pNext->Node))
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync break;
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync pNode = pNext;
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync }
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync VbglR3GuestCtrlDisconnect(g_GuestControlSvcClientID);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync g_GuestControlSvcClientID = 0;
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync if (g_hControlEvent != NIL_RTSEMEVENTMULTI)
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync {
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync RTSemEventMultiDestroy(g_hControlEvent);
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync g_hControlEvent = NIL_RTSEMEVENTMULTI;
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync }
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync}
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync/**
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync * The 'vminfo' service description.
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsyncVBOXSERVICE g_Control =
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync{
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync /* pszName. */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync "control",
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync /* pszDescription. */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync "Host-driven Guest Control",
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync /* pszUsage. */
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync "[--control-interval <ms>]"
6578276195b5b6a53ef2fc44f96a3348c516d3f5vboxsync ,
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 ,
4bcaf5d320bf0d88910212509c37bdd634e0879evboxsync /* methods */
4bcaf5d320bf0d88910212509c37bdd634e0879evboxsync VBoxServiceControlPreInit,
4bcaf5d320bf0d88910212509c37bdd634e0879evboxsync VBoxServiceControlOption,
4bcaf5d320bf0d88910212509c37bdd634e0879evboxsync VBoxServiceControlInit,
cec3b04587a02f0dc7d0cc679e9a0de19b730e2cvboxsync VBoxServiceControlWorker,
cec3b04587a02f0dc7d0cc679e9a0de19b730e2cvboxsync VBoxServiceControlStop,
cec3b04587a02f0dc7d0cc679e9a0de19b730e2cvboxsync VBoxServiceControlTerm
cec3b04587a02f0dc7d0cc679e9a0de19b730e2cvboxsync};
cec3b04587a02f0dc7d0cc679e9a0de19b730e2cvboxsync
cec3b04587a02f0dc7d0cc679e9a0de19b730e2cvboxsync