VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/GuestCtrlIO.cpp@ 40192

Last change on this file since 40192 was 39843, checked in by vboxsync, 13 years ago

GuestCtrl: Request (IPC) changes, bugfixes, fixed handle leaks.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.5 KB
Line 
1/* $Id: GuestCtrlIO.cpp 39843 2012-01-23 18:38:18Z vboxsync $ */
2/** @file
3 *
4 * IO helper for IGuest COM class implementations.
5 */
6
7/*
8 * Copyright (C) 2011 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#ifdef DEBUG
24# include "Logging.h"
25# include <iprt/file.h>
26#endif /* DEBUG */
27
28/******************************************************************************
29 * Structures and Typedefs *
30 ******************************************************************************/
31
32/** @todo *NOT* thread safe yet! */
33/** @todo Add exception handling for STL stuff! */
34
35GuestProcessStreamBlock::GuestProcessStreamBlock()
36{
37
38}
39
40/*
41GuestProcessStreamBlock::GuestProcessStreamBlock(const GuestProcessStreamBlock &otherBlock)
42{
43 for (GuestCtrlStreamPairsIter it = otherBlock.m_mapPairs.begin();
44 it != otherBlock.end(); it++)
45 {
46 m_mapPairs[it->first] = new
47 if (it->second.pszValue)
48 {
49 RTMemFree(it->second.pszValue);
50 it->second.pszValue = NULL;
51 }
52 }
53}*/
54
55GuestProcessStreamBlock::~GuestProcessStreamBlock()
56{
57 Clear();
58}
59
60/**
61 * Destroys the currently stored stream pairs.
62 *
63 * @return IPRT status code.
64 */
65void GuestProcessStreamBlock::Clear()
66{
67 m_mapPairs.clear();
68}
69
70#ifdef DEBUG
71void GuestProcessStreamBlock::Dump()
72{
73 LogFlowFunc(("Dumping contents of stream block=0x%p (%ld items):\n",
74 this, m_mapPairs.size()));
75
76 for (GuestCtrlStreamPairMapIterConst it = m_mapPairs.begin();
77 it != m_mapPairs.end(); it++)
78 {
79 LogFlowFunc(("\t%s=%s\n", it->first.c_str(), it->second.mValue.c_str()));
80 }
81}
82#endif
83
84/**
85 * Returns a 64-bit signed integer of a specified key.
86 *
87 * @return IPRT status code. VERR_NOT_FOUND if key was not found.
88 * @param pszKey Name of key to get the value for.
89 * @param piVal Pointer to value to return.
90 */
91int GuestProcessStreamBlock::GetInt64Ex(const char *pszKey, int64_t *piVal)
92{
93 AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
94 AssertPtrReturn(piVal, VERR_INVALID_POINTER);
95 const char *pszValue = GetString(pszKey);
96 if (pszValue)
97 {
98 *piVal = RTStrToInt64(pszValue);
99 return VINF_SUCCESS;
100 }
101 return VERR_NOT_FOUND;
102}
103
104/**
105 * Returns a 64-bit integer of a specified key.
106 *
107 * @return int64_t Value to return, 0 if not found / on failure.
108 * @param pszKey Name of key to get the value for.
109 */
110int64_t GuestProcessStreamBlock::GetInt64(const char *pszKey)
111{
112 int64_t iVal;
113 if (RT_SUCCESS(GetInt64Ex(pszKey, &iVal)))
114 return iVal;
115 return 0;
116}
117
118/**
119 * Returns the current number of stream pairs.
120 *
121 * @return uint32_t Current number of stream pairs.
122 */
123size_t GuestProcessStreamBlock::GetCount()
124{
125 return m_mapPairs.size();
126}
127
128/**
129 * Returns a string value of a specified key.
130 *
131 * @return uint32_t Pointer to string to return, NULL if not found / on failure.
132 * @param pszKey Name of key to get the value for.
133 */
134const char* GuestProcessStreamBlock::GetString(const char *pszKey)
135{
136 AssertPtrReturn(pszKey, NULL);
137
138 try
139 {
140 GuestCtrlStreamPairMapIterConst itPairs = m_mapPairs.find(Utf8Str(pszKey));
141 if (itPairs != m_mapPairs.end())
142 return itPairs->second.mValue.c_str();
143 }
144 catch (const std::exception &ex)
145 {
146 NOREF(ex);
147 }
148 return NULL;
149}
150
151/**
152 * Returns a 32-bit unsigned integer of a specified key.
153 *
154 * @return IPRT status code. VERR_NOT_FOUND if key was not found.
155 * @param pszKey Name of key to get the value for.
156 * @param puVal Pointer to value to return.
157 */
158int GuestProcessStreamBlock::GetUInt32Ex(const char *pszKey, uint32_t *puVal)
159{
160 AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
161 AssertPtrReturn(puVal, VERR_INVALID_POINTER);
162 const char *pszValue = GetString(pszKey);
163 if (pszValue)
164 {
165 *puVal = RTStrToUInt32(pszValue);
166 return VINF_SUCCESS;
167 }
168 return VERR_NOT_FOUND;
169}
170
171/**
172 * Returns a 32-bit unsigned integer of a specified key.
173 *
174 * @return uint32_t Value to return, 0 if not found / on failure.
175 * @param pszKey Name of key to get the value for.
176 */
177uint32_t GuestProcessStreamBlock::GetUInt32(const char *pszKey)
178{
179 uint32_t uVal;
180 if (RT_SUCCESS(GetUInt32Ex(pszKey, &uVal)))
181 return uVal;
182 return 0;
183}
184
185/**
186 * Sets a value to a key or deletes a key by setting a NULL value.
187 *
188 * @return IPRT status code.
189 * @param pszKey Key name to process.
190 * @param pszValue Value to set. Set NULL for deleting the key.
191 */
192int GuestProcessStreamBlock::SetValue(const char *pszKey, const char *pszValue)
193{
194 AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
195
196 int rc = VINF_SUCCESS;
197 try
198 {
199 Utf8Str Utf8Key(pszKey);
200
201 /* Take a shortcut and prevent crashes on some funny versions
202 * of STL if map is empty initially. */
203 if (!m_mapPairs.empty())
204 {
205 GuestCtrlStreamPairMapIter it = m_mapPairs.find(Utf8Key);
206 if (it != m_mapPairs.end())
207 m_mapPairs.erase(it);
208 }
209
210 if (pszValue)
211 {
212 GuestProcessStreamValue val(pszValue);
213 m_mapPairs[Utf8Key] = val;
214 }
215 }
216 catch (const std::exception &ex)
217 {
218 NOREF(ex);
219 }
220 return rc;
221}
222
223///////////////////////////////////////////////////////////////////////////////
224
225GuestProcessStream::GuestProcessStream()
226 : m_cbAllocated(0),
227 m_cbSize(0),
228 m_cbOffset(0),
229 m_pbBuffer(NULL)
230{
231
232}
233
234GuestProcessStream::~GuestProcessStream()
235{
236 Destroy();
237}
238
239/**
240 * Adds data to the internal parser buffer. Useful if there
241 * are multiple rounds of adding data needed.
242 *
243 * @return IPRT status code.
244 * @param pbData Pointer to data to add.
245 * @param cbData Size (in bytes) of data to add.
246 */
247int GuestProcessStream::AddData(const BYTE *pbData, size_t cbData)
248{
249 AssertPtrReturn(pbData, VERR_INVALID_POINTER);
250 AssertReturn(cbData, VERR_INVALID_PARAMETER);
251
252 int rc = VINF_SUCCESS;
253
254 /* Rewind the buffer if it's empty. */
255 size_t cbInBuf = m_cbSize - m_cbOffset;
256 bool const fAddToSet = cbInBuf == 0;
257 if (fAddToSet)
258 m_cbSize = m_cbOffset = 0;
259
260 /* Try and see if we can simply append the data. */
261 if (cbData + m_cbSize <= m_cbAllocated)
262 {
263 memcpy(&m_pbBuffer[m_cbSize], pbData, cbData);
264 m_cbSize += cbData;
265 }
266 else
267 {
268 /* Move any buffered data to the front. */
269 cbInBuf = m_cbSize - m_cbOffset;
270 if (cbInBuf == 0)
271 m_cbSize = m_cbOffset = 0;
272 else if (m_cbOffset) /* Do we have something to move? */
273 {
274 memmove(m_pbBuffer, &m_pbBuffer[m_cbOffset], cbInBuf);
275 m_cbSize = cbInBuf;
276 m_cbOffset = 0;
277 }
278
279 /* Do we need to grow the buffer? */
280 if (cbData + m_cbSize > m_cbAllocated)
281 {
282 size_t cbAlloc = m_cbSize + cbData;
283 cbAlloc = RT_ALIGN_Z(cbAlloc, _64K);
284 void *pvNew = RTMemRealloc(m_pbBuffer, cbAlloc);
285 if (pvNew)
286 {
287 m_pbBuffer = (uint8_t *)pvNew;
288 m_cbAllocated = cbAlloc;
289 }
290 else
291 rc = VERR_NO_MEMORY;
292 }
293
294 /* Finally, copy the data. */
295 if (RT_SUCCESS(rc))
296 {
297 if (cbData + m_cbSize <= m_cbAllocated)
298 {
299 memcpy(&m_pbBuffer[m_cbSize], pbData, cbData);
300 m_cbSize += cbData;
301 }
302 else
303 rc = VERR_BUFFER_OVERFLOW;
304 }
305 }
306
307 return rc;
308}
309
310/**
311 * Destroys the the internal data buffer.
312 */
313void GuestProcessStream::Destroy()
314{
315 if (m_pbBuffer)
316 {
317 RTMemFree(m_pbBuffer);
318 m_pbBuffer = NULL;
319 }
320
321 m_cbAllocated = 0;
322 m_cbSize = 0;
323 m_cbOffset = 0;
324}
325
326#ifdef DEBUG
327void GuestProcessStream::Dump(const char *pszFile)
328{
329 LogFlowFunc(("Dumping contents of stream=0x%p (cbAlloc=%u, cbSize=%u, cbOff=%u) to %s\n",
330 m_pbBuffer, m_cbAllocated, m_cbSize, m_cbOffset, pszFile));
331
332 RTFILE hFile;
333 int rc = RTFileOpen(&hFile, pszFile, RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE);
334 if (RT_SUCCESS(rc))
335 {
336 rc = RTFileWrite(hFile, m_pbBuffer, m_cbSize, NULL /* pcbWritten */);
337 RTFileClose(hFile);
338 }
339}
340#endif
341
342/**
343 * Returns the current offset of the parser within
344 * the internal data buffer.
345 *
346 * @return uint32_t Parser offset.
347 */
348uint32_t GuestProcessStream::GetOffset()
349{
350 return m_cbOffset;
351}
352
353uint32_t GuestProcessStream::GetSize()
354{
355 return m_cbSize;
356}
357
358/**
359 * Tries to parse the next upcoming pair block within the internal
360 * buffer.
361 *
362 * Returns VERR_NO_DATA is no data is in internal buffer or buffer has been
363 * completely parsed already.
364 *
365 * Returns VERR_MORE_DATA if current block was parsed (with zero or more pairs
366 * stored in stream block) but still contains incomplete (unterminated)
367 * data.
368 *
369 * Returns VINF_SUCCESS if current block was parsed until the next upcoming
370 * block (with zero or more pairs stored in stream block).
371 *
372 * @return IPRT status code.
373 * @param streamBlock Reference to guest stream block to fill.
374 *
375 */
376int GuestProcessStream::ParseBlock(GuestProcessStreamBlock &streamBlock)
377{
378 if ( !m_pbBuffer
379 || !m_cbSize)
380 {
381 return VERR_NO_DATA;
382 }
383
384 AssertReturn(m_cbOffset <= m_cbSize, VERR_INVALID_PARAMETER);
385 if (m_cbOffset == m_cbSize)
386 return VERR_NO_DATA;
387
388 int rc = VINF_SUCCESS;
389
390 char *pszOff = (char*)&m_pbBuffer[m_cbOffset];
391 char *pszStart = pszOff;
392 uint32_t uDistance;
393 while (*pszStart)
394 {
395 size_t pairLen = strlen(pszStart);
396 uDistance = (pszStart - pszOff);
397 if (m_cbOffset + uDistance + pairLen + 1 >= m_cbSize)
398 {
399 rc = VERR_MORE_DATA;
400 break;
401 }
402 else
403 {
404 char *pszSep = strchr(pszStart, '=');
405 char *pszVal = NULL;
406 if (pszSep)
407 pszVal = pszSep + 1;
408 if (!pszSep || !pszVal)
409 {
410 rc = VERR_MORE_DATA;
411 break;
412 }
413
414 /* Terminate the separator so that we can
415 * use pszStart as our key from now on. */
416 *pszSep = '\0';
417
418 rc = streamBlock.SetValue(pszStart, pszVal);
419 if (RT_FAILURE(rc))
420 return rc;
421 }
422
423 /* Next pair. */
424 pszStart += pairLen + 1;
425 }
426
427 /* If we did not do any movement but we have stuff left
428 * in our buffer just skip the current termination so that
429 * we can try next time. */
430 uDistance = (pszStart - pszOff);
431 if ( !uDistance
432 && *pszStart == '\0'
433 && m_cbOffset < m_cbSize)
434 {
435 uDistance++;
436 }
437 m_cbOffset += uDistance;
438
439 return rc;
440}
441
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