VirtualBox

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

Last change on this file since 15049 was 14461, checked in by vboxsync, 16 years ago

HostServices/GuestProperties: reverted r39730

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