VirtualBox

source: vbox/trunk/src/VBox/Main/GuestImpl.cpp@ 27842

Last change on this file since 27842 was 27822, checked in by vboxsync, 15 years ago

Removed guest statistics interface; to be merged with metrics.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.2 KB
Line 
1/* $Id: GuestImpl.cpp 27822 2010-03-30 13:01:36Z vboxsync $ */
2
3/** @file
4 *
5 * VirtualBox COM class implementation
6 */
7
8/*
9 * Copyright (C) 2006-2008 Sun Microsystems, Inc.
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
20 * Clara, CA 95054 USA or visit http://www.sun.com if you need
21 * additional information or have any questions.
22 */
23
24#include "GuestImpl.h"
25
26#include "Global.h"
27#include "ConsoleImpl.h"
28#include "VMMDev.h"
29
30#include "AutoCaller.h"
31#include "Logging.h"
32
33#include <VBox/VMMDev.h>
34#ifdef VBOX_WITH_GUEST_CONTROL
35# include <VBox/HostServices/GuestControlSvc.h>
36# include <VBox/com/array.h>
37#endif
38#include <iprt/cpp/utils.h>
39#include <iprt/getopt.h>
40
41// defines
42/////////////////////////////////////////////////////////////////////////////
43
44// constructor / destructor
45/////////////////////////////////////////////////////////////////////////////
46
47DEFINE_EMPTY_CTOR_DTOR (Guest)
48
49HRESULT Guest::FinalConstruct()
50{
51 return S_OK;
52}
53
54void Guest::FinalRelease()
55{
56 uninit ();
57}
58
59// public methods only for internal purposes
60/////////////////////////////////////////////////////////////////////////////
61
62/**
63 * Initializes the guest object.
64 */
65HRESULT Guest::init (Console *aParent)
66{
67 LogFlowThisFunc(("aParent=%p\n", aParent));
68
69 ComAssertRet(aParent, E_INVALIDARG);
70
71 /* Enclose the state transition NotReady->InInit->Ready */
72 AutoInitSpan autoInitSpan(this);
73 AssertReturn(autoInitSpan.isOk(), E_FAIL);
74
75 unconst(mParent) = aParent;
76
77 /* mData.mAdditionsActive is FALSE */
78
79 /* Confirm a successful initialization when it's the case */
80 autoInitSpan.setSucceeded();
81
82 ULONG aMemoryBalloonSize;
83 HRESULT ret = mParent->machine()->COMGETTER(MemoryBalloonSize)(&aMemoryBalloonSize);
84 if (ret == S_OK)
85 mMemoryBalloonSize = aMemoryBalloonSize;
86 else
87 mMemoryBalloonSize = 0; /* Default is no ballooning */
88
89 mStatUpdateInterval = 0; /* Default is not to report guest statistics at all */
90 return S_OK;
91}
92
93/**
94 * Uninitializes the instance and sets the ready flag to FALSE.
95 * Called either from FinalRelease() or by the parent when it gets destroyed.
96 */
97void Guest::uninit()
98{
99 LogFlowThisFunc(("\n"));
100
101 /* Enclose the state transition Ready->InUninit->NotReady */
102 AutoUninitSpan autoUninitSpan(this);
103 if (autoUninitSpan.uninitDone())
104 return;
105
106 unconst(mParent) = NULL;
107}
108
109// IGuest properties
110/////////////////////////////////////////////////////////////////////////////
111
112STDMETHODIMP Guest::COMGETTER(OSTypeId) (BSTR *aOSTypeId)
113{
114 CheckComArgOutPointerValid(aOSTypeId);
115
116 AutoCaller autoCaller(this);
117 if (FAILED(autoCaller.rc())) return autoCaller.rc();
118
119 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
120
121 // redirect the call to IMachine if no additions are installed
122 if (mData.mAdditionsVersion.isEmpty())
123 return mParent->machine()->COMGETTER(OSTypeId)(aOSTypeId);
124
125 mData.mOSTypeId.cloneTo(aOSTypeId);
126
127 return S_OK;
128}
129
130STDMETHODIMP Guest::COMGETTER(AdditionsActive) (BOOL *aAdditionsActive)
131{
132 CheckComArgOutPointerValid(aAdditionsActive);
133
134 AutoCaller autoCaller(this);
135 if (FAILED(autoCaller.rc())) return autoCaller.rc();
136
137 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
138
139 *aAdditionsActive = mData.mAdditionsActive;
140
141 return S_OK;
142}
143
144STDMETHODIMP Guest::COMGETTER(AdditionsVersion) (BSTR *aAdditionsVersion)
145{
146 CheckComArgOutPointerValid(aAdditionsVersion);
147
148 AutoCaller autoCaller(this);
149 if (FAILED(autoCaller.rc())) return autoCaller.rc();
150
151 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
152
153 mData.mAdditionsVersion.cloneTo(aAdditionsVersion);
154
155 return S_OK;
156}
157
158STDMETHODIMP Guest::COMGETTER(SupportsSeamless) (BOOL *aSupportsSeamless)
159{
160 CheckComArgOutPointerValid(aSupportsSeamless);
161
162 AutoCaller autoCaller(this);
163 if (FAILED(autoCaller.rc())) return autoCaller.rc();
164
165 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
166
167 *aSupportsSeamless = mData.mSupportsSeamless;
168
169 return S_OK;
170}
171
172STDMETHODIMP Guest::COMGETTER(SupportsGraphics) (BOOL *aSupportsGraphics)
173{
174 CheckComArgOutPointerValid(aSupportsGraphics);
175
176 AutoCaller autoCaller(this);
177 if (FAILED(autoCaller.rc())) return autoCaller.rc();
178
179 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
180
181 *aSupportsGraphics = mData.mSupportsGraphics;
182
183 return S_OK;
184}
185
186STDMETHODIMP Guest::COMGETTER(MemoryBalloonSize) (ULONG *aMemoryBalloonSize)
187{
188 CheckComArgOutPointerValid(aMemoryBalloonSize);
189
190 AutoCaller autoCaller(this);
191 if (FAILED(autoCaller.rc())) return autoCaller.rc();
192
193 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
194
195 *aMemoryBalloonSize = mMemoryBalloonSize;
196
197 return S_OK;
198}
199
200STDMETHODIMP Guest::COMSETTER(MemoryBalloonSize) (ULONG aMemoryBalloonSize)
201{
202 AutoCaller autoCaller(this);
203 if (FAILED(autoCaller.rc())) return autoCaller.rc();
204
205 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
206
207 HRESULT ret = mParent->machine()->COMSETTER(MemoryBalloonSize)(aMemoryBalloonSize);
208 if (ret == S_OK)
209 {
210 mMemoryBalloonSize = aMemoryBalloonSize;
211 /* forward the information to the VMM device */
212 VMMDev *vmmDev = mParent->getVMMDev();
213 if (vmmDev)
214 vmmDev->getVMMDevPort()->pfnSetMemoryBalloon(vmmDev->getVMMDevPort(), aMemoryBalloonSize);
215 }
216
217 return ret;
218}
219
220HRESULT Guest::GetStatisticsUpdateInterval (ULONG *aUpdateInterval)
221{
222 CheckComArgOutPointerValid(aUpdateInterval);
223
224 AutoCaller autoCaller(this);
225 if (FAILED(autoCaller.rc())) return autoCaller.rc();
226
227 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
228
229 *aUpdateInterval = mStatUpdateInterval;
230
231 return S_OK;
232}
233
234HRESULT Guest::SetStatisticsUpdateInterval (ULONG aUpdateInterval)
235{
236 AutoCaller autoCaller(this);
237 if (FAILED(autoCaller.rc())) return autoCaller.rc();
238
239 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
240
241 mStatUpdateInterval = aUpdateInterval;
242 /* forward the information to the VMM device */
243 VMMDev *vmmDev = mParent->getVMMDev();
244 if (vmmDev)
245 vmmDev->getVMMDevPort()->pfnSetStatisticsInterval(vmmDev->getVMMDevPort(), aUpdateInterval);
246
247 return S_OK;
248}
249
250STDMETHODIMP Guest::SetCredentials(IN_BSTR aUserName, IN_BSTR aPassword,
251 IN_BSTR aDomain, BOOL aAllowInteractiveLogon)
252{
253 AutoCaller autoCaller(this);
254 if (FAILED(autoCaller.rc())) return autoCaller.rc();
255
256 /* forward the information to the VMM device */
257 VMMDev *vmmDev = mParent->getVMMDev();
258 if (vmmDev)
259 {
260 uint32_t u32Flags = VMMDEV_SETCREDENTIALS_GUESTLOGON;
261 if (!aAllowInteractiveLogon)
262 u32Flags = VMMDEV_SETCREDENTIALS_NOLOCALLOGON;
263
264 vmmDev->getVMMDevPort()->pfnSetCredentials(vmmDev->getVMMDevPort(),
265 Utf8Str(aUserName).raw(), Utf8Str(aPassword).raw(),
266 Utf8Str(aDomain).raw(), u32Flags);
267 return S_OK;
268 }
269
270 return setError(VBOX_E_VM_ERROR,
271 tr("VMM device is not available (is the VM running?)"));
272}
273
274#ifdef VBOX_WITH_GUEST_CONTROL
275/**
276 * Creates the argument list as an array used for executing a program.
277 *
278 * @returns VBox status code.
279 *
280 * @todo
281 *
282 * @todo Respect spaces when quoting for arguments, e.g. "c:\\program files\\".
283 * @todo Handle empty ("") argguments.
284 */
285int Guest::prepareExecuteArgs(const char *pszArgs, void **ppvList, uint32_t *pcbList, uint32_t *pcArgs)
286{
287 char **ppaArg;
288 int iArgs;
289 int rc = RTGetOptArgvFromString(&ppaArg, &iArgs, pszArgs, NULL);
290 if (RT_SUCCESS(rc))
291 {
292 char *pszTemp = NULL;
293 *pcbList = 0;
294 for (int i=0; i<iArgs; i++)
295 {
296 if (i > 0) /* Insert space as delimiter. */
297 rc = RTStrAAppendN(&pszTemp, " ", 1);
298
299 if (RT_FAILURE(rc))
300 break;
301 else
302 {
303 rc = RTStrAAppendN(&pszTemp, ppaArg[i], strlen(ppaArg[i]));
304 if (RT_FAILURE(rc))
305 break;
306 }
307 }
308 RTGetOptArgvFree(ppaArg);
309 if (RT_SUCCESS(rc))
310 {
311 *ppvList = pszTemp;
312 *pcArgs = iArgs;
313 if (pszTemp)
314 *pcbList = strlen(pszTemp) + 1; /* Include zero termination. */
315 }
316 else
317 RTStrFree(pszTemp);
318 }
319 return rc;
320}
321
322/**
323 * Appends environment variables to the environment block. Each var=value pair is separated
324 * by NULL (\0) sequence. The whole block will be stored in one blob and disassembled on the
325 * guest side later to fit into the HGCM param structure.
326 *
327 * @returns VBox status code.
328 *
329 * @todo
330 *
331 */
332int Guest::prepareExecuteEnv(const char *pszEnv, void **ppvList, uint32_t *pcbList, uint32_t *pcEnv)
333{
334 int rc = VINF_SUCCESS;
335 uint32_t cbLen = strlen(pszEnv);
336 if (*ppvList)
337 {
338 uint32_t cbNewLen = *pcbList + cbLen + 1; /* Include zero termination. */
339 char *pvTmp = (char*)RTMemRealloc(*ppvList, cbNewLen);
340 if (NULL == pvTmp)
341 {
342 rc = VERR_NO_MEMORY;
343 }
344 else
345 {
346 memcpy(pvTmp + *pcbList, pszEnv, cbLen);
347 pvTmp[cbNewLen - 1] = '\0'; /* Add zero termination. */
348 *ppvList = (void**)pvTmp;
349 }
350 }
351 else
352 {
353 char *pcTmp;
354 if (RTStrAPrintf(&pcTmp, "%s", pszEnv) > 0)
355 {
356 *ppvList = (void**)pcTmp;
357 /* Reset counters. */
358 *pcEnv = 0;
359 *pcbList = 0;
360 }
361 }
362 if (RT_SUCCESS(rc))
363 {
364 *pcbList += cbLen + 1; /* Include zero termination. */
365 *pcEnv += 1; /* Increase env pairs count. */
366 }
367 return rc;
368}
369#endif /* VBOX_WITH_GUEST_CONTROL */
370
371STDMETHODIMP Guest::ExecuteProgram(IN_BSTR aCommand, ULONG aFlags,
372 IN_BSTR aArguments, ComSafeArrayIn(IN_BSTR, aEnvironment),
373 IN_BSTR aStdIn, IN_BSTR aStdOut, IN_BSTR aStdErr,
374 IN_BSTR aUserName, IN_BSTR aPassword,
375 ULONG aTimeoutMS, ULONG *aPID)
376{
377#ifndef VBOX_WITH_GUEST_CONTROL
378 ReturnComNotImplemented();
379#else /* VBOX_WITH_GUEST_CONTROL */
380 using namespace guestControl;
381
382 CheckComArgStrNotEmptyOrNull(aCommand);
383 CheckComArgOutPointerValid(aPID);
384 /* Flags are not supported at the moment. */
385 if (aFlags != 0)
386 return E_INVALIDARG;
387
388 HRESULT rc = S_OK;
389
390 try
391 {
392 AutoCaller autoCaller(this);
393 if (FAILED(autoCaller.rc())) return autoCaller.rc();
394
395 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
396
397 /* Just be on the safe side when calling another process. */
398 alock.leave();
399
400 HRESULT rc = E_UNEXPECTED;
401 using namespace guestControl;
402
403 int vrc = VINF_SUCCESS;
404 Utf8Str Utf8Command(aCommand);
405
406 /* Prepare arguments. */
407 void *pvArgs;
408 uint32_t uNumArgs;
409 uint32_t cbArgs;
410
411 const char *pszCurArg = Utf8Str(aArguments).raw();
412 vrc = prepareExecuteArgs(pszCurArg,
413 &pvArgs, &cbArgs, &uNumArgs);
414 if (RT_SUCCESS(vrc))
415 {
416 /* Prepare environment. */
417 com::SafeArray<IN_BSTR> env(ComSafeArrayInArg(aEnvironment));
418
419 void *pvEnv = NULL;
420 uint32_t uNumEnv = env.size();
421 uint32_t cbEnv = 0;
422
423 for (unsigned i = 0; i < uNumEnv; i++)
424 {
425 const char *pszCurEnv = Utf8Str(env[i]).raw();
426 vrc = prepareExecuteEnv(pszCurEnv, &pvEnv, &cbEnv, &uNumEnv);
427 if (RT_FAILURE(vrc))
428 break;
429 }
430
431 if (RT_SUCCESS(vrc))
432 {
433 Utf8Str Utf8StdIn(aStdIn);
434 Utf8Str Utf8StdOut(aStdOut);
435 Utf8Str Utf8StdErr(aStdErr);
436 Utf8Str Utf8UserName(aUserName);
437 Utf8Str Utf8Password(aPassword);
438
439 VBOXHGCMSVCPARM paParms[13];
440 paParms[0].setUInt32(HOST_EXEC_CMD);
441 paParms[1].setUInt32(aFlags);
442 paParms[2].setPointer((void*)Utf8Command.raw(), (uint32_t)strlen(Utf8Command.raw()) + 1);
443 paParms[3].setUInt32(uNumArgs);
444 paParms[4].setPointer((void*)pvArgs, cbArgs);
445 paParms[5].setUInt32(uNumEnv);
446 paParms[6].setPointer((void*)pvEnv, cbEnv);
447 paParms[7].setPointer((void*)Utf8StdIn.raw(), (uint32_t)strlen(Utf8StdIn.raw()) + 1);
448 paParms[8].setPointer((void*)Utf8StdOut.raw(), (uint32_t)strlen(Utf8StdOut.raw()) + 1);
449 paParms[9].setPointer((void*)Utf8StdErr.raw(), (uint32_t)strlen(Utf8StdErr.raw()) + 1);
450 paParms[10].setPointer((void*)Utf8UserName.raw(), (uint32_t)strlen(Utf8UserName.raw()) + 1);
451 paParms[11].setPointer((void*)Utf8Password.raw(), (uint32_t)strlen(Utf8Password.raw()) + 1);
452 paParms[12].setUInt32(aTimeoutMS);
453
454 /* Forward the information to the VMM device. */
455 AssertPtr(mParent);
456 VMMDev *vmmDev = mParent->getVMMDev();
457 if (vmmDev)
458 {
459 vrc = vmmDev->hgcmHostCall("VBoxGuestControlSvc", HOST_EXEC_CMD,
460 13, paParms);
461 /** @todo Get the PID. */
462 }
463 RTMemFree(pvEnv);
464 }
465 RTMemFree(pvArgs);
466 }
467 if (RT_SUCCESS(vrc))
468 rc = S_OK;
469 else
470 rc = setError(E_UNEXPECTED,
471 tr("The service call failed with the error %Rrc"),
472 vrc);
473 }
474 catch (std::bad_alloc &)
475 {
476 rc = E_OUTOFMEMORY;
477 };
478
479 return rc;
480#endif /* VBOX_WITH_GUEST_CONTROL */
481}
482
483// public methods only for internal purposes
484/////////////////////////////////////////////////////////////////////////////
485
486void Guest::setAdditionsVersion(Bstr aVersion, VBOXOSTYPE aOsType)
487{
488 AutoCaller autoCaller(this);
489 AssertComRCReturnVoid (autoCaller.rc());
490
491 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
492
493 mData.mAdditionsVersion = aVersion;
494 mData.mAdditionsActive = !aVersion.isEmpty();
495 /* Older Additions didn't have this finer grained capability bit,
496 * so enable it by default. Newer Additions will disable it immediately
497 * if relevant. */
498 mData.mSupportsGraphics = mData.mAdditionsActive;
499
500 mData.mOSTypeId = Global::OSTypeId (aOsType);
501}
502
503void Guest::setSupportsSeamless (BOOL aSupportsSeamless)
504{
505 AutoCaller autoCaller(this);
506 AssertComRCReturnVoid (autoCaller.rc());
507
508 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
509
510 mData.mSupportsSeamless = aSupportsSeamless;
511}
512
513void Guest::setSupportsGraphics (BOOL aSupportsGraphics)
514{
515 AutoCaller autoCaller(this);
516 AssertComRCReturnVoid (autoCaller.rc());
517
518 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
519
520 mData.mSupportsGraphics = aSupportsGraphics;
521}
522/* vi: set tabstop=4 shiftwidth=4 expandtab: */
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