VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp@ 55588

Last change on this file since 55588 was 55588, checked in by vboxsync, 10 years ago

Main: Environment cleanup in the guest control area. The GuestEnvironment class implementation has been replaced by one based on IPRT's RTEnv API and it has been changed into a way of recording environment changes, thus renamed to GuestEnvironmentChanges.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.0 KB
Line 
1/* $Id: GuestCtrlPrivate.cpp 55588 2015-05-01 19:37:46Z vboxsync $ */
2/** @file
3 * Internal helpers/structures for guest control functionality.
4 */
5
6/*
7 * Copyright (C) 2011-2015 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/******************************************************************************
19 * Header Files *
20 ******************************************************************************/
21#include "GuestCtrlImplPrivate.h"
22#include "GuestSessionImpl.h"
23#include "VMMDev.h"
24
25#include <iprt/asm.h>
26#include <iprt/cpp/utils.h> /* For unconst(). */
27#include <iprt/ctype.h>
28#ifdef DEBUG
29# include <iprt/file.h>
30#endif /* DEBUG */
31
32#ifdef LOG_GROUP
33 #undef LOG_GROUP
34#endif
35#define LOG_GROUP LOG_GROUP_GUEST_CONTROL
36#include <VBox/log.h>
37
38
39
40int GuestFsObjData::FromLs(const GuestProcessStreamBlock &strmBlk)
41{
42 LogFlowFunc(("\n"));
43
44 int rc = VINF_SUCCESS;
45
46 try
47 {
48#ifdef DEBUG
49 strmBlk.DumpToLog();
50#endif
51 /* Object name. */
52 mName = strmBlk.GetString("name");
53 if (mName.isEmpty()) throw VERR_NOT_FOUND;
54 /* Type. */
55 Utf8Str strType(strmBlk.GetString("ftype"));
56 if (strType.equalsIgnoreCase("-"))
57 mType = FsObjType_File;
58 else if (strType.equalsIgnoreCase("d"))
59 mType = FsObjType_Directory;
60 /** @todo Add more types! */
61 else
62 mType = FsObjType_Undefined;
63 /* Object size. */
64 rc = strmBlk.GetInt64Ex("st_size", &mObjectSize);
65 if (RT_FAILURE(rc)) throw rc;
66 /** @todo Add complete ls info! */
67 }
68 catch (int rc2)
69 {
70 rc = rc2;
71 }
72
73 LogFlowFuncLeaveRC(rc);
74 return rc;
75}
76
77int GuestFsObjData::FromMkTemp(const GuestProcessStreamBlock &strmBlk)
78{
79 LogFlowFunc(("\n"));
80
81 int rc;
82
83 try
84 {
85#ifdef DEBUG
86 strmBlk.DumpToLog();
87#endif
88 /* Object name. */
89 mName = strmBlk.GetString("name");
90 if (mName.isEmpty()) throw VERR_NOT_FOUND;
91 /* Assign the stream block's rc. */
92 rc = strmBlk.GetRc();
93 }
94 catch (int rc2)
95 {
96 rc = rc2;
97 }
98
99 LogFlowFuncLeaveRC(rc);
100 return rc;
101}
102
103int GuestFsObjData::FromStat(const GuestProcessStreamBlock &strmBlk)
104{
105 LogFlowFunc(("\n"));
106
107 int rc = VINF_SUCCESS;
108
109 try
110 {
111#ifdef DEBUG
112 strmBlk.DumpToLog();
113#endif
114 /* Node ID, optional because we don't include this
115 * in older VBoxService (< 4.2) versions. */
116 mNodeID = strmBlk.GetInt64("node_id");
117 /* Object name. */
118 mName = strmBlk.GetString("name");
119 if (mName.isEmpty()) throw VERR_NOT_FOUND;
120 /* Type. */
121 Utf8Str strType(strmBlk.GetString("ftype"));
122 if (strType.equalsIgnoreCase("-"))
123 mType = FsObjType_File;
124 else if (strType.equalsIgnoreCase("d"))
125 mType = FsObjType_Directory;
126 /** @todo Add more types! */
127 else
128 mType = FsObjType_Undefined;
129 /* Object size. */
130 rc = strmBlk.GetInt64Ex("st_size", &mObjectSize);
131 if (RT_FAILURE(rc)) throw rc;
132 /** @todo Add complete stat info! */
133 }
134 catch (int rc2)
135 {
136 rc = rc2;
137 }
138
139 LogFlowFuncLeaveRC(rc);
140 return rc;
141}
142
143///////////////////////////////////////////////////////////////////////////////
144
145/** @todo *NOT* thread safe yet! */
146/** @todo Add exception handling for STL stuff! */
147
148GuestProcessStreamBlock::GuestProcessStreamBlock(void)
149{
150
151}
152
153/*
154GuestProcessStreamBlock::GuestProcessStreamBlock(const GuestProcessStreamBlock &otherBlock)
155{
156 for (GuestCtrlStreamPairsIter it = otherBlock.mPairs.begin();
157 it != otherBlock.end(); it++)
158 {
159 mPairs[it->first] = new
160 if (it->second.pszValue)
161 {
162 RTMemFree(it->second.pszValue);
163 it->second.pszValue = NULL;
164 }
165 }
166}*/
167
168GuestProcessStreamBlock::~GuestProcessStreamBlock()
169{
170 Clear();
171}
172
173/**
174 * Destroys the currently stored stream pairs.
175 *
176 * @return IPRT status code.
177 */
178void GuestProcessStreamBlock::Clear(void)
179{
180 mPairs.clear();
181}
182
183#ifdef DEBUG
184void GuestProcessStreamBlock::DumpToLog(void) const
185{
186 LogFlowFunc(("Dumping contents of stream block=0x%p (%ld items):\n",
187 this, mPairs.size()));
188
189 for (GuestCtrlStreamPairMapIterConst it = mPairs.begin();
190 it != mPairs.end(); it++)
191 {
192 LogFlowFunc(("\t%s=%s\n", it->first.c_str(), it->second.mValue.c_str()));
193 }
194}
195#endif
196
197/**
198 * Returns a 64-bit signed integer of a specified key.
199 *
200 * @return IPRT status code. VERR_NOT_FOUND if key was not found.
201 * @param pszKey Name of key to get the value for.
202 * @param piVal Pointer to value to return.
203 */
204int GuestProcessStreamBlock::GetInt64Ex(const char *pszKey, int64_t *piVal) const
205{
206 AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
207 AssertPtrReturn(piVal, VERR_INVALID_POINTER);
208 const char *pszValue = GetString(pszKey);
209 if (pszValue)
210 {
211 *piVal = RTStrToInt64(pszValue);
212 return VINF_SUCCESS;
213 }
214 return VERR_NOT_FOUND;
215}
216
217/**
218 * Returns a 64-bit integer of a specified key.
219 *
220 * @return int64_t Value to return, 0 if not found / on failure.
221 * @param pszKey Name of key to get the value for.
222 */
223int64_t GuestProcessStreamBlock::GetInt64(const char *pszKey) const
224{
225 int64_t iVal;
226 if (RT_SUCCESS(GetInt64Ex(pszKey, &iVal)))
227 return iVal;
228 return 0;
229}
230
231/**
232 * Returns the current number of stream pairs.
233 *
234 * @return uint32_t Current number of stream pairs.
235 */
236size_t GuestProcessStreamBlock::GetCount(void) const
237{
238 return mPairs.size();
239}
240
241/**
242 * Gets the return code (name = "rc") of this stream block.
243 *
244 * @return IPRT status code.
245 */
246int GuestProcessStreamBlock::GetRc(void) const
247{
248 const char *pszValue = GetString("rc");
249 if (pszValue)
250 {
251 return RTStrToInt16(pszValue);
252 }
253 return VERR_NOT_FOUND;
254}
255
256/**
257 * Returns a string value of a specified key.
258 *
259 * @return uint32_t Pointer to string to return, NULL if not found / on failure.
260 * @param pszKey Name of key to get the value for.
261 */
262const char* GuestProcessStreamBlock::GetString(const char *pszKey) const
263{
264 AssertPtrReturn(pszKey, NULL);
265
266 try
267 {
268 GuestCtrlStreamPairMapIterConst itPairs = mPairs.find(Utf8Str(pszKey));
269 if (itPairs != mPairs.end())
270 return itPairs->second.mValue.c_str();
271 }
272 catch (const std::exception &ex)
273 {
274 NOREF(ex);
275 }
276 return NULL;
277}
278
279/**
280 * Returns a 32-bit unsigned integer of a specified key.
281 *
282 * @return IPRT status code. VERR_NOT_FOUND if key was not found.
283 * @param pszKey Name of key to get the value for.
284 * @param puVal Pointer to value to return.
285 */
286int GuestProcessStreamBlock::GetUInt32Ex(const char *pszKey, uint32_t *puVal) const
287{
288 AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
289 AssertPtrReturn(puVal, VERR_INVALID_POINTER);
290 const char *pszValue = GetString(pszKey);
291 if (pszValue)
292 {
293 *puVal = RTStrToUInt32(pszValue);
294 return VINF_SUCCESS;
295 }
296 return VERR_NOT_FOUND;
297}
298
299/**
300 * Returns a 32-bit unsigned integer of a specified key.
301 *
302 * @return uint32_t Value to return, 0 if not found / on failure.
303 * @param pszKey Name of key to get the value for.
304 */
305uint32_t GuestProcessStreamBlock::GetUInt32(const char *pszKey) const
306{
307 uint32_t uVal;
308 if (RT_SUCCESS(GetUInt32Ex(pszKey, &uVal)))
309 return uVal;
310 return 0;
311}
312
313/**
314 * Sets a value to a key or deletes a key by setting a NULL value.
315 *
316 * @return IPRT status code.
317 * @param pszKey Key name to process.
318 * @param pszValue Value to set. Set NULL for deleting the key.
319 */
320int GuestProcessStreamBlock::SetValue(const char *pszKey, const char *pszValue)
321{
322 AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
323
324 int rc = VINF_SUCCESS;
325 try
326 {
327 Utf8Str Utf8Key(pszKey);
328
329 /* Take a shortcut and prevent crashes on some funny versions
330 * of STL if map is empty initially. */
331 if (!mPairs.empty())
332 {
333 GuestCtrlStreamPairMapIter it = mPairs.find(Utf8Key);
334 if (it != mPairs.end())
335 mPairs.erase(it);
336 }
337
338 if (pszValue)
339 {
340 GuestProcessStreamValue val(pszValue);
341 mPairs[Utf8Key] = val;
342 }
343 }
344 catch (const std::exception &ex)
345 {
346 NOREF(ex);
347 }
348 return rc;
349}
350
351///////////////////////////////////////////////////////////////////////////////
352
353GuestProcessStream::GuestProcessStream(void)
354 : m_cbAllocated(0),
355 m_cbSize(0),
356 m_cbOffset(0),
357 m_pbBuffer(NULL)
358{
359
360}
361
362GuestProcessStream::~GuestProcessStream(void)
363{
364 Destroy();
365}
366
367/**
368 * Adds data to the internal parser buffer. Useful if there
369 * are multiple rounds of adding data needed.
370 *
371 * @return IPRT status code.
372 * @param pbData Pointer to data to add.
373 * @param cbData Size (in bytes) of data to add.
374 */
375int GuestProcessStream::AddData(const BYTE *pbData, size_t cbData)
376{
377 AssertPtrReturn(pbData, VERR_INVALID_POINTER);
378 AssertReturn(cbData, VERR_INVALID_PARAMETER);
379
380 int rc = VINF_SUCCESS;
381
382 /* Rewind the buffer if it's empty. */
383 size_t cbInBuf = m_cbSize - m_cbOffset;
384 bool const fAddToSet = cbInBuf == 0;
385 if (fAddToSet)
386 m_cbSize = m_cbOffset = 0;
387
388 /* Try and see if we can simply append the data. */
389 if (cbData + m_cbSize <= m_cbAllocated)
390 {
391 memcpy(&m_pbBuffer[m_cbSize], pbData, cbData);
392 m_cbSize += cbData;
393 }
394 else
395 {
396 /* Move any buffered data to the front. */
397 cbInBuf = m_cbSize - m_cbOffset;
398 if (cbInBuf == 0)
399 m_cbSize = m_cbOffset = 0;
400 else if (m_cbOffset) /* Do we have something to move? */
401 {
402 memmove(m_pbBuffer, &m_pbBuffer[m_cbOffset], cbInBuf);
403 m_cbSize = cbInBuf;
404 m_cbOffset = 0;
405 }
406
407 /* Do we need to grow the buffer? */
408 if (cbData + m_cbSize > m_cbAllocated)
409 {
410 size_t cbAlloc = m_cbSize + cbData;
411 cbAlloc = RT_ALIGN_Z(cbAlloc, _64K);
412 void *pvNew = RTMemRealloc(m_pbBuffer, cbAlloc);
413 if (pvNew)
414 {
415 m_pbBuffer = (uint8_t *)pvNew;
416 m_cbAllocated = cbAlloc;
417 }
418 else
419 rc = VERR_NO_MEMORY;
420 }
421
422 /* Finally, copy the data. */
423 if (RT_SUCCESS(rc))
424 {
425 if (cbData + m_cbSize <= m_cbAllocated)
426 {
427 memcpy(&m_pbBuffer[m_cbSize], pbData, cbData);
428 m_cbSize += cbData;
429 }
430 else
431 rc = VERR_BUFFER_OVERFLOW;
432 }
433 }
434
435 return rc;
436}
437
438/**
439 * Destroys the internal data buffer.
440 */
441void GuestProcessStream::Destroy(void)
442{
443 if (m_pbBuffer)
444 {
445 RTMemFree(m_pbBuffer);
446 m_pbBuffer = NULL;
447 }
448
449 m_cbAllocated = 0;
450 m_cbSize = 0;
451 m_cbOffset = 0;
452}
453
454#ifdef DEBUG
455void GuestProcessStream::Dump(const char *pszFile)
456{
457 LogFlowFunc(("Dumping contents of stream=0x%p (cbAlloc=%u, cbSize=%u, cbOff=%u) to %s\n",
458 m_pbBuffer, m_cbAllocated, m_cbSize, m_cbOffset, pszFile));
459
460 RTFILE hFile;
461 int rc = RTFileOpen(&hFile, pszFile, RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE);
462 if (RT_SUCCESS(rc))
463 {
464 rc = RTFileWrite(hFile, m_pbBuffer, m_cbSize, NULL /* pcbWritten */);
465 RTFileClose(hFile);
466 }
467}
468#endif
469
470/**
471 * Tries to parse the next upcoming pair block within the internal
472 * buffer.
473 *
474 * Returns VERR_NO_DATA is no data is in internal buffer or buffer has been
475 * completely parsed already.
476 *
477 * Returns VERR_MORE_DATA if current block was parsed (with zero or more pairs
478 * stored in stream block) but still contains incomplete (unterminated)
479 * data.
480 *
481 * Returns VINF_SUCCESS if current block was parsed until the next upcoming
482 * block (with zero or more pairs stored in stream block).
483 *
484 * @return IPRT status code.
485 * @param streamBlock Reference to guest stream block to fill.
486 *
487 */
488int GuestProcessStream::ParseBlock(GuestProcessStreamBlock &streamBlock)
489{
490 if ( !m_pbBuffer
491 || !m_cbSize)
492 {
493 return VERR_NO_DATA;
494 }
495
496 AssertReturn(m_cbOffset <= m_cbSize, VERR_INVALID_PARAMETER);
497 if (m_cbOffset == m_cbSize)
498 return VERR_NO_DATA;
499
500 int rc = VINF_SUCCESS;
501
502 char *pszOff = (char*)&m_pbBuffer[m_cbOffset];
503 char *pszStart = pszOff;
504 uint32_t uDistance;
505 while (*pszStart)
506 {
507 size_t pairLen = strlen(pszStart);
508 uDistance = (pszStart - pszOff);
509 if (m_cbOffset + uDistance + pairLen + 1 >= m_cbSize)
510 {
511 rc = VERR_MORE_DATA;
512 break;
513 }
514 else
515 {
516 char *pszSep = strchr(pszStart, '=');
517 char *pszVal = NULL;
518 if (pszSep)
519 pszVal = pszSep + 1;
520 if (!pszSep || !pszVal)
521 {
522 rc = VERR_MORE_DATA;
523 break;
524 }
525
526 /* Terminate the separator so that we can
527 * use pszStart as our key from now on. */
528 *pszSep = '\0';
529
530 rc = streamBlock.SetValue(pszStart, pszVal);
531 if (RT_FAILURE(rc))
532 return rc;
533 }
534
535 /* Next pair. */
536 pszStart += pairLen + 1;
537 }
538
539 /* If we did not do any movement but we have stuff left
540 * in our buffer just skip the current termination so that
541 * we can try next time. */
542 uDistance = (pszStart - pszOff);
543 if ( !uDistance
544 && *pszStart == '\0'
545 && m_cbOffset < m_cbSize)
546 {
547 uDistance++;
548 }
549 m_cbOffset += uDistance;
550
551 return rc;
552}
553
554GuestBase::GuestBase(void)
555 : mConsole(NULL),
556 mNextContextID(0)
557{
558}
559
560GuestBase::~GuestBase(void)
561{
562}
563
564int GuestBase::baseInit(void)
565{
566 int rc = RTCritSectInit(&mWaitEventCritSect);
567
568 LogFlowFuncLeaveRC(rc);
569 return rc;
570}
571
572void GuestBase::baseUninit(void)
573{
574 LogFlowThisFuncEnter();
575
576 int rc = RTCritSectDelete(&mWaitEventCritSect);
577
578 LogFlowFuncLeaveRC(rc);
579 /* No return value. */
580}
581
582int GuestBase::cancelWaitEvents(void)
583{
584 LogFlowThisFuncEnter();
585
586 int rc = RTCritSectEnter(&mWaitEventCritSect);
587 if (RT_SUCCESS(rc))
588 {
589 GuestEventGroup::iterator itEventGroups = mWaitEventGroups.begin();
590 while (itEventGroups != mWaitEventGroups.end())
591 {
592 GuestWaitEvents::iterator itEvents = itEventGroups->second.begin();
593 while (itEvents != itEventGroups->second.end())
594 {
595 GuestWaitEvent *pEvent = itEvents->second;
596 AssertPtr(pEvent);
597
598 /*
599 * Just cancel the event, but don't remove it from the
600 * wait events map. Don't delete it though, this (hopefully)
601 * is done by the caller using unregisterWaitEvent().
602 */
603 int rc2 = pEvent->Cancel();
604 AssertRC(rc2);
605
606 itEvents++;
607 }
608
609 itEventGroups++;
610 }
611
612 int rc2 = RTCritSectLeave(&mWaitEventCritSect);
613 if (RT_SUCCESS(rc))
614 rc = rc2;
615 }
616
617 LogFlowFuncLeaveRC(rc);
618 return rc;
619}
620
621int GuestBase::dispatchGeneric(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
622{
623 LogFlowFunc(("pCtxCb=%p, pSvcCb=%p\n", pCtxCb, pSvcCb));
624
625 AssertPtrReturn(pCtxCb, VERR_INVALID_POINTER);
626 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
627
628 int vrc = VINF_SUCCESS;
629
630 try
631 {
632 LogFlowFunc(("uFunc=%RU32, cParms=%RU32\n",
633 pCtxCb->uFunction, pSvcCb->mParms));
634
635 switch (pCtxCb->uFunction)
636 {
637 case GUEST_MSG_PROGRESS_UPDATE:
638 break;
639
640 case GUEST_MSG_REPLY:
641 {
642 if (pSvcCb->mParms >= 3)
643 {
644 int idx = 1; /* Current parameter index. */
645 CALLBACKDATA_MSG_REPLY dataCb;
646 /* pSvcCb->mpaParms[0] always contains the context ID. */
647 vrc = pSvcCb->mpaParms[idx++].getUInt32(&dataCb.uType);
648 AssertRCReturn(vrc, vrc);
649 vrc = pSvcCb->mpaParms[idx++].getUInt32(&dataCb.rc);
650 AssertRCReturn(vrc, vrc);
651 vrc = pSvcCb->mpaParms[idx++].getPointer(&dataCb.pvPayload, &dataCb.cbPayload);
652 AssertRCReturn(vrc, vrc);
653
654 GuestWaitEventPayload evPayload(dataCb.uType, dataCb.pvPayload, dataCb.cbPayload);
655 int rc2 = signalWaitEventInternal(pCtxCb, dataCb.rc, &evPayload);
656 AssertRC(rc2);
657 }
658 else
659 vrc = VERR_INVALID_PARAMETER;
660 break;
661 }
662
663 default:
664 vrc = VERR_NOT_SUPPORTED;
665 break;
666 }
667 }
668 catch (std::bad_alloc)
669 {
670 vrc = VERR_NO_MEMORY;
671 }
672 catch (int rc)
673 {
674 vrc = rc;
675 }
676
677 LogFlowFuncLeaveRC(vrc);
678 return vrc;
679}
680
681int GuestBase::generateContextID(uint32_t uSessionID, uint32_t uObjectID, uint32_t *puContextID)
682{
683 AssertPtrReturn(puContextID, VERR_INVALID_POINTER);
684
685 if ( uSessionID >= VBOX_GUESTCTRL_MAX_SESSIONS
686 || uObjectID >= VBOX_GUESTCTRL_MAX_OBJECTS)
687 return VERR_INVALID_PARAMETER;
688
689 uint32_t uCount = ASMAtomicIncU32(&mNextContextID);
690 if (uCount == VBOX_GUESTCTRL_MAX_CONTEXTS)
691 uCount = 0;
692
693 uint32_t uNewContextID =
694 VBOX_GUESTCTRL_CONTEXTID_MAKE(uSessionID, uObjectID, uCount);
695
696 *puContextID = uNewContextID;
697
698#if 0
699 LogFlowThisFunc(("mNextContextID=%RU32, uSessionID=%RU32, uObjectID=%RU32, uCount=%RU32, uNewContextID=%RU32\n",
700 mNextContextID, uSessionID, uObjectID, uCount, uNewContextID));
701#endif
702 return VINF_SUCCESS;
703}
704
705int GuestBase::registerWaitEvent(uint32_t uSessionID, uint32_t uObjectID,
706 GuestWaitEvent **ppEvent)
707{
708 GuestEventTypes eventTypesEmpty;
709 return registerWaitEvent(uSessionID, uObjectID, eventTypesEmpty, ppEvent);
710}
711
712int GuestBase::registerWaitEvent(uint32_t uSessionID, uint32_t uObjectID,
713 const GuestEventTypes &lstEvents,
714 GuestWaitEvent **ppEvent)
715{
716 AssertPtrReturn(ppEvent, VERR_INVALID_POINTER);
717
718 uint32_t uContextID;
719 int rc = generateContextID(uSessionID, uObjectID, &uContextID);
720 if (RT_FAILURE(rc))
721 return rc;
722
723 rc = RTCritSectEnter(&mWaitEventCritSect);
724 if (RT_SUCCESS(rc))
725 {
726 try
727 {
728 GuestWaitEvent *pEvent = new GuestWaitEvent(uContextID, lstEvents);
729 AssertPtr(pEvent);
730
731 LogFlowThisFunc(("New event=%p, CID=%RU32\n", pEvent, uContextID));
732
733 /* Insert event into matching event group. This is for faster per-group
734 * lookup of all events later. */
735 for (GuestEventTypes::const_iterator itEvents = lstEvents.begin();
736 itEvents != lstEvents.end(); itEvents++)
737 {
738 mWaitEventGroups[(*itEvents)].insert(
739 std::pair<uint32_t, GuestWaitEvent*>(uContextID, pEvent));
740 /** @todo Check for key collision. */
741 }
742
743 /* Register event in regular event list. */
744 /** @todo Check for key collisions. */
745 mWaitEvents[uContextID] = pEvent;
746
747 *ppEvent = pEvent;
748 }
749 catch(std::bad_alloc &)
750 {
751 rc = VERR_NO_MEMORY;
752 }
753
754 int rc2 = RTCritSectLeave(&mWaitEventCritSect);
755 if (RT_SUCCESS(rc))
756 rc = rc2;
757 }
758
759 return rc;
760}
761
762int GuestBase::signalWaitEvent(VBoxEventType_T aType, IEvent *aEvent)
763{
764 int rc = RTCritSectEnter(&mWaitEventCritSect);
765#ifdef DEBUG
766 uint32_t cEvents = 0;
767#endif
768 if (RT_SUCCESS(rc))
769 {
770 GuestEventGroup::iterator itGroup = mWaitEventGroups.find(aType);
771 if (itGroup != mWaitEventGroups.end())
772 {
773 GuestWaitEvents::iterator itEvents = itGroup->second.begin();
774 while (itEvents != itGroup->second.end())
775 {
776#ifdef DEBUG
777 LogFlowThisFunc(("Signalling event=%p, type=%ld (CID %RU32: Session=%RU32, Object=%RU32, Count=%RU32) ...\n",
778 itEvents->second, aType, itEvents->first,
779 VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(itEvents->first),
780 VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(itEvents->first),
781 VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(itEvents->first)));
782#endif
783 ComPtr<IEvent> pThisEvent = aEvent;
784 Assert(!pThisEvent.isNull());
785 int rc2 = itEvents->second->SignalExternal(aEvent);
786 if (RT_SUCCESS(rc))
787 rc = rc2;
788
789 if (RT_SUCCESS(rc2))
790 {
791 /* Remove the event from all other event groups (except the
792 * original one!) because it was signalled. */
793 AssertPtr(itEvents->second);
794 const GuestEventTypes evTypes = itEvents->second->Types();
795 for (GuestEventTypes::const_iterator itType = evTypes.begin();
796 itType != evTypes.end(); itType++)
797 {
798 if ((*itType) != aType) /* Only remove all other groups. */
799 {
800 /* Get current event group. */
801 GuestEventGroup::iterator evGroup = mWaitEventGroups.find((*itType));
802 Assert(evGroup != mWaitEventGroups.end());
803
804 /* Lookup event in event group. */
805 GuestWaitEvents::iterator evEvent = evGroup->second.find(itEvents->first /* Context ID */);
806 Assert(evEvent != evGroup->second.end());
807
808 LogFlowThisFunc(("Removing event=%p (type %ld)\n", evEvent->second, (*itType)));
809 evGroup->second.erase(evEvent);
810
811 LogFlowThisFunc(("%zu events for type=%ld left\n",
812 evGroup->second.size(), aType));
813 }
814 }
815
816 /* Remove the event from the passed-in event group. */
817 itGroup->second.erase(itEvents++);
818 }
819 else
820 itEvents++;
821#ifdef DEBUG
822 cEvents++;
823#endif
824 }
825 }
826
827 int rc2 = RTCritSectLeave(&mWaitEventCritSect);
828 if (RT_SUCCESS(rc))
829 rc = rc2;
830 }
831
832#ifdef DEBUG
833 LogFlowThisFunc(("Signalled %RU32 events, rc=%Rrc\n", cEvents, rc));
834#endif
835 return rc;
836}
837
838int GuestBase::signalWaitEventInternal(PVBOXGUESTCTRLHOSTCBCTX pCbCtx,
839 int guestRc, const GuestWaitEventPayload *pPayload)
840{
841 if (RT_SUCCESS(guestRc))
842 return signalWaitEventInternalEx(pCbCtx, VINF_SUCCESS,
843 0 /* Guest rc */, pPayload);
844
845 return signalWaitEventInternalEx(pCbCtx, VERR_GSTCTL_GUEST_ERROR,
846 guestRc, pPayload);
847}
848
849int GuestBase::signalWaitEventInternalEx(PVBOXGUESTCTRLHOSTCBCTX pCbCtx,
850 int rc, int guestRc,
851 const GuestWaitEventPayload *pPayload)
852{
853 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
854 /* pPayload is optional. */
855
856 int rc2;
857 GuestWaitEvents::iterator itEvent = mWaitEvents.find(pCbCtx->uContextID);
858 if (itEvent != mWaitEvents.end())
859 {
860 LogFlowThisFunc(("Signalling event=%p (CID %RU32, rc=%Rrc, guestRc=%Rrc, pPayload=%p) ...\n",
861 itEvent->second, itEvent->first, rc, guestRc, pPayload));
862 GuestWaitEvent *pEvent = itEvent->second;
863 AssertPtr(pEvent);
864 rc2 = pEvent->SignalInternal(rc, guestRc, pPayload);
865 }
866 else
867 rc2 = VERR_NOT_FOUND;
868
869 return rc2;
870}
871
872void GuestBase::unregisterWaitEvent(GuestWaitEvent *pEvent)
873{
874 if (!pEvent) /* Nothing to unregister. */
875 return;
876
877 int rc = RTCritSectEnter(&mWaitEventCritSect);
878 if (RT_SUCCESS(rc))
879 {
880 LogFlowThisFunc(("pEvent=%p\n", pEvent));
881
882 const GuestEventTypes lstTypes = pEvent->Types();
883 for (GuestEventTypes::const_iterator itEvents = lstTypes.begin();
884 itEvents != lstTypes.end(); itEvents++)
885 {
886 /** @todo Slow O(n) lookup. Optimize this. */
887 GuestWaitEvents::iterator itCurEvent = mWaitEventGroups[(*itEvents)].begin();
888 while (itCurEvent != mWaitEventGroups[(*itEvents)].end())
889 {
890 if (itCurEvent->second == pEvent)
891 {
892 mWaitEventGroups[(*itEvents)].erase(itCurEvent++);
893 break;
894 }
895 else
896 itCurEvent++;
897 }
898 }
899
900 delete pEvent;
901 pEvent = NULL;
902
903 int rc2 = RTCritSectLeave(&mWaitEventCritSect);
904 if (RT_SUCCESS(rc))
905 rc = rc2;
906 }
907}
908
909/**
910 * Waits for a formerly registered guest event.
911 *
912 * @return IPRT status code.
913 * @param pEvent Pointer to event to wait for.
914 * @param uTimeoutMS Timeout (in ms) for waiting.
915 * @param pType Event type of following IEvent.
916 * Optional.
917 * @param ppEvent Pointer to IEvent which got triggered
918 * for this event. Optional.
919 */
920int GuestBase::waitForEvent(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
921 VBoxEventType_T *pType, IEvent **ppEvent)
922{
923 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
924 /* pType is optional. */
925 /* ppEvent is optional. */
926
927 int vrc = pEvent->Wait(uTimeoutMS);
928 if (RT_SUCCESS(vrc))
929 {
930 const ComPtr<IEvent> pThisEvent = pEvent->Event();
931 if (!pThisEvent.isNull()) /* Having a VBoxEventType_ event is optional. */
932 {
933 if (pType)
934 {
935 HRESULT hr = pThisEvent->COMGETTER(Type)(pType);
936 if (FAILED(hr))
937 vrc = VERR_COM_UNEXPECTED;
938 }
939 if ( RT_SUCCESS(vrc)
940 && ppEvent)
941 pThisEvent.queryInterfaceTo(ppEvent);
942
943 unconst(pThisEvent).setNull();
944 }
945 }
946
947 return vrc;
948}
949
950GuestObject::GuestObject(void)
951 : mSession(NULL),
952 mObjectID(0)
953{
954}
955
956GuestObject::~GuestObject(void)
957{
958}
959
960int GuestObject::bindToSession(Console *pConsole, GuestSession *pSession, uint32_t uObjectID)
961{
962 AssertPtrReturn(pConsole, VERR_INVALID_POINTER);
963 AssertPtrReturn(pSession, VERR_INVALID_POINTER);
964
965 mConsole = pConsole;
966 mSession = pSession;
967 mObjectID = uObjectID;
968
969 return VINF_SUCCESS;
970}
971
972int GuestObject::registerWaitEvent(const GuestEventTypes &lstEvents,
973 GuestWaitEvent **ppEvent)
974{
975 AssertPtr(mSession);
976 return GuestBase::registerWaitEvent(mSession->i_getId(), mObjectID, lstEvents, ppEvent);
977}
978
979int GuestObject::sendCommand(uint32_t uFunction,
980 uint32_t uParms, PVBOXHGCMSVCPARM paParms)
981{
982#ifndef VBOX_GUESTCTRL_TEST_CASE
983 ComObjPtr<Console> pConsole = mConsole;
984 Assert(!pConsole.isNull());
985
986 int vrc = VERR_HGCM_SERVICE_NOT_FOUND;
987
988 /* Forward the information to the VMM device. */
989 VMMDev *pVMMDev = pConsole->i_getVMMDev();
990 if (pVMMDev)
991 {
992 LogFlowThisFunc(("uFunction=%RU32, uParms=%RU32\n", uFunction, uParms));
993 vrc = pVMMDev->hgcmHostCall(HGCMSERVICE_NAME, uFunction, uParms, paParms);
994 if (RT_FAILURE(vrc))
995 {
996 /** @todo What to do here? */
997 }
998 }
999#else
1000 LogFlowThisFuncEnter();
1001
1002 /* Not needed within testcases. */
1003 int vrc = VINF_SUCCESS;
1004#endif
1005 return vrc;
1006}
1007
1008GuestWaitEventBase::GuestWaitEventBase(void)
1009 : mfAborted(false),
1010 mCID(0),
1011 mEventSem(NIL_RTSEMEVENT),
1012 mRc(VINF_SUCCESS),
1013 mGuestRc(VINF_SUCCESS)
1014{
1015}
1016
1017GuestWaitEventBase::~GuestWaitEventBase(void)
1018{
1019 if (mEventSem != NIL_RTSEMEVENT)
1020 {
1021 RTSemEventDestroy(mEventSem);
1022 mEventSem = NIL_RTSEMEVENT;
1023 }
1024}
1025
1026int GuestWaitEventBase::Init(uint32_t uCID)
1027{
1028 mCID = uCID;
1029
1030 return RTSemEventCreate(&mEventSem);
1031}
1032
1033int GuestWaitEventBase::SignalInternal(int rc, int guestRc,
1034 const GuestWaitEventPayload *pPayload)
1035{
1036 if (ASMAtomicReadBool(&mfAborted))
1037 return VERR_CANCELLED;
1038
1039#ifdef VBOX_STRICT
1040 if (rc == VERR_GSTCTL_GUEST_ERROR)
1041 AssertMsg(RT_FAILURE(guestRc), ("Guest error indicated but no actual guest error set (%Rrc)\n", guestRc));
1042 else
1043 AssertMsg(RT_SUCCESS(guestRc), ("No guest error indicated but actual guest error set (%Rrc)\n", guestRc));
1044#endif
1045
1046 int rc2;
1047 if (pPayload)
1048 rc2 = mPayload.CopyFromDeep(*pPayload);
1049 else
1050 rc2 = VINF_SUCCESS;
1051 if (RT_SUCCESS(rc2))
1052 {
1053 mRc = rc;
1054 mGuestRc = guestRc;
1055
1056 rc2 = RTSemEventSignal(mEventSem);
1057 }
1058
1059 return rc2;
1060}
1061
1062int GuestWaitEventBase::Wait(RTMSINTERVAL uTimeoutMS)
1063{
1064 int rc = VINF_SUCCESS;
1065
1066 if (ASMAtomicReadBool(&mfAborted))
1067 rc = VERR_CANCELLED;
1068
1069 if (RT_SUCCESS(rc))
1070 {
1071 AssertReturn(mEventSem != NIL_RTSEMEVENT, VERR_CANCELLED);
1072
1073 RTMSINTERVAL msInterval = uTimeoutMS;
1074 if (!uTimeoutMS)
1075 msInterval = RT_INDEFINITE_WAIT;
1076 rc = RTSemEventWait(mEventSem, msInterval);
1077 if (ASMAtomicReadBool(&mfAborted))
1078 rc = VERR_CANCELLED;
1079 if (RT_SUCCESS(rc))
1080 {
1081 /* If waiting succeeded, return the overall
1082 * result code. */
1083 rc = mRc;
1084 }
1085 }
1086
1087 return rc;
1088}
1089
1090GuestWaitEvent::GuestWaitEvent(uint32_t uCID,
1091 const GuestEventTypes &lstEvents)
1092{
1093 int rc2 = Init(uCID);
1094 AssertRC(rc2); /** @todo Throw exception here. */
1095
1096 mEventTypes = lstEvents;
1097}
1098
1099GuestWaitEvent::GuestWaitEvent(uint32_t uCID)
1100{
1101 int rc2 = Init(uCID);
1102 AssertRC(rc2); /** @todo Throw exception here. */
1103}
1104
1105GuestWaitEvent::~GuestWaitEvent(void)
1106{
1107
1108}
1109
1110/**
1111 * Cancels the event.
1112 */
1113int GuestWaitEvent::Cancel(void)
1114{
1115 AssertReturn(!mfAborted, VERR_CANCELLED);
1116 ASMAtomicWriteBool(&mfAborted, true);
1117
1118#ifdef DEBUG_andy
1119 LogFlowThisFunc(("Cancelling %p ...\n"));
1120#endif
1121 return RTSemEventSignal(mEventSem);
1122}
1123
1124int GuestWaitEvent::Init(uint32_t uCID)
1125{
1126 return GuestWaitEventBase::Init(uCID);
1127}
1128
1129/**
1130 * Signals the event.
1131 *
1132 * @return IPRT status code.
1133 * @param pEvent Public IEvent to associate.
1134 * Optional.
1135 */
1136int GuestWaitEvent::SignalExternal(IEvent *pEvent)
1137{
1138 AssertReturn(mEventSem != NIL_RTSEMEVENT, VERR_CANCELLED);
1139
1140 if (pEvent)
1141 mEvent = pEvent;
1142
1143 return RTSemEventSignal(mEventSem);
1144}
1145
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