VirtualBox

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

Last change on this file since 78018 was 77588, checked in by vboxsync, 6 years ago

Guest Control/Main: Implemented virtual guest object methods for session status changes to allow guest objects set their internal state accordingly. The guest session's object map now also keeps a (weak) pointer to the guest objects for handling the callbacks [build fix, no C++11 yet].

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