VirtualBox

source: vbox/trunk/src/VBox/HostServices/GuestProperties/service.cpp@ 43687

Last change on this file since 43687 was 40767, checked in by vboxsync, 13 years ago

also enumerate guest properties during guru meditation

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 47.4 KB
Line 
1/* $Id: service.cpp 40767 2012-04-05 09:47:33Z vboxsync $ */
2/** @file
3 * Guest Property Service: Host service entry points.
4 */
5
6/*
7 * Copyright (C) 2008 Oracle Corporation
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
18/** @page pg_svc_guest_properties Guest Property HGCM Service
19 *
20 * This HGCM service allows the guest to set and query values in a property
21 * store on the host. The service proxies the guest requests to the service
22 * owner on the host using a request callback provided by the owner, and is
23 * notified of changes to properties made by the host. It forwards these
24 * notifications to clients in the guest which have expressed interest and
25 * are waiting for notification.
26 *
27 * The service currently consists of two threads. One of these is the main
28 * HGCM service thread which deals with requests from the guest and from the
29 * host. The second thread sends the host asynchronous notifications of
30 * changes made by the guest and deals with notification timeouts.
31 *
32 * Guest requests to wait for notification are added to a list of open
33 * notification requests and completed when a corresponding guest property
34 * is changed or when the request times out.
35 */
36
37/*******************************************************************************
38* Header Files *
39*******************************************************************************/
40#define LOG_GROUP LOG_GROUP_HGCM
41#include <VBox/HostServices/GuestPropertySvc.h>
42
43#include <VBox/log.h>
44#include <iprt/asm.h>
45#include <iprt/assert.h>
46#include <iprt/cpp/autores.h>
47#include <iprt/cpp/utils.h>
48#include <iprt/err.h>
49#include <iprt/mem.h>
50#include <iprt/req.h>
51#include <iprt/string.h>
52#include <iprt/thread.h>
53#include <iprt/time.h>
54#include <VBox/vmm/dbgf.h>
55
56#include <memory> /* for auto_ptr */
57#include <string>
58#include <list>
59
60namespace guestProp {
61
62/**
63 * Structure for holding a property
64 */
65struct Property
66{
67 /** The string space core record. */
68 RTSTRSPACECORE mStrCore;
69 /** The name of the property */
70 std::string mName;
71 /** The property value */
72 std::string mValue;
73 /** The timestamp of the property */
74 uint64_t mTimestamp;
75 /** The property flags */
76 uint32_t mFlags;
77
78 /** Default constructor */
79 Property() : mTimestamp(0), mFlags(NILFLAG)
80 {
81 RT_ZERO(mStrCore);
82 }
83 /** Constructor with const char * */
84 Property(const char *pcszName, const char *pcszValue,
85 uint64_t u64Timestamp, uint32_t u32Flags)
86 : mName(pcszName), mValue(pcszValue), mTimestamp(u64Timestamp),
87 mFlags(u32Flags)
88 {
89 RT_ZERO(mStrCore);
90 mStrCore.pszString = mName.c_str();
91 }
92 /** Constructor with std::string */
93 Property(std::string name, std::string value, uint64_t u64Timestamp,
94 uint32_t u32Flags)
95 : mName(name), mValue(value), mTimestamp(u64Timestamp),
96 mFlags(u32Flags) {}
97
98 /** Does the property name match one of a set of patterns? */
99 bool Matches(const char *pszPatterns) const
100 {
101 return ( pszPatterns[0] == '\0' /* match all */
102 || RTStrSimplePatternMultiMatch(pszPatterns, RTSTR_MAX,
103 mName.c_str(), RTSTR_MAX,
104 NULL)
105 );
106 }
107
108 /** Are two properties equal? */
109 bool operator==(const Property &prop)
110 {
111 if (mTimestamp != prop.mTimestamp)
112 return false;
113 if (mFlags != prop.mFlags)
114 return false;
115 if (mName != prop.mName)
116 return false;
117 if (mValue != prop.mValue)
118 return false;
119 return true;
120 }
121
122 /* Is the property nil? */
123 bool isNull()
124 {
125 return mName.empty();
126 }
127};
128/** The properties list type */
129typedef std::list <Property> PropertyList;
130
131/**
132 * Structure for holding an uncompleted guest call
133 */
134struct GuestCall
135{
136 /** The call handle */
137 VBOXHGCMCALLHANDLE mHandle;
138 /** The function that was requested */
139 uint32_t mFunction;
140 /** The call parameters */
141 VBOXHGCMSVCPARM *mParms;
142 /** The default return value, used for passing warnings */
143 int mRc;
144
145 /** The standard constructor */
146 GuestCall() : mFunction(0) {}
147 /** The normal constructor */
148 GuestCall(VBOXHGCMCALLHANDLE aHandle, uint32_t aFunction,
149 VBOXHGCMSVCPARM aParms[], int aRc)
150 : mHandle(aHandle), mFunction(aFunction), mParms(aParms),
151 mRc(aRc) {}
152};
153/** The guest call list type */
154typedef std::list <GuestCall> CallList;
155
156/**
157 * Class containing the shared information service functionality.
158 */
159class Service : public RTCNonCopyable
160{
161private:
162 /** Type definition for use in callback functions */
163 typedef Service SELF;
164 /** HGCM helper functions. */
165 PVBOXHGCMSVCHELPERS mpHelpers;
166 /** Global flags for the service */
167 ePropFlags meGlobalFlags;
168 /** The property string space handle. */
169 RTSTRSPACE mhProperties;
170 /** The number of properties. */
171 unsigned mcProperties;
172 /** The list of property changes for guest notifications */
173 PropertyList mGuestNotifications;
174 /** The list of outstanding guest notification calls */
175 CallList mGuestWaiters;
176 /** @todo we should have classes for thread and request handler thread */
177 /** Callback function supplied by the host for notification of updates
178 * to properties */
179 PFNHGCMSVCEXT mpfnHostCallback;
180 /** User data pointer to be supplied to the host callback function */
181 void *mpvHostData;
182 /** The previous timestamp.
183 * This is used by getCurrentTimestamp() to decrease the chance of
184 * generating duplicate timestamps. */
185 uint64_t mPrevTimestamp;
186 /** The number of consecutive timestamp adjustments that we've made.
187 * Together with mPrevTimestamp, this defines a set of obsolete timestamp
188 * values: {(mPrevTimestamp - mcTimestampAdjustments), ..., mPrevTimestamp} */
189 uint64_t mcTimestampAdjustments;
190
191 /**
192 * Get the next property change notification from the queue of saved
193 * notification based on the timestamp of the last notification seen.
194 * Notifications will only be reported if the property name matches the
195 * pattern given.
196 *
197 * @returns iprt status value
198 * @returns VWRN_NOT_FOUND if the last notification was not found in the queue
199 * @param pszPatterns the patterns to match the property name against
200 * @param u64Timestamp the timestamp of the last notification
201 * @param pProp where to return the property found. If none is
202 * found this will be set to nil.
203 * @thread HGCM
204 */
205 int getOldNotification(const char *pszPatterns, uint64_t u64Timestamp,
206 Property *pProp)
207 {
208 AssertPtrReturn(pszPatterns, VERR_INVALID_POINTER);
209 /* Zero means wait for a new notification. */
210 AssertReturn(u64Timestamp != 0, VERR_INVALID_PARAMETER);
211 AssertPtrReturn(pProp, VERR_INVALID_POINTER);
212 int rc = getOldNotificationInternal(pszPatterns, u64Timestamp, pProp);
213#ifdef VBOX_STRICT
214 /*
215 * ENSURE that pProp is the first event in the notification queue that:
216 * - Appears later than u64Timestamp
217 * - Matches the pszPatterns
218 */
219 /** @todo r=bird: This incorrectly ASSUMES that mTimestamp is unique.
220 * The timestamp resolution can be very coarse on windows for instance. */
221 PropertyList::const_iterator it = mGuestNotifications.begin();
222 for (; it != mGuestNotifications.end()
223 && it->mTimestamp != u64Timestamp; ++it)
224 {}
225 if (it == mGuestNotifications.end()) /* Not found */
226 it = mGuestNotifications.begin();
227 else
228 ++it; /* Next event */
229 for (; it != mGuestNotifications.end()
230 && it->mTimestamp != pProp->mTimestamp; ++it)
231 Assert(!it->Matches(pszPatterns));
232 if (pProp->mTimestamp != 0)
233 {
234 Assert(*pProp == *it);
235 Assert(pProp->Matches(pszPatterns));
236 }
237#endif /* VBOX_STRICT */
238 return rc;
239 }
240
241 /**
242 * Check whether we have permission to change a property.
243 *
244 * @returns Strict VBox status code.
245 * @retval VINF_SUCCESS if we do.
246 * @retval VERR_PERMISSION_DENIED if the value is read-only for the requesting
247 * side.
248 * @retval VINF_PERMISSION_DENIED if the side is globally marked read-only.
249 *
250 * @param eFlags the flags on the property in question
251 * @param isGuest is the guest or the host trying to make the change?
252 */
253 int checkPermission(ePropFlags eFlags, bool isGuest)
254 {
255 if (eFlags & (isGuest ? RDONLYGUEST : RDONLYHOST))
256 return VERR_PERMISSION_DENIED;
257 if (isGuest && (meGlobalFlags & RDONLYGUEST))
258 return VINF_PERMISSION_DENIED;
259 return VINF_SUCCESS;
260 }
261
262 /**
263 * Gets a property.
264 *
265 * @returns Pointer to the property if found, NULL if not.
266 *
267 * @param pszName The name of the property to get.
268 */
269 Property *getPropertyInternal(const char *pszName)
270 {
271 return (Property *)RTStrSpaceGet(&mhProperties, pszName);
272 }
273
274public:
275 explicit Service(PVBOXHGCMSVCHELPERS pHelpers)
276 : mpHelpers(pHelpers)
277 , meGlobalFlags(NILFLAG)
278 , mhProperties(NULL)
279 , mcProperties(0)
280 , mpfnHostCallback(NULL)
281 , mpvHostData(NULL)
282 , mPrevTimestamp(0)
283 , mcTimestampAdjustments(0)
284 { }
285
286 /**
287 * @copydoc VBOXHGCMSVCHELPERS::pfnUnload
288 * Simply deletes the service object
289 */
290 static DECLCALLBACK(int) svcUnload(void *pvService)
291 {
292 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
293 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
294 int rc = pSelf->uninit();
295 AssertRC(rc);
296 if (RT_SUCCESS(rc))
297 delete pSelf;
298 return rc;
299 }
300
301 /**
302 * @copydoc VBOXHGCMSVCHELPERS::pfnConnect
303 * Stub implementation of pfnConnect and pfnDisconnect.
304 */
305 static DECLCALLBACK(int) svcConnectDisconnect(void * /* pvService */,
306 uint32_t /* u32ClientID */,
307 void * /* pvClient */)
308 {
309 return VINF_SUCCESS;
310 }
311
312 /**
313 * @copydoc VBOXHGCMSVCHELPERS::pfnCall
314 * Wraps to the call member function
315 */
316 static DECLCALLBACK(void) svcCall(void * pvService,
317 VBOXHGCMCALLHANDLE callHandle,
318 uint32_t u32ClientID,
319 void *pvClient,
320 uint32_t u32Function,
321 uint32_t cParms,
322 VBOXHGCMSVCPARM paParms[])
323 {
324 AssertLogRelReturnVoid(VALID_PTR(pvService));
325 LogFlowFunc(("pvService=%p, callHandle=%p, u32ClientID=%u, pvClient=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, callHandle, u32ClientID, pvClient, u32Function, cParms, paParms));
326 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
327 pSelf->call(callHandle, u32ClientID, pvClient, u32Function, cParms, paParms);
328 LogFlowFunc(("returning\n"));
329 }
330
331 /**
332 * @copydoc VBOXHGCMSVCHELPERS::pfnHostCall
333 * Wraps to the hostCall member function
334 */
335 static DECLCALLBACK(int) svcHostCall(void *pvService,
336 uint32_t u32Function,
337 uint32_t cParms,
338 VBOXHGCMSVCPARM paParms[])
339 {
340 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
341 LogFlowFunc(("pvService=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, u32Function, cParms, paParms));
342 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
343 int rc = pSelf->hostCall(u32Function, cParms, paParms);
344 LogFlowFunc(("rc=%Rrc\n", rc));
345 return rc;
346 }
347
348 /**
349 * @copydoc VBOXHGCMSVCHELPERS::pfnRegisterExtension
350 * Installs a host callback for notifications of property changes.
351 */
352 static DECLCALLBACK(int) svcRegisterExtension(void *pvService,
353 PFNHGCMSVCEXT pfnExtension,
354 void *pvExtension)
355 {
356 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
357 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
358 pSelf->mpfnHostCallback = pfnExtension;
359 pSelf->mpvHostData = pvExtension;
360 return VINF_SUCCESS;
361 }
362
363private:
364 static DECLCALLBACK(int) reqThreadFn(RTTHREAD ThreadSelf, void *pvUser);
365 uint64_t getCurrentTimestamp(void);
366 int validateName(const char *pszName, uint32_t cbName);
367 int validateValue(const char *pszValue, uint32_t cbValue);
368 int setPropertyBlock(uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
369 int getProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
370 int setProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest);
371 int delProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest);
372 int enumProps(uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
373 int getNotification(VBOXHGCMCALLHANDLE callHandle, uint32_t cParms,
374 VBOXHGCMSVCPARM paParms[]);
375 int getOldNotificationInternal(const char *pszPattern,
376 uint64_t u64Timestamp, Property *pProp);
377 int getNotificationWriteOut(VBOXHGCMSVCPARM paParms[], Property prop);
378 void doNotifications(const char *pszProperty, uint64_t u64Timestamp);
379 int notifyHost(const char *pszName, const char *pszValue,
380 uint64_t u64Timestamp, const char *pszFlags);
381
382 void call(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID,
383 void *pvClient, uint32_t eFunction, uint32_t cParms,
384 VBOXHGCMSVCPARM paParms[]);
385 int hostCall(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
386 int uninit();
387 void dbgInfoShow(PCDBGFINFOHLP pHlp);
388 static DECLCALLBACK(void) dbgInfo(void *pvUser, PCDBGFINFOHLP pHlp, const char *pszArgs);
389};
390
391
392/**
393 * Gets the current timestamp.
394 *
395 * Since the RTTimeNow resolution can be very coarse, this method takes some
396 * simple steps to try avoid returning the same timestamp for two consecutive
397 * calls. Code like getOldNotification() more or less assumes unique
398 * timestamps.
399 *
400 * @returns Nanosecond timestamp.
401 */
402uint64_t Service::getCurrentTimestamp(void)
403{
404 RTTIMESPEC time;
405 uint64_t u64NanoTS = RTTimeSpecGetNano(RTTimeNow(&time));
406 if (mPrevTimestamp - u64NanoTS > mcTimestampAdjustments)
407 mcTimestampAdjustments = 0;
408 else
409 {
410 mcTimestampAdjustments++;
411 u64NanoTS = mPrevTimestamp + 1;
412 }
413 this->mPrevTimestamp = u64NanoTS;
414 return u64NanoTS;
415}
416
417/**
418 * Check that a string fits our criteria for a property name.
419 *
420 * @returns IPRT status code
421 * @param pszName the string to check, must be valid Utf8
422 * @param cbName the number of bytes @a pszName points to, including the
423 * terminating '\0'
424 * @thread HGCM
425 */
426int Service::validateName(const char *pszName, uint32_t cbName)
427{
428 LogFlowFunc(("cbName=%d\n", cbName));
429 int rc = VINF_SUCCESS;
430 if (RT_SUCCESS(rc) && (cbName < 2))
431 rc = VERR_INVALID_PARAMETER;
432 for (unsigned i = 0; RT_SUCCESS(rc) && i < cbName; ++i)
433 if (pszName[i] == '*' || pszName[i] == '?' || pszName[i] == '|')
434 rc = VERR_INVALID_PARAMETER;
435 LogFlowFunc(("returning %Rrc\n", rc));
436 return rc;
437}
438
439
440/**
441 * Check a string fits our criteria for the value of a guest property.
442 *
443 * @returns IPRT status code
444 * @param pszValue the string to check, must be valid Utf8
445 * @param cbValue the length in bytes of @a pszValue, including the
446 * terminator
447 * @thread HGCM
448 */
449int Service::validateValue(const char *pszValue, uint32_t cbValue)
450{
451 LogFlowFunc(("cbValue=%d\n", cbValue));
452
453 int rc = VINF_SUCCESS;
454 if (RT_SUCCESS(rc) && cbValue == 0)
455 rc = VERR_INVALID_PARAMETER;
456 if (RT_SUCCESS(rc))
457 LogFlow((" pszValue=%s\n", cbValue > 0 ? pszValue : NULL));
458 LogFlowFunc(("returning %Rrc\n", rc));
459 return rc;
460}
461
462/**
463 * Set a block of properties in the property registry, checking the validity
464 * of the arguments passed.
465 *
466 * @returns iprt status value
467 * @param cParms the number of HGCM parameters supplied
468 * @param paParms the array of HGCM parameters
469 * @thread HGCM
470 */
471int Service::setPropertyBlock(uint32_t cParms, VBOXHGCMSVCPARM paParms[])
472{
473 const char **papszNames;
474 const char **papszValues;
475 const char **papszFlags;
476 uint64_t *pau64Timestamps;
477 uint32_t cbDummy;
478 int rc = VINF_SUCCESS;
479
480 /*
481 * Get and validate the parameters
482 */
483 if ( cParms != 4
484 || RT_FAILURE(paParms[0].getPointer((void **)&papszNames, &cbDummy))
485 || RT_FAILURE(paParms[1].getPointer((void **)&papszValues, &cbDummy))
486 || RT_FAILURE(paParms[2].getPointer((void **)&pau64Timestamps, &cbDummy))
487 || RT_FAILURE(paParms[3].getPointer((void **)&papszFlags, &cbDummy))
488 )
489 rc = VERR_INVALID_PARAMETER;
490 /** @todo validate the array sizes... */
491
492 for (unsigned i = 0; RT_SUCCESS(rc) && papszNames[i] != NULL; ++i)
493 {
494 if ( !RT_VALID_PTR(papszNames[i])
495 || !RT_VALID_PTR(papszValues[i])
496 || !RT_VALID_PTR(papszFlags[i])
497 )
498 rc = VERR_INVALID_POINTER;
499 else
500 {
501 uint32_t fFlagsIgn;
502 rc = validateFlags(papszFlags[i], &fFlagsIgn);
503 }
504 }
505
506 if (RT_SUCCESS(rc))
507 {
508 /*
509 * Add the properties. No way to roll back here.
510 */
511 for (unsigned i = 0; papszNames[i] != NULL; ++i)
512 {
513 uint32_t fFlags;
514 rc = validateFlags(papszFlags[i], &fFlags);
515 AssertRCBreak(rc);
516
517 Property *pProp = getPropertyInternal(papszNames[i]);
518 if (pProp)
519 {
520 /* Update existing property. */
521 pProp->mValue = papszValues[i];
522 pProp->mTimestamp = pau64Timestamps[i];
523 pProp->mFlags = fFlags;
524 }
525 else
526 {
527 /* Create a new property */
528 pProp = new Property(papszNames[i], papszValues[i], pau64Timestamps[i], fFlags);
529 if (!pProp)
530 {
531 rc = VERR_NO_MEMORY;
532 break;
533 }
534 if (RTStrSpaceInsert(&mhProperties, &pProp->mStrCore))
535 mcProperties++;
536 else
537 {
538 delete pProp;
539 rc = VERR_INTERNAL_ERROR_3;
540 AssertFailedBreak();
541 }
542 }
543 }
544 }
545
546 return rc;
547}
548
549/**
550 * Retrieve a value from the property registry by name, checking the validity
551 * of the arguments passed. If the guest has not allocated enough buffer
552 * space for the value then we return VERR_OVERFLOW and set the size of the
553 * buffer needed in the "size" HGCM parameter. If the name was not found at
554 * all, we return VERR_NOT_FOUND.
555 *
556 * @returns iprt status value
557 * @param cParms the number of HGCM parameters supplied
558 * @param paParms the array of HGCM parameters
559 * @thread HGCM
560 */
561int Service::getProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[])
562{
563 int rc;
564 const char *pcszName = NULL; /* shut up gcc */
565 char *pchBuf;
566 uint32_t cbName, cbBuf;
567
568 /*
569 * Get and validate the parameters
570 */
571 LogFlowThisFunc(("\n"));
572 if ( cParms != 4 /* Hardcoded value as the next lines depend on it. */
573 || RT_FAILURE(paParms[0].getString(&pcszName, &cbName)) /* name */
574 || RT_FAILURE(paParms[1].getBuffer((void **)&pchBuf, &cbBuf)) /* buffer */
575 )
576 rc = VERR_INVALID_PARAMETER;
577 else
578 rc = validateName(pcszName, cbName);
579 if (RT_FAILURE(rc))
580 {
581 LogFlowThisFunc(("rc = %Rrc\n", rc));
582 return rc;
583 }
584
585 /*
586 * Read and set the values we will return
587 */
588
589 /* Get the property. */
590 Property *pProp = getPropertyInternal(pcszName);
591 if (pProp)
592 {
593 char szFlags[MAX_FLAGS_LEN];
594 rc = writeFlags(pProp->mFlags, szFlags);
595 if (RT_SUCCESS(rc))
596 {
597 /* Check that the buffer is big enough */
598 size_t const cbFlags = strlen(szFlags) + 1;
599 size_t const cbValue = pProp->mValue.size() + 1;
600 size_t const cbNeeded = cbValue + cbFlags;
601 paParms[3].setUInt32((uint32_t)cbNeeded);
602 if (cbBuf >= cbNeeded)
603 {
604 /* Write the value, flags and timestamp */
605 memcpy(pchBuf, pProp->mValue.c_str(), cbValue);
606 memcpy(pchBuf + cbValue, szFlags, cbFlags);
607
608 paParms[2].setUInt64(pProp->mTimestamp);
609
610 /*
611 * Done! Do exit logging and return.
612 */
613 Log2(("Queried string %s, value=%s, timestamp=%lld, flags=%s\n",
614 pcszName, pProp->mValue.c_str(), pProp->mTimestamp, szFlags));
615 }
616 else
617 rc = VERR_BUFFER_OVERFLOW;
618 }
619 }
620 else
621 rc = VERR_NOT_FOUND;
622
623 LogFlowThisFunc(("rc = %Rrc (%s)\n", rc, pcszName));
624 return rc;
625}
626
627/**
628 * Set a value in the property registry by name, checking the validity
629 * of the arguments passed.
630 *
631 * @returns iprt status value
632 * @param cParms the number of HGCM parameters supplied
633 * @param paParms the array of HGCM parameters
634 * @param isGuest is this call coming from the guest (or the host)?
635 * @throws std::bad_alloc if an out of memory condition occurs
636 * @thread HGCM
637 */
638int Service::setProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest)
639{
640 int rc = VINF_SUCCESS;
641 const char *pcszName = NULL; /* shut up gcc */
642 const char *pcszValue = NULL; /* ditto */
643 const char *pcszFlags = NULL;
644 uint32_t cchName = 0; /* ditto */
645 uint32_t cchValue = 0; /* ditto */
646 uint32_t cchFlags = 0;
647 uint32_t fFlags = NILFLAG;
648 uint64_t u64TimeNano = getCurrentTimestamp();
649
650 LogFlowThisFunc(("\n"));
651
652 /*
653 * General parameter correctness checking.
654 */
655 if ( RT_SUCCESS(rc)
656 && ( (cParms < 2) || (cParms > 3) /* Hardcoded value as the next lines depend on it. */
657 || RT_FAILURE(paParms[0].getString(&pcszName, &cchName)) /* name */
658 || RT_FAILURE(paParms[1].getString(&pcszValue, &cchValue)) /* value */
659 || ( (3 == cParms)
660 && RT_FAILURE(paParms[2].getString(&pcszFlags, &cchFlags)) /* flags */
661 )
662 )
663 )
664 rc = VERR_INVALID_PARAMETER;
665
666 /*
667 * Check the values passed in the parameters for correctness.
668 */
669 if (RT_SUCCESS(rc))
670 rc = validateName(pcszName, cchName);
671 if (RT_SUCCESS(rc))
672 rc = validateValue(pcszValue, cchValue);
673 if ((3 == cParms) && RT_SUCCESS(rc))
674 rc = RTStrValidateEncodingEx(pcszFlags, cchFlags,
675 RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED);
676 if ((3 == cParms) && RT_SUCCESS(rc))
677 rc = validateFlags(pcszFlags, &fFlags);
678 if (RT_FAILURE(rc))
679 {
680 LogFlowThisFunc(("rc = %Rrc\n", rc));
681 return rc;
682 }
683
684 /*
685 * If the property already exists, check its flags to see if we are allowed
686 * to change it.
687 */
688 Property *pProp = getPropertyInternal(pcszName);
689 rc = checkPermission(pProp ? (ePropFlags)pProp->mFlags : NILFLAG, isGuest);
690 if (rc == VINF_SUCCESS)
691 {
692 /*
693 * Set the actual value
694 */
695 if (pProp)
696 {
697 pProp->mValue = pcszValue;
698 pProp->mTimestamp = u64TimeNano;
699 pProp->mFlags = fFlags;
700 }
701 else if (mcProperties < MAX_PROPS)
702 {
703 /* Create a new string space record. */
704 pProp = new Property(pcszName, pcszValue, u64TimeNano, fFlags);
705 if (pProp)
706 {
707 if (RTStrSpaceInsert(&mhProperties, &pProp->mStrCore))
708 mcProperties++;
709 else
710 {
711 AssertFailed();
712 delete pProp;
713 rc = VERR_INTERNAL_ERROR_3;
714 }
715 }
716 else
717 rc = VERR_NO_MEMORY;
718 }
719 else
720 rc = VERR_TOO_MUCH_DATA;
721
722 /*
723 * Send a notification to the host and return.
724 */
725 // if (isGuest) /* Notify the host even for properties that the host
726 // * changed. Less efficient, but ensures consistency. */
727 doNotifications(pcszName, u64TimeNano);
728 Log2(("Set string %s, rc=%Rrc, value=%s\n", pcszName, rc, pcszValue));
729 }
730
731 LogFlowThisFunc(("rc = %Rrc (%s = %s)\n", rc, pcszName, pcszValue));
732 return rc;
733}
734
735
736/**
737 * Remove a value in the property registry by name, checking the validity
738 * of the arguments passed.
739 *
740 * @returns iprt status value
741 * @param cParms the number of HGCM parameters supplied
742 * @param paParms the array of HGCM parameters
743 * @param isGuest is this call coming from the guest (or the host)?
744 * @thread HGCM
745 */
746int Service::delProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest)
747{
748 int rc;
749 const char *pcszName = NULL; /* shut up gcc */
750 uint32_t cbName;
751
752 LogFlowThisFunc(("\n"));
753
754 /*
755 * Check the user-supplied parameters.
756 */
757 if ( (cParms == 1) /* Hardcoded value as the next lines depend on it. */
758 && RT_SUCCESS(paParms[0].getString(&pcszName, &cbName)) /* name */
759 )
760 rc = validateName(pcszName, cbName);
761 else
762 rc = VERR_INVALID_PARAMETER;
763 if (RT_FAILURE(rc))
764 {
765 LogFlowThisFunc(("rc = %Rrc\n", rc));
766 return rc;
767 }
768
769 /*
770 * If the property exists, check its flags to see if we are allowed
771 * to change it.
772 */
773 Property *pProp = getPropertyInternal(pcszName);
774 if (pProp)
775 rc = checkPermission((ePropFlags)pProp->mFlags, isGuest);
776
777 /*
778 * And delete the property if all is well.
779 */
780 if (rc == VINF_SUCCESS && pProp)
781 {
782 uint64_t u64Timestamp = getCurrentTimestamp();
783 PRTSTRSPACECORE pStrCore = RTStrSpaceRemove(&mhProperties, pProp->mStrCore.pszString);
784 AssertPtr(pStrCore); NOREF(pStrCore);
785 mcProperties--;
786 delete pProp;
787 // if (isGuest) /* Notify the host even for properties that the host
788 // * changed. Less efficient, but ensures consistency. */
789 doNotifications(pcszName, u64Timestamp);
790 }
791
792 LogFlowThisFunc(("rc = %Rrc (%s)\n", rc, pcszName));
793 return rc;
794}
795
796/**
797 * Enumeration data shared between enumPropsCallback and Service::enumProps.
798 */
799typedef struct ENUMDATA
800{
801 const char *pszPattern; /**< The pattern to match properties against. */
802 char *pchCur; /**< The current buffer postion. */
803 size_t cbLeft; /**< The amount of available buffer space. */
804 size_t cbNeeded; /**< The amount of needed buffer space. */
805} ENUMDATA;
806
807/**
808 * @callback_method_impl{FNRTSTRSPACECALLBACK}
809 */
810static DECLCALLBACK(int) enumPropsCallback(PRTSTRSPACECORE pStr, void *pvUser)
811{
812 Property *pProp = (Property *)pStr;
813 ENUMDATA *pEnum = (ENUMDATA *)pvUser;
814
815 /* Included in the enumeration? */
816 if (!pProp->Matches(pEnum->pszPattern))
817 return 0;
818
819 /* Convert the non-string members into strings. */
820 char szTimestamp[256];
821 size_t const cbTimestamp = RTStrFormatNumber(szTimestamp, pProp->mTimestamp, 10, 0, 0, 0) + 1;
822
823 char szFlags[MAX_FLAGS_LEN];
824 int rc = writeFlags(pProp->mFlags, szFlags);
825 if (RT_FAILURE(rc))
826 return rc;
827 size_t const cbFlags = strlen(szFlags) + 1;
828
829 /* Calculate the buffer space requirements. */
830 size_t const cbName = pProp->mName.length() + 1;
831 size_t const cbValue = pProp->mValue.length() + 1;
832 size_t const cbRequired = cbName + cbValue + cbTimestamp + cbFlags;
833 pEnum->cbNeeded += cbRequired;
834
835 /* Sufficient buffer space? */
836 if (cbRequired > pEnum->cbLeft)
837 {
838 pEnum->cbLeft = 0;
839 return 0; /* don't quit */
840 }
841 pEnum->cbLeft -= cbRequired;
842
843 /* Append the property to the buffer. */
844 char *pchCur = pEnum->pchCur;
845 pEnum->pchCur += cbRequired;
846
847 memcpy(pchCur, pProp->mName.c_str(), cbName);
848 pchCur += cbName;
849
850 memcpy(pchCur, pProp->mValue.c_str(), cbValue);
851 pchCur += cbValue;
852
853 memcpy(pchCur, szTimestamp, cbTimestamp);
854 pchCur += cbTimestamp;
855
856 memcpy(pchCur, szFlags, cbFlags);
857 pchCur += cbFlags;
858
859 Assert(pchCur == pEnum->pchCur);
860 return 0;
861}
862
863/**
864 * Enumerate guest properties by mask, checking the validity
865 * of the arguments passed.
866 *
867 * @returns iprt status value
868 * @param cParms the number of HGCM parameters supplied
869 * @param paParms the array of HGCM parameters
870 * @thread HGCM
871 */
872int Service::enumProps(uint32_t cParms, VBOXHGCMSVCPARM paParms[])
873{
874 int rc = VINF_SUCCESS;
875
876 /*
877 * Get the HGCM function arguments.
878 */
879 char const *pchPatterns = NULL;
880 char *pchBuf = NULL;
881 uint32_t cbPatterns = 0;
882 uint32_t cbBuf = 0;
883 LogFlowThisFunc(("\n"));
884 if ( (cParms != 3) /* Hardcoded value as the next lines depend on it. */
885 || RT_FAILURE(paParms[0].getString(&pchPatterns, &cbPatterns)) /* patterns */
886 || RT_FAILURE(paParms[1].getBuffer((void **)&pchBuf, &cbBuf)) /* return buffer */
887 )
888 rc = VERR_INVALID_PARAMETER;
889 if (RT_SUCCESS(rc) && cbPatterns > MAX_PATTERN_LEN)
890 rc = VERR_TOO_MUCH_DATA;
891
892 /*
893 * First repack the patterns into the format expected by RTStrSimplePatternMatch()
894 */
895 char szPatterns[MAX_PATTERN_LEN];
896 if (RT_SUCCESS(rc))
897 {
898 for (unsigned i = 0; i < cbPatterns - 1; ++i)
899 if (pchPatterns[i] != '\0')
900 szPatterns[i] = pchPatterns[i];
901 else
902 szPatterns[i] = '|';
903 szPatterns[cbPatterns - 1] = '\0';
904 }
905
906 /*
907 * Next enumerate into the buffer.
908 */
909 if (RT_SUCCESS(rc))
910 {
911 ENUMDATA EnumData;
912 EnumData.pszPattern = szPatterns;
913 EnumData.pchCur = pchBuf;
914 EnumData.cbLeft = cbBuf;
915 EnumData.cbNeeded = 0;
916 rc = RTStrSpaceEnumerate(&mhProperties, enumPropsCallback, &EnumData);
917 AssertRCSuccess(rc);
918 if (RT_SUCCESS(rc))
919 {
920 paParms[2].setUInt32((uint32_t)(EnumData.cbNeeded + 4));
921 if (EnumData.cbLeft >= 4)
922 {
923 /* The final terminators. */
924 EnumData.pchCur[0] = '\0';
925 EnumData.pchCur[1] = '\0';
926 EnumData.pchCur[2] = '\0';
927 EnumData.pchCur[3] = '\0';
928 }
929 else
930 rc = VERR_BUFFER_OVERFLOW;
931 }
932 }
933
934 return rc;
935}
936
937
938/** Helper query used by getOldNotification */
939int Service::getOldNotificationInternal(const char *pszPatterns,
940 uint64_t u64Timestamp,
941 Property *pProp)
942{
943 /* We count backwards, as the guest should normally be querying the
944 * most recent events. */
945 int rc = VWRN_NOT_FOUND;
946 PropertyList::reverse_iterator it = mGuestNotifications.rbegin();
947 for (; it != mGuestNotifications.rend(); ++it)
948 if (it->mTimestamp == u64Timestamp)
949 {
950 rc = VINF_SUCCESS;
951 break;
952 }
953
954 /* Now look for an event matching the patterns supplied. The base()
955 * member conveniently points to the following element. */
956 PropertyList::iterator base = it.base();
957 for (; base != mGuestNotifications.end(); ++base)
958 if (base->Matches(pszPatterns))
959 {
960 *pProp = *base;
961 return rc;
962 }
963 *pProp = Property();
964 return rc;
965}
966
967
968/** Helper query used by getNotification */
969int Service::getNotificationWriteOut(VBOXHGCMSVCPARM paParms[], Property prop)
970{
971 int rc = VINF_SUCCESS;
972 /* Format the data to write to the buffer. */
973 std::string buffer;
974 uint64_t u64Timestamp;
975 char *pchBuf;
976 uint32_t cbBuf;
977 rc = paParms[2].getBuffer((void **)&pchBuf, &cbBuf);
978 if (RT_SUCCESS(rc))
979 {
980 char szFlags[MAX_FLAGS_LEN];
981 rc = writeFlags(prop.mFlags, szFlags);
982 if (RT_SUCCESS(rc))
983 {
984 buffer += prop.mName;
985 buffer += '\0';
986 buffer += prop.mValue;
987 buffer += '\0';
988 buffer += szFlags;
989 buffer += '\0';
990 u64Timestamp = prop.mTimestamp;
991 }
992 }
993 /* Write out the data. */
994 if (RT_SUCCESS(rc))
995 {
996 paParms[1].setUInt64(u64Timestamp);
997 paParms[3].setUInt32((uint32_t)buffer.size());
998 if (buffer.size() <= cbBuf)
999 buffer.copy(pchBuf, cbBuf);
1000 else
1001 rc = VERR_BUFFER_OVERFLOW;
1002 }
1003 return rc;
1004}
1005
1006
1007/**
1008 * Get the next guest notification.
1009 *
1010 * @returns iprt status value
1011 * @param cParms the number of HGCM parameters supplied
1012 * @param paParms the array of HGCM parameters
1013 * @thread HGCM
1014 * @throws can throw std::bad_alloc
1015 */
1016int Service::getNotification(VBOXHGCMCALLHANDLE callHandle, uint32_t cParms,
1017 VBOXHGCMSVCPARM paParms[])
1018{
1019 int rc = VINF_SUCCESS;
1020 char *pszPatterns = NULL; /* shut up gcc */
1021 char *pchBuf;
1022 uint32_t cchPatterns = 0;
1023 uint32_t cbBuf = 0;
1024 uint64_t u64Timestamp;
1025
1026 /*
1027 * Get the HGCM function arguments and perform basic verification.
1028 */
1029 LogFlowThisFunc(("\n"));
1030 if ( (cParms != 4) /* Hardcoded value as the next lines depend on it. */
1031 || RT_FAILURE(paParms[0].getString(&pszPatterns, &cchPatterns)) /* patterns */
1032 || RT_FAILURE(paParms[1].getUInt64(&u64Timestamp)) /* timestamp */
1033 || RT_FAILURE(paParms[2].getBuffer((void **)&pchBuf, &cbBuf)) /* return buffer */
1034 )
1035 rc = VERR_INVALID_PARAMETER;
1036 if (RT_SUCCESS(rc))
1037 LogFlow((" pszPatterns=%s, u64Timestamp=%llu\n", pszPatterns,
1038 u64Timestamp));
1039
1040 /*
1041 * If no timestamp was supplied or no notification was found in the queue
1042 * of old notifications, enqueue the request in the waiting queue.
1043 */
1044 Property prop;
1045 if (RT_SUCCESS(rc) && u64Timestamp != 0)
1046 rc = getOldNotification(pszPatterns, u64Timestamp, &prop);
1047 if (RT_SUCCESS(rc) && prop.isNull())
1048 {
1049 mGuestWaiters.push_back(GuestCall(callHandle, GET_NOTIFICATION,
1050 paParms, rc));
1051 rc = VINF_HGCM_ASYNC_EXECUTE;
1052 }
1053 /*
1054 * Otherwise reply at once with the enqueued notification we found.
1055 */
1056 else
1057 {
1058 int rc2 = getNotificationWriteOut(paParms, prop);
1059 if (RT_FAILURE(rc2))
1060 rc = rc2;
1061 }
1062 return rc;
1063}
1064
1065
1066/**
1067 * Notify the service owner and the guest that a property has been
1068 * added/deleted/changed
1069 * @param pszProperty the name of the property which has changed
1070 * @param u64Timestamp the time at which the change took place
1071 *
1072 * @thread HGCM service
1073 */
1074void Service::doNotifications(const char *pszProperty, uint64_t u64Timestamp)
1075{
1076 AssertPtrReturnVoid(pszProperty);
1077 LogFlowThisFunc (("pszProperty=%s, u64Timestamp=%llu\n", pszProperty, u64Timestamp));
1078 /* Ensure that our timestamp is different to the last one. */
1079 if ( !mGuestNotifications.empty()
1080 && u64Timestamp == mGuestNotifications.back().mTimestamp)
1081 ++u64Timestamp;
1082
1083 /*
1084 * Try to find the property. Create a change event if we find it and a
1085 * delete event if we do not.
1086 */
1087 Property prop;
1088 prop.mName = pszProperty;
1089 prop.mTimestamp = u64Timestamp;
1090 /* prop is currently a delete event for pszProperty */
1091 Property const * const pProp = getPropertyInternal(pszProperty);
1092 if (pProp)
1093 {
1094 /* Make prop into a change event. */
1095 prop.mValue = pProp->mValue;
1096 prop.mFlags = pProp->mFlags;
1097 }
1098
1099 /* Release waiters if applicable and add the event to the queue for
1100 * guest notifications */
1101 int rc = VINF_SUCCESS;
1102 try
1103 {
1104 CallList::iterator it = mGuestWaiters.begin();
1105 while (it != mGuestWaiters.end())
1106 {
1107 const char *pszPatterns;
1108 uint32_t cchPatterns;
1109 it->mParms[0].getString(&pszPatterns, &cchPatterns);
1110 if (prop.Matches(pszPatterns))
1111 {
1112 GuestCall curCall = *it;
1113 int rc2 = getNotificationWriteOut(curCall.mParms, prop);
1114 if (RT_SUCCESS(rc2))
1115 rc2 = curCall.mRc;
1116 mpHelpers->pfnCallComplete(curCall.mHandle, rc2);
1117 it = mGuestWaiters.erase(it);
1118 }
1119 else
1120 ++it;
1121 }
1122 mGuestNotifications.push_back(prop);
1123 }
1124 catch (std::bad_alloc)
1125 {
1126 rc = VERR_NO_MEMORY;
1127 }
1128 if (mGuestNotifications.size() > MAX_GUEST_NOTIFICATIONS)
1129 mGuestNotifications.pop_front();
1130
1131 /*
1132 * Host notifications - first case: if the property exists then send its
1133 * current value
1134 */
1135 if (pProp && mpfnHostCallback != NULL)
1136 {
1137 char szFlags[MAX_FLAGS_LEN];
1138 /* Send out a host notification */
1139 const char *pszValue = prop.mValue.c_str();
1140 if (RT_SUCCESS(rc))
1141 rc = writeFlags(prop.mFlags, szFlags);
1142 if (RT_SUCCESS(rc))
1143 rc = notifyHost(pszProperty, pszValue, u64Timestamp, szFlags);
1144 }
1145
1146 /*
1147 * Host notifications - second case: if the property does not exist then
1148 * send the host an empty value
1149 */
1150 if (!pProp && mpfnHostCallback != NULL)
1151 {
1152 /* Send out a host notification */
1153 if (RT_SUCCESS(rc))
1154 rc = notifyHost(pszProperty, "", u64Timestamp, "");
1155 }
1156 LogFlowThisFunc(("returning\n"));
1157}
1158
1159/**
1160 * Notify the service owner that a property has been added/deleted/changed.
1161 * @returns IPRT status value
1162 * @param pszName the property name
1163 * @param pszValue the new value, or NULL if the property was deleted
1164 * @param u64Timestamp the time of the change
1165 * @param pszFlags the new flags string
1166 */
1167int Service::notifyHost(const char *pszName, const char *pszValue,
1168 uint64_t u64Timestamp, const char *pszFlags)
1169{
1170 LogFlowFunc(("pszName=%s, pszValue=%s, u64Timestamp=%llu, pszFlags=%s\n",
1171 pszName, pszValue, u64Timestamp, pszFlags));
1172 HOSTCALLBACKDATA HostCallbackData;
1173 HostCallbackData.u32Magic = HOSTCALLBACKMAGIC;
1174 HostCallbackData.pcszName = pszName;
1175 HostCallbackData.pcszValue = pszValue;
1176 HostCallbackData.u64Timestamp = u64Timestamp;
1177 HostCallbackData.pcszFlags = pszFlags;
1178 int rc = mpfnHostCallback (mpvHostData, 0 /*u32Function*/,
1179 (void *)(&HostCallbackData),
1180 sizeof(HostCallbackData));
1181 LogFlowFunc (("returning %Rrc\n", rc));
1182 return rc;
1183}
1184
1185
1186/**
1187 * Handle an HGCM service call.
1188 * @copydoc VBOXHGCMSVCFNTABLE::pfnCall
1189 * @note All functions which do not involve an unreasonable delay will be
1190 * handled synchronously. If needed, we will add a request handler
1191 * thread in future for those which do.
1192 *
1193 * @thread HGCM
1194 */
1195void Service::call (VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID,
1196 void * /* pvClient */, uint32_t eFunction, uint32_t cParms,
1197 VBOXHGCMSVCPARM paParms[])
1198{
1199 int rc = VINF_SUCCESS;
1200 LogFlowFunc(("u32ClientID = %d, fn = %d, cParms = %d, pparms = %p\n",
1201 u32ClientID, eFunction, cParms, paParms));
1202
1203 try
1204 {
1205 switch (eFunction)
1206 {
1207 /* The guest wishes to read a property */
1208 case GET_PROP:
1209 LogFlowFunc(("GET_PROP\n"));
1210 rc = getProperty(cParms, paParms);
1211 break;
1212
1213 /* The guest wishes to set a property */
1214 case SET_PROP:
1215 LogFlowFunc(("SET_PROP\n"));
1216 rc = setProperty(cParms, paParms, true);
1217 break;
1218
1219 /* The guest wishes to set a property value */
1220 case SET_PROP_VALUE:
1221 LogFlowFunc(("SET_PROP_VALUE\n"));
1222 rc = setProperty(cParms, paParms, true);
1223 break;
1224
1225 /* The guest wishes to remove a configuration value */
1226 case DEL_PROP:
1227 LogFlowFunc(("DEL_PROP\n"));
1228 rc = delProperty(cParms, paParms, true);
1229 break;
1230
1231 /* The guest wishes to enumerate all properties */
1232 case ENUM_PROPS:
1233 LogFlowFunc(("ENUM_PROPS\n"));
1234 rc = enumProps(cParms, paParms);
1235 break;
1236
1237 /* The guest wishes to get the next property notification */
1238 case GET_NOTIFICATION:
1239 LogFlowFunc(("GET_NOTIFICATION\n"));
1240 rc = getNotification(callHandle, cParms, paParms);
1241 break;
1242
1243 default:
1244 rc = VERR_NOT_IMPLEMENTED;
1245 }
1246 }
1247 catch (std::bad_alloc)
1248 {
1249 rc = VERR_NO_MEMORY;
1250 }
1251 LogFlowFunc(("rc = %Rrc\n", rc));
1252 if (rc != VINF_HGCM_ASYNC_EXECUTE)
1253 {
1254 mpHelpers->pfnCallComplete (callHandle, rc);
1255 }
1256}
1257
1258/**
1259 * Enumeration data shared between dbgInfoCallback and Service::dbgInfoShow.
1260 */
1261typedef struct ENUMDBGINFO
1262{
1263 PCDBGFINFOHLP pHlp;
1264} ENUMDBGINFO;
1265
1266static DECLCALLBACK(int) dbgInfoCallback(PRTSTRSPACECORE pStr, void *pvUser)
1267{
1268 Property *pProp = (Property *)pStr;
1269 PCDBGFINFOHLP pHlp = ((ENUMDBGINFO*)pvUser)->pHlp;
1270
1271 char szFlags[MAX_FLAGS_LEN];
1272 int rc = writeFlags(pProp->mFlags, szFlags);
1273 if (RT_FAILURE(rc))
1274 RTStrPrintf(szFlags, sizeof(szFlags), "???");
1275
1276 pHlp->pfnPrintf(pHlp, "%s: '%s', %RU64",
1277 pProp->mName.c_str(), pProp->mValue.c_str(), pProp->mTimestamp);
1278 if (strlen(szFlags))
1279 pHlp->pfnPrintf(pHlp, " (%s)", szFlags);
1280 pHlp->pfnPrintf(pHlp, "\n");
1281 return 0;
1282}
1283
1284void Service::dbgInfoShow(PCDBGFINFOHLP pHlp)
1285{
1286 ENUMDBGINFO EnumData = { pHlp };
1287 RTStrSpaceEnumerate(&mhProperties, dbgInfoCallback, &EnumData);
1288}
1289
1290/**
1291 * Handler for debug info.
1292 *
1293 * @param pvUser user pointer.
1294 * @param pHlp The info helper functions.
1295 * @param pszArgs Arguments, ignored.
1296 */
1297void Service::dbgInfo(void *pvUser, PCDBGFINFOHLP pHlp, const char *pszArgs)
1298{
1299 SELF *pSelf = reinterpret_cast<SELF *>(pvUser);
1300 pSelf->dbgInfoShow(pHlp);
1301}
1302
1303
1304/**
1305 * Service call handler for the host.
1306 * @copydoc VBOXHGCMSVCFNTABLE::pfnHostCall
1307 * @thread hgcm
1308 */
1309int Service::hostCall (uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1310{
1311 int rc = VINF_SUCCESS;
1312
1313 LogFlowFunc(("fn = %d, cParms = %d, pparms = %p\n",
1314 eFunction, cParms, paParms));
1315
1316 try
1317 {
1318 switch (eFunction)
1319 {
1320 /* The host wishes to set a block of properties */
1321 case SET_PROPS_HOST:
1322 LogFlowFunc(("SET_PROPS_HOST\n"));
1323 rc = setPropertyBlock(cParms, paParms);
1324 break;
1325
1326 /* The host wishes to read a configuration value */
1327 case GET_PROP_HOST:
1328 LogFlowFunc(("GET_PROP_HOST\n"));
1329 rc = getProperty(cParms, paParms);
1330 break;
1331
1332 /* The host wishes to set a configuration value */
1333 case SET_PROP_HOST:
1334 LogFlowFunc(("SET_PROP_HOST\n"));
1335 rc = setProperty(cParms, paParms, false);
1336 break;
1337
1338 /* The host wishes to set a configuration value */
1339 case SET_PROP_VALUE_HOST:
1340 LogFlowFunc(("SET_PROP_VALUE_HOST\n"));
1341 rc = setProperty(cParms, paParms, false);
1342 break;
1343
1344 /* The host wishes to remove a configuration value */
1345 case DEL_PROP_HOST:
1346 LogFlowFunc(("DEL_PROP_HOST\n"));
1347 rc = delProperty(cParms, paParms, false);
1348 break;
1349
1350 /* The host wishes to enumerate all properties */
1351 case ENUM_PROPS_HOST:
1352 LogFlowFunc(("ENUM_PROPS\n"));
1353 rc = enumProps(cParms, paParms);
1354 break;
1355
1356 /* The host wishes to set global flags for the service */
1357 case SET_GLOBAL_FLAGS_HOST:
1358 LogFlowFunc(("SET_GLOBAL_FLAGS_HOST\n"));
1359 if (cParms == 1)
1360 {
1361 uint32_t eFlags;
1362 rc = paParms[0].getUInt32(&eFlags);
1363 if (RT_SUCCESS(rc))
1364 meGlobalFlags = (ePropFlags)eFlags;
1365 }
1366 else
1367 rc = VERR_INVALID_PARAMETER;
1368 break;
1369
1370 case GET_DBGF_INFO_FN:
1371 if (cParms != 2)
1372 return VERR_INVALID_PARAMETER;
1373 paParms[0].u.pointer.addr = (void*)(uintptr_t)dbgInfo;
1374 paParms[1].u.pointer.addr = (void*)this;
1375 break;
1376
1377 default:
1378 rc = VERR_NOT_SUPPORTED;
1379 break;
1380 }
1381 }
1382 catch (std::bad_alloc)
1383 {
1384 rc = VERR_NO_MEMORY;
1385 }
1386
1387 LogFlowFunc(("rc = %Rrc\n", rc));
1388 return rc;
1389}
1390
1391int Service::uninit()
1392{
1393 return VINF_SUCCESS;
1394}
1395
1396} /* namespace guestProp */
1397
1398using guestProp::Service;
1399
1400/**
1401 * @copydoc VBOXHGCMSVCLOAD
1402 */
1403extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad (VBOXHGCMSVCFNTABLE *ptable)
1404{
1405 int rc = VERR_IPE_UNINITIALIZED_STATUS;
1406
1407 LogFlowFunc(("ptable = %p\n", ptable));
1408
1409 if (!RT_VALID_PTR(ptable))
1410 rc = VERR_INVALID_PARAMETER;
1411 else
1412 {
1413 LogFlowFunc(("ptable->cbSize = %d, ptable->u32Version = 0x%08X\n", ptable->cbSize, ptable->u32Version));
1414
1415 if ( ptable->cbSize != sizeof(VBOXHGCMSVCFNTABLE)
1416 || ptable->u32Version != VBOX_HGCM_SVC_VERSION)
1417 rc = VERR_VERSION_MISMATCH;
1418 else
1419 {
1420 Service *pService = NULL;
1421 /* No exceptions may propagate outside. */
1422 try
1423 {
1424 pService = new Service(ptable->pHelpers);
1425 rc = VINF_SUCCESS;
1426 }
1427 catch (int rcThrown)
1428 {
1429 rc = rcThrown;
1430 }
1431 catch (...)
1432 {
1433 rc = VERR_UNEXPECTED_EXCEPTION;
1434 }
1435
1436 if (RT_SUCCESS(rc))
1437 {
1438 /* We do not maintain connections, so no client data is needed. */
1439 ptable->cbClient = 0;
1440
1441 ptable->pfnUnload = Service::svcUnload;
1442 ptable->pfnConnect = Service::svcConnectDisconnect;
1443 ptable->pfnDisconnect = Service::svcConnectDisconnect;
1444 ptable->pfnCall = Service::svcCall;
1445 ptable->pfnHostCall = Service::svcHostCall;
1446 ptable->pfnSaveState = NULL; /* The service is stateless, so the normal */
1447 ptable->pfnLoadState = NULL; /* construction done before restoring suffices */
1448 ptable->pfnRegisterExtension = Service::svcRegisterExtension;
1449
1450 /* Service specific initialization. */
1451 ptable->pvService = pService;
1452 }
1453 else
1454 Assert(!pService);
1455 }
1456 }
1457
1458 LogFlowFunc(("returning %Rrc\n", rc));
1459 return rc;
1460}
1461
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