VirtualBox

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

最後變更 在這個檔案從55640是 55611,由 vboxsync 提交於 10 年 前

Main: Merged the VFSFileType and FsObjType enums, keeping the 'FsObjType' name while picking the values and most of the names from VFSFileType (because they make more sense to someone who came up with the RTFS_TYPE_XXX and RTDIRENTRYTYPE_XXX bits). VFSFileType used 'SymLink', that's not 'Symlink' in keeping with the rest of the API and IPRT.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 31.0 KB
 
1/* $Id: GuestCtrlPrivate.cpp 55611 2015-05-03 01:31:34Z 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.alldomusa.eu.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_Unknown;
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_Unknown;
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
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette