VirtualBox

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

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

src-client: Define LOG_GROUP according to interface or similar.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use