VirtualBox

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

Last change on this file since 45234 was 45109, checked in by vboxsync, 12 years ago

GuestCtrl: More stuff for IGuestFile and IGuestSession handling (work in progress).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.7 KB
Line 
1/* $Id: GuestCtrlPrivate.cpp 45109 2013-03-20 16:41:00Z vboxsync $ */
2/** @file
3 *
4 * Internal helpers/structures for guest control functionality.
5 */
6
7/*
8 * Copyright (C) 2011-2013 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19/******************************************************************************
20 * Header Files *
21 ******************************************************************************/
22#include "GuestCtrlImplPrivate.h"
23#include "GuestSessionImpl.h"
24#include "VMMDev.h"
25
26#include <iprt/asm.h>
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 * Structures and Typedefs *
40 ******************************************************************************/
41
42GuestCtrlEvent::GuestCtrlEvent(void)
43 : fCanceled(false),
44 fCompleted(false),
45 hEventSem(NIL_RTSEMEVENT),
46 mRC(VINF_SUCCESS)
47{
48}
49
50GuestCtrlEvent::~GuestCtrlEvent(void)
51{
52 Destroy();
53}
54
55int GuestCtrlEvent::Cancel(void)
56{
57 int rc = VINF_SUCCESS;
58 if (!ASMAtomicReadBool(&fCompleted))
59 {
60 if (!ASMAtomicReadBool(&fCanceled))
61 {
62 ASMAtomicXchgBool(&fCanceled, true);
63
64 LogFlowThisFunc(("Cancelling event ...\n"));
65 rc = hEventSem != NIL_RTSEMEVENT
66 ? RTSemEventSignal(hEventSem) : VINF_SUCCESS;
67 }
68 }
69
70 return rc;
71}
72
73bool GuestCtrlEvent::Canceled(void)
74{
75 return ASMAtomicReadBool(&fCanceled);
76}
77
78void GuestCtrlEvent::Destroy(void)
79{
80 int rc = Cancel();
81 AssertRC(rc);
82
83 if (hEventSem != NIL_RTSEMEVENT)
84 {
85 RTSemEventDestroy(hEventSem);
86 hEventSem = NIL_RTSEMEVENT;
87 }
88}
89
90int GuestCtrlEvent::Init(void)
91{
92 return RTSemEventCreate(&hEventSem);
93}
94
95int GuestCtrlEvent::Signal(int rc /*= VINF_SUCCESS*/)
96{
97 AssertReturn(hEventSem != NIL_RTSEMEVENT, VERR_CANCELLED);
98
99 mRC = rc;
100
101 return RTSemEventSignal(hEventSem);
102}
103
104int GuestCtrlEvent::Wait(ULONG uTimeoutMS)
105{
106 LogFlowThisFuncEnter();
107
108 AssertReturn(hEventSem != NIL_RTSEMEVENT, VERR_CANCELLED);
109
110 RTMSINTERVAL msInterval = uTimeoutMS;
111 if (!uTimeoutMS)
112 msInterval = RT_INDEFINITE_WAIT;
113 int rc = RTSemEventWait(hEventSem, msInterval);
114 if (RT_SUCCESS(rc))
115 ASMAtomicWriteBool(&fCompleted, true);
116
117 LogFlowFuncLeaveRC(rc);
118 return rc;
119}
120
121///////////////////////////////////////////////////////////////////////////////
122
123GuestCtrlCallback::GuestCtrlCallback(void)
124 : pvData(NULL),
125 cbData(0),
126 mType(CALLBACKTYPE_UNKNOWN),
127 uFlags(0),
128 pvPayload(NULL),
129 cbPayload(0)
130{
131}
132
133GuestCtrlCallback::GuestCtrlCallback(CALLBACKTYPE enmType)
134 : pvData(NULL),
135 cbData(0),
136 mType(CALLBACKTYPE_UNKNOWN),
137 uFlags(0),
138 pvPayload(NULL),
139 cbPayload(0)
140{
141 int rc = Init(enmType);
142 AssertRC(rc);
143}
144
145GuestCtrlCallback::~GuestCtrlCallback(void)
146{
147 Destroy();
148}
149
150int GuestCtrlCallback::Init(CALLBACKTYPE enmType)
151{
152 AssertReturn(enmType > CALLBACKTYPE_UNKNOWN, VERR_INVALID_PARAMETER);
153 Assert((pvData == NULL) && !cbData);
154
155 int rc = VINF_SUCCESS;
156
157 switch (enmType)
158 {
159 case CALLBACKTYPE_SESSION_NOTIFY:
160 {
161 pvData = (PCALLBACKDATA_SESSION_NOTIFY)RTMemAllocZ(sizeof(CALLBACKDATA_SESSION_NOTIFY));
162 AssertPtrReturn(pvData, VERR_NO_MEMORY);
163 cbData = sizeof(CALLBACKDATA_SESSION_NOTIFY);
164 break;
165 }
166
167 case CALLBACKTYPE_PROC_STATUS:
168 {
169 pvData = (PCALLBACKDATA_PROC_STATUS)RTMemAllocZ(sizeof(CALLBACKDATA_PROC_STATUS));
170 AssertPtrReturn(pvData, VERR_NO_MEMORY);
171 cbData = sizeof(CALLBACKDATA_PROC_STATUS);
172 break;
173 }
174
175 case CALLBACKTYPE_PROC_OUTPUT:
176 {
177 pvData = (PCALLBACKDATA_PROC_OUTPUT)RTMemAllocZ(sizeof(CALLBACKDATA_PROC_OUTPUT));
178 AssertPtrReturn(pvData, VERR_NO_MEMORY);
179 cbData = sizeof(CALLBACKDATA_PROC_OUTPUT);
180 break;
181 }
182
183 case CALLBACKTYPE_PROC_INPUT:
184 {
185 pvData = (PCALLBACKDATA_PROC_INPUT)RTMemAllocZ(sizeof(CALLBACKDATA_PROC_INPUT));
186 AssertPtrReturn(pvData, VERR_NO_MEMORY);
187 cbData = sizeof(CALLBACKDATA_PROC_INPUT);
188 break;
189 }
190
191 case CALLBACKTYPE_FILE_NOTIFY:
192 {
193 pvData = (PCALLBACKDATA_FILE_NOTIFY)RTMemAllocZ(sizeof(CALLBACKDATA_FILE_NOTIFY));
194 AssertPtrReturn(pvData, VERR_NO_MEMORY);
195 cbData = sizeof(CALLBACKDATA_FILE_NOTIFY);
196 break;
197 }
198
199 default:
200 AssertMsgFailed(("Unknown callback type specified (%ld)\n", enmType));
201 rc = VERR_NOT_IMPLEMENTED;
202 break;
203 }
204
205 if (RT_SUCCESS(rc))
206 {
207 rc = GuestCtrlEvent::Init();
208 if (RT_SUCCESS(rc))
209 mType = enmType;
210 }
211
212 return rc;
213}
214
215void GuestCtrlCallback::Destroy(void)
216{
217 GuestCtrlEvent::Destroy();
218
219 switch (mType)
220 {
221 case CALLBACKTYPE_PROC_OUTPUT:
222 {
223 PCALLBACKDATA_PROC_OUTPUT pThis = (PCALLBACKDATA_PROC_OUTPUT)pvData;
224 AssertPtr(pThis);
225 if (pThis->pvData)
226 RTMemFree(pThis->pvData);
227 break;
228 }
229
230 case CALLBACKTYPE_FILE_NOTIFY:
231 {
232 PCALLBACKDATA_FILE_NOTIFY pThis = (PCALLBACKDATA_FILE_NOTIFY)pvData;
233 AssertPtr(pThis);
234 switch (pThis->uType)
235 {
236 case GUEST_FILE_NOTIFYTYPE_READ:
237 {
238 if (pThis->u.read.pvData)
239 {
240 RTMemFree(pThis->u.read.pvData);
241 pThis->u.read.pvData = NULL;
242 }
243
244 break;
245 }
246
247 default:
248 break;
249 }
250 }
251
252 default:
253 break;
254 }
255
256 mType = CALLBACKTYPE_UNKNOWN;
257 if (pvData)
258 {
259 RTMemFree(pvData);
260 pvData = NULL;
261 }
262 cbData = 0;
263
264 if (pvPayload)
265 {
266 RTMemFree(pvPayload);
267 pvPayload = NULL;
268 }
269 cbPayload = 0;
270}
271
272int GuestCtrlCallback::SetData(const void *pvCallback, size_t cbCallback)
273{
274 if (!cbCallback)
275 return VINF_SUCCESS;
276 AssertPtr(pvCallback);
277
278 int rc = VINF_SUCCESS;
279 switch (mType)
280 {
281 case CALLBACKTYPE_SESSION_NOTIFY:
282 {
283 PCALLBACKDATA_SESSION_NOTIFY pThis = (PCALLBACKDATA_SESSION_NOTIFY)pvData;
284 PCALLBACKDATA_SESSION_NOTIFY pCB = (PCALLBACKDATA_SESSION_NOTIFY)pvCallback;
285 Assert(cbCallback == sizeof(CALLBACKDATA_SESSION_NOTIFY));
286
287 memcpy(pThis, pCB, sizeof(CALLBACKDATA_SESSION_NOTIFY));
288 break;
289 }
290
291 case CALLBACKTYPE_PROC_STATUS:
292 {
293 PCALLBACKDATA_PROC_STATUS pThis = (PCALLBACKDATA_PROC_STATUS)pvData;
294 PCALLBACKDATA_PROC_STATUS pCB = (PCALLBACKDATA_PROC_STATUS)pvCallback;
295 Assert(cbCallback == sizeof(CALLBACKDATA_PROC_STATUS));
296
297 memcpy(pThis, pCB, sizeof(CALLBACKDATA_PROC_STATUS));
298 break;
299 }
300
301 case CALLBACKTYPE_PROC_OUTPUT:
302 {
303 PCALLBACKDATA_PROC_OUTPUT pThis = (PCALLBACKDATA_PROC_OUTPUT)pvData;
304 PCALLBACKDATA_PROC_OUTPUT pCB = (PCALLBACKDATA_PROC_OUTPUT)pvCallback;
305 Assert(cbCallback == sizeof(CALLBACKDATA_PROC_OUTPUT));
306
307 if (pCB->cbData)
308 {
309 pThis->pvData = RTMemAlloc(pCB->cbData);
310 AssertPtrReturn(pThis->pvData, VERR_NO_MEMORY);
311 memcpy(pThis->pvData, pCB->pvData, pCB->cbData);
312 pThis->cbData = pCB->cbData;
313 }
314 pThis->uFlags = pCB->uFlags;
315 pThis->uPID = pCB->uPID;
316 break;
317 }
318
319 case CALLBACKTYPE_PROC_INPUT:
320 {
321 PCALLBACKDATA_PROC_INPUT pThis = (PCALLBACKDATA_PROC_INPUT)pvData;
322 PCALLBACKDATA_PROC_INPUT pCB = (PCALLBACKDATA_PROC_INPUT)pvCallback;
323 Assert(cbCallback == sizeof(CALLBACKDATA_PROC_INPUT));
324
325 memcpy(pThis, pCB, sizeof(CALLBACKDATA_PROC_INPUT));
326 break;
327 }
328
329 case CALLBACKTYPE_FILE_NOTIFY:
330 {
331 PCALLBACKDATA_FILE_NOTIFY pThis = (PCALLBACKDATA_FILE_NOTIFY)pvData;
332 PCALLBACKDATA_FILE_NOTIFY pCB = (PCALLBACKDATA_FILE_NOTIFY)pvCallback;
333 Assert(cbCallback == sizeof(CALLBACKDATA_FILE_NOTIFY));
334
335 memcpy(pThis, pCB, sizeof(CALLBACKDATA_FILE_NOTIFY));
336
337 switch (pThis->uType)
338 {
339 case GUEST_FILE_NOTIFYTYPE_READ:
340 {
341 pThis->u.read.pvData = RTMemAlloc(pCB->u.read.cbData);
342 AssertPtrReturn(pThis->u.read.pvData, VERR_NO_MEMORY);
343 memcpy(pThis->u.read.pvData, pCB->u.read.pvData, pCB->u.read.cbData);
344 pThis->u.read.cbData = pCB->u.read.cbData;
345 break;
346 }
347
348 default:
349 break;
350 }
351 break;
352 }
353
354#if 0
355 case CALLBACKTYPE_FILE_OPEN:
356 {
357 PCALLBACKPAYLOAD_FILE_NOTIFY_OPEN pThis = (PCALLBACKPAYLOAD_FILE_NOTIFY_OPEN)pvData;
358 PCALLBACKPAYLOAD_FILE_NOTIFY_OPEN pCB = (PCALLBACKPAYLOAD_FILE_NOTIFY_OPEN)pvCallback;
359 Assert(cbCallback == sizeof(CALLBACKPAYLOAD_FILE_NOTIFY_OPEN));
360
361 pThis->rc = pCB->rc;
362 pThis->uHandle = pCB->uHandle;
363 break;
364 }
365
366 case CALLBACKTYPE_FILE_CLOSE:
367 {
368 PCALLBACKPAYLOAD_FILE_NOTIFY_CLOSE pThis = (PCALLBACKPAYLOAD_FILE_NOTIFY_CLOSE)pvData;
369 PCALLBACKPAYLOAD_FILE_NOTIFY_CLOSE pCB = (PCALLBACKPAYLOAD_FILE_NOTIFY_CLOSE)pvCallback;
370 Assert(cbCallback == sizeof(CALLBACKPAYLOAD_FILE_NOTIFY_CLOSE));
371
372 pThis->rc = pCB->rc;
373 break;
374 }
375
376 case CALLBACKTYPE_FILE_READ:
377 {
378 PCALLBACKPAYLOAD_FILE_NOTIFY_READ pThis = (PCALLBACKPAYLOAD_FILE_NOTIFY_READ)pvData;
379 PCALLBACKPAYLOAD_FILE_NOTIFY_READ pCB = (PCALLBACKPAYLOAD_FILE_NOTIFY_READ)pvCallback;
380 Assert(cbCallback == sizeof(CALLBACKPAYLOAD_FILE_NOTIFY_READ));
381
382 pThis->rc = pCB->rc;
383 if (pCB->cbData)
384 {
385 pThis->pvData = RTMemAlloc(pCB->cbData);
386 AssertPtrReturn(pThis->pvData, VERR_NO_MEMORY);
387 memcpy(pThis->pvData, pCB->pvData, pCB->cbData);
388 pThis->cbData = pCB->cbData;
389 }
390 break;
391 }
392
393 case CALLBACKTYPE_FILE_WRITE:
394 {
395 PCALLBACKPAYLOAD_FILE_NOTIFY_WRITE pThis = (PCALLBACKPAYLOAD_FILE_NOTIFY_WRITE)pvData;
396 PCALLBACKPAYLOAD_FILE_NOTIFY_WRITE pCB = (PCALLBACKPAYLOAD_FILE_NOTIFY_WRITE)pvCallback;
397 Assert(cbCallback == sizeof(CALLBACKPAYLOAD_FILE_NOTIFY_WRITE));
398
399 pThis->rc = pCB->rc;
400 pThis->cbWritten = pCB->cbWritten;
401 break;
402 }
403
404 case CALLBACKTYPE_FILE_SEEK:
405 {
406 PCALLBACKPAYLOAD_FILE_NOTIFY_SEEK pThis = (PCALLBACKPAYLOAD_FILE_NOTIFY_SEEK)pvData;
407 PCALLBACKPAYLOAD_FILE_NOTIFY_SEEK pCB = (PCALLBACKPAYLOAD_FILE_NOTIFY_SEEK)pvCallback;
408 Assert(cbCallback == sizeof(CALLBACKPAYLOAD_FILE_NOTFIY_SEEK));
409
410 pThis->rc = pCB->rc;
411 pThis->uOffActual = pCB->uOffActual;
412 break;
413 }
414
415 case CALLBACKTYPE_FILE_TELL:
416 {
417 PCALLBACKPAYLOAD_FILE_NOTIFY_TELL pThis = (PCALLBACKPAYLOAD_FILE_NOTIFY_TELL)pvData;
418 PCALLBACKPAYLOAD_FILE_NOTIFY_TELL pCB = (PCALLBACKPAYLOAD_FILE_NOTIFY_TELL)pvCallback;
419 Assert(cbCallback == sizeof(CALLBACKPAYLOAD_FILE_NOTFIY_TELL));
420
421 pThis->rc = pCB->rc;
422 pThis->uOffActual = pCB->uOffActual;
423 break;
424 }
425#endif
426 default:
427 AssertMsgFailed(("Callback type not supported (%ld)\n", mType));
428 rc = VERR_NOT_SUPPORTED;
429 break;
430 }
431
432 return rc;
433}
434
435int GuestCtrlCallback::SetPayload(const void *pvToWrite, size_t cbToWrite)
436{
437 if (!cbToWrite)
438 return VINF_SUCCESS;
439 AssertPtr(pvToWrite);
440
441 Assert(pvPayload == NULL); /* Can't reuse callbacks! */
442 pvPayload = RTMemAlloc(cbToWrite);
443 if (!pvPayload)
444 return VERR_NO_MEMORY;
445
446 memcpy(pvPayload, pvToWrite, cbToWrite);
447 cbPayload = cbToWrite;
448
449 return VINF_SUCCESS;
450}
451
452///////////////////////////////////////////////////////////////////////////////
453
454GuestProcessWaitEvent::GuestProcessWaitEvent(void)
455 : mFlags(0),
456 mResult(ProcessWaitResult_None)
457{
458}
459
460GuestProcessWaitEvent::GuestProcessWaitEvent(uint32_t uWaitFlags)
461 : mFlags(uWaitFlags)
462{
463 int rc = GuestCtrlEvent::Init();
464 AssertRC(rc);
465}
466
467GuestProcessWaitEvent::~GuestProcessWaitEvent(void)
468{
469 Destroy();
470}
471
472void GuestProcessWaitEvent::Destroy(void)
473{
474 GuestCtrlEvent::Destroy();
475
476 mFlags = ProcessWaitForFlag_None;
477}
478
479int GuestProcessWaitEvent::Signal(ProcessWaitResult_T enmResult, int rc /*= VINF_SUCCESS*/)
480{
481 mResult = enmResult;
482
483 return GuestCtrlEvent::Signal(rc);
484}
485
486///////////////////////////////////////////////////////////////////////////////
487
488GuestSessionWaitEvent::GuestSessionWaitEvent(void)
489 : mFlags(0),
490 mResult(GuestSessionWaitResult_None)
491{
492}
493
494GuestSessionWaitEvent::GuestSessionWaitEvent(uint32_t uWaitFlags)
495 : mFlags(uWaitFlags)
496{
497 int rc = GuestCtrlEvent::Init();
498 AssertRC(rc);
499}
500
501GuestSessionWaitEvent::~GuestSessionWaitEvent(void)
502{
503 Destroy();
504}
505
506void GuestSessionWaitEvent::Destroy(void)
507{
508 GuestCtrlEvent::Destroy();
509
510 mFlags = GuestSessionWaitForFlag_None;
511}
512
513int GuestSessionWaitEvent::Signal(GuestSessionWaitResult_T enmResult, int rc /*= VINF_SUCCESS*/)
514{
515 mResult = enmResult;
516
517 return GuestCtrlEvent::Signal(rc);
518}
519
520///////////////////////////////////////////////////////////////////////////////
521
522int GuestEnvironment::BuildEnvironmentBlock(void **ppvEnv, size_t *pcbEnv, uint32_t *pcEnvVars)
523{
524 AssertPtrReturn(ppvEnv, VERR_INVALID_POINTER);
525 /* Rest is optional. */
526
527 size_t cbEnv = 0;
528 uint32_t cEnvVars = 0;
529
530 int rc = VINF_SUCCESS;
531
532 size_t cEnv = mEnvironment.size();
533 if (cEnv)
534 {
535 std::map<Utf8Str, Utf8Str>::const_iterator itEnv = mEnvironment.begin();
536 for (; itEnv != mEnvironment.end() && RT_SUCCESS(rc); itEnv++)
537 {
538 char *pszEnv;
539 if (!RTStrAPrintf(&pszEnv, "%s=%s", itEnv->first.c_str(), itEnv->second.c_str()))
540 {
541 rc = VERR_NO_MEMORY;
542 break;
543 }
544 AssertPtr(pszEnv);
545 rc = appendToEnvBlock(pszEnv, ppvEnv, &cbEnv, &cEnvVars);
546 RTStrFree(pszEnv);
547 }
548 Assert(cEnv == cEnvVars);
549 }
550
551 if (pcbEnv)
552 *pcbEnv = cbEnv;
553 if (pcEnvVars)
554 *pcEnvVars = cEnvVars;
555
556 return rc;
557}
558
559void GuestEnvironment::Clear(void)
560{
561 mEnvironment.clear();
562}
563
564int GuestEnvironment::CopyFrom(const GuestEnvironmentArray &environment)
565{
566 int rc = VINF_SUCCESS;
567
568 for (GuestEnvironmentArray::const_iterator it = environment.begin();
569 it != environment.end() && RT_SUCCESS(rc);
570 ++it)
571 {
572 rc = Set((*it));
573 }
574
575 return rc;
576}
577
578int GuestEnvironment::CopyTo(GuestEnvironmentArray &environment)
579{
580 size_t s = 0;
581 for (std::map<Utf8Str, Utf8Str>::const_iterator it = mEnvironment.begin();
582 it != mEnvironment.end();
583 ++it, ++s)
584 {
585 environment[s] = Bstr(it->first + "=" + it->second).raw();
586 }
587
588 return VINF_SUCCESS;
589}
590
591/* static */
592void GuestEnvironment::FreeEnvironmentBlock(void *pvEnv)
593{
594 if (pvEnv)
595 RTMemFree(pvEnv);
596}
597
598Utf8Str GuestEnvironment::Get(size_t nPos)
599{
600 size_t curPos = 0;
601 std::map<Utf8Str, Utf8Str>::const_iterator it = mEnvironment.begin();
602 for (; it != mEnvironment.end() && curPos < nPos;
603 ++it, ++curPos) { }
604
605 if (it != mEnvironment.end())
606 return Utf8Str(it->first + "=" + it->second);
607
608 return Utf8Str("");
609}
610
611Utf8Str GuestEnvironment::Get(const Utf8Str &strKey)
612{
613 std::map <Utf8Str, Utf8Str>::const_iterator itEnv = mEnvironment.find(strKey);
614 Utf8Str strRet;
615 if (itEnv != mEnvironment.end())
616 strRet = itEnv->second;
617 return strRet;
618}
619
620bool GuestEnvironment::Has(const Utf8Str &strKey)
621{
622 std::map <Utf8Str, Utf8Str>::const_iterator itEnv = mEnvironment.find(strKey);
623 return (itEnv != mEnvironment.end());
624}
625
626int GuestEnvironment::Set(const Utf8Str &strKey, const Utf8Str &strValue)
627{
628 /** @todo Do some validation using regex. */
629 if (strKey.isEmpty())
630 return VERR_INVALID_PARAMETER;
631
632 int rc = VINF_SUCCESS;
633 const char *pszString = strKey.c_str();
634 while (*pszString != '\0' && RT_SUCCESS(rc))
635 {
636 if ( !RT_C_IS_ALNUM(*pszString)
637 && !RT_C_IS_GRAPH(*pszString))
638 rc = VERR_INVALID_PARAMETER;
639 *pszString++;
640 }
641
642 if (RT_SUCCESS(rc))
643 mEnvironment[strKey] = strValue;
644
645 return rc;
646}
647
648int GuestEnvironment::Set(const Utf8Str &strPair)
649{
650 RTCList<RTCString> listPair = strPair.split("=", RTCString::KeepEmptyParts);
651 /* Skip completely empty pairs. Note that we still need pairs with a valid
652 * (set) key and an empty value. */
653 if (listPair.size() <= 1)
654 return VINF_SUCCESS;
655
656 int rc = VINF_SUCCESS;
657 size_t p = 0;
658 while(p < listPair.size() && RT_SUCCESS(rc))
659 {
660 Utf8Str strKey = listPair.at(p++);
661 if ( strKey.isEmpty()
662 || strKey.equals("=")) /* Skip pairs with empty keys (e.g. "=FOO"). */
663 {
664 break;
665 }
666 Utf8Str strValue;
667 if (p < listPair.size()) /* Does the list also contain a value? */
668 strValue = listPair.at(p++);
669
670#ifdef DEBUG
671 LogFlowFunc(("strKey=%s, strValue=%s\n",
672 strKey.c_str(), strValue.c_str()));
673#endif
674 rc = Set(strKey, strValue);
675 }
676
677 return rc;
678}
679
680size_t GuestEnvironment::Size(void)
681{
682 return mEnvironment.size();
683}
684
685int GuestEnvironment::Unset(const Utf8Str &strKey)
686{
687 std::map <Utf8Str, Utf8Str>::iterator itEnv = mEnvironment.find(strKey);
688 if (itEnv != mEnvironment.end())
689 {
690 mEnvironment.erase(itEnv);
691 return VINF_SUCCESS;
692 }
693
694 return VERR_NOT_FOUND;
695}
696
697GuestEnvironment& GuestEnvironment::operator=(const GuestEnvironmentArray &that)
698{
699 CopyFrom(that);
700 return *this;
701}
702
703GuestEnvironment& GuestEnvironment::operator=(const GuestEnvironment &that)
704{
705 for (std::map<Utf8Str, Utf8Str>::const_iterator it = that.mEnvironment.begin();
706 it != that.mEnvironment.end();
707 ++it)
708 {
709 mEnvironment[it->first] = it->second;
710 }
711
712 return *this;
713}
714
715/**
716 * Appends environment variables to the environment block.
717 *
718 * Each var=value pair is separated by the null character ('\\0'). The whole
719 * block will be stored in one blob and disassembled on the guest side later to
720 * fit into the HGCM param structure.
721 *
722 * @returns VBox status code.
723 *
724 * @param pszEnvVar The environment variable=value to append to the
725 * environment block.
726 * @param ppvList This is actually a pointer to a char pointer
727 * variable which keeps track of the environment block
728 * that we're constructing.
729 * @param pcbList Pointer to the variable holding the current size of
730 * the environment block. (List is a misnomer, go
731 * ahead a be confused.)
732 * @param pcEnvVars Pointer to the variable holding count of variables
733 * stored in the environment block.
734 */
735int GuestEnvironment::appendToEnvBlock(const char *pszEnv, void **ppvList, size_t *pcbList, uint32_t *pcEnvVars)
736{
737 int rc = VINF_SUCCESS;
738 size_t cchEnv = strlen(pszEnv); Assert(cchEnv >= 2);
739 if (*ppvList)
740 {
741 size_t cbNewLen = *pcbList + cchEnv + 1; /* Include zero termination. */
742 char *pvTmp = (char *)RTMemRealloc(*ppvList, cbNewLen);
743 if (pvTmp == NULL)
744 rc = VERR_NO_MEMORY;
745 else
746 {
747 memcpy(pvTmp + *pcbList, pszEnv, cchEnv);
748 pvTmp[cbNewLen - 1] = '\0'; /* Add zero termination. */
749 *ppvList = (void **)pvTmp;
750 }
751 }
752 else
753 {
754 char *pszTmp;
755 if (RTStrAPrintf(&pszTmp, "%s", pszEnv) >= 0)
756 {
757 *ppvList = (void **)pszTmp;
758 /* Reset counters. */
759 *pcEnvVars = 0;
760 *pcbList = 0;
761 }
762 }
763 if (RT_SUCCESS(rc))
764 {
765 *pcbList += cchEnv + 1; /* Include zero termination. */
766 *pcEnvVars += 1; /* Increase env variable count. */
767 }
768 return rc;
769}
770
771int GuestFsObjData::FromLs(const GuestProcessStreamBlock &strmBlk)
772{
773 LogFlowFunc(("\n"));
774
775 int rc = VINF_SUCCESS;
776
777 try
778 {
779#ifdef DEBUG
780 strmBlk.DumpToLog();
781#endif
782 /* Object name. */
783 mName = strmBlk.GetString("name");
784 if (mName.isEmpty()) throw VERR_NOT_FOUND;
785 /* Type. */
786 Utf8Str strType(strmBlk.GetString("ftype"));
787 if (strType.equalsIgnoreCase("-"))
788 mType = FsObjType_File;
789 else if (strType.equalsIgnoreCase("d"))
790 mType = FsObjType_Directory;
791 /** @todo Add more types! */
792 else
793 mType = FsObjType_Undefined;
794 /* Object size. */
795 rc = strmBlk.GetInt64Ex("st_size", &mObjectSize);
796 if (RT_FAILURE(rc)) throw rc;
797 /** @todo Add complete ls info! */
798 }
799 catch (int rc2)
800 {
801 rc = rc2;
802 }
803
804 LogFlowFuncLeaveRC(rc);
805 return rc;
806}
807
808int GuestFsObjData::FromStat(const GuestProcessStreamBlock &strmBlk)
809{
810 LogFlowFunc(("\n"));
811
812 int rc = VINF_SUCCESS;
813
814 try
815 {
816#ifdef DEBUG
817 strmBlk.DumpToLog();
818#endif
819 /* Node ID, optional because we don't include this
820 * in older VBoxService (< 4.2) versions. */
821 mNodeID = strmBlk.GetInt64("node_id");
822 /* Object name. */
823 mName = strmBlk.GetString("name");
824 if (mName.isEmpty()) throw VERR_NOT_FOUND;
825 /* Type. */
826 Utf8Str strType(strmBlk.GetString("ftype"));
827 if (strType.equalsIgnoreCase("-"))
828 mType = FsObjType_File;
829 else if (strType.equalsIgnoreCase("d"))
830 mType = FsObjType_Directory;
831 /** @todo Add more types! */
832 else
833 mType = FsObjType_Undefined;
834 /* Object size. */
835 rc = strmBlk.GetInt64Ex("st_size", &mObjectSize);
836 if (RT_FAILURE(rc)) throw rc;
837 /** @todo Add complete stat info! */
838 }
839 catch (int rc2)
840 {
841 rc = rc2;
842 }
843
844 LogFlowFuncLeaveRC(rc);
845 return rc;
846}
847
848///////////////////////////////////////////////////////////////////////////////
849
850/** @todo *NOT* thread safe yet! */
851/** @todo Add exception handling for STL stuff! */
852
853GuestProcessStreamBlock::GuestProcessStreamBlock(void)
854{
855
856}
857
858/*
859GuestProcessStreamBlock::GuestProcessStreamBlock(const GuestProcessStreamBlock &otherBlock)
860{
861 for (GuestCtrlStreamPairsIter it = otherBlock.mPairs.begin();
862 it != otherBlock.end(); it++)
863 {
864 mPairs[it->first] = new
865 if (it->second.pszValue)
866 {
867 RTMemFree(it->second.pszValue);
868 it->second.pszValue = NULL;
869 }
870 }
871}*/
872
873GuestProcessStreamBlock::~GuestProcessStreamBlock()
874{
875 Clear();
876}
877
878/**
879 * Destroys the currently stored stream pairs.
880 *
881 * @return IPRT status code.
882 */
883void GuestProcessStreamBlock::Clear(void)
884{
885 mPairs.clear();
886}
887
888#ifdef DEBUG
889void GuestProcessStreamBlock::DumpToLog(void) const
890{
891 LogFlowFunc(("Dumping contents of stream block=0x%p (%ld items):\n",
892 this, mPairs.size()));
893
894 for (GuestCtrlStreamPairMapIterConst it = mPairs.begin();
895 it != mPairs.end(); it++)
896 {
897 LogFlowFunc(("\t%s=%s\n", it->first.c_str(), it->second.mValue.c_str()));
898 }
899}
900#endif
901
902/**
903 * Returns a 64-bit signed integer of a specified key.
904 *
905 * @return IPRT status code. VERR_NOT_FOUND if key was not found.
906 * @param pszKey Name of key to get the value for.
907 * @param piVal Pointer to value to return.
908 */
909int GuestProcessStreamBlock::GetInt64Ex(const char *pszKey, int64_t *piVal) const
910{
911 AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
912 AssertPtrReturn(piVal, VERR_INVALID_POINTER);
913 const char *pszValue = GetString(pszKey);
914 if (pszValue)
915 {
916 *piVal = RTStrToInt64(pszValue);
917 return VINF_SUCCESS;
918 }
919 return VERR_NOT_FOUND;
920}
921
922/**
923 * Returns a 64-bit integer of a specified key.
924 *
925 * @return int64_t Value to return, 0 if not found / on failure.
926 * @param pszKey Name of key to get the value for.
927 */
928int64_t GuestProcessStreamBlock::GetInt64(const char *pszKey) const
929{
930 int64_t iVal;
931 if (RT_SUCCESS(GetInt64Ex(pszKey, &iVal)))
932 return iVal;
933 return 0;
934}
935
936/**
937 * Returns the current number of stream pairs.
938 *
939 * @return uint32_t Current number of stream pairs.
940 */
941size_t GuestProcessStreamBlock::GetCount(void) const
942{
943 return mPairs.size();
944}
945
946/**
947 * Returns a string value of a specified key.
948 *
949 * @return uint32_t Pointer to string to return, NULL if not found / on failure.
950 * @param pszKey Name of key to get the value for.
951 */
952const char* GuestProcessStreamBlock::GetString(const char *pszKey) const
953{
954 AssertPtrReturn(pszKey, NULL);
955
956 try
957 {
958 GuestCtrlStreamPairMapIterConst itPairs = mPairs.find(Utf8Str(pszKey));
959 if (itPairs != mPairs.end())
960 return itPairs->second.mValue.c_str();
961 }
962 catch (const std::exception &ex)
963 {
964 NOREF(ex);
965 }
966 return NULL;
967}
968
969/**
970 * Returns a 32-bit unsigned integer of a specified key.
971 *
972 * @return IPRT status code. VERR_NOT_FOUND if key was not found.
973 * @param pszKey Name of key to get the value for.
974 * @param puVal Pointer to value to return.
975 */
976int GuestProcessStreamBlock::GetUInt32Ex(const char *pszKey, uint32_t *puVal) const
977{
978 AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
979 AssertPtrReturn(puVal, VERR_INVALID_POINTER);
980 const char *pszValue = GetString(pszKey);
981 if (pszValue)
982 {
983 *puVal = RTStrToUInt32(pszValue);
984 return VINF_SUCCESS;
985 }
986 return VERR_NOT_FOUND;
987}
988
989/**
990 * Returns a 32-bit unsigned integer of a specified key.
991 *
992 * @return uint32_t Value to return, 0 if not found / on failure.
993 * @param pszKey Name of key to get the value for.
994 */
995uint32_t GuestProcessStreamBlock::GetUInt32(const char *pszKey) const
996{
997 uint32_t uVal;
998 if (RT_SUCCESS(GetUInt32Ex(pszKey, &uVal)))
999 return uVal;
1000 return 0;
1001}
1002
1003/**
1004 * Sets a value to a key or deletes a key by setting a NULL value.
1005 *
1006 * @return IPRT status code.
1007 * @param pszKey Key name to process.
1008 * @param pszValue Value to set. Set NULL for deleting the key.
1009 */
1010int GuestProcessStreamBlock::SetValue(const char *pszKey, const char *pszValue)
1011{
1012 AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
1013
1014 int rc = VINF_SUCCESS;
1015 try
1016 {
1017 Utf8Str Utf8Key(pszKey);
1018
1019 /* Take a shortcut and prevent crashes on some funny versions
1020 * of STL if map is empty initially. */
1021 if (!mPairs.empty())
1022 {
1023 GuestCtrlStreamPairMapIter it = mPairs.find(Utf8Key);
1024 if (it != mPairs.end())
1025 mPairs.erase(it);
1026 }
1027
1028 if (pszValue)
1029 {
1030 GuestProcessStreamValue val(pszValue);
1031 mPairs[Utf8Key] = val;
1032 }
1033 }
1034 catch (const std::exception &ex)
1035 {
1036 NOREF(ex);
1037 }
1038 return rc;
1039}
1040
1041///////////////////////////////////////////////////////////////////////////////
1042
1043GuestProcessStream::GuestProcessStream(void)
1044 : m_cbAllocated(0),
1045 m_cbSize(0),
1046 m_cbOffset(0),
1047 m_pbBuffer(NULL)
1048{
1049
1050}
1051
1052GuestProcessStream::~GuestProcessStream(void)
1053{
1054 Destroy();
1055}
1056
1057/**
1058 * Adds data to the internal parser buffer. Useful if there
1059 * are multiple rounds of adding data needed.
1060 *
1061 * @return IPRT status code.
1062 * @param pbData Pointer to data to add.
1063 * @param cbData Size (in bytes) of data to add.
1064 */
1065int GuestProcessStream::AddData(const BYTE *pbData, size_t cbData)
1066{
1067 AssertPtrReturn(pbData, VERR_INVALID_POINTER);
1068 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1069
1070 int rc = VINF_SUCCESS;
1071
1072 /* Rewind the buffer if it's empty. */
1073 size_t cbInBuf = m_cbSize - m_cbOffset;
1074 bool const fAddToSet = cbInBuf == 0;
1075 if (fAddToSet)
1076 m_cbSize = m_cbOffset = 0;
1077
1078 /* Try and see if we can simply append the data. */
1079 if (cbData + m_cbSize <= m_cbAllocated)
1080 {
1081 memcpy(&m_pbBuffer[m_cbSize], pbData, cbData);
1082 m_cbSize += cbData;
1083 }
1084 else
1085 {
1086 /* Move any buffered data to the front. */
1087 cbInBuf = m_cbSize - m_cbOffset;
1088 if (cbInBuf == 0)
1089 m_cbSize = m_cbOffset = 0;
1090 else if (m_cbOffset) /* Do we have something to move? */
1091 {
1092 memmove(m_pbBuffer, &m_pbBuffer[m_cbOffset], cbInBuf);
1093 m_cbSize = cbInBuf;
1094 m_cbOffset = 0;
1095 }
1096
1097 /* Do we need to grow the buffer? */
1098 if (cbData + m_cbSize > m_cbAllocated)
1099 {
1100 size_t cbAlloc = m_cbSize + cbData;
1101 cbAlloc = RT_ALIGN_Z(cbAlloc, _64K);
1102 void *pvNew = RTMemRealloc(m_pbBuffer, cbAlloc);
1103 if (pvNew)
1104 {
1105 m_pbBuffer = (uint8_t *)pvNew;
1106 m_cbAllocated = cbAlloc;
1107 }
1108 else
1109 rc = VERR_NO_MEMORY;
1110 }
1111
1112 /* Finally, copy the data. */
1113 if (RT_SUCCESS(rc))
1114 {
1115 if (cbData + m_cbSize <= m_cbAllocated)
1116 {
1117 memcpy(&m_pbBuffer[m_cbSize], pbData, cbData);
1118 m_cbSize += cbData;
1119 }
1120 else
1121 rc = VERR_BUFFER_OVERFLOW;
1122 }
1123 }
1124
1125 return rc;
1126}
1127
1128/**
1129 * Destroys the internal data buffer.
1130 */
1131void GuestProcessStream::Destroy(void)
1132{
1133 if (m_pbBuffer)
1134 {
1135 RTMemFree(m_pbBuffer);
1136 m_pbBuffer = NULL;
1137 }
1138
1139 m_cbAllocated = 0;
1140 m_cbSize = 0;
1141 m_cbOffset = 0;
1142}
1143
1144#ifdef DEBUG
1145void GuestProcessStream::Dump(const char *pszFile)
1146{
1147 LogFlowFunc(("Dumping contents of stream=0x%p (cbAlloc=%u, cbSize=%u, cbOff=%u) to %s\n",
1148 m_pbBuffer, m_cbAllocated, m_cbSize, m_cbOffset, pszFile));
1149
1150 RTFILE hFile;
1151 int rc = RTFileOpen(&hFile, pszFile, RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE);
1152 if (RT_SUCCESS(rc))
1153 {
1154 rc = RTFileWrite(hFile, m_pbBuffer, m_cbSize, NULL /* pcbWritten */);
1155 RTFileClose(hFile);
1156 }
1157}
1158#endif
1159
1160/**
1161 * Returns the current offset of the parser within
1162 * the internal data buffer.
1163 *
1164 * @return uint32_t Parser offset.
1165 */
1166uint32_t GuestProcessStream::GetOffset()
1167{
1168 return m_cbOffset;
1169}
1170
1171uint32_t GuestProcessStream::GetSize()
1172{
1173 return m_cbSize;
1174}
1175
1176/**
1177 * Tries to parse the next upcoming pair block within the internal
1178 * buffer.
1179 *
1180 * Returns VERR_NO_DATA is no data is in internal buffer or buffer has been
1181 * completely parsed already.
1182 *
1183 * Returns VERR_MORE_DATA if current block was parsed (with zero or more pairs
1184 * stored in stream block) but still contains incomplete (unterminated)
1185 * data.
1186 *
1187 * Returns VINF_SUCCESS if current block was parsed until the next upcoming
1188 * block (with zero or more pairs stored in stream block).
1189 *
1190 * @return IPRT status code.
1191 * @param streamBlock Reference to guest stream block to fill.
1192 *
1193 */
1194int GuestProcessStream::ParseBlock(GuestProcessStreamBlock &streamBlock)
1195{
1196 if ( !m_pbBuffer
1197 || !m_cbSize)
1198 {
1199 return VERR_NO_DATA;
1200 }
1201
1202 AssertReturn(m_cbOffset <= m_cbSize, VERR_INVALID_PARAMETER);
1203 if (m_cbOffset == m_cbSize)
1204 return VERR_NO_DATA;
1205
1206 int rc = VINF_SUCCESS;
1207
1208 char *pszOff = (char*)&m_pbBuffer[m_cbOffset];
1209 char *pszStart = pszOff;
1210 uint32_t uDistance;
1211 while (*pszStart)
1212 {
1213 size_t pairLen = strlen(pszStart);
1214 uDistance = (pszStart - pszOff);
1215 if (m_cbOffset + uDistance + pairLen + 1 >= m_cbSize)
1216 {
1217 rc = VERR_MORE_DATA;
1218 break;
1219 }
1220 else
1221 {
1222 char *pszSep = strchr(pszStart, '=');
1223 char *pszVal = NULL;
1224 if (pszSep)
1225 pszVal = pszSep + 1;
1226 if (!pszSep || !pszVal)
1227 {
1228 rc = VERR_MORE_DATA;
1229 break;
1230 }
1231
1232 /* Terminate the separator so that we can
1233 * use pszStart as our key from now on. */
1234 *pszSep = '\0';
1235
1236 rc = streamBlock.SetValue(pszStart, pszVal);
1237 if (RT_FAILURE(rc))
1238 return rc;
1239 }
1240
1241 /* Next pair. */
1242 pszStart += pairLen + 1;
1243 }
1244
1245 /* If we did not do any movement but we have stuff left
1246 * in our buffer just skip the current termination so that
1247 * we can try next time. */
1248 uDistance = (pszStart - pszOff);
1249 if ( !uDistance
1250 && *pszStart == '\0'
1251 && m_cbOffset < m_cbSize)
1252 {
1253 uDistance++;
1254 }
1255 m_cbOffset += uDistance;
1256
1257 return rc;
1258}
1259
1260int GuestObject::bindToSession(Console *pConsole, GuestSession *pSession, uint32_t uObjectID)
1261{
1262 AssertPtrReturn(pConsole, VERR_INVALID_POINTER);
1263 AssertPtrReturn(pSession, VERR_INVALID_POINTER);
1264
1265 mObject.mConsole = pConsole;
1266 mObject.mSession = pSession;
1267
1268 mObject.mNextContextID = 0;
1269 mObject.mObjectID = uObjectID;
1270
1271 return VINF_SUCCESS;
1272}
1273
1274int GuestObject::callbackAdd(GuestCtrlCallback *pCallback, uint32_t *puContextID)
1275{
1276 const ComObjPtr<GuestSession> pSession(mObject.mSession);
1277 Assert(!pSession.isNull());
1278 ULONG uSessionID = 0;
1279 pSession->COMGETTER(Id)(&uSessionID);
1280
1281 /* Create a new context ID and assign it. */
1282 int vrc = VERR_NOT_FOUND;
1283
1284 ULONG uCount = mObject.mNextContextID++;
1285 ULONG uNewContextID = 0;
1286 ULONG uTries = 0;
1287 for (;;)
1288 {
1289 if (uCount == VBOX_GUESTCTRL_MAX_CONTEXTS)
1290 uCount = 0;
1291
1292 /* Create a new context ID ... */
1293 uNewContextID = VBOX_GUESTCTRL_CONTEXTID_MAKE(uSessionID, mObject.mObjectID, uCount);
1294
1295 /* Is the context ID already used? Try next ID ... */
1296 if (!callbackExists(uCount))
1297 {
1298 /* Callback with context ID was not found. This means
1299 * we can use this context ID for our new callback we want
1300 * to add below. */
1301 vrc = VINF_SUCCESS;
1302 break;
1303 }
1304
1305 uCount++;
1306 if (++uTries == UINT32_MAX)
1307 break; /* Don't try too hard. */
1308 }
1309
1310 if (RT_SUCCESS(vrc))
1311 {
1312 /* Add callback with new context ID to our callback map.
1313 * Note: This is *not* uNewContextID (which also includes
1314 * the session + process ID), just the context count
1315 * will be used here. */
1316 mObject.mCallbacks[uCount] = pCallback;
1317 Assert(mObject.mCallbacks.size());
1318
1319 /* Report back new context ID. */
1320 if (puContextID)
1321 *puContextID = uNewContextID;
1322
1323 LogFlowThisFunc(("Added new callback (Session: %RU32, Object: %RU32, Count: %RU32) CID=%RU32\n",
1324 uSessionID, mObject.mObjectID, uCount, uNewContextID));
1325 }
1326
1327 return vrc;
1328}
1329
1330void GuestObject::callbackDelete(GuestCtrlCallback *pCallback)
1331{
1332 if (pCallback)
1333 {
1334 delete pCallback;
1335 pCallback = NULL;
1336 }
1337}
1338
1339bool GuestObject::callbackExists(uint32_t uContextID)
1340{
1341 GuestCtrlCallbacks::const_iterator it =
1342 mObject.mCallbacks.find(VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID));
1343 return (it == mObject.mCallbacks.end()) ? false : true;
1344}
1345
1346int GuestObject::callbackRemove(uint32_t uContextID)
1347{
1348 LogFlowThisFunc(("Removing callback (Session=%RU32, Object=%RU32, Count=%RU32) CID=%RU32\n",
1349 VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(uContextID),
1350 VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(uContextID),
1351 VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID),
1352 uContextID));
1353
1354 GuestCtrlCallbacks::iterator it =
1355 mObject.mCallbacks.find(VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID));
1356 if (it != mObject.mCallbacks.end())
1357 {
1358 mObject.mCallbacks.erase(it);
1359
1360 return VINF_SUCCESS;
1361 }
1362
1363 return VERR_NOT_FOUND;
1364}
1365
1366int GuestObject::callbackRemoveAll(void)
1367{
1368 int vrc = VINF_SUCCESS;
1369
1370 /*
1371 * Cancel all callbacks + waiters.
1372 * Note: Deleting them is the job of the caller!
1373 */
1374 for (GuestCtrlCallbacks::iterator itCallbacks = mObject.mCallbacks.begin();
1375 itCallbacks != mObject.mCallbacks.end(); ++itCallbacks)
1376 {
1377 GuestCtrlCallback *pCallback = itCallbacks->second;
1378 AssertPtr(pCallback);
1379 int rc2 = pCallback->Cancel();
1380 if (RT_SUCCESS(vrc))
1381 vrc = rc2;
1382 }
1383 mObject.mCallbacks.clear();
1384
1385 return vrc;
1386}
1387
1388int GuestObject::sendCommand(uint32_t uFunction,
1389 uint32_t uParms, PVBOXHGCMSVCPARM paParms)
1390{
1391 LogFlowThisFuncEnter();
1392
1393#ifndef VBOX_GUESTCTRL_TEST_CASE
1394 ComObjPtr<Console> pConsole = mObject.mConsole;
1395 Assert(!pConsole.isNull());
1396
1397 /* Forward the information to the VMM device. */
1398 VMMDev *pVMMDev = pConsole->getVMMDev();
1399 AssertPtr(pVMMDev);
1400
1401 LogFlowThisFunc(("uFunction=%RU32, uParms=%RU32\n", uFunction, uParms));
1402 int vrc = pVMMDev->hgcmHostCall(HGCMSERVICE_NAME, uFunction, uParms, paParms);
1403 if (RT_FAILURE(vrc))
1404 {
1405 /** @todo What to do here? */
1406 }
1407#else
1408 /* Not needed within testcases. */
1409 int vrc = VINF_SUCCESS;
1410#endif
1411 LogFlowFuncLeaveRC(vrc);
1412 return vrc;
1413}
1414
Note: See TracBrowser for help on using the repository browser.

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