VirtualBox

Changeset 13759

Show
Ignore:
Timestamp:
11/03/08 17:13:04 (2 months ago)
Author:
vboxsync
Message:

Guest Properties (HostServices? and Main): major clean up of the guest property service

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/include/VBox/HostServices/GuestPropertySvc.h

    r13574 r13759  
    148148                break; 
    149149        if (RT_ELEMENTS(flagList) == i) 
    150              rc = VERR_INVALID_PARAMETER; 
     150             rc = VERR_PARSE_ERROR; 
    151151        else 
    152152        { 
     
    157157            if (',' == *pcszNext) 
    158158                ++pcszNext; 
     159            else if (*pcszNext != '\0') 
     160                rc = VERR_PARSE_ERROR; 
    159161            while (' ' == *pcszNext) 
    160162                ++pcszNext; 
     
    189191        for (; i < RT_ELEMENTS(flagList); ++i) 
    190192        { 
    191             if (fFlags & flagList[i]
     193            if (flagList[i] == (fFlags & flagList[i])
    192194            { 
    193195                strcpy(pszNext, flagName(flagList[i])); 
     
    213215enum eHostFn 
    214216{ 
    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, 
    217224    /** 
    218225     * Get the value attached to a guest property 
  • trunk/src/VBox/HostServices/GuestProperties/service.cpp

    r13574 r13759  
    4747 
    4848#include <memory>  /* for auto_ptr */ 
     49#include <string> 
     50#include <list> 
    4951 
    5052#include <iprt/err.h> 
     
    5961#include <VBox/log.h> 
    6062 
    61 #include <VBox/cfgm.h> 
    62  
    6363/******************************************************************************* 
    6464*   Internal functions                                                         * 
     
    7777} 
    7878 
     79/** Extract a constant pointer value from an HGCM parameter structure */ 
     80static 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 
    7992/** Set a uint32_t value to an HGCM parameter structure */ 
    8093static void VBoxHGCMParmUInt32Set (VBOXHGCMSVCPARM *pParm, uint32_t u32) 
     
    8497} 
    8598 
    86  
    8799/** Set a uint64_t value to an HGCM parameter structure */ 
    88100static void VBoxHGCMParmUInt64Set (VBOXHGCMSVCPARM *pParm, uint64_t u64) 
     
    90102    pParm->type = VBOX_HGCM_SVC_PARM_64BIT; 
    91103    pParm->u.uint64 = u64; 
     104} 
     105 
     106/** Set a pointer value to an HGCM parameter structure */ 
     107static 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; 
    92112} 
    93113 
     
    104124    /** HGCM helper functions. */ 
    105125    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; 
    112152    /** @todo we should have classes for thread and request handler thread */ 
    113153    /** Queue of outstanding property change notifications */ 
     
    125165public: 
    126166    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), 
    129168          mpvHostData(NULL) 
    130169    { 
    131170        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 
    134177        if (RT_FAILURE(rc)) 
    135178            throw rc; 
     
    210253    static DECLCALLBACK(int) reqThreadFn(RTTHREAD ThreadSelf, void *pvUser); 
    211254    int validateName(const char *pszName, uint32_t cbName); 
    212     int validateValue(char *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[]); 
    214257    int getProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 
    215258    int setProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest); 
     
    286329 * @thread  HGCM 
    287330 */ 
    288 int Service::validateValue(char *pszValue, uint32_t cbValue) 
     331int Service::validateValue(const char *pszValue, uint32_t cbValue) 
    289332{ 
    290333    LogFlowFunc(("cbValue=%d\n", cbValue)); 
     
    305348} 
    306349 
     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 */ 
     359int 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} 
    307439 
    308440/** 
     
    318450 * @thread  HGCM 
    319451 */ 
    320 int Service::getPropValue(uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 
     452int Service::getProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 
    321453{ 
    322454    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; 
    373457    uint32_t cchName, cchBuf; 
    374     size_t cchValue, cchFlags, cchBufActual; 
     458    size_t cchFlags, cchBufActual; 
    375459    char szFlags[MAX_FLAGS_LEN]; 
    376460    uint32_t fFlags; 
     
    380464     */ 
    381465    LogFlowThisFunc(("\n")); 
    382     AssertReturn(VALID_PTR(mpValueNode), VERR_WRONG_ORDER);  /* a.k.a. VERR_NOT_INITIALIZED */ 
    383466    if (   (cParms != 4)  /* Hardcoded value as the next lines depend on it. */ 
    384467        || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR)    /* name */ 
     
    387470        rc = VERR_INVALID_PARAMETER; 
    388471    if (RT_SUCCESS(rc)) 
    389         rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszName, &cchName); 
     472        rc = VBoxHGCMParmPtrConstGet(&paParms[0], (const void **) &pcszName, &cchName); 
    390473    if (RT_SUCCESS(rc)) 
    391474        rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pchBuf, &cchBuf); 
    392475    if (RT_SUCCESS(rc)) 
    393         rc = validateName(pszName, cchName); 
     476        rc = validateName(pcszName, cchName); 
    394477 
    395478    /* 
     
    398481 
    399482    /* 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); 
    407496    if (RT_SUCCESS(rc)) 
    408497        cchFlags = strlen(szFlags); 
     
    410499    if (RT_SUCCESS(rc)) 
    411500    { 
    412         cchBufActual = cchValue + cchFlags; 
     501        cchBufActual = it->mValue.size() + 1 + cchFlags; 
    413502        VBoxHGCMParmUInt32Set(&paParms[3], cchBufActual); 
    414503    } 
    415504    if (RT_SUCCESS(rc) && (cchBufActual > cchBuf)) 
    416505        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    } 
    428514 
    429515    /* 
     
    431517     */ 
    432518    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)); 
    438521    LogFlowThisFunc(("rc = %Rrc\n", rc)); 
    439522    return rc; 
    440523} 
    441524 
    442  
    443525/** 
    444526 * 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 */ 
     536int 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 */ 
     641int 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 
    445695 * of the arguments passed. 
    446696 * 
     
    450700 * @thread  HGCM 
    451701 */ 
    452 int Service::setProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest
     702int Service::enumProps(uint32_t cParms, VBOXHGCMSVCPARM paParms[]
    453703{ 
    454704    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; 
    459711    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 */ 
    480717       ) 
    481718        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 allowed 
    496      * 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 value 
    520      */ 
    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 state 
    534          * 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 validity 
    558  * of the arguments passed. 
    559  * 
    560  * @returns iprt status value 
    561  * @param   cParms  the number of HGCM parameters supplied 
    562  * @param   paParms the array of HGCM parameters 
    563  * @thread  HGCM 
    564  */ 
    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 allowed 
    588      * 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 validity 
    615  * of the arguments passed. 
    616  * 
    617  * @returns iprt status value 
    618  * @param   cParms  the number of HGCM parameters supplied 
    619  * @param   paParms the array of HGCM parameters 
    620  * @thread  HGCM 
    621  */ 
    622 int Service::enumProps(uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 
    623 { 
    624     /* We reallocate the temporary buffer in which we build up our array in 
    625      * increments of size BLOCK: */ 
    626     enum 
    627     { 
    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 % 1024 
    632     }; 
    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); 
    649719    if (RT_SUCCESS(rc) && cchPatterns > MAX_PATTERN_LEN) 
    650720        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     */ 
    657725    bool matchAll = false; 
    658726    char pszPatterns[MAX_PATTERN_LEN]; 
    659     if (   (NULL == paszPatterns) 
     727    if (   (NULL == pcchPatterns) 
    660728        || (cchPatterns < 2)  /* An empty pattern string means match all */ 
    661729       ) 
     
    664732    { 
    665733        for (unsigned i = 0; i < cchPatterns - 1; ++i) 
    666             if (paszPatterns[i] != '\0') 
    667                 pszPatterns[i] = paszPatterns[i]; 
     734            if (pcchPatterns[i] != '\0') 
     735                pszPatterns[i] = pcchPatterns[i]; 
    668736            else 
    669737                pszPatterns[i] = '|'; 
     
    671739    } 
    672740 
    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) 
    701752           ) 
    702753        { 
    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); 
    708766            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'; 
    723769        } 
    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()); 
    736780        /* 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); 
    739783        else 
    740784            rc = VERR_BUFFER_OVERFLOW; 
     
    753797void Service::notifyHost(const char *pszProperty) 
    754798{ 
    755     char szValue[MAX_VALUE_LEN]; 
    756     uint64_t u64Timestamp = 0; 
    757     uint32_t fFlags = NILFLAG; 
     799#ifndef VBOX_GUEST_PROP_TEST_NOTHREAD 
    758800    char szFlags[MAX_FLAGS_LEN]; 
    759801    char *pszName = NULL, *pszValue = NULL, *pszFlags = NULL; 
    760  
    761     AssertPtr(mpValueNode); 
     802    int rc = VINF_SUCCESS; 
     803 
    762804    if (NULL == mpfnHostCallback) 
    763805        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            } 
    766815    /* 
    767816     * First case: if the property exists then send the host its current value 
    768817     */ 
    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); 
    777821        if (RT_SUCCESS(rc)) 
    778822            rc = RTStrDupEx(&pszName, pszProperty); 
    779823        if (RT_SUCCESS(rc)) 
    780             rc = RTStrDupEx(&pszValue, szValue); 
     824            rc = RTStrDupEx(&pszValue, it->mValue.c_str()); 
    781825        if (RT_SUCCESS(rc)) 
    782826            rc = RTStrDupEx(&pszFlags, szFlags); 
     
    785829                             (PFNRT)Service::reqNotify, 7, mpfnHostCallback, 
    786830                &n