VirtualBox

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

Last change on this file since 62598 was 62485, checked in by vboxsync, 8 years ago

(C) 2016

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