Changeset 39228 in vbox for trunk/src/VBox/HostServices/GuestProperties
- Timestamp:
- Nov 8, 2011 11:06:20 AM (13 years ago)
- Location:
- trunk/src/VBox/HostServices/GuestProperties
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostServices/GuestProperties/service.cpp
r36529 r39228 64 64 struct Property 65 65 { 66 //#define USE_STRSPACE - later. 67 #ifdef USE_STRSPACE 68 /** The string space core record. */ 69 RTSTRSPACECORE mStrCore; 70 #endif 66 71 /** The name of the property */ 67 72 std::string mName; … … 74 79 75 80 /** Default constructor */ 76 Property() : mTimestamp(0), mFlags(NILFLAG) {} 81 Property() : mTimestamp(0), mFlags(NILFLAG) 82 { 83 #ifdef USE_STRSPACE 84 RT_ZERO(mStrCore); 85 #endif 86 } 77 87 /** Constructor with const char * */ 78 88 Property(const char *pcszName, const char *pcszValue, 79 89 uint64_t u64Timestamp, uint32_t u32Flags) 80 90 : mName(pcszName), mValue(pcszValue), mTimestamp(u64Timestamp), 81 mFlags(u32Flags) {} 91 mFlags(u32Flags) 92 { 93 #ifdef USE_STRSPACE 94 RT_ZERO(mStrCore); 95 mStrCore.pszString = mName.c_str(); 96 #endif 97 } 82 98 /** Constructor with std::string */ 83 99 Property(std::string name, std::string value, uint64_t u64Timestamp, … … 156 172 /** Global flags for the service */ 157 173 ePropFlags meGlobalFlags; 174 #ifdef USE_STRSPACE 175 /** The property string space handle. */ 176 RTSTRSPACE mhProperties; 177 /** The number of properties. */ 178 unsigned mcProperties; 179 #else 158 180 /** The property list */ 159 181 PropertyList mProperties; 182 #endif 160 183 /** The list of property changes for guest notifications */ 161 184 PropertyList mGuestNotifications; … … 248 271 } 249 272 273 /** 274 * Gets a property. 275 * 276 * @returns Pointer to the property if found, NULL if not. 277 * 278 * @param pszName The name of the property to get. 279 */ 280 Property *getPropertyInternal(const char *pszName) 281 { 282 #ifdef USE_STRSPACE 283 return (Property *)RTStrSpaceGet(&mhProperties, pszName); 284 #else 285 for (PropertyList::iterator it = mProperties.begin(); 286 it != mProperties.end(); 287 ++it) 288 if (it->mName.compare(pszName) == 0) 289 return &*it; /* the wonders of stdandard C++... ;-) */ 290 return NULL; 291 #endif 292 } 293 250 294 public: 251 295 explicit Service(PVBOXHGCMSVCHELPERS pHelpers) 252 296 : mpHelpers(pHelpers) 253 297 , meGlobalFlags(NILFLAG) 298 #ifdef USE_STRSPACE 299 , mhProperties(NULL) 300 , mcProperties(0) 301 #endif 254 302 , mpfnHostCallback(NULL) 255 303 , mpvHostData(NULL) … … 442 490 int Service::setPropertyBlock(uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 443 491 { 444 char **ppNames, **ppValues, **ppFlags; 445 uint64_t *pTimestamps; 446 uint32_t cbDummy; 447 int rc = VINF_SUCCESS; 492 const char **papszNames; 493 const char **papszValues; 494 const char **papszFlags; 495 uint64_t *pau64Timestamps; 496 uint32_t cbDummy; 497 int rc = VINF_SUCCESS; 448 498 449 499 /* 450 500 * Get and validate the parameters 451 501 */ 452 if ( (cParms != 4)453 || RT_FAILURE(paParms[0].getPointer ((void **) &ppNames, &cbDummy))454 || RT_FAILURE(paParms[1].getPointer ((void **) &ppValues, &cbDummy))455 || RT_FAILURE(paParms[2].getPointer ((void **) &pTimestamps, &cbDummy))456 || RT_FAILURE(paParms[3].getPointer ((void **) &ppFlags, &cbDummy))502 if ( cParms != 4 503 || RT_FAILURE(paParms[0].getPointer((void **)&papszNames, &cbDummy)) 504 || RT_FAILURE(paParms[1].getPointer((void **)&papszValues, &cbDummy)) 505 || RT_FAILURE(paParms[2].getPointer((void **)&pau64Timestamps, &cbDummy)) 506 || RT_FAILURE(paParms[3].getPointer((void **)&papszFlags, &cbDummy)) 457 507 ) 458 508 rc = VERR_INVALID_PARAMETER; 459 509 /** @todo validate the array sizes... */ 510 511 #ifdef USE_STRSPACE 512 for (unsigned i = 0; RT_SUCCESS(rc) && papszNames[i] != NULL; ++i) 513 { 514 if ( !RT_VALID_PTR(papszNames[i]) 515 || !RT_VALID_PTR(papszValues[i]) 516 || !RT_VALID_PTR(papszFlags[i]) 517 ) 518 rc = VERR_INVALID_POINTER; 519 else 520 { 521 uint32_t fFlagsIgn; 522 rc = validateFlags(papszFlags[i], &fFlagsIgn); 523 } 524 } 525 526 if (RT_SUCCESS(rc)) 527 { 528 /* 529 * Add the properties. No way to roll back here. 530 */ 531 for (unsigned i = 0; papszNames[i] != NULL; ++i) 532 { 533 uint32_t fFlags; 534 rc = validateFlags(papszFlags[i], &fFlags); 535 AssertRCBreak(rc); 536 537 Property *pProp = getPropertyInternal(papszNames[i]); 538 if (pProp) 539 { 540 /* Update existing property. */ 541 pProp->mValue = papszValues[i]; 542 pProp->mTimestamp = pau64Timestamps[i]; 543 pProp->mFlags = fFlags; 544 } 545 else 546 { 547 /* Create a new property */ 548 pProp = new Property(papszNames[i], papszValues[i], pau64Timestamps[i], fFlags); 549 if (!pProp) 550 { 551 rc = VERR_NO_MEMORY; 552 break; 553 } 554 if (RTStrSpaceInsert(&mhProperties, &pProp->mStrCore)) 555 mcProperties++; 556 else 557 { 558 delete pProp; 559 rc = VERR_INTERNAL_ERROR_3; 560 AssertFailedBreak(); 561 } 562 } 563 } 564 } 565 566 #else /* !USE_STRSPACE */ 460 567 /* 461 568 * Add the properties to the end of the list. If we succeed then we … … 469 576 try 470 577 { 471 for (unsigned i = 0; RT_SUCCESS(rc) && p pNames[i] != NULL; ++i)578 for (unsigned i = 0; RT_SUCCESS(rc) && papszNames[i] != NULL; ++i) 472 579 { 473 580 uint32_t fFlags; 474 if ( !VALID_PTR(p pNames[i])475 || !VALID_PTR(p pValues[i])476 || !VALID_PTR(p pFlags[i])581 if ( !VALID_PTR(papszNames[i]) 582 || !VALID_PTR(papszValues[i]) 583 || !VALID_PTR(papszFlags[i]) 477 584 ) 478 585 rc = VERR_INVALID_POINTER; 479 586 if (RT_SUCCESS(rc)) 480 rc = validateFlags(p pFlags[i], &fFlags);587 rc = validateFlags(papszFlags[i], &fFlags); 481 588 if (RT_SUCCESS(rc)) 482 mProperties.push_back(Property(p pNames[i], ppValues[i],483 p Timestamps[i], fFlags));589 mProperties.push_back(Property(papszNames[i], papszValues[i], 590 pau64Timestamps[i], fFlags)); 484 591 } 485 592 } … … 495 602 { 496 603 ++itEnd; 497 for (unsigned i = 0; p pNames[i] != NULL; ++i)604 for (unsigned i = 0; papszNames[i] != NULL; ++i) 498 605 for (PropertyList::iterator it = mProperties.begin(); it != itEnd; ++it) 499 if (it->mName.compare(p pNames[i]) == 0)606 if (it->mName.compare(papszNames[i]) == 0) 500 607 { 501 608 mProperties.erase(it); … … 514 621 mProperties.erase(itEnd, mProperties.end()); 515 622 } 623 #endif /* !USE_STRSPACE */ 516 624 return rc; 517 625 } … … 534 642 const char *pcszName = NULL; /* shut up gcc */ 535 643 char *pchBuf; 536 uint32_t c chName, cchBuf;644 uint32_t cbName, cchBuf; 537 645 char szFlags[MAX_FLAGS_LEN]; 538 646 … … 542 650 LogFlowThisFunc(("\n")); 543 651 if ( cParms != 4 /* Hardcoded value as the next lines depend on it. */ 544 || RT_FAILURE (paParms[0].getString(&pcszName, &cchName)) /* name */545 || RT_FAILURE (paParms[1].getBuffer((void **)&pchBuf, &cchBuf)) /* buffer */652 || RT_FAILURE(paParms[0].getString(&pcszName, &cbName)) /* name */ 653 || RT_FAILURE(paParms[1].getBuffer((void **)&pchBuf, &cchBuf)) /* buffer */ 546 654 ) 547 655 rc = VERR_INVALID_PARAMETER; 548 656 else 549 rc = validateName(pcszName, c chName);657 rc = validateName(pcszName, cbName); 550 658 551 659 /* … … 553 661 */ 554 662 663 #ifdef USE_STRSPACE 664 /* Get the property. */ 665 Property *it = NULL; 666 if (RT_SUCCESS(rc)) 667 { 668 it = getPropertyInternal(pcszName); 669 if (!it) 670 rc = VERR_NOT_FOUND; 671 } 672 673 #else /* !USE_STRSPACE */ 555 674 /* Get the value size */ 556 675 PropertyList::const_iterator it; … … 565 684 } 566 685 } 686 #endif /* !USE_STRSPACE */ 567 687 if (RT_SUCCESS(rc)) 568 688 rc = writeFlags(it->mFlags, szFlags); … … 618 738 619 739 LogFlowThisFunc(("\n")); 740 741 #ifndef USE_STRSPACE /** @todo r=bird: This check is wrong as it will prevent updating 742 * existing properties when the maximum is reached! */ 620 743 /* 621 744 * First of all, make sure that we won't exceed the maximum number of properties. … … 623 746 if (mProperties.size() >= MAX_PROPS) 624 747 rc = VERR_TOO_MUCH_DATA; 748 #endif 625 749 626 750 /* … … 656 780 * to change it. 657 781 */ 782 #ifdef USE_STRSPACE 783 Property *it = getPropertyInternal(pcszName); 784 bool found = it != NULL; 785 #else 658 786 PropertyList::iterator it; 659 787 bool found = false; … … 664 792 break; 665 793 } 794 #endif /* !USE_STRSPACE */ 666 795 667 796 rc = checkPermission(found ? (ePropFlags)it->mFlags : NILFLAG, … … 678 807 it->mFlags = fFlags; 679 808 } 809 #ifdef USE_STRSPACE 810 else if (mcProperties < MAX_PROPS) 811 { 812 /* Create a new string space record. */ 813 it = new Property(pcszName, pcszValue, u64TimeNano, fFlags); 814 if (it) 815 { 816 if (RTStrSpaceInsert(&mhProperties, &it->mStrCore)) 817 mcProperties++; 818 else 819 { 820 AssertFailed(); 821 delete it; 822 rc = VERR_INTERNAL_ERROR_3; 823 } 824 } 825 else 826 rc = VERR_NO_MEMORY; 827 } 828 else 829 rc = VERR_TOO_MUCH_DATA; 830 #else 680 831 else /* This can throw. No problem as we have nothing to roll back. */ 681 832 mProperties.push_back(Property(pcszName, pcszValue, u64TimeNano, fFlags)); 833 #endif 682 834 683 835 /* … … 729 881 * to change it. 730 882 */ 883 #ifdef USE_STRSPACE 884 Property *it = getPropertyInternal(pcszName); 885 bool found = it != NULL; 886 if (it) 887 rc = checkPermission((ePropFlags)it->mFlags, isGuest); 888 #else 731 889 PropertyList::iterator it; 732 890 bool found = false; … … 738 896 break; 739 897 } 898 #endif 740 899 741 900 /* … … 745 904 { 746 905 uint64_t u64Timestamp = getCurrentTimestamp(); 906 #ifdef USE_STRSPACE 907 bool fRc = RTStrSpaceRemove(&mhProperties, it->mStrCore.pszString); 908 Assert(fRc); NOREF(fRc); 909 mcProperties--; 910 delete it; 911 #else 747 912 mProperties.erase(it); 913 #endif 748 914 // if (isGuest) /* Notify the host even for properties that the host 749 915 // * changed. Less efficient, but ensures consistency. */ … … 755 921 return rc; 756 922 } 923 924 #ifdef USE_STRSPACE 925 926 /** 927 * Enumeration data shared between enumPropsCallback and Service::enumProps. 928 */ 929 typedef struct EnumData 930 { 931 const char *pszPattern; /**< The pattern to match properties against. */ 932 char *pchCur; /**< The current buffer postion. */ 933 size_t cbLeft; /**< The amount of available buffer space. */ 934 size_t cbNeeded; /**< The amount of needed buffer space. */ 935 } EnumData; 936 937 /** 938 * @callback_method_impl{FNRTSTRSPACECALLBACK} 939 */ 940 static DECLCALLBACK(int) enumPropsCallback(PRTSTRSPACECORE pStr, void *pvUser) 941 { 942 Property *pProp = (Property *)pStr; 943 EnumData *pEnum = (EnumData *)pvUser; 944 945 /* Included in the enumeration? */ 946 if (!pProp->Matches(pEnum->pszPattern)) 947 return 0; 948 949 /* Convert the non-string members into strings. */ 950 char szTimestamp[256]; 951 size_t const cbTimestamp = RTStrFormatNumber(szTimestamp, pProp->mTimestamp, 10, 0, 0, 0) + 1; 952 953 char szFlags[MAX_FLAGS_LEN]; 954 int rc = writeFlags(pProp->mFlags, szFlags); 955 if (RT_FAILURE(rc)) 956 return rc; 957 size_t const cbFlags = strlen(szFlags) + 1; 958 959 /* Calculate the buffer space requirements. */ 960 size_t const cbName = pProp->mName.length() + 1; 961 size_t const cbValue = pProp->mValue.length() + 1; 962 size_t const cbRequired = cbName + cbValue + cbTimestamp + cbFlags; 963 pEnum->cbNeeded += cbRequired; 964 965 /* Sufficient buffer space? */ 966 if (cbRequired > pEnum->cbLeft) 967 { 968 pEnum->cbLeft = 0; 969 return 0; /* don't quit */ 970 } 971 pEnum->cbLeft -= cbRequired; 972 973 /* Append the property to the buffer. */ 974 char *pchCur = pEnum->pchCur; 975 pEnum->pchCur += cbRequired; 976 977 memcpy(pchCur, pProp->mName.c_str(), cbName); 978 pchCur += cbName; 979 980 memcpy(pchCur, pProp->mValue.c_str(), cbValue); 981 pchCur += cbValue; 982 983 memcpy(pchCur, szTimestamp, cbTimestamp); 984 pchCur += cbTimestamp; 985 986 memcpy(pchCur, szFlags, cbFlags); 987 pchCur += cbFlags; 988 989 Assert(pchCur == pEnum->pchCur); 990 return 0; 991 } 992 #endif /* USE_STRSPACE */ 757 993 758 994 /** … … 772 1008 * Get the HGCM function arguments. 773 1009 */ 774 char *pcchPatterns = NULL, *pchBuf = NULL; 775 uint32_t cchPatterns = 0, cchBuf = 0; 1010 char const *pchPatterns = NULL; 1011 char *pchBuf = NULL; 1012 uint32_t cbPatterns = 0; 1013 uint32_t cchBuf = 0; 776 1014 LogFlowThisFunc(("\n")); 777 1015 if ( (cParms != 3) /* Hardcoded value as the next lines depend on it. */ 778 || RT_FAILURE(paParms[0].getString(&pc chPatterns, &cchPatterns)) /* patterns */1016 || RT_FAILURE(paParms[0].getString(&pchPatterns, &cbPatterns)) /* patterns */ 779 1017 || RT_FAILURE(paParms[1].getBuffer((void **) &pchBuf, &cchBuf)) /* return buffer */ 780 1018 ) 781 1019 rc = VERR_INVALID_PARAMETER; 782 if (RT_SUCCESS(rc) && c chPatterns > MAX_PATTERN_LEN)1020 if (RT_SUCCESS(rc) && cbPatterns > MAX_PATTERN_LEN) 783 1021 rc = VERR_TOO_MUCH_DATA; 784 1022 … … 789 1027 if (RT_SUCCESS(rc)) 790 1028 { 791 for (unsigned i = 0; i < c chPatterns - 1; ++i)792 if (pc chPatterns[i] != '\0')793 pszPatterns[i] = pc chPatterns[i];1029 for (unsigned i = 0; i < cbPatterns - 1; ++i) 1030 if (pchPatterns[i] != '\0') 1031 pszPatterns[i] = pchPatterns[i]; 794 1032 else 795 1033 pszPatterns[i] = '|'; 796 pszPatterns[cchPatterns - 1] = '\0'; 797 } 798 1034 pszPatterns[cbPatterns - 1] = '\0'; 1035 } 1036 1037 #ifdef USE_STRSPACE 1038 /* 1039 * Next enumerate into the buffer. 1040 */ 1041 if (RT_SUCCESS(rc)) 1042 { 1043 EnumData EnumData; 1044 EnumData.pszPattern = pszPatterns; 1045 EnumData.pchCur = pchBuf; 1046 EnumData.cbLeft = cchBuf; 1047 EnumData.cbNeeded = 0; 1048 rc = RTStrSpaceEnumerate(&mhProperties, enumPropsCallback, &EnumData); 1049 AssertRCSuccess(rc); 1050 if (RT_SUCCESS(rc)) 1051 { 1052 paParms[2].setUInt32((uint32_t)(EnumData.cbNeeded + 4)); 1053 if (EnumData.cbLeft >= 4) 1054 { 1055 /* The final terminators. */ 1056 EnumData.pchCur[0] = '\0'; 1057 EnumData.pchCur[1] = '\0'; 1058 EnumData.pchCur[2] = '\0'; 1059 EnumData.pchCur[3] = '\0'; 1060 } 1061 else 1062 rc = VERR_BUFFER_OVERFLOW; 1063 } 1064 } 1065 1066 #else /* !USE_STRSPACE */ 799 1067 /* 800 1068 * Next enumerate into a temporary buffer. This can throw, but this is … … 833 1101 if (RT_SUCCESS(rc)) 834 1102 { 835 paParms[2].setUInt32 1103 paParms[2].setUInt32((uint32_t)buffer.size()); 836 1104 /* Copy the memory if it fits into the guest buffer */ 837 1105 if (buffer.size() <= cchBuf) … … 840 1108 rc = VERR_BUFFER_OVERFLOW; 841 1109 } 1110 #endif /* !USE_STRSPACE */ 842 1111 return rc; 843 1112 } … … 1000 1269 /* prop is currently a delete event for pszProperty */ 1001 1270 bool found = false; 1271 #ifdef USE_STRSPACE 1272 if (RT_SUCCESS(rc)) 1273 { 1274 Property *pProp = getPropertyInternal(pszProperty); 1275 if (pProp) 1276 { 1277 found = true; 1278 /* Make prop into a change event. */ 1279 prop.mValue = pProp->mValue; 1280 prop.mFlags = pProp->mFlags; 1281 } 1282 } 1283 #else /* !USE_STRSPACE */ 1002 1284 if (RT_SUCCESS(rc)) 1003 1285 for (PropertyList::const_iterator it = mProperties.begin(); … … 1010 1292 prop.mFlags = it->mFlags; 1011 1293 } 1012 1294 #endif /* !USE_STRSPACE */ 1013 1295 1014 1296 /* Release waiters if applicable and add the event to the queue for … … 1115 1397 { 1116 1398 int rc = VINF_SUCCESS; 1117 LogFlowFunc(("u32ClientID = %d, fn = %d, cParms = %d, pparms = % d\n",1399 LogFlowFunc(("u32ClientID = %d, fn = %d, cParms = %d, pparms = %p\n", 1118 1400 u32ClientID, eFunction, cParms, paParms)); 1119 1401 … … 1183 1465 int rc = VINF_SUCCESS; 1184 1466 1185 LogFlowFunc(("fn = %d, cParms = %d, pparms = % d\n",1467 LogFlowFunc(("fn = %d, cParms = %d, pparms = %p\n", 1186 1468 eFunction, cParms, paParms)); 1187 1469 -
trunk/src/VBox/HostServices/GuestProperties/testcase/tstGuestPropSvc.cpp
r36412 r39228 21 21 *******************************************************************************/ 22 22 #include <VBox/HostServices/GuestPropertySvc.h> 23 #include <iprt/initterm.h>24 #include <iprt/stream.h>25 23 #include <iprt/test.h> 24 #include <iprt/time.h> 25 26 26 27 27 /******************************************************************************* … … 54 54 void initTable(VBOXHGCMSVCFNTABLE *pTable, VBOXHGCMSVCHELPERS *pHelpers) 55 55 { 56 pTable->cbSize = sizeof (VBOXHGCMSVCFNTABLE);57 pTable->u32Version = VBOX_HGCM_SVC_VERSION;58 pHelpers->pfnCallComplete = callComplete;59 pTable->pHelpers = pHelpers;56 pTable->cbSize = sizeof (VBOXHGCMSVCFNTABLE); 57 pTable->u32Version = VBOX_HGCM_SVC_VERSION; 58 pHelpers->pfnCallComplete = callComplete; 59 pTable->pHelpers = pHelpers; 60 60 } 61 61 … … 72 72 const char *pcszOut; 73 73 } 74 g_ validFlagStrings[] =74 g_aValidFlagStrings[] = 75 75 { 76 76 /* pcszIn, pcszOut */ … … 91 91 * functions should reject these. 92 92 */ 93 const char *g_ invalidFlagStrings[] =93 const char *g_apszInvalidFlagStrings[] = 94 94 { 95 95 "RDONLYHOST,,", … … 102 102 * @note prints its own diagnostic information to stdout. 103 103 */ 104 int testConvertFlags()104 static void testConvertFlags(void) 105 105 { 106 106 int rc = VINF_SUCCESS; 107 107 char *pszFlagBuffer = (char *)RTTestGuardedAllocTail(g_hTest, MAX_FLAGS_LEN); 108 108 109 RT Printf("tstGuestPropSvc: Testing conversion of valid flags strings.\n");110 for (unsigned i = 0; i < RT_ELEMENTS(g_ validFlagStrings) && RT_SUCCESS(rc); ++i)109 RTTestISub("Conversion of valid flags strings"); 110 for (unsigned i = 0; i < RT_ELEMENTS(g_aValidFlagStrings) && RT_SUCCESS(rc); ++i) 111 111 { 112 112 uint32_t fFlags; 113 rc = validateFlags(g_ validFlagStrings[i].pcszIn, &fFlags);113 rc = validateFlags(g_aValidFlagStrings[i].pcszIn, &fFlags); 114 114 if (RT_FAILURE(rc)) 115 RT Printf("tstGuestPropSvc: FAILURE - Failed to validate flag string '%s'.\n", g_validFlagStrings[i].pcszIn);115 RTTestIFailed("Failed to validate flag string '%s'", g_aValidFlagStrings[i].pcszIn); 116 116 if (RT_SUCCESS(rc)) 117 117 { 118 118 rc = writeFlags(fFlags, pszFlagBuffer); 119 119 if (RT_FAILURE(rc)) 120 RT Printf("tstGuestPropSvc: FAILURE - Failed to convert flag string '%s' back to a string.\n",121 g_validFlagStrings[i].pcszIn);120 RTTestIFailed("Failed to convert flag string '%s' back to a string.", 121 g_aValidFlagStrings[i].pcszIn); 122 122 } 123 123 if (RT_SUCCESS(rc) && (strlen(pszFlagBuffer) > MAX_FLAGS_LEN - 1)) 124 124 { 125 RT Printf("tstGuestPropSvc: FAILURE -String '%s' converts back to a flag string which is too long.\n",126 g_validFlagStrings[i].pcszIn);125 RTTestIFailed("String '%s' converts back to a flag string which is too long.\n", 126 g_aValidFlagStrings[i].pcszIn); 127 127 rc = VERR_TOO_MUCH_DATA; 128 128 } 129 if (RT_SUCCESS(rc) && (strcmp(pszFlagBuffer, g_ validFlagStrings[i].pcszOut) != 0))130 { 131 RT Printf("tstGuestPropSvc: FAILURE -String '%s' converts back to '%s' instead of to '%s'\n",132 g_validFlagStrings[i].pcszIn, pszFlagBuffer,133 g_validFlagStrings[i].pcszOut);129 if (RT_SUCCESS(rc) && (strcmp(pszFlagBuffer, g_aValidFlagStrings[i].pcszOut) != 0)) 130 { 131 RTTestIFailed("String '%s' converts back to '%s' instead of to '%s'\n", 132 g_aValidFlagStrings[i].pcszIn, pszFlagBuffer, 133 g_aValidFlagStrings[i].pcszOut); 134 134 rc = VERR_PARSE_ERROR; 135 135 } … … 137 137 if (RT_SUCCESS(rc)) 138 138 { 139 RT Printf("Testing rejection of invalid flags strings.\n");140 for (unsigned i = 0; i < RT_ELEMENTS(g_ invalidFlagStrings) && RT_SUCCESS(rc); ++i)139 RTTestISub("Rejection of invalid flags strings"); 140 for (unsigned i = 0; i < RT_ELEMENTS(g_apszInvalidFlagStrings) && RT_SUCCESS(rc); ++i) 141 141 { 142 142 uint32_t fFlags; 143 143 /* This is required to fail. */ 144 if (RT_SUCCESS(validateFlags(g_ invalidFlagStrings[i], &fFlags)))144 if (RT_SUCCESS(validateFlags(g_apszInvalidFlagStrings[i], &fFlags))) 145 145 { 146 RT Printf("String '%s' was incorrectly accepted as a valid flag string.\n",147 g_invalidFlagStrings[i]);146 RTTestIFailed("String '%s' was incorrectly accepted as a valid flag string.\n", 147 g_apszInvalidFlagStrings[i]); 148 148 rc = VERR_PARSE_ERROR; 149 149 } … … 153 153 { 154 154 uint32_t u32BadFlags = ALLFLAGS << 1; 155 RT Printf("Testing rejection of an invalid flags field.\n");155 RTTestISub("Rejection of an invalid flags field"); 156 156 /* This is required to fail. */ 157 157 if (RT_SUCCESS(writeFlags(u32BadFlags, pszFlagBuffer))) 158 158 { 159 RT Printf("Flags 0x%x were incorrectly written out as '%.*s'\n",160 u32BadFlags, MAX_FLAGS_LEN, pszFlagBuffer);159 RTTestIFailed("Flags 0x%x were incorrectly written out as '%.*s'\n", 160 u32BadFlags, MAX_FLAGS_LEN, pszFlagBuffer); 161 161 rc = VERR_PARSE_ERROR; 162 162 } … … 164 164 165 165 RTTestGuardedFree(g_hTest, pszFlagBuffer); 166 return rc;167 166 } 168 167 … … 170 169 * List of property names for testSetPropsHost. 171 170 */ 172 const char * apcszNameBlock[] =171 const char *g_apcszNameBlock[] = 173 172 { 174 173 "test/name/", … … 182 181 * List of property values for testSetPropsHost. 183 182 */ 184 const char * apcszValueBlock[] =183 const char *g_apcszValueBlock[] = 185 184 { 186 185 "test/value/", … … 194 193 * List of property timestamps for testSetPropsHost. 195 194 */ 196 uint64_t au64TimestampBlock[] =195 uint64_t g_au64TimestampBlock[] = 197 196 { 198 197 0, 999, 999999, UINT64_C(999999999999), 0 … … 202 201 * List of property flags for testSetPropsHost. 203 202 */ 204 const char * apcszFlagsBlock[] =203 const char *g_apcszFlagsBlock[] = 205 204 { 206 205 "", … … 216 215 * @note prints its own diagnostic information to stdout. 217 216 */ 218 int testSetPropsHost(VBOXHGCMSVCFNTABLE *ptable) 219 { 220 int rc = VINF_SUCCESS; 221 RTPrintf("Testing the SET_PROPS_HOST call.\n"); 222 if (!VALID_PTR(ptable->pfnHostCall)) 223 { 224 RTPrintf("Invalid pfnHostCall() pointer\n"); 225 rc = VERR_INVALID_POINTER; 226 } 227 if (RT_SUCCESS(rc)) 228 { 229 VBOXHGCMSVCPARM paParms[4]; 230 paParms[0].setPointer ((void *) apcszNameBlock, 0); 231 paParms[1].setPointer ((void *) apcszValueBlock, 0); 232 paParms[2].setPointer ((void *) au64TimestampBlock, 0); 233 paParms[3].setPointer ((void *) apcszFlagsBlock, 0); 234 rc = ptable->pfnHostCall(ptable->pvService, SET_PROPS_HOST, 4, 235 paParms); 236 if (RT_FAILURE(rc)) 237 RTPrintf("SET_PROPS_HOST call failed with rc=%Rrc\n", rc); 238 } 239 return rc; 217 static void testSetPropsHost(VBOXHGCMSVCFNTABLE *ptable) 218 { 219 RTTestISub("SET_PROPS_HOST"); 220 RTTESTI_CHECK_RETV(RT_VALID_PTR(ptable->pfnHostCall)); 221 222 VBOXHGCMSVCPARM aParms[4]; 223 aParms[0].setPointer((void *)g_apcszNameBlock, 0); 224 aParms[1].setPointer((void *)g_apcszValueBlock, 0); 225 aParms[2].setPointer((void *)g_au64TimestampBlock, 0); 226 aParms[3].setPointer((void *)g_apcszFlagsBlock, 0); 227 RTTESTI_CHECK_RC(ptable->pfnHostCall(ptable->pvService, SET_PROPS_HOST, 4, &aParms[0]), VINF_SUCCESS); 240 228 } 241 229 242 230 /** Result strings for zeroth enumeration test */ 243 static const char * pcchEnumResult0[] =231 static const char *g_apchEnumResult0[] = 244 232 { 245 233 "test/name/\0test/value/\0""0\0", … … 251 239 252 240 /** Result string sizes for zeroth enumeration test */ 253 static const uint32_t cchEnumResult0[] =241 static const uint32_t g_acbEnumResult0[] = 254 242 { 255 243 sizeof("test/name/\0test/value/\0""0\0"), … … 264 252 * the - 1 at the end is because of the hidden zero terminator 265 253 */ 266 static const uint32_t cchEnumBuffer0 =267 sizeof("test/name/\0test/value/\0""0\0\0"268 "test name\0test value\0""999\0TRANSIENT, READONLY\0"269 "TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST\0"270 "/test/name\0/test/value\0""999999999999\0RDONLYGUEST\0\0\0\0\0") - 1;254 static const uint32_t g_cbEnumBuffer0 = 255 sizeof("test/name/\0test/value/\0""0\0\0" 256 "test name\0test value\0""999\0TRANSIENT, READONLY\0" 257 "TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST\0" 258 "/test/name\0/test/value\0""999999999999\0RDONLYGUEST\0\0\0\0\0") - 1; 271 259 272 260 /** Result strings for first and second enumeration test */ 273 static const char * pcchEnumResult1[] =261 static const char *g_apchEnumResult1[] = 274 262 { 275 263 "TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST", … … 279 267 280 268 /** Result string sizes for first and second enumeration test */ 281 static const uint32_t cchEnumResult1[] =269 static const uint32_t g_acbEnumResult1[] = 282 270 { 283 271 sizeof("TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST"), … … 290 278 * the - 1 at the end is because of the hidden zero terminator 291 279 */ 292 static const uint32_t cchEnumBuffer1 =293 sizeof("TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST\0"294 "/test/name\0/test/value\0""999999999999\0RDONLYGUEST\0\0\0\0\0") - 1;280 static const uint32_t g_cbEnumBuffer1 = 281 sizeof("TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST\0" 282 "/test/name\0/test/value\0""999999999999\0RDONLYGUEST\0\0\0\0\0") - 1; 295 283 296 284 static const struct enumStringStruct 297 285 { 298 286 /** The enumeration pattern to test */ 299 const char *pcszPatterns;287 const char *pszPatterns; 300 288 /** The size of the pattern string */ 301 const uint32_t cchPatterns;289 const uint32_t cchPatterns; 302 290 /** The expected enumeration output strings */ 303 const char **ppcchResult;291 const char **papchResult; 304 292 /** The size of the output strings */ 305 const uint32_t *p cchResult;293 const uint32_t *pacchResult; 306 294 /** The size of the buffer needed for the enumeration */ 307 const uint32_t cchBuffer; 308 } 309 enumStrings[] = 295 const uint32_t cbBuffer; 296 } g_aEnumStrings[] = 310 297 { 311 298 { 312 299 "", sizeof(""), 313 pcchEnumResult0,314 cchEnumResult0,315 cchEnumBuffer0300 g_apchEnumResult0, 301 g_acbEnumResult0, 302 g_cbEnumBuffer0 316 303 }, 317 304 { 318 305 "/*\0?E*", sizeof("/*\0?E*"), 319 pcchEnumResult1,320 cchEnumResult1,321 cchEnumBuffer1306 g_apchEnumResult1, 307 g_acbEnumResult1, 308 g_cbEnumBuffer1 322 309 }, 323 310 { 324 311 "/*|?E*", sizeof("/*|?E*"), 325 pcchEnumResult1,326 cchEnumResult1,327 cchEnumBuffer1312 g_apchEnumResult1, 313 g_acbEnumResult1, 314 g_cbEnumBuffer1 328 315 } 329 316 }; … … 334 321 * @note prints its own diagnostic information to stdout. 335 322 */ 336 int testEnumPropsHost(VBOXHGCMSVCFNTABLE *ptable) 337 { 338 int rc = VINF_SUCCESS; 339 RTPrintf("Testing the ENUM_PROPS_HOST call.\n"); 340 if (!VALID_PTR(ptable->pfnHostCall)) 341 { 342 RTPrintf("Invalid pfnHostCall() pointer\n"); 343 rc = VERR_INVALID_POINTER; 344 } 345 for (unsigned i = 0; RT_SUCCESS(rc) && i < RT_ELEMENTS(enumStrings); 346 ++i) 347 { 348 char buffer[2048]; 349 VBOXHGCMSVCPARM paParms[3]; 350 paParms[0].setPointer ((void *) enumStrings[i].pcszPatterns, 351 enumStrings[i].cchPatterns); 352 paParms[1].setPointer ((void *) buffer, 353 enumStrings[i].cchBuffer - 1); 354 AssertBreakStmt(sizeof(buffer) > enumStrings[i].cchBuffer, 355 rc = VERR_INTERNAL_ERROR); 356 if (RT_SUCCESS(rc)) 357 { 358 /* This should fail as the buffer is too small. */ 359 int rc2 = ptable->pfnHostCall(ptable->pvService, ENUM_PROPS_HOST, 360 3, paParms); 361 if (rc2 != VERR_BUFFER_OVERFLOW) 323 static void testEnumPropsHost(VBOXHGCMSVCFNTABLE *ptable) 324 { 325 RTTestISub("ENUM_PROPS_HOST"); 326 RTTESTI_CHECK_RETV(RT_VALID_PTR(ptable->pfnHostCall)); 327 328 for (unsigned i = 0; i < RT_ELEMENTS(g_aEnumStrings); ++i) 329 { 330 VBOXHGCMSVCPARM aParms[3]; 331 char abBuffer[2048]; 332 RTTESTI_CHECK_RETV(g_aEnumStrings[i].cbBuffer < sizeof(abBuffer)); 333 334 /* Check that we get buffer overflow with a too small buffer. */ 335 aParms[0].setPointer((void *)g_aEnumStrings[i].pszPatterns, g_aEnumStrings[i].cchPatterns); 336 aParms[1].setPointer((void *)abBuffer, g_aEnumStrings[i].cbBuffer - 1); 337 int rc2 = ptable->pfnHostCall(ptable->pvService, ENUM_PROPS_HOST, 3, aParms); 338 if (rc2 == VERR_BUFFER_OVERFLOW) 339 { 340 uint32_t cbNeeded; 341 RTTESTI_CHECK_RC(rc2 = aParms[2].getUInt32(&cbNeeded), VINF_SUCCESS); 342 if (RT_SUCCESS(rc2)) 343 RTTESTI_CHECK_MSG(cbNeeded == g_aEnumStrings[i].cbBuffer, 344 ("expected %u, got %u, pattern %d\n", g_aEnumStrings[i].cbBuffer, cbNeeded, i)); 345 } 346 else 347 RTTestIFailed("ENUM_PROPS_HOST returned %Rrc instead of VERR_BUFFER_OVERFLOW on too small buffer, pattern number %d.", rc2, i); 348 349 /* Make a successfull call. */ 350 aParms[0].setPointer((void *)g_aEnumStrings[i].pszPatterns, g_aEnumStrings[i].cchPatterns); 351 aParms[1].setPointer((void *)abBuffer, g_aEnumStrings[i].cbBuffer); 352 rc2 = ptable->pfnHostCall(ptable->pvService, ENUM_PROPS_HOST, 3, aParms); 353 if (rc2 == VINF_SUCCESS) 354 { 355 /* Look for each of the result strings in the buffer which was returned */ 356 for (unsigned j = 0; g_aEnumStrings[i].papchResult[j] != NULL; ++j) 362 357 { 363 RTPrintf("ENUM_PROPS_HOST returned %Rrc instead of VERR_BUFFER_OVERFLOW on too small buffer, pattern number %d\n", rc2, i); 364 rc = VERR_BUFFER_OVERFLOW; 358 bool found = false; 359 for (unsigned k = 0; !found && k < g_aEnumStrings[i].cbBuffer 360 - g_aEnumStrings[i].pacchResult[j]; 361 ++k) 362 if (memcmp(abBuffer + k, g_aEnumStrings[i].papchResult[j], 363 g_aEnumStrings[i].pacchResult[j]) == 0) 364 found = true; 365 if (!found) 366 RTTestIFailed("ENUM_PROPS_HOST did not produce the expected output for pattern %d.", i); 365 367 } 366 else 367 { 368 uint32_t cchBufferActual; 369 rc = paParms[2].getUInt32 (&cchBufferActual); 370 if (RT_SUCCESS(rc) && cchBufferActual != enumStrings[i].cchBuffer) 371 { 372 RTPrintf("ENUM_PROPS_HOST requested a buffer size of %lu instead of %lu for pattern number %d\n", cchBufferActual, enumStrings[i].cchBuffer, i); 373 rc = VERR_OUT_OF_RANGE; 374 } 375 else if (RT_FAILURE(rc)) 376 RTPrintf("ENUM_PROPS_HOST did not return the required buffer size properly for pattern %d\n", i); 377 } 378 } 379 if (RT_SUCCESS(rc)) 380 { 381 paParms[1].setPointer ((void *) buffer, enumStrings[i].cchBuffer); 382 rc = ptable->pfnHostCall(ptable->pvService, ENUM_PROPS_HOST, 383 3, paParms); 384 if (RT_FAILURE(rc)) 385 RTPrintf("ENUM_PROPS_HOST call failed for pattern %d with rc=%Rrc\n", i, rc); 386 else 387 /* Look for each of the result strings in the buffer which was returned */ 388 for (unsigned j = 0; RT_SUCCESS(rc) && enumStrings[i].ppcchResult[j] != NULL; 389 ++j) 390 { 391 bool found = false; 392 for (unsigned k = 0; !found && k < enumStrings[i].cchBuffer 393 - enumStrings[i].pcchResult[j]; 394 ++k) 395 if (memcmp(buffer + k, enumStrings[i].ppcchResult[j], 396 enumStrings[i].pcchResult[j]) == 0) 397 found = true; 398 if (!found) 399 { 400 RTPrintf("ENUM_PROPS_HOST did not produce the expected output for pattern %d\n", 401 i); 402 rc = VERR_UNRESOLVED_ERROR; 403 } 404 } 405 } 406 } 407 return rc; 368 } 369 else 370 RTTestIFailed("ENUM_PROPS_HOST returned %Rrc instead of VINF_SUCCESS, pattern number %d.", rc2, i); 371 } 408 372 } 409 373 … … 437 401 else if (useSetProp) 438 402 command = SET_PROP; 439 VBOXHGCMSVCPARM paParms[3];403 VBOXHGCMSVCPARM aParms[3]; 440 404 /* Work around silly constant issues - we ought to allow passing 441 405 * constant strings in the hgcm parameters. */ … … 446 410 RTStrPrintf(szValue, sizeof(szValue), "%s", pcszValue); 447 411 RTStrPrintf(szFlags, sizeof(szFlags), "%s", pcszFlags); 448 paParms[0].setPointer (szName, (uint32_t)strlen(szName) + 1);449 paParms[1].setPointer (szValue, (uint32_t)strlen(szValue) + 1);450 paParms[2].setPointer (szFlags, (uint32_t)strlen(szFlags) + 1);412 aParms[0].setPointer (szName, (uint32_t)strlen(szName) + 1); 413 aParms[1].setPointer (szValue, (uint32_t)strlen(szValue) + 1); 414 aParms[2].setPointer (szFlags, (uint32_t)strlen(szFlags) + 1); 451 415 if (isHost) 452 416 callHandle.rc = pTable->pfnHostCall(pTable->pvService, command, 453 useSetProp ? 3 : 2, paParms);417 useSetProp ? 3 : 2, aParms); 454 418 else 455 419 pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, command, 456 useSetProp ? 3 : 2, paParms);420 useSetProp ? 3 : 2, aParms); 457 421 return callHandle.rc; 458 422 } 459 460 461 /** Array of properties for testing SET_PROP_HOST and _GUEST. */462 static const struct463 {464 /** Property name */465 const char *pcszName;466 /** Property value */467 const char *pcszValue;468 /** Property flags */469 const char *pcszFlags;470 /** Should this be set as the host or the guest? */471 bool isHost;472 /** Should we use SET_PROP or SET_PROP_VALUE? */473 bool useSetProp;474 /** Should this succeed or be rejected with VERR_PERMISSION_DENIED? */475 bool isAllowed;476 }477 setProperties[] =478 {479 { "Red", "Stop!", "transient", false, true, true },480 { "Amber", "Caution!", "", false, false, true },481 { "Green", "Go!", "readonly", true, true, true },482 { "Blue", "What on earth...?", "", true, false, true },483 { "/test/name", "test", "", false, true, false },484 { "TEST NAME", "test", "", true, true, false },485 { "Green", "gone out...", "", false, false, false },486 { "Green", "gone out...", "", true, false, false },487 { NULL, NULL, NULL, false, false, false }488 };489 423 490 424 /** … … 494 428 * @note prints its own diagnostic information to stdout. 495 429 */ 496 int testSetProp(VBOXHGCMSVCFNTABLE *pTable) 497 { 498 int rc = VINF_SUCCESS; 499 RTPrintf("Testing the SET_PROP, SET_PROP_VALUE, SET_PROP_HOST and SET_PROP_VALUE_HOST calls.\n"); 500 for (unsigned i = 0; RT_SUCCESS(rc) && (setProperties[i].pcszName != NULL); 501 ++i) 502 { 503 rc = doSetProperty(pTable, setProperties[i].pcszName, 504 setProperties[i].pcszValue, 505 setProperties[i].pcszFlags, 506 setProperties[i].isHost, 507 setProperties[i].useSetProp); 508 if (setProperties[i].isAllowed && RT_FAILURE(rc)) 509 RTPrintf("Setting property '%s' failed with rc=%Rrc.\n", 510 setProperties[i].pcszName, rc); 511 else if ( !setProperties[i].isAllowed 512 && (rc != VERR_PERMISSION_DENIED)) 513 { 514 RTPrintf("Setting property '%s' returned %Rrc instead of VERR_PERMISSION_DENIED.\n", 515 setProperties[i].pcszName, rc); 516 rc = VERR_IPE_UNEXPECTED_STATUS; 517 } 518 else 519 rc = VINF_SUCCESS; 520 } 521 return rc; 430 static void testSetProp(VBOXHGCMSVCFNTABLE *pTable) 431 { 432 RTTestISub("SET_PROP, SET_PROP_VALUE, SET_PROP_HOST, SET_PROP_VALUE_HOST"); 433 434 /** Array of properties for testing SET_PROP_HOST and _GUEST. */ 435 static const struct 436 { 437 /** Property name */ 438 const char *pcszName; 439 /** Property value */ 440 const char *pcszValue; 441 /** Property flags */ 442 const char *pcszFlags; 443 /** Should this be set as the host or the guest? */ 444 bool isHost; 445 /** Should we use SET_PROP or SET_PROP_VALUE? */ 446 bool useSetProp; 447 /** Should this succeed or be rejected with VERR_PERMISSION_DENIED? */ 448 bool isAllowed; 449 } 450 s_aSetProperties[] = 451 { 452 { "Red", "Stop!", "transient", false, true, true }, 453 { "Amber", "Caution!", "", false, false, true }, 454 { "Green", "Go!", "readonly", true, true, true }, 455 { "Blue", "What on earth...?", "", true, false, true }, 456 { "/test/name", "test", "", false, true, false }, 457 { "TEST NAME", "test", "", true, true, false }, 458 { "Green", "gone out...", "", false, false, false }, 459 { "Green", "gone out...", "", true, false, false }, 460 }; 461 462 for (unsigned i = 0; i < RT_ELEMENTS(s_aSetProperties); ++i) 463 { 464 int rc = doSetProperty(pTable, 465 s_aSetProperties[i].pcszName, 466 s_aSetProperties[i].pcszValue, 467 s_aSetProperties[i].pcszFlags, 468 s_aSetProperties[i].isHost, 469 s_aSetProperties[i].useSetProp); 470 if (s_aSetProperties[i].isAllowed && RT_FAILURE(rc)) 471 RTTestIFailed("Setting property '%s' failed with rc=%Rrc.", 472 s_aSetProperties[i].pcszName, rc); 473 else if ( !s_aSetProperties[i].isAllowed 474 && rc != VERR_PERMISSION_DENIED) 475 RTTestIFailed("Setting property '%s' returned %Rrc instead of VERR_PERMISSION_DENIED.", 476 s_aSetProperties[i].pcszName, rc); 477 } 522 478 } 523 479 … … 531 487 * than the guest one 532 488 */ 533 int doDelProp(VBOXHGCMSVCFNTABLE *pTable, const char *pcszName, bool isHost)489 static int doDelProp(VBOXHGCMSVCFNTABLE *pTable, const char *pcszName, bool isHost) 534 490 { 535 491 VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS }; … … 537 493 if (isHost) 538 494 command = DEL_PROP_HOST; 539 VBOXHGCMSVCPARM paParms[1];495 VBOXHGCMSVCPARM aParms[1]; 540 496 /* Work around silly constant issues - we ought to allow passing 541 497 * constant strings in the hgcm parameters. */ 542 498 char szName[MAX_NAME_LEN]; 543 499 RTStrPrintf(szName, sizeof(szName), "%s", pcszName); 544 paParms[0].setPointer (szName, (uint32_t)strlen(szName) + 1);500 aParms[0].setPointer (szName, (uint32_t)strlen(szName) + 1); 545 501 if (isHost) 546 callHandle.rc = pTable->pfnHostCall(pTable->pvService, command, 547 1, paParms); 502 callHandle.rc = pTable->pfnHostCall(pTable->pvService, command, 1, aParms); 548 503 else 549 pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, command, 550 1, paParms); 504 pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, command, 1, aParms); 551 505 return callHandle.rc; 552 506 } 553 554 /** Array of properties for testing DEL_PROP_HOST and _GUEST. */555 static const struct556 {557 /** Property name */558 const char *pcszName;559 /** Should this be set as the host or the guest? */560 bool isHost;561 /** Should this succeed or be rejected with VERR_PERMISSION_DENIED? */562 bool isAllowed;563 }564 delProperties[] =565 {566 { "Red", false, true },567 { "Amber", true, true },568 { "Red2", false, true },569 { "Amber2", true, true },570 { "Green", false, false },571 { "Green", true, false },572 { "/test/name", false, false },573 { "TEST NAME", true, false },574 { NULL, false, false }575 };576 507 577 508 /** … … 580 511 * @note prints its own diagnostic information to stdout. 581 512 */ 582 int testDelProp(VBOXHGCMSVCFNTABLE *pTable) 583 { 584 int rc = VINF_SUCCESS; 585 RTPrintf("Testing the DEL_PROP and DEL_PROP_HOST calls.\n"); 586 for (unsigned i = 0; RT_SUCCESS(rc) && (delProperties[i].pcszName != NULL); 587 ++i) 588 { 589 rc = doDelProp(pTable, delProperties[i].pcszName, 590 delProperties[i].isHost); 591 if (delProperties[i].isAllowed && RT_FAILURE(rc)) 592 RTPrintf("Deleting property '%s' failed with rc=%Rrc.\n", 593 delProperties[i].pcszName, rc); 594 else if ( !delProperties[i].isAllowed 595 && (rc != VERR_PERMISSION_DENIED) 596 ) 597 { 598 RTPrintf("Deleting property '%s' returned %Rrc instead of VERR_PERMISSION_DENIED.\n", 599 delProperties[i].pcszName, rc); 600 rc = VERR_IPE_UNEXPECTED_STATUS; 601 } 602 else 603 rc = VINF_SUCCESS; 604 } 605 return rc; 606 } 607 608 /** Array of properties for testing GET_PROP_HOST. */ 609 static const struct 610 { 611 /** Property name */ 612 const char *pcszName; 613 /** What value/flags pattern do we expect back? */ 614 const char *pcchValue; 615 /** What size should the value/flags array be? */ 616 uint32_t cchValue; 617 /** Should this property exist? */ 618 bool exists; 619 /** Do we expect a particular timestamp? */ 620 bool hasTimestamp; 621 /** What timestamp if any do ex expect? */ 622 uint64_t u64Timestamp; 623 } 624 getProperties[] = 625 { 626 { "test/name/", "test/value/\0", sizeof("test/value/\0"), true, true, 0 }, 627 { "test name", "test value\0TRANSIENT, READONLY", 628 sizeof("test value\0TRANSIENT, READONLY"), true, true, 999 }, 629 { "TEST NAME", "TEST VALUE\0RDONLYHOST", sizeof("TEST VALUE\0RDONLYHOST"), 630 true, true, 999999 }, 631 { "/test/name", "/test/value\0RDONLYGUEST", 632 sizeof("/test/value\0RDONLYGUEST"), true, true, UINT64_C(999999999999) }, 633 { "Green", "Go!\0READONLY", sizeof("Go!\0READONLY"), true, false, 0 }, 634 { "Blue", "What on earth...?\0", sizeof("What on earth...?\0"), true, 635 false, 0 }, 636 { "Red", "", 0, false, false, 0 }, 637 { NULL, NULL, 0, false, false, 0 } 638 }; 513 static void testDelProp(VBOXHGCMSVCFNTABLE *pTable) 514 { 515 RTTestISub("DEL_PROP, DEL_PROP_HOST"); 516 517 /** Array of properties for testing DEL_PROP_HOST and _GUEST. */ 518 static const struct 519 { 520 /** Property name */ 521 const char *pcszName; 522 /** Should this be set as the host or the guest? */ 523 bool isHost; 524 /** Should this succeed or be rejected with VERR_PERMISSION_DENIED? */ 525 bool isAllowed; 526 } 527 s_aDelProperties[] = 528 { 529 { "Red", false, true }, 530 { "Amber", true, true }, 531 { "Red2", false, true }, 532 { "Amber2", true, true }, 533 { "Green", false, false }, 534 { "Green", true, false }, 535 { "/test/name", false, false }, 536 { "TEST NAME", true, false }, 537 }; 538 539 for (unsigned i = 0; i < RT_ELEMENTS(s_aDelProperties); ++i) 540 { 541 int rc = doDelProp(pTable, s_aDelProperties[i].pcszName, 542 s_aDelProperties[i].isHost); 543 if (s_aDelProperties[i].isAllowed && RT_FAILURE(rc)) 544 RTTestIFailed("Deleting property '%s' failed with rc=%Rrc.", 545 s_aDelProperties[i].pcszName, rc); 546 else if ( !s_aDelProperties[i].isAllowed 547 && rc != VERR_PERMISSION_DENIED ) 548 RTTestIFailed("Deleting property '%s' returned %Rrc instead of VERR_PERMISSION_DENIED.", 549 s_aDelProperties[i].pcszName, rc); 550 } 551 } 639 552 640 553 /** … … 643 556 * @note prints its own diagnostic information to stdout. 644 557 */ 645 int testGetProp(VBOXHGCMSVCFNTABLE *pTable) 646 { 647 int rc = VINF_SUCCESS, rc2 = VINF_SUCCESS; 648 RTPrintf("Testing the GET_PROP_HOST call.\n"); 649 for (unsigned i = 0; RT_SUCCESS(rc) && (getProperties[i].pcszName != NULL); 650 ++i) 651 { 652 VBOXHGCMSVCPARM paParms[4]; 558 static void testGetProp(VBOXHGCMSVCFNTABLE *pTable) 559 { 560 RTTestISub("GET_PROP_HOST"); 561 562 /** Array of properties for testing GET_PROP_HOST. */ 563 static const struct 564 { 565 /** Property name */ 566 const char *pcszName; 567 /** What value/flags pattern do we expect back? */ 568 const char *pchValue; 569 /** What size should the value/flags array be? */ 570 uint32_t cchValue; 571 /** Should this property exist? */ 572 bool exists; 573 /** Do we expect a particular timestamp? */ 574 bool hasTimestamp; 575 /** What timestamp if any do ex expect? */ 576 uint64_t u64Timestamp; 577 } 578 s_aGetProperties[] = 579 { 580 { "test/name/", "test/value/\0", sizeof("test/value/\0"), true, true, 0 }, 581 { "test name", "test value\0TRANSIENT, READONLY", 582 sizeof("test value\0TRANSIENT, READONLY"), true, true, 999 }, 583 { "TEST NAME", "TEST VALUE\0RDONLYHOST", sizeof("TEST VALUE\0RDONLYHOST"), 584 true, true, 999999 }, 585 { "/test/name", "/test/value\0RDONLYGUEST", 586 sizeof("/test/value\0RDONLYGUEST"), true, true, UINT64_C(999999999999) }, 587 { "Green", "Go!\0READONLY", sizeof("Go!\0READONLY"), true, false, 0 }, 588 { "Blue", "What on earth...?\0", sizeof("What on earth...?\0"), true, 589 false, 0 }, 590 { "Red", "", 0, false, false, 0 }, 591 }; 592 593 for (unsigned i = 0; i < RT_ELEMENTS(s_aGetProperties); ++i) 594 { 595 VBOXHGCMSVCPARM aParms[4]; 653 596 /* Work around silly constant issues - we ought to allow passing 654 597 * constant strings in the hgcm parameters. */ 655 598 char szName[MAX_NAME_LEN] = ""; 656 599 char szBuffer[MAX_VALUE_LEN + MAX_FLAGS_LEN]; 657 AssertBreakStmt(sizeof(szBuffer) >= getProperties[i].cchValue, 658 rc = VERR_INTERNAL_ERROR); 659 RTStrPrintf(szName, sizeof(szName), "%s", getProperties[i].pcszName); 660 paParms[0].setPointer (szName, (uint32_t)strlen(szName) + 1); 661 paParms[1].setPointer (szBuffer, sizeof(szBuffer)); 662 rc2 = pTable->pfnHostCall(pTable->pvService, GET_PROP_HOST, 4, 663 paParms); 664 if (getProperties[i].exists && RT_FAILURE(rc2)) 665 { 666 RTPrintf("Getting property '%s' failed with rc=%Rrc.\n", 667 getProperties[i].pcszName, rc2); 668 rc = rc2; 669 } 670 else if (!getProperties[i].exists && (rc2 != VERR_NOT_FOUND)) 671 { 672 RTPrintf("Getting property '%s' returned %Rrc instead of VERR_NOT_FOUND.\n", 673 getProperties[i].pcszName, rc2); 674 rc = VERR_IPE_UNEXPECTED_STATUS; 675 } 676 if (RT_SUCCESS(rc) && getProperties[i].exists) 677 { 678 uint32_t u32ValueLen; 679 rc = paParms[3].getUInt32 (&u32ValueLen); 680 if (RT_FAILURE(rc)) 681 RTPrintf("Failed to get the size of the output buffer for property '%s'\n", 682 getProperties[i].pcszName); 683 if ( RT_SUCCESS(rc) 684 && (memcmp(szBuffer, getProperties[i].pcchValue, 685 getProperties[i].cchValue) != 0) 686 ) 600 RTTESTI_CHECK_RETV(s_aGetProperties[i].cchValue < sizeof(szBuffer)); 601 RTTESTI_CHECK_RETV(strlen(s_aGetProperties[i].pcszName) < sizeof(szName)); 602 603 strcpy(szName, s_aGetProperties[i].pcszName); 604 aParms[0].setPointer(szName, (uint32_t)(strlen(szName) + 1)); 605 aParms[1].setPointer(szBuffer, sizeof(szBuffer)); 606 int rc2 = pTable->pfnHostCall(pTable->pvService, GET_PROP_HOST, 4, aParms); 607 608 if (s_aGetProperties[i].exists && RT_FAILURE(rc2)) 609 { 610 RTTestIFailed("Getting property '%s' failed with rc=%Rrc.", 611 s_aGetProperties[i].pcszName, rc2); 612 continue; 613 } 614 615 if (!s_aGetProperties[i].exists && rc2 != VERR_NOT_FOUND) 616 { 617 RTTestIFailed("Getting property '%s' returned %Rrc instead of VERR_NOT_FOUND.", 618 s_aGetProperties[i].pcszName, rc2); 619 continue; 620 } 621 622 if (s_aGetProperties[i].exists) 623 { 624 AssertRC(rc2); 625 626 uint32_t u32ValueLen = UINT32_MAX; 627 RTTESTI_CHECK_RC(rc2 = aParms[3].getUInt32(&u32ValueLen), VINF_SUCCESS); 628 if (RT_SUCCESS(rc2)) 687 629 { 688 RTPrintf("Unexpected result '%.*s' for property '%s', expected '%.*s'.\n", 689 u32ValueLen, szBuffer, getProperties[i].pcszName, 690 getProperties[i].cchValue, getProperties[i].pcchValue); 691 rc = VERR_UNRESOLVED_ERROR; 630 RTTESTI_CHECK_MSG(u32ValueLen <= sizeof(szBuffer), ("u32ValueLen=%d", u32ValueLen)); 631 if (memcmp(szBuffer, s_aGetProperties[i].pchValue, s_aGetProperties[i].cchValue) != 0) 632 RTTestIFailed("Unexpected result '%.*s' for property '%s', expected '%.*s'.", 633 u32ValueLen, szBuffer, s_aGetProperties[i].pcszName, 634 s_aGetProperties[i].cchValue, s_aGetProperties[i].pchValue); 692 635 } 693 if (RT_SUCCESS(rc) && getProperties[i].hasTimestamp) 636 637 if (s_aGetProperties[i].hasTimestamp) 694 638 { 695 uint64_t u64Timestamp; 696 rc = paParms[2].getUInt64 (&u64Timestamp); 697 if (RT_FAILURE(rc)) 698 RTPrintf("Failed to get the timestamp for property '%s'\n", 699 getProperties[i].pcszName); 700 if ( RT_SUCCESS(rc) 701 && (u64Timestamp != getProperties[i].u64Timestamp) 702 ) 703 { 704 RTPrintf("Bad timestamp %llu for property '%s', expected %llu.\n", 705 u64Timestamp, getProperties[i].pcszName, 706 getProperties[i].u64Timestamp); 707 rc = VERR_UNRESOLVED_ERROR; 708 } 639 uint64_t u64Timestamp = UINT64_MAX; 640 RTTESTI_CHECK_RC(rc2 = aParms[2].getUInt64(&u64Timestamp), VINF_SUCCESS); 641 if (u64Timestamp != s_aGetProperties[i].u64Timestamp) 642 RTTestIFailed("Bad timestamp %llu for property '%s', expected %llu.", 643 u64Timestamp, s_aGetProperties[i].pcszName, 644 s_aGetProperties[i].u64Timestamp); 709 645 } 710 646 } 711 647 } 712 return rc;713 648 } 714 649 … … 719 654 const char *pchBuffer; 720 655 /** What size should the buffer be? */ 721 uint32_t c chBuffer;722 } 723 g etNotifications[] =656 uint32_t cbBuffer; 657 } 658 g_aGetNotifications[] = 724 659 { 725 660 { "Red\0Stop!\0TRANSIENT", sizeof("Red\0Stop!\0TRANSIENT") }, … … 729 664 { "Red\0\0", sizeof("Red\0\0") }, 730 665 { "Amber\0\0", sizeof("Amber\0\0") }, 731 { NULL, 0 }732 666 }; 733 667 … … 737 671 * @note prints its own diagnostic information to stdout. 738 672 */ 739 int testGetNotification(VBOXHGCMSVCFNTABLE *pTable) 740 { 741 int rc = VINF_SUCCESS; 742 VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS }; 743 char achBuffer[MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN]; 744 static char szPattern[] = ""; 745 746 RTPrintf("Testing the GET_NOTIFICATION call.\n"); 747 uint64_t u64Timestamp; 748 uint32_t u32Size = 0; 749 VBOXHGCMSVCPARM paParms[4]; 673 static void testGetNotification(VBOXHGCMSVCFNTABLE *pTable) 674 { 675 RTTestISub("GET_NOTIFICATION"); 750 676 751 677 /* Test "buffer too small" */ 752 u64Timestamp = 1; 753 paParms[0].setPointer ((void *) szPattern, sizeof(szPattern)); 754 paParms[1].setUInt64 (u64Timestamp); 755 paParms[2].setPointer ((void *) achBuffer, getNotifications[0].cchBuffer - 1); 756 pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, 757 GET_NOTIFICATION, 4, paParms); 678 char achBuffer[MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN]; 679 static char s_szPattern[] = ""; 680 VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS }; 681 VBOXHGCMSVCPARM aParms[4]; 682 aParms[0].setPointer((void *)s_szPattern, sizeof(s_szPattern)); 683 aParms[1].setUInt64(1); 684 aParms[2].setPointer((void *)achBuffer, g_aGetNotifications[0].cbBuffer - 1); 685 pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, GET_NOTIFICATION, 4, aParms); 686 687 uint32_t cbRetNeeded; 758 688 if ( callHandle.rc != VERR_BUFFER_OVERFLOW 759 || RT_FAILURE( paParms[3].getUInt32 (&u32Size))760 || u32Size != getNotifications[0].cchBuffer689 || RT_FAILURE(aParms[3].getUInt32(&cbRetNeeded)) 690 || cbRetNeeded != g_aGetNotifications[0].cbBuffer 761 691 ) 762 692 { 763 RT Printf("Getting notification for property '%s' with a too small buffer did not fail correctly.\n",764 getNotifications[0].pchBuffer);765 r c = VERR_UNRESOLVED_ERROR;693 RTTestIFailed("Getting notification for property '%s' with a too small buffer did not fail correctly.", 694 g_aGetNotifications[0].pchBuffer); 695 return; 766 696 } 767 697 768 698 /* Test successful notification queries. Start with an unknown timestamp 769 699 * to get the oldest available notification. */ 770 u64Timestamp = 1; 771 for (unsigned i = 0; RT_SUCCESS(rc) && (getNotifications[i].pchBuffer != NULL); 772 ++i) 773 { 774 paParms[0].setPointer ((void *) szPattern, sizeof(szPattern)); 775 paParms[1].setUInt64 (u64Timestamp); 776 paParms[2].setPointer ((void *) achBuffer, sizeof(achBuffer)); 777 pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, 778 GET_NOTIFICATION, 4, paParms); 700 uint64_t u64Timestamp = 1; 701 for (unsigned i = 0; i < RT_ELEMENTS(g_aGetNotifications); ++i) 702 { 703 aParms[0].setPointer((void *)s_szPattern, sizeof(s_szPattern)); 704 aParms[1].setUInt64(u64Timestamp); 705 aParms[2].setPointer((void *)achBuffer, sizeof(achBuffer)); 706 pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, GET_NOTIFICATION, 4, aParms); 779 707 if ( RT_FAILURE(callHandle.rc) 780 708 || (i == 0 && callHandle.rc != VWRN_NOT_FOUND) 781 || RT_FAILURE( paParms[1].getUInt64(&u64Timestamp))782 || RT_FAILURE( paParms[3].getUInt32 (&u32Size))783 || u32Size != getNotifications[i].cchBuffer784 || memcmp(achBuffer, g etNotifications[i].pchBuffer, u32Size) != 0709 || RT_FAILURE(aParms[1].getUInt64(&u64Timestamp)) 710 || RT_FAILURE(aParms[3].getUInt32(&cbRetNeeded)) 711 || cbRetNeeded != g_aGetNotifications[i].cbBuffer 712 || memcmp(achBuffer, g_aGetNotifications[i].pchBuffer, cbRetNeeded) != 0 785 713 ) 786 714 { 787 RTPrintf("Failed to get notification for property '%s' (rc=%Rrc).\n", 788 getNotifications[i].pchBuffer, rc); 789 rc = VERR_UNRESOLVED_ERROR; 790 } 791 } 792 return rc; 715 RTTestIFailed("Failed to get notification for property '%s' (rc=%Rrc).", 716 g_aGetNotifications[i].pchBuffer, callHandle.rc); 717 } 718 } 793 719 } 794 720 … … 799 725 VBOXHGCMSVCPARM aParms[4]; 800 726 /** Result buffer */ 801 char chBuffer[MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN];727 char abBuffer[MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN]; 802 728 /** Return value */ 803 729 VBOXHGCMCALLHANDLE_TYPEDEF callHandle; 804 } asyncNotification;730 } g_AsyncNotification; 805 731 806 732 /** 807 733 * Set up the test for the asynchronous GET_NOTIFICATION function. 808 * @returns iprt status value to indicate whether the test went as expected. 809 * @note prints its own diagnostic information to stdout. 810 */ 811 int setupAsyncNotification(VBOXHGCMSVCFNTABLE *pTable) 812 { 813 int rc = VINF_SUCCESS; 814 815 RTPrintf("Testing the asynchronous GET_NOTIFICATION call with no notifications are available.\n"); 816 uint64_t u64Timestamp = 0; 817 uint32_t u32Size = 0; 818 static char szPattern[] = ""; 819 820 asyncNotification.aParms[0].setPointer ((void *) szPattern, sizeof(szPattern)); 821 asyncNotification.aParms[1].setUInt64 (u64Timestamp); 822 asyncNotification.aParms[2].setPointer ((void *) asyncNotification.chBuffer, 823 sizeof(asyncNotification.chBuffer)); 824 asyncNotification.callHandle.rc = VINF_HGCM_ASYNC_EXECUTE; 825 pTable->pfnCall(pTable->pvService, &asyncNotification.callHandle, 0, NULL, 826 GET_NOTIFICATION, 4, asyncNotification.aParms); 827 if (RT_FAILURE(asyncNotification.callHandle.rc)) 828 { 829 RTPrintf("GET_NOTIFICATION call failed, rc=%Rrc.\n", asyncNotification.callHandle.rc); 830 rc = VERR_UNRESOLVED_ERROR; 831 } 832 else if (asyncNotification.callHandle.rc != VINF_HGCM_ASYNC_EXECUTE) 833 { 834 RTPrintf("GET_NOTIFICATION call completed when no new notifications should be available.\n"); 835 rc = VERR_UNRESOLVED_ERROR; 836 } 837 return rc; 734 */ 735 static void setupAsyncNotification(VBOXHGCMSVCFNTABLE *pTable) 736 { 737 RTTestISub("Asynchronous GET_NOTIFICATION call with no notifications are available"); 738 static char s_szPattern[] = ""; 739 740 g_AsyncNotification.aParms[0].setPointer((void *)s_szPattern, sizeof(s_szPattern)); 741 g_AsyncNotification.aParms[1].setUInt64(0); 742 g_AsyncNotification.aParms[2].setPointer((void *)g_AsyncNotification.abBuffer, 743 sizeof(g_AsyncNotification.abBuffer)); 744 g_AsyncNotification.callHandle.rc = VINF_HGCM_ASYNC_EXECUTE; 745 pTable->pfnCall(pTable->pvService, &g_AsyncNotification.callHandle, 0, NULL, 746 GET_NOTIFICATION, 4, g_AsyncNotification.aParms); 747 if (RT_FAILURE(g_AsyncNotification.callHandle.rc)) 748 RTTestIFailed("GET_NOTIFICATION call failed, rc=%Rrc.", g_AsyncNotification.callHandle.rc); 749 else if (g_AsyncNotification.callHandle.rc != VINF_HGCM_ASYNC_EXECUTE) 750 RTTestIFailed("GET_NOTIFICATION call completed when no new notifications should be available."); 838 751 } 839 752 840 753 /** 841 754 * Test the asynchronous GET_NOTIFICATION function. 842 * @returns iprt status value to indicate whether the test went as expected. 843 * @note prints its own diagnostic information to stdout. 844 */ 845 int testAsyncNotification(VBOXHGCMSVCFNTABLE *pTable) 846 { 847 int rc = VINF_SUCCESS; 755 */ 756 static void testAsyncNotification(VBOXHGCMSVCFNTABLE *pTable) 757 { 848 758 uint64_t u64Timestamp; 849 759 uint32_t u32Size; 850 if ( asyncNotification.callHandle.rc != VINF_SUCCESS851 || RT_FAILURE( asyncNotification.aParms[1].getUInt64(&u64Timestamp))852 || RT_FAILURE( asyncNotification.aParms[3].getUInt32(&u32Size))853 || u32Size != g etNotifications[0].cchBuffer854 || memcmp( asyncNotification.chBuffer, getNotifications[0].pchBuffer, u32Size) != 0760 if ( g_AsyncNotification.callHandle.rc != VINF_SUCCESS 761 || RT_FAILURE(g_AsyncNotification.aParms[1].getUInt64(&u64Timestamp)) 762 || RT_FAILURE(g_AsyncNotification.aParms[3].getUInt32(&u32Size)) 763 || u32Size != g_aGetNotifications[0].cbBuffer 764 || memcmp(g_AsyncNotification.abBuffer, g_aGetNotifications[0].pchBuffer, u32Size) != 0 855 765 ) 856 766 { 857 RTPrintf("Asynchronous GET_NOTIFICATION call did not complete as expected, rc=%Rrc\n", 858 asyncNotification.callHandle.rc); 859 rc = VERR_UNRESOLVED_ERROR; 860 } 861 return rc; 862 } 863 864 /** Array of properties for testing SET_PROP_HOST and _GUEST with the 865 * READONLYGUEST global flag set. */ 866 static const struct 867 { 868 /** Property name */ 869 const char *pcszName; 870 /** Property value */ 871 const char *pcszValue; 872 /** Property flags */ 873 const char *pcszFlags; 874 /** Should this be set as the host or the guest? */ 875 bool isHost; 876 /** Should we use SET_PROP or SET_PROP_VALUE? */ 877 bool useSetProp; 878 /** Should this succeed or be rejected with VERR_ (NOT VINF_!) 879 * PERMISSION_DENIED? The global check is done after the property one. */ 880 bool isAllowed; 881 } 882 setPropertiesROGuest[] = 883 { 884 { "Red", "Stop!", "transient", false, true, true }, 885 { "Amber", "Caution!", "", false, false, true }, 886 { "Green", "Go!", "readonly", true, true, true }, 887 { "Blue", "What on earth...?", "", true, false, true }, 888 { "/test/name", "test", "", false, true, true }, 889 { "TEST NAME", "test", "", true, true, true }, 890 { "Green", "gone out...", "", false, false, false }, 891 { "Green", "gone out....", "", true, false, false }, 892 { NULL, NULL, NULL, false, false, true } 893 }; 767 RTTestIFailed("Asynchronous GET_NOTIFICATION call did not complete as expected, rc=%Rrc.", 768 g_AsyncNotification.callHandle.rc); 769 } 770 } 771 772 773 static void test2(void) 774 { 775 VBOXHGCMSVCFNTABLE svcTable; 776 VBOXHGCMSVCHELPERS svcHelpers; 777 initTable(&svcTable, &svcHelpers); 778 779 /* The function is inside the service, not HGCM. */ 780 RTTESTI_CHECK_RC_OK_RETV(VBoxHGCMSvcLoad(&svcTable)); 781 782 testSetPropsHost(&svcTable); 783 testEnumPropsHost(&svcTable); 784 785 /* Set up the asynchronous notification test */ 786 setupAsyncNotification(&svcTable); 787 testSetProp(&svcTable); 788 RTTestISub("Checking the data returned by the asynchronous notification call"); 789 testAsyncNotification(&svcTable); /* Our previous notification call should have completed by now. */ 790 791 testDelProp(&svcTable); 792 testGetProp(&svcTable); 793 testGetNotification(&svcTable); 794 795 /* Cleanup */ 796 RTTESTI_CHECK_RC_OK(svcTable.pfnUnload(svcTable.pvService)); 797 } 894 798 895 799 /** … … 900 804 * @param eFlags the flags to set 901 805 */ 902 int doSetGlobalFlags(VBOXHGCMSVCFNTABLE *pTable, ePropFlags eFlags)806 static int doSetGlobalFlags(VBOXHGCMSVCFNTABLE *pTable, ePropFlags eFlags) 903 807 { 904 808 VBOXHGCMSVCPARM paParm; 905 809 paParm.setUInt32(eFlags); 906 int rc = pTable->pfnHostCall(pTable->pvService, SET_GLOBAL_FLAGS_HOST, 907 1, &paParm); 810 int rc = pTable->pfnHostCall(pTable->pvService, SET_GLOBAL_FLAGS_HOST, 1, &paParm); 908 811 if (RT_FAILURE(rc)) 909 812 { 910 813 char szFlags[MAX_FLAGS_LEN]; 911 814 if (RT_FAILURE(writeFlags(eFlags, szFlags))) 912 RT Printf("Failed to set the global flags.\n");815 RTTestIFailed("Failed to set the global flags."); 913 816 else 914 RTPrintf("Failed to set the global flags \"%s\".\n", 915 szFlags); 817 RTTestIFailed("Failed to set the global flags \"%s\".", szFlags); 916 818 } 917 819 return rc; … … 924 826 * @note prints its own diagnostic information to stdout. 925 827 */ 926 int testSetPropROGuest(VBOXHGCMSVCFNTABLE *pTable) 927 { 928 int rc = VINF_SUCCESS; 929 RTPrintf("Testing the SET_PROP, SET_PROP_VALUE, SET_PROP_HOST and SET_PROP_VALUE_HOST calls with READONLYGUEST set globally.\n"); 930 rc = VBoxHGCMSvcLoad(pTable); 931 if (RT_FAILURE(rc)) 932 RTPrintf("Failed to start the HGCM service.\n"); 828 static void testSetPropROGuest(VBOXHGCMSVCFNTABLE *pTable) 829 { 830 RTTestISub("SET_PROP, SET_PROP_VALUE, SET_PROP_HOST and SET_PROP_VALUE_HOST calls with READONLYGUEST set globally"); 831 832 /** Array of properties for testing SET_PROP_HOST and _GUEST with the 833 * READONLYGUEST global flag set. */ 834 static const struct 835 { 836 /** Property name */ 837 const char *pcszName; 838 /** Property value */ 839 const char *pcszValue; 840 /** Property flags */ 841 const char *pcszFlags; 842 /** Should this be set as the host or the guest? */ 843 bool isHost; 844 /** Should we use SET_PROP or SET_PROP_VALUE? */ 845 bool useSetProp; 846 /** Should this succeed or be rejected with VERR_ (NOT VINF_!) 847 * PERMISSION_DENIED? The global check is done after the property one. */ 848 bool isAllowed; 849 } 850 s_aSetPropertiesROGuest[] = 851 { 852 { "Red", "Stop!", "transient", false, true, true }, 853 { "Amber", "Caution!", "", false, false, true }, 854 { "Green", "Go!", "readonly", true, true, true }, 855 { "Blue", "What on earth...?", "", true, false, true }, 856 { "/test/name", "test", "", false, true, true }, 857 { "TEST NAME", "test", "", true, true, true }, 858 { "Green", "gone out...", "", false, false, false }, 859 { "Green", "gone out....", "", true, false, false }, 860 }; 861 862 RTTESTI_CHECK_RC_OK_RETV(VBoxHGCMSvcLoad(pTable)); 863 int rc = doSetGlobalFlags(pTable, RDONLYGUEST); 933 864 if (RT_SUCCESS(rc)) 934 rc = doSetGlobalFlags(pTable, RDONLYGUEST); 935 for (unsigned i = 0; RT_SUCCESS(rc) && (setPropertiesROGuest[i].pcszName != NULL); 936 ++i) 937 { 938 rc = doSetProperty(pTable, setPropertiesROGuest[i].pcszName, 939 setPropertiesROGuest[i].pcszValue, 940 setPropertiesROGuest[i].pcszFlags, 941 setPropertiesROGuest[i].isHost, 942 setPropertiesROGuest[i].useSetProp); 943 if (setPropertiesROGuest[i].isAllowed && RT_FAILURE(rc)) 944 RTPrintf("Setting property '%s' to '%s' failed with rc=%Rrc.\n", 945 setPropertiesROGuest[i].pcszName, 946 setPropertiesROGuest[i].pcszValue, rc); 947 else if ( !setPropertiesROGuest[i].isAllowed 948 && (rc != VERR_PERMISSION_DENIED)) 949 { 950 RTPrintf("Setting property '%s' to '%s' returned %Rrc instead of VERR_PERMISSION_DENIED.\n", 951 setPropertiesROGuest[i].pcszName, 952 setPropertiesROGuest[i].pcszValue, rc); 953 rc = VERR_IPE_UNEXPECTED_STATUS; 954 } 955 else if ( !setPropertiesROGuest[i].isHost 956 && setPropertiesROGuest[i].isAllowed 957 && (rc != VINF_PERMISSION_DENIED)) 958 { 959 RTPrintf("Setting property '%s' to '%s' returned %Rrc instead of VINF_PERMISSION_DENIED.\n", 960 setPropertiesROGuest[i].pcszName, 961 setPropertiesROGuest[i].pcszValue, rc); 962 rc = VERR_IPE_UNEXPECTED_STATUS; 963 } 964 else 965 rc = VINF_SUCCESS; 966 } 967 if (RT_FAILURE(pTable->pfnUnload(pTable->pvService))) 968 RTPrintf("Failed to unload the HGCM service.\n"); 969 return rc; 970 } 971 972 /** Array of properties for testing DEL_PROP_HOST and _GUEST with 973 * READONLYGUEST set globally. */ 974 static const struct 975 { 976 /** Property name */ 977 const char *pcszName; 978 /** Should this be deleted as the host (or the guest)? */ 979 bool isHost; 980 /** Should this property be created first? (As host, obviously) */ 981 bool shouldCreate; 982 /** And with what flags? */ 983 const char *pcszFlags; 984 /** Should this succeed or be rejected with VERR_ (NOT VINF_!) 985 * PERMISSION_DENIED? The global check is done after the property one. */ 986 bool isAllowed; 987 } 988 delPropertiesROGuest[] = 989 { 990 { "Red", true, true, "", true }, 991 { "Amber", false, true, "", true }, 992 { "Red2", true, false, "", true }, 993 { "Amber2", false, false, "", true }, 994 { "Red3", true, true, "READONLY", false }, 995 { "Amber3", false, true, "READONLY", false }, 996 { "Red4", true, true, "RDONLYHOST", false }, 997 { "Amber4", false, true, "RDONLYHOST", true }, 998 { NULL, false, false, "", false } 999 }; 865 { 866 for (unsigned i = 0; i < RT_ELEMENTS(s_aSetPropertiesROGuest); ++i) 867 { 868 rc = doSetProperty(pTable, s_aSetPropertiesROGuest[i].pcszName, 869 s_aSetPropertiesROGuest[i].pcszValue, 870 s_aSetPropertiesROGuest[i].pcszFlags, 871 s_aSetPropertiesROGuest[i].isHost, 872 s_aSetPropertiesROGuest[i].useSetProp); 873 if (s_aSetPropertiesROGuest[i].isAllowed && RT_FAILURE(rc)) 874 RTTestIFailed("Setting property '%s' to '%s' failed with rc=%Rrc.", 875 s_aSetPropertiesROGuest[i].pcszName, 876 s_aSetPropertiesROGuest[i].pcszValue, rc); 877 else if ( !s_aSetPropertiesROGuest[i].isAllowed 878 && rc != VERR_PERMISSION_DENIED) 879 RTTestIFailed("Setting property '%s' to '%s' returned %Rrc instead of VERR_PERMISSION_DENIED.\n", 880 s_aSetPropertiesROGuest[i].pcszName, 881 s_aSetPropertiesROGuest[i].pcszValue, rc); 882 else if ( !s_aSetPropertiesROGuest[i].isHost 883 && s_aSetPropertiesROGuest[i].isAllowed 884 && rc != VINF_PERMISSION_DENIED) 885 RTTestIFailed("Setting property '%s' to '%s' returned %Rrc instead of VINF_PERMISSION_DENIED.\n", 886 s_aSetPropertiesROGuest[i].pcszName, 887 s_aSetPropertiesROGuest[i].pcszValue, rc); 888 } 889 } 890 RTTESTI_CHECK_RC_OK(pTable->pfnUnload(pTable->pvService)); 891 } 1000 892 1001 893 /** … … 1004 896 * @note prints its own diagnostic information to stdout. 1005 897 */ 1006 int testDelPropROGuest(VBOXHGCMSVCFNTABLE *pTable) 1007 { 1008 int rc = VINF_SUCCESS; 1009 RTPrintf("Testing the DEL_PROP and DEL_PROP_HOST calls with RDONLYGUEST set globally.\n"); 1010 rc = VBoxHGCMSvcLoad(pTable); 1011 if (RT_FAILURE(rc)) 1012 RTPrintf("Failed to start the HGCM service.\n"); 898 static void testDelPropROGuest(VBOXHGCMSVCFNTABLE *pTable) 899 { 900 RTTestISub("DEL_PROP and DEL_PROP_HOST calls with RDONLYGUEST set globally"); 901 902 /** Array of properties for testing DEL_PROP_HOST and _GUEST with 903 * READONLYGUEST set globally. */ 904 static const struct 905 { 906 /** Property name */ 907 const char *pcszName; 908 /** Should this be deleted as the host (or the guest)? */ 909 bool isHost; 910 /** Should this property be created first? (As host, obviously) */ 911 bool shouldCreate; 912 /** And with what flags? */ 913 const char *pcszFlags; 914 /** Should this succeed or be rejected with VERR_ (NOT VINF_!) 915 * PERMISSION_DENIED? The global check is done after the property one. */ 916 bool isAllowed; 917 } 918 s_aDelPropertiesROGuest[] = 919 { 920 { "Red", true, true, "", true }, 921 { "Amber", false, true, "", true }, 922 { "Red2", true, false, "", true }, 923 { "Amber2", false, false, "", true }, 924 { "Red3", true, true, "READONLY", false }, 925 { "Amber3", false, true, "READONLY", false }, 926 { "Red4", true, true, "RDONLYHOST", false }, 927 { "Amber4", false, true, "RDONLYHOST", true }, 928 }; 929 930 RTTESTI_CHECK_RC_OK_RETV(VBoxHGCMSvcLoad(pTable)); 931 int rc = doSetGlobalFlags(pTable, RDONLYGUEST); 1013 932 if (RT_SUCCESS(rc)) 1014 rc = doSetGlobalFlags(pTable, RDONLYGUEST); 1015 for (unsigned i = 0; RT_SUCCESS(rc) 1016 && (delPropertiesROGuest[i].pcszName != NULL); ++i) 1017 { 1018 if (RT_SUCCESS(rc) && delPropertiesROGuest[i].shouldCreate) 1019 rc = doSetProperty(pTable, delPropertiesROGuest[i].pcszName, 1020 "none", delPropertiesROGuest[i].pcszFlags, 1021 true, true); 1022 rc = doDelProp(pTable, delPropertiesROGuest[i].pcszName, 1023 delPropertiesROGuest[i].isHost); 1024 if (delPropertiesROGuest[i].isAllowed && RT_FAILURE(rc)) 1025 RTPrintf("Deleting property '%s' failed with rc=%Rrc.\n", 1026 delPropertiesROGuest[i].pcszName, rc); 1027 else if ( !delPropertiesROGuest[i].isAllowed 1028 && (rc != VERR_PERMISSION_DENIED) 1029 ) 1030 { 1031 RTPrintf("Deleting property '%s' returned %Rrc instead of VERR_PERMISSION_DENIED.\n", 1032 delPropertiesROGuest[i].pcszName, rc); 1033 rc = VERR_IPE_UNEXPECTED_STATUS; 1034 } 1035 else if ( !delPropertiesROGuest[i].isHost 1036 && delPropertiesROGuest[i].shouldCreate 1037 && delPropertiesROGuest[i].isAllowed 1038 && (rc != VINF_PERMISSION_DENIED)) 1039 { 1040 RTPrintf("Deleting property '%s' as guest returned %Rrc instead of VINF_PERMISSION_DENIED.\n", 1041 delPropertiesROGuest[i].pcszName, rc); 1042 rc = VERR_IPE_UNEXPECTED_STATUS; 1043 } 1044 else 1045 rc = VINF_SUCCESS; 1046 } 1047 if (RT_FAILURE(pTable->pfnUnload(pTable->pvService))) 1048 RTPrintf("Failed to unload the HGCM service.\n"); 1049 return rc; 1050 } 1051 1052 int main(int argc, char **argv) 933 { 934 for (unsigned i = 0; i < RT_ELEMENTS(s_aDelPropertiesROGuest); ++i) 935 { 936 if (s_aDelPropertiesROGuest[i].shouldCreate) 937 rc = doSetProperty(pTable, s_aDelPropertiesROGuest[i].pcszName, 938 "none", s_aDelPropertiesROGuest[i].pcszFlags, 939 true, true); 940 rc = doDelProp(pTable, s_aDelPropertiesROGuest[i].pcszName, 941 s_aDelPropertiesROGuest[i].isHost); 942 if (s_aDelPropertiesROGuest[i].isAllowed && RT_FAILURE(rc)) 943 RTTestIFailed("Deleting property '%s' failed with rc=%Rrc.", 944 s_aDelPropertiesROGuest[i].pcszName, rc); 945 else if ( !s_aDelPropertiesROGuest[i].isAllowed 946 && rc != VERR_PERMISSION_DENIED) 947 RTTestIFailed("Deleting property '%s' returned %Rrc instead of VERR_PERMISSION_DENIED.", 948 s_aDelPropertiesROGuest[i].pcszName, rc); 949 else if ( !s_aDelPropertiesROGuest[i].isHost 950 && s_aDelPropertiesROGuest[i].shouldCreate 951 && s_aDelPropertiesROGuest[i].isAllowed 952 && rc != VINF_PERMISSION_DENIED) 953 RTTestIFailed("Deleting property '%s' as guest returned %Rrc instead of VINF_PERMISSION_DENIED.", 954 s_aDelPropertiesROGuest[i].pcszName, rc); 955 } 956 } 957 RTTESTI_CHECK_RC_OK(pTable->pfnUnload(pTable->pvService)); 958 } 959 960 static void test3(void) 1053 961 { 1054 962 VBOXHGCMSVCFNTABLE svcTable; 1055 963 VBOXHGCMSVCHELPERS svcHelpers; 1056 RTEXITCODE rcExit; 1057 1058 rcExit = RTTestInitAndCreate("tstGuestPropSvc", &g_hTest); 964 initTable(&svcTable, &svcHelpers); 965 testSetPropROGuest(&svcTable); 966 testDelPropROGuest(&svcTable); 967 } 968 969 970 static void test4(void) 971 { 972 RTTestISub("Max properties"); 973 974 VBOXHGCMSVCFNTABLE svcTable; 975 VBOXHGCMSVCHELPERS svcHelpers; 976 initTable(&svcTable, &svcHelpers); 977 RTTESTI_CHECK_RC_OK_RETV(VBoxHGCMSvcLoad(&svcTable)); 978 979 /* Insert the max number of properties. */ 980 static char const s_szPropFmt[] = "/MyProperties/Sub/Sub/Sub/Sub/Sub/Sub/Sub/PropertyNo#%u"; 981 char szProp[80]; 982 unsigned cProps = 0; 983 for (;;) 984 { 985 RTStrPrintf(szProp, sizeof(szProp), s_szPropFmt, cProps); 986 int rc = doSetProperty(&svcTable, szProp, "myvalue", "", true, true); 987 if (rc == VERR_TOO_MUCH_DATA) 988 break; 989 if (RT_FAILURE(rc)) 990 { 991 RTTestIFailed("Unexpected error %Rrc setting property number %u", rc, cProps); 992 break; 993 } 994 cProps++; 995 } 996 RTTestIValue("Max Properties", cProps, RTTESTUNIT_OCCURRENCES); 997 998 /* Touch them all again. */ 999 for (unsigned iProp = 0; iProp < cProps; iProp++) 1000 { 1001 RTStrPrintf(szProp, sizeof(szProp), s_szPropFmt, iProp); 1002 int rc; 1003 RTTESTI_CHECK_MSG((rc = doSetProperty(&svcTable, szProp, "myvalue", "", true, true)) == VINF_SUCCESS, 1004 ("%Rrc - #%u\n", rc, iProp)); 1005 RTTESTI_CHECK_MSG((rc = doSetProperty(&svcTable, szProp, "myvalue", "", true, false)) == VINF_SUCCESS, 1006 ("%Rrc - #%u\n", rc, iProp)); 1007 RTTESTI_CHECK_MSG((rc = doSetProperty(&svcTable, szProp, "myvalue", "", false, true)) == VINF_SUCCESS, 1008 ("%Rrc - #%u\n", rc, iProp)); 1009 RTTESTI_CHECK_MSG((rc = doSetProperty(&svcTable, szProp, "myvalue", "", false, false)) == VINF_SUCCESS, 1010 ("%Rrc - #%u\n", rc, iProp)); 1011 } 1012 1013 /* Benchmark. */ 1014 uint64_t cNsMax = 0; 1015 uint64_t cNsMin = UINT64_MAX; 1016 uint64_t cNsAvg = 0; 1017 for (unsigned iProp = 0; iProp < cProps; iProp++) 1018 { 1019 size_t cchProp = RTStrPrintf(szProp, sizeof(szProp), s_szPropFmt, iProp); 1020 1021 uint64_t cNsElapsed = RTTimeNanoTS(); 1022 unsigned iCall; 1023 for (iCall = 0; iCall < 1000; iCall++) 1024 { 1025 VBOXHGCMSVCPARM aParms[4]; 1026 char szBuffer[256]; 1027 aParms[0].setPointer(szProp, cchProp + 1); 1028 aParms[1].setPointer(szBuffer, sizeof(szBuffer)); 1029 RTTESTI_CHECK_RC_BREAK(svcTable.pfnHostCall(svcTable.pvService, GET_PROP_HOST, 4, aParms), VINF_SUCCESS); 1030 } 1031 cNsElapsed = RTTimeNanoTS() - cNsElapsed; 1032 if (iCall) 1033 { 1034 uint64_t cNsPerCall = cNsElapsed / iCall; 1035 cNsAvg += cNsPerCall; 1036 if (cNsPerCall < cNsMin) 1037 cNsMin = cNsPerCall; 1038 if (cNsPerCall > cNsMax) 1039 cNsMax = cNsPerCall; 1040 } 1041 } 1042 if (cProps) 1043 cNsAvg /= cProps; 1044 RTTestIValue("GET_PROP_HOST Min", cNsMin, RTTESTUNIT_NS_PER_CALL); 1045 RTTestIValue("GET_PROP_HOST Avg", cNsAvg, RTTESTUNIT_NS_PER_CALL); 1046 RTTestIValue("GET_PROP_HOST Max", cNsMax, RTTESTUNIT_NS_PER_CALL); 1047 1048 /* Done. */ 1049 RTTESTI_CHECK_RC_OK(svcTable.pfnUnload(svcTable.pvService)); 1050 } 1051 1052 1053 int main(int argc, char **argv) 1054 { 1055 RTEXITCODE rcExit = RTTestInitAndCreate("tstGuestPropSvc", &g_hTest); 1059 1056 if (rcExit != RTEXITCODE_SUCCESS) 1060 1057 return rcExit; 1061 1058 RTTestBanner(g_hTest); 1062 1059 1063 /** @todo convert the rest of this testcase. */ 1064 initTable(&svcTable, &svcHelpers); 1065 1066 if (RT_FAILURE(testConvertFlags())) 1067 return 1; 1068 /* The function is inside the service, not HGCM. */ 1069 if (RT_FAILURE(VBoxHGCMSvcLoad(&svcTable))) 1070 { 1071 RTPrintf("Failed to start the HGCM service.\n"); 1072 return 1; 1073 } 1074 if (RT_FAILURE(testSetPropsHost(&svcTable))) 1075 return 1; 1076 if (RT_FAILURE(testEnumPropsHost(&svcTable))) 1077 return 1; 1078 /* Set up the asynchronous notification test */ 1079 if (RT_FAILURE(setupAsyncNotification(&svcTable))) 1080 return 1; 1081 if (RT_FAILURE(testSetProp(&svcTable))) 1082 return 1; 1083 RTPrintf("Checking the data returned by the asynchronous notification call.\n"); 1084 /* Our previous notification call should have completed by now. */ 1085 if (RT_FAILURE(testAsyncNotification(&svcTable))) 1086 return 1; 1087 if (RT_FAILURE(testDelProp(&svcTable))) 1088 return 1; 1089 if (RT_FAILURE(testGetProp(&svcTable))) 1090 return 1; 1091 if (RT_FAILURE(testGetNotification(&svcTable))) 1092 return 1; 1093 if (RT_FAILURE(svcTable.pfnUnload(svcTable.pvService))) 1094 { 1095 RTPrintf("Failed to unload the HGCM service.\n"); 1096 return 1; 1097 } 1098 if (RT_FAILURE(testSetPropROGuest(&svcTable))) 1099 return 1; 1100 if (RT_FAILURE(testDelPropROGuest(&svcTable))) 1101 return 1; 1060 testConvertFlags(); 1061 test2(); 1062 test3(); 1063 test4(); 1102 1064 1103 1065 return RTTestSummaryAndDestroy(g_hTest);
Note:
See TracChangeset
for help on using the changeset viewer.