VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxBalloonCtrl/VBoxModAPIMonitor.cpp@ 40012

Last change on this file since 40012 was 40011, checked in by vboxsync, 13 years ago

Build fix.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.1 KB
Line 
1
2/* $Id: VBoxModAPIMonitor.cpp 40011 2012-02-06 22:26:52Z vboxsync $ */
3/** @file
4 * VBoxModAPIMonitor - API monitor module for detecting host isolation.
5 */
6
7/*
8 * Copyright (C) 2012 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19
20/*******************************************************************************
21* Header Files *
22*******************************************************************************/
23#ifndef VBOX_ONLY_DOCS
24# include <VBox/com/errorprint.h>
25#endif /* !VBOX_ONLY_DOCS */
26
27#include "VBoxWatchdogInternal.h"
28
29using namespace com;
30
31#define VBOX_MOD_APIMON_NAME "apimon"
32
33/**
34 * The module's RTGetOpt-IDs for the command line.
35 */
36enum GETOPTDEF_APIMON
37{
38 GETOPTDEF_APIMON_ISLN_RESPONSE = 3000,
39 GETOPTDEF_APIMON_ISLN_TIMEOUT,
40 GETOPTDEF_APIMON_GROUPS
41};
42
43/**
44 * The module's command line arguments.
45 */
46static const RTGETOPTDEF g_aAPIMonitorOpts[] = {
47 { "--apimon-isln-response", GETOPTDEF_APIMON_ISLN_RESPONSE, RTGETOPT_REQ_STRING },
48 { "--apimon-isln-timeout", GETOPTDEF_APIMON_ISLN_TIMEOUT, RTGETOPT_REQ_UINT32 },
49 { "--apimon-groups", GETOPTDEF_APIMON_GROUPS, RTGETOPT_REQ_STRING }
50};
51
52static enum APIMON_RESPONSE
53{
54 /** Unknown / unhandled response. */
55 APIMON_RESPONSE_UNKNOWN = 0,
56 /** Tries to shut down all running VMs in
57 * a gentle manner. */
58 APIMON_RESPONSE_SHUTDOWN = 200
59};
60
61static Bstr g_strAPIMonGroups;
62
63static APIMON_RESPONSE g_enmAPIMonIslnResp = APIMON_RESPONSE_UNKNOWN;
64static unsigned long g_ulAPIMonIslnTimeoutMS = 0;
65static Bstr g_strAPIMonIslnLastBeat;
66static uint64_t g_uAPIMonIslnLastBeatMS = 0;
67
68int apimonResponseToEnum(const char *pszResponse, APIMON_RESPONSE *pResp)
69{
70 AssertPtrReturn(pszResponse, VERR_INVALID_POINTER);
71 AssertPtrReturn(pResp, VERR_INVALID_POINTER);
72
73 int rc = VINF_SUCCESS;
74 if ( !RTStrICmp(pszResponse, "shutdown")
75 || !RTStrICmp(pszResponse, "poweroff"))
76 {
77 *pResp = APIMON_RESPONSE_SHUTDOWN;
78 }
79 else
80 *pResp = APIMON_RESPONSE_UNKNOWN;
81
82 return (*pResp > APIMON_RESPONSE_UNKNOWN ? VINF_SUCCESS : VERR_INVALID_PARAMETER);
83}
84
85int apimonMachineControl(const Bstr &strUuid, PVBOXWATCHDOG_MACHINE pMachine,
86 APIMON_RESPONSE enmResp)
87{
88 /** @todo Add other commands (with enmResp) here. */
89 AssertPtrReturn(pMachine, VERR_INVALID_PARAMETER);
90
91 serviceLog("Shutting down machine \"%ls\"\n", strUuid.raw());
92
93 /* Open a session for the VM. */
94 HRESULT rc;
95 CHECK_ERROR_RET(pMachine->machine, LockMachine(g_pSession, LockType_Shared), VERR_ACCESS_DENIED);
96 do
97 {
98 /* get the associated console */
99 ComPtr<IConsole> console;
100 CHECK_ERROR_BREAK(g_pSession, COMGETTER(Console)(console.asOutParam()));
101
102 if (!g_fDryrun)
103 {
104 ComPtr<IProgress> progress;
105 CHECK_ERROR_BREAK(console, PowerDown(progress.asOutParam()));
106 if (g_fVerbose)
107 {
108 serviceLogVerbose(("Waiting for shutting down machine \"%ls\" ...\n",
109 strUuid.raw()));
110 progress->WaitForCompletion(-1);
111 }
112 }
113 } while (0);
114
115 /* Unlock the machine again. */
116 g_pSession->UnlockMachine();
117
118 return SUCCEEDED(rc) ? VINF_SUCCESS : VERR_COM_IPRT_ERROR;
119}
120
121int apimonTrigger(APIMON_RESPONSE enmResp)
122{
123 int rc = VINF_SUCCESS;
124
125 /** @todo Add proper grouping support! */
126 bool fAllGroups = g_strAPIMonGroups.isEmpty();
127 mapVMIter it = g_mapVM.begin();
128 while (it != g_mapVM.end())
129 {
130 if ( !it->second.group.compare(g_strAPIMonGroups, Bstr::CaseInsensitive)
131 || fAllGroups)
132 {
133 rc = apimonMachineControl(it->first /* Uuid */,
134 &it->second, enmResp);
135 }
136 it++;
137 }
138
139 return rc;
140}
141
142/* Callbacks. */
143static DECLCALLBACK(int) VBoxModAPIMonitorPreInit(void)
144{
145 return VINF_SUCCESS;
146}
147
148static DECLCALLBACK(int) VBoxModAPIMonitorOption(int argc, char **argv)
149{
150 if (!argc) /* Take a shortcut. */
151 return -1;
152
153 AssertPtrReturn(argv, VERR_INVALID_PARAMETER);
154
155 RTGETOPTSTATE GetState;
156 int rc = RTGetOptInit(&GetState, argc, argv,
157 g_aAPIMonitorOpts, RT_ELEMENTS(g_aAPIMonitorOpts),
158 0 /* First */, 0 /*fFlags*/);
159 if (RT_FAILURE(rc))
160 return rc;
161
162 rc = 0; /* Set default parsing result to valid. */
163
164 int c;
165 RTGETOPTUNION ValueUnion;
166 while ((c = RTGetOpt(&GetState, &ValueUnion)))
167 {
168 switch (c)
169 {
170 case GETOPTDEF_APIMON_ISLN_RESPONSE:
171 rc = apimonResponseToEnum(ValueUnion.psz, &g_enmAPIMonIslnResp);
172 if (RT_FAILURE(rc))
173 rc = -1; /* Option unknown. */
174 break;
175
176 case GETOPTDEF_APIMON_ISLN_TIMEOUT:
177 g_ulAPIMonIslnTimeoutMS = ValueUnion.u32;
178 if (g_ulAPIMonIslnTimeoutMS < 1000)
179 g_ulAPIMonIslnTimeoutMS = 1000;
180 break;
181
182 case GETOPTDEF_APIMON_GROUPS:
183 g_strAPIMonGroups = ValueUnion.psz;
184 break;
185
186 default:
187 rc = -1; /* We don't handle this option, skip. */
188 break;
189 }
190 }
191
192 return rc;
193}
194
195static DECLCALLBACK(int) VBoxModAPIMonitorInit(void)
196{
197 HRESULT rc = S_OK;
198
199 do
200 {
201 Bstr strValue;
202
203 /* Host isolation timeout (in ms). */
204 if (!g_ulAPIMonIslnTimeoutMS) /* Not set by command line? */
205 {
206 CHECK_ERROR_BREAK(g_pVirtualBox, GetExtraData(Bstr("Watchdog/APIMonitor/IsolationTimeout").raw(),
207 strValue.asOutParam()));
208 if (!strValue.isEmpty())
209 g_ulAPIMonIslnTimeoutMS = Utf8Str(strValue).toUInt32();
210 }
211 if (!g_ulAPIMonIslnTimeoutMS) /* Still not set? Use a default. */
212 {
213 serviceLogVerbose(("API monitor isolation timeout not given, defaulting to 30s\n"));
214
215 /* Default is 30 seconds timeout. */
216 g_ulAPIMonIslnTimeoutMS = 30 * 1000;
217 }
218
219 /* VM groups to watch for. */
220 if (g_strAPIMonGroups.isEmpty()) /* Not set by command line? */
221 {
222 CHECK_ERROR_BREAK(g_pVirtualBox, GetExtraData(Bstr("Watchdog/APIMonitor/Groups").raw(),
223 g_strAPIMonGroups.asOutParam()));
224 }
225
226 /* Host isolation command response. */
227 if (g_enmAPIMonIslnResp == APIMON_RESPONSE_UNKNOWN) /* Not set by command line? */
228 {
229 CHECK_ERROR_BREAK(g_pVirtualBox, GetExtraData(Bstr("Watchdog/APIMonitor/IsolationResponse").raw(),
230 strValue.asOutParam()));
231 if (!strValue.isEmpty())
232 {
233 int rc2 = apimonResponseToEnum(Utf8Str(strValue).c_str(), &g_enmAPIMonIslnResp);
234 if (RT_FAILURE(rc2))
235 {
236 serviceLog("Warning: API monitor response string invalid (%ls), default to shutdown\n",
237 strValue.raw());
238 g_enmAPIMonIslnResp = APIMON_RESPONSE_SHUTDOWN;
239 }
240 }
241 else
242 g_enmAPIMonIslnResp = APIMON_RESPONSE_SHUTDOWN;
243 }
244 } while (0);
245
246 if (SUCCEEDED(rc))
247 {
248 g_uAPIMonIslnLastBeatMS = 0;
249 }
250
251 return SUCCEEDED(rc) ? VINF_SUCCESS : VERR_COM_IPRT_ERROR; /* @todo Find a better rc! */
252}
253
254static DECLCALLBACK(int) VBoxModAPIMonitorMain(void)
255{
256 static uint64_t uLastRun = 0;
257 uint64_t uNow = RTTimeProgramMilliTS();
258 uint64_t uDelta = uNow - uLastRun;
259 if (uDelta < 1000)
260 return VINF_SUCCESS;
261 uLastRun = uNow;
262
263 int vrc = VINF_SUCCESS;
264 HRESULT rc;
265
266 serviceLogVerbose(("Checking for API heartbeat (%RU64ms) ...\n",
267 g_ulAPIMonIslnTimeoutMS));
268
269 do
270 {
271 Bstr strHeartbeat;
272 CHECK_ERROR_BREAK(g_pVirtualBox, GetExtraData(Bstr("Watchdog/APIMonitor/Heartbeat").raw(),
273 strHeartbeat.asOutParam()));
274 if ( SUCCEEDED(rc)
275 && !strHeartbeat.isEmpty()
276 && g_strAPIMonIslnLastBeat.compare(strHeartbeat, Bstr::CaseSensitive))
277 {
278 serviceLogVerbose(("API heartbeat received, resetting timeout\n"));
279
280 g_uAPIMonIslnLastBeatMS = 0;
281 g_strAPIMonIslnLastBeat = strHeartbeat;
282 }
283 else
284 {
285 g_uAPIMonIslnLastBeatMS += uDelta;
286 if (g_uAPIMonIslnLastBeatMS > g_ulAPIMonIslnTimeoutMS)
287 {
288 serviceLogVerbose(("No API heartbeat within time received (%RU64ms)\n",
289 g_ulAPIMonIslnTimeoutMS));
290
291 vrc = apimonTrigger(g_enmAPIMonIslnResp);
292 g_uAPIMonIslnLastBeatMS = 0;
293 }
294 }
295 } while (0);
296
297 if (FAILED(rc))
298 vrc = VERR_COM_IPRT_ERROR;
299
300 return vrc;
301}
302
303static DECLCALLBACK(int) VBoxModAPIMonitorStop(void)
304{
305 return VINF_SUCCESS;
306}
307
308static DECLCALLBACK(void) VBoxModAPIMonitorTerm(void)
309{
310}
311
312static DECLCALLBACK(int) VBoxModAPIMonitorOnMachineRegistered(const Bstr &strUuid)
313{
314 return VINF_SUCCESS;
315}
316
317static DECLCALLBACK(int) VBoxModAPIMonitorOnMachineUnregistered(const Bstr &strUuid)
318{
319 return VINF_SUCCESS;
320}
321
322static DECLCALLBACK(int) VBoxModAPIMonitorOnMachineStateChanged(const Bstr &strUuid,
323 MachineState_T enmState)
324{
325 return VINF_SUCCESS;
326}
327
328static DECLCALLBACK(int) VBoxModAPIMonitorOnServiceStateChanged(bool fAvailable)
329{
330 if (!fAvailable)
331 apimonTrigger(g_enmAPIMonIslnResp);
332 return VINF_SUCCESS;
333}
334
335/**
336 * The 'apimonitor' module description.
337 */
338VBOXMODULE g_ModAPIMonitor =
339{
340 /* pszName. */
341 VBOX_MOD_APIMON_NAME,
342 /* pszDescription. */
343 "API monitor for host isolation detection",
344 /* pszDepends. */
345 NULL,
346 /* uPriority. */
347 0 /* Not used */,
348 /* pszUsage. */
349 " [--apimon-isln-response=<cmd>] [--apimon-isln-timeout=<ms>]\n"
350 " [--apimon-groups=<string>]\n",
351 /* pszOptions. */
352 "--apimon-isln-response Sets the isolation response (shutdown VM).\n"
353 "--apimon-isln-timeout Sets the isolation timeout in ms (30s).\n"
354 "--apimon-groups Sets the VM groups for monitoring (none).\n",
355 /* methods. */
356 VBoxModAPIMonitorPreInit,
357 VBoxModAPIMonitorOption,
358 VBoxModAPIMonitorInit,
359 VBoxModAPIMonitorMain,
360 VBoxModAPIMonitorStop,
361 VBoxModAPIMonitorTerm,
362 /* callbacks. */
363 VBoxModAPIMonitorOnMachineRegistered,
364 VBoxModAPIMonitorOnMachineUnregistered,
365 VBoxModAPIMonitorOnMachineStateChanged,
366 VBoxModAPIMonitorOnServiceStateChanged
367};
368
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette