Changeset 13159 in vbox
- Timestamp:
- Oct 10, 2008 10:10:36 AM (16 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
-
include/VBox/HostServices/GuestPropertySvc.h (modified) (6 diffs)
-
src/VBox/HostServices/GuestProperties/service.cpp (modified) (31 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/HostServices/GuestPropertySvc.h
r11934 r13159 46 46 /** Pass the address of the cfgm node used by the service as a database. */ 47 47 SET_CFGM_NODE = 1, 48 /** 49 * Get the value attached to a configuration property key50 * The parameter format matches that of GET_PROP. 48 /** 49 * Get the value attached to a guest property 50 * The parameter format matches that of GET_PROP. 51 51 */ 52 52 GET_PROP_HOST = 2, 53 /** 54 * Set the value attached to a configuration property key53 /** 54 * Set the value attached to a guest property 55 55 * The parameter format matches that of SET_PROP. 56 56 */ 57 57 SET_PROP_HOST = 3, 58 /** 59 * Set the value attached to a configuration property key58 /** 59 * Set the value attached to a guest property 60 60 * The parameter format matches that of SET_PROP_VALUE. 61 61 */ 62 62 SET_PROP_VALUE_HOST = 4, 63 /** 64 * Remove the value attached to a configuration property key63 /** 64 * Remove a guest property. 65 65 * The parameter format matches that of DEL_PROP. 66 66 */ 67 67 DEL_PROP_HOST = 5, 68 /** 68 /** 69 69 * Enumerate guest properties. 70 70 * The parameter format matches that of ENUM_PROPS. 71 71 */ 72 ENUM_PROPS_HOST = 6 72 ENUM_PROPS_HOST = 6, 73 /** 74 * Register a callback with the service which will be called when a 75 * property is modified. The callback is a function returning void and 76 * taking a pointer to a HOSTCALLBACKDATA structure. 77 */ 78 REGISTER_CALLBACK = 7 73 79 }; 80 81 typedef struct _HOSTCALLBACKDATA 82 { 83 /** Callback structure header */ 84 VBOXHGCMCALLBACKHDR hdr; 85 /** The name of the property that was changed */ 86 const char *pcszName; 87 /** The new property value, or NULL if the property was deleted */ 88 const char *pcszValue; 89 /** The timestamp of the modification */ 90 uint64_t u64Timestamp; 91 /** The flags field of the modified property */ 92 const char *pcszFlags; 93 } HOSTCALLBACKDATA, *PHOSTCALLBACKDATA; 74 94 75 95 /** … … 91 111 }; 92 112 93 /** Prefix for extra data keys used by the get and set key value functions */94 #define VBOX_SHARED_INFO_KEY_PREFIX "Guest/"95 /** Helper macro for the length of the prefix VBOX_SHARED_INFO_KEY_PREFIX */96 #define VBOX_SHARED_INFO_PREFIX_LEN (sizeof(VBOX_SHARED_INFO_KEY_PREFIX) - 1)97 113 /** Maximum length for property names */ 98 114 enum { MAX_NAME_LEN = 64 }; 99 115 /** Maximum length for property values */ 100 116 enum { MAX_VALUE_LEN = 128 }; 101 /** Maximum length for extra data key values used by the get and set key value functions*/117 /** Maximum length for the property flags field */ 102 118 enum { MAX_FLAGS_LEN = 128 }; 103 119 /** Maximum number of properties per guest */ 104 enum { MAX_ KEYS = 256 };120 enum { MAX_PROPS = 256 }; 105 121 106 122 /** … … 150 166 151 167 /** 152 * The property key. (IN pointer)168 * The property name. (IN pointer) 153 169 * This must fit to a number of criteria, namely 154 170 * - Only Utf8 strings are allowed … … 160 176 /** 161 177 * The value of the property (IN pointer) 162 * Criteria as for the keyparameter, but with length less than or equal to178 * Criteria as for the name parameter, but with length less than or equal to 163 179 * MAX_VALUE_LEN. 164 180 */ … … 180 196 181 197 /** 182 * The property key. (IN pointer)198 * The property name. (IN pointer) 183 199 * This must fit to a number of criteria, namely 184 200 * - Only Utf8 strings are allowed … … 190 206 /** 191 207 * The value of the property (IN pointer) 192 * Criteria as for the keyparameter, but with length less than or equal to208 * Criteria as for the name parameter, but with length less than or equal to 193 209 * MAX_VALUE_LEN. 194 210 */ -
trunk/src/VBox/HostServices/GuestProperties/service.cpp
r11314 r13159 30 30 * 31 31 * The service currently consists of two threads. One of these is the main 32 * HGCM service thread which waits for requests from the guest and schedules 33 * these to the second thread. The second thread deals with the requests 34 * sequentially by calling the callback provided by the service owner, 35 * notifying the guest clients when it has finished dealing with a given 36 * request. 37 * 38 * Guest requests to wait for notification are dealt with differently. They 39 * are added to a list of open notification requests but do not schedule 40 * anything in the request thread except for a possible timeout. 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. 41 39 */ 42 40 … … 57 55 #include <iprt/time.h> 58 56 #include <iprt/cpputils.h> 57 #include <iprt/req.h> 58 #include <iprt/thread.h> 59 59 #include <VBox/log.h> 60 60 … … 90 90 pParm->type = VBOX_HGCM_SVC_PARM_64BIT; 91 91 pParm->u.uint64 = u64; 92 } 93 94 /** Extract a callback pointer value from an HGCM parameter structure */ 95 static int VBoxHGCMParmPtrGet (VBOXHGCMSVCPARM *pParm, 96 PFNVBOXHGCMCALLBACK *ppfnCallback, 97 void **ppvData) 98 { 99 if (pParm->type == VBOX_HGCM_SVC_PARM_CALLBACK) 100 { 101 *ppfnCallback = pParm->u.callback.pFunction; 102 *ppvData = pParm->u.callback.pvData; 103 return VINF_SUCCESS; 104 } 105 106 return VERR_INVALID_PARAMETER; 92 107 } 93 108 … … 111 126 /** Pointer to our configuration flags node. */ 112 127 PCFGMNODE mpFlagsNode; 128 /** @todo we should have classes for thread and request handler thread */ 129 /** Queue of outstanding property change notifications */ 130 RTREQQUEUE *mReqQueue; 131 /** Thread for processing the request queue */ 132 RTTHREAD mReqThread; 133 /** Tell the thread that it should exit */ 134 bool mfExitThread; 135 /** Callback function supplied by the host for notification of updates 136 * to properties */ 137 PFNVBOXHGCMCALLBACK mpfnHostCallback; 138 /** User data pointer to be supplied to the host callback function */ 139 void *mpvHostData; 113 140 114 141 public: 115 142 explicit Service(PVBOXHGCMSVCHELPERS pHelpers) 116 143 : mpHelpers(pHelpers), mpValueNode(NULL), mpTimestampNode(NULL), 117 mpFlagsNode(NULL) {} 144 mpFlagsNode(NULL), mfExitThread(false), mpfnHostCallback(NULL), 145 mpvHostData(NULL) 146 { 147 int rc = RTReqCreateQueue(&mReqQueue); 148 rc = RTThreadCreate(&mReqThread, reqThreadFn, this, 0, RTTHREADTYPE_MSG_PUMP, 149 RTTHREADFLAGS_WAITABLE, "GuestPropReq"); 150 if (!RT_SUCCESS(rc)) 151 throw rc; 152 } 118 153 119 154 /** … … 125 160 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER); 126 161 SELF *pSelf = reinterpret_cast<SELF *>(pvService); 127 delete pSelf; 128 return VINF_SUCCESS; 162 int rc = pSelf->uninit(); 163 AssertRC(rc); 164 if (RT_SUCCESS(rc)) 165 delete pSelf; 166 return rc; 129 167 } 130 168 … … 171 209 } 172 210 private: 173 int validateKey(const char *pszKey, uint32_t cbKey); 211 static DECLCALLBACK(int) reqThreadFn(RTTHREAD ThreadSelf, void *pvUser); 212 int validateName(const char *pszName, uint32_t cbName); 174 213 int validateValue(char *pszValue, uint32_t cbValue); 175 int get Key(uint32_t cParms, VBOXHGCMSVCPARM paParms[]);214 int getPropValue(uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 176 215 int getProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 177 int set Key(uint32_t cParms, VBOXHGCMSVCPARM paParms[]);178 int del Key(uint32_t cParms, VBOXHGCMSVCPARM paParms[]);216 int setProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 217 int delProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 179 218 int enumProps(uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 219 void notifyHost(const char *pszProperty); 220 static DECLCALLBACK(int) reqNotify(PFNVBOXHGCMCALLBACK pfnCallback, 221 void *pvData, char *pszName, 222 char *pszValue, uint32_t u32TimeHigh, 223 uint32_t u32TimeLow, char *pszFlags); 224 /** 225 * Empty request function for terminating the request thread. 226 * @returns VINF_EOF to cause the request processing function to return 227 * @todo return something more appropriate 228 */ 229 static DECLCALLBACK(int) reqVoid() { return VINF_EOF; } 230 180 231 void call (VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, 181 232 void *pvClient, uint32_t eFunction, uint32_t cParms, 182 233 VBOXHGCMSVCPARM paParms[]); 183 234 int hostCall (uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 235 int uninit (); 184 236 }; 185 237 186 238 187 239 /** 188 * Checking that the key passed by the guest fits our criteria for a 189 * configuration key. 240 * Thread function for processing the request queue 241 * @copydoc FNRTTHREAD 242 */ 243 DECLCALLBACK(int) Service::reqThreadFn(RTTHREAD ThreadSelf, void *pvUser) 244 { 245 SELF *pSelf = reinterpret_cast<SELF *>(pvUser); 246 while (!pSelf->mfExitThread) 247 RTReqProcess(pSelf->mReqQueue, RT_INDEFINITE_WAIT); 248 return VINF_SUCCESS; 249 } 250 251 252 /** 253 * Checking that the name passed by the guest fits our criteria for a 254 * property name. 190 255 * 191 256 * @returns IPRT status code 192 * @param psz Key the keypassed by the guest193 * @param cb Key the number of bytes pszKeypoints to, including the257 * @param pszName the name passed by the guest 258 * @param cbName the number of bytes pszName points to, including the 194 259 * terminating '\0' 195 260 * @thread HGCM 196 261 */ 197 int Service::validate Key(const char *pszKey, uint32_t cbKey)198 { 199 LogFlowFunc(("cb Key=%d\n", cbKey));200 201 /* 202 * Validate the key, checking that it's proper UTF-8 and has262 int Service::validateName(const char *pszName, uint32_t cbName) 263 { 264 LogFlowFunc(("cbName=%d\n", cbName)); 265 266 /* 267 * Validate the name, checking that it's proper UTF-8 and has 203 268 * a string terminator. 204 269 */ 205 int rc = RTStrValidateEncodingEx(psz Key, RT_MIN(cbKey,MAX_NAME_LEN),270 int rc = RTStrValidateEncodingEx(pszName, RT_MIN(cbName, (uint32_t) MAX_NAME_LEN), 206 271 RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED); 207 if (RT_SUCCESS(rc) && (cb Key< 2))272 if (RT_SUCCESS(rc) && (cbName < 2)) 208 273 rc = VERR_INVALID_PARAMETER; 209 274 … … 215 280 /** 216 281 * Check that the data passed by the guest fits our criteria for the value of 217 * a configuration key.282 * a guest property. 218 283 * 219 284 * @returns IPRT status code 220 * @param pszValue the value to store in the key285 * @param pszValue the value to store in the property 221 286 * @param cbValue the number of bytes in the buffer pszValue points to 222 287 * @thread HGCM … … 233 298 int rc = VINF_SUCCESS; 234 299 if (cbValue) 235 rc = RTStrValidateEncodingEx(pszValue, RT_MIN(cbValue, MAX_VALUE_LEN),300 rc = RTStrValidateEncodingEx(pszValue, RT_MIN(cbValue, (uint32_t) MAX_VALUE_LEN), 236 301 RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED); 237 302 if (RT_SUCCESS(rc)) … … 243 308 244 309 /** 245 * Retrieve a value from the guest registry by key, checking the validity310 * Retrieve a value from the property registry by name, checking the validity 246 311 * of the arguments passed. If the guest has not allocated enough buffer 247 312 * space for the value then we return VERR_OVERFLOW and set the size of the 248 * buffer needed in the "size" HGCM parameter. If the keywas not found at313 * buffer needed in the "size" HGCM parameter. If the name was not found at 249 314 * all, we return VERR_NOT_FOUND. 250 315 * … … 254 319 * @thread HGCM 255 320 */ 256 int Service::get Key(uint32_t cParms, VBOXHGCMSVCPARM paParms[])321 int Service::getPropValue(uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 257 322 { 258 323 int rc = VINF_SUCCESS; 259 char *psz Key, *pszValue;260 uint32_t cb Key, cbValue;324 char *pszName, *pszValue; 325 uint32_t cbName, cbValue; 261 326 size_t cbValueActual; 262 327 263 328 LogFlowThisFunc(("\n")); 264 329 if ( (cParms != 3) /* Hardcoded value as the next lines depend on it. */ 265 || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR) /* key*/330 || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR) /* name */ 266 331 || (paParms[1].type != VBOX_HGCM_SVC_PARM_PTR) /* value */ 267 332 ) 268 333 rc = VERR_INVALID_PARAMETER; 269 334 if (RT_SUCCESS(rc)) 270 rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &psz Key, &cbKey);335 rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszName, &cbName); 271 336 if (RT_SUCCESS(rc)) 272 337 rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pszValue, &cbValue); 273 338 if (RT_SUCCESS(rc)) 274 rc = validate Key(pszKey, cbKey);275 if (RT_SUCCESS(rc)) 276 rc = CFGMR3QuerySize(mpValueNode, psz Key, &cbValueActual);339 rc = validateName(pszName, cbName); 340 if (RT_SUCCESS(rc)) 341 rc = CFGMR3QuerySize(mpValueNode, pszName, &cbValueActual); 277 342 if (RT_SUCCESS(rc)) 278 343 VBoxHGCMParmUInt32Set(&paParms[2], cbValueActual); … … 280 345 rc = VERR_BUFFER_OVERFLOW; 281 346 if (RT_SUCCESS(rc)) 282 rc = CFGMR3QueryString(mpValueNode, psz Key, pszValue, cbValue);283 if (RT_SUCCESS(rc)) 284 Log2(("Queried string %s, rc=%Rrc, value=%.*s\n", psz Key, rc, cbValue, pszValue));347 rc = CFGMR3QueryString(mpValueNode, pszName, pszValue, cbValue); 348 if (RT_SUCCESS(rc)) 349 Log2(("Queried string %s, rc=%Rrc, value=%.*s\n", pszName, rc, cbValue, pszValue)); 285 350 else if (VERR_CFGM_VALUE_NOT_FOUND == rc) 286 351 rc = VERR_NOT_FOUND; … … 291 356 292 357 /** 293 * Retrieve a value from the guest registry by key, checking the validity358 * Retrieve a value from the property registry by name, checking the validity 294 359 * of the arguments passed. If the guest has not allocated enough buffer 295 360 * space for the value then we return VERR_OVERFLOW and set the size of the 296 * buffer needed in the "size" HGCM parameter. If the keywas not found at361 * buffer needed in the "size" HGCM parameter. If the name was not found at 297 362 * all, we return VERR_NOT_FOUND. 298 363 * … … 309 374 size_t cchValue, cchFlags, cchBufActual; 310 375 311 /*312 * Get and validate the parameters313 */376 /* 377 * Get and validate the parameters 378 */ 314 379 LogFlowThisFunc(("\n")); 315 380 if ( (cParms != 4) /* Hardcoded value as the next lines depend on it. */ … … 323 388 rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pchBuf, &cchBuf); 324 389 if (RT_SUCCESS(rc)) 325 rc = validate Key(pszName, cchName);390 rc = validateName(pszName, cchName); 326 391 /* Get the value size */ 327 392 if (RT_SUCCESS(rc)) 328 393 rc = CFGMR3QuerySize(mpValueNode, pszName, &cchValue); 329 394 330 /*331 * Read and set the values we will return332 */395 /* 396 * Read and set the values we will return 397 */ 333 398 /* Get the flags size */ 334 399 cchFlags = 1; /* Empty string if no flags set. */ … … 358 423 VBoxHGCMParmUInt64Set(&paParms[2], u64Timestamp); 359 424 360 /*361 * Done! Do exit logging and return.362 */425 /* 426 * Done! Do exit logging and return. 427 */ 363 428 if (RT_SUCCESS(rc)) 364 429 Log2(("Queried string %S, value=%.*S, timestamp=%lld, flags=%.*S\n", … … 373 438 374 439 /** 375 * Set a value in the guest registry by key, checking the validity440 * Set a value in the property registry by name, checking the validity 376 441 * of the arguments passed. 377 442 * … … 381 446 * @thread HGCM 382 447 */ 383 int Service::set Key(uint32_t cParms, VBOXHGCMSVCPARM paParms[])448 int Service::setProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 384 449 { 385 450 int rc = VINF_SUCCESS; 386 char *psz Key, *pszValue;387 uint32_t cch Key, cchValue;451 char *pszName, *pszValue, *pszFlags; 452 uint32_t cchName, cchValue, cchFlags = 0; 388 453 389 454 LogFlowThisFunc(("\n")); 390 if ( (cParms < 2) || (cParms > 4) /* Hardcoded value as the next lines depend on it. */ 391 || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR) /* key */ 392 || (paParms[1].type != VBOX_HGCM_SVC_PARM_PTR) /* value */ 393 || ((3 == cParms) && (paParms[2].type != VBOX_HGCM_SVC_PARM_PTR)) 394 ) 395 rc = VERR_INVALID_PARAMETER; 396 if (RT_SUCCESS(rc)) 397 rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszKey, &cchKey); 398 if (RT_SUCCESS(rc)) 399 rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pszValue, &cchValue); 400 if (RT_SUCCESS(rc)) 401 rc = validateKey(pszKey, cchKey); 402 if (RT_SUCCESS(rc)) 403 rc = validateValue(pszValue, cchValue); 404 if (RT_SUCCESS(rc)) 405 { 406 /* Limit the number of keys that we can set. */ 455 /* 456 * First of all, make sure that we won't exceed the maximum number of properties. 457 */ 458 { 407 459 unsigned cChildren = 0; 408 460 for (PCFGMNODE pChild = CFGMR3GetFirstChild(mpValueNode); pChild != 0; pChild = CFGMR3GetNextChild(pChild)) 409 461 ++cChildren; 410 if (cChildren >= MAX_ KEYS)462 if (cChildren >= MAX_PROPS) 411 463 rc = VERR_TOO_MUCH_DATA; 412 464 } 465 /* 466 * General parameter correctness checking. 467 */ 468 if ( RT_SUCCESS(rc) 469 && ( (cParms < 2) || (cParms > 4) /* Hardcoded value as the next lines depend on it. */ 470 || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR) /* name */ 471 || (paParms[1].type != VBOX_HGCM_SVC_PARM_PTR) /* value */ 472 || ((3 == cParms) && (paParms[2].type != VBOX_HGCM_SVC_PARM_PTR)) /* flags */ 473 ) 474 ) 475 rc = VERR_INVALID_PARAMETER; 476 /* 477 * And check the values passed in the parameters for correctness. 478 */ 479 if (RT_SUCCESS(rc)) 480 rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszName, &cchName); 481 if (RT_SUCCESS(rc)) 482 rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pszValue, &cchValue); 483 if (RT_SUCCESS(rc)) 484 rc = validateName(pszName, cchName); 485 if (RT_SUCCESS(rc)) 486 rc = validateValue(pszValue, cchValue); 413 487 /* For now, we do not support any flags */ 414 488 if (RT_SUCCESS(rc) && (3 == cParms)) 415 489 { 416 char *pszFlags;417 uint32_t cchFlags = 0;418 490 rc = VBoxHGCMParmPtrGet(&paParms[2], (void **) &pszFlags, &cchFlags); 419 491 for (size_t i = 0; (i < cchFlags - 1) && RT_SUCCESS(rc); ++i) … … 421 493 rc = VERR_INVALID_PARAMETER; 422 494 } 495 /* 496 * Set the actual value 497 */ 423 498 if (RT_SUCCESS(rc)) 424 499 { 425 500 RTTIMESPEC time; 426 CFGMR3RemoveValue(mpValueNode, psz Key);501 CFGMR3RemoveValue(mpValueNode, pszName); 427 502 if (mpTimestampNode != NULL) 428 CFGMR3RemoveValue(mpTimestampNode, psz Key);503 CFGMR3RemoveValue(mpTimestampNode, pszName); 429 504 if ((3 == cParms) && (mpFlagsNode != NULL)) 430 CFGMR3RemoveValue(mpFlagsNode, psz Key);431 rc = CFGMR3InsertString(mpValueNode, psz Key, pszValue);505 CFGMR3RemoveValue(mpFlagsNode, pszName); 506 rc = CFGMR3InsertString(mpValueNode, pszName, pszValue); 432 507 if (RT_SUCCESS(rc)) 433 rc = CFGMR3InsertInteger(mpTimestampNode, psz Key,508 rc = CFGMR3InsertInteger(mpTimestampNode, pszName, 434 509 RTTimeSpecGetNano(RTTimeNow(&time))); 435 } 436 if (RT_SUCCESS(rc)) 437 Log2(("Set string %s, rc=%Rrc, value=%s\n", pszKey, rc, pszValue)); 510 if (RT_SUCCESS(rc) && (3 == cParms)) 511 rc = CFGMR3InsertString(mpFlagsNode, pszName, pszFlags); 512 /* If we are not setting flags, make sure that there are some */ 513 if (RT_SUCCESS(rc) && (mpFlagsNode != NULL) && (cParms != 3)) 514 { 515 CFGMVALUETYPE dummy; 516 if ( CFGMR3QueryType(mpFlagsNode, pszName, &dummy) 517 == VERR_CFGM_VALUE_NOT_FOUND) 518 rc = CFGMR3InsertString(mpFlagsNode, pszName, ""); 519 } 520 } 521 /* 522 * Send a notification to the host and return. 523 */ 524 if (RT_SUCCESS(rc)) 525 { 526 notifyHost(pszName); 527 Log2(("Set string %s, rc=%Rrc, value=%s\n", pszName, rc, pszValue)); 528 } 438 529 LogFlowThisFunc(("rc = %Rrc\n", rc)); 439 530 return rc; … … 442 533 443 534 /** 444 * Remove a value in the guest registry by key, checking the validity535 * Remove a value in the property registry by name, checking the validity 445 536 * of the arguments passed. 446 537 * … … 450 541 * @thread HGCM 451 542 */ 452 int Service::del Key(uint32_t cParms, VBOXHGCMSVCPARM paParms[])543 int Service::delProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 453 544 { 454 545 int rc = VINF_SUCCESS; 455 char *psz Key;456 uint32_t cb Key;546 char *pszName; 547 uint32_t cbName; 457 548 458 549 LogFlowThisFunc(("\n")); 459 550 if ( (cParms != 1) /* Hardcoded value as the next lines depend on it. */ 460 || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR) /* key*/551 || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR) /* name */ 461 552 ) 462 553 rc = VERR_INVALID_PARAMETER; 463 554 if (RT_SUCCESS(rc)) 464 rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszKey, &cbKey); 465 if (RT_SUCCESS(rc)) 466 rc = validateKey(pszKey, cbKey); 467 if (RT_SUCCESS(rc)) 468 CFGMR3RemoveValue(mpValueNode, pszKey); 555 rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszName, &cbName); 556 if (RT_SUCCESS(rc)) 557 rc = validateName(pszName, cbName); 558 if (RT_SUCCESS(rc)) 559 { 560 CFGMR3RemoveValue(mpValueNode, pszName); 561 notifyHost(pszName); 562 } 469 563 LogFlowThisFunc(("rc = %Rrc\n", rc)); 470 564 return rc; … … 567 661 enum 568 662 { 663 /* Calculate the increment, not yet rounded down */ 569 664 BLOCKINCRFULL = (MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN + 2048), 665 /* And this is the increment after rounding */ 570 666 BLOCKINCR = BLOCKINCRFULL - BLOCKINCRFULL % 1024 571 667 }; … … 657 753 } 658 754 755 /** 756 * Notify the service owner that a property has been added/deleted/changed 757 * @param pszProperty the name of the property which has changed 758 * @note this call allocates memory which the reqNotify request is expected to 759 * free again, using RTStrFree(). 760 * 761 * @thread HGCM service 762 */ 763 void Service::notifyHost(const char *pszProperty) 764 { 765 char szValue[MAX_VALUE_LEN]; 766 uint64_t u64Timestamp = 0; 767 char szFlags[MAX_FLAGS_LEN]; 768 char *pszName = NULL, *pszValue = NULL, *pszFlags = NULL; 769 770 if (NULL == mpfnHostCallback) 771 return; /* Nothing to do. */ 772 int rc = CFGMR3QueryString(mpValueNode, pszProperty, szValue, 773 sizeof(szValue)); 774 /* 775 * First case: if the property exists then send the host its current value 776 */ 777 if (rc != VERR_CFGM_VALUE_NOT_FOUND) 778 { 779 if (RT_SUCCESS(rc) && (mpTimestampNode != NULL)) 780 rc = CFGMR3QueryU64(mpTimestampNode, pszProperty, &u64Timestamp); 781 if (RT_SUCCESS(rc) && (mpFlagsNode != NULL)) 782 rc = CFGMR3QueryString(mpFlagsNode, pszProperty, szFlags, 783 sizeof(szFlags)); 784 if (RT_SUCCESS(rc)) 785 rc = RTStrDupEx(&pszName, pszProperty); 786 if (RT_SUCCESS(rc) && (mpTimestampNode != NULL)) 787 rc = RTStrDupEx(&pszValue, szValue); 788 if (RT_SUCCESS(rc) && (mpFlagsNode != NULL)) 789 rc = RTStrDupEx(&pszFlags, szFlags); 790 if (RT_SUCCESS(rc)) 791 rc = RTReqCallEx(mReqQueue, NULL, 0, RTREQFLAGS_NO_WAIT, 792 (PFNRT)Service::reqNotify, 7, mpfnHostCallback, 793 mpvHostData, pszName, pszValue, u64Timestamp / 0xffff, 794 u64Timestamp % 0xffff, pszFlags); 795 if (!RT_SUCCESS(rc)) /* clean up */ 796 { 797 RTStrFree(pszName); 798 RTStrFree(pszValue); 799 RTStrFree(pszFlags); 800 } 801 } 802 else 803 /* 804 * Second case: if the property does not exist then send the host an empty 805 * value 806 */ 807 { 808 rc = RTStrDupEx(&pszName, pszProperty); 809 if (RT_SUCCESS(rc)) 810 rc = RTReqCallEx(mReqQueue, NULL, 0, RTREQFLAGS_NO_WAIT, 811 (PFNRT)Service::reqNotify, 7, mpfnHostCallback, 812 mpvHostData, pszName, NULL, 0, 0, NULL); 813 } 814 if (!RT_SUCCESS(rc)) /* clean up if we failed somewhere */ 815 { 816 RTStrFree(pszName); 817 RTStrFree(pszValue); 818 RTStrFree(pszFlags); 819 } 820 } 821 822 /** 823 * Notify the service owner that a property has been added/deleted/changed. 824 * asynchronous part. 825 * @param pszProperty the name of the property which has changed 826 * @note this call allocates memory which the reqNotify request is expected to 827 * free again, using RTStrFree(). 828 * 829 * @thread request thread 830 */ 831 int Service::reqNotify(PFNVBOXHGCMCALLBACK pfnCallback, void *pvData, 832 char *pszName, char *pszValue, uint32_t u32TimeHigh, 833 uint32_t u32TimeLow, char *pszFlags) 834 { 835 HOSTCALLBACKDATA HostCallbackData; 836 HostCallbackData.hdr.u32Magic = VBOXHGCMCALLBACKMAGIC; 837 HostCallbackData.hdr.cbStruct = sizeof(HostCallbackData); 838 HostCallbackData.hdr.pvData = pvData; 839 HostCallbackData.pcszName = pszName; 840 HostCallbackData.pcszValue = pszValue; 841 HostCallbackData.u64Timestamp = u32TimeHigh * 0xffff + u32TimeLow; 842 HostCallbackData.pcszFlags = pszFlags; 843 pfnCallback(&HostCallbackData.hdr); 844 RTStrFree(pszName); 845 RTStrFree(pszValue); 846 RTStrFree(pszFlags); 847 return VINF_SUCCESS; 848 } 849 659 850 660 851 /** … … 688 879 case SET_PROP: 689 880 LogFlowFunc(("SET_PROP\n")); 690 rc = set Key(cParms, paParms);881 rc = setProperty(cParms, paParms); 691 882 break; 692 883 … … 694 885 case SET_PROP_VALUE: 695 886 LogFlowFunc(("SET_PROP_VALUE\n")); 696 rc = set Key(cParms, paParms);887 rc = setProperty(cParms, paParms); 697 888 break; 698 889 … … 700 891 case DEL_PROP: 701 892 LogFlowFunc(("DEL_PROP\n")); 702 rc = del Key(cParms, paParms);893 rc = delProperty(cParms, paParms); 703 894 break; 704 895 … … 735 926 /* Set the root CFGM node used. This should be called when instantiating 736 927 * the service. */ 928 /* This whole case is due to go away, so I will not clean it up. */ 737 929 case SET_CFGM_NODE: 738 930 { … … 780 972 case SET_PROP_HOST: 781 973 LogFlowFunc(("SET_PROP_HOST\n")); 782 rc = set Key(cParms, paParms);974 rc = setProperty(cParms, paParms); 783 975 break; 784 976 … … 786 978 case SET_PROP_VALUE_HOST: 787 979 LogFlowFunc(("SET_PROP_VALUE_HOST\n")); 788 rc = set Key(cParms, paParms);980 rc = setProperty(cParms, paParms); 789 981 break; 790 982 791 983 /* The host wishes to remove a configuration value */ 792 984 case DEL_PROP_HOST: 793 LogFlowFunc(("DEL_ CONFIG_KEY_HOST\n"));794 rc = del Key(cParms, paParms);985 LogFlowFunc(("DEL_PROP_HOST\n")); 986 rc = delProperty(cParms, paParms); 795 987 break; 796 988 … … 800 992 rc = enumProps(cParms, paParms); 801 993 break; 994 case REGISTER_CALLBACK: 995 if ((1 != cParms) || (paParms[0].type != VBOX_HGCM_SVC_PARM_CALLBACK)) 996 rc = VERR_INVALID_PARAMETER; 997 else 998 { 999 PFNVBOXHGCMCALLBACK pfnCallback = NULL; 1000 void *pvData = NULL; 1001 rc = VBoxHGCMParmPtrGet (&paParms[0], &pfnCallback, &pvData); 1002 mpfnHostCallback = pfnCallback; 1003 mpvHostData = pvData; 1004 } 1005 break; 802 1006 default: 803 1007 rc = VERR_NOT_SUPPORTED; … … 806 1010 807 1011 LogFlowFunc(("rc = %Vrc\n", rc)); 1012 return rc; 1013 } 1014 1015 int Service::uninit() 1016 { 1017 int rc; 1018 unsigned count = 0; 1019 1020 mfExitThread = true; 1021 rc = RTReqCallEx(mReqQueue, NULL, 0, RTREQFLAGS_NO_WAIT, (PFNRT)reqVoid, 0); 1022 if (RT_SUCCESS(rc)) 1023 do 1024 { 1025 rc = RTThreadWait(mReqThread, 1000, NULL); 1026 ++count; 1027 Assert(RT_SUCCESS(rc) || ((VERR_TIMEOUT == rc) && (count != 5))); 1028 } while ((VERR_TIMEOUT == rc) && (count < 300)); 1029 if (RT_SUCCESS(rc)) 1030 RTReqDestroyQueue(mReqQueue); 808 1031 return rc; 809 1032 } … … 838 1061 { 839 1062 std::auto_ptr<Service> apService; 1063 /* No exceptions may propogate outside. */ 840 1064 try { 841 1065 apService = std::auto_ptr<Service>(new Service(ptable->pHelpers)); 1066 } catch (int rcThrown) { 1067 rc = rcThrown; 842 1068 } catch (...) { 843 /* No exceptions may propogate outside. */844 1069 rc = VERR_UNRESOLVED_ERROR; 845 1070 }
Note:
See TracChangeset
for help on using the changeset viewer.

