VirtualBox

Changeset 13916

Show
Ignore:
Timestamp:
11/06/08 14:48:05 (2 months ago)
Author:
vboxsync
Message:

HostServices/GuestProperties?: added guest notification querying

Files:

Legend:

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

    r13780 r13916  
    5959/** Maximum size for enumeration patterns */ 
    6060enum { MAX_PATTERN_LEN = 1024 }; 
     61/** Maximum number of changes we remember for guest notifications */ 
     62enum { MAX_GUEST_NOTIFICATIONS = 256 }; 
    6163 
    6264/** 
     
    264266    DEL_PROP = 4, 
    265267    /** Enumerate guest properties */ 
    266     ENUM_PROPS = 5 
     268    ENUM_PROPS = 5, 
     269    /** Poll for guest notifications */ 
     270    GET_NOTIFICATION = 6 
    267271}; 
    268272 
     
    426430    HGCMFunctionParameter size; 
    427431} EnumProperties; 
     432 
     433/** 
     434 * The guest is polling for notifications on changes to properties, optionally 
     435 * specifying the timestamp of the last notification seen. 
     436 * On success, VINF_SUCCESS will be returned and the buffer will contain 
     437 * details of a property notification.  If no new notification is available, 
     438 * a timestamp of zero will be returned. 
     439 * If the last notification could not be found by timestamp, VWRN_NOT_FOUND 
     440 * will be returned and the oldest available notification will be returned. 
     441 * if no timestamp is specified, the oldest available notification will be 
     442 * returned. 
     443 * If the buffer supplied was not large enough to hold the notification, 
     444 * VERR_BUFFER_OVERFLOW will be returned and the size parameter will contain 
     445 * the size of the buffer needed. 
     446 */ 
     447typedef struct _GetNotification 
     448{ 
     449    VBoxGuestHGCMCallInfo hdr; 
     450 
     451    /** 
     452     * The timestamp of the last change seen (IN uint64_t) 
     453     * This may be zero, in which case the oldest available change will be 
     454     * sent.  If the service does not remember an event matching the 
     455     * timestamp, then VWRN_NOT_FOUND will be returned, and the guest should 
     456     * assume that it has missed a certain number of notifications. 
     457     * 
     458     * The timestamp of the change being notified of (OUT uint64_t) 
     459     * If this is zero then no new events are available.  Undefined on 
     460     * failure. 
     461     */ 
     462    HGCMFunctionParameter timestamp; 
     463 
     464    /** 
     465     * The returned data. if any will be placed here.  (OUT pointer) 
     466     * This call returns three null-terminated strings which will be placed 
     467     * one after another: name, value and flags.  For a delete notification, 
     468     * value and flags will be empty strings.  Undefined on failure. 
     469     */ 
     470    HGCMFunctionParameter buffer; 
     471 
     472    /** 
     473     * On success, the size of the returned data.  (OUT uint32_t) 
     474     * On buffer overflow, the size of the buffer needed to hold the data. 
     475     * Undefined on failure. 
     476     */ 
     477    HGCMFunctionParameter size; 
     478} GetNotification; 
    428479#pragma pack () 
    429480 
  • trunk/src/VBox/HostServices/GuestProperties/Makefile.kmk

    r13574 r13916  
    3737        $(PATH_TOOL_$(VBOX_VCC_TOOL)_ATLMFC_INC) \ 
    3838        $(VBOX_PATH_SDK) 
     39# For now! 
     40VBoxGuestPropSvc_CXXFLAGS.win = -EHsc 
    3941 
    4042VBoxGuestPropSvc_SOURCES = \ 
  • trunk/src/VBox/HostServices/GuestProperties/service.cpp

    r13837 r13916  
    4646#include <VBox/HostServices/GuestPropertySvc.h> 
    4747 
    48 #include <memory>  /* for auto_ptr */ 
    49 #include <string> 
    50 #include <list> 
    51  
     48#include <VBox/log.h> 
    5249#include <iprt/err.h> 
    5350#include <iprt/assert.h> 
     
    5956#include <iprt/req.h> 
    6057#include <iprt/thread.h> 
    61 #include <VBox/log.h> 
    62  
    63 /******************************************************************************* 
    64 *   Internal functions                                                         * 
    65 *******************************************************************************/ 
    66 /** Extract a pointer value from an HGCM parameter structure */ 
    67 static int VBoxHGCMParmPtrGet (VBOXHGCMSVCPARM *pParm, void **ppv, uint32_t *pcb) 
    68 
    69     if (pParm->type == VBOX_HGCM_SVC_PARM_PTR) 
    70     { 
    71         *ppv = pParm->u.pointer.addr; 
    72         *pcb = pParm->u.pointer.size; 
    73         return VINF_SUCCESS; 
    74     } 
    75  
    76     return VERR_INVALID_PARAMETER; 
    77 
    78  
    79 /** Extract a constant pointer value from an HGCM parameter structure */ 
    80 static int VBoxHGCMParmPtrConstGet (VBOXHGCMSVCPARM *pParm, const void **ppv, uint32_t *pcb) 
    81 
    82     if (pParm->type == VBOX_HGCM_SVC_PARM_PTR) 
    83     { 
    84         *ppv = pParm->u.pointer.addr; 
    85         *pcb = pParm->u.pointer.size; 
    86         return VINF_SUCCESS; 
    87     } 
    88  
    89     return VERR_INVALID_PARAMETER; 
    90 
    91  
    92 /** Set a uint32_t value to an HGCM parameter structure */ 
    93 static void VBoxHGCMParmUInt32Set (VBOXHGCMSVCPARM *pParm, uint32_t u32) 
    94 
    95     pParm->type = VBOX_HGCM_SVC_PARM_32BIT; 
    96     pParm->u.uint32 = u32; 
    97 
    98  
    99 /** Set a uint64_t value to an HGCM parameter structure */ 
    100 static void VBoxHGCMParmUInt64Set (VBOXHGCMSVCPARM *pParm, uint64_t u64) 
    101 
    102     pParm->type = VBOX_HGCM_SVC_PARM_64BIT; 
    103     pParm->u.uint64 = u64; 
    104 
    105  
    106 /** Set a pointer value to an HGCM parameter structure */ 
    107 static void VBoxHGCMParmPtrSet (VBOXHGCMSVCPARM *pParm, void *pv, uint32_t cb) 
    108 
    109     pParm->type = VBOX_HGCM_SVC_PARM_PTR; 
    110     pParm->u.pointer.addr = pv; 
    111     pParm->u.pointer.size = cb; 
    112 
     58 
     59#include <memory>  /* for auto_ptr */ 
     60#include <string> 
     61#include <list> 
    11362 
    11463namespace guestProp { 
     
    13584        /** The property flags */ 
    13685        uint32_t mFlags; 
     86 
     87        /** Default constructor */ 
     88        Property() : mName(""), mValue(""), mTimestamp(0), mFlags(NILFLAG) {} 
    13789        /** Constructor with const char * */ 
    13890        Property(const char *pcszName, const char *pcszValue, 
     
    150102    /** The property list */ 
    151103    PropertyList mProperties; 
     104    /** The list of property changes for guest notifications */ 
     105    PropertyList mGuestNotifications; 
    152106    /** @todo we should have classes for thread and request handler thread */ 
    153107    /** Queue of outstanding property change notifications */ 
     
    259213    int delProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest); 
    260214    int enumProps(uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 
    261     void notifyHost(const char *pszProperty); 
     215    int getNotification(uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 
     216    void doNotifications(const char *pszProperty, uint64_t u64Timestamp); 
    262217    static DECLCALLBACK(int) reqNotify(PFNHGCMSVCEXT pfnCallback, 
    263218                                       void *pvData, char *pszName, 
     
    310265     * a string terminator. 
    311266     */ 
    312     int rc = RTStrValidateEncodingEx(pszName, RT_MIN(cbName, (uint32_t) MAX_NAME_LEN), 
    313                                      RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED); 
     267    int rc = VINF_SUCCESS; 
    314268    if (RT_SUCCESS(rc) && (cbName < 2)) 
    315269        rc = VERR_INVALID_PARAMETER; 
     270    if (RT_SUCCESS(rc)) 
     271        rc = RTStrValidateEncodingEx(pszName, RT_MIN(cbName, (uint32_t) MAX_NAME_LEN), 
     272                                     RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED); 
    316273 
    317274    LogFlowFunc(("returning %Rrc\n", rc)); 
     
    335292    /* 
    336293     * Validate the value, checking that it's proper UTF-8 and has 
    337      * a string terminator. Don't pass a 0 length request to the 
    338      * validator since it won't find any '\0' then. 
    339      */ 
    340     int rc = VINF_SUCCESS; 
    341     if (cbValue) 
     294     * a string terminator. 
     295     */ 
     296    int rc = VINF_SUCCESS; 
     297    if (RT_SUCCESS(rc) && (cbValue < 2)) 
     298        rc = VERR_INVALID_PARAMETER; 
     299    if (RT_SUCCESS(rc)) 
    342300        rc = RTStrValidateEncodingEx(pszValue, RT_MIN(cbValue, (uint32_t) MAX_VALUE_LEN), 
    343301                                     RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED); 
     
    368326     */ 
    369327    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)) 
     328        || RT_FAILURE(paParms[0].getPointer ((void **) &ppNames, &cbDummy)) 
     329        || RT_FAILURE(paParms[1].getPointer ((void **) &ppValues, &cbDummy)) 
     330        || RT_FAILURE(paParms[2].getPointer ((void **) &pTimestamps, &cbDummy)) 
     331        || RT_FAILURE(paParms[3].getPointer ((void **) &ppFlags, &cbDummy)) 
    374332        ) 
    375333        rc = VERR_INVALID_PARAMETER; 
     
    464422     */ 
    465423    LogFlowThisFunc(("\n")); 
    466     if (   (cParms != 4)  /* Hardcoded value as the next lines depend on it. */ 
    467         || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR)    /* name */ 
    468         || (paParms[1].type != VBOX_HGCM_SVC_PARM_PTR)    /* buffer */ 
     424    if (   cParms != 4  /* Hardcoded value as the next lines depend on it. */ 
     425        || RT_FAILURE (paParms[0].getPointer ((const void **) &pcszName, &cchName))    /* name */ 
     426        || RT_FAILURE (paParms[1].getPointer ((void **) &pchBuf, &cchBuf))    /* buffer */ 
    469427       ) 
    470428        rc = VERR_INVALID_PARAMETER; 
    471     if (RT_SUCCESS(rc)) 
    472         rc = VBoxHGCMParmPtrConstGet(&paParms[0], (const void **) &pcszName, &cchName); 
    473     if (RT_SUCCESS(rc)) 
    474         rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pchBuf, &cchBuf); 
    475429    if (RT_SUCCESS(rc)) 
    476430        rc = validateName(pcszName, cchName); 
     
    500454    { 
    501455        cchBufActual = it->mValue.size() + 1 + cchFlags; 
    502         VBoxHGCMParmUInt32Set(&paParms[3], cchBufActual); 
     456        paParms[3].setUInt32 (cchBufActual); 
    503457    } 
    504458    if (RT_SUCCESS(rc) && (cchBufActual > cchBuf)) 
     
    510464        pchBuf[it->mValue.size()] = '\0'; /* Terminate the value */ 
    511465        strcpy(pchBuf + it->mValue.size() + 1, szFlags); 
    512         VBoxHGCMParmUInt64Set(&paParms[2], it->mTimestamp); 
     466        paParms[2].setUInt64 (it->mTimestamp); 
    513467    } 
    514468 
     
    540494    uint32_t cchName, cchValue, cchFlags = 0; 
    541495    uint32_t fFlags = NILFLAG; 
     496    RTTIMESPEC time; 
     497    uint64_t u64TimeNano = RTTimeSpecGetNano(RTTimeNow(&time)); 
    542498 
    543499    LogFlowThisFunc(("\n")); 
     
    553509    if (   RT_SUCCESS(rc) 
    554510        && (   (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 */ 
     511            || RT_FAILURE(paParms[0].getPointer ((const void **) &pcszName
     512                                                 &cchName)) /* name */ 
     513            || RT_FAILURE(paParms[1].getPointer ((const void **) &pcszValue
     514                                                 &cchValue)) /* value */ 
    559515            || (   (3 == cParms) 
    560                 && RT_FAILURE(VBoxHGCMParmPtrConstGet(&paParms[2]
    561                        (const void **) &pcszFlags, &cchFlags)) /* flags */ 
     516                && RT_FAILURE(paParms[2].getPointer ((const void **) &pcszFlags
     517                                                     &cchFlags)) /* flags */ 
    562518               ) 
    563519           ) 
     
    602558    if (RT_SUCCESS(rc)) 
    603559    { 
    604         RTTIMESPEC time; 
    605         uint64_t u64TimeNano = RTTimeSpecGetNano(RTTimeNow(&time)); 
    606560        if (found) 
    607561        { 
     
    621575        // if (isGuest)  /* Notify the host even for properties that the host 
    622576        //                * changed.  Less efficient, but ensures consistency. */ 
    623             notifyHost(pcszName); 
     577            doNotifications(pcszName, u64TimeNano); 
    624578        Log2(("Set string %s, rc=%Rrc, value=%s\n", pcszName, rc, pcszValue)); 
    625579    } 
     
    651605     */ 
    652606    if (   (cParms != 1)  /* Hardcoded value as the next lines depend on it. */ 
    653         || RT_FAILURE(VBoxHGCMParmPtrConstGet(&paParms[0]
    654                (const void **) &pcszName, &cbName))  /* name */ 
     607        || RT_FAILURE(paParms[0].getPointer ((const void **) &pcszName
     608                                             &cbName))  /* name */ 
    655609       ) 
    656610        rc = VERR_INVALID_PARAMETER; 
     
    682636    if (RT_SUCCESS(rc) && found) 
    683637    { 
     638        RTTIMESPEC time; 
     639        uint64_t u64Timestamp = RTTimeSpecGetNano(RTTimeNow(&time)); 
    684640        mProperties.erase(it); 
    685641        // if (isGuest)  /* Notify the host even for properties that the host 
    686642        //                * changed.  Less efficient, but ensures consistency. */ 
    687             notifyHost(pcszName); 
     643            doNotifications(pcszName, u64Timestamp); 
    688644    } 
    689645    LogFlowThisFunc(("rc = %Rrc\n", rc)); 
     
    711667    LogFlowThisFunc(("\n")); 
    712668    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 */ 
     669        || RT_FAILURE(paParms[0].getPointer ((const void **) &pcchPatterns, 
     670                                             &cchPatterns))  /* patterns */ 
     671        || RT_FAILURE(paParms[1].getPointer ((void **) &pchBuf, &cchBuf))  /* return buffer */ 
    717672       ) 
    718673        rc = VERR_INVALID_PARAMETER; 
     
    777732    if (RT_SUCCESS(rc)) 
    778733    { 
    779         VBoxHGCMParmUInt32Set(&paParms[2], buffer.size()); 
     734        paParms[2].setUInt32 (buffer.size()); 
    780735        /* Copy the memory if it fits into the guest buffer */ 
    781736        if (buffer.size() <= cchBuf) 
     
    788743 
    789744/** 
    790  * Notify the service owner that a property has been added/deleted/changed 
    791  * @param pszProperty the name of the property which has changed 
     745 * Get the next guest notification. 
     746 * 
     747 * @returns iprt status value 
     748 * @param   cParms  the number of HGCM parameters supplied 
     749 * @param   paParms the array of HGCM parameters 
     750 * @thread  HGCM 
     751 */ 
     752int Service::getNotification(uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 
     753
     754    int rc = VINF_SUCCESS; 
     755    char *pchBuf; 
     756    uint32_t cchBuf = 0; 
     757    uint64_t u64Timestamp; 
     758    bool warn = false; 
     759 
     760    /* 
     761     * Get the HGCM function arguments and perform basic verification. 
     762     */ 
     763    LogFlowThisFunc(("\n")); 
     764    if (   (cParms != 3)  /* Hardcoded value as the next lines depend on it. */ 
     765        || RT_FAILURE(paParms[0].getUInt64 (&u64Timestamp))  /* timestamp */ 
     766        || RT_FAILURE(paParms[1].getPointer ((void **) &pchBuf, &cchBuf))  /* return buffer */ 
     767        || cchBuf < 1 
     768       ) 
     769        rc = VERR_INVALID_PARAMETER; 
     770 
     771    /* 
     772     * Find the change to notify of. 
     773     */ 
     774    Property next; 
     775    /* Return the oldest notification if no timestamp was specified. */ 
     776    if (RT_SUCCESS(rc) && !mGuestNotifications.empty() && u64Timestamp == 0) 
     777        next = mGuestNotifications.front(); 
     778    /* Only search if the guest hasn't seen the most recent notification. */ 
     779    else if (   RT_SUCCESS(rc) 
     780             && !mGuestNotifications.empty() 
     781             && mGuestNotifications.back().mTimestamp != u64Timestamp) 
     782    { 
     783        /* We count backwards, as the guest should normally be querying the 
     784         * most recent events. */ 
     785        PropertyList::const_reverse_iterator it = mGuestNotifications.rbegin(); 
     786        for ( ;    it != mGuestNotifications.rend() 
     787                && it->mTimestamp != u64Timestamp; 
     788             ++it 
     789            ) {} 
     790        /* Warn if the timestamp was not found. */ 
     791        if (it == mGuestNotifications.rend()) 
     792            warn = true; 
     793        /* This is a reverse iterator, so --it goes up the list. */ 
     794        --it; 
     795        next = *it; 
     796    } 
     797 
     798    /* 
     799     * Format the data to write to the buffer. 
     800     */ 
     801    std::string buffer; 
     802    if (RT_SUCCESS(rc)) 
     803    { 
     804        char szFlags[MAX_FLAGS_LEN]; 
     805        rc = writeFlags(next.mFlags, szFlags); 
     806        if (RT_SUCCESS(rc)) 
     807        { 
     808            buffer += next.mName; 
     809            buffer += '\0'; 
     810            buffer += next.mValue; 
     811            buffer += '\0'; 
     812            buffer += szFlags; 
     813            buffer += '\0'; 
     814            u64Timestamp = next.mTimestamp; 
     815        } 
     816    } 
     817 
     818    /* 
     819     * Write out the data. 
     820     */ 
     821    paParms[0].setUInt64(u64Timestamp); 
     822    paParms[2].setUInt32(buffer.size()); 
     823    if (RT_SUCCESS(rc) && buffer.size() <= cchBuf) 
     824        buffer.copy(pchBuf, cchBuf); 
     825    else if (RT_SUCCESS(rc)) 
     826        rc = VERR_BUFFER_OVERFLOW; 
     827    if (RT_SUCCESS(rc) && warn) 
     828        rc = VWRN_NOT_FOUND; 
     829    return rc; 
     830
     831 
     832/** 
     833 * Notify the service owner and the guest that a property has been 
     834 * added/deleted/changed 
     835 * @param pszProperty  the name of the property which has changed 
     836 * @param u64Timestamp the time at which the change took place 
    792837 * @note this call allocates memory which the reqNotify request is expected to 
    793838 *       free again, using RTStrFree(). 
     
    795840 * @thread  HGCM service 
    796841 */ 
    797 void Service::notifyHost(const char *pszProperty) 
    798 
    799 #ifndef VBOX_GUEST_PROP_TEST_NOTHREAD 
     842void Service::doNotifications(const char *pszProperty, uint64_t u64Timestamp) 
     843
    800844    char szFlags[MAX_FLAGS_LEN]; 
    801845    char *pszName = NULL, *pszValue = NULL, *pszFlags = NULL; 
    802846    int rc = VINF_SUCCESS; 
    803847 
    804     if (NULL == mpfnHostCallback) 
    805         return;  /* Nothing to do. */ 
     848    AssertPtrReturnVoid(pszProperty); 
    806849    PropertyList::const_iterator it; 
    807850    bool found = false; 
     
    814857            } 
    815858    /* 
    816      * First case: if the property exists then send the host its current value 
    817      */ 
    818     if (found) 
    819     { 
     859     * First case: if the property exists then send its current value 
     860     */ 
     861    if (found && mpfnHostCallback != NULL) 
     862    { 
     863#ifndef VBOX_GUEST_PROP_TEST_NOTHREAD 
     864        /* Send out a host notification */ 
    820865        rc = writeFlags(it->mFlags, szFlags); 
    821866        if (RT_SUCCESS(rc)) 
     
    831876                             (uint32_t) RT_HIDWORD(it->mTimestamp), 
    832877                             (uint32_t) RT_LODWORD(it->mTimestamp), pszFlags); 
    833     } 
    834     else 
     878#endif /* VBOX_GUEST_PROP_TEST_NOTHREAD not defined */ 
     879    } 
     880    if (found) 
     881    { 
     882        /* Add the change to the queue for guest notifications */ 
     883        if (RT_SUCCESS(rc)) 
     884        { 
     885            try 
     886            { 
     887                mGuestNotifications.push_back(*it); 
     888            } 
     889            catch (std::bad_alloc) 
     890            { 
     891                rc = VERR_NO_MEMORY; 
     892            } 
     893        } 
     894    } 
     895 
    835896    /* 
    836897     * Second case: if the property does not exist then send the host an empty 
    837898     * value 
    838899     */ 
    839     { 
     900    if (!found && mpfnHostCallback != NULL) 
     901    { 
     902#ifndef VBOX_GUEST_PROP_TEST_NOTHREAD 
     903        /* Send out a host notification */ 
    840904        rc = RTStrDupEx(&pszName, pszProperty); 
    841905        if (RT_SUCCESS(rc)) 
    842906            rc = RTReqCallEx(mReqQueue, NULL, 0, RTREQFLAGS_NO_WAIT, 
    843907                             (PFNRT)Service::reqNotify, 7, mpfnHostCallback, 
    844                              mpvHostData, pszName, NULL, 0, 0, NULL); 
    845     } 
     908                             mpvHostData, pszName, NULL, 
     909                             RT_HIDWORD(u64Timestamp), 
     910                             RT_LODWORD(u64Timestamp), NULL); 
     911#endif /* VBOX_GUEST_PROP_TEST_NOTHREAD not defined */ 
     912    } 
     913    if (!found) 
     914    { 
     915        /* Add the change to the queue for guest notifications */ 
     916        if (RT_SUCCESS(rc)) 
     917        { 
     918            try 
     919            { 
     920                mGuestNotifications.push_back(Property(pszProperty, "", 
     921                                                       u64Timestamp, NILFLAG) 
     922                                             ); 
     923            } 
     924            catch (std::bad_alloc) 
     925            { 
     926                rc = VERR_NO_MEMORY; 
     927            } 
     928        } 
     929    } 
     930    if (mGuestNotifications.size() > MAX_GUEST_NOTIFICATIONS) 
     931        mGuestNotifications.pop_front(); 
    846932    if (RT_FAILURE(rc)) /* clean up if we failed somewhere */ 
    847933    { 
     
    850936        RTStrFree(pszFlags); 
    851937    } 
    852 #endif /* VBOX_GUEST_PROP_TEST_NOTHREAD not defined */ 
    853938} 
    854939 
     
    9321017                LogFlowFunc(("ENUM_PROPS\n")); 
    9331018                rc = enumProps(cParms, paParms); 
     1019                break; 
     1020 
     1021            /* The guest wishes to get the next property notification */ 
     1022            case GET_NOTIFICATION: 
     1023                LogFlowFunc(("GET_NOTIFICATION\n")); 
     1024                rc = getNotification(cParms, paParms); 
    9341025                break; 
    9351026 
  • trunk/src/VBox/HostServices/GuestProperties/testcase/Makefile.kmk

    r13779 r13916  
    4242  OTHERS += $(PATH_tstGuestPropSvc)/tstGuestPropSvc.run 
    4343$$(PATH_tstGuestPropSvc)/tstGuestPropSvc.run: $$(INSTARGET_tstGuestPropSvc) 
    44         $(INSTARGET_tstGuestPropSvc) quiet 
     44        export VBOX_LOG_DEST=nofile; $(INSTARGET_tstGuestPropSvc) quiet 
    4545        $(QUIET)$(APPEND) -t "$@" "done" 
    4646 endif 
  • trunk/src/VBox/HostServices/GuestProperties/testcase/tstGuestPropSvc.cpp

    r13781 r13916  
    3232extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad (VBOXHGCMSVCFNTABLE *ptable); 
    3333 
    34 /** Set a pointer value to an HGCM parameter structure */ 
    35 static void VBoxHGCMParmPtrSet (VBOXHGCMSVCPARM *pParm, void *pv, uint32_t cb) 
    36 { 
    37     pParm->type = VBOX_HGCM_SVC_PARM_PTR; 
    38     pParm->u.pointer.addr = pv; 
    39     pParm->u.pointer.size = cb; 
    40 } 
    41  
    42 /** Extract a uint64_t value from an HGCM parameter structure */ 
    43 static int VBoxHGCMParmUInt32Get (VBOXHGCMSVCPARM *pParm, uint32_t *pu32Value) 
    44 { 
    45     if (pParm->type == VBOX_HGCM_SVC_PARM_32BIT) 
    46     { 
    47         *pu32Value = pParm->u.uint32; 
    48         return VINF_SUCCESS; 
    49     } 
    50  
    51     return VERR_INVALID_PARAMETER; 
    52 } 
    53  
    54 /** Extract a uint64_t value from an HGCM parameter structure */ 
    55 static int VBoxHGCMParmUInt64Get (VBOXHGCMSVCPARM *pParm, uint64_t *pu64Value) 
    56 { 
    57     if (pParm->type == VBOX_HGCM_SVC_PARM_64BIT) 
    58     { 
    59         *pu64Value = pParm->u.uint64; 
    60         return VINF_SUCCESS; 
    61     } 
    62  
    63     return VERR_INVALID_PARAMETER; 
    64 } 
    65  
    6634/** Simple call handle structure for the guest call completion callback */ 
    6735struct VBOXHGCMCALLHANDLE_TYPEDEF 
     
    250218    { 
    251219        VBOXHGCMSVCPARM paParms[4]; 
    252         VBoxHGCMParmPtrSet(&paParms[0], (void *) apcszNameBlock, 0); 
    253         VBoxHGCMParmPtrSet(&paParms[1], (void *) apcszValueBlock, 0); 
    254         VBoxHGCMParmPtrSet(&paParms[2], (void *) au64TimestampBlock, 0); 
    255         VBoxHGCMParmPtrSet(&paParms[3], (void *) apcszFlagsBlock, 0); 
     220        paParms[0].setPointer ((void *) apcszNameBlock, 0); 
     221        paParms[1].setPointer ((void *) apcszValueBlock, 0); 
     222        paParms[2].setPointer ((void *) au64TimestampBlock, 0); 
     223        paParms[3].setPointer ((void *) apcszFlagsBlock, 0); 
    256224        rc = ptable->pfnHostCall(ptable->pvService, SET_PROPS_HOST, 4, 
    257225                                 paParms); 
     
    370338        char buffer[2048]; 
    371339        VBOXHGCMSVCPARM paParms[3]; 
    372         VBoxHGCMParmPtrSet(&paParms[0], 
    373                            (void *) enumStrings[i].pcszPatterns, 
    374                            enumStrings[i].cchPatterns); 
    375         VBoxHGCMParmPtrSet(&paParms[1], 
    376                            (void *) buffer, 
    377                            enumStrings[i].cchBuffer - 1); 
     340        paParms[0].setPointer ((void *) enumStrings[i].pcszPatterns, 
     341                               enumStrings[i].cchPatterns); 
     342        paParms[1].setPointer ((void *) buffer, 
     343                               enumStrings[i].cchBuffer - 1); 
    378344        AssertBreakStmt(sizeof(buffer) > enumStrings[i].cchBuffer, 
    379345                        rc = VERR_INTERNAL_ERROR); 
     
    391357            { 
    392358                uint32_t cchBufferActual; 
    393                 rc = VBoxHGCMParmUInt32Get(&paParms[2], &cchBufferActual); 
     359                rc = paParms[2].getUInt32 (&cchBufferActual); 
    394360                if (RT_SUCCESS(rc) && cchBufferActual != enumStrings[i].cchBuffer) 
    395361                { 
     
    403369        if (RT_SUCCESS(rc)) 
    404370        { 
    405             VBoxHGCMParmPtrSet(&paParms[1], (void *) buffer, 
    406                                enumStrings[i].cchBuffer); 
     371            paParms[1].setPointer ((void *) buffer, enumStrings[i].cchBuffer); 
    407372            rc = ptable->pfnHostCall(ptable->pvService, ENUM_PROPS_HOST, 
    408373                                      3, paParms); 
     
    495460        strncat(szValue, setProperties[i].pcszValue, sizeof(szValue)); 
    496461        strncat(szFlags, setProperties[i].pcszFlags, sizeof(szFlags)); 
    497         VBoxHGCMParmPtrSet(&paParms[0], szName, strlen(szName) + 1); 
    498         VBoxHGCMParmPtrSet(&paParms[1], szValue, strlen(szValue) + 1); 
    499         VBoxHGCMParmPtrSet(&paParms[2], szFlags, strlen(szFlags) + 1); 
     462        paParms[0].setPointer (szName, strlen(szName) + 1); 
     463        paParms[1].setPointer (szValue, strlen(szValue) + 1); 
     464        paParms[2].setPointer (szFlags, strlen(szFlags) + 1); 
    500465        if (setProperties[i].isHost) 
    501466            callHandle.rc = pTable->pfnHostCall(pTable->pvService, command, 
     
    567532        char szName[MAX_NAME_LEN] = ""; 
    568533        strncat(szName, delProperties[i].pcszName, sizeof(szName)); 
    569         VBoxHGCMParmPtrSet(&paParms[0], szName, strlen(szName) + 1); 
     534        paParms[0].setPointer (szName, strlen(szName) + 1); 
    570535        if (delProperties[i].isHost) 
    571536            callHandle.rc = pTable->pfnHostCall(pTable->pvService, command, 
     
    644609                        rc = VERR_INTERNAL_ERROR); 
    645610        strncat(szName, getProperties[i].pcszName, sizeof(szName)); 
    646         VBoxHGCMParmPtrSet(&paParms[0], szName, strlen(szName) + 1); 
    647         VBoxHGCMParmPtrSet(&paParms[1], szBuffer, sizeof(szBuffer)); 
     611        paParms[0].setPointer (szName, strlen(szName) + 1); 
     612        paParms[1].setPointer (szBuffer, sizeof(szBuffer)); 
    648613        rc2 = pTable->pfnHostCall(pTable->pvService, GET_PROP_HOST, 4, 
    649614                                  paParms); 
     
    663628        { 
    664629            uint32_t u32ValueLen; 
    665             rc = VBoxHGCMParmUInt32Get(&paParms[3], &u32ValueLen); 
     630            rc = paParms[3].getUInt32 (&u32ValueLen); 
    666631            if (RT_FAILURE(rc)) 
    667632                RTPrintf("Failed to get the size of the output buffer for property '%s'\n", 
     
    680645            { 
    681646                uint64_t u64Timestamp; 
    682                 rc = VBoxHGCMParmUInt64Get(&paParms[2], &u64Timestamp); 
     647                rc = paParms[2].getUInt64 (&u64Timestamp); 
    683648                if (RT_FAILURE(rc)) 
    684649                    RTPrintf("Failed to get the timestamp for property '%s'\n", 
     
    699664} 
    700665 
     666/** Array of properties for testing GET_PROP_HOST. */ 
     667static const struct 
     668{ 
     669    /** Buffer returned */ 
     670    const char *pchBuffer; 
     671    /** What size should the buffer be? */ 
     672    uint32_t cchBuffer; 
     673} 
     674getNotifications[] = 
     675{ 
     676    { "Red\0Stop!\0TRANSIENT", sizeof("Red\0Stop!\0TRANSIENT") }, 
     677    { "Amber\0Caution!\0", sizeof("Amber\0Caution!\0") }, 
     678    { "Green\0Go!\0READONLY", sizeof("Green\0Go!\0READONLY") }, 
     679    { "Blue\0What on earth...?\0", sizeof("Blue\0What on earth...?\0") }, 
     680    { "Red\0\0", sizeof("Red\0\0") }, 
     681    { "Amber\0\0", sizeof("Amber\0\0") }, 
     682    { NULL, 0 } 
     683}; 
     684 
     685/** 
     686 * Test the GET_NOTIFICATION function. 
     687 * @returns iprt status value to indicate whether the test went as expected. 
     688 * @note    prints its own diagnostic information to stdout. 
     689 */ 
     690int testGetNotification(VBOXHGCMSVCFNTABLE *pTable) 
     691{ 
     692    int rc = VINF_SUCCESS; 
     693    VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS }; 
     694    char chBuffer[MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN]; 
     695 
     696    RTPrintf("Testing the GET_NOTIFICATION call.\n"); 
     697    uint64_t u64Timestamp = 0; 
     698    uint32_t u32Size = 0; 
     699    VBOXHGCMSVCPARM paParms[3]; 
     700 
     701    /* Test "buffer too small" */ 
     702    paParms[0].setUInt64 (u64Timestamp); 
     703    paParms[1].setPointer ((void *) chBuffer, getNotifications[0].cchBuffer - 1); 
     704    pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, 
     705                    GET_NOTIFICATION, 3, paParms); 
     706    if (   callHandle.rc != VERR_BUFFER_OVERFLOW 
     707        || RT_FAILURE(paParms[2].getUInt32 (&u32Size)) 
     708        || u32Size != getNotifications[0].cchBuffer 
     709       ) 
     710    { 
     711        RTPrintf("Getting notification for property '%s' with a too small buffer did not fail correctly.\n", 
     712                 getNotifications[0].pchBuffer); 
     713        rc = VERR_UNRESOLVED_ERROR; 
     714    } 
     715 
     716    /* Test successful notification queries */ 
     717    for (unsigned i = 0; RT_SUCCESS(rc) && (getNotifications[i].pchBuffer != NULL); 
     718         ++i) 
     719    { 
     720        paParms[0].setUInt64 (u64Timestamp); 
     721        paParms[1].setPointer ((void *) chBuffer, sizeof(chBuffer)); 
     722        pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, 
     723                        GET_NOTIFICATION, 3, paParms); 
     724        if (   RT_FAILURE(callHandle.rc) 
     725            || RT_FAILURE(paParms[0].getUInt64 (&u64Timestamp)) 
     726            || RT_FAILURE(paParms[2].getUInt32 (&u32Size)) 
     727            || u32Size != getNotifications[i].cchBuffer 
     728            || memcmp(chBuffer, getNotifications[i].pchBuffer, u32Size) != 0 
     729           ) 
     730        { 
     731            RTPrintf("Failed to get notification for property '%s'.\n", 
     732                     getNotifications[i].pchBuffer); 
     733            rc = VERR_UNRESOLVED_ERROR; 
     734        } 
     735    } 
     736 
     737    /* Test when no new events are available */ 
     738    pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, 
     739                    GET_NOTIFICATION, 3, paParms); 
     740    if (   RT_FAILURE(callHandle.rc) 
     741        || RT_FAILURE(paParms[0].getUInt64 (&u64Timestamp)) 
     742        || u64Timestamp != 0 
     743       ) 
     744    { 
     745        RTPrintf("Failed to signal properly that no new notifications are available.\n"); 
     746        rc = VERR_UNRESOLVED_ERROR; 
     747    } 
     748 
     749    /* Test a query with an unknown timestamp */ 
     750    paParms[0].setUInt64 (1); 
     751    paParms[1].setPointer ((void *) chBuffer, sizeof(chBuffer)); 
     752    if (RT_SUCCESS(rc)) 
     753        pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, 
     754                        GET_NOTIFICATION, 3, paParms); 
     755    if (   RT_SUCCESS(rc) 
     756        && (   callHandle.rc != VWRN_NOT_FOUND 
     757            || RT_FAILURE(callHandle.rc) 
     758            || RT_FAILURE(paParms[0].getUInt64 (&u64Timestamp)) 
     759            || RT_FAILURE(paParms[2].getUInt32 (&u32Size)) 
     760            || u32Size != getNotifications[0].cchBuffer 
     761            || memcmp(chBuffer, getNotifications[0].pchBuffer, u32Size) != 0 
     762           ) 
     763       ) 
     764    { 
     765        RTPrintf("Problem getting notification for property '%s' with unknown timestamp, rc=%Rrc.\n", 
     766                 getNotifications[0].pchBuffer, callHandle.rc); 
     767        rc = VERR_UNRESOLVED_ERROR; 
     768    } 
     769    return rc; 
     770} 
     771 
     772/** 
     773 * Test the GET_NOTIFICATION function when no notifications are available. 
     774 * @returns iprt status value to indicate whether the test went as expected. 
     775 * @note    prints its own diagnostic information to stdout. 
     776 */ 
     777int testNoNotifications(VBOXHGCMSVCFNTABLE *pTable) 
     778{ 
     779    int rc = VINF_SUCCESS; 
     780    VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS }; 
     781    char chBuffer[MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN]; 
     782 
     783    RTPrintf("Testing the GET_NOTIFICATION call when no notifications are available.\n"); 
     784    uint64_t u64Timestamp = 0; 
     785    uint32_t u32Size = 0; 
     786    VBOXHGCMSVCPARM paParms[3]; 
     787 
     788    paParms[0].setUInt64 (u64Timestamp); 
     789    paParms[1].setPointer ((void *) chBuffer, sizeof(chBuffer)); 
     790    pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, 
     791                    GET_NOTIFICATION, 3, paParms); 
     792    if (   RT_FAILURE(callHandle.rc) 
     793        || RT_FAILURE(paParms[0].getUInt64 (&u64Timestamp)) 
     794        || u64Timestamp != 0 
     795       ) 
     796    { 
     797        RTPrintf("Failed to signal properly that no new notifications are available.\n"); 
     798        rc = VERR_UNRESOLVED_ERROR; 
     799    } 
     800    return rc; 
     801} 
     802 
    701803int main(int argc, char **argv) 
    702804{ 
     
    717819    if (RT_FAILURE(testEnumPropsHost(&svcTable))) 
    718820        return 1; 
     821    if (RT_FAILURE(testNoNotifications(&svcTable))) 
     822        return 1; 
    719823    if (RT_FAILURE(testSetProp(&svcTable))) 
    720824        return 1; 
     
    723827    if (RT_FAILURE(testGetProp(&svcTable))) 
    724828        return 1; 
     829    if (RT_FAILURE(testGetNotification(&svcTable))) 
     830        return 1; 
    725831    RTPrintf("tstGuestPropSvc: SUCCEEDED.\n"); 
    726832    return 0; 

© 2008 Sun Microsystems, Inc.
ContactPrivacy policy