Changeset 13759 in vbox
- Timestamp:
- Nov 3, 2008 4:13:04 PM (16 years ago)
- svn:sync-xref-src-repo-rev:
- 38734
- Location:
- trunk
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/HostServices/GuestPropertySvc.h
r13574 r13759 148 148 break; 149 149 if (RT_ELEMENTS(flagList) == i) 150 rc = VERR_ INVALID_PARAMETER;150 rc = VERR_PARSE_ERROR; 151 151 else 152 152 { … … 157 157 if (',' == *pcszNext) 158 158 ++pcszNext; 159 else if (*pcszNext != '\0') 160 rc = VERR_PARSE_ERROR; 159 161 while (' ' == *pcszNext) 160 162 ++pcszNext; … … 189 191 for (; i < RT_ELEMENTS(flagList); ++i) 190 192 { 191 if (f Flags & flagList[i])193 if (flagList[i] == (fFlags & flagList[i])) 192 194 { 193 195 strcpy(pszNext, flagName(flagList[i])); … … 213 215 enum eHostFn 214 216 { 215 /** Pass the address of the cfgm node used by the service as a database. */ 216 SET_CFGM_NODE = 1, 217 /** 218 * Set properties in a block. The parameters are pointers to 219 * NULL-terminated arrays containing the paramters. These are, in order, 220 * name, value, timestamp, flags. Strings are stored as pointers to 221 * mutable utf8 data. All parameters must be supplied. 222 */ 223 SET_PROPS_HOST = 1, 217 224 /** 218 225 * Get the value attached to a guest property -
trunk/src/VBox/HostServices/GuestProperties/service.cpp
r13574 r13759 47 47 48 48 #include <memory> /* for auto_ptr */ 49 #include <string> 50 #include <list> 49 51 50 52 #include <iprt/err.h> … … 59 61 #include <VBox/log.h> 60 62 61 #include <VBox/cfgm.h>62 63 63 /******************************************************************************* 64 64 * Internal functions * … … 77 77 } 78 78 79 /** Extract a constant pointer value from an HGCM parameter structure */ 80 static int VBoxHGCMParmPtrConstGet (VBOXHGCMSVCPARM *pParm, const void **ppv, uint32_t *pcb) 81 { 82 if (pParm->type == VBOX_HGCM_SVC_PARM_PTR) 83 { 84 *ppv = pParm->u.pointer.addr; 85 *pcb = pParm->u.pointer.size; 86 return VINF_SUCCESS; 87 } 88 89 return VERR_INVALID_PARAMETER; 90 } 91 79 92 /** Set a uint32_t value to an HGCM parameter structure */ 80 93 static void VBoxHGCMParmUInt32Set (VBOXHGCMSVCPARM *pParm, uint32_t u32) … … 84 97 } 85 98 86 87 99 /** Set a uint64_t value to an HGCM parameter structure */ 88 100 static void VBoxHGCMParmUInt64Set (VBOXHGCMSVCPARM *pParm, uint64_t u64) … … 90 102 pParm->type = VBOX_HGCM_SVC_PARM_64BIT; 91 103 pParm->u.uint64 = u64; 104 } 105 106 /** Set a pointer value to an HGCM parameter structure */ 107 static void VBoxHGCMParmPtrSet (VBOXHGCMSVCPARM *pParm, void *pv, uint32_t cb) 108 { 109 pParm->type = VBOX_HGCM_SVC_PARM_PTR; 110 pParm->u.pointer.addr = pv; 111 pParm->u.pointer.size = cb; 92 112 } 93 113 … … 104 124 /** HGCM helper functions. */ 105 125 PVBOXHGCMSVCHELPERS mpHelpers; 106 /** Pointer to our configuration values node. */ 107 PCFGMNODE mpValueNode; 108 /** Pointer to our configuration timestamps node. */ 109 PCFGMNODE mpTimestampNode; 110 /** Pointer to our configuration flags node. */ 111 PCFGMNODE mpFlagsNode; 126 /** Structure for holding a property */ 127 struct Property 128 { 129 /** The name of the property */ 130 std::string mName; 131 /** The property value */ 132 std::string mValue; 133 /** The timestamp of the property */ 134 uint64_t mTimestamp; 135 /** The property flags */ 136 uint32_t mFlags; 137 /** Constructor with const char * */ 138 Property(const char *pcszName, const char *pcszValue, 139 uint64_t u64Timestamp, uint32_t u32Flags) 140 : mName(pcszName), mValue(pcszValue), mTimestamp(u64Timestamp), 141 mFlags(u32Flags) {} 142 /** Constructor with std::string */ 143 Property(std::string name, std::string value, uint64_t u64Timestamp, 144 uint32_t u32Flags) 145 : mName(name), mValue(value), mTimestamp(u64Timestamp), 146 mFlags(u32Flags) {} 147 }; 148 /** The properties list type */ 149 typedef std::list <Property> PropertyList; 150 /** The property list */ 151 PropertyList mProperties; 112 152 /** @todo we should have classes for thread and request handler thread */ 113 153 /** Queue of outstanding property change notifications */ … … 125 165 public: 126 166 explicit Service(PVBOXHGCMSVCHELPERS pHelpers) 127 : mpHelpers(pHelpers), mpValueNode(NULL), mpTimestampNode(NULL), 128 mpFlagsNode(NULL), mfExitThread(false), mpfnHostCallback(NULL), 167 : mpHelpers(pHelpers), mfExitThread(false), mpfnHostCallback(NULL), 129 168 mpvHostData(NULL) 130 169 { 131 170 int rc = RTReqCreateQueue(&mReqQueue); 132 rc = RTThreadCreate(&mReqThread, reqThreadFn, this, 0, RTTHREADTYPE_MSG_PUMP, 133 RTTHREADFLAGS_WAITABLE, "GuestPropReq"); 171 #ifndef VBOX_GUEST_PROP_TEST_NOTHREAD 172 if (RT_SUCCESS(rc)) 173 rc = RTThreadCreate(&mReqThread, reqThreadFn, this, 0, 174 RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE, 175 "GuestPropReq"); 176 #endif 134 177 if (RT_FAILURE(rc)) 135 178 throw rc; … … 210 253 static DECLCALLBACK(int) reqThreadFn(RTTHREAD ThreadSelf, void *pvUser); 211 254 int validateName(const char *pszName, uint32_t cbName); 212 int validateValue(c har *pszValue, uint32_t cbValue);213 int getPropValue(uint32_t cParms, VBOXHGCMSVCPARM paParms[]);255 int validateValue(const char *pszValue, uint32_t cbValue); 256 int setPropertyBlock(uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 214 257 int getProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 215 258 int setProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest); … … 286 329 * @thread HGCM 287 330 */ 288 int Service::validateValue(c har *pszValue, uint32_t cbValue)331 int Service::validateValue(const char *pszValue, uint32_t cbValue) 289 332 { 290 333 LogFlowFunc(("cbValue=%d\n", cbValue)); … … 305 348 } 306 349 350 /** 351 * Set a block of properties in the property registry, checking the validity 352 * of the arguments passed. 353 * 354 * @returns iprt status value 355 * @param cParms the number of HGCM parameters supplied 356 * @param paParms the array of HGCM parameters 357 * @thread HGCM 358 */ 359 int Service::setPropertyBlock(uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 360 { 361 char **ppNames, **ppValues, **ppFlags; 362 uint64_t *pTimestamps; 363 uint32_t cbDummy; 364 int rc = VINF_SUCCESS; 365 366 /* 367 * Get and validate the parameters 368 */ 369 if ( (cParms != 4) 370 || RT_FAILURE(VBoxHGCMParmPtrGet (&paParms[0], (void **) &ppNames, &cbDummy)) 371 || RT_FAILURE(VBoxHGCMParmPtrGet (&paParms[1], (void **) &ppValues, &cbDummy)) 372 || RT_FAILURE(VBoxHGCMParmPtrGet (&paParms[2], (void **) &pTimestamps, &cbDummy)) 373 || RT_FAILURE(VBoxHGCMParmPtrGet (&paParms[3], (void **) &ppFlags, &cbDummy)) 374 ) 375 rc = VERR_INVALID_PARAMETER; 376 377 /* 378 * Add the properties to the end of the list. If we succeed then we 379 * will remove duplicates afterwards. 380 */ 381 /* Remember the last property before we started adding, for rollback or 382 * cleanup. */ 383 PropertyList::iterator itEnd = mProperties.end(); 384 if (!mProperties.empty()) 385 --itEnd; 386 try 387 { 388 for (unsigned i = 0; RT_SUCCESS(rc) && ppNames[i] != NULL; ++i) 389 { 390 uint32_t fFlags; 391 if ( !VALID_PTR(ppNames[i]) 392 || !VALID_PTR(ppValues[i]) 393 || !VALID_PTR(ppFlags[i]) 394 ) 395 rc = VERR_INVALID_POINTER; 396 if (RT_SUCCESS(rc)) 397 rc = validateFlags(ppFlags[i], &fFlags); 398 if (RT_SUCCESS(rc)) 399 mProperties.push_back(Property(ppNames[i], ppValues[i], 400 pTimestamps[i], fFlags)); 401 } 402 } 403 catch (std::bad_alloc) 404 { 405 rc = VERR_NO_MEMORY; 406 } 407 408 /* 409 * If all went well then remove the duplicate elements. 410 */ 411 if (RT_SUCCESS(rc) && itEnd != mProperties.end()) 412 { 413 ++itEnd; 414 for (unsigned i = 0; ppNames[i] != NULL; ++i) 415 { 416 bool found = false; 417 for (PropertyList::iterator it = mProperties.begin(); 418 !found && it != itEnd; ++it) 419 if (it->mName.compare(ppNames[i]) == 0) 420 { 421 found = true; 422 mProperties.erase(it); 423 } 424 } 425 } 426 427 /* 428 * If something went wrong then rollback. This is possible because we 429 * haven't deleted anything yet. 430 */ 431 if (RT_FAILURE(rc)) 432 { 433 if (itEnd != mProperties.end()) 434 ++itEnd; 435 mProperties.erase(itEnd, mProperties.end()); 436 } 437 return rc; 438 } 307 439 308 440 /** … … 318 450 * @thread HGCM 319 451 */ 320 int Service::getProp Value(uint32_t cParms, VBOXHGCMSVCPARM paParms[])452 int Service::getProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 321 453 { 322 454 int rc = VINF_SUCCESS; 323 char *pszName, *pszValue; 324 uint32_t cbName, cbValue; 325 size_t cbValueActual; 326 327 LogFlowThisFunc(("\n")); 328 AssertReturn(VALID_PTR(mpValueNode), VERR_WRONG_ORDER); /* a.k.a. VERR_NOT_INITIALIZED */ 329 if ( (cParms != 3) /* Hardcoded value as the next lines depend on it. */ 330 || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR) /* name */ 331 || (paParms[1].type != VBOX_HGCM_SVC_PARM_PTR) /* value */ 332 ) 333 rc = VERR_INVALID_PARAMETER; 334 if (RT_SUCCESS(rc)) 335 rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszName, &cbName); 336 if (RT_SUCCESS(rc)) 337 rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pszValue, &cbValue); 338 if (RT_SUCCESS(rc)) 339 rc = validateName(pszName, cbName); 340 if (RT_SUCCESS(rc)) 341 rc = CFGMR3QuerySize(mpValueNode, pszName, &cbValueActual); 342 if (RT_SUCCESS(rc)) 343 VBoxHGCMParmUInt32Set(&paParms[2], cbValueActual); 344 if (RT_SUCCESS(rc) && (cbValueActual > cbValue)) 345 rc = VERR_BUFFER_OVERFLOW; 346 if (RT_SUCCESS(rc)) 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)); 350 else if (VERR_CFGM_VALUE_NOT_FOUND == rc) 351 rc = VERR_NOT_FOUND; 352 LogFlowThisFunc(("rc = %Rrc\n", rc)); 353 return rc; 354 } 355 356 357 /** 358 * Retrieve a value from the property registry by name, checking the validity 359 * of the arguments passed. If the guest has not allocated enough buffer 360 * space for the value then we return VERR_OVERFLOW and set the size of the 361 * buffer needed in the "size" HGCM parameter. If the name was not found at 362 * all, we return VERR_NOT_FOUND. 363 * 364 * @returns iprt status value 365 * @param cParms the number of HGCM parameters supplied 366 * @param paParms the array of HGCM parameters 367 * @thread HGCM 368 */ 369 int Service::getProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 370 { 371 int rc = VINF_SUCCESS; 372 char *pszName, *pchBuf; 455 const char *pcszName; 456 char *pchBuf; 373 457 uint32_t cchName, cchBuf; 374 size_t cch Value, cchFlags, cchBufActual;458 size_t cchFlags, cchBufActual; 375 459 char szFlags[MAX_FLAGS_LEN]; 376 460 uint32_t fFlags; … … 380 464 */ 381 465 LogFlowThisFunc(("\n")); 382 AssertReturn(VALID_PTR(mpValueNode), VERR_WRONG_ORDER); /* a.k.a. VERR_NOT_INITIALIZED */383 466 if ( (cParms != 4) /* Hardcoded value as the next lines depend on it. */ 384 467 || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR) /* name */ … … 387 470 rc = VERR_INVALID_PARAMETER; 388 471 if (RT_SUCCESS(rc)) 389 rc = VBoxHGCMParmPtr Get(&paParms[0], (void **) &pszName, &cchName);472 rc = VBoxHGCMParmPtrConstGet(&paParms[0], (const void **) &pcszName, &cchName); 390 473 if (RT_SUCCESS(rc)) 391 474 rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pchBuf, &cchBuf); 392 475 if (RT_SUCCESS(rc)) 393 rc = validateName(p szName, cchName);476 rc = validateName(pcszName, cchName); 394 477 395 478 /* … … 398 481 399 482 /* Get the value size */ 400 if (RT_SUCCESS(rc)) 401 rc = CFGMR3QuerySize(mpValueNode, pszName, &cchValue); 402 /* Get the flags and their size */ 403 if (RT_SUCCESS(rc)) 404 CFGMR3QueryU32(mpFlagsNode, pszName, (uint32_t *)&fFlags); 405 if (RT_SUCCESS(rc)) 406 rc = writeFlags(fFlags, szFlags); 483 PropertyList::const_iterator it; 484 bool found = false; 485 if (RT_SUCCESS(rc)) 486 for (it = mProperties.begin(); it != mProperties.end(); ++it) 487 if (it->mName.compare(pcszName) == 0) 488 { 489 found = true; 490 break; 491 } 492 if (RT_SUCCESS(rc) && !found) 493 rc = VERR_NOT_FOUND; 494 if (RT_SUCCESS(rc)) 495 rc = writeFlags(it->mFlags, szFlags); 407 496 if (RT_SUCCESS(rc)) 408 497 cchFlags = strlen(szFlags); … … 410 499 if (RT_SUCCESS(rc)) 411 500 { 412 cchBufActual = cchValue+ cchFlags;501 cchBufActual = it->mValue.size() + 1 + cchFlags; 413 502 VBoxHGCMParmUInt32Set(&paParms[3], cchBufActual); 414 503 } 415 504 if (RT_SUCCESS(rc) && (cchBufActual > cchBuf)) 416 505 rc = VERR_BUFFER_OVERFLOW; 417 /* Write the value */ 418 if (RT_SUCCESS(rc)) 419 rc = CFGMR3QueryString(mpValueNode, pszName, pchBuf, cchBuf); 420 /* Write the flags */ 421 if (RT_SUCCESS(rc)) 422 strcpy(pchBuf + cchValue, szFlags); 423 /* Timestamp */ 424 uint64_t u64Timestamp = 0; 425 if (RT_SUCCESS(rc)) 426 CFGMR3QueryU64(mpTimestampNode, pszName, &u64Timestamp); 427 VBoxHGCMParmUInt64Set(&paParms[2], u64Timestamp); 506 /* Write the value, flags and timestamp */ 507 if (RT_SUCCESS(rc)) 508 { 509 it->mValue.copy(pchBuf, cchBuf, 0); 510 pchBuf[it->mValue.size()] = '\0'; /* Terminate the value */ 511 strcpy(pchBuf + it->mValue.size() + 1, szFlags); 512 VBoxHGCMParmUInt64Set(&paParms[2], it->mTimestamp); 513 } 428 514 429 515 /* … … 431 517 */ 432 518 if (RT_SUCCESS(rc)) 433 Log2(("Queried string %S, value=%.*S, timestamp=%lld, flags=%.*S\n", 434 pszName, cchValue, pchBuf, u64Timestamp, cchFlags, 435 pchBuf + cchValue)); 436 else if (VERR_CFGM_VALUE_NOT_FOUND == rc) 437 rc = VERR_NOT_FOUND; 519 Log2(("Queried string %s, value=%s, timestamp=%lld, flags=%s\n", 520 pcszName, it->mValue.c_str(), it->mTimestamp, szFlags)); 438 521 LogFlowThisFunc(("rc = %Rrc\n", rc)); 439 522 return rc; 440 523 } 441 524 442 443 525 /** 444 526 * Set a value in the property registry by name, checking the validity 527 * of the arguments passed. 528 * 529 * @returns iprt status value 530 * @param cParms the number of HGCM parameters supplied 531 * @param paParms the array of HGCM parameters 532 * @param isGuest is this call coming from the guest (or the host)? 533 * @throws std::bad_alloc if an out of memory condition occurs 534 * @thread HGCM 535 */ 536 int Service::setProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest) 537 { 538 int rc = VINF_SUCCESS; 539 const char *pcszName, *pcszValue, *pcszFlags = NULL; 540 uint32_t cchName, cchValue, cchFlags = 0; 541 uint32_t fFlags = NILFLAG; 542 543 LogFlowThisFunc(("\n")); 544 /* 545 * First of all, make sure that we won't exceed the maximum number of properties. 546 */ 547 if (mProperties.size() >= MAX_PROPS) 548 rc = VERR_TOO_MUCH_DATA; 549 550 /* 551 * General parameter correctness checking. 552 */ 553 if ( RT_SUCCESS(rc) 554 && ( (cParms < 2) || (cParms > 3) /* Hardcoded value as the next lines depend on it. */ 555 || RT_FAILURE(VBoxHGCMParmPtrConstGet(&paParms[0], 556 (const void **) &pcszName, &cchName)) /* name */ 557 || RT_FAILURE(VBoxHGCMParmPtrConstGet(&paParms[1], 558 (const void **) &pcszValue, &cchValue)) /* value */ 559 || ( (3 == cParms) 560 && RT_FAILURE(VBoxHGCMParmPtrConstGet(&paParms[2], 561 (const void **) &pcszFlags, &cchFlags)) /* flags */ 562 ) 563 ) 564 ) 565 rc = VERR_INVALID_PARAMETER; 566 567 /* 568 * Check the values passed in the parameters for correctness. 569 */ 570 if (RT_SUCCESS(rc)) 571 rc = validateName(pcszName, cchName); 572 if (RT_SUCCESS(rc)) 573 rc = validateValue(pcszValue, cchValue); 574 if ((3 == cParms) && RT_SUCCESS(rc)) 575 rc = RTStrValidateEncodingEx(pcszFlags, cchFlags, 576 RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED); 577 if ((3 == cParms) && RT_SUCCESS(rc)) 578 rc = validateFlags(pcszFlags, &fFlags); 579 580 /* 581 * If the property already exists, check its flags to see if we are allowed 582 * to change it. 583 */ 584 PropertyList::iterator it; 585 bool found = false; 586 if (RT_SUCCESS(rc)) 587 for (it = mProperties.begin(); it != mProperties.end(); ++it) 588 if (it->mName.compare(pcszName) == 0) 589 { 590 found = true; 591 break; 592 } 593 if (RT_SUCCESS(rc) && found) 594 if ( (isGuest && (it->mFlags & RDONLYGUEST)) 595 || (!isGuest && (it->mFlags & RDONLYHOST)) 596 ) 597 rc = VERR_PERMISSION_DENIED; 598 599 /* 600 * Set the actual value 601 */ 602 if (RT_SUCCESS(rc)) 603 { 604 RTTIMESPEC time; 605 uint64_t u64TimeNano = RTTimeSpecGetNano(RTTimeNow(&time)); 606 if (found) 607 { 608 it->mValue = pcszValue; 609 it->mTimestamp = u64TimeNano; 610 it->mFlags = fFlags; 611 } 612 else /* This can throw. No problem as we have nothing to roll back. */ 613 mProperties.push_back(Property(pcszName, pcszValue, u64TimeNano, fFlags)); 614 } 615 616 /* 617 * Send a notification to the host and return. 618 */ 619 if (RT_SUCCESS(rc)) 620 { 621 // if (isGuest) /* Notify the host even for properties that the host 622 // * changed. Less efficient, but ensures consistency. */ 623 notifyHost(pcszName); 624 Log2(("Set string %s, rc=%Rrc, value=%s\n", pcszName, rc, pcszValue)); 625 } 626 LogFlowThisFunc(("rc = %Rrc\n", rc)); 627 return rc; 628 } 629 630 631 /** 632 * Remove a value in the property registry by name, checking the validity 633 * of the arguments passed. 634 * 635 * @returns iprt status value 636 * @param cParms the number of HGCM parameters supplied 637 * @param paParms the array of HGCM parameters 638 * @param isGuest is this call coming from the guest (or the host)? 639 * @thread HGCM 640 */ 641 int Service::delProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest) 642 { 643 int rc = VINF_SUCCESS; 644 const char *pcszName; 645 uint32_t cbName; 646 647 LogFlowThisFunc(("\n")); 648 649 /* 650 * Check the user-supplied parameters. 651 */ 652 if ( (cParms != 1) /* Hardcoded value as the next lines depend on it. */ 653 || RT_FAILURE(VBoxHGCMParmPtrConstGet(&paParms[0], 654 (const void **) &pcszName, &cbName)) /* name */ 655 ) 656 rc = VERR_INVALID_PARAMETER; 657 if (RT_SUCCESS(rc)) 658 rc = validateName(pcszName, cbName); 659 660 /* 661 * If the property exists, check its flags to see if we are allowed 662 * to change it. 663 */ 664 PropertyList::iterator it; 665 bool found = false; 666 if (RT_SUCCESS(rc)) 667 for (it = mProperties.begin(); it != mProperties.end(); ++it) 668 if (it->mName.compare(pcszName) == 0) 669 { 670 found = true; 671 break; 672 } 673 if (RT_SUCCESS(rc) && found) 674 if ( (isGuest && (it->mFlags & RDONLYGUEST)) 675 || (!isGuest && (it->mFlags & RDONLYHOST)) 676 ) 677 rc = VERR_PERMISSION_DENIED; 678 679 /* 680 * And delete the property if all is well. 681 */ 682 if (RT_SUCCESS(rc) && found) 683 { 684 mProperties.erase(it); 685 // if (isGuest) /* Notify the host even for properties that the host 686 // * changed. Less efficient, but ensures consistency. */ 687 notifyHost(pcszName); 688 } 689 LogFlowThisFunc(("rc = %Rrc\n", rc)); 690 return rc; 691 } 692 693 /** 694 * Enumerate guest properties by mask, checking the validity 445 695 * of the arguments passed. 446 696 * … … 450 700 * @thread HGCM 451 701 */ 452 int Service:: setProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest)702 int Service::enumProps(uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 453 703 { 454 704 int rc = VINF_SUCCESS; 455 char *pszName, *pszValue; 456 uint32_t cchName, cchValue; 457 uint32_t fFlags = NILFLAG; 458 705 706 /* 707 * Get the HGCM function arguments. 708 */ 709 char *pcchPatterns = NULL, *pchBuf = NULL; 710 uint32_t cchPatterns = 0, cchBuf = 0; 459 711 LogFlowThisFunc(("\n")); 460 AssertReturn(VALID_PTR(mpValueNode), VERR_WRONG_ORDER); /* a.k.a. VERR_NOT_INITIALIZED */ 461 /* 462 * First of all, make sure that we won't exceed the maximum number of properties. 463 */ 464 { 465 unsigned cChildren = 0; 466 for (PCFGMNODE pChild = CFGMR3GetFirstChild(mpValueNode); pChild != 0; pChild = CFGMR3GetNextChild(pChild)) 467 ++cChildren; 468 if (cChildren >= MAX_PROPS) 469 rc = VERR_TOO_MUCH_DATA; 470 } 471 /* 472 * General parameter correctness checking. 473 */ 474 if ( RT_SUCCESS(rc) 475 && ( (cParms < 2) || (cParms > 4) /* Hardcoded value as the next lines depend on it. */ 476 || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR) /* name */ 477 || (paParms[1].type != VBOX_HGCM_SVC_PARM_PTR) /* value */ 478 || ((3 == cParms) && (paParms[2].type != VBOX_HGCM_SVC_PARM_PTR)) /* flags */ 479 ) 712 if ( (cParms != 3) /* Hardcoded value as the next lines depend on it. */ 713 || RT_FAILURE(VBoxHGCMParmPtrConstGet(&paParms[0], 714 (const void **) &pcchPatterns, &cchPatterns)) /* patterns */ 715 || RT_FAILURE(VBoxHGCMParmPtrGet(&paParms[1], 716 (void **) &pchBuf, &cchBuf)) /* return buffer */ 480 717 ) 481 718 rc = VERR_INVALID_PARAMETER; 482 /*483 * Check the values passed in the parameters for correctness.484 */485 if (RT_SUCCESS(rc))486 rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszName, &cchName);487 if (RT_SUCCESS(rc))488 rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pszValue, &cchValue);489 if (RT_SUCCESS(rc))490 rc = validateName(pszName, cchName);491 if (RT_SUCCESS(rc))492 rc = validateValue(pszValue, cchValue);493 494 /*495 * If the property already exists, check its flags to see if we are allowed496 * to change it.497 */498 if (RT_SUCCESS(rc))499 {500 CFGMR3QueryU32(mpFlagsNode, pszName, &fFlags); /* Failure is no problem here. */501 if ( (isGuest && (fFlags & RDONLYGUEST))502 || (!isGuest && (fFlags & RDONLYHOST))503 )504 rc = VERR_PERMISSION_DENIED;505 }506 507 /*508 * Check whether the user supplied flags (if any) are valid.509 */510 if (RT_SUCCESS(rc) && (3 == cParms))511 {512 char *pszFlags;513 uint32_t cchFlags;514 rc = VBoxHGCMParmPtrGet(&paParms[2], (void **) &pszFlags, &cchFlags);515 if (RT_SUCCESS(rc))516 rc = validateFlags(pszFlags, &fFlags);517 }518 /*519 * Set the actual value520 */521 if (RT_SUCCESS(rc))522 {523 RTTIMESPEC time;524 CFGMR3RemoveValue(mpValueNode, pszName);525 CFGMR3RemoveValue(mpTimestampNode, pszName);526 CFGMR3RemoveValue(mpFlagsNode, pszName);527 rc = CFGMR3InsertString(mpValueNode, pszName, pszValue);528 if (RT_SUCCESS(rc))529 rc = CFGMR3InsertInteger(mpTimestampNode, pszName,530 RTTimeSpecGetNano(RTTimeNow(&time)));531 if (RT_SUCCESS(rc))532 rc = CFGMR3InsertInteger(mpFlagsNode, pszName, fFlags);533 /* If anything goes wrong, make sure that we leave a clean state534 * behind. */535 if (RT_FAILURE(rc))536 {537 CFGMR3RemoveValue(mpValueNode, pszName);538 CFGMR3RemoveValue(mpTimestampNode, pszName);539 CFGMR3RemoveValue(mpFlagsNode, pszName);540 }541 }542 /*543 * Send a notification to the host and return.544 */545 if (RT_SUCCESS(rc))546 {547 if (isGuest)548 notifyHost(pszName);549 Log2(("Set string %s, rc=%Rrc, value=%s\n", pszName, rc, pszValue));550 }551 LogFlowThisFunc(("rc = %Rrc\n", rc));552 return rc;553 }554 555 556 /**557 * Remove a value in the property registry by name, checking the validity558 * of the arguments passed.559 *560 * @returns iprt status value561 * @param cParms the number of HGCM parameters supplied562 * @param paParms the array of HGCM parameters563 * @thread HGCM564 */565 int Service::delProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest)566 {567 int rc = VINF_SUCCESS;568 char *pszName;569 uint32_t cbName;570 571 LogFlowThisFunc(("\n"));572 AssertReturn(VALID_PTR(mpValueNode), VERR_WRONG_ORDER); /* a.k.a. VERR_NOT_INITIALIZED */573 574 /*575 * Check the user-supplied parameters.576 */577 if ( (cParms != 1) /* Hardcoded value as the next lines depend on it. */578 || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR) /* name */579 )580 rc = VERR_INVALID_PARAMETER;581 if (RT_SUCCESS(rc))582 rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszName, &cbName);583 if (RT_SUCCESS(rc))584 rc = validateName(pszName, cbName);585 586 /*587 * If the property already exists, check its flags to see if we are allowed588 * to change it.589 */590 if (RT_SUCCESS(rc))591 {592 uint32_t fFlags = NILFLAG;593 CFGMR3QueryU32(mpFlagsNode, pszName, &fFlags); /* Failure is no problem here. */594 if ( (isGuest && (fFlags & RDONLYGUEST))595 || (!isGuest && (fFlags & RDONLYHOST))596 )597 rc = VERR_PERMISSION_DENIED;598 }599 600 /*601 * And delete the property if all is well.602 */603 if (RT_SUCCESS(rc))604 {605 CFGMR3RemoveValue(mpValueNode, pszName);606 if (isGuest)607 notifyHost(pszName);608 }609 LogFlowThisFunc(("rc = %Rrc\n", rc));610 return rc;611 }612 613 /**614 * Enumerate guest properties by mask, checking the validity615 * of the arguments passed.616 *617 * @returns iprt status value618 * @param cParms the number of HGCM parameters supplied619 * @param paParms the array of HGCM parameters620 * @thread HGCM621 */622 int Service::enumProps(uint32_t cParms, VBOXHGCMSVCPARM paParms[])623 {624 /* We reallocate the temporary buffer in which we build up our array in625 * increments of size BLOCK: */626 enum627 {628 /* Calculate the increment, not yet rounded down */629 BLOCKINCRFULL = (MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN + 2048),630 /* And this is the increment after rounding */631 BLOCKINCR = BLOCKINCRFULL - BLOCKINCRFULL % 1024632 };633 int rc = VINF_SUCCESS;634 635 /*636 * Get the HGCM function arguments.637 */638 char *paszPatterns = NULL, *pchBuf = NULL;639 uint32_t cchPatterns = 0, cchBuf = 0;640 LogFlowThisFunc(("\n"));641 AssertReturn(VALID_PTR(mpValueNode), VERR_WRONG_ORDER); /* a.k.a. VERR_NOT_INITIALIZED */642 if ( (cParms != 3) /* Hardcoded value as the next lines depend on it. */643 || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR) /* patterns */644 || (paParms[1].type != VBOX_HGCM_SVC_PARM_PTR) /* return buffer */645 )646 rc = VERR_INVALID_PARAMETER;647 if (RT_SUCCESS(rc))648 rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &paszPatterns, &cchPatterns);649 719 if (RT_SUCCESS(rc) && cchPatterns > MAX_PATTERN_LEN) 650 720 rc = VERR_TOO_MUCH_DATA; 651 if (RT_SUCCESS(rc)) 652 rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pchBuf, &cchBuf); 653 654 /* 655 * First repack the patterns into the format expected by RTStrSimplePatternMatch() 656 */ 721 722 /* 723 * First repack the patterns into the format expected by RTStrSimplePatternMatch() 724 */ 657 725 bool matchAll = false; 658 726 char pszPatterns[MAX_PATTERN_LEN]; 659 if ( (NULL == p aszPatterns)727 if ( (NULL == pcchPatterns) 660 728 || (cchPatterns < 2) /* An empty pattern string means match all */ 661 729 ) … … 664 732 { 665 733 for (unsigned i = 0; i < cchPatterns - 1; ++i) 666 if (p aszPatterns[i] != '\0')667 pszPatterns[i] = p aszPatterns[i];734 if (pcchPatterns[i] != '\0') 735 pszPatterns[i] = pcchPatterns[i]; 668 736 else 669 737 pszPatterns[i] = '|'; … … 671 739 } 672 740 673 /* 674 * Next enumerate all values in the current node into a temporary buffer. 675 */ 676 RTMemAutoPtr<char> TmpBuf; 677 uint32_t cchTmpBuf = 0, iTmpBuf = 0; 678 PCFGMLEAF pLeaf = CFGMR3GetFirstValue(mpValueNode); 679 while ((pLeaf != NULL) && RT_SUCCESS(rc)) 680 { 681 /* Reallocate the buffer if it has got too tight */ 682 if (iTmpBuf + BLOCKINCR > cchTmpBuf) 683 { 684 cchTmpBuf += BLOCKINCR * 2; 685 if (!TmpBuf.realloc(cchTmpBuf)) 686 rc = VERR_NO_MEMORY; 687 } 688 /* Fetch the name into the buffer and if it matches one of the 689 * patterns, add its value and an empty timestamp and flags. If it 690 * doesn't match, we simply overwrite it in the buffer. */ 691 if (RT_SUCCESS(rc)) 692 rc = CFGMR3GetValueName(pLeaf, &TmpBuf[iTmpBuf], cchTmpBuf - iTmpBuf); 693 /* Only increment the buffer offest if the name matches, otherwise we 694 * overwrite it next iteration. */ 695 if ( RT_SUCCESS(rc) 696 && ( matchAll 697 || RTStrSimplePatternMultiMatch(pszPatterns, RTSTR_MAX, 698 &TmpBuf[iTmpBuf], RTSTR_MAX, 699 NULL) 700 ) 741 /* 742 * Next enumerate into a temporary buffer. This can throw, but this is 743 * not a problem as we have nothing to roll back. 744 */ 745 std::string buffer; 746 for (PropertyList::const_iterator it = mProperties.begin(); 747 RT_SUCCESS(rc) && (it != mProperties.end()); ++it) 748 { 749 if ( matchAll 750 || RTStrSimplePatternMultiMatch(pszPatterns, RTSTR_MAX, 751 it->mName.c_str(), RTSTR_MAX, NULL) 701 752 ) 702 753 { 703 const char *pszName = &TmpBuf[iTmpBuf]; 704 /* Get value */ 705 iTmpBuf += strlen(&TmpBuf[iTmpBuf]) + 1; 706 rc = CFGMR3QueryString(mpValueNode, pszName, &TmpBuf[iTmpBuf], 707 cchTmpBuf - iTmpBuf); 754 char szFlags[MAX_FLAGS_LEN]; 755 char szTimestamp[256]; 756 size_t cchTimestamp; 757 buffer += it->mName; 758 buffer += '\0'; 759 buffer += it->mValue; 760 buffer += '\0'; 761 cchTimestamp = RTStrFormatNumber(szTimestamp, it->mTimestamp, 762 10, 0, 0, 0); 763 buffer.append(szTimestamp, cchTimestamp); 764 buffer += '\0'; 765 rc = writeFlags(it->mFlags, szFlags); 708 766 if (RT_SUCCESS(rc)) 709 { 710 /* Get timestamp */ 711 iTmpBuf += strlen(&TmpBuf[iTmpBuf]) + 1; 712 uint64_t u64Timestamp = 0; 713 CFGMR3QueryU64(mpTimestampNode, pszName, &u64Timestamp); 714 iTmpBuf += RTStrFormatNumber(&TmpBuf[iTmpBuf], u64Timestamp, 715 10, 0, 0, 0) + 1; 716 /* Get flags */ 717 uint32_t fFlags = NILFLAG; 718 CFGMR3QueryU32(mpFlagsNode, pszName, &fFlags); 719 TmpBuf[iTmpBuf] = '\0'; /* Bad (== in)sanity, will be fixed. */ 720 writeFlags(fFlags, &TmpBuf[iTmpBuf]); 721 iTmpBuf += strlen(&TmpBuf[iTmpBuf]) + 1; 722 } 767 buffer += szFlags; 768 buffer += '\0'; 723 769 } 724 if (RT_SUCCESS(rc)) 725 pLeaf = CFGMR3GetNextValue(pLeaf); 726 } 727 if (RT_SUCCESS(rc)) 728 { 729 /* The terminator. We *do* have space left for this. */ 730 TmpBuf[iTmpBuf] = '\0'; 731 TmpBuf[iTmpBuf + 1] = '\0'; 732 TmpBuf[iTmpBuf + 2] = '\0'; 733 TmpBuf[iTmpBuf + 3] = '\0'; 734 iTmpBuf += 4; 735 VBoxHGCMParmUInt32Set(&paParms[2], iTmpBuf); 770 } 771 buffer.append(4, '\0'); /* The final terminators */ 772 773 /* 774 * Finally write out the temporary buffer to the real one if it is not too 775 * small. 776 */ 777 if (RT_SUCCESS(rc)) 778 { 779 VBoxHGCMParmUInt32Set(&paParms[2], buffer.size()); 736 780 /* Copy the memory if it fits into the guest buffer */ 737 if ( iTmpBuf<= cchBuf)738 memcpy(pchBuf, TmpBuf.get(), iTmpBuf);781 if (buffer.size() <= cchBuf) 782 buffer.copy(pchBuf, cchBuf); 739 783 else 740 784 rc = VERR_BUFFER_OVERFLOW; … … 753 797 void Service::notifyHost(const char *pszProperty) 754 798 { 755 char szValue[MAX_VALUE_LEN]; 756 uint64_t u64Timestamp = 0; 757 uint32_t fFlags = NILFLAG; 799 #ifndef VBOX_GUEST_PROP_TEST_NOTHREAD 758 800 char szFlags[MAX_FLAGS_LEN]; 759 801 char *pszName = NULL, *pszValue = NULL, *pszFlags = NULL; 760 761 AssertPtr(mpValueNode); 802 int rc = VINF_SUCCESS; 803 762 804 if (NULL == mpfnHostCallback) 763 805 return; /* Nothing to do. */ 764 int rc = CFGMR3QueryString(mpValueNode, pszProperty, szValue, 765 sizeof(szValue)); 806 PropertyList::const_iterator it; 807 bool found = false; 808 if (RT_SUCCESS(rc)) 809 for (it = mProperties.begin(); it != mProperties.end(); ++it) 810 if (it->mName.compare(pszProperty) == 0) 811 { 812 found = true; 813 break; 814 } 766 815 /* 767 816 * First case: if the property exists then send the host its current value 768 817 */ 769 if (rc != VERR_CFGM_VALUE_NOT_FOUND) 770 { 771 if (RT_SUCCESS(rc)) 772 rc = CFGMR3QueryU64(mpTimestampNode, pszProperty, &u64Timestamp); 773 if (RT_SUCCESS(rc)) 774 rc = CFGMR3QueryU32(mpFlagsNode, pszProperty, &fFlags); 775 if (RT_SUCCESS(rc)) 776 rc = writeFlags(fFlags, szFlags); 818 if (found) 819 { 820 rc = writeFlags(it->mFlags, szFlags); 777 821 if (RT_SUCCESS(rc)) 778 822 rc = RTStrDupEx(&pszName, pszProperty); 779 823 if (RT_SUCCESS(rc)) 780 rc = RTStrDupEx(&pszValue, szValue);824 rc = RTStrDupEx(&pszValue, it->mValue.c_str()); 781 825 if (RT_SUCCESS(rc)) 782 826 rc = RTStrDupEx(&pszFlags, szFlags); … … 785 829 (PFNRT)Service::reqNotify, 7, mpfnHostCallback, 786 830 mpvHostData, pszName, pszValue, 787 (uint32_t) RT_HIDWORD(u64Timestamp), 788 (uint32_t) RT_LODWORD(u64Timestamp), pszFlags); 789 if (RT_FAILURE(rc)) /* clean up */ 790 { 791 RTStrFree(pszName); 792 RTStrFree(pszValue); 793 RTStrFree(pszFlags); 794 } 831 (uint32_t) RT_HIDWORD(it->mTimestamp), 832 (uint32_t) RT_LODWORD(it->mTimestamp), pszFlags); 795 833 } 796 834 else … … 812 850 RTStrFree(pszFlags); 813 851 } 852 #endif /* VBOX_GUEST_PROP_TEST_NOTHREAD not defined */ 814 853 } 815 854 … … 861 900 u32ClientID, eFunction, cParms, paParms)); 862 901 863 switch (eFunction) 864 { 865 /* The guest wishes to read a property */ 866 case GET_PROP: 867 LogFlowFunc(("GET_PROP\n")); 868 rc = getProperty(cParms, paParms); 869 break; 870 871 /* The guest wishes to set a property */ 872 case SET_PROP: 873 LogFlowFunc(("SET_PROP\n")); 874 rc = setProperty(cParms, paParms, true); 875 break; 876 877 /* The guest wishes to set a property value */ 878 case SET_PROP_VALUE: 879 LogFlowFunc(("SET_PROP_VALUE\n")); 880 rc = setProperty(cParms, paParms, true); 881 break; 882 883 /* The guest wishes to remove a configuration value */ 884 case DEL_PROP: 885 LogFlowFunc(("DEL_PROP\n")); 886 rc = delProperty(cParms, paParms, true); 887 break; 888 889 /* The guest wishes to enumerate all properties */ 890 case ENUM_PROPS: 891 LogFlowFunc(("ENUM_PROPS\n")); 892 rc = enumProps(cParms, paParms); 893 break; 894 default: 895 rc = VERR_NOT_IMPLEMENTED; 902 try 903 { 904 switch (eFunction) 905 { 906 /* The guest wishes to read a property */ 907 case GET_PROP: 908 LogFlowFunc(("GET_PROP\n")); 909 rc = getProperty(cParms, paParms); 910 break; 911 912 /* The guest wishes to set a property */ 913 case SET_PROP: 914 LogFlowFunc(("SET_PROP\n")); 915 rc = setProperty(cParms, paParms, true); 916 break; 917 918 /* The guest wishes to set a property value */ 919 case SET_PROP_VALUE: 920 LogFlowFunc(("SET_PROP_VALUE\n")); 921 rc = setProperty(cParms, paParms, true); 922 break; 923 924 /* The guest wishes to remove a configuration value */ 925 case DEL_PROP: 926 LogFlowFunc(("DEL_PROP\n")); 927 rc = delProperty(cParms, paParms, true); 928 break; 929 930 /* The guest wishes to enumerate all properties */ 931 case ENUM_PROPS: 932 LogFlowFunc(("ENUM_PROPS\n")); 933 rc = enumProps(cParms, paParms); 934 break; 935 936 default: 937 rc = VERR_NOT_IMPLEMENTED; 938 } 939 } 940 catch (std::bad_alloc) 941 { 942 rc = VERR_NO_MEMORY; 896 943 } 897 944 if (fCallSync) … … 915 962 eFunction, cParms, paParms)); 916 963 917 switch (eFunction) 918 { 919 /* Set the root CFGM node used. This should be called when instantiating 920 * the service. */ 921 /* This whole case is due to go away, so I will not clean it up. */ 922 case SET_CFGM_NODE: 964 try 965 { 966 switch (eFunction) 923 967 { 924 LogFlowFunc(("SET_CFGM_NODE\n")); 925 926 if ( (cParms != 3) 927 || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR) /* pValue */ 928 || (paParms[1].type != VBOX_HGCM_SVC_PARM_PTR) /* pTimestamp */ 929 || (paParms[2].type != VBOX_HGCM_SVC_PARM_PTR) /* pFlags */ 930 ) 931 rc = VERR_INVALID_PARAMETER; 932 else 933 { 934 PCFGMNODE pValue = NULL, pTimestamp = NULL, pFlags = NULL; 935 uint32_t cbDummy; 936 937 rc = VBoxHGCMParmPtrGet (&paParms[0], (void **) &pValue, &cbDummy); 938 if (RT_SUCCESS(rc)) 939 rc = VBoxHGCMParmPtrGet (&paParms[1], (void **) &pTimestamp, &cbDummy); 940 if (RT_SUCCESS(rc)) 941 rc = VBoxHGCMParmPtrGet (&paParms[2], (void **) &pFlags, &cbDummy); 942 if (RT_SUCCESS(rc)) 943 { 944 mpValueNode = pValue; 945 mpTimestampNode = pTimestamp; 946 mpFlagsNode = pFlags; 947 } 948 } 949 } break; 950 951 /* The host wishes to read a configuration value */ 952 case GET_PROP_HOST: 953 LogFlowFunc(("GET_PROP_HOST\n")); 954 rc = getProperty(cParms, paParms); 955 break; 956 957 /* The host wishes to set a configuration value */ 958 case SET_PROP_HOST: 959 LogFlowFunc(("SET_PROP_HOST\n")); 960 rc = setProperty(cParms, paParms, false); 961 break; 962 963 /* The host wishes to set a configuration value */ 964 case SET_PROP_VALUE_HOST: 965 LogFlowFunc(("SET_PROP_VALUE_HOST\n")); 966 rc = setProperty(cParms, paParms, false); 967 break; 968 969 /* The host wishes to remove a configuration value */ 970 case DEL_PROP_HOST: 971 LogFlowFunc(("DEL_PROP_HOST\n")); 972 rc = delProperty(cParms, paParms, false); 973 break; 974 975 /* The host wishes to enumerate all properties */ 976 case ENUM_PROPS_HOST: 977 LogFlowFunc(("ENUM_PROPS\n")); 978 rc = enumProps(cParms, paParms); 979 break; 980 default: 981 rc = VERR_NOT_SUPPORTED; 982 break; 968 /* The host wishes to set a block of properties */ 969 case SET_PROPS_HOST: 970 LogFlowFunc(("SET_PROPS_HOST\n")); 971 rc = setPropertyBlock(cParms, paParms); 972 break; 973 974 /* The host wishes to read a configuration value */ 975 case GET_PROP_HOST: 976 LogFlowFunc(("GET_PROP_HOST\n")); 977 rc = getProperty(cParms, paParms); 978 break; 979 980 /* The host wishes to set a configuration value */ 981 case SET_PROP_HOST: 982 LogFlowFunc(("SET_PROP_HOST\n")); 983 rc = setProperty(cParms, paParms, false); 984 break; 985 986 /* The host wishes to set a configuration value */ 987 case SET_PROP_VALUE_HOST: 988 LogFlowFunc(("SET_PROP_VALUE_HOST\n")); 989 rc = setProperty(cParms, paParms, false); 990 break; 991 992 /* The host wishes to remove a configuration value */ 993 case DEL_PROP_HOST: 994 LogFlowFunc(("DEL_PROP_HOST\n")); 995 rc = delProperty(cParms, paParms, false); 996 break; 997 998 /* The host wishes to enumerate all properties */ 999 case ENUM_PROPS_HOST: 1000 LogFlowFunc(("ENUM_PROPS\n")); 1001 rc = enumProps(cParms, paParms); 1002 break; 1003 1004 default: 1005 rc = VERR_NOT_SUPPORTED; 1006 break; 1007 } 1008 } 1009 catch (std::bad_alloc) 1010 { 1011 rc = VERR_NO_MEMORY; 983 1012 } 984 1013 … … 989 1018 int Service::uninit() 990 1019 { 991 int rc ;1020 int rc = VINF_SUCCESS; 992 1021 unsigned count = 0; 993 1022 994 1023 mfExitThread = true; 1024 #ifndef VBOX_GUEST_PROP_TEST_NOTHREAD 995 1025 rc = RTReqCallEx(mReqQueue, NULL, 0, RTREQFLAGS_NO_WAIT, (PFNRT)reqVoid, 0); 996 1026 if (RT_SUCCESS(rc)) … … 1001 1031 Assert(RT_SUCCESS(rc) || ((VERR_TIMEOUT == rc) && (count != 5))); 1002 1032 } while ((VERR_TIMEOUT == rc) && (count < 300)); 1033 #endif /* VBOX_GUEST_PROP_TEST_NOTHREAD not defined */ 1003 1034 if (RT_SUCCESS(rc)) 1004 1035 RTReqDestroyQueue(mReqQueue); -
trunk/src/VBox/HostServices/GuestProperties/testcase/Makefile.kmk
r13629 r13759 29 29 PROGRAMS += tstGuestPropSvc 30 30 tstGuestPropSvc_TEMPLATE = VBOXR3TSTEXE 31 tstGuestPropSvc_DEFS = VBOX_WITH_HGCM 32 tstGuestPropSvc_SOURCES = tstGuestPropSvc.cpp 31 # The second define here is to ensure that the testcase will run fast, without 32 # waiting for any thread synchronisation. 33 tstGuestPropSvc_DEFS = VBOX_WITH_HGCM VBOX_GUEST_PROP_TEST_NOTHREAD 34 tstGuestPropSvc_SOURCES = tstGuestPropSvc.cpp ../service.cpp 33 35 tstGuestPropSvc_LIBS = $(LIB_RUNTIME) 36 37 # Set this in LocalConfig.kmk if you are working on the guest property service 38 # to automatically run the testcase at build time. 39 ifdef VBOX_RUN_GUEST_PROPERTY_TEST 40 ifndef VBOX_ONLY_SDK 41 TESTING += $(PATH_tstGuestPropSvc)/tstGuestPropSvc.run 42 OTHERS += $(PATH_tstGuestPropSvc)/tstGuestPropSvc.run 43 $$(PATH_tstGuestPropSvc)/tstGuestPropSvc.run: $$(INSTARGET_tstGuestPropSvc) 44 $(INSTARGET_tstGuestPropSvc) quiet 45 $(QUIET)$(APPEND) -t "$@" "done" 46 endif 47 endif 34 48 35 49 endif # VBOX_WITH_TESTCASES -
trunk/src/VBox/HostServices/GuestProperties/testcase/tstGuestPropSvc.cpp
r13627 r13759 2 2 /** @file 3 3 * 4 * Testcase for the guest property service. For now, this only tests 5 * flag conversion. 4 * Testcase for the guest property service. 6 5 */ 7 6 … … 31 30 using namespace guestProp; 32 31 33 /** 34 * A list of valid flag strings. The flag conversion functions should accept 35 * these and convert them from string to a flag type and back without errors. 32 extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad (VBOXHGCMSVCFNTABLE *ptable); 33 34 /** Set a pointer value to an HGCM parameter structure */ 35 static void VBoxHGCMParmPtrSet (VBOXHGCMSVCPARM *pParm, void *pv, uint32_t cb) 36 { 37 pParm->type = VBOX_HGCM_SVC_PARM_PTR; 38 pParm->u.pointer.addr = pv; 39 pParm->u.pointer.size = cb; 40 } 41 42 /** Extract a uint64_t value from an HGCM parameter structure */ 43 static int VBoxHGCMParmUInt32Get (VBOXHGCMSVCPARM *pParm, uint32_t *pu32Value) 44 { 45 if (pParm->type == VBOX_HGCM_SVC_PARM_32BIT) 46 { 47 *pu32Value = pParm->u.uint32; 48 return VINF_SUCCESS; 49 } 50 51 return VERR_INVALID_PARAMETER; 52 } 53 54 /** Extract a uint64_t value from an HGCM parameter structure */ 55 static int VBoxHGCMParmUInt64Get (VBOXHGCMSVCPARM *pParm, uint64_t *pu64Value) 56 { 57 if (pParm->type == VBOX_HGCM_SVC_PARM_64BIT) 58 { 59 *pu64Value = pParm->u.uint64; 60 return VINF_SUCCESS; 61 } 62 63 return VERR_INVALID_PARAMETER; 64 } 65 66 /** Simple call handle structure for the guest call completion callback */ 67 struct VBOXHGCMCALLHANDLE_TYPEDEF 68 { 69 /** Where to store the result code */ 70 int32_t rc; 71 }; 72 73 /** Call completion callback for guest calls. */ 74 static void callComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc) 75 { 76 callHandle->rc = rc; 77 } 78 79 /** 80 * Initialise the HGCM service table as much as we need to start the 81 * service 82 * @param pTable the table to initialise 83 */ 84 void initTable(VBOXHGCMSVCFNTABLE *pTable, VBOXHGCMSVCHELPERS *pHelpers) 85 { 86 pTable->cbSize = sizeof (VBOXHGCMSVCFNTABLE); 87 pTable->u32Version = VBOX_HGCM_SVC_VERSION; 88 pHelpers->pfnCallComplete = callComplete; 89 pTable->pHelpers = pHelpers; 90 } 91 92 /** 93 * A list of valid flag strings for testConvertFlags. The flag conversion 94 * functions should accept these and convert them from string to a flag type 95 * and back without errors. 36 96 */ 37 97 struct flagStrings … … 44 104 validFlagStrings[] = 45 105 { 46 { " ", "" },106 { " ", "" }, 47 107 { "transient, ", "TRANSIENT" }, 48 { " rdOnLyHOST, transIENT , READONLY ", "TRANSIENT, READONLY" } 49 }; 50 108 { " rdOnLyHOST, transIENT , READONLY ", "TRANSIENT, READONLY" }, 109 { " rdonlyguest", "RDONLYGUEST" }, 110 { "rdonlyhost ", "RDONLYHOST" } 111 }; 112 113 /** 114 * A list of invalid flag strings for testConvertFlags. The flag conversion 115 * functions should reject these. 116 */ 117 const char *invalidFlagStrings[] = 118 { 119 "RDONLYHOST,,", 120 " TRANSIENT READONLY" 121 }; 122 123 /** 124 * Test the flag conversion functions. 125 * @returns iprt status value to indicate whether the test went as expected. 126 * @note prints its own diagnostic information to stdout. 127 */ 51 128 int testConvertFlags() 52 129 { … … 55 132 for (unsigned i = 0; i < RT_ELEMENTS(validFlagStrings) && RT_SUCCESS(rc); ++i) 56 133 { 57 char szFlagBuffer[MAX_FLAGS_LEN ];134 char szFlagBuffer[MAX_FLAGS_LEN * 2]; 58 135 uint32_t fFlags; 59 136 rc = validateFlags(validFlagStrings[i].pcszIn, &fFlags); 60 137 if (RT_FAILURE(rc)) 61 RTPrintf("tstGuestPropSvc: FAILURE - Failed to validate flag string %s.\n", validFlagStrings[i].pcszIn);138 RTPrintf("tstGuestPropSvc: FAILURE - Failed to validate flag string '%s'.\n", validFlagStrings[i].pcszIn); 62 139 if (RT_SUCCESS(rc)) 63 140 { 64 141 rc = writeFlags(fFlags, szFlagBuffer); 65 142 if (RT_FAILURE(rc)) 66 RTPrintf("tstGuestPropSvc: FAILURE - Failed to convert flag string %sback to a string.\n",143 RTPrintf("tstGuestPropSvc: FAILURE - Failed to convert flag string '%s' back to a string.\n", 67 144 validFlagStrings[i].pcszIn); 68 145 } 69 146 if (RT_SUCCESS(rc) && (strlen(szFlagBuffer) > MAX_FLAGS_LEN - 1)) 70 147 { 71 RTPrintf("tstGuestPropSvc: FAILURE - String %sconverts back to a flag string which is too long.\n",148 RTPrintf("tstGuestPropSvc: FAILURE - String '%s' converts back to a flag string which is too long.\n", 72 149 validFlagStrings[i].pcszIn); 73 150 rc = VERR_TOO_MUCH_DATA; … … 75 152 if (RT_SUCCESS(rc) && (strcmp(szFlagBuffer, validFlagStrings[i].pcszOut) != 0)) 76 153 { 77 RTPrintf("tstGuestPropSvc: FAILURE - String %s converts back to %s instead of to %s\n",154 RTPrintf("tstGuestPropSvc: FAILURE - String '%s' converts back to '%s' instead of to '%s'\n", 78 155 validFlagStrings[i].pcszIn, szFlagBuffer, 79 156 validFlagStrings[i].pcszOut); … … 81 158 } 82 159 } 160 if (RT_SUCCESS(rc)) 161 { 162 RTPrintf("Testing rejection of invalid flags strings.\n"); 163 for (unsigned i = 0; i < RT_ELEMENTS(invalidFlagStrings) && RT_SUCCESS(rc); ++i) 164 { 165 uint32_t fFlags; 166 /* This is required to fail. */ 167 if (RT_SUCCESS(validateFlags(invalidFlagStrings[i], &fFlags))) 168 { 169 RTPrintf("String '%s' was incorrectly accepted as a valid flag string.\n", 170 invalidFlagStrings[i]); 171 rc = VERR_PARSE_ERROR; 172 } 173 } 174 } 175 if (RT_SUCCESS(rc)) 176 { 177 char szFlagBuffer[MAX_FLAGS_LEN * 2]; 178 uint32_t u32BadFlags = ALLFLAGS << 1; 179 RTPrintf("Testing rejection of an invalid flags field.\n"); 180 /* This is required to fail. */ 181 if (RT_SUCCESS(writeFlags(u32BadFlags, szFlagBuffer))) 182 { 183 RTPrintf("Flags 0x%x were incorrectly written out as '%.*s'\n", 184 u32BadFlags, MAX_FLAGS_LEN, szFlagBuffer); 185 rc = VERR_PARSE_ERROR; 186 } 187 } 83 188 return rc; 84 189 } 85 190 191 /** 192 * List of property names for testSetPropsHost. 193 */ 194 const char *apcszNameBlock[] = 195 { 196 "test/name/", 197 "test name", 198 "TEST NAME", 199 "/test/name", 200 NULL 201 }; 202 203 /** 204 * List of property values for testSetPropsHost. 205 */ 206 const char *apcszValueBlock[] = 207 { 208 "test/value/", 209 "test value", 210 "TEST VALUE", 211 "/test/value", 212 NULL 213 }; 214 215 /** 216 * List of property timestamps for testSetPropsHost. 217 */ 218 uint64_t au64TimestampBlock[] = 219 { 220 0, 999, 999999, 999999999999, 0 221 }; 222 223 /** 224 * List of property flags for testSetPropsHost. 225 */ 226 const char *apcszFlagsBlock[] = 227 { 228 "", 229 "readonly, transient", 230 "RDONLYHOST", 231 "RdOnlyGuest", 232 NULL 233 }; 234 235 /** 236 * Test the SET_PROPS_HOST function. 237 * @returns iprt status value to indicate whether the test went as expected. 238 * @note prints its own diagnostic information to stdout. 239 */ 240 int testSetPropsHost(VBOXHGCMSVCFNTABLE *ptable) 241 { 242 int rc = VINF_SUCCESS; 243 RTPrintf("Testing the SET_PROPS_HOST call.\n"); 244 if (!VALID_PTR(ptable->pfnHostCall)) 245 { 246 RTPrintf("Invalid pfnHostCall() pointer\n"); 247 rc = VERR_INVALID_POINTER; 248 } 249 if (RT_SUCCESS(rc)) 250 { 251 VBOXHGCMSVCPARM paParms[4]; 252 VBoxHGCMParmPtrSet(&paParms[0], (void *) apcszNameBlock, 0); 253 VBoxHGCMParmPtrSet(&paParms[1], (void *) apcszValueBlock, 0); 254 VBoxHGCMParmPtrSet(&paParms[2], (void *) au64TimestampBlock, 0); 255 VBoxHGCMParmPtrSet(&paParms[3], (void *) apcszFlagsBlock, 0); 256 rc = ptable->pfnHostCall(ptable->pvService, SET_PROPS_HOST, 4, 257 paParms); 258 if (RT_FAILURE(rc)) 259 RTPrintf("SET_PROPS_HOST call failed with rc=%Rrc\n", rc); 260 } 261 return rc; 262 } 263 264 /** Result strings for zeroth enumeration test */ 265 static const char *pcchEnumResult0[] = 266 { 267 "test/name/\0test/value/\0""0\0", 268 "test name\0test value\0""999\0TRANSIENT, READONLY", 269 "TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST", 270 "/test/name\0/test/value\0""999999999999\0RDONLYGUEST", 271 NULL 272 }; 273 274 /** Result string sizes for zeroth enumeration test */ 275 static const size_t cchEnumResult0[] = 276 { 277 sizeof("test/name/\0test/value/\0""0\0"), 278 sizeof("test name\0test value\0""999\0TRANSIENT, READONLY"), 279 sizeof("TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST"), 280 sizeof("/test/name\0/test/value\0""999999999999\0RDONLYGUEST"), 281 0 282 }; 283 284 /** 285 * The size of the buffer returned by the zeroth enumeration test - 286 * the - 1 at the end is because of the hidden zero terminator 287 */ 288 static const size_t cchEnumBuffer0 = 289 sizeof("test/name/\0test/value/\0""0\0\0" 290 "test name\0test value\0""999\0TRANSIENT, READONLY\0" 291 "TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST\0" 292 "/test/name\0/test/value\0""999999999999\0RDONLYGUEST\0\0\0\0\0") - 1; 293 294 /** Result strings for first and second enumeration test */ 295 static const char *pcchEnumResult1[] = 296 { 297 "TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST", 298 "/test/name\0/test/value\0""999999999999\0RDONLYGUEST", 299 NULL 300 }; 301 302 /** Result string sizes for first and second enumeration test */ 303 static const size_t cchEnumResult1[] = 304 { 305 sizeof("TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST"), 306 sizeof("/test/name\0/test/value\0""999999999999\0RDONLYGUEST"), 307 0 308 }; 309 310 /** 311 * The size of the buffer returned by the first enumeration test - 312 * the - 1 at the end is because of the hidden zero terminator 313 */ 314 static const size_t cchEnumBuffer1 = 315 sizeof("TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST\0" 316 "/test/name\0/test/value\0""999999999999\0RDONLYGUEST\0\0\0\0\0") - 1; 317 318 static const struct enumStringStruct 319 { 320 /** The enumeration pattern to test */ 321 const char *pcszPatterns; 322 /** The size of the pattern string */ 323 const size_t cchPatterns; 324 /** The expected enumeration output strings */ 325 const char **ppcchResult; 326 /** The size of the output strings */ 327 const size_t *pcchResult; 328 /** The size of the buffer needed for the enumeration */ 329 const size_t cchBuffer; 330 } 331 enumStrings[] = 332 { 333 { 334 "", sizeof(""), 335 pcchEnumResult0, 336 cchEnumResult0, 337 cchEnumBuffer0 338 }, 339 { 340 "/*\0?E*", sizeof("/*\0?E*"), 341 pcchEnumResult1, 342 cchEnumResult1, 343 cchEnumBuffer1 344 }, 345 { 346 "/*|?E*", sizeof("/*|?E*"), 347 pcchEnumResult1, 348 cchEnumResult1, 349 cchEnumBuffer1 350 } 351 }; 352 353 /** 354 * Test the ENUM_PROPS_HOST function. 355 * @returns iprt status value to indicate whether the test went as expected. 356 * @note prints its own diagnostic information to stdout. 357 */ 358 int testEnumPropsHost(VBOXHGCMSVCFNTABLE *ptable) 359 { 360 int rc = VINF_SUCCESS; 361 RTPrintf("Testing the ENUM_PROPS_HOST call.\n"); 362 if (!VALID_PTR(ptable->pfnHostCall)) 363 { 364 RTPrintf("Invalid pfnHostCall() pointer\n"); 365 rc = VERR_INVALID_POINTER; 366 } 367 for (unsigned i = 0; RT_SUCCESS(rc) && i < RT_ELEMENTS(enumStrings); 368 ++i) 369 { 370 char buffer[2048]; 371 VBOXHGCMSVCPARM paParms[3]; 372 VBoxHGCMParmPtrSet(&paParms[0], 373 (void *) enumStrings[i].pcszPatterns, 374 enumStrings[i].cchPatterns); 375 VBoxHGCMParmPtrSet(&paParms[1], 376 (void *) buffer, 377 enumStrings[i].cchBuffer - 1); 378 AssertBreakStmt(sizeof(buffer) > enumStrings[i].cchBuffer, 379 rc = VERR_INTERNAL_ERROR); 380 if (RT_SUCCESS(rc)) 381 { 382 /* This should fail as the buffer is too small. */ 383 int rc2 = ptable->pfnHostCall(ptable->pvService, ENUM_PROPS_HOST, 384 3, paParms); 385 if (rc2 != VERR_BUFFER_OVERFLOW) 386 { 387 RTPrintf("ENUM_PROPS_HOST returned %Rrc instead of VERR_BUFFER_OVERFLOW on too small buffer, pattern number %d\n", rc2, i); 388 rc = VERR_BUFFER_OVERFLOW; 389 } 390 else 391 { 392 uint32_t cchBufferActual; 393 rc = VBoxHGCMParmUInt32Get(&paParms[2], &cchBufferActual); 394 if (RT_SUCCESS(rc) && cchBufferActual != enumStrings[i].cchBuffer) 395 { 396 RTPrintf("ENUM_PROPS_HOST requested a buffer size of %lu instead of %lu for pattern number %d\n", cchBufferActual, enumStrings[i].cchBuffer, i); 397 rc = VERR_OUT_OF_RANGE; 398 } 399 else if (RT_FAILURE(rc)) 400 RTPrintf("ENUM_PROPS_HOST did not return the required buffer size properly for pattern %d\n", i); 401 } 402 } 403 if (RT_SUCCESS(rc)) 404 { 405 VBoxHGCMParmPtrSet(&paParms[1], (void *) buffer, 406 enumStrings[i].cchBuffer); 407 rc = ptable->pfnHostCall(ptable->pvService, ENUM_PROPS_HOST, 408 3, paParms); 409 if (RT_FAILURE(rc)) 410 RTPrintf("ENUM_PROPS_HOST call failed for pattern %d with rc=%Rrc\n", i, rc); 411 else 412 /* Look for each of the result strings in the buffer which was returned */ 413 for (unsigned j = 0; RT_SUCCESS(rc) && enumStrings[i].ppcchResult[j] != NULL; 414 ++j) 415 { 416 bool found = false; 417 for (unsigned k = 0; !found && k < enumStrings[i].cchBuffer 418 - enumStrings[i].pcchResult[j]; 419 ++k) 420 if (memcmp(buffer + k, enumStrings[i].ppcchResult[j], 421 enumStrings[i].pcchResult[j]) == 0) 422 found = true; 423 if (!found) 424 { 425 RTPrintf("ENUM_PROPS_HOST did not produce the expected output for pattern %d\n", 426 i); 427 rc = VERR_UNRESOLVED_ERROR; 428 } 429 } 430 } 431 } 432 return rc; 433 } 434 435 /** Array of properties for testing SET_PROP_HOST and _GUEST. */ 436 static const struct 437 { 438 /** Property name */ 439 const char *pcszName; 440 /** Property value */ 441 const char *pcszValue; 442 /** Property flags */ 443 const char *pcszFlags; 444 /** Should this be set as the host or the guest? */ 445 bool isHost; 446 /** Should we use SET_PROP or SET_PROP_VALUE? */ 447 bool useSetProp; 448 /** Should this succeed or be rejected with VERR_PERMISSION_DENIED? */ 449 bool isAllowed; 450 } 451 setProperties[] = 452 { 453 { "Red", "Stop!", "transient", false, true, true }, 454 { "Amber", "Caution!", "", false, false, true }, 455 { "Green", "Go!", "readonly", true, true, true }, 456 { "Blue", "What on earth...?", "", true, false, true }, 457 { "/test/name", "test", "", false, true, false }, 458 { "TEST NAME", "test", "", true, true, false }, 459 { "Green", "gone out...", "", false, false, false }, 460 { "Green", "gone out...", "", true, false, false }, 461 { NULL, NULL, NULL, false, false, false } 462 }; 463 464 /** 465 * Test the SET_PROP, SET_PROP_VALUE, SET_PROP_HOST and SET_PROP_VALUE_HOST 466 * functions. 467 * @returns iprt status value to indicate whether the test went as expected. 468 * @note prints its own diagnostic information to stdout. 469 */ 470 int testSetProp(VBOXHGCMSVCFNTABLE *pTable) 471 { 472 int rc = VINF_SUCCESS; 473 VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS }; 474 RTPrintf("Testing the SET_PROP, SET_PROP_VALUE, SET_PROP_HOST and SET_PROP_VALUE_HOST calls.\n"); 475 for (unsigned i = 0; RT_SUCCESS(rc) && (setProperties[i].pcszName != NULL); 476 ++i) 477 { 478 int command = SET_PROP_VALUE; 479 if (setProperties[i].isHost) 480 { 481 if (setProperties[i].useSetProp) 482 command = SET_PROP_HOST; 483 else 484 command = SET_PROP_VALUE_HOST; 485 } 486 else if (setProperties[i].useSetProp) 487 command = SET_PROP; 488 VBOXHGCMSVCPARM paParms[3]; 489 /* Work around silly constant issues - we ought to allow passing 490 * constant strings in the hgcm parameters. */ 491 char szName[MAX_NAME_LEN] = ""; 492 char szValue[MAX_VALUE_LEN] = ""; 493 char szFlags[MAX_FLAGS_LEN] = ""; 494 strncat(szName, setProperties[i].pcszName, sizeof(szName)); 495 strncat(szValue, setProperties[i].pcszValue, sizeof(szValue)); 496 strncat(szFlags, setProperties[i].pcszFlags, sizeof(szFlags)); 497 VBoxHGCMParmPtrSet(&paParms[0], szName, strlen(szName) + 1); 498 VBoxHGCMParmPtrSet(&paParms[1], szValue, strlen(szValue) + 1); 499 VBoxHGCMParmPtrSet(&paParms[2], szFlags, strlen(szFlags) + 1); 500 if (setProperties[i].isHost) 501 callHandle.rc = pTable->pfnHostCall(pTable->pvService, command, 502 setProperties[i].useSetProp 503 ? 3 : 2, paParms); 504 else 505 pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, command, 506 setProperties[i].useSetProp ? 3 : 2, paParms); 507 if (setProperties[i].isAllowed && RT_FAILURE(callHandle.rc)) 508 { 509 RTPrintf("Setting property '%s' failed with rc=%Rrc.\n", 510 setProperties[i].pcszName, callHandle.rc); 511 rc = callHandle.rc; 512 } 513 else if ( !setProperties[i].isAllowed 514 && (callHandle.rc != VERR_PERMISSION_DENIED) 515 ) 516 { 517 RTPrintf("Setting property '%s' returned %Rrc instead of VERR_PERMISSION_DENIED.\n", 518 setProperties[i].pcszName, callHandle.rc); 519 rc = VERR_UNRESOLVED_ERROR; 520 } 521 } 522 return rc; 523 } 524 525 /** Array of properties for testing DEL_PROP_HOST and _GUEST. */ 526 static const struct 527 { 528 /** Property name */ 529 const char *pcszName; 530 /** Should this be set as the host or the guest? */ 531 bool isHost; 532 /** Should this succeed or be rejected with VERR_PERMISSION_DENIED? */ 533 bool isAllowed; 534 } 535 delProperties[] = 536 { 537 { "Red", false, true }, 538 { "Amber", true, true }, 539 { "Red2", false, true }, 540 { "Amber2", true, true }, 541 { "Green", false, false }, 542 { "Green", true, false }, 543 { "/test/name", false, false }, 544 { "TEST NAME", true, false }, 545 { NULL, false, false } 546 }; 547 548 /** 549 * Test the DEL_PROP, and DEL_PROP_HOST functions. 550 * @returns iprt status value to indicate whether the test went as expected. 551 * @note prints its own diagnostic information to stdout. 552 */ 553 int testDelProp(VBOXHGCMSVCFNTABLE *pTable) 554 { 555 int rc = VINF_SUCCESS; 556 VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS }; 557 RTPrintf("Testing the DEL_PROP and DEL_PROP_HOST calls.\n"); 558 for (unsigned i = 0; RT_SUCCESS(rc) && (delProperties[i].pcszName != NULL); 559 ++i) 560 { 561 int command = DEL_PROP; 562 if (delProperties[i].isHost) 563 command = DEL_PROP_HOST; 564 VBOXHGCMSVCPARM paParms[1]; 565 /* Work around silly constant issues - we ought to allow passing 566 * constant strings in the hgcm parameters. */ 567 char szName[MAX_NAME_LEN] = ""; 568 strncat(szName, delProperties[i].pcszName, sizeof(szName)); 569 VBoxHGCMParmPtrSet(&paParms[0], szName, strlen(szName) + 1); 570 if (delProperties[i].isHost) 571 callHandle.rc = pTable->pfnHostCall(pTable->pvService, command, 572 1, paParms); 573 else 574 pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, command, 575 1, paParms); 576 if (delProperties[i].isAllowed && RT_FAILURE(callHandle.rc)) 577 { 578 RTPrintf("Deleting property '%s' failed with rc=%Rrc.\n", 579 delProperties[i].pcszName, callHandle.rc); 580 rc = callHandle.rc; 581 } 582 else if ( !delProperties[i].isAllowed 583 && (callHandle.rc != VERR_PERMISSION_DENIED) 584 ) 585 { 586 RTPrintf("Deleting property '%s' returned %Rrc instead of VERR_PERMISSION_DENIED.\n", 587 delProperties[i].pcszName, callHandle.rc); 588 rc = VERR_UNRESOLVED_ERROR; 589 } 590 } 591 return rc; 592 } 593 594 /** Array of properties for testing GET_PROP_HOST. */ 595 static const struct 596 { 597 /** Property name */ 598 const char *pcszName; 599 /** What value/flags pattern do we expect back? */ 600 const char *pcchValue; 601 /** What size should the value/flags array be? */ 602 uint32_t cchValue; 603 /** Should this proeprty exist? */ 604 bool exists; 605 /** Do we expect a particular timestamp? */ 606 bool hasTimestamp; 607 /** What timestamp if any do ex expect? */ 608 uint64_t u64Timestamp; 609 } 610 getProperties[] = 611 { 612 { "test/name/", "test/value/\0", sizeof("test/value/\0"), true, true, 0 }, 613 { "test name", "test value\0TRANSIENT, READONLY", 614 sizeof("test value\0TRANSIENT, READONLY"), true, true, 999 }, 615 { "TEST NAME", "TEST VALUE\0RDONLYHOST", sizeof("TEST VALUE\0RDONLYHOST"), 616 true, true, 999999 }, 617 { "/test/name", "/test/value\0RDONLYGUEST", 618 sizeof("/test/value\0RDONLYGUEST"), true, true, 999999999999 }, 619 { "Green", "Go!\0READONLY", sizeof("Go!\0READONLY"), true, false, 0 }, 620 { "Blue", "What on earth...?\0", sizeof("What on earth...?\0"), true, 621 false, 0 }, 622 { "Red", "", 0, false, false, 0 }, 623 { NULL, NULL, 0, false, false, 0 } 624 }; 625 626 /** 627 * Test the GET_PROP_HOST function. 628 * @returns iprt status value to indicate whether the test went as expected. 629 * @note prints its own diagnostic information to stdout. 630 */ 631 int testGetProp(VBOXHGCMSVCFNTABLE *pTable) 632 { 633 int rc = VINF_SUCCESS, rc2 = VINF_SUCCESS; 634 RTPrintf("Testing the GET_PROP_HOST call.\n"); 635 for (unsigned i = 0; RT_SUCCESS(rc) && (getProperties[i].pcszName != NULL); 636 ++i) 637 { 638 VBOXHGCMSVCPARM paParms[4]; 639 /* Work around silly constant issues - we ought to allow passing 640 * constant strings in the hgcm parameters. */ 641 char szName[MAX_NAME_LEN] = ""; 642 char szBuffer[MAX_VALUE_LEN + MAX_FLAGS_LEN]; 643 AssertBreakStmt(sizeof(szBuffer) >= getProperties[i].cchValue, 644 rc = VERR_INTERNAL_ERROR); 645 strncat(szName, getProperties[i].pcszName, sizeof(szName)); 646 VBoxHGCMParmPtrSet(&paParms[0], szName, strlen(szName) + 1); 647 VBoxHGCMParmPtrSet(&paParms[1], szBuffer, sizeof(szBuffer)); 648 rc2 = pTable->pfnHostCall(pTable->pvService, GET_PROP_HOST, 4, 649 paParms); 650 if (getProperties[i].exists && RT_FAILURE(rc2)) 651 { 652 RTPrintf("Getting property '%s' failed with rc=%Rrc.\n", 653 getProperties[i].pcszName, rc2); 654 rc = rc2; 655 } 656 else if (!getProperties[i].exists && (rc2 != VERR_NOT_FOUND)) 657 { 658 RTPrintf("Getting property '%s' returned %Rrc instead of VERR_NOT_FOUND.\n", 659 getProperties[i].pcszName, rc2); 660 rc = VERR_UNRESOLVED_ERROR; 661 } 662 if (RT_SUCCESS(rc) && getProperties[i].exists) 663 { 664 uint32_t u32ValueLen; 665 rc = VBoxHGCMParmUInt32Get(&paParms[3], &u32ValueLen); 666 if (RT_FAILURE(rc)) 667 RTPrintf("Failed to get the size of the output buffer for property '%s'\n", 668 getProperties[i].pcszName); 669 if ( RT_SUCCESS(rc) 670 && (memcmp(szBuffer, getProperties[i].pcchValue, 671 getProperties[i].cchValue) != 0) 672 ) 673 { 674 RTPrintf("Unexpected result '%.*s' for property '%s', expected '%.*s'.\n", 675 u32ValueLen, szBuffer, getProperties[i].pcszName, 676 getProperties[i].cchValue, getProperties[i].pcchValue); 677 rc = VERR_UNRESOLVED_ERROR; 678 } 679 if (RT_SUCCESS(rc) && getProperties[i].hasTimestamp) 680 { 681 uint64_t u64Timestamp; 682 rc = VBoxHGCMParmUInt64Get(&paParms[2], &u64Timestamp); 683 if (RT_FAILURE(rc)) 684 RTPrintf("Failed to get the timestamp for property '%s'\n", 685 getProperties[i].pcszName); 686 if ( RT_SUCCESS(rc) 687 && (u64Timestamp != getProperties[i].u64Timestamp) 688 ) 689 { 690 RTPrintf("Bad timestamp %llu for property '%s', expected %llu.\n", 691 u64Timestamp, getProperties[i].pcszName, 692 getProperties[i].u64Timestamp); 693 rc = VERR_UNRESOLVED_ERROR; 694 } 695 } 696 } 697 } 698 return rc; 699 } 700 86 701 int main(int argc, char **argv) 87 702 { 703 VBOXHGCMSVCFNTABLE svcTable; 704 VBOXHGCMSVCHELPERS svcHelpers; 705 initTable(&svcTable, &svcHelpers); 88 706 RTR3Init(); 89 707 if (RT_FAILURE(testConvertFlags())) 90 708 return 1; 709 /* The function is inside the service, not HGCM. */ 710 if (RT_FAILURE(VBoxHGCMSvcLoad(&svcTable))) 711 { 712 RTPrintf("Failed to start HGCM service.\n"); 713 return 1; 714 } 715 if (RT_FAILURE(testSetPropsHost(&svcTable))) 716 return 1; 717 if (RT_FAILURE(testEnumPropsHost(&svcTable))) 718 return 1; 719 if (RT_FAILURE(testSetProp(&svcTable))) 720 return 1; 721 if (RT_FAILURE(testDelProp(&svcTable))) 722 return 1; 723 if (RT_FAILURE(testGetProp(&svcTable))) 724 return 1; 91 725 RTPrintf("tstGuestPropSvc: SUCCEEDED.\n"); 92 726 return 0; 93 727 } 94 -
trunk/src/VBox/Main/ConsoleImpl.cpp
r13755 r13759 96 96 #include <algorithm> 97 97 #include <memory> // for auto_ptr 98 #include <vector> 98 99 99 100 … … 1062 1063 rc = VERR_UNRESOLVED_ERROR; /** @todo translate error code */ 1063 1064 return rc; 1065 } 1066 1067 HRESULT Console::doEnumerateGuestProperties (INPTR BSTR aPatterns, 1068 ComSafeArrayOut(BSTR, aNames), 1069 ComSafeArrayOut(BSTR, aValues), 1070 ComSafeArrayOut(ULONG64, aTimestamps), 1071 ComSafeArrayOut(BSTR, aFlags)) 1072 { 1073 using namespace guestProp; 1074 1075 VBOXHGCMSVCPARM parm[3]; 1076 1077 Utf8Str utf8Patterns(aPatterns); 1078 parm[0].type = VBOX_HGCM_SVC_PARM_PTR; 1079 parm[0].u.pointer.addr = utf8Patterns.mutableRaw(); 1080 parm[0].u.pointer.size = utf8Patterns.length() + 1; 1081 1082 /* 1083 * Now things get slightly complicated. Due to a race with the guest adding 1084 * properties, there is no good way to know how much large a buffer to provide 1085 * the service to enumerate into. We choose a decent starting size and loop a 1086 * few times, each time retrying with the size suggested by the service plus 1087 * one Kb. 1088 */ 1089 size_t cchBuf = 4096; 1090 Utf8Str Utf8Buf; 1091 int vrc = VERR_BUFFER_OVERFLOW; 1092 for (unsigned i = 0; i < 10 && (VERR_BUFFER_OVERFLOW == vrc); ++i) 1093 { 1094 Utf8Buf.alloc(cchBuf + 1024); 1095 if (Utf8Buf.isNull()) 1096 return E_OUTOFMEMORY; 1097 parm[1].type = VBOX_HGCM_SVC_PARM_PTR; 1098 parm[1].u.pointer.addr = Utf8Buf.mutableRaw(); 1099 parm[1].u.pointer.size = cchBuf + 1024; 1100 vrc = mVMMDev->hgcmHostCall ("VBoxGuestPropSvc", ENUM_PROPS_HOST, 3, 1101 &parm[0]); 1102 if (parm[2].type != VBOX_HGCM_SVC_PARM_32BIT) 1103 return setError (E_FAIL, tr ("Internal application error")); 1104 cchBuf = parm[2].u.uint32; 1105 } 1106 if (VERR_BUFFER_OVERFLOW == vrc) 1107 return setError (E_UNEXPECTED, tr ("Temporary failure due to guest activity, please retry")); 1108 1109 /* 1110 * Finally we have to unpack the data returned by the service into the safe 1111 * arrays supplied by the caller. We start by counting the number of entries. 1112 */ 1113 const char *pszBuf 1114 = reinterpret_cast<const char *>(parm[1].u.pointer.addr); 1115 unsigned cEntries = 0; 1116 /* The list is terminated by a zero-length string at the end of a set 1117 * of four strings. */ 1118 for (size_t i = 0; strlen(pszBuf + i) != 0; ) 1119 { 1120 /* We are counting sets of four strings. */ 1121 for (unsigned j = 0; j < 4; ++j) 1122 i += strlen(pszBuf + i) + 1; 1123 ++cEntries; 1124 } 1125 1126 /* 1127 * And now we create the COM safe arrays and fill them in. 1128 */ 1129 com::SafeArray <BSTR> names(cEntries); 1130 com::SafeArray <BSTR> values(cEntries); 1131 com::SafeArray <ULONG64> timestamps(cEntries); 1132 com::SafeArray <BSTR> flags(cEntries); 1133 size_t iBuf = 0; 1134 /* Rely on the service to have formated the data correctly. */ 1135 for (unsigned i = 0; i < cEntries; ++i) 1136 { 1137 size_t cchName = strlen(pszBuf + iBuf); 1138 Bstr(pszBuf + iBuf).detachTo(&names[i]); 1139 iBuf += cchName + 1; 1140 size_t cchValue = strlen(pszBuf + iBuf); 1141 Bstr(pszBuf + iBuf).detachTo(&values[i]); 1142 iBuf += cchValue + 1; 1143 size_t cchTimestamp = strlen(pszBuf + iBuf); 1144 timestamps[i] = RTStrToUInt64(pszBuf + iBuf); 1145 iBuf += cchTimestamp + 1; 1146 size_t cchFlags = strlen(pszBuf + iBuf); 1147 Bstr(pszBuf + iBuf).detachTo(&flags[i]); 1148 iBuf += cchFlags + 1; 1149 } 1150 names.detachTo(ComSafeArrayOutArg (aNames)); 1151 values.detachTo(ComSafeArrayOutArg (aValues)); 1152 timestamps.detachTo(ComSafeArrayOutArg (aTimestamps)); 1153 flags.detachTo(ComSafeArrayOutArg (aFlags)); 1154 return S_OK; 1064 1155 } 1065 1156 #endif … … 3687 3778 * autoVMCaller, so there is no need to hold a lock of this */ 3688 3779 3689 using namespace guestProp; 3690 3691 VBOXHGCMSVCPARM parm[3]; 3692 3693 Utf8Str utf8Patterns(aPatterns); 3694 parm[0].type = VBOX_HGCM_SVC_PARM_PTR; 3695 parm[0].u.pointer.addr = utf8Patterns.mutableRaw(); 3696 parm[0].u.pointer.size = utf8Patterns.length() + 1; 3697 3698 /* 3699 * Now things get slightly complicated. Due to a race with the guest adding 3700 * properties, there is no good way to know how much large a buffer to provide 3701 * the service to enumerate into. We choose a decent starting size and loop a 3702 * few times, each time retrying with the size suggested by the service plus 3703 * one Kb. 3704 */ 3705 size_t cchBuf = 4096; 3706 Utf8Str Utf8Buf; 3707 int vrc = VERR_BUFFER_OVERFLOW; 3708 for (unsigned i = 0; i < 10 && (VERR_BUFFER_OVERFLOW == vrc); ++i) 3709 { 3710 Utf8Buf.alloc(cchBuf + 1024); 3711 if (Utf8Buf.isNull()) 3712 return E_OUTOFMEMORY; 3713 parm[1].type = VBOX_HGCM_SVC_PARM_PTR; 3714 parm[1].u.pointer.addr = Utf8Buf.mutableRaw(); 3715 parm[1].u.pointer.size = cchBuf + 1024; 3716 vrc = mVMMDev->hgcmHostCall ("VBoxGuestPropSvc", ENUM_PROPS_HOST, 3, 3717 &parm[0]); 3718 if (parm[2].type != VBOX_HGCM_SVC_PARM_32BIT) 3719 return setError (E_FAIL, tr ("Internal application error")); 3720 cchBuf = parm[2].u.uint32; 3721 } 3722 if (VERR_BUFFER_OVERFLOW == vrc) 3723 return setError (E_UNEXPECTED, tr ("Temporary failure due to guest activity, please retry")); 3724 3725 /* 3726 * Finally we have to unpack the data returned by the service into the safe 3727 * arrays supplied by the caller. We start by counting the number of entries. 3728 */ 3729 const char *pszBuf 3730 = reinterpret_cast<const char *>(parm[1].u.pointer.addr); 3731 unsigned cEntries = 0; 3732 /* The list is terminated by a zero-length string at the end of a set 3733 * of four strings. */ 3734 for (size_t i = 0; strlen(pszBuf + i) != 0; ) 3735 { 3736 /* We are counting sets of four strings. */ 3737 for (unsigned j = 0; j < 4; ++j) 3738 i += strlen(pszBuf + i) + 1; 3739 ++cEntries; 3740 } 3741 3742 /* 3743 * And now we create the COM safe arrays and fill them in. 3744 */ 3745 com::SafeArray <BSTR> names(cEntries); 3746 com::SafeArray <BSTR> values(cEntries); 3747 com::SafeArray <ULONG64> timestamps(cEntries); 3748 com::SafeArray <BSTR> flags(cEntries); 3749 size_t iBuf = 0; 3750 /* Rely on the service to have formated the data correctly. */ 3751 for (unsigned i = 0; i < cEntries; ++i) 3752 { 3753 size_t cchName = strlen(pszBuf + iBuf); 3754 Bstr(pszBuf + iBuf).detachTo(&names[i]); 3755 iBuf += cchName + 1; 3756 size_t cchValue = strlen(pszBuf + iBuf); 3757 Bstr(pszBuf + iBuf).detachTo(&values[i]); 3758 iBuf += cchValue + 1; 3759 size_t cchTimestamp = strlen(pszBuf + iBuf); 3760 timestamps[i] = RTStrToUInt64(pszBuf + iBuf); 3761 iBuf += cchTimestamp + 1; 3762 size_t cchFlags = strlen(pszBuf + iBuf); 3763 Bstr(pszBuf + iBuf).detachTo(&flags[i]); 3764 iBuf += cchFlags + 1; 3765 } 3766 names.detachTo(ComSafeArrayOutArg (aNames)); 3767 values.detachTo(ComSafeArrayOutArg (aValues)); 3768 timestamps.detachTo(ComSafeArrayOutArg (aTimestamps)); 3769 flags.detachTo(ComSafeArrayOutArg (aFlags)); 3770 return S_OK; 3780 return doEnumerateGuestProperties (aPatterns, ComSafeArrayOutArg(aNames), 3781 ComSafeArrayOutArg(aValues), 3782 ComSafeArrayOutArg(aTimestamps), 3783 ComSafeArrayOutArg(aFlags)); 3771 3784 #endif /* else !defined (VBOX_WITH_GUEST_PROPS) */ 3772 3785 } … … 4633 4646 #ifdef VBOX_WITH_HGCM 4634 4647 4648 # ifdef VBOX_WITH_GUEST_PROPS 4649 4650 /* Save all guest property store entries to the machine XML file */ 4651 com::SafeArray <BSTR> namesOut; 4652 com::SafeArray <BSTR> valuesOut; 4653 com::SafeArray <ULONG64> timestampsOut; 4654 com::SafeArray <BSTR> flagsOut; 4655 Bstr pattern(""); 4656 if (pattern.isNull()) 4657 rc = E_OUTOFMEMORY; 4658 else 4659 rc = doEnumerateGuestProperties (Bstr (""), ComSafeArrayAsOutParam (namesOut), 4660 ComSafeArrayAsOutParam (valuesOut), 4661 ComSafeArrayAsOutParam (timestampsOut), 4662 ComSafeArrayAsOutParam (flagsOut)); 4663 if (SUCCEEDED(rc)) 4664 { 4665 try 4666 { 4667 std::vector <BSTR> names; 4668 std::vector <BSTR> values; 4669 std::vector <ULONG64> timestamps; 4670 std::vector <BSTR> flags; 4671 for (unsigned i = 0; i < namesOut.size(); ++i) 4672 { 4673 uint32_t fFlags; 4674 guestProp::validateFlags (Utf8Str(flagsOut[i]).raw(), &fFlags); 4675 if ( !( fFlags & guestProp::TRANSIENT) 4676 || (mMachineState == MachineState_Saving) 4677 ) 4678 { 4679 names.push_back(namesOut[i]); 4680 values.push_back(valuesOut[i]); 4681 timestamps.push_back(timestampsOut[i]); 4682 flags.push_back(flagsOut[i]); 4683 } 4684 } 4685 com::SafeArray <BSTR> namesIn (names); 4686 com::SafeArray <BSTR> valuesIn (values); 4687 com::SafeArray <ULONG64> timestampsIn (timestamps); 4688 com::SafeArray <BSTR> flagsIn (flags); 4689 if ( namesIn.isNull() 4690 || valuesIn.isNull() 4691 || timestampsIn.isNull() 4692 || flagsIn.isNull() 4693 ) 4694 throw std::bad_alloc(); 4695 /* PushGuestProperties() calls DiscardSettings(), which calls us back */ 4696 alock.leave(); 4697 mControl->PushGuestProperties (ComSafeArrayAsInParam (namesIn), 4698 ComSafeArrayAsInParam (valuesIn), 4699 ComSafeArrayAsInParam (timestampsIn), 4700 ComSafeArrayAsInParam (flagsIn)); 4701 alock.enter(); 4702 } 4703 catch (std::bad_alloc) 4704 { 4705 rc = E_OUTOFMEMORY; 4706 } 4707 } 4708 4709 /* advance percent count */ 4710 if (aProgress) 4711 aProgress->notifyProgress (99 * (++ step) / StepCount ); 4712 4713 # endif /* VBOX_WITH_GUEST_PROPS defined */ 4714 4635 4715 /* Shutdown HGCM services before stopping the guest, because they might 4636 4716 * need a cleanup. */ … … 4650 4730 if (aProgress) 4651 4731 aProgress->notifyProgress (99 * (++ step) / StepCount ); 4652 4653 # ifdef VBOX_WITH_GUEST_PROPS4654 4655 /* Save all guest property store entries to the machine XML file */4656 PCFGMNODE pValues = CFGMR3GetChild (CFGMR3GetRoot (mpVM), "GuestProps/Values/");4657 PCFGMNODE pTimestamps = CFGMR3GetChild (CFGMR3GetRoot (mpVM), "GuestProps/Timestamps/");4658 PCFGMNODE pFlags = CFGMR3GetChild (CFGMR3GetRoot (mpVM), "GuestProps/Flags/");4659 4660 /* Count the number of entries we have */4661 unsigned cValues = 0;4662 PCFGMLEAF pValue;4663 for (pValue = CFGMR3GetFirstValue (pValues); pValue != NULL;4664 pValue = CFGMR3GetNextValue (pValue))4665 {4666 char szPropName[guestProp::MAX_NAME_LEN];4667 vrc = CFGMR3GetValueName (pValue, szPropName, sizeof(szPropName));4668 if (RT_SUCCESS(vrc))4669 {4670 /* Do not send transient properties unless we are saving state */4671 uint32_t fFlags = guestProp::NILFLAG;4672 CFGMR3QueryU32 (pFlags, szPropName, &fFlags);4673 if (!(fFlags & guestProp::TRANSIENT) ||4674 (mMachineState == MachineState_Saving))4675 ++cValues;4676 }4677 }4678 4679 /* And pack them into safe arrays */4680 com::SafeArray <BSTR> names(cValues);4681 com::SafeArray <BSTR> values(cValues);4682 com::SafeArray <ULONG64> timestamps(cValues);4683 com::SafeArray <BSTR> flags(cValues);4684 pValue = CFGMR3GetFirstValue (pValues);4685 4686 vrc = VINF_SUCCESS;4687 unsigned iProp = 0;4688 while (pValue != NULL && RT_SUCCESS (vrc))4689 {4690 using namespace guestProp;4691 4692 char szPropName [MAX_NAME_LEN];4693 char szPropValue [MAX_VALUE_LEN];4694 char szPropFlags [MAX_FLAGS_LEN];4695 ULONG64 u64Timestamp = 0; /* default */4696 vrc = CFGMR3GetValueName (pValue, szPropName, sizeof (szPropName));4697 if (RT_SUCCESS(vrc))4698 vrc = CFGMR3QueryString (pValues, szPropName, szPropValue,4699 sizeof (szPropValue));4700 if (RT_SUCCESS(vrc))4701 {4702 uint32_t fFlags = NILFLAG;4703 CFGMR3QueryU32 (pFlags, szPropName, &fFlags);4704 /* Skip transient properties unless we are saving state */4705 if (!(fFlags & TRANSIENT) ||4706 (mMachineState == MachineState_Saving))4707 {4708 writeFlags(fFlags, szPropFlags);4709 CFGMR3QueryU64 (pTimestamps, szPropName, &u64Timestamp);4710 Bstr(szPropName).cloneTo(&names[iProp]);4711 Bstr(szPropValue).cloneTo(&values[iProp]);4712 timestamps[iProp] = u64Timestamp;4713 Bstr(szPropFlags).cloneTo(&flags[iProp]);4714 ++iProp;4715 if (iProp >= cValues)4716 vrc = VERR_TOO_MUCH_DATA;4717 }4718 pValue = CFGMR3GetNextValue (pValue);4719 }4720 }4721 4722 if (RT_SUCCESS(vrc) || (VERR_TOO_MUCH_DATA == vrc))4723 {4724 /* PushGuestProperties() calls DiscardSettings(), which calls us back */4725 alock.leave();4726 mControl->PushGuestProperties (ComSafeArrayAsInParam (names),4727 ComSafeArrayAsInParam (values),4728 ComSafeArrayAsInParam (timestamps),4729 ComSafeArrayAsInParam (flags));4730 alock.enter();4731 }4732 4733 /* advance percent count */4734 if (aProgress)4735 aProgress->notifyProgress (99 * (++ step) / StepCount );4736 4737 # endif /* VBOX_WITH_GUEST_PROPS defined */4738 4732 4739 4733 #endif /* VBOX_WITH_HGCM */ -
trunk/src/VBox/Main/ConsoleImpl2.cpp
r13722 r13759 51 51 # include <hgcm/HGCM.h> /** @todo it should be possible to register a service 52 52 * extension using a VMMDev callback. */ 53 # include <vector> 53 54 #endif /* VBOX_WITH_GUEST_PROPS */ 54 55 #include <VBox/intnet.h> … … 269 270 PCFGMNODE pSataInst = NULL; /* /Devices/ahci/0/ */ 270 271 PCFGMNODE pBiosCfg = NULL; /* /Devices/pcbios/0/Config/ */ 271 #ifdef VBOX_WITH_GUEST_PROPS272 PCFGMNODE pGuestProps = NULL; /* /GuestProps */273 PCFGMNODE pValues = NULL; /* /GuestProps/Values */274 PCFGMNODE pTimestamps = NULL; /* /GuestProps/Timestamps */275 PCFGMNODE pFlags = NULL; /* /GuestProps/Flags */276 #endif /* VBOX_WITH_GUEST_PROPS defined */277 272 278 273 rc = CFGMR3InsertNode(pRoot, "Devices", &pDevices); RC_CHECK(); … … 1729 1724 #ifdef VBOX_WITH_GUEST_PROPS 1730 1725 /* 1731 * Shared information services1726 * Guest property service 1732 1727 */ 1733 1728 { … … 1743 1738 else 1744 1739 { 1745 rc = CFGMR3InsertNode(pRoot, "GuestProps", &pGuestProps); RC_CHECK();1746 rc = CFGMR3InsertNode(pGuestProps, "Values", &pValues); RC_CHECK();1747 rc = CFGMR3InsertNode(pGuestProps, "Timestamps", &pTimestamps); RC_CHECK();1748 rc = CFGMR3InsertNode(pGuestProps, "Flags", &pFlags); RC_CHECK();1749 1750 1740 /* Pull over the properties from the server. */ 1751 SafeArray <BSTR> names; 1752 SafeArray <BSTR> values; 1753 SafeArray <ULONG64> timestamps; 1754 SafeArray <BSTR> flags; 1755 hrc = pConsole->mControl->PullGuestProperties(ComSafeArrayAsOutParam(names), 1756 ComSafeArrayAsOutParam(values), 1757 ComSafeArrayAsOutParam(timestamps), 1758 ComSafeArrayAsOutParam(flags)); H(); 1759 size_t cProps = names.size(); 1760 for (size_t i = 0; i < cProps; ++i) 1761 { 1762 rc = CFGMR3InsertString(pValues, Utf8Str(names[i]).raw(), Utf8Str(values[i]).raw()); RC_CHECK(); 1763 rc = CFGMR3InsertInteger(pTimestamps, Utf8Str(names[i]).raw(), timestamps[i]); RC_CHECK(); 1764 uint32_t fFlags; 1765 rc = guestProp::validateFlags(Utf8Str(flags[i]).raw(), &fFlags); 1766 AssertLogRelRCReturn(rc, VMSetError(pVM, VERR_INVALID_PARAMETER, RT_SRC_POS, 1767 N_("Guest property '%lS' has invalid flags '%lS' in machine definition file"), 1768 names[i], flags[i])); 1769 rc = CFGMR3InsertInteger(pFlags, Utf8Str(names[i]).raw(), fFlags); RC_CHECK(); 1770 } 1741 SafeArray <BSTR> namesOut; 1742 SafeArray <BSTR> valuesOut; 1743 SafeArray <ULONG64> timestampsOut; 1744 SafeArray <BSTR> flagsOut; 1745 hrc = pConsole->mControl->PullGuestProperties(ComSafeArrayAsOutParam(namesOut), 1746 ComSafeArrayAsOutParam(valuesOut), 1747 ComSafeArrayAsOutParam(timestampsOut), 1748 ComSafeArrayAsOutParam(flagsOut)); H(); 1749 size_t cProps = namesOut.size(); 1750 if ( valuesOut.size() != cProps 1751 || timestampsOut.size() != cProps 1752 || flagsOut.size() != cProps 1753 ) 1754 rc = VERR_INVALID_PARAMETER; 1755 1756 std::vector <Utf8Str> utf8Names, utf8Values, utf8Flags; 1757 std::vector <char *> names, values, flags; 1758 std::vector <ULONG64> timestamps; 1759 for (unsigned i = 0; i < cProps && RT_SUCCESS(rc); ++i) 1760 if ( !VALID_PTR(namesOut[i]) 1761 || !VALID_PTR(valuesOut[i]) 1762 || !VALID_PTR(flagsOut[i]) 1763 ) 1764 rc = VERR_INVALID_POINTER; 1765 for (unsigned i = 0; i < cProps && RT_SUCCESS(rc); ++i) 1766 { 1767 utf8Names.push_back(Bstr(namesOut[i])); 1768 utf8Values.push_back(Bstr(valuesOut[i])); 1769 timestamps.push_back(timestampsOut[i]); 1770 utf8Flags.push_back(Bstr(flagsOut[i])); 1771 if ( utf8Names.back().isNull() 1772 || utf8Values.back().isNull() 1773 || utf8Flags.back().isNull() 1774 ) 1775 throw std::bad_alloc(); 1776 } 1777 for (unsigned i = 0; i < cProps && RT_SUCCESS(rc); ++i) 1778 { 1779 names.push_back(utf8Names[i].mutableRaw()); 1780 values.push_back(utf8Values[i].mutableRaw()); 1781 flags.push_back(utf8Flags[i].mutableRaw()); 1782 } 1783 names.push_back(NULL); 1784 values.push_back(NULL); 1785 timestamps.push_back(0); 1786 flags.push_back(NULL); 1771 1787 1772 1788 /* Setup the service. */ 1773 VBOXHGCMSVCPARM parms[ 3];1789 VBOXHGCMSVCPARM parms[4]; 1774 1790 1775 1791 parms[0].type = VBOX_HGCM_SVC_PARM_PTR; 1776 parms[0].u.pointer.addr = pValues;1777 parms[0].u.pointer.size = sizeof(pValues); /* We don't actually care. */1792 parms[0].u.pointer.addr = &names.front(); 1793 parms[0].u.pointer.size = 0; /* We don't actually care. */ 1778 1794 parms[1].type = VBOX_HGCM_SVC_PARM_PTR; 1779 parms[1].u.pointer.addr = pTimestamps;1780 parms[1].u.pointer.size = sizeof(pTimestamps);1795 parms[1].u.pointer.addr = &values.front(); 1796 parms[1].u.pointer.size = 0; /* We don't actually care. */ 1781 1797 parms[2].type = VBOX_HGCM_SVC_PARM_PTR; 1782 parms[2].u.pointer.addr = pFlags; 1783 parms[2].u.pointer.size = sizeof(pFlags); 1784 1785 pConsole->mVMMDev->hgcmHostCall ("VBoxGuestPropSvc", guestProp::SET_CFGM_NODE, 3, &parms[0]); 1798 parms[2].u.pointer.addr = ×tamps.front(); 1799 parms[2].u.pointer.size = 0; /* We don't actually care. */ 1800 parms[3].type = VBOX_HGCM_SVC_PARM_PTR; 1801 parms[3].u.pointer.addr = &flags.front(); 1802 parms[3].u.pointer.size = 0; /* We don't actually care. */ 1803 1804 pConsole->mVMMDev->hgcmHostCall ("VBoxGuestPropSvc", guestProp::SET_PROPS_HOST, 4, &parms[0]); 1786 1805 1787 1806 /* Register the host notification callback */ -
trunk/src/VBox/Main/MachineImpl.cpp
r13723 r13759 3085 3085 mHWData->mGuestProperties.push_back(property); 3086 3086 } 3087 if ( SUCCEEDED (rc) 3088 && ( matchAll 3089 || RTStrSimplePatternMultiMatch (utf8Patterns.raw(), RTSTR_MAX, 3090 utf8Name.raw(), RTSTR_MAX, NULL) 3091 ) 3092 ) 3093 mParent->onGuestPropertyChange (mData->mUuid, aName, aValue, aFlags); 3087 3094 } 3088 3095 else … … 3100 3107 &dummy, &dummy64, &dummy); 3101 3108 } 3102 if ( SUCCEEDED (rc)3103 && ( matchAll3104 || RTStrSimplePatternMultiMatch (utf8Patterns.raw(), RTSTR_MAX,3105 utf8Name.raw(), RTSTR_MAX, NULL)3106 )3107 )3108 mParent->onGuestPropertyChange (mData->mUuid, aName, aValue, aFlags);3109 3109 return rc; 3110 3110 #endif /* else !defined (VBOX_WITH_GUEST_PROPS) */ -
trunk/src/VBox/Main/include/ConsoleImpl.h
r13606 r13759 494 494 static DECLCALLBACK(int) doGuestPropNotification (void *pvExtension, uint32_t, 495 495 void *pvParms, uint32_t cbParms); 496 HRESULT doEnumerateGuestProperties (INPTR BSTR aPatterns, 497 ComSafeArrayOut(BSTR, aNames), 498 ComSafeArrayOut(BSTR, aValues), 499 ComSafeArrayOut(ULONG64, aTimestamps), 500 ComSafeArrayOut(BSTR, aFlags)); 496 501 #endif 497 502
Note:
See TracChangeset
for help on using the changeset viewer.