VirtualBox

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

Last change on this file since 44029 was 43162, checked in by vboxsync, 12 years ago

Main/Guest Control 2.0: Cleanup, separated guest error handling.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.7 KB
Line 
1/* $Id: GuestCtrlPrivate.cpp 43162 2012-09-04 13:53:59Z vboxsync $ */
2/** @file
3 *
4 * Internal helpers/structures for guest control functionality.
5 */
6
7/*
8 * Copyright (C) 2011-2012 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
24#include <iprt/asm.h>
25#include <iprt/ctype.h>
26#ifdef DEBUG
27# include <iprt/file.h>
28#endif /* DEBUG */
29
30#ifdef LOG_GROUP
31 #undef LOG_GROUP
32#endif
33#define LOG_GROUP LOG_GROUP_GUEST_CONTROL
34#include <VBox/log.h>
35
36/******************************************************************************
37 * Structures and Typedefs *
38 ******************************************************************************/
39
40GuestCtrlEvent::GuestCtrlEvent(void)
41 : fCanceled(false),
42 fCompleted(false),
43 hEventSem(NIL_RTSEMEVENT),
44 mRC(VINF_SUCCESS)
45{
46}
47
48GuestCtrlEvent::~GuestCtrlEvent(void)
49{
50 Destroy();
51}
52
53int GuestCtrlEvent::Cancel(void)
54{
55 int rc = VINF_SUCCESS;
56 if (!ASMAtomicReadBool(&fCompleted))
57 {
58 if (!ASMAtomicReadBool(&fCanceled))
59 {
60 ASMAtomicXchgBool(&fCanceled, true);
61
62 LogFlowThisFunc(("Cancelling event ...\n"));
63 rc = hEventSem != NIL_RTSEMEVENT
64 ? RTSemEventSignal(hEventSem) : VINF_SUCCESS;
65 }
66 }
67
68 return rc;
69}
70
71bool GuestCtrlEvent::Canceled(void)
72{
73 return ASMAtomicReadBool(&fCanceled);
74}
75
76void GuestCtrlEvent::Destroy(void)
77{
78 int rc = Cancel();
79 AssertRC(rc);
80
81 if (hEventSem != NIL_RTSEMEVENT)
82 {
83 RTSemEventDestroy(hEventSem);
84 hEventSem = NIL_RTSEMEVENT;
85 }
86}
87
88int GuestCtrlEvent::Init(void)
89{
90 return RTSemEventCreate(&hEventSem);
91}
92
93int GuestCtrlEvent::Signal(int rc /*= VINF_SUCCESS*/)
94{
95 AssertReturn(hEventSem != NIL_RTSEMEVENT, VERR_CANCELLED);
96
97 mRC = rc;
98
99 return RTSemEventSignal(hEventSem);
100}
101
102int GuestCtrlEvent::Wait(ULONG uTimeoutMS)
103{
104 LogFlowThisFuncEnter();
105
106 AssertReturn(hEventSem != NIL_RTSEMEVENT, VERR_CANCELLED);
107
108 RTMSINTERVAL msInterval = uTimeoutMS;
109 if (!uTimeoutMS)
110 msInterval = RT_INDEFINITE_WAIT;
111 int rc = RTSemEventWait(hEventSem, msInterval);
112 if (RT_SUCCESS(rc))
113 ASMAtomicWriteBool(&fCompleted, true);
114
115 LogFlowFuncLeaveRC(rc);
116 return rc;
117}
118
119///////////////////////////////////////////////////////////////////////////////
120
121GuestCtrlCallback::GuestCtrlCallback(void)
122 : pvData(NULL),
123 cbData(0),
124 mType(VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN),
125 uFlags(0),
126 pvPayload(NULL),
127 cbPayload(0)
128{
129}
130
131GuestCtrlCallback::GuestCtrlCallback(eVBoxGuestCtrlCallbackType enmType)
132 : pvData(NULL),
133 cbData(0),
134 mType(VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN),
135 uFlags(0),
136 pvPayload(NULL),
137 cbPayload(0)
138{
139 int rc = Init(enmType);
140 AssertRC(rc);
141}
142
143GuestCtrlCallback::~GuestCtrlCallback(void)
144{
145 Destroy();
146}
147
148int GuestCtrlCallback::Init(eVBoxGuestCtrlCallbackType enmType)
149{
150 AssertReturn(enmType > VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN, VERR_INVALID_PARAMETER);
151 Assert((pvData == NULL) && !cbData);
152
153 switch (enmType)
154 {
155 case VBOXGUESTCTRLCALLBACKTYPE_EXEC_START:
156 {
157 pvData = (PCALLBACKDATAEXECSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECSTATUS));
158 AssertPtrReturn(pvData, VERR_NO_MEMORY);
159 RT_BZERO(pvData, sizeof(CALLBACKDATAEXECSTATUS));
160 cbData = sizeof(CALLBACKDATAEXECSTATUS);
161 break;
162 }
163
164 case VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT:
165 {
166 pvData = (PCALLBACKDATAEXECOUT)RTMemAlloc(sizeof(CALLBACKDATAEXECOUT));
167 AssertPtrReturn(pvData, VERR_NO_MEMORY);
168 RT_BZERO(pvData, sizeof(CALLBACKDATAEXECOUT));
169 cbData = sizeof(CALLBACKDATAEXECOUT);
170 break;
171 }
172
173 case VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS:
174 {
175 pvData = (PCALLBACKDATAEXECINSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECINSTATUS));
176 AssertPtrReturn(pvData, VERR_NO_MEMORY);
177 RT_BZERO(pvData, sizeof(CALLBACKDATAEXECINSTATUS));
178 cbData = sizeof(CALLBACKDATAEXECINSTATUS);
179 break;
180 }
181
182 default:
183 AssertMsgFailed(("Unknown callback type specified (%d)\n", enmType));
184 break;
185 }
186
187 int rc = GuestCtrlEvent::Init();
188 if (RT_SUCCESS(rc))
189 mType = enmType;
190
191 return rc;
192}
193
194void GuestCtrlCallback::Destroy(void)
195{
196 GuestCtrlEvent::Destroy();
197
198 switch (mType)
199 {
200 case VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT:
201 {
202 PCALLBACKDATAEXECOUT pThis = (PCALLBACKDATAEXECOUT)pvData;
203 AssertPtr(pThis);
204 if (pThis->pvData)
205 RTMemFree(pThis->pvData);
206 }
207
208 default:
209 break;
210 }
211
212 mType = VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN;
213 if (pvData)
214 {
215 RTMemFree(pvData);
216 pvData = NULL;
217 }
218 cbData = 0;
219
220 if (pvPayload)
221 {
222 RTMemFree(pvPayload);
223 pvPayload = NULL;
224 }
225 cbPayload = 0;
226}
227
228int GuestCtrlCallback::SetData(const void *pvCallback, size_t cbCallback)
229{
230 if (!cbCallback)
231 return VINF_SUCCESS;
232 AssertPtr(pvCallback);
233
234 switch (mType)
235 {
236 case VBOXGUESTCTRLCALLBACKTYPE_EXEC_START:
237 {
238 PCALLBACKDATAEXECSTATUS pThis = (PCALLBACKDATAEXECSTATUS)pvData;
239 PCALLBACKDATAEXECSTATUS pCB = (PCALLBACKDATAEXECSTATUS)pvCallback;
240 Assert(cbCallback == sizeof(CALLBACKDATAEXECSTATUS));
241
242 pThis->u32Flags = pCB->u32Flags;
243 pThis->u32PID = pCB->u32PID;
244 pThis->u32Status = pCB->u32Status;
245 break;
246 }
247
248 case VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT:
249 {
250 PCALLBACKDATAEXECOUT pThis = (PCALLBACKDATAEXECOUT)pvData;
251 PCALLBACKDATAEXECOUT pCB = (PCALLBACKDATAEXECOUT)pvCallback;
252 Assert(cbCallback == sizeof(CALLBACKDATAEXECOUT));
253
254 pThis->cbData = pCB->cbData;
255 if (pThis->cbData)
256 {
257 pThis->pvData = RTMemAlloc(pCB->cbData);
258 AssertPtrReturn(pThis->pvData, VERR_NO_MEMORY);
259 memcpy(pThis->pvData, pCB->pvData, pCB->cbData);
260 }
261 pThis->u32Flags = pCB->u32Flags;
262 pThis->u32PID = pCB->u32PID;
263 break;
264 }
265
266 case VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS:
267 {
268 PCALLBACKDATAEXECINSTATUS pThis = (PCALLBACKDATAEXECINSTATUS)pvData;
269 PCALLBACKDATAEXECINSTATUS pCB = (PCALLBACKDATAEXECINSTATUS)pvCallback;
270 Assert(cbCallback == sizeof(CALLBACKDATAEXECINSTATUS));
271
272 pThis->cbProcessed = pCB->cbProcessed;
273 pThis->u32Flags = pCB->u32Flags;
274 pThis->u32PID = pCB->u32PID;
275 pThis->u32Status = pCB->u32Status;
276 break;
277 }
278
279 default:
280 AssertMsgFailed(("Callback type not handled (%d)\n", mType));
281 break;
282 }
283
284 return VINF_SUCCESS;
285}
286
287int GuestCtrlCallback::SetPayload(const void *pvToWrite, size_t cbToWrite)
288{
289 if (!cbToWrite)
290 return VINF_SUCCESS;
291 AssertPtr(pvToWrite);
292
293 Assert(pvPayload == NULL); /* Can't reuse callbacks! */
294 pvPayload = RTMemAlloc(cbToWrite);
295 if (!pvPayload)
296 return VERR_NO_MEMORY;
297
298 memcpy(pvPayload, pvToWrite, cbToWrite);
299 cbPayload = cbToWrite;
300
301 return VINF_SUCCESS;
302}
303
304///////////////////////////////////////////////////////////////////////////////
305
306GuestProcessWaitEvent::GuestProcessWaitEvent(void)
307 : mFlags(0),
308 mResult(ProcessWaitResult_None)
309{
310}
311
312GuestProcessWaitEvent::GuestProcessWaitEvent(uint32_t uWaitFlags)
313 : mFlags(uWaitFlags)
314{
315 int rc = GuestCtrlEvent::Init();
316 AssertRC(rc);
317}
318
319GuestProcessWaitEvent::~GuestProcessWaitEvent(void)
320{
321 Destroy();
322}
323
324void GuestProcessWaitEvent::Destroy(void)
325{
326 GuestCtrlEvent::Destroy();
327
328 mFlags = ProcessWaitForFlag_None;
329}
330
331int GuestProcessWaitEvent::Signal(ProcessWaitResult_T enmResult, int rc /*= VINF_SUCCESS*/)
332{
333 mResult = enmResult;
334
335 return GuestCtrlEvent::Signal(rc);
336}
337
338///////////////////////////////////////////////////////////////////////////////
339
340int GuestEnvironment::BuildEnvironmentBlock(void **ppvEnv, size_t *pcbEnv, uint32_t *pcEnvVars)
341{
342 AssertPtrReturn(ppvEnv, VERR_INVALID_POINTER);
343 /* Rest is optional. */
344
345 size_t cbEnv = 0;
346 uint32_t cEnvVars = 0;
347
348 int rc = VINF_SUCCESS;
349
350 size_t cEnv = mEnvironment.size();
351 if (cEnv)
352 {
353 std::map<Utf8Str, Utf8Str>::const_iterator itEnv = mEnvironment.begin();
354 for (; itEnv != mEnvironment.end() && RT_SUCCESS(rc); itEnv++)
355 {
356 char *pszEnv;
357 if (!RTStrAPrintf(&pszEnv, "%s=%s", itEnv->first.c_str(), itEnv->second.c_str()))
358 {
359 rc = VERR_NO_MEMORY;
360 break;
361 }
362 AssertPtr(pszEnv);
363 rc = appendToEnvBlock(pszEnv, ppvEnv, &cbEnv, &cEnvVars);
364 RTStrFree(pszEnv);
365 }
366 Assert(cEnv == cEnvVars);
367 }
368
369 if (pcbEnv)
370 *pcbEnv = cbEnv;
371 if (pcEnvVars)
372 *pcEnvVars = cEnvVars;
373
374 return rc;
375}
376
377void GuestEnvironment::Clear(void)
378{
379 mEnvironment.clear();
380}
381
382int GuestEnvironment::CopyFrom(const GuestEnvironmentArray &environment)
383{
384 int rc = VINF_SUCCESS;
385
386 for (GuestEnvironmentArray::const_iterator it = environment.begin();
387 it != environment.end() && RT_SUCCESS(rc);
388 ++it)
389 {
390 rc = Set((*it));
391 }
392
393 return rc;
394}
395
396int GuestEnvironment::CopyTo(GuestEnvironmentArray &environment)
397{
398 size_t s = 0;
399 for (std::map<Utf8Str, Utf8Str>::const_iterator it = mEnvironment.begin();
400 it != mEnvironment.end();
401 ++it, ++s)
402 {
403 environment[s] = Bstr(it->first + "=" + it->second).raw();
404 }
405
406 return VINF_SUCCESS;
407}
408
409/* static */
410void GuestEnvironment::FreeEnvironmentBlock(void *pvEnv)
411{
412 if (pvEnv)
413 RTMemFree(pvEnv);
414}
415
416Utf8Str GuestEnvironment::Get(size_t nPos)
417{
418 size_t curPos = 0;
419 std::map<Utf8Str, Utf8Str>::const_iterator it = mEnvironment.begin();
420 for (; it != mEnvironment.end() && curPos < nPos;
421 ++it, ++curPos) { }
422
423 if (it != mEnvironment.end())
424 return Utf8Str(it->first + "=" + it->second);
425
426 return Utf8Str("");
427}
428
429Utf8Str GuestEnvironment::Get(const Utf8Str &strKey)
430{
431 std::map <Utf8Str, Utf8Str>::const_iterator itEnv = mEnvironment.find(strKey);
432 Utf8Str strRet;
433 if (itEnv != mEnvironment.end())
434 strRet = itEnv->second;
435 return strRet;
436}
437
438bool GuestEnvironment::Has(const Utf8Str &strKey)
439{
440 std::map <Utf8Str, Utf8Str>::const_iterator itEnv = mEnvironment.find(strKey);
441 return (itEnv != mEnvironment.end());
442}
443
444int GuestEnvironment::Set(const Utf8Str &strKey, const Utf8Str &strValue)
445{
446 /** @todo Do some validation using regex. */
447 if (strKey.isEmpty())
448 return VERR_INVALID_PARAMETER;
449
450 int rc = VINF_SUCCESS;
451 const char *pszString = strKey.c_str();
452 while (*pszString != '\0' && RT_SUCCESS(rc))
453 {
454 if ( !RT_C_IS_ALNUM(*pszString)
455 && !RT_C_IS_GRAPH(*pszString))
456 rc = VERR_INVALID_PARAMETER;
457 *pszString++;
458 }
459
460 if (RT_SUCCESS(rc))
461 mEnvironment[strKey] = strValue;
462
463 return rc;
464}
465
466int GuestEnvironment::Set(const Utf8Str &strPair)
467{
468 RTCList<RTCString> listPair = strPair.split("=", RTCString::KeepEmptyParts);
469 /* Skip completely empty pairs. Note that we still need pairs with a valid
470 * (set) key and an empty value. */
471 if (listPair.size() <= 1)
472 return VINF_SUCCESS;
473
474 int rc = VINF_SUCCESS;
475 size_t p = 0;
476 while(p < listPair.size() && RT_SUCCESS(rc))
477 {
478 Utf8Str strKey = listPair.at(p++);
479 if ( strKey.isEmpty()
480 || strKey.equals("=")) /* Skip pairs with empty keys (e.g. "=FOO"). */
481 {
482 break;
483 }
484 Utf8Str strValue;
485 if (p < listPair.size()) /* Does the list also contain a value? */
486 strValue = listPair.at(p++);
487
488#ifdef DEBUG
489 LogFlowFunc(("strKey=%s, strValue=%s\n",
490 strKey.c_str(), strValue.c_str()));
491#endif
492 rc = Set(strKey, strValue);
493 }
494
495 return rc;
496}
497
498size_t GuestEnvironment::Size(void)
499{
500 return mEnvironment.size();
501}
502
503int GuestEnvironment::Unset(const Utf8Str &strKey)
504{
505 std::map <Utf8Str, Utf8Str>::iterator itEnv = mEnvironment.find(strKey);
506 if (itEnv != mEnvironment.end())
507 {
508 mEnvironment.erase(itEnv);
509 return VINF_SUCCESS;
510 }
511
512 return VERR_NOT_FOUND;
513}
514
515GuestEnvironment& GuestEnvironment::operator=(const GuestEnvironmentArray &that)
516{
517 CopyFrom(that);
518 return *this;
519}
520
521GuestEnvironment& GuestEnvironment::operator=(const GuestEnvironment &that)
522{
523 for (std::map<Utf8Str, Utf8Str>::const_iterator it = that.mEnvironment.begin();
524 it != that.mEnvironment.end();
525 ++it)
526 {
527 mEnvironment[it->first] = it->second;
528 }
529
530 return *this;
531}
532
533/**
534 * Appends environment variables to the environment block.
535 *
536 * Each var=value pair is separated by the null character ('\\0'). The whole
537 * block will be stored in one blob and disassembled on the guest side later to
538 * fit into the HGCM param structure.
539 *
540 * @returns VBox status code.
541 *
542 * @param pszEnvVar The environment variable=value to append to the
543 * environment block.
544 * @param ppvList This is actually a pointer to a char pointer
545 * variable which keeps track of the environment block
546 * that we're constructing.
547 * @param pcbList Pointer to the variable holding the current size of
548 * the environment block. (List is a misnomer, go
549 * ahead a be confused.)
550 * @param pcEnvVars Pointer to the variable holding count of variables
551 * stored in the environment block.
552 */
553int GuestEnvironment::appendToEnvBlock(const char *pszEnv, void **ppvList, size_t *pcbList, uint32_t *pcEnvVars)
554{
555 int rc = VINF_SUCCESS;
556 size_t cchEnv = strlen(pszEnv); Assert(cchEnv >= 2);
557 if (*ppvList)
558 {
559 size_t cbNewLen = *pcbList + cchEnv + 1; /* Include zero termination. */
560 char *pvTmp = (char *)RTMemRealloc(*ppvList, cbNewLen);
561 if (pvTmp == NULL)
562 rc = VERR_NO_MEMORY;
563 else
564 {
565 memcpy(pvTmp + *pcbList, pszEnv, cchEnv);
566 pvTmp[cbNewLen - 1] = '\0'; /* Add zero termination. */
567 *ppvList = (void **)pvTmp;
568 }
569 }
570 else
571 {
572 char *pszTmp;
573 if (RTStrAPrintf(&pszTmp, "%s", pszEnv) >= 0)
574 {
575 *ppvList = (void **)pszTmp;
576 /* Reset counters. */
577 *pcEnvVars = 0;
578 *pcbList = 0;
579 }
580 }
581 if (RT_SUCCESS(rc))
582 {
583 *pcbList += cchEnv + 1; /* Include zero termination. */
584 *pcEnvVars += 1; /* Increase env variable count. */
585 }
586 return rc;
587}
588
589int GuestFsObjData::FromLs(const GuestProcessStreamBlock &strmBlk)
590{
591 LogFlowFunc(("\n"));
592
593 int rc = VINF_SUCCESS;
594
595 try
596 {
597#ifdef DEBUG
598 strmBlk.DumpToLog();
599#endif
600 /* Object name. */
601 mName = strmBlk.GetString("name");
602 if (mName.isEmpty()) throw VERR_NOT_FOUND;
603 /* Type. */
604 Utf8Str strType(strmBlk.GetString("ftype"));
605 if (strType.equalsIgnoreCase("-"))
606 mType = FsObjType_File;
607 else if (strType.equalsIgnoreCase("d"))
608 mType = FsObjType_Directory;
609 /** @todo Add more types! */
610 else
611 mType = FsObjType_Undefined;
612 /* Object size. */
613 rc = strmBlk.GetInt64Ex("st_size", &mObjectSize);
614 if (RT_FAILURE(rc)) throw rc;
615 /** @todo Add complete ls info! */
616 }
617 catch (int rc2)
618 {
619 rc = rc2;
620 }
621
622 LogFlowFuncLeaveRC(rc);
623 return rc;
624}
625
626int GuestFsObjData::FromStat(const GuestProcessStreamBlock &strmBlk)
627{
628 LogFlowFunc(("\n"));
629
630 int rc = VINF_SUCCESS;
631
632 try
633 {
634#ifdef DEBUG
635 strmBlk.DumpToLog();
636#endif
637 /* Node ID, optional because we don't include this
638 * in older VBoxService (< 4.2) versions. */
639 mNodeID = strmBlk.GetInt64("node_id");
640 /* Object name. */
641 mName = strmBlk.GetString("name");
642 if (mName.isEmpty()) throw VERR_NOT_FOUND;
643 /* Type. */
644 Utf8Str strType(strmBlk.GetString("ftype"));
645 if (strType.equalsIgnoreCase("-"))
646 mType = FsObjType_File;
647 else if (strType.equalsIgnoreCase("d"))
648 mType = FsObjType_Directory;
649 /** @todo Add more types! */
650 else
651 mType = FsObjType_Undefined;
652 /* Object size. */
653 rc = strmBlk.GetInt64Ex("st_size", &mObjectSize);
654 if (RT_FAILURE(rc)) throw rc;
655 /** @todo Add complete stat info! */
656 }
657 catch (int rc2)
658 {
659 rc = rc2;
660 }
661
662 LogFlowFuncLeaveRC(rc);
663 return rc;
664}
665
666///////////////////////////////////////////////////////////////////////////////
667
668/** @todo *NOT* thread safe yet! */
669/** @todo Add exception handling for STL stuff! */
670
671GuestProcessStreamBlock::GuestProcessStreamBlock(void)
672{
673
674}
675
676/*
677GuestProcessStreamBlock::GuestProcessStreamBlock(const GuestProcessStreamBlock &otherBlock)
678{
679 for (GuestCtrlStreamPairsIter it = otherBlock.m_mapPairs.begin();
680 it != otherBlock.end(); it++)
681 {
682 m_mapPairs[it->first] = new
683 if (it->second.pszValue)
684 {
685 RTMemFree(it->second.pszValue);
686 it->second.pszValue = NULL;
687 }
688 }
689}*/
690
691GuestProcessStreamBlock::~GuestProcessStreamBlock()
692{
693 Clear();
694}
695
696/**
697 * Destroys the currently stored stream pairs.
698 *
699 * @return IPRT status code.
700 */
701void GuestProcessStreamBlock::Clear(void)
702{
703 m_mapPairs.clear();
704}
705
706#ifdef DEBUG
707void GuestProcessStreamBlock::DumpToLog(void) const
708{
709 LogFlowFunc(("Dumping contents of stream block=0x%p (%ld items):\n",
710 this, m_mapPairs.size()));
711
712 for (GuestCtrlStreamPairMapIterConst it = m_mapPairs.begin();
713 it != m_mapPairs.end(); it++)
714 {
715 LogFlowFunc(("\t%s=%s\n", it->first.c_str(), it->second.mValue.c_str()));
716 }
717}
718#endif
719
720/**
721 * Returns a 64-bit signed integer of a specified key.
722 *
723 * @return IPRT status code. VERR_NOT_FOUND if key was not found.
724 * @param pszKey Name of key to get the value for.
725 * @param piVal Pointer to value to return.
726 */
727int GuestProcessStreamBlock::GetInt64Ex(const char *pszKey, int64_t *piVal) const
728{
729 AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
730 AssertPtrReturn(piVal, VERR_INVALID_POINTER);
731 const char *pszValue = GetString(pszKey);
732 if (pszValue)
733 {
734 *piVal = RTStrToInt64(pszValue);
735 return VINF_SUCCESS;
736 }
737 return VERR_NOT_FOUND;
738}
739
740/**
741 * Returns a 64-bit integer of a specified key.
742 *
743 * @return int64_t Value to return, 0 if not found / on failure.
744 * @param pszKey Name of key to get the value for.
745 */
746int64_t GuestProcessStreamBlock::GetInt64(const char *pszKey) const
747{
748 int64_t iVal;
749 if (RT_SUCCESS(GetInt64Ex(pszKey, &iVal)))
750 return iVal;
751 return 0;
752}
753
754/**
755 * Returns the current number of stream pairs.
756 *
757 * @return uint32_t Current number of stream pairs.
758 */
759size_t GuestProcessStreamBlock::GetCount(void) const
760{
761 return m_mapPairs.size();
762}
763
764/**
765 * Returns a string value of a specified key.
766 *
767 * @return uint32_t Pointer to string to return, NULL if not found / on failure.
768 * @param pszKey Name of key to get the value for.
769 */
770const char* GuestProcessStreamBlock::GetString(const char *pszKey) const
771{
772 AssertPtrReturn(pszKey, NULL);
773
774 try
775 {
776 GuestCtrlStreamPairMapIterConst itPairs = m_mapPairs.find(Utf8Str(pszKey));
777 if (itPairs != m_mapPairs.end())
778 return itPairs->second.mValue.c_str();
779 }
780 catch (const std::exception &ex)
781 {
782 NOREF(ex);
783 }
784 return NULL;
785}
786
787/**
788 * Returns a 32-bit unsigned integer of a specified key.
789 *
790 * @return IPRT status code. VERR_NOT_FOUND if key was not found.
791 * @param pszKey Name of key to get the value for.
792 * @param puVal Pointer to value to return.
793 */
794int GuestProcessStreamBlock::GetUInt32Ex(const char *pszKey, uint32_t *puVal) const
795{
796 AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
797 AssertPtrReturn(puVal, VERR_INVALID_POINTER);
798 const char *pszValue = GetString(pszKey);
799 if (pszValue)
800 {
801 *puVal = RTStrToUInt32(pszValue);
802 return VINF_SUCCESS;
803 }
804 return VERR_NOT_FOUND;
805}
806
807/**
808 * Returns a 32-bit unsigned integer of a specified key.
809 *
810 * @return uint32_t Value to return, 0 if not found / on failure.
811 * @param pszKey Name of key to get the value for.
812 */
813uint32_t GuestProcessStreamBlock::GetUInt32(const char *pszKey) const
814{
815 uint32_t uVal;
816 if (RT_SUCCESS(GetUInt32Ex(pszKey, &uVal)))
817 return uVal;
818 return 0;
819}
820
821/**
822 * Sets a value to a key or deletes a key by setting a NULL value.
823 *
824 * @return IPRT status code.
825 * @param pszKey Key name to process.
826 * @param pszValue Value to set. Set NULL for deleting the key.
827 */
828int GuestProcessStreamBlock::SetValue(const char *pszKey, const char *pszValue)
829{
830 AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
831
832 int rc = VINF_SUCCESS;
833 try
834 {
835 Utf8Str Utf8Key(pszKey);
836
837 /* Take a shortcut and prevent crashes on some funny versions
838 * of STL if map is empty initially. */
839 if (!m_mapPairs.empty())
840 {
841 GuestCtrlStreamPairMapIter it = m_mapPairs.find(Utf8Key);
842 if (it != m_mapPairs.end())
843 m_mapPairs.erase(it);
844 }
845
846 if (pszValue)
847 {
848 GuestProcessStreamValue val(pszValue);
849 m_mapPairs[Utf8Key] = val;
850 }
851 }
852 catch (const std::exception &ex)
853 {
854 NOREF(ex);
855 }
856 return rc;
857}
858
859///////////////////////////////////////////////////////////////////////////////
860
861GuestProcessStream::GuestProcessStream(void)
862 : m_cbAllocated(0),
863 m_cbSize(0),
864 m_cbOffset(0),
865 m_pbBuffer(NULL)
866{
867
868}
869
870GuestProcessStream::~GuestProcessStream(void)
871{
872 Destroy();
873}
874
875/**
876 * Adds data to the internal parser buffer. Useful if there
877 * are multiple rounds of adding data needed.
878 *
879 * @return IPRT status code.
880 * @param pbData Pointer to data to add.
881 * @param cbData Size (in bytes) of data to add.
882 */
883int GuestProcessStream::AddData(const BYTE *pbData, size_t cbData)
884{
885 AssertPtrReturn(pbData, VERR_INVALID_POINTER);
886 AssertReturn(cbData, VERR_INVALID_PARAMETER);
887
888 int rc = VINF_SUCCESS;
889
890 /* Rewind the buffer if it's empty. */
891 size_t cbInBuf = m_cbSize - m_cbOffset;
892 bool const fAddToSet = cbInBuf == 0;
893 if (fAddToSet)
894 m_cbSize = m_cbOffset = 0;
895
896 /* Try and see if we can simply append the data. */
897 if (cbData + m_cbSize <= m_cbAllocated)
898 {
899 memcpy(&m_pbBuffer[m_cbSize], pbData, cbData);
900 m_cbSize += cbData;
901 }
902 else
903 {
904 /* Move any buffered data to the front. */
905 cbInBuf = m_cbSize - m_cbOffset;
906 if (cbInBuf == 0)
907 m_cbSize = m_cbOffset = 0;
908 else if (m_cbOffset) /* Do we have something to move? */
909 {
910 memmove(m_pbBuffer, &m_pbBuffer[m_cbOffset], cbInBuf);
911 m_cbSize = cbInBuf;
912 m_cbOffset = 0;
913 }
914
915 /* Do we need to grow the buffer? */
916 if (cbData + m_cbSize > m_cbAllocated)
917 {
918 size_t cbAlloc = m_cbSize + cbData;
919 cbAlloc = RT_ALIGN_Z(cbAlloc, _64K);
920 void *pvNew = RTMemRealloc(m_pbBuffer, cbAlloc);
921 if (pvNew)
922 {
923 m_pbBuffer = (uint8_t *)pvNew;
924 m_cbAllocated = cbAlloc;
925 }
926 else
927 rc = VERR_NO_MEMORY;
928 }
929
930 /* Finally, copy the data. */
931 if (RT_SUCCESS(rc))
932 {
933 if (cbData + m_cbSize <= m_cbAllocated)
934 {
935 memcpy(&m_pbBuffer[m_cbSize], pbData, cbData);
936 m_cbSize += cbData;
937 }
938 else
939 rc = VERR_BUFFER_OVERFLOW;
940 }
941 }
942
943 return rc;
944}
945
946/**
947 * Destroys the internal data buffer.
948 */
949void GuestProcessStream::Destroy(void)
950{
951 if (m_pbBuffer)
952 {
953 RTMemFree(m_pbBuffer);
954 m_pbBuffer = NULL;
955 }
956
957 m_cbAllocated = 0;
958 m_cbSize = 0;
959 m_cbOffset = 0;
960}
961
962#ifdef DEBUG
963void GuestProcessStream::Dump(const char *pszFile)
964{
965 LogFlowFunc(("Dumping contents of stream=0x%p (cbAlloc=%u, cbSize=%u, cbOff=%u) to %s\n",
966 m_pbBuffer, m_cbAllocated, m_cbSize, m_cbOffset, pszFile));
967
968 RTFILE hFile;
969 int rc = RTFileOpen(&hFile, pszFile, RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE);
970 if (RT_SUCCESS(rc))
971 {
972 rc = RTFileWrite(hFile, m_pbBuffer, m_cbSize, NULL /* pcbWritten */);
973 RTFileClose(hFile);
974 }
975}
976#endif
977
978/**
979 * Returns the current offset of the parser within
980 * the internal data buffer.
981 *
982 * @return uint32_t Parser offset.
983 */
984uint32_t GuestProcessStream::GetOffset()
985{
986 return m_cbOffset;
987}
988
989uint32_t GuestProcessStream::GetSize()
990{
991 return m_cbSize;
992}
993
994/**
995 * Tries to parse the next upcoming pair block within the internal
996 * buffer.
997 *
998 * Returns VERR_NO_DATA is no data is in internal buffer or buffer has been
999 * completely parsed already.
1000 *
1001 * Returns VERR_MORE_DATA if current block was parsed (with zero or more pairs
1002 * stored in stream block) but still contains incomplete (unterminated)
1003 * data.
1004 *
1005 * Returns VINF_SUCCESS if current block was parsed until the next upcoming
1006 * block (with zero or more pairs stored in stream block).
1007 *
1008 * @return IPRT status code.
1009 * @param streamBlock Reference to guest stream block to fill.
1010 *
1011 */
1012int GuestProcessStream::ParseBlock(GuestProcessStreamBlock &streamBlock)
1013{
1014 if ( !m_pbBuffer
1015 || !m_cbSize)
1016 {
1017 return VERR_NO_DATA;
1018 }
1019
1020 AssertReturn(m_cbOffset <= m_cbSize, VERR_INVALID_PARAMETER);
1021 if (m_cbOffset == m_cbSize)
1022 return VERR_NO_DATA;
1023
1024 int rc = VINF_SUCCESS;
1025
1026 char *pszOff = (char*)&m_pbBuffer[m_cbOffset];
1027 char *pszStart = pszOff;
1028 uint32_t uDistance;
1029 while (*pszStart)
1030 {
1031 size_t pairLen = strlen(pszStart);
1032 uDistance = (pszStart - pszOff);
1033 if (m_cbOffset + uDistance + pairLen + 1 >= m_cbSize)
1034 {
1035 rc = VERR_MORE_DATA;
1036 break;
1037 }
1038 else
1039 {
1040 char *pszSep = strchr(pszStart, '=');
1041 char *pszVal = NULL;
1042 if (pszSep)
1043 pszVal = pszSep + 1;
1044 if (!pszSep || !pszVal)
1045 {
1046 rc = VERR_MORE_DATA;
1047 break;
1048 }
1049
1050 /* Terminate the separator so that we can
1051 * use pszStart as our key from now on. */
1052 *pszSep = '\0';
1053
1054 rc = streamBlock.SetValue(pszStart, pszVal);
1055 if (RT_FAILURE(rc))
1056 return rc;
1057 }
1058
1059 /* Next pair. */
1060 pszStart += pairLen + 1;
1061 }
1062
1063 /* If we did not do any movement but we have stuff left
1064 * in our buffer just skip the current termination so that
1065 * we can try next time. */
1066 uDistance = (pszStart - pszOff);
1067 if ( !uDistance
1068 && *pszStart == '\0'
1069 && m_cbOffset < m_cbSize)
1070 {
1071 uDistance++;
1072 }
1073 m_cbOffset += uDistance;
1074
1075 return rc;
1076}
1077
Note: See TracBrowser for help on using the repository browser.

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