VirtualBox

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

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

Guest Control: Update (Main, registering host service, bugfixes).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.7 KB
Line 
1/* $Id: GuestImpl.cpp 27788 2010-03-29 12:42:22Z 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 ULONG aStatUpdateInterval;
90 ret = mParent->machine()->COMGETTER(StatisticsUpdateInterval)(&aStatUpdateInterval);
91 if (ret == S_OK)
92 mStatUpdateInterval = aStatUpdateInterval;
93 else
94 mStatUpdateInterval = 0; /* Default is not to report guest statistics at all */
95
96 /* invalidate all stats */
97 for (int i=0;i<GuestStatisticType_MaxVal;i++)
98 mCurrentGuestStat[i] = GUEST_STAT_INVALID;
99
100 /* start with sample 0 */
101 mCurrentGuestStat[GuestStatisticType_SampleNumber] = 0;
102 return S_OK;
103}
104
105/**
106 * Uninitializes the instance and sets the ready flag to FALSE.
107 * Called either from FinalRelease() or by the parent when it gets destroyed.
108 */
109void Guest::uninit()
110{
111 LogFlowThisFunc(("\n"));
112
113 /* Enclose the state transition Ready->InUninit->NotReady */
114 AutoUninitSpan autoUninitSpan(this);
115 if (autoUninitSpan.uninitDone())
116 return;
117
118 unconst(mParent) = NULL;
119}
120
121// IGuest properties
122/////////////////////////////////////////////////////////////////////////////
123
124STDMETHODIMP Guest::COMGETTER(OSTypeId) (BSTR *aOSTypeId)
125{
126 CheckComArgOutPointerValid(aOSTypeId);
127
128 AutoCaller autoCaller(this);
129 if (FAILED(autoCaller.rc())) return autoCaller.rc();
130
131 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
132
133 // redirect the call to IMachine if no additions are installed
134 if (mData.mAdditionsVersion.isEmpty())
135 return mParent->machine()->COMGETTER(OSTypeId)(aOSTypeId);
136
137 mData.mOSTypeId.cloneTo(aOSTypeId);
138
139 return S_OK;
140}
141
142STDMETHODIMP Guest::COMGETTER(AdditionsActive) (BOOL *aAdditionsActive)
143{
144 CheckComArgOutPointerValid(aAdditionsActive);
145
146 AutoCaller autoCaller(this);
147 if (FAILED(autoCaller.rc())) return autoCaller.rc();
148
149 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
150
151 *aAdditionsActive = mData.mAdditionsActive;
152
153 return S_OK;
154}
155
156STDMETHODIMP Guest::COMGETTER(AdditionsVersion) (BSTR *aAdditionsVersion)
157{
158 CheckComArgOutPointerValid(aAdditionsVersion);
159
160 AutoCaller autoCaller(this);
161 if (FAILED(autoCaller.rc())) return autoCaller.rc();
162
163 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
164
165 mData.mAdditionsVersion.cloneTo(aAdditionsVersion);
166
167 return S_OK;
168}
169
170STDMETHODIMP Guest::COMGETTER(SupportsSeamless) (BOOL *aSupportsSeamless)
171{
172 CheckComArgOutPointerValid(aSupportsSeamless);
173
174 AutoCaller autoCaller(this);
175 if (FAILED(autoCaller.rc())) return autoCaller.rc();
176
177 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
178
179 *aSupportsSeamless = mData.mSupportsSeamless;
180
181 return S_OK;
182}
183
184STDMETHODIMP Guest::COMGETTER(SupportsGraphics) (BOOL *aSupportsGraphics)
185{
186 CheckComArgOutPointerValid(aSupportsGraphics);
187
188 AutoCaller autoCaller(this);
189 if (FAILED(autoCaller.rc())) return autoCaller.rc();
190
191 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
192
193 *aSupportsGraphics = mData.mSupportsGraphics;
194
195 return S_OK;
196}
197
198STDMETHODIMP Guest::COMGETTER(MemoryBalloonSize) (ULONG *aMemoryBalloonSize)
199{
200 CheckComArgOutPointerValid(aMemoryBalloonSize);
201
202 AutoCaller autoCaller(this);
203 if (FAILED(autoCaller.rc())) return autoCaller.rc();
204
205 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
206
207 *aMemoryBalloonSize = mMemoryBalloonSize;
208
209 return S_OK;
210}
211
212STDMETHODIMP Guest::COMSETTER(MemoryBalloonSize) (ULONG aMemoryBalloonSize)
213{
214 AutoCaller autoCaller(this);
215 if (FAILED(autoCaller.rc())) return autoCaller.rc();
216
217 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
218
219 HRESULT ret = mParent->machine()->COMSETTER(MemoryBalloonSize)(aMemoryBalloonSize);
220 if (ret == S_OK)
221 {
222 mMemoryBalloonSize = aMemoryBalloonSize;
223 /* forward the information to the VMM device */
224 VMMDev *vmmDev = mParent->getVMMDev();
225 if (vmmDev)
226 vmmDev->getVMMDevPort()->pfnSetMemoryBalloon(vmmDev->getVMMDevPort(), aMemoryBalloonSize);
227 }
228
229 return ret;
230}
231
232STDMETHODIMP Guest::COMGETTER(StatisticsUpdateInterval) (ULONG *aUpdateInterval)
233{
234 CheckComArgOutPointerValid(aUpdateInterval);
235
236 AutoCaller autoCaller(this);
237 if (FAILED(autoCaller.rc())) return autoCaller.rc();
238
239 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
240
241 *aUpdateInterval = mStatUpdateInterval;
242
243 return S_OK;
244}
245
246STDMETHODIMP Guest::COMSETTER(StatisticsUpdateInterval) (ULONG aUpdateInterval)
247{
248 AutoCaller autoCaller(this);
249 if (FAILED(autoCaller.rc())) return autoCaller.rc();
250
251 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
252
253 HRESULT ret = mParent->machine()->COMSETTER(StatisticsUpdateInterval)(aUpdateInterval);
254 if (ret == S_OK)
255 {
256 mStatUpdateInterval = aUpdateInterval;
257 /* forward the information to the VMM device */
258 VMMDev *vmmDev = mParent->getVMMDev();
259 if (vmmDev)
260 vmmDev->getVMMDevPort()->pfnSetStatisticsInterval(vmmDev->getVMMDevPort(), aUpdateInterval);
261 }
262
263 return ret;
264}
265
266STDMETHODIMP Guest::SetCredentials(IN_BSTR aUserName, IN_BSTR aPassword,
267 IN_BSTR aDomain, BOOL aAllowInteractiveLogon)
268{
269 AutoCaller autoCaller(this);
270 if (FAILED(autoCaller.rc())) return autoCaller.rc();
271
272 /* forward the information to the VMM device */
273 VMMDev *vmmDev = mParent->getVMMDev();
274 if (vmmDev)
275 {
276 uint32_t u32Flags = VMMDEV_SETCREDENTIALS_GUESTLOGON;
277 if (!aAllowInteractiveLogon)
278 u32Flags = VMMDEV_SETCREDENTIALS_NOLOCALLOGON;
279
280 vmmDev->getVMMDevPort()->pfnSetCredentials(vmmDev->getVMMDevPort(),
281 Utf8Str(aUserName).raw(), Utf8Str(aPassword).raw(),
282 Utf8Str(aDomain).raw(), u32Flags);
283 return S_OK;
284 }
285
286 return setError(VBOX_E_VM_ERROR,
287 tr("VMM device is not available (is the VM running?)"));
288}
289
290STDMETHODIMP Guest::GetStatistic(ULONG aCpuId, GuestStatisticType_T aStatistic, ULONG *aStatVal)
291{
292 CheckComArgExpr(aCpuId, aCpuId == 0);
293 CheckComArgExpr(aStatistic, aStatistic < GuestStatisticType_MaxVal);
294 CheckComArgOutPointerValid(aStatVal);
295
296 /* Not available or not yet reported? In that case, just return with a proper error
297 * but don't use setError(). */
298 if (mCurrentGuestStat[aStatistic] == GUEST_STAT_INVALID)
299 return E_INVALIDARG;
300
301 *aStatVal = mCurrentGuestStat[aStatistic];
302 return S_OK;
303}
304
305STDMETHODIMP Guest::SetStatistic(ULONG aCpuId, GuestStatisticType_T aStatistic, ULONG aStatVal)
306{
307 CheckComArgExpr(aCpuId, aCpuId == 0);
308 CheckComArgExpr(aStatistic, aStatistic < GuestStatisticType_MaxVal);
309
310 /* internal method assumes that the caller knows what he's doing (no boundary checks) */
311 mCurrentGuestStat[aStatistic] = aStatVal;
312 return S_OK;
313}
314
315#ifdef VBOX_WITH_GUEST_CONTROL
316/**
317 * Creates the argument list as an array used for executing a program.
318 *
319 * @returns VBox status code.
320 *
321 * @todo
322 *
323 * @todo Respect spaces when quoting for arguments, e.g. "c:\\program files\\".
324 * @todo Handle empty ("") argguments.
325 */
326int Guest::prepareExecuteArgs(const char *pszArgs, void **ppvList, uint32_t *pcbList, uint32_t *pcArgs)
327{
328 char **ppaArg;
329 int iArgs;
330 int rc = RTGetOptArgvFromString(&ppaArg, &iArgs, pszArgs, NULL);
331 if (RT_SUCCESS(rc))
332 {
333 char *pszTemp = NULL;
334 *pcbList = 0;
335 for (int i=0; i<iArgs; i++)
336 {
337 if (i > 0) /* Insert space as delimiter. */
338 rc = RTStrAAppendN(&pszTemp, " ", 1);
339
340 if (RT_FAILURE(rc))
341 break;
342 else
343 {
344 rc = RTStrAAppendN(&pszTemp, ppaArg[i], strlen(ppaArg[i]));
345 if (RT_FAILURE(rc))
346 break;
347 }
348 }
349 RTGetOptArgvFree(ppaArg);
350 if (RT_SUCCESS(rc))
351 {
352 *ppvList = pszTemp;
353 *pcArgs = iArgs;
354 if (pszTemp)
355 *pcbList = strlen(pszTemp) + 1; /* Include zero termination. */
356 }
357 else
358 RTStrFree(pszTemp);
359 }
360 return rc;
361}
362
363/**
364 * Appends environment variables to the environment block. Each var=value pair is separated
365 * by NULL (\0) sequence. The whole block will be stored in one blob and disassembled on the
366 * guest side later to fit into the HGCM param structure.
367 *
368 * @returns VBox status code.
369 *
370 * @todo
371 *
372 */
373int Guest::prepareExecuteEnv(const char *pszEnv, void **ppvList, uint32_t *pcbList, uint32_t *pcEnv)
374{
375 int rc = VINF_SUCCESS;
376 uint32_t cbLen = strlen(pszEnv);
377 if (*ppvList)
378 {
379 uint32_t cbNewLen = *pcbList + cbLen + 1; /* Include zero termination. */
380 char *pvTmp = (char*)RTMemRealloc(*ppvList, cbNewLen);
381 if (NULL == pvTmp)
382 {
383 rc = VERR_NO_MEMORY;
384 }
385 else
386 {
387 memcpy(pvTmp + *pcbList, pszEnv, cbLen);
388 pvTmp[cbNewLen - 1] = '\0'; /* Add zero termination. */
389 *ppvList = (void**)pvTmp;
390 }
391 }
392 else
393 {
394 char *pcTmp;
395 if (RTStrAPrintf(&pcTmp, "%s", pszEnv) > 0)
396 {
397 *ppvList = (void**)pcTmp;
398 /* Reset counters. */
399 *pcEnv = 0;
400 *pcbList = 0;
401 }
402 }
403 if (RT_SUCCESS(rc))
404 {
405 *pcbList += cbLen + 1; /* Include zero termination. */
406 *pcEnv += 1; /* Increase env pairs count. */
407 }
408 return rc;
409}
410#endif /* VBOX_WITH_GUEST_CONTROL */
411
412STDMETHODIMP Guest::ExecuteProgram(IN_BSTR aCommand, ULONG aFlags,
413 IN_BSTR aArguments, ComSafeArrayIn(IN_BSTR, aEnvironment),
414 IN_BSTR aStdIn, IN_BSTR aStdOut, IN_BSTR aStdErr,
415 IN_BSTR aUserName, IN_BSTR aPassword,
416 ULONG aTimeoutMS, ULONG *aPID)
417{
418#ifndef VBOX_WITH_GUEST_CONTROL
419 ReturnComNotImplemented();
420#else /* VBOX_WITH_GUEST_CONTROL */
421 using namespace guestControl;
422
423 CheckComArgStrNotEmptyOrNull(aCommand);
424 CheckComArgOutPointerValid(aPID);
425 /* Flags are not supported at the moment. */
426 if (aFlags != 0)
427 return E_INVALIDARG;
428
429 HRESULT rc = S_OK;
430
431 try
432 {
433 AutoCaller autoCaller(this);
434 if (FAILED(autoCaller.rc())) return autoCaller.rc();
435
436 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
437
438 /* Just be on the safe side when calling another process. */
439 alock.leave();
440
441 HRESULT rc = E_UNEXPECTED;
442 using namespace guestControl;
443
444 int vrc = VINF_SUCCESS;
445 Utf8Str Utf8Command(aCommand);
446
447 /* Prepare arguments. */
448 void *pvArgs;
449 uint32_t uNumArgs;
450 uint32_t cbArgs;
451
452 const char *pszCurArg = Utf8Str(aArguments).raw();
453 vrc = prepareExecuteArgs(pszCurArg,
454 &pvArgs, &cbArgs, &uNumArgs);
455 if (RT_SUCCESS(vrc))
456 {
457 /* Prepare environment. */
458 com::SafeArray<IN_BSTR> env(ComSafeArrayInArg(aEnvironment));
459
460 void *pvEnv = NULL;
461 uint32_t uNumEnv = env.size();
462 uint32_t cbEnv = 0;
463
464 for (unsigned i = 0; i < uNumEnv; i++)
465 {
466 const char *pszCurEnv = Utf8Str(env[i]).raw();
467 vrc = prepareExecuteEnv(pszCurEnv, &pvEnv, &cbEnv, &uNumEnv);
468 if (RT_FAILURE(vrc))
469 break;
470 }
471
472 if (RT_SUCCESS(vrc))
473 {
474 Utf8Str Utf8StdIn(aStdIn);
475 Utf8Str Utf8StdOut(aStdOut);
476 Utf8Str Utf8StdErr(aStdErr);
477 Utf8Str Utf8UserName(aUserName);
478 Utf8Str Utf8Password(aPassword);
479
480 VBOXHGCMSVCPARM paParms[13];
481 paParms[0].setUInt32(HOST_EXEC_CMD);
482 paParms[1].setUInt32(aFlags);
483 paParms[2].setPointer((void*)Utf8Command.raw(), (uint32_t)strlen(Utf8Command.raw()) + 1);
484 paParms[3].setUInt32(uNumArgs);
485 paParms[4].setPointer((void*)pvArgs, cbArgs);
486 paParms[5].setUInt32(uNumEnv);
487 paParms[6].setPointer((void*)pvEnv, cbEnv);
488 paParms[7].setPointer((void*)Utf8StdIn.raw(), (uint32_t)strlen(Utf8StdIn.raw()) + 1);
489 paParms[8].setPointer((void*)Utf8StdOut.raw(), (uint32_t)strlen(Utf8StdOut.raw()) + 1);
490 paParms[9].setPointer((void*)Utf8StdErr.raw(), (uint32_t)strlen(Utf8StdErr.raw()) + 1);
491 paParms[10].setPointer((void*)Utf8UserName.raw(), (uint32_t)strlen(Utf8UserName.raw()) + 1);
492 paParms[11].setPointer((void*)Utf8Password.raw(), (uint32_t)strlen(Utf8Password.raw()) + 1);
493 paParms[12].setUInt32(aTimeoutMS);
494
495 /* Forward the information to the VMM device. */
496 AssertPtr(mParent);
497 VMMDev *vmmDev = mParent->getVMMDev();
498 if (vmmDev)
499 {
500 vrc = vmmDev->hgcmHostCall("VBoxGuestControlSvc", HOST_EXEC_CMD,
501 13, paParms);
502 /** @todo Get the PID. */
503 }
504 RTMemFree(pvEnv);
505 }
506 RTMemFree(pvArgs);
507 }
508 if (RT_SUCCESS(vrc))
509 rc = S_OK;
510 else
511 rc = setError(E_UNEXPECTED,
512 tr("The service call failed with the error %Rrc"),
513 vrc);
514 }
515 catch (std::bad_alloc &)
516 {
517 rc = E_OUTOFMEMORY;
518 };
519
520 return rc;
521#endif /* VBOX_WITH_GUEST_CONTROL */
522}
523
524// public methods only for internal purposes
525/////////////////////////////////////////////////////////////////////////////
526
527void Guest::setAdditionsVersion(Bstr aVersion, VBOXOSTYPE aOsType)
528{
529 AutoCaller autoCaller(this);
530 AssertComRCReturnVoid (autoCaller.rc());
531
532 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
533
534 mData.mAdditionsVersion = aVersion;
535 mData.mAdditionsActive = !aVersion.isEmpty();
536 /* Older Additions didn't have this finer grained capability bit,
537 * so enable it by default. Newer Additions will disable it immediately
538 * if relevant. */
539 mData.mSupportsGraphics = mData.mAdditionsActive;
540
541 mData.mOSTypeId = Global::OSTypeId (aOsType);
542}
543
544void Guest::setSupportsSeamless (BOOL aSupportsSeamless)
545{
546 AutoCaller autoCaller(this);
547 AssertComRCReturnVoid (autoCaller.rc());
548
549 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
550
551 mData.mSupportsSeamless = aSupportsSeamless;
552}
553
554void Guest::setSupportsGraphics (BOOL aSupportsGraphics)
555{
556 AutoCaller autoCaller(this);
557 AssertComRCReturnVoid (autoCaller.rc());
558
559 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
560
561 mData.mSupportsGraphics = aSupportsGraphics;
562}
563/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

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