VirtualBox

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

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

Main: it++ => ++it

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