VirtualBox

Changeset 13159 in vbox


Ignore:
Timestamp:
Oct 10, 2008 10:10:36 AM (16 years ago)
Author:
vboxsync
Message:

HostServices/GuestProperties: add host notifications of property changes and clean up somewhat

Location:
trunk
Files:
2 edited

Legend:

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

    r11934 r13159  
    4646    /** Pass the address of the cfgm node used by the service as a database. */
    4747    SET_CFGM_NODE = 1,
    48     /** 
    49      * Get the value attached to a configuration property key
    50      * The parameter format matches that of GET_PROP. 
     48    /**
     49     * Get the value attached to a guest property
     50     * The parameter format matches that of GET_PROP.
    5151     */
    5252    GET_PROP_HOST = 2,
    53     /** 
    54      * Set the value attached to a configuration property key
     53    /**
     54     * Set the value attached to a guest property
    5555     * The parameter format matches that of SET_PROP.
    5656     */
    5757    SET_PROP_HOST = 3,
    58     /** 
    59      * Set the value attached to a configuration property key
     58    /**
     59     * Set the value attached to a guest property
    6060     * The parameter format matches that of SET_PROP_VALUE.
    6161     */
    6262    SET_PROP_VALUE_HOST = 4,
    63     /** 
    64      * Remove the value attached to a configuration property key
     63    /**
     64     * Remove a guest property.
    6565     * The parameter format matches that of DEL_PROP.
    6666     */
    6767    DEL_PROP_HOST = 5,
    68     /** 
     68    /**
    6969     * Enumerate guest properties.
    7070     * The parameter format matches that of ENUM_PROPS.
    7171     */
    72     ENUM_PROPS_HOST = 6
     72    ENUM_PROPS_HOST = 6,
     73    /**
     74     * Register a callback with the service which will be called when a
     75     * property is modified.  The callback is a function returning void and
     76     * taking a pointer to a HOSTCALLBACKDATA structure.
     77     */
     78    REGISTER_CALLBACK = 7
    7379};
     80
     81typedef struct _HOSTCALLBACKDATA
     82{
     83    /** Callback structure header */
     84    VBOXHGCMCALLBACKHDR hdr;
     85    /** The name of the property that was changed */
     86    const char *pcszName;
     87    /** The new property value, or NULL if the property was deleted */
     88    const char *pcszValue;
     89    /** The timestamp of the modification */
     90    uint64_t u64Timestamp;
     91    /** The flags field of the modified property */
     92    const char *pcszFlags;
     93} HOSTCALLBACKDATA, *PHOSTCALLBACKDATA;
    7494
    7595/**
     
    91111};
    92112
    93 /** Prefix for extra data keys used by the get and set key value functions */
    94 #define VBOX_SHARED_INFO_KEY_PREFIX          "Guest/"
    95 /** Helper macro for the length of the prefix VBOX_SHARED_INFO_KEY_PREFIX */
    96 #define VBOX_SHARED_INFO_PREFIX_LEN          (sizeof(VBOX_SHARED_INFO_KEY_PREFIX) - 1)
    97113/** Maximum length for property names */
    98114enum { MAX_NAME_LEN = 64 };
    99115/** Maximum length for property values */
    100116enum { MAX_VALUE_LEN = 128 };
    101 /** Maximum length for extra data key values used by the get and set key value functions */
     117/** Maximum length for the property flags field */
    102118enum { MAX_FLAGS_LEN = 128 };
    103119/** Maximum number of properties per guest */
    104 enum { MAX_KEYS = 256 };
     120enum { MAX_PROPS = 256 };
    105121
    106122/**
     
    150166
    151167    /**
    152      * The property key.  (IN pointer)
     168     * The property name.  (IN pointer)
    153169     * This must fit to a number of criteria, namely
    154170     *  - Only Utf8 strings are allowed
     
    160176    /**
    161177     * The value of the property (IN pointer)
    162      * Criteria as for the key parameter, but with length less than or equal to
     178     * Criteria as for the name parameter, but with length less than or equal to
    163179     * MAX_VALUE_LEN. 
    164180     */
     
    180196
    181197    /**
    182      * The property key.  (IN pointer)
     198     * The property name.  (IN pointer)
    183199     * This must fit to a number of criteria, namely
    184200     *  - Only Utf8 strings are allowed
     
    190206    /**
    191207     * The value of the property (IN pointer)
    192      * Criteria as for the key parameter, but with length less than or equal to
     208     * Criteria as for the name parameter, but with length less than or equal to
    193209     * MAX_VALUE_LEN. 
    194210     */
  • trunk/src/VBox/HostServices/GuestProperties/service.cpp

    r11314 r13159  
    3030 *
    3131 * The service currently consists of two threads.  One of these is the main
    32  * HGCM service thread which waits for requests from the guest and schedules
    33  * these to the second thread.  The second thread deals with the requests
    34  * sequentially by calling the callback provided by the service owner,
    35  * notifying the guest clients when it has finished dealing with a given
    36  * request.
    37  *
    38  * Guest requests to wait for notification are dealt with differently.  They
    39  * are added to a list of open notification requests but do not schedule
    40  * anything in the request thread except for a possible timeout.
     32 * HGCM service thread which deals with requests from the guest and from the
     33 * host.  The second thread sends the host asynchronous notifications of
     34 * changes made by the guest and deals with notification timeouts.
     35 *
     36 * Guest requests to wait for notification are added to a list of open
     37 * notification requests and completed when a corresponding guest property
     38 * is changed or when the request times out.
    4139 */
    4240
     
    5755#include <iprt/time.h>
    5856#include <iprt/cpputils.h>
     57#include <iprt/req.h>
     58#include <iprt/thread.h>
    5959#include <VBox/log.h>
    6060
     
    9090    pParm->type = VBOX_HGCM_SVC_PARM_64BIT;
    9191    pParm->u.uint64 = u64;
     92}
     93
     94/** Extract a callback pointer value from an HGCM parameter structure */
     95static int VBoxHGCMParmPtrGet (VBOXHGCMSVCPARM *pParm,
     96                               PFNVBOXHGCMCALLBACK *ppfnCallback,
     97                               void **ppvData)
     98{
     99    if (pParm->type == VBOX_HGCM_SVC_PARM_CALLBACK)
     100    {
     101        *ppfnCallback = pParm->u.callback.pFunction;
     102        *ppvData      = pParm->u.callback.pvData;
     103        return VINF_SUCCESS;
     104    }
     105
     106    return VERR_INVALID_PARAMETER;
    92107}
    93108
     
    111126    /** Pointer to our configuration flags node. */
    112127    PCFGMNODE mpFlagsNode;
     128    /** @todo we should have classes for thread and request handler thread */
     129    /** Queue of outstanding property change notifications */
     130    RTREQQUEUE *mReqQueue;
     131    /** Thread for processing the request queue */
     132    RTTHREAD mReqThread;
     133    /** Tell the thread that it should exit */
     134    bool mfExitThread;
     135    /** Callback function supplied by the host for notification of updates
     136     * to properties */
     137    PFNVBOXHGCMCALLBACK mpfnHostCallback;
     138    /** User data pointer to be supplied to the host callback function */
     139    void *mpvHostData;
    113140
    114141public:
    115142    explicit Service(PVBOXHGCMSVCHELPERS pHelpers)
    116143        : mpHelpers(pHelpers), mpValueNode(NULL), mpTimestampNode(NULL),
    117           mpFlagsNode(NULL) {}
     144          mpFlagsNode(NULL), mfExitThread(false), mpfnHostCallback(NULL),
     145          mpvHostData(NULL)
     146    {
     147        int rc = RTReqCreateQueue(&mReqQueue);
     148        rc = RTThreadCreate(&mReqThread, reqThreadFn, this, 0, RTTHREADTYPE_MSG_PUMP,
     149                                RTTHREADFLAGS_WAITABLE, "GuestPropReq");
     150        if (!RT_SUCCESS(rc))
     151            throw rc;
     152    }
    118153
    119154    /**
     
    125160        AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
    126161        SELF *pSelf = reinterpret_cast<SELF *>(pvService);
    127         delete pSelf;
    128         return VINF_SUCCESS;
     162        int rc = pSelf->uninit();
     163        AssertRC(rc);
     164        if (RT_SUCCESS(rc))
     165            delete pSelf;
     166        return rc;
    129167    }
    130168
     
    171209    }
    172210private:
    173     int validateKey(const char *pszKey, uint32_t cbKey);
     211    static DECLCALLBACK(int) reqThreadFn(RTTHREAD ThreadSelf, void *pvUser);
     212    int validateName(const char *pszName, uint32_t cbName);
    174213    int validateValue(char *pszValue, uint32_t cbValue);
    175     int getKey(uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
     214    int getPropValue(uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
    176215    int getProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
    177     int setKey(uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
    178     int delKey(uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
     216    int setProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
     217    int delProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
    179218    int enumProps(uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
     219    void notifyHost(const char *pszProperty);
     220    static DECLCALLBACK(int) reqNotify(PFNVBOXHGCMCALLBACK pfnCallback,
     221                                       void *pvData, char *pszName,
     222                                       char *pszValue, uint32_t u32TimeHigh,
     223                                       uint32_t u32TimeLow, char *pszFlags);
     224    /**
     225     * Empty request function for terminating the request thread.
     226     * @returns VINF_EOF to cause the request processing function to return
     227     * @todo    return something more appropriate
     228     */
     229    static DECLCALLBACK(int) reqVoid() { return VINF_EOF; }
     230
    180231    void call (VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID,
    181232               void *pvClient, uint32_t eFunction, uint32_t cParms,
    182233               VBOXHGCMSVCPARM paParms[]);
    183234    int hostCall (uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
     235    int uninit ();
    184236};
    185237
    186238
    187239/**
    188  * Checking that the key passed by the guest fits our criteria for a
    189  * configuration key.
     240 * Thread function for processing the request queue
     241 * @copydoc FNRTTHREAD
     242 */
     243DECLCALLBACK(int) Service::reqThreadFn(RTTHREAD ThreadSelf, void *pvUser)
     244{
     245    SELF *pSelf = reinterpret_cast<SELF *>(pvUser);
     246    while (!pSelf->mfExitThread)
     247        RTReqProcess(pSelf->mReqQueue, RT_INDEFINITE_WAIT);
     248    return VINF_SUCCESS;
     249}
     250
     251
     252/**
     253 * Checking that the name passed by the guest fits our criteria for a
     254 * property name.
    190255 *
    191256 * @returns IPRT status code
    192  * @param   pszKey    the key passed by the guest
    193  * @param   cbKey     the number of bytes pszKey points to, including the
     257 * @param   pszName   the name passed by the guest
     258 * @param   cbName    the number of bytes pszName points to, including the
    194259 *                    terminating '\0'
    195260 * @thread  HGCM
    196261 */
    197 int Service::validateKey(const char *pszKey, uint32_t cbKey)
    198 {
    199     LogFlowFunc(("cbKey=%d\n", cbKey));
    200 
    201     /*
    202      * Validate the key, checking that it's proper UTF-8 and has
     262int Service::validateName(const char *pszName, uint32_t cbName)
     263{
     264    LogFlowFunc(("cbName=%d\n", cbName));
     265
     266    /*
     267     * Validate the name, checking that it's proper UTF-8 and has
    203268     * a string terminator.
    204269     */
    205     int rc = RTStrValidateEncodingEx(pszKey, RT_MIN(cbKey, MAX_NAME_LEN),
     270    int rc = RTStrValidateEncodingEx(pszName, RT_MIN(cbName, (uint32_t) MAX_NAME_LEN),
    206271                                     RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED);
    207     if (RT_SUCCESS(rc) && (cbKey < 2))
     272    if (RT_SUCCESS(rc) && (cbName < 2))
    208273        rc = VERR_INVALID_PARAMETER;
    209274
     
    215280/**
    216281 * Check that the data passed by the guest fits our criteria for the value of
    217  * a configuration key.
     282 * a guest property.
    218283 *
    219284 * @returns IPRT status code
    220  * @param   pszValue  the value to store in the key
     285 * @param   pszValue  the value to store in the property
    221286 * @param   cbValue   the number of bytes in the buffer pszValue points to
    222287 * @thread  HGCM
     
    233298    int rc = VINF_SUCCESS;
    234299    if (cbValue)
    235         rc = RTStrValidateEncodingEx(pszValue, RT_MIN(cbValue, MAX_VALUE_LEN),
     300        rc = RTStrValidateEncodingEx(pszValue, RT_MIN(cbValue, (uint32_t) MAX_VALUE_LEN),
    236301                                     RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED);
    237302    if (RT_SUCCESS(rc))
     
    243308
    244309/**
    245  * Retrieve a value from the guest registry by key, checking the validity
     310 * Retrieve a value from the property registry by name, checking the validity
    246311 * of the arguments passed.  If the guest has not allocated enough buffer
    247312 * space for the value then we return VERR_OVERFLOW and set the size of the
    248  * buffer needed in the "size" HGCM parameter.  If the key was not found at
     313 * buffer needed in the "size" HGCM parameter.  If the name was not found at
    249314 * all, we return VERR_NOT_FOUND.
    250315 *
     
    254319 * @thread  HGCM
    255320 */
    256 int Service::getKey(uint32_t cParms, VBOXHGCMSVCPARM paParms[])
     321int Service::getPropValue(uint32_t cParms, VBOXHGCMSVCPARM paParms[])
    257322{
    258323    int rc = VINF_SUCCESS;
    259     char *pszKey, *pszValue;
    260     uint32_t cbKey, cbValue;
     324    char *pszName, *pszValue;
     325    uint32_t cbName, cbValue;
    261326    size_t cbValueActual;
    262327
    263328    LogFlowThisFunc(("\n"));
    264329    if (   (cParms != 3)  /* Hardcoded value as the next lines depend on it. */
    265         || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR)   /* key */
     330        || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR)   /* name */
    266331        || (paParms[1].type != VBOX_HGCM_SVC_PARM_PTR)   /* value */
    267332       )
    268333        rc = VERR_INVALID_PARAMETER;
    269334    if (RT_SUCCESS(rc))
    270         rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszKey, &cbKey);
     335        rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszName, &cbName);
    271336    if (RT_SUCCESS(rc))
    272337        rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pszValue, &cbValue);
    273338    if (RT_SUCCESS(rc))
    274         rc = validateKey(pszKey, cbKey);
    275     if (RT_SUCCESS(rc))
    276         rc = CFGMR3QuerySize(mpValueNode, pszKey, &cbValueActual);
     339        rc = validateName(pszName, cbName);
     340    if (RT_SUCCESS(rc))
     341        rc = CFGMR3QuerySize(mpValueNode, pszName, &cbValueActual);
    277342    if (RT_SUCCESS(rc))
    278343        VBoxHGCMParmUInt32Set(&paParms[2], cbValueActual);
     
    280345        rc = VERR_BUFFER_OVERFLOW;
    281346    if (RT_SUCCESS(rc))
    282         rc = CFGMR3QueryString(mpValueNode, pszKey, pszValue, cbValue);
    283     if (RT_SUCCESS(rc))
    284         Log2(("Queried string %s, rc=%Rrc, value=%.*s\n", pszKey, rc, cbValue, pszValue));
     347        rc = CFGMR3QueryString(mpValueNode, pszName, pszValue, cbValue);
     348    if (RT_SUCCESS(rc))
     349        Log2(("Queried string %s, rc=%Rrc, value=%.*s\n", pszName, rc, cbValue, pszValue));
    285350    else if (VERR_CFGM_VALUE_NOT_FOUND == rc)
    286351        rc = VERR_NOT_FOUND;
     
    291356
    292357/**
    293  * Retrieve a value from the guest registry by key, checking the validity
     358 * Retrieve a value from the property registry by name, checking the validity
    294359 * of the arguments passed.  If the guest has not allocated enough buffer
    295360 * space for the value then we return VERR_OVERFLOW and set the size of the
    296  * buffer needed in the "size" HGCM parameter.  If the key was not found at
     361 * buffer needed in the "size" HGCM parameter.  If the name was not found at
    297362 * all, we return VERR_NOT_FOUND.
    298363 *
     
    309374    size_t cchValue, cchFlags, cchBufActual;
    310375
    311 /*
    312  * Get and validate the parameters
    313  */
     376    /*
     377     * Get and validate the parameters
     378     */
    314379    LogFlowThisFunc(("\n"));
    315380    if (   (cParms != 4)  /* Hardcoded value as the next lines depend on it. */
     
    323388        rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pchBuf, &cchBuf);
    324389    if (RT_SUCCESS(rc))
    325         rc = validateKey(pszName, cchName);
     390        rc = validateName(pszName, cchName);
    326391    /* Get the value size */
    327392    if (RT_SUCCESS(rc))
    328393        rc = CFGMR3QuerySize(mpValueNode, pszName, &cchValue);
    329394
    330 /*
    331  * Read and set the values we will return
    332  */
     395    /*
     396     * Read and set the values we will return
     397     */
    333398    /* Get the flags size */
    334399    cchFlags = 1;  /* Empty string if no flags set. */
     
    358423    VBoxHGCMParmUInt64Set(&paParms[2], u64Timestamp);
    359424
    360 /*
    361  * Done!  Do exit logging and return.
    362  */
     425    /*
     426     * Done!  Do exit logging and return.
     427     */
    363428    if (RT_SUCCESS(rc))
    364429        Log2(("Queried string %S, value=%.*S, timestamp=%lld, flags=%.*S\n",
     
    373438
    374439/**
    375  * Set a value in the guest registry by key, checking the validity
     440 * Set a value in the property registry by name, checking the validity
    376441 * of the arguments passed.
    377442 *
     
    381446 * @thread  HGCM
    382447 */
    383 int Service::setKey(uint32_t cParms, VBOXHGCMSVCPARM paParms[])
     448int Service::setProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[])
    384449{
    385450    int rc = VINF_SUCCESS;
    386     char *pszKey, *pszValue;
    387     uint32_t cchKey, cchValue;
     451    char *pszName, *pszValue, *pszFlags;
     452    uint32_t cchName, cchValue, cchFlags = 0;
    388453
    389454    LogFlowThisFunc(("\n"));
    390     if (   (cParms < 2) || (cParms > 4)  /* Hardcoded value as the next lines depend on it. */
    391         || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR)   /* key */
    392         || (paParms[1].type != VBOX_HGCM_SVC_PARM_PTR)   /* value */
    393         || ((3 == cParms) && (paParms[2].type != VBOX_HGCM_SVC_PARM_PTR))
    394        )
    395         rc = VERR_INVALID_PARAMETER;
    396     if (RT_SUCCESS(rc))
    397         rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszKey, &cchKey);
    398     if (RT_SUCCESS(rc))
    399         rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pszValue, &cchValue);
    400     if (RT_SUCCESS(rc))
    401         rc = validateKey(pszKey, cchKey);
    402     if (RT_SUCCESS(rc))
    403         rc = validateValue(pszValue, cchValue);
    404     if (RT_SUCCESS(rc))
    405     {
    406         /* Limit the number of keys that we can set. */
     455    /*
     456     * First of all, make sure that we won't exceed the maximum number of properties.
     457     */
     458    {
    407459        unsigned cChildren = 0;
    408460        for (PCFGMNODE pChild = CFGMR3GetFirstChild(mpValueNode); pChild != 0; pChild = CFGMR3GetNextChild(pChild))
    409461            ++cChildren;
    410         if (cChildren >= MAX_KEYS)
     462        if (cChildren >= MAX_PROPS)
    411463            rc = VERR_TOO_MUCH_DATA;
    412464    }
     465    /*
     466     * General parameter correctness checking.
     467     */
     468    if (   RT_SUCCESS(rc)
     469        && (   (cParms < 2) || (cParms > 4)  /* Hardcoded value as the next lines depend on it. */
     470            || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR)   /* name */
     471            || (paParms[1].type != VBOX_HGCM_SVC_PARM_PTR)   /* value */
     472            || ((3 == cParms) && (paParms[2].type != VBOX_HGCM_SVC_PARM_PTR))  /* flags */
     473           )
     474       )
     475        rc = VERR_INVALID_PARAMETER;
     476    /*
     477     * And check the values passed in the parameters for correctness.
     478     */
     479    if (RT_SUCCESS(rc))
     480        rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszName, &cchName);
     481    if (RT_SUCCESS(rc))
     482        rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pszValue, &cchValue);
     483    if (RT_SUCCESS(rc))
     484        rc = validateName(pszName, cchName);
     485    if (RT_SUCCESS(rc))
     486        rc = validateValue(pszValue, cchValue);
    413487    /* For now, we do not support any flags */
    414488    if (RT_SUCCESS(rc) && (3 == cParms))
    415489    {
    416         char *pszFlags;
    417         uint32_t cchFlags = 0;
    418490        rc = VBoxHGCMParmPtrGet(&paParms[2], (void **) &pszFlags, &cchFlags);
    419491        for (size_t i = 0; (i < cchFlags - 1) && RT_SUCCESS(rc); ++i)
     
    421493                rc = VERR_INVALID_PARAMETER;
    422494    }
     495    /*
     496     * Set the actual value
     497     */
    423498    if (RT_SUCCESS(rc))
    424499    {
    425500        RTTIMESPEC time;
    426         CFGMR3RemoveValue(mpValueNode, pszKey);
     501        CFGMR3RemoveValue(mpValueNode, pszName);
    427502        if (mpTimestampNode != NULL)
    428             CFGMR3RemoveValue(mpTimestampNode, pszKey);
     503            CFGMR3RemoveValue(mpTimestampNode, pszName);
    429504        if ((3 == cParms) && (mpFlagsNode != NULL))
    430             CFGMR3RemoveValue(mpFlagsNode, pszKey);
    431         rc = CFGMR3InsertString(mpValueNode, pszKey, pszValue);
     505            CFGMR3RemoveValue(mpFlagsNode, pszName);
     506        rc = CFGMR3InsertString(mpValueNode, pszName, pszValue);
    432507        if (RT_SUCCESS(rc))
    433             rc = CFGMR3InsertInteger(mpTimestampNode, pszKey,
     508            rc = CFGMR3InsertInteger(mpTimestampNode, pszName,
    434509                                     RTTimeSpecGetNano(RTTimeNow(&time)));
    435     }
    436     if (RT_SUCCESS(rc))
    437         Log2(("Set string %s, rc=%Rrc, value=%s\n", pszKey, rc, pszValue));
     510        if (RT_SUCCESS(rc) && (3 == cParms))
     511            rc = CFGMR3InsertString(mpFlagsNode, pszName, pszFlags);
     512        /* If we are not setting flags, make sure that there are some */
     513        if (RT_SUCCESS(rc) && (mpFlagsNode != NULL) && (cParms != 3))
     514        {
     515            CFGMVALUETYPE dummy;
     516            if (   CFGMR3QueryType(mpFlagsNode, pszName, &dummy)
     517                == VERR_CFGM_VALUE_NOT_FOUND)
     518                rc = CFGMR3InsertString(mpFlagsNode, pszName, "");
     519        }
     520    }
     521    /*
     522     * Send a notification to the host and return.
     523     */
     524    if (RT_SUCCESS(rc))
     525    {
     526        notifyHost(pszName);
     527        Log2(("Set string %s, rc=%Rrc, value=%s\n", pszName, rc, pszValue));
     528    }
    438529    LogFlowThisFunc(("rc = %Rrc\n", rc));
    439530    return rc;
     
    442533
    443534/**
    444  * Remove a value in the guest registry by key, checking the validity
     535 * Remove a value in the property registry by name, checking the validity
    445536 * of the arguments passed.
    446537 *
     
    450541 * @thread  HGCM
    451542 */
    452 int Service::delKey(uint32_t cParms, VBOXHGCMSVCPARM paParms[])
     543int Service::delProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[])
    453544{
    454545    int rc = VINF_SUCCESS;
    455     char *pszKey;
    456     uint32_t cbKey;
     546    char *pszName;
     547    uint32_t cbName;
    457548
    458549    LogFlowThisFunc(("\n"));
    459550    if (   (cParms != 1)  /* Hardcoded value as the next lines depend on it. */
    460         || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR)   /* key */
     551        || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR)   /* name */
    461552       )
    462553        rc = VERR_INVALID_PARAMETER;
    463554    if (RT_SUCCESS(rc))
    464         rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszKey, &cbKey);
    465     if (RT_SUCCESS(rc))
    466         rc = validateKey(pszKey, cbKey);
    467     if (RT_SUCCESS(rc))
    468         CFGMR3RemoveValue(mpValueNode, pszKey);
     555        rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszName, &cbName);
     556    if (RT_SUCCESS(rc))
     557        rc = validateName(pszName, cbName);
     558    if (RT_SUCCESS(rc))
     559    {
     560        CFGMR3RemoveValue(mpValueNode, pszName);
     561        notifyHost(pszName);
     562    }
    469563    LogFlowThisFunc(("rc = %Rrc\n", rc));
    470564    return rc;
     
    567661    enum
    568662    {
     663        /* Calculate the increment, not yet rounded down */
    569664        BLOCKINCRFULL = (MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN + 2048),
     665        /* And this is the increment after rounding */
    570666        BLOCKINCR = BLOCKINCRFULL - BLOCKINCRFULL % 1024
    571667    };
     
    657753}
    658754
     755/**
     756 * Notify the service owner that a property has been added/deleted/changed
     757 * @param pszProperty the name of the property which has changed
     758 * @note this call allocates memory which the reqNotify request is expected to
     759 *       free again, using RTStrFree().
     760 *
     761 * @thread  HGCM service
     762 */
     763void Service::notifyHost(const char *pszProperty)
     764{
     765    char szValue[MAX_VALUE_LEN];
     766    uint64_t u64Timestamp = 0;
     767    char szFlags[MAX_FLAGS_LEN];
     768    char *pszName = NULL, *pszValue = NULL, *pszFlags = NULL;
     769
     770    if (NULL == mpfnHostCallback)
     771        return;  /* Nothing to do. */
     772    int rc = CFGMR3QueryString(mpValueNode, pszProperty, szValue,
     773                               sizeof(szValue));
     774    /*
     775     * First case: if the property exists then send the host its current value
     776     */
     777    if (rc != VERR_CFGM_VALUE_NOT_FOUND)
     778    {
     779        if (RT_SUCCESS(rc) && (mpTimestampNode != NULL))
     780            rc = CFGMR3QueryU64(mpTimestampNode, pszProperty, &u64Timestamp);
     781        if (RT_SUCCESS(rc) && (mpFlagsNode != NULL))
     782            rc = CFGMR3QueryString(mpFlagsNode, pszProperty, szFlags,
     783                                   sizeof(szFlags));
     784        if (RT_SUCCESS(rc))
     785            rc = RTStrDupEx(&pszName, pszProperty);
     786        if (RT_SUCCESS(rc) && (mpTimestampNode != NULL))
     787            rc = RTStrDupEx(&pszValue, szValue);
     788        if (RT_SUCCESS(rc) && (mpFlagsNode != NULL))
     789            rc = RTStrDupEx(&pszFlags, szFlags);
     790        if (RT_SUCCESS(rc))
     791            rc = RTReqCallEx(mReqQueue, NULL, 0, RTREQFLAGS_NO_WAIT,
     792                             (PFNRT)Service::reqNotify, 7, mpfnHostCallback,
     793                             mpvHostData, pszName, pszValue, u64Timestamp / 0xffff,
     794                             u64Timestamp % 0xffff, pszFlags);
     795        if (!RT_SUCCESS(rc)) /* clean up */
     796        {
     797            RTStrFree(pszName);
     798            RTStrFree(pszValue);
     799            RTStrFree(pszFlags);
     800        }
     801    }
     802    else
     803    /*
     804     * Second case: if the property does not exist then send the host an empty
     805     * value
     806     */
     807    {
     808        rc = RTStrDupEx(&pszName, pszProperty);
     809        if (RT_SUCCESS(rc))
     810            rc = RTReqCallEx(mReqQueue, NULL, 0, RTREQFLAGS_NO_WAIT,
     811                             (PFNRT)Service::reqNotify, 7, mpfnHostCallback,
     812                             mpvHostData, pszName, NULL, 0, 0, NULL);
     813    }
     814    if (!RT_SUCCESS(rc)) /* clean up if we failed somewhere */
     815    {
     816        RTStrFree(pszName);
     817        RTStrFree(pszValue);
     818        RTStrFree(pszFlags);
     819    }
     820}
     821
     822/**
     823 * Notify the service owner that a property has been added/deleted/changed.
     824 * asynchronous part.
     825 * @param pszProperty the name of the property which has changed
     826 * @note this call allocates memory which the reqNotify request is expected to
     827 *       free again, using RTStrFree().
     828 *
     829 * @thread  request thread
     830 */
     831int Service::reqNotify(PFNVBOXHGCMCALLBACK pfnCallback, void *pvData,
     832                       char *pszName, char *pszValue, uint32_t u32TimeHigh,
     833                       uint32_t u32TimeLow, char *pszFlags)
     834{
     835    HOSTCALLBACKDATA HostCallbackData;
     836    HostCallbackData.hdr.u32Magic = VBOXHGCMCALLBACKMAGIC;
     837    HostCallbackData.hdr.cbStruct = sizeof(HostCallbackData);
     838    HostCallbackData.hdr.pvData   = pvData;
     839    HostCallbackData.pcszName     = pszName;
     840    HostCallbackData.pcszValue    = pszValue;
     841    HostCallbackData.u64Timestamp = u32TimeHigh * 0xffff + u32TimeLow;
     842    HostCallbackData.pcszFlags    = pszFlags;
     843    pfnCallback(&HostCallbackData.hdr);
     844    RTStrFree(pszName);
     845    RTStrFree(pszValue);
     846    RTStrFree(pszFlags);
     847    return VINF_SUCCESS;
     848}
     849
    659850
    660851/**
     
    688879        case SET_PROP:
    689880            LogFlowFunc(("SET_PROP\n"));
    690             rc = setKey(cParms, paParms);
     881            rc = setProperty(cParms, paParms);
    691882            break;
    692883
     
    694885        case SET_PROP_VALUE:
    695886            LogFlowFunc(("SET_PROP_VALUE\n"));
    696             rc = setKey(cParms, paParms);
     887            rc = setProperty(cParms, paParms);
    697888            break;
    698889
     
    700891        case DEL_PROP:
    701892            LogFlowFunc(("DEL_PROP\n"));
    702             rc = delKey(cParms, paParms);
     893            rc = delProperty(cParms, paParms);
    703894            break;
    704895
     
    735926        /* Set the root CFGM node used.  This should be called when instantiating
    736927         * the service. */
     928        /* This whole case is due to go away, so I will not clean it up. */
    737929        case SET_CFGM_NODE:
    738930        {
     
    780972        case SET_PROP_HOST:
    781973            LogFlowFunc(("SET_PROP_HOST\n"));
    782             rc = setKey(cParms, paParms);
     974            rc = setProperty(cParms, paParms);
    783975            break;
    784976
     
    786978        case SET_PROP_VALUE_HOST:
    787979            LogFlowFunc(("SET_PROP_VALUE_HOST\n"));
    788             rc = setKey(cParms, paParms);
     980            rc = setProperty(cParms, paParms);
    789981            break;
    790982
    791983        /* The host wishes to remove a configuration value */
    792984        case DEL_PROP_HOST:
    793             LogFlowFunc(("DEL_CONFIG_KEY_HOST\n"));
    794             rc = delKey(cParms, paParms);
     985            LogFlowFunc(("DEL_PROP_HOST\n"));
     986            rc = delProperty(cParms, paParms);
    795987            break;
    796988
     
    800992            rc = enumProps(cParms, paParms);
    801993            break;
     994        case REGISTER_CALLBACK:
     995            if ((1 != cParms) || (paParms[0].type != VBOX_HGCM_SVC_PARM_CALLBACK))
     996                rc = VERR_INVALID_PARAMETER;
     997            else
     998            {
     999                PFNVBOXHGCMCALLBACK pfnCallback = NULL;
     1000                void *pvData = NULL;
     1001                rc = VBoxHGCMParmPtrGet (&paParms[0], &pfnCallback, &pvData);
     1002                mpfnHostCallback = pfnCallback;
     1003                mpvHostData = pvData;
     1004            }
     1005            break;
    8021006        default:
    8031007            rc = VERR_NOT_SUPPORTED;
     
    8061010
    8071011    LogFlowFunc(("rc = %Vrc\n", rc));
     1012    return rc;
     1013}
     1014
     1015int Service::uninit()
     1016{
     1017    int rc;
     1018    unsigned count = 0;
     1019
     1020    mfExitThread = true;
     1021    rc = RTReqCallEx(mReqQueue, NULL, 0, RTREQFLAGS_NO_WAIT, (PFNRT)reqVoid, 0);
     1022    if (RT_SUCCESS(rc))
     1023        do
     1024        {
     1025            rc = RTThreadWait(mReqThread, 1000, NULL);
     1026            ++count;
     1027            Assert(RT_SUCCESS(rc) || ((VERR_TIMEOUT == rc) && (count != 5)));
     1028        } while ((VERR_TIMEOUT == rc) && (count < 300));
     1029    if (RT_SUCCESS(rc))
     1030        RTReqDestroyQueue(mReqQueue);
    8081031    return rc;
    8091032}
     
    8381061        {
    8391062            std::auto_ptr<Service> apService;
     1063            /* No exceptions may propogate outside. */
    8401064            try {
    8411065                apService = std::auto_ptr<Service>(new Service(ptable->pHelpers));
     1066            } catch (int rcThrown) {
     1067                rc = rcThrown;
    8421068            } catch (...) {
    843                 /* No exceptions may propogate outside. */
    8441069                rc = VERR_UNRESOLVED_ERROR;
    8451070            }
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette