VirtualBox

source: vbox/trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h@ 71482

Last change on this file since 71482 was 71482, checked in by vboxsync, 7 years ago

Guest Control/Main: Skip empty entries in GuestEnvironmentBase::applyPutEnvArray().

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.3 KB
Line 
1/* $Id: GuestCtrlImplPrivate.h 71482 2018-03-23 11:10:18Z vboxsync $ */
2/** @file
3 * Internal helpers/structures for guest control functionality.
4 */
5
6/*
7 * Copyright (C) 2011-2018 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#ifndef ____H_GUESTIMPLPRIVATE
19#define ____H_GUESTIMPLPRIVATE
20
21#include "ConsoleImpl.h"
22#include "Global.h"
23
24#include <iprt/asm.h>
25#include <iprt/env.h>
26#include <iprt/semaphore.h>
27#include <iprt/cpp/utils.h>
28
29#include <VBox/com/com.h>
30#include <VBox/com/ErrorInfo.h>
31#include <VBox/com/string.h>
32#include <VBox/com/VirtualBox.h>
33
34#include <map>
35#include <vector>
36
37using namespace com;
38
39#ifdef VBOX_WITH_GUEST_CONTROL
40# include <VBox/GuestHost/GuestControl.h>
41# include <VBox/HostServices/GuestControlSvc.h>
42using namespace guestControl;
43#endif
44
45/** Vector holding a process' CPU affinity. */
46typedef std::vector <LONG> ProcessAffinity;
47/** Vector holding process startup arguments. */
48typedef std::vector <Utf8Str> ProcessArguments;
49
50class GuestProcessStreamBlock;
51class GuestSession;
52
53
54/**
55 * Simple structure mantaining guest credentials.
56 */
57struct GuestCredentials
58{
59 Utf8Str mUser;
60 Utf8Str mPassword;
61 Utf8Str mDomain;
62};
63
64
65
66/**
67 * Wrapper around the RTEnv API, unusable base class.
68 *
69 * @remarks Feel free to elevate this class to iprt/cpp/env.h as RTCEnv.
70 */
71class GuestEnvironmentBase
72{
73public:
74 /**
75 * Default constructor.
76 *
77 * The user must invoke one of the init methods before using the object.
78 */
79 GuestEnvironmentBase(void)
80 : m_hEnv(NIL_RTENV)
81 , m_cRefs(1)
82 { }
83
84 /**
85 * Destructor.
86 */
87 virtual ~GuestEnvironmentBase(void)
88 {
89 Assert(m_cRefs <= 1);
90 int rc = RTEnvDestroy(m_hEnv); AssertRC(rc);
91 m_hEnv = NIL_RTENV;
92 }
93
94 /**
95 * Retains a reference to this object.
96 * @returns New reference count.
97 * @remarks Sharing an object is currently only safe if no changes are made to
98 * it because RTENV does not yet implement any locking. For the only
99 * purpose we need this, implementing IGuestProcess::environment by
100 * using IGuestSession::environmentBase, that's fine as the session
101 * base environment is immutable.
102 */
103 uint32_t retain(void)
104 {
105 uint32_t cRefs = ASMAtomicIncU32(&m_cRefs);
106 Assert(cRefs > 1); Assert(cRefs < _1M);
107 return cRefs;
108
109 }
110 /** Useful shortcut. */
111 uint32_t retainConst(void) const { return unconst(this)->retain(); }
112
113 /**
114 * Releases a reference to this object, deleting the object when reaching zero.
115 * @returns New reference count.
116 */
117 uint32_t release(void)
118 {
119 uint32_t cRefs = ASMAtomicDecU32(&m_cRefs);
120 Assert(cRefs < _1M);
121 if (cRefs == 0)
122 delete this;
123 return cRefs;
124 }
125
126 /** Useful shortcut. */
127 uint32_t releaseConst(void) const { return unconst(this)->retain(); }
128
129 /**
130 * Checks if the environment has been successfully initialized or not.
131 *
132 * @returns @c true if initialized, @c false if not.
133 */
134 bool isInitialized(void) const
135 {
136 return m_hEnv != NIL_RTENV;
137 }
138
139 /**
140 * Returns the variable count.
141 * @return Number of variables.
142 * @sa RTEnvCountEx
143 */
144 uint32_t count(void) const
145 {
146 return RTEnvCountEx(m_hEnv);
147 }
148
149 /**
150 * Deletes the environment change record entirely.
151 *
152 * The count() method will return zero after this call.
153 *
154 * @sa RTEnvReset
155 */
156 void reset(void)
157 {
158 int rc = RTEnvReset(m_hEnv);
159 AssertRC(rc);
160 }
161
162 /**
163 * Exports the environment change block as an array of putenv style strings.
164 *
165 *
166 * @returns VINF_SUCCESS or VERR_NO_MEMORY.
167 * @param pArray The output array.
168 */
169 int queryPutEnvArray(std::vector<com::Utf8Str> *pArray) const
170 {
171 uint32_t cVars = RTEnvCountEx(m_hEnv);
172 try
173 {
174 pArray->resize(cVars);
175 for (uint32_t iVar = 0; iVar < cVars; iVar++)
176 {
177 const char *psz = RTEnvGetByIndexRawEx(m_hEnv, iVar);
178 AssertReturn(psz, VERR_INTERNAL_ERROR_3); /* someone is racing us! */
179 (*pArray)[iVar] = psz;
180 }
181 return VINF_SUCCESS;
182 }
183 catch (std::bad_alloc &)
184 {
185 return VERR_NO_MEMORY;
186 }
187 }
188
189 /**
190 * Applies an array of putenv style strings.
191 *
192 * @returns IPRT status code.
193 * @param rArray The array with the putenv style strings.
194 * @sa RTEnvPutEnvEx
195 */
196 int applyPutEnvArray(const std::vector<com::Utf8Str> &rArray)
197 {
198 size_t cArray = rArray.size();
199 for (size_t i = 0; i < cArray; i++)
200 {
201 if (rArray[i].isEmpty())
202 continue;
203
204 int rc = RTEnvPutEx(m_hEnv, rArray[i].c_str());
205 if (RT_FAILURE(rc))
206 return rc;
207 }
208 return VINF_SUCCESS;
209 }
210
211 /**
212 * Applies the changes from another environment to this.
213 *
214 * @returns IPRT status code.
215 * @param rChanges Reference to an environment which variables will be
216 * imported and, if it's a change record, schedule
217 * variable unsets will be applied.
218 * @sa RTEnvApplyChanges
219 */
220 int applyChanges(const GuestEnvironmentBase &rChanges)
221 {
222 return RTEnvApplyChanges(m_hEnv, rChanges.m_hEnv);
223 }
224
225
226 /**
227 * See RTEnvQueryUtf8Block for details.
228 * @returns IPRT status code.
229 * @param ppszzBlock Where to return the block pointer.
230 * @param pcbBlock Where to optionally return the block size.
231 * @sa RTEnvQueryUtf8Block
232 */
233 int queryUtf8Block(char **ppszzBlock, size_t *pcbBlock)
234 {
235 return RTEnvQueryUtf8Block(m_hEnv, true /*fSorted*/, ppszzBlock, pcbBlock);
236 }
237
238 /**
239 * Frees what queryUtf8Block returned, NULL ignored.
240 * @sa RTEnvFreeUtf8Block
241 */
242 static void freeUtf8Block(char *pszzBlock)
243 {
244 return RTEnvFreeUtf8Block(pszzBlock);
245 }
246
247 /**
248 * Applies a block on the format returned by queryUtf8Block.
249 *
250 * @returns IPRT status code.
251 * @param pszzBlock Pointer to the block.
252 * @param cbBlock The size of the block.
253 * @param fNoEqualMeansUnset Whether the lack of a '=' (equal) sign in a
254 * string means it should be unset (@c true), or if
255 * it means the variable should be defined with an
256 * empty value (@c false, the default).
257 * @todo move this to RTEnv!
258 */
259 int copyUtf8Block(const char *pszzBlock, size_t cbBlock, bool fNoEqualMeansUnset = false)
260 {
261 int rc = VINF_SUCCESS;
262 while (cbBlock > 0 && *pszzBlock != '\0')
263 {
264 const char *pszEnd = (const char *)memchr(pszzBlock, '\0', cbBlock);
265 if (!pszEnd)
266 return VERR_BUFFER_UNDERFLOW;
267 int rc2;
268 if (fNoEqualMeansUnset || strchr(pszzBlock, '='))
269 rc2 = RTEnvPutEx(m_hEnv, pszzBlock);
270 else
271 rc2 = RTEnvSetEx(m_hEnv, pszzBlock, "");
272 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
273 rc = rc2;
274
275 /* Advance. */
276 cbBlock -= pszEnd - pszzBlock;
277 if (cbBlock < 2)
278 return VERR_BUFFER_UNDERFLOW;
279 cbBlock--;
280 pszzBlock = pszEnd + 1;
281 }
282
283 /* The remainder must be zero padded. */
284 if (RT_SUCCESS(rc))
285 {
286 if (ASMMemIsZero(pszzBlock, cbBlock))
287 return VINF_SUCCESS;
288 return VERR_TOO_MUCH_DATA;
289 }
290 return rc;
291 }
292
293
294 /**
295 * Get an environment variable.
296 *
297 * @returns IPRT status code.
298 * @param rName The variable name.
299 * @param pValue Where to return the value.
300 * @sa RTEnvGetEx
301 */
302 int getVariable(const com::Utf8Str &rName, com::Utf8Str *pValue) const
303 {
304 size_t cchNeeded;
305 int rc = RTEnvGetEx(m_hEnv, rName.c_str(), NULL, 0, &cchNeeded);
306 if ( RT_SUCCESS(rc)
307 || rc == VERR_BUFFER_OVERFLOW)
308 {
309 try
310 {
311 pValue->reserve(cchNeeded + 1);
312 rc = RTEnvGetEx(m_hEnv, rName.c_str(), pValue->mutableRaw(), pValue->capacity(), NULL);
313 pValue->jolt();
314 }
315 catch (std::bad_alloc &)
316 {
317 rc = VERR_NO_STR_MEMORY;
318 }
319 }
320 return rc;
321 }
322
323 /**
324 * Checks if the given variable exists.
325 *
326 * @returns @c true if it exists, @c false if not or if it's an scheduled unset
327 * in a environment change record.
328 * @param rName The variable name.
329 * @sa RTEnvExistEx
330 */
331 bool doesVariableExist(const com::Utf8Str &rName) const
332 {
333 return RTEnvExistEx(m_hEnv, rName.c_str());
334 }
335
336 /**
337 * Set an environment variable.
338 *
339 * @returns IPRT status code.
340 * @param rName The variable name.
341 * @param rValue The value of the variable.
342 * @sa RTEnvSetEx
343 */
344 int setVariable(const com::Utf8Str &rName, const com::Utf8Str &rValue)
345 {
346 return RTEnvSetEx(m_hEnv, rName.c_str(), rValue.c_str());
347 }
348
349 /**
350 * Unset an environment variable.
351 *
352 * @returns IPRT status code.
353 * @param rName The variable name.
354 * @sa RTEnvUnsetEx
355 */
356 int unsetVariable(const com::Utf8Str &rName)
357 {
358 return RTEnvUnsetEx(m_hEnv, rName.c_str());
359 }
360
361protected:
362 /**
363 * Copy constructor.
364 * @throws HRESULT
365 */
366 GuestEnvironmentBase(const GuestEnvironmentBase &rThat, bool fChangeRecord)
367 : m_hEnv(NIL_RTENV)
368 , m_cRefs(1)
369 {
370 int rc = cloneCommon(rThat, fChangeRecord);
371 if (RT_FAILURE(rc))
372 throw (Global::vboxStatusCodeToCOM(rc));
373 }
374
375 /**
376 * Common clone/copy method with type conversion abilities.
377 *
378 * @returns IPRT status code.
379 * @param rThat The object to clone.
380 * @param fChangeRecord Whether the this instance is a change record (true)
381 * or normal (false) environment.
382 */
383 int cloneCommon(const GuestEnvironmentBase &rThat, bool fChangeRecord)
384 {
385 int rc = VINF_SUCCESS;
386 RTENV hNewEnv = NIL_RTENV;
387 if (rThat.m_hEnv != NIL_RTENV)
388 {
389 /*
390 * Clone it.
391 */
392 if (RTEnvIsChangeRecord(rThat.m_hEnv) == fChangeRecord)
393 rc = RTEnvClone(&hNewEnv, rThat.m_hEnv);
394 else
395 {
396 /* Need to type convert it. */
397 if (fChangeRecord)
398 rc = RTEnvCreateChangeRecord(&hNewEnv);
399 else
400 rc = RTEnvCreate(&hNewEnv);
401 if (RT_SUCCESS(rc))
402 {
403 rc = RTEnvApplyChanges(hNewEnv, rThat.m_hEnv);
404 if (RT_FAILURE(rc))
405 RTEnvDestroy(hNewEnv);
406 }
407 }
408 }
409 else
410 {
411 /*
412 * Create an empty one so the object works smoothly.
413 * (Relevant for GuestProcessStartupInfo and internal commands.)
414 */
415 if (fChangeRecord)
416 rc = RTEnvCreateChangeRecord(&hNewEnv);
417 else
418 rc = RTEnvCreate(&hNewEnv);
419 }
420 if (RT_SUCCESS(rc))
421 {
422 RTEnvDestroy(m_hEnv);
423 m_hEnv = hNewEnv;
424 }
425 return rc;
426 }
427
428
429 /** The environment change record. */
430 RTENV m_hEnv;
431 /** Reference counter. */
432 uint32_t volatile m_cRefs;
433};
434
435class GuestEnvironmentChanges;
436
437
438/**
439 * Wrapper around the RTEnv API for a normal environment.
440 */
441class GuestEnvironment : public GuestEnvironmentBase
442{
443public:
444 /**
445 * Default constructor.
446 *
447 * The user must invoke one of the init methods before using the object.
448 */
449 GuestEnvironment(void)
450 : GuestEnvironmentBase()
451 { }
452
453 /**
454 * Copy operator.
455 * @param rThat The object to copy.
456 * @throws HRESULT
457 */
458 GuestEnvironment(const GuestEnvironment &rThat)
459 : GuestEnvironmentBase(rThat, false /*fChangeRecord*/)
460 { }
461
462 /**
463 * Copy operator.
464 * @param rThat The object to copy.
465 * @throws HRESULT
466 */
467 GuestEnvironment(const GuestEnvironmentBase &rThat)
468 : GuestEnvironmentBase(rThat, false /*fChangeRecord*/)
469 { }
470
471 /**
472 * Initialize this as a normal environment block.
473 * @returns IPRT status code.
474 */
475 int initNormal(void)
476 {
477 AssertReturn(m_hEnv == NIL_RTENV, VERR_WRONG_ORDER);
478 return RTEnvCreate(&m_hEnv);
479 }
480
481 /**
482 * Replaces this environemnt with that in @a rThat.
483 *
484 * @returns IPRT status code
485 * @param rThat The environment to copy. If it's a different type
486 * we'll convert the data to a normal environment block.
487 */
488 int copy(const GuestEnvironmentBase &rThat)
489 {
490 return cloneCommon(rThat, false /*fChangeRecord*/);
491 }
492
493 /**
494 * @copydoc copy()
495 */
496 GuestEnvironment &operator=(const GuestEnvironmentBase &rThat)
497 {
498 int rc = cloneCommon(rThat, true /*fChangeRecord*/);
499 if (RT_FAILURE(rc))
500 throw (Global::vboxStatusCodeToCOM(rc));
501 return *this;
502 }
503
504 /** @copydoc copy() */
505 GuestEnvironment &operator=(const GuestEnvironment &rThat)
506 { return operator=((const GuestEnvironmentBase &)rThat); }
507
508 /** @copydoc copy() */
509 GuestEnvironment &operator=(const GuestEnvironmentChanges &rThat)
510 { return operator=((const GuestEnvironmentBase &)rThat); }
511
512};
513
514
515/**
516 * Wrapper around the RTEnv API for a environment change record.
517 *
518 * This class is used as a record of changes to be applied to a different
519 * environment block (in VBoxService before launching a new process).
520 */
521class GuestEnvironmentChanges : public GuestEnvironmentBase
522{
523public:
524 /**
525 * Default constructor.
526 *
527 * The user must invoke one of the init methods before using the object.
528 */
529 GuestEnvironmentChanges(void)
530 : GuestEnvironmentBase()
531 { }
532
533 /**
534 * Copy operator.
535 * @param rThat The object to copy.
536 * @throws HRESULT
537 */
538 GuestEnvironmentChanges(const GuestEnvironmentChanges &rThat)
539 : GuestEnvironmentBase(rThat, true /*fChangeRecord*/)
540 { }
541
542 /**
543 * Copy operator.
544 * @param rThat The object to copy.
545 * @throws HRESULT
546 */
547 GuestEnvironmentChanges(const GuestEnvironmentBase &rThat)
548 : GuestEnvironmentBase(rThat, true /*fChangeRecord*/)
549 { }
550
551 /**
552 * Initialize this as a environment change record.
553 * @returns IPRT status code.
554 */
555 int initChangeRecord(void)
556 {
557 AssertReturn(m_hEnv == NIL_RTENV, VERR_WRONG_ORDER);
558 return RTEnvCreateChangeRecord(&m_hEnv);
559 }
560
561 /**
562 * Replaces this environemnt with that in @a rThat.
563 *
564 * @returns IPRT status code
565 * @param rThat The environment to copy. If it's a different type
566 * we'll convert the data to a set of changes.
567 */
568 int copy(const GuestEnvironmentBase &rThat)
569 {
570 return cloneCommon(rThat, true /*fChangeRecord*/);
571 }
572
573 /**
574 * @copydoc copy()
575 */
576 GuestEnvironmentChanges &operator=(const GuestEnvironmentBase &rThat)
577 {
578 int rc = cloneCommon(rThat, true /*fChangeRecord*/);
579 if (RT_FAILURE(rc))
580 throw (Global::vboxStatusCodeToCOM(rc));
581 return *this;
582 }
583
584 /** @copydoc copy() */
585 GuestEnvironmentChanges &operator=(const GuestEnvironmentChanges &rThat)
586 { return operator=((const GuestEnvironmentBase &)rThat); }
587
588 /** @copydoc copy() */
589 GuestEnvironmentChanges &operator=(const GuestEnvironment &rThat)
590 { return operator=((const GuestEnvironmentBase &)rThat); }
591};
592
593
594/**
595 * Structure for keeping all the relevant guest directory
596 * information around.
597 */
598struct GuestDirectoryOpenInfo
599{
600 /** The directory path. */
601 Utf8Str mPath;
602 /** Then open filter. */
603 Utf8Str mFilter;
604 /** Opening flags. */
605 uint32_t mFlags;
606};
607
608
609/**
610 * Structure for keeping all the relevant guest file
611 * information around.
612 */
613struct GuestFileOpenInfo
614{
615 /** The filename. */
616 Utf8Str mFileName;
617 /** The file access mode. */
618 FileAccessMode_T mAccessMode;
619 /** String translation of mFileAccessMode for the GAs. */
620 const char *mpszAccessMode;
621 /** The file open action. */
622 FileOpenAction_T mOpenAction;
623 /** String translation of mOpenAction for the GAs. */
624 const char *mpszOpenAction;
625 /** The file sharing mode. */
626 FileSharingMode_T mSharingMode;
627 /** Octal creation mode. */
628 uint32_t mCreationMode;
629 /** Extended open flags (currently none defined). */
630 uint32_t mfOpenEx;
631};
632
633
634/**
635 * Structure representing information of a
636 * file system object.
637 */
638struct GuestFsObjData
639{
640 /** @name Helper functions to extract the data from a certin VBoxService tool's guest stream block.
641 * @{ */
642 int FromLs(const GuestProcessStreamBlock &strmBlk, bool fLong);
643 int FromMkTemp(const GuestProcessStreamBlock &strmBlk);
644 int FromStat(const GuestProcessStreamBlock &strmBlk);
645 /** @} */
646
647 /** @name Static helper functions to work with time from stream block keys.
648 * @{ */
649 static PRTTIMESPEC TimeSpecFromKey(const GuestProcessStreamBlock &strmBlk, const Utf8Str &strKey, PRTTIMESPEC pTimeSpec);
650 static int64_t UnixEpochNsFromKey(const GuestProcessStreamBlock &strmBlk, const Utf8Str &strKey);
651 /** @} */
652
653 int64_t mAccessTime;
654 int64_t mAllocatedSize;
655 int64_t mBirthTime;
656 int64_t mChangeTime;
657 uint32_t mDeviceNumber;
658 Utf8Str mFileAttrs;
659 uint32_t mGenerationID;
660 uint32_t mGID;
661 Utf8Str mGroupName;
662 uint32_t mNumHardLinks;
663 int64_t mModificationTime;
664 Utf8Str mName;
665 int64_t mNodeID;
666 uint32_t mNodeIDDevice;
667 int64_t mObjectSize;
668 FsObjType_T mType;
669 uint32_t mUID;
670 uint32_t mUserFlags;
671 Utf8Str mUserName;
672 Utf8Str mACL;
673};
674
675
676/**
677 * Structure for keeping all the relevant guest session
678 * startup parameters around.
679 */
680class GuestSessionStartupInfo
681{
682public:
683
684 GuestSessionStartupInfo(void)
685 : mIsInternal(false /* Non-internal session */),
686 mOpenTimeoutMS(30 * 1000 /* 30s opening timeout */),
687 mOpenFlags(0 /* No opening flags set */) { }
688
689 /** The session's friendly name. Optional. */
690 Utf8Str mName;
691 /** The session's unique ID. Used to encode a context ID. */
692 uint32_t mID;
693 /** Flag indicating if this is an internal session
694 * or not. Internal session are not accessible by
695 * public API clients. */
696 bool mIsInternal;
697 /** Timeout (in ms) used for opening the session. */
698 uint32_t mOpenTimeoutMS;
699 /** Session opening flags. */
700 uint32_t mOpenFlags;
701};
702
703
704/**
705 * Structure for keeping all the relevant guest process
706 * startup parameters around.
707 */
708class GuestProcessStartupInfo
709{
710public:
711
712 GuestProcessStartupInfo(void)
713 : mFlags(ProcessCreateFlag_None),
714 mTimeoutMS(UINT32_MAX /* No timeout by default */),
715 mPriority(ProcessPriority_Default) { }
716
717 /** The process' friendly name. */
718 Utf8Str mName;
719 /** The executable. */
720 Utf8Str mExecutable;
721 /** Arguments vector (starting with argument \#0). */
722 ProcessArguments mArguments;
723 /** The process environment change record. */
724 GuestEnvironmentChanges mEnvironmentChanges;
725 /** Process creation flags. */
726 uint32_t mFlags;
727 /** Timeout (in ms) the process is allowed to run.
728 * Specify UINT32_MAX if no timeout (unlimited run time) is given. */
729 ULONG mTimeoutMS;
730 /** Process priority. */
731 ProcessPriority_T mPriority;
732 /** Process affinity. At the moment we
733 * only support 64 VCPUs. API and
734 * guest can do more already! */
735 uint64_t mAffinity;
736};
737
738
739/**
740 * Class representing the "value" side of a "key=value" pair.
741 */
742class GuestProcessStreamValue
743{
744public:
745
746 GuestProcessStreamValue(void) { }
747 GuestProcessStreamValue(const char *pszValue)
748 : mValue(pszValue) {}
749
750 GuestProcessStreamValue(const GuestProcessStreamValue& aThat)
751 : mValue(aThat.mValue) { }
752
753 Utf8Str mValue;
754};
755
756/** Map containing "key=value" pairs of a guest process stream. */
757typedef std::pair< Utf8Str, GuestProcessStreamValue > GuestCtrlStreamPair;
758typedef std::map < Utf8Str, GuestProcessStreamValue > GuestCtrlStreamPairMap;
759typedef std::map < Utf8Str, GuestProcessStreamValue >::iterator GuestCtrlStreamPairMapIter;
760typedef std::map < Utf8Str, GuestProcessStreamValue >::const_iterator GuestCtrlStreamPairMapIterConst;
761
762/**
763 * Class representing a block of stream pairs (key=value). Each block in a raw guest
764 * output stream is separated by "\0\0", each pair is separated by "\0". The overall
765 * end of a guest stream is marked by "\0\0\0\0".
766 */
767class GuestProcessStreamBlock
768{
769public:
770
771 GuestProcessStreamBlock(void);
772
773 virtual ~GuestProcessStreamBlock(void);
774
775public:
776
777 void Clear(void);
778
779#ifdef DEBUG
780 void DumpToLog(void) const;
781#endif
782
783 int GetInt64Ex(const char *pszKey, int64_t *piVal) const;
784
785 int64_t GetInt64(const char *pszKey) const;
786
787 size_t GetCount(void) const;
788
789 int GetRc(void) const;
790
791 const char* GetString(const char *pszKey) const;
792
793 int GetUInt32Ex(const char *pszKey, uint32_t *puVal) const;
794
795 uint32_t GetUInt32(const char *pszKey) const;
796
797 bool IsEmpty(void) { return mPairs.empty(); }
798
799 int SetValue(const char *pszKey, const char *pszValue);
800
801protected:
802
803 GuestCtrlStreamPairMap mPairs;
804};
805
806/** Vector containing multiple allocated stream pair objects. */
807typedef std::vector< GuestProcessStreamBlock > GuestCtrlStreamObjects;
808typedef std::vector< GuestProcessStreamBlock >::iterator GuestCtrlStreamObjectsIter;
809typedef std::vector< GuestProcessStreamBlock >::const_iterator GuestCtrlStreamObjectsIterConst;
810
811/**
812 * Class for parsing machine-readable guest process output by VBoxService'
813 * toolbox commands ("vbox_ls", "vbox_stat" etc), aka "guest stream".
814 */
815class GuestProcessStream
816{
817
818public:
819
820 GuestProcessStream();
821
822 virtual ~GuestProcessStream();
823
824public:
825
826 int AddData(const BYTE *pbData, size_t cbData);
827
828 void Destroy();
829
830#ifdef DEBUG
831 void Dump(const char *pszFile);
832#endif
833
834 size_t GetOffset() { return m_offBuffer; }
835
836 size_t GetSize() { return m_cbUsed; }
837
838 int ParseBlock(GuestProcessStreamBlock &streamBlock);
839
840protected:
841
842 /** Currently allocated size of internal stream buffer. */
843 size_t m_cbAllocated;
844 /** Currently used size at m_offBuffer. */
845 size_t m_cbUsed;
846 /** Current byte offset within the internal stream buffer. */
847 size_t m_offBuffer;
848 /** Internal stream buffer. */
849 BYTE *m_pbBuffer;
850};
851
852class Guest;
853class Progress;
854
855class GuestTask
856{
857
858public:
859
860 enum TaskType
861 {
862 /** Copies a file from host to the guest. */
863 TaskType_CopyFileToGuest = 50,
864 /** Copies a file from guest to the host. */
865 TaskType_CopyFileFromGuest = 55,
866 /** Update Guest Additions by directly copying the required installer
867 * off the .ISO file, transfer it to the guest and execute the installer
868 * with system privileges. */
869 TaskType_UpdateGuestAdditions = 100
870 };
871
872 GuestTask(TaskType aTaskType, Guest *aThat, Progress *aProgress);
873
874 virtual ~GuestTask();
875
876 int startThread();
877
878 static int taskThread(RTTHREAD aThread, void *pvUser);
879 static int uploadProgress(unsigned uPercent, void *pvUser);
880 static HRESULT setProgressSuccess(ComObjPtr<Progress> pProgress);
881 static HRESULT setProgressErrorMsg(HRESULT hr,
882 ComObjPtr<Progress> pProgress, const char * pszText, ...);
883 static HRESULT setProgressErrorParent(HRESULT hr,
884 ComObjPtr<Progress> pProgress, ComObjPtr<Guest> pGuest);
885
886 TaskType taskType;
887 ComObjPtr<Guest> pGuest;
888 ComObjPtr<Progress> pProgress;
889 HRESULT rc;
890
891 /* Task data. */
892 Utf8Str strSource;
893 Utf8Str strDest;
894 Utf8Str strUserName;
895 Utf8Str strPassword;
896 ULONG uFlags;
897};
898
899class GuestWaitEventPayload
900{
901
902public:
903
904 GuestWaitEventPayload(void)
905 : uType(0),
906 cbData(0),
907 pvData(NULL) { }
908
909 GuestWaitEventPayload(uint32_t uTypePayload,
910 const void *pvPayload, uint32_t cbPayload)
911 : uType(0),
912 cbData(0),
913 pvData(NULL)
914 {
915 int rc = copyFrom(uTypePayload, pvPayload, cbPayload);
916 if (RT_FAILURE(rc))
917 throw rc;
918 }
919
920 virtual ~GuestWaitEventPayload(void)
921 {
922 Clear();
923 }
924
925 GuestWaitEventPayload& operator=(const GuestWaitEventPayload &that)
926 {
927 CopyFromDeep(that);
928 return *this;
929 }
930
931public:
932
933 void Clear(void)
934 {
935 if (pvData)
936 {
937 Assert(cbData);
938 RTMemFree(pvData);
939 cbData = 0;
940 pvData = NULL;
941 }
942 uType = 0;
943 }
944
945 int CopyFromDeep(const GuestWaitEventPayload &payload)
946 {
947 return copyFrom(payload.uType, payload.pvData, payload.cbData);
948 }
949
950 const void* Raw(void) const { return pvData; }
951
952 size_t Size(void) const { return cbData; }
953
954 uint32_t Type(void) const { return uType; }
955
956 void* MutableRaw(void) { return pvData; }
957
958 Utf8Str ToString(void)
959 {
960 const char *pszStr = (const char *)pvData;
961 size_t cbStr = cbData;
962
963 if (RT_FAILURE(RTStrValidateEncodingEx(pszStr, cbStr,
964 RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED | RTSTR_VALIDATE_ENCODING_EXACT_LENGTH)))
965 {
966 AssertFailed();
967 return "";
968 }
969
970 return Utf8Str(pszStr, cbStr);
971 }
972
973protected:
974
975 int copyFrom(uint32_t uTypePayload, const void *pvPayload, uint32_t cbPayload)
976 {
977 if (cbPayload > _64K) /* Paranoia. */
978 return VERR_TOO_MUCH_DATA;
979
980 Clear();
981
982 int rc = VINF_SUCCESS;
983
984 if (cbPayload)
985 {
986 pvData = RTMemAlloc(cbPayload);
987 if (pvData)
988 {
989 uType = uTypePayload;
990
991 memcpy(pvData, pvPayload, cbPayload);
992 cbData = cbPayload;
993 }
994 else
995 rc = VERR_NO_MEMORY;
996 }
997 else
998 {
999 uType = uTypePayload;
1000
1001 pvData = NULL;
1002 cbData = 0;
1003 }
1004
1005 return rc;
1006 }
1007
1008protected:
1009
1010 /** Type of payload. */
1011 uint32_t uType;
1012 /** Size (in bytes) of payload. */
1013 uint32_t cbData;
1014 /** Pointer to actual payload data. */
1015 void *pvData;
1016};
1017
1018class GuestWaitEventBase
1019{
1020
1021protected:
1022
1023 GuestWaitEventBase(void);
1024 virtual ~GuestWaitEventBase(void);
1025
1026public:
1027
1028 uint32_t ContextID(void) { return mCID; };
1029 int GuestResult(void) { return mGuestRc; }
1030 int Result(void) { return mRc; }
1031 GuestWaitEventPayload & Payload(void) { return mPayload; }
1032 int SignalInternal(int rc, int guestRc, const GuestWaitEventPayload *pPayload);
1033 int Wait(RTMSINTERVAL uTimeoutMS);
1034
1035protected:
1036
1037 int Init(uint32_t uCID);
1038
1039protected:
1040
1041 /* Shutdown indicator. */
1042 bool mfAborted;
1043 /* Associated context ID (CID). */
1044 uint32_t mCID;
1045 /** The event semaphore for triggering
1046 * the actual event. */
1047 RTSEMEVENT mEventSem;
1048 /** The event's overall result. If
1049 * set to VERR_GSTCTL_GUEST_ERROR,
1050 * mGuestRc will contain the actual
1051 * error code from the guest side. */
1052 int mRc;
1053 /** The event'S overall result from the
1054 * guest side. If used, mRc must be
1055 * set to VERR_GSTCTL_GUEST_ERROR. */
1056 int mGuestRc;
1057 /** The event's payload data. Optional. */
1058 GuestWaitEventPayload mPayload;
1059};
1060
1061/** List of public guest event types. */
1062typedef std::list < VBoxEventType_T > GuestEventTypes;
1063
1064class GuestWaitEvent : public GuestWaitEventBase
1065{
1066
1067public:
1068
1069 GuestWaitEvent(uint32_t uCID);
1070 GuestWaitEvent(uint32_t uCID, const GuestEventTypes &lstEvents);
1071 virtual ~GuestWaitEvent(void);
1072
1073public:
1074
1075 int Cancel(void);
1076 const ComPtr<IEvent> Event(void) { return mEvent; }
1077 int SignalExternal(IEvent *pEvent);
1078 const GuestEventTypes Types(void) { return mEventTypes; }
1079 size_t TypeCount(void) { return mEventTypes.size(); }
1080
1081protected:
1082
1083 int Init(uint32_t uCID);
1084
1085protected:
1086
1087 /** List of public event types this event should
1088 * be signalled on. Optional. */
1089 GuestEventTypes mEventTypes;
1090 /** Pointer to the actual public event, if any. */
1091 ComPtr<IEvent> mEvent;
1092};
1093/** Map of pointers to guest events. The primary key
1094 * contains the context ID. */
1095typedef std::map < uint32_t, GuestWaitEvent* > GuestWaitEvents;
1096/** Map of wait events per public guest event. Nice for
1097 * faster lookups when signalling a whole event group. */
1098typedef std::map < VBoxEventType_T, GuestWaitEvents > GuestEventGroup;
1099
1100class GuestBase
1101{
1102
1103public:
1104
1105 GuestBase(void);
1106 virtual ~GuestBase(void);
1107
1108public:
1109
1110 /** Signals a wait event using a public guest event; also used for
1111 * for external event listeners. */
1112 int signalWaitEvent(VBoxEventType_T aType, IEvent *aEvent);
1113 /** Signals a wait event using a guest rc. */
1114 int signalWaitEventInternal(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, int guestRc, const GuestWaitEventPayload *pPayload);
1115 /** Signals a wait event without letting public guest events know,
1116 * extended director's cut version. */
1117 int signalWaitEventInternalEx(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, int rc, int guestRc, const GuestWaitEventPayload *pPayload);
1118public:
1119
1120 int baseInit(void);
1121 void baseUninit(void);
1122 int cancelWaitEvents(void);
1123 int dispatchGeneric(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb);
1124 int generateContextID(uint32_t uSessionID, uint32_t uObjectID, uint32_t *puContextID);
1125 int registerWaitEvent(uint32_t uSessionID, uint32_t uObjectID, GuestWaitEvent **ppEvent);
1126 int registerWaitEventEx(uint32_t uSessionID, uint32_t uObjectID, const GuestEventTypes &lstEvents, GuestWaitEvent **ppEvent);
1127 int unregisterWaitEvent(GuestWaitEvent *pEvent);
1128 int waitForEvent(GuestWaitEvent *pEvent, uint32_t uTimeoutMS, VBoxEventType_T *pType, IEvent **ppEvent);
1129
1130protected:
1131
1132 /** Pointer to the console object. Needed
1133 * for HGCM (VMMDev) communication. */
1134 Console *mConsole;
1135 /** The next upcoming context ID for this object. */
1136 uint32_t mNextContextID;
1137 /** Local listener for handling the waiting events
1138 * internally. */
1139 ComPtr<IEventListener> mLocalListener;
1140 /** Critical section for wait events access. */
1141 RTCRITSECT mWaitEventCritSect;
1142 /** Map of registered wait events per event group. */
1143 GuestEventGroup mWaitEventGroups;
1144 /** Map of registered wait events. */
1145 GuestWaitEvents mWaitEvents;
1146};
1147
1148/**
1149 * Virtual class (interface) for guest objects (processes, files, ...) --
1150 * contains all per-object callback management.
1151 */
1152class GuestObject : public GuestBase
1153{
1154
1155public:
1156
1157 GuestObject(void);
1158 virtual ~GuestObject(void);
1159
1160public:
1161
1162 ULONG getObjectID(void) { return mObjectID; }
1163
1164protected:
1165
1166 virtual int i_onRemove(void) = 0;
1167
1168 /** Callback dispatcher -- must be implemented by the actual object. */
1169 virtual int i_callbackDispatcher(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb) = 0;
1170
1171protected:
1172
1173 int bindToSession(Console *pConsole, GuestSession *pSession, uint32_t uObjectID);
1174 int registerWaitEvent(const GuestEventTypes &lstEvents, GuestWaitEvent **ppEvent);
1175 int sendCommand(uint32_t uFunction, uint32_t cParms, PVBOXHGCMSVCPARM paParms);
1176
1177protected:
1178
1179 /** @name Common parameters for all derived objects. They have their own
1180 * mData structure to keep their specific data around.
1181 * @{ */
1182 /** Pointer to parent session. Per definition
1183 * this objects *always* lives shorter than the
1184 * parent.
1185 * @todo r=bird: When wanting to use mSession in the
1186 * IGuestProcess::getEnvironment() implementation I wanted to access
1187 * GuestSession::mData::mpBaseEnvironment. Seeing the comment in
1188 * GuestProcess::terminate() saying:
1189 * "Now only API clients still can hold references to it."
1190 * and recalling seeing similar things in VirtualBox.xidl or some such place,
1191 * I'm wondering how this "per definition" behavior is enforced. Is there any
1192 * GuestProcess:uninit() call or similar magic that invalidates objects that
1193 * GuestSession loses track of in place like GuestProcess::terminate() that I've
1194 * failed to spot?
1195 *
1196 * Please enlighten me.
1197 */
1198 GuestSession *mSession;
1199 /** The object ID -- must be unique for each guest
1200 * object and is encoded into the context ID. Must
1201 * be set manually when initializing the object.
1202 *
1203 * For guest processes this is the internal PID,
1204 * for guest files this is the internal file ID. */
1205 uint32_t mObjectID;
1206 /** @} */
1207};
1208#endif // !____H_GUESTIMPLPRIVATE
1209
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