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
RevLine 
[38085]1/* $Id: GuestCtrlPrivate.cpp 67914 2017-07-11 20:46:37Z vboxsync $ */
2/** @file
[42160]3 * Internal helpers/structures for guest control functionality.
[38085]4 */
5
6/*
[66857]7 * Copyright (C) 2011-2017 Oracle Corporation
[38085]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
[57372]18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
[67914]22#define LOG_GROUP LOG_GROUP_GUEST_CONTROL
23#include "LoggingNew.h"
24
[55644]25#ifndef VBOX_WITH_GUEST_CONTROL
26# error "VBOX_WITH_GUEST_CONTROL must defined in this file"
27#endif
[38085]28#include "GuestCtrlImplPrivate.h"
[44863]29#include "GuestSessionImpl.h"
30#include "VMMDev.h"
[42194]31
[42214]32#include <iprt/asm.h>
[47469]33#include <iprt/cpp/utils.h> /* For unconst(). */
[42194]34#include <iprt/ctype.h>
[39843]35#ifdef DEBUG
36# include <iprt/file.h>
37#endif /* DEBUG */
[38085]38
[42897]39
[38085]40
[42673]41int GuestFsObjData::FromLs(const GuestProcessStreamBlock &strmBlk)
[42530]42{
[42674]43 LogFlowFunc(("\n"));
[42673]44
[42530]45 int rc = VINF_SUCCESS;
46
47 try
48 {
[42673]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. */
[42530]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
[55611]63 mType = FsObjType_Unknown;
[42673]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 }
[42530]73
[42673]74 LogFlowFuncLeaveRC(rc);
75 return rc;
76}
77
[49948]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
[42673]104int GuestFsObjData::FromStat(const GuestProcessStreamBlock &strmBlk)
105{
[42674]106 LogFlowFunc(("\n"));
[42673]107
108 int rc = VINF_SUCCESS;
109
110 try
111 {
112#ifdef DEBUG
113 strmBlk.DumpToLog();
114#endif
[42716]115 /* Node ID, optional because we don't include this
116 * in older VBoxService (< 4.2) versions. */
117 mNodeID = strmBlk.GetInt64("node_id");
[42673]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
[55611]129 mType = FsObjType_Unknown;
[42673]130 /* Object size. */
[42530]131 rc = strmBlk.GetInt64Ex("st_size", &mObjectSize);
132 if (RT_FAILURE(rc)) throw rc;
[42673]133 /** @todo Add complete stat info! */
[42530]134 }
135 catch (int rc2)
136 {
137 rc = rc2;
138 }
139
[42673]140 LogFlowFuncLeaveRC(rc);
[42530]141 return rc;
142}
143
[42171]144///////////////////////////////////////////////////////////////////////////////
145
[38085]146/** @todo *NOT* thread safe yet! */
[38269]147/** @todo Add exception handling for STL stuff! */
[38085]148
[42160]149GuestProcessStreamBlock::GuestProcessStreamBlock(void)
[38085]150{
151
152}
153
[38395]154/*
155GuestProcessStreamBlock::GuestProcessStreamBlock(const GuestProcessStreamBlock &otherBlock)
156{
[44863]157 for (GuestCtrlStreamPairsIter it = otherBlock.mPairs.begin();
[55769]158 it != otherBlock.end(); ++it)
[38395]159 {
[44863]160 mPairs[it->first] = new
[38395]161 if (it->second.pszValue)
162 {
163 RTMemFree(it->second.pszValue);
164 it->second.pszValue = NULL;
165 }
166 }
167}*/
168
[38269]169GuestProcessStreamBlock::~GuestProcessStreamBlock()
[38085]170{
[38269]171 Clear();
[38085]172}
173
[38235]174/**
175 * Destroys the currently stored stream pairs.
176 *
177 * @return IPRT status code.
178 */
[42530]179void GuestProcessStreamBlock::Clear(void)
[38085]180{
[44863]181 mPairs.clear();
[38085]182}
183
[39843]184#ifdef DEBUG
[42673]185void GuestProcessStreamBlock::DumpToLog(void) const
[39843]186{
187 LogFlowFunc(("Dumping contents of stream block=0x%p (%ld items):\n",
[44863]188 this, mPairs.size()));
[39843]189
[44863]190 for (GuestCtrlStreamPairMapIterConst it = mPairs.begin();
[55769]191 it != mPairs.end(); ++it)
[39843]192 {
193 LogFlowFunc(("\t%s=%s\n", it->first.c_str(), it->second.mValue.c_str()));
194 }
195}
196#endif
197
[38085]198/**
[38235]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 */
[42530]205int GuestProcessStreamBlock::GetInt64Ex(const char *pszKey, int64_t *piVal) const
[38085]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 */
[42530]224int64_t GuestProcessStreamBlock::GetInt64(const char *pszKey) const
[38085]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 */
[42530]237size_t GuestProcessStreamBlock::GetCount(void) const
[38085]238{
[44863]239 return mPairs.size();
[38085]240}
241
[38210]242/**
[49948]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/**
[38235]258 * Returns a string value of a specified key.
[38210]259 *
[38235]260 * @return uint32_t Pointer to string to return, NULL if not found / on failure.
[38210]261 * @param pszKey Name of key to get the value for.
262 */
[42530]263const char* GuestProcessStreamBlock::GetString(const char *pszKey) const
[38210]264{
265 AssertPtrReturn(pszKey, NULL);
[38085]266
[38210]267 try
[38085]268 {
[44863]269 GuestCtrlStreamPairMapIterConst itPairs = mPairs.find(Utf8Str(pszKey));
270 if (itPairs != mPairs.end())
[38395]271 return itPairs->second.mValue.c_str();
[38085]272 }
[38210]273 catch (const std::exception &ex)
[38085]274 {
[38210]275 NOREF(ex);
276 }
277 return NULL;
278}
[38085]279
[38235]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 */
[42530]287int GuestProcessStreamBlock::GetUInt32Ex(const char *pszKey, uint32_t *puVal) const
[38210]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;
[38085]296 }
[38210]297 return VERR_NOT_FOUND;
298}
[38085]299
[38210]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 */
[42530]306uint32_t GuestProcessStreamBlock::GetUInt32(const char *pszKey) const
[38210]307{
308 uint32_t uVal;
309 if (RT_SUCCESS(GetUInt32Ex(pszKey, &uVal)))
310 return uVal;
311 return 0;
[38085]312}
313
[38235]314/**
[38269]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;
[38395]326 try
[38269]327 {
[38395]328 Utf8Str Utf8Key(pszKey);
329
330 /* Take a shortcut and prevent crashes on some funny versions
331 * of STL if map is empty initially. */
[44863]332 if (!mPairs.empty())
[38269]333 {
[44863]334 GuestCtrlStreamPairMapIter it = mPairs.find(Utf8Key);
335 if (it != mPairs.end())
336 mPairs.erase(it);
[38269]337 }
[38395]338
339 if (pszValue)
340 {
[39843]341 GuestProcessStreamValue val(pszValue);
[44863]342 mPairs[Utf8Key] = val;
[38395]343 }
[38269]344 }
[38395]345 catch (const std::exception &ex)
346 {
347 NOREF(ex);
348 }
[38269]349 return rc;
350}
351
352///////////////////////////////////////////////////////////////////////////////
353
[42160]354GuestProcessStream::GuestProcessStream(void)
[38269]355 : m_cbAllocated(0),
[63154]356 m_cbUsed(0),
357 m_offBuffer(0),
[38269]358 m_pbBuffer(NULL)
359{
360
361}
362
[42160]363GuestProcessStream::~GuestProcessStream(void)
[38269]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. */
[63154]384 size_t cbInBuf = m_cbUsed - m_offBuffer;
[38269]385 bool const fAddToSet = cbInBuf == 0;
386 if (fAddToSet)
[63154]387 m_cbUsed = m_offBuffer = 0;
[38269]388
389 /* Try and see if we can simply append the data. */
[63154]390 if (cbData + m_cbUsed <= m_cbAllocated)
[38269]391 {
[63154]392 memcpy(&m_pbBuffer[m_cbUsed], pbData, cbData);
393 m_cbUsed += cbData;
[38269]394 }
395 else
396 {
397 /* Move any buffered data to the front. */
[63154]398 cbInBuf = m_cbUsed - m_offBuffer;
[38269]399 if (cbInBuf == 0)
[63154]400 m_cbUsed = m_offBuffer = 0;
401 else if (m_offBuffer) /* Do we have something to move? */
[38269]402 {
[63154]403 memmove(m_pbBuffer, &m_pbBuffer[m_offBuffer], cbInBuf);
404 m_cbUsed = cbInBuf;
405 m_offBuffer = 0;
[38269]406 }
407
408 /* Do we need to grow the buffer? */
[63154]409 if (cbData + m_cbUsed > m_cbAllocated)
[38269]410 {
[63154]411/** @todo Put an upper limit on the allocation? */
412 size_t cbAlloc = m_cbUsed + cbData;
[38269]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 {
[63154]427 if (cbData + m_cbUsed <= m_cbAllocated)
[38269]428 {
[63154]429 memcpy(&m_pbBuffer[m_cbUsed], pbData, cbData);
430 m_cbUsed += cbData;
[38269]431 }
432 else
433 rc = VERR_BUFFER_OVERFLOW;
434 }
435 }
436
437 return rc;
438}
439
440/**
[41783]441 * Destroys the internal data buffer.
[38269]442 */
[42160]443void GuestProcessStream::Destroy(void)
[38269]444{
445 if (m_pbBuffer)
446 {
447 RTMemFree(m_pbBuffer);
448 m_pbBuffer = NULL;
449 }
450
451 m_cbAllocated = 0;
[63154]452 m_cbUsed = 0;
453 m_offBuffer = 0;
[38269]454}
455
[39843]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",
[63154]460 m_pbBuffer, m_cbAllocated, m_cbUsed, m_offBuffer, pszFile));
[39843]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 {
[63154]466 rc = RTFileWrite(hFile, m_pbBuffer, m_cbUsed, NULL /* pcbWritten */);
[39843]467 RTFileClose(hFile);
468 }
469}
470#endif
471
[38269]472/**
[38395]473 * Tries to parse the next upcoming pair block within the internal
474 * buffer.
[38235]475 *
[38395]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 *
[38235]489 */
[38269]490int GuestProcessStream::ParseBlock(GuestProcessStreamBlock &streamBlock)
[38085]491{
[38395]492 if ( !m_pbBuffer
[63154]493 || !m_cbUsed)
[38395]494 {
495 return VERR_NO_DATA;
496 }
497
[63154]498 AssertReturn(m_offBuffer <= m_cbUsed, VERR_INVALID_PARAMETER);
499 if (m_offBuffer == m_cbUsed)
[38395]500 return VERR_NO_DATA;
[38085]501
502 int rc = VINF_SUCCESS;
503
[63154]504 char *pszOff = (char*)&m_pbBuffer[m_offBuffer];
[39791]505 char *pszStart = pszOff;
506 uint32_t uDistance;
[38395]507 while (*pszStart)
[38085]508 {
[38395]509 size_t pairLen = strlen(pszStart);
[39791]510 uDistance = (pszStart - pszOff);
[63154]511 if (m_offBuffer + uDistance + pairLen + 1 >= m_cbUsed)
[38085]512 {
[38395]513 rc = VERR_MORE_DATA;
514 break;
[38085]515 }
[38395]516 else
[38085]517 {
[38395]518 char *pszSep = strchr(pszStart, '=');
519 char *pszVal = NULL;
520 if (pszSep)
521 pszVal = pszSep + 1;
522 if (!pszSep || !pszVal)
[38085]523 {
524 rc = VERR_MORE_DATA;
[38395]525 break;
[38085]526 }
527
[38395]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);
[38085]533 if (RT_FAILURE(rc))
[38395]534 return rc;
[38085]535 }
536
[38395]537 /* Next pair. */
538 pszStart += pairLen + 1;
[38085]539 }
540
[38395]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. */
[39791]544 uDistance = (pszStart - pszOff);
[38395]545 if ( !uDistance
546 && *pszStart == '\0'
[63154]547 && m_offBuffer < m_cbUsed)
[38395]548 {
549 uDistance++;
550 }
[63154]551 m_offBuffer += uDistance;
[38085]552
553 return rc;
554}
555
[45415]556GuestBase::GuestBase(void)
557 : mConsole(NULL),
558 mNextContextID(0)
[44863]559{
[45415]560}
[44863]561
[45415]562GuestBase::~GuestBase(void)
563{
[44863]564}
565
[47469]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);
[63258]579 NOREF(rc);
[47469]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 {
[49349]592 GuestEventGroup::iterator itEventGroups = mWaitEventGroups.begin();
593 while (itEventGroups != mWaitEventGroups.end())
[47469]594 {
[49349]595 GuestWaitEvents::iterator itEvents = itEventGroups->second.begin();
596 while (itEvents != itEventGroups->second.end())
[47469]597 {
[49349]598 GuestWaitEvent *pEvent = itEvents->second;
[47469]599 AssertPtr(pEvent);
600
601 /*
[49349]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().
[47469]605 */
[49349]606 int rc2 = pEvent->Cancel();
[47469]607 AssertRC(rc2);
[49349]608
[56030]609 ++itEvents;
[47469]610 }
611
[56030]612 ++itEventGroups;
[47469]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
[49349]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
[45415]684int GuestBase::generateContextID(uint32_t uSessionID, uint32_t uObjectID, uint32_t *puContextID)
[44863]685{
[45415]686 AssertPtrReturn(puContextID, VERR_INVALID_POINTER);
[44863]687
[47627]688 if ( uSessionID >= VBOX_GUESTCTRL_MAX_SESSIONS
689 || uObjectID >= VBOX_GUESTCTRL_MAX_OBJECTS)
690 return VERR_INVALID_PARAMETER;
691
[47469]692 uint32_t uCount = ASMAtomicIncU32(&mNextContextID);
[45415]693 if (uCount == VBOX_GUESTCTRL_MAX_CONTEXTS)
694 uCount = 0;
[44863]695
[45415]696 uint32_t uNewContextID =
697 VBOX_GUESTCTRL_CONTEXTID_MAKE(uSessionID, uObjectID, uCount);
[44863]698
[45415]699 *puContextID = uNewContextID;
[45571]700
[49440]701#if 0
[47627]702 LogFlowThisFunc(("mNextContextID=%RU32, uSessionID=%RU32, uObjectID=%RU32, uCount=%RU32, uNewContextID=%RU32\n",
703 mNextContextID, uSessionID, uObjectID, uCount, uNewContextID));
[49440]704#endif
[45571]705 return VINF_SUCCESS;
[44863]706}
707
[47469]708int GuestBase::registerWaitEvent(uint32_t uSessionID, uint32_t uObjectID,
709 GuestWaitEvent **ppEvent)
[45780]710{
[49349]711 GuestEventTypes eventTypesEmpty;
712 return registerWaitEvent(uSessionID, uObjectID, eventTypesEmpty, ppEvent);
713}
714
[66857]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 */
[49349]730int GuestBase::registerWaitEvent(uint32_t uSessionID, uint32_t uObjectID,
731 const GuestEventTypes &lstEvents,
732 GuestWaitEvent **ppEvent)
733{
[45780]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
[49440]749 LogFlowThisFunc(("New event=%p, CID=%RU32\n", pEvent, uContextID));
750
[49349]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();
[56030]754 itEvents != lstEvents.end(); ++itEvents)
[45780]755 {
[66857]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 }
[45780]769 }
770
[66857]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 }
[49349]781
[66857]782 if (RT_SUCCESS(rc))
783 *ppEvent = pEvent;
[45780]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
[49349]798int GuestBase::signalWaitEvent(VBoxEventType_T aType, IEvent *aEvent)
[45780]799{
800 int rc = RTCritSectEnter(&mWaitEventCritSect);
[49349]801#ifdef DEBUG
802 uint32_t cEvents = 0;
803#endif
[45780]804 if (RT_SUCCESS(rc))
805 {
[49440]806 GuestEventGroup::iterator itGroup = mWaitEventGroups.find(aType);
807 if (itGroup != mWaitEventGroups.end())
[45780]808 {
[49440]809 GuestWaitEvents::iterator itEvents = itGroup->second.begin();
810 while (itEvents != itGroup->second.end())
[45780]811 {
[49349]812#ifdef DEBUG
[49440]813 LogFlowThisFunc(("Signalling event=%p, type=%ld (CID %RU32: Session=%RU32, Object=%RU32, Count=%RU32) ...\n",
[49349]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
[45780]819 ComPtr<IEvent> pThisEvent = aEvent;
820 Assert(!pThisEvent.isNull());
[49349]821 int rc2 = itEvents->second->SignalExternal(aEvent);
[45780]822 if (RT_SUCCESS(rc))
823 rc = rc2;
[49440]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();
[56030]832 itType != evTypes.end(); ++itType)
[49440]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. */
[66900]853 GuestWaitEvents::iterator itEventsNext = itEvents;
854 ++itEventsNext;
[66896]855 itGroup->second.erase(itEvents);
[66900]856 itEvents = itEventsNext;
[49440]857 }
858 else
[66894]859 ++itEvents;
[49349]860#ifdef DEBUG
861 cEvents++;
862#endif
[45780]863 }
864 }
865
866 int rc2 = RTCritSectLeave(&mWaitEventCritSect);
867 if (RT_SUCCESS(rc))
868 rc = rc2;
869 }
870
[49349]871#ifdef DEBUG
872 LogFlowThisFunc(("Signalled %RU32 events, rc=%Rrc\n", cEvents, rc));
873#endif
[45780]874 return rc;
875}
876
[49349]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
[66857]895 int rc2 = RTCritSectEnter(&mWaitEventCritSect);
896 if (RT_SUCCESS(rc2))
[49349]897 {
[66857]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;
[49349]913 }
914
915 return rc2;
916}
917
[66857]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)
[45780]927{
[47469]928 if (!pEvent) /* Nothing to unregister. */
[66857]929 return VINF_SUCCESS;
[45780]930
931 int rc = RTCritSectEnter(&mWaitEventCritSect);
932 if (RT_SUCCESS(rc))
933 {
[49440]934 LogFlowThisFunc(("pEvent=%p\n", pEvent));
935
[66857]936 try
[45780]937 {
[66857]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)
[45780]942 {
[66857]943 /** @todo Slow O(n) lookup. Optimize this. */
944 GuestWaitEvents::iterator itCurEvent = mWaitEventGroups[(*itType)].begin();
945 while (itCurEvent != mWaitEventGroups[(*itType)].end())
[49350]946 {
[66857]947 if (itCurEvent->second == pEvent)
948 {
[66896]949 mWaitEventGroups[(*itType)].erase(itCurEvent);
[66857]950 break;
951 }
952 else
[66894]953 ++itCurEvent;
[49350]954 }
[45780]955 }
[66857]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;
[45780]967 }
[66857]968 catch (const std::exception &ex)
969 {
970 NOREF(ex);
971 AssertFailedStmt(rc = VERR_NOT_FOUND);
972 }
[45780]973
974 int rc2 = RTCritSectLeave(&mWaitEventCritSect);
975 if (RT_SUCCESS(rc))
976 rc = rc2;
977 }
[66857]978
979 return rc;
[45780]980}
981
[49349]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 */
[45780]993int GuestBase::waitForEvent(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
994 VBoxEventType_T *pType, IEvent **ppEvent)
995{
996 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
[49349]997 /* pType is optional. */
998 /* ppEvent is optional. */
[45780]999
1000 int vrc = pEvent->Wait(uTimeoutMS);
1001 if (RT_SUCCESS(vrc))
1002 {
1003 const ComPtr<IEvent> pThisEvent = pEvent->Event();
[49349]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);
[45780]1015
[49349]1016 unconst(pThisEvent).setNull();
[45780]1017 }
1018 }
1019
1020 return vrc;
1021}
1022
[45415]1023GuestObject::GuestObject(void)
1024 : mSession(NULL),
1025 mObjectID(0)
[45109]1026{
1027}
1028
[45415]1029GuestObject::~GuestObject(void)
[44863]1030{
1031}
1032
[45415]1033int GuestObject::bindToSession(Console *pConsole, GuestSession *pSession, uint32_t uObjectID)
[44863]1034{
[45415]1035 AssertPtrReturn(pConsole, VERR_INVALID_POINTER);
1036 AssertPtrReturn(pSession, VERR_INVALID_POINTER);
[44863]1037
[45415]1038 mConsole = pConsole;
1039 mSession = pSession;
1040 mObjectID = uObjectID;
[44863]1041
[45415]1042 return VINF_SUCCESS;
[44863]1043}
1044
[49349]1045int GuestObject::registerWaitEvent(const GuestEventTypes &lstEvents,
[47469]1046 GuestWaitEvent **ppEvent)
[45780]1047{
1048 AssertPtr(mSession);
[50727]1049 return GuestBase::registerWaitEvent(mSession->i_getId(), mObjectID, lstEvents, ppEvent);
[45780]1050}
1051
[44863]1052int GuestObject::sendCommand(uint32_t uFunction,
[63258]1053 uint32_t cParms, PVBOXHGCMSVCPARM paParms)
[44863]1054{
1055#ifndef VBOX_GUESTCTRL_TEST_CASE
[45415]1056 ComObjPtr<Console> pConsole = mConsole;
[44863]1057 Assert(!pConsole.isNull());
1058
[47627]1059 int vrc = VERR_HGCM_SERVICE_NOT_FOUND;
1060
[44863]1061 /* Forward the information to the VMM device. */
[51612]1062 VMMDev *pVMMDev = pConsole->i_getVMMDev();
[47627]1063 if (pVMMDev)
[44863]1064 {
[63258]1065 LogFlowThisFunc(("uFunction=%RU32, cParms=%RU32\n", uFunction, cParms));
1066 vrc = pVMMDev->hgcmHostCall(HGCMSERVICE_NAME, uFunction, cParms, paParms);
[47627]1067 if (RT_FAILURE(vrc))
1068 {
1069 /** @todo What to do here? */
1070 }
[44863]1071 }
1072#else
[47627]1073 LogFlowThisFuncEnter();
1074
[44863]1075 /* Not needed within testcases. */
[63258]1076 RT_NOREF(uFunction, cParms, paParms);
[44863]1077 int vrc = VINF_SUCCESS;
1078#endif
1079 return vrc;
1080}
1081
[49349]1082GuestWaitEventBase::GuestWaitEventBase(void)
[49350]1083 : mfAborted(false),
1084 mCID(0),
[49349]1085 mEventSem(NIL_RTSEMEVENT),
1086 mRc(VINF_SUCCESS),
1087 mGuestRc(VINF_SUCCESS)
[45780]1088{
1089}
1090
[49349]1091GuestWaitEventBase::~GuestWaitEventBase(void)
[45780]1092{
[52981]1093 if (mEventSem != NIL_RTSEMEVENT)
1094 {
1095 RTSemEventDestroy(mEventSem);
1096 mEventSem = NIL_RTSEMEVENT;
1097 }
[45780]1098}
1099
[49349]1100int GuestWaitEventBase::Init(uint32_t uCID)
[45780]1101{
[49349]1102 mCID = uCID;
[45780]1103
[49349]1104 return RTSemEventCreate(&mEventSem);
1105}
1106
1107int GuestWaitEventBase::SignalInternal(int rc, int guestRc,
1108 const GuestWaitEventPayload *pPayload)
1109{
[49440]1110 if (ASMAtomicReadBool(&mfAborted))
1111 return VERR_CANCELLED;
[49349]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));
[47469]1116 else
[49349]1117 AssertMsg(RT_SUCCESS(guestRc), ("No guest error indicated but actual guest error set (%Rrc)\n", guestRc));
1118#endif
[45780]1119
[49349]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;
[45780]1134}
1135
[49349]1136int GuestWaitEventBase::Wait(RTMSINTERVAL uTimeoutMS)
[45780]1137{
[47469]1138 int rc = VINF_SUCCESS;
[45780]1139
[49349]1140 if (ASMAtomicReadBool(&mfAborted))
[47469]1141 rc = VERR_CANCELLED;
[45780]1142
[47469]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);
[49349]1151 if (ASMAtomicReadBool(&mfAborted))
[47469]1152 rc = VERR_CANCELLED;
[49349]1153 if (RT_SUCCESS(rc))
1154 {
1155 /* If waiting succeeded, return the overall
1156 * result code. */
1157 rc = mRc;
1158 }
[47469]1159 }
1160
[45780]1161 return rc;
1162}
1163
[49349]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
[49440]1192#ifdef DEBUG_andy
1193 LogFlowThisFunc(("Cancelling %p ...\n"));
1194#endif
[49349]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