VirtualBox

Changeset 14104

Show
Ignore:
Timestamp:
11/11/08 20:16:32 (2 months ago)
Author:
vboxsync
Message:

HostServices/GuestProperties?: fixed the GET_NOTIFICATION protocol

Files:

Legend:

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

    r13995 r14104  
    426426 
    427427/** 
    428  * The guest is polling for notifications on changes to properties, optionally 
    429  * specifying the timestamp of the last notification seen. 
     428 * The guest is polling for notifications on changes to properties, specifying 
     429 * a set of patterns to match the names of changed properties against and 
     430 * optionally the timestamp of the last notification seen. 
    430431 * On success, VINF_SUCCESS will be returned and the buffer will contain 
    431  * details of a property notification.  If no new notification is available, 
    432  * the call will block until one is. 
     432 * details of a property notification.  If no new notification is available 
     433 * which matches one of the specified patterns, the call will block until one 
     434 * is. 
    433435 * If the last notification could not be found by timestamp, VWRN_NOT_FOUND 
    434436 * will be returned and the oldest available notification will be returned. 
    435  * If no timestamp is specified, the oldest available notification will be 
    436  * returned
     437 * If a zero timestamp is specified, the call will always wait for a new 
     438 * notification to arrive
    437439 * If the buffer supplied was not large enough to hold the notification, 
    438440 * VERR_BUFFER_OVERFLOW will be returned and the size parameter will contain 
     
    446448typedef struct _GetNotification 
    447449{ 
    448     VBoxGuestHGCMCallInfo hdr; 
    449  
     450    VBoxGuestHGCMCallInfoTimeout hdr; 
     451 
     452    /** 
     453     * A list of patterns to match the guest event name against, separated by 
     454     * vertical bars (|) (IN pointer) 
     455     * An empty string means match all. 
     456     */ 
     457    HGCMFunctionParameter patterns; 
    450458    /** 
    451459     * The timestamp of the last change seen (IN uint64_t) 
  • trunk/src/VBox/HostServices/GuestProperties/service.cpp

    r14011 r14104  
    6060#include <string> 
    6161#include <list> 
    62 #include <vector> 
    6362 
    6463namespace guestProp { 
     
    112111        /** The function that was requested */ 
    113112        uint32_t mFunction; 
    114         /** The number of parameters */ 
    115         uint32_t mcParms; 
    116         /** The parameters themselves */ 
     113        /** The call parameters */ 
    117114        VBOXHGCMSVCPARM *mParms; 
     115        /** The default return value, used for passing warnings */ 
     116        int mRc; 
    118117 
    119118        /** The standard constructor */ 
    120         GuestCall() : mFunction(0), mcParms(0) {} 
     119        GuestCall() : mFunction(0) {} 
    121120        /** The normal contructor */ 
    122121        GuestCall(VBOXHGCMCALLHANDLE aHandle, uint32_t aFunction, 
    123                   uint32_t acParms, VBOXHGCMSVCPARM aParms[]
    124                   : mHandle(aHandle), mFunction(aFunction), mcParms(acParms), 
    125                   mParms(aParms) {} 
     122                  VBOXHGCMSVCPARM aParms[], int aRc
     123                  : mHandle(aHandle), mFunction(aFunction), mParms(aParms), 
     124                    mRc(aRc) {} 
    126125    }; 
    127     typedef std::vector <GuestCall> CallVector
     126    typedef std::list <GuestCall> CallList
    128127    /** The list of outstanding guest notification calls */ 
    129     CallVector mGuestWaiters; 
     128    CallList mGuestWaiters; 
    130129    /** @todo we should have classes for thread and request handler thread */ 
    131130    /** Queue of outstanding property change notifications */ 
     
    238237    int enumProps(uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 
    239238    int getNotification(VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, 
    240                         VBOXHGCMSVCPARM paParms[], bool canWait); 
     239                        VBOXHGCMSVCPARM paParms[]); 
     240    int getOldNotification(const char *pszPattern, uint64_t u64Timestamp, 
     241                           Property *pProp); 
     242    int getNotificationWriteOut(VBOXHGCMSVCPARM paParms[], Property prop); 
    241243    void doNotifications(const char *pszProperty, uint64_t u64Timestamp); 
    242244    static DECLCALLBACK(int) reqNotify(PFNHGCMSVCEXT pfnCallback, 
     
    439441    char *pchBuf; 
    440442    uint32_t cchName, cchBuf; 
    441     size_t cchFlags, cchBufActual; 
     443    uint32_t cchFlags, cchBufActual; 
    442444    char szFlags[MAX_FLAGS_LEN]; 
    443     uint32_t fFlags; 
    444445 
    445446    /* 
     
    734735            char szFlags[MAX_FLAGS_LEN]; 
    735736            char szTimestamp[256]; 
    736             size_t cchTimestamp; 
     737            uint32_t cchTimestamp; 
    737738            buffer += it->mName; 
    738739            buffer += '\0'; 
     
    768769 
    769770/** 
     771 * Get the next property change notification from the queue of saved 
     772 * notification based on the timestamp of the last notification seen. 
     773 * Notifications will only be reported if the property name matches the 
     774 * pattern given. 
     775 * 
     776 * @returns iprt status value 
     777 * @returns VWRN_NOT_FOUND if the last notification was not found in the queue 
     778 * @param   pszPatterns   the patterns to match the property name against 
     779 * @param   u64Timestamp  the timestamp of the last notification 
     780 * @param   pProp         where to return the property found.  If none is 
     781 *                        found this will be set to nil. 
     782 * @thread  HGCM 
     783 */ 
     784int Service::getOldNotification(const char *pszPatterns, uint64_t u64Timestamp, 
     785                                Property *pProp) 
     786{ 
     787    AssertPtrReturn(pszPatterns, VERR_INVALID_POINTER); 
     788    AssertReturn(u64Timestamp != 0, VERR_INVALID_PARAMETER);  /* Zero means wait for a new notification. */ 
     789    AssertPtrReturn(pProp, VERR_INVALID_POINTER); 
     790    int rc = VINF_SUCCESS; 
     791    bool warn = false; 
     792 
     793    /* We count backwards, as the guest should normally be querying the 
     794     * most recent events. */ 
     795    PropertyList::reverse_iterator it = mGuestNotifications.rbegin(); 
     796    for (; it->mTimestamp != u64Timestamp && it != mGuestNotifications.rend(); 
     797         ++it) {} 
     798    /* Warn if the timestamp was not found. */ 
     799    if (it->mTimestamp != u64Timestamp) 
     800        warn = true; 
     801    /* Now look for an event matching the patterns supplied.  The base() 
     802     * member conveniently points to the following element. */ 
     803    PropertyList::iterator base = it.base(); 
     804    for (;    pszPatterns[0] != '\0' 
     805           && !RTStrSimplePatternMultiMatch(pszPatterns, RTSTR_MAX, 
     806                                            base->mName.c_str(), RTSTR_MAX, 
     807                                            NULL) 
     808           && base != mGuestNotifications.end(); ++base) {} 
     809    if (RT_SUCCESS(rc) && base != mGuestNotifications.end()) 
     810        *pProp = *base; 
     811    else if (RT_SUCCESS(rc)) 
     812        *pProp = Property(); 
     813    if (warn) 
     814        rc = VWRN_NOT_FOUND; 
     815    return rc; 
     816} 
     817 
     818int Service::getNotificationWriteOut(VBOXHGCMSVCPARM paParms[], Property prop) 
     819{ 
     820    int rc = VINF_SUCCESS; 
     821    /* Format the data to write to the buffer. */ 
     822    std::string buffer; 
     823    uint64_t u64Timestamp; 
     824    char *pchBuf; 
     825    uint32_t cchBuf; 
     826    rc = paParms[2].getPointer((void **) &pchBuf, &cchBuf); 
     827    if (RT_SUCCESS(rc)) 
     828    { 
     829        char szFlags[MAX_FLAGS_LEN]; 
     830        rc = writeFlags(prop.mFlags, szFlags); 
     831        if (RT_SUCCESS(rc)) 
     832        { 
     833            buffer += prop.mName; 
     834            buffer += '\0'; 
     835            buffer += prop.mValue; 
     836            buffer += '\0'; 
     837            buffer += szFlags; 
     838            buffer += '\0'; 
     839            u64Timestamp = prop.mTimestamp; 
     840        } 
     841    } 
     842    /* Write out the data. */ 
     843    if (RT_SUCCESS(rc)) 
     844    { 
     845        paParms[1].setUInt64(u64Timestamp); 
     846        paParms[3].setUInt32(buffer.size()); 
     847        if (buffer.size() <= cchBuf) 
     848            buffer.copy(pchBuf, cchBuf); 
     849        else 
     850            rc = VERR_BUFFER_OVERFLOW; 
     851    } 
     852    return rc; 
     853} 
     854 
     855/** 
    770856 * Get the next guest notification. 
    771857 * 
     
    773859 * @param   cParms  the number of HGCM parameters supplied 
    774860 * @param   paParms the array of HGCM parameters 
    775  * @param   canWait can this request be enqueued 
    776861 * @thread  HGCM 
    777  * @throws  can throw std::bad_alloc if canWait==true 
     862 * @throws  can throw std::bad_alloc 
    778863 */ 
    779864int Service::getNotification(VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, 
    780                              VBOXHGCMSVCPARM paParms[], bool canWait
    781 { 
    782     int rc = VINF_SUCCESS; 
    783     char *pchBuf; 
    784     uint32_t cchBuf = 0; 
     865                             VBOXHGCMSVCPARM paParms[]
     866{ 
     867    int rc = VINF_SUCCESS; 
     868    char *pszPatterns, *pchBuf; 
     869    uint32_t cchPatterns = 0, cchBuf = 0; 
    785870    uint64_t u64Timestamp; 
    786     bool warn = false; 
    787871 
    788872    /* 
     
    790874     */ 
    791875    LogFlowThisFunc(("\n")); 
    792     if (   (cParms != 3)  /* Hardcoded value as the next lines depend on it. */ 
    793         || RT_FAILURE(paParms[0].getUInt64 (&u64Timestamp))  /* timestamp */ 
    794         || RT_FAILURE(paParms[1].getPointer ((void **) &pchBuf, &cchBuf))  /* return buffer */ 
     876    if (   (cParms != 4)  /* Hardcoded value as the next lines depend on it. */ 
     877        || RT_FAILURE(paParms[0].getPointer ((void **) &pszPatterns, &cchPatterns))  /* patterns */ 
     878        || pszPatterns[cchPatterns - 1] != '\0'  /* The patterns string must be zero-terminated */ 
     879        || RT_FAILURE(paParms[1].getUInt64 (&u64Timestamp))  /* timestamp */ 
     880        || RT_FAILURE(paParms[2].getPointer ((void **) &pchBuf, &cchBuf))  /* return buffer */ 
    795881        || cchBuf < 1 
    796882       ) 
     
    800886     * Find the change to notify of. 
    801887     */ 
    802     Property next; 
    803     /* Return the oldest notification if no timestamp was specified. */ 
    804     if (RT_SUCCESS(rc) && !mGuestNotifications.empty() && u64Timestamp == 0) 
    805         next = mGuestNotifications.front(); 
    806     /* Only search if the guest hasn't seen the most recent notification. */ 
    807     else if (   RT_SUCCESS(rc) 
    808              && !mGuestNotifications.empty() 
    809              && mGuestNotifications.back().mTimestamp != u64Timestamp) 
    810     { 
    811         /* We count backwards, as the guest should normally be querying the 
    812          * most recent events. */ 
    813         PropertyList::reverse_iterator it = mGuestNotifications.rbegin(); 
    814         for ( ;    it != mGuestNotifications.rend() 
    815                 && it->mTimestamp != u64Timestamp; 
    816              ++it 
    817             ) {} 
    818         /* Warn if the timestamp was not found. */ 
    819         if (it == mGuestNotifications.rend()) 
    820             warn = true; 
    821         /* This is a reverse iterator, so --it goes up the list. */ 
    822         --it; 
    823         next = *it; 
    824     } 
    825  
    826     /* 
    827      * Format the data to write to the buffer. 
    828      */ 
    829     std::string buffer; 
    830     if (RT_SUCCESS(rc)) 
    831     { 
    832         char szFlags[MAX_FLAGS_LEN]; 
    833         rc = writeFlags(next.mFlags, szFlags); 
    834         if (RT_SUCCESS(rc)) 
    835         { 
    836             buffer += next.mName; 
    837             buffer += '\0'; 
    838             buffer += next.mValue; 
    839             buffer += '\0'; 
    840             buffer += szFlags; 
    841             buffer += '\0'; 
    842             u64Timestamp = next.mTimestamp; 
    843         } 
    844     } 
    845  
    846     /* 
    847      * Write out the data or add the caller to the notification list if there 
    848      * is no notification available. 
    849      */ 
     888    Property prop; 
    850889    if (RT_SUCCESS(rc) && u64Timestamp != 0) 
    851     { 
    852         paParms[0].setUInt64(u64Timestamp); 
    853         paParms[2].setUInt32(buffer.size()); 
    854         if (RT_SUCCESS(rc) && buffer.size() <= cchBuf) 
    855             buffer.copy(pchBuf, cchBuf); 
    856         else if (RT_SUCCESS(rc)) 
    857             rc = VERR_BUFFER_OVERFLOW; 
    858         if (RT_SUCCESS(rc) && warn) 
    859             rc = VWRN_NOT_FOUND; 
    860     } 
    861     else if (RT_SUCCESS(rc) && canWait) 
    862     { 
    863         mGuestWaiters.push_back(GuestCall(callHandle, GET_NOTIFICATION, cParms, 
    864                                          paParms)); 
     890        rc = getOldNotification(pszPatterns, u64Timestamp, &prop); 
     891    if (   (RT_SUCCESS(rc) && u64Timestamp == 0) 
     892        || (RT_SUCCESS(rc) && prop.mName.size() == 1)  /* Empty name -> not found */ 
     893       ) 
     894    { 
     895        mGuestWaiters.push_back(GuestCall(callHandle, GET_NOTIFICATION, 
     896                                          paParms, rc)); 
    865897        rc = VINF_HGCM_ASYNC_EXECUTE; 
    866898    } 
    867     else if (RT_SUCCESS(rc)) 
    868     { 
    869         AssertFailed(); 
    870         rc = VERR_INTERNAL_ERROR; 
     899    else 
     900    { 
     901        int rc2 = getNotificationWriteOut(paParms, prop); 
     902        if (RT_FAILURE(rc2)) 
     903            rc = rc2; 
    871904    } 
    872905    return rc; 
     
    885918void Service::doNotifications(const char *pszProperty, uint64_t u64Timestamp) 
    886919{ 
    887     char szFlags[MAX_FLAGS_LEN]; 
    888920    char *pszName = NULL, *pszValue = NULL, *pszFlags = NULL; 
    889921    int rc = VINF_SUCCESS; 
     
    898930     * Try to find the property. 
    899931     */ 
    900     PropertyList::const_iterator it
     932    Property prop
    901933    bool found = false; 
    902934    if (RT_SUCCESS(rc)) 
    903         for (it = mProperties.begin(); it != mProperties.end(); ++it) 
     935        for (PropertyList::const_iterator it = mProperties.begin(); 
     936             !found && it != mProperties.end(); ++it) 
    904937            if (it->mName.compare(pszProperty) == 0) 
    905938            { 
    906939                found = true; 
    907                 break
     940                prop = *it
    908941            } 
    909942 
     
    914947    { 
    915948#ifndef VBOX_GUEST_PROP_TEST_NOTHREAD 
     949        char szFlags[MAX_FLAGS_LEN]; 
    916950        /* Send out a host notification */ 
    917         rc = writeFlags(it->mFlags, szFlags); 
     951        rc = writeFlags(prop.mFlags, szFlags); 
    918952        if (RT_SUCCESS(rc)) 
    919953            rc = RTStrDupEx(&pszName, pszProperty); 
    920954        if (RT_SUCCESS(rc)) 
    921             rc = RTStrDupEx(&pszValue, it->mValue.c_str()); 
     955            rc = RTStrDupEx(&pszValue, prop.mValue.c_str()); 
    922956        if (RT_SUCCESS(rc)) 
    923957            rc = RTStrDupEx(&pszFlags, szFlags); 
     
    932966    if (found) 
    933967    { 
    934         /* Add the change to the queue for guest notifications and release 
    935          * waiters */ 
     968        /* Release waiters if applicable and add the change to the queue for 
     969         * guest notifications */ 
    936970        if (RT_SUCCESS(rc)) 
    937971        { 
    938972            try 
    939973            { 
    940                 mGuestNotifications.push_back(*it); 
    941                 while (mGuestWaiters.size() > 0
     974                for (CallList::iterator it = mGuestWaiters.begin(); 
     975                     it != mGuestWaiters.end(); ++it
    942976                { 
    943                     GuestCall call = mGuestWaiters.back(); 
    944                     int rc2 = getNotification(call.mHandle, call.mcParms, 
    945                                               call.mParms, false); 
    946                     mpHelpers->pfnCallComplete (call.mHandle, rc2); 
    947                     mGuestWaiters.pop_back(); 
     977                    const char *pszPatterns; 
     978                    uint32_t cchPatterns; 
     979                    it->mParms[0].getPointer((void **) &pszPatterns, &cchPatterns); 
     980                    if (   pszPatterns[0] == '\0' 
     981                        || RTStrSimplePatternMultiMatch(pszPatterns, RTSTR_MAX, 
     982                                                        pszProperty, RTSTR_MAX, 
     983                                                        NULL)) 
     984                    { 
     985                        GuestCall call = mGuestWaiters.back(); 
     986                        int rc2 = getNotificationWriteOut(call.mParms, prop); 
     987                        if (RT_SUCCESS(rc2)) 
     988                            rc2 = call.mRc; 
     989                        mpHelpers->pfnCallComplete (call.mHandle, rc2); 
     990                        it = mGuestWaiters.erase(it); 
     991                    } 
    948992                } 
     993                mGuestNotifications.push_back(prop); 
    949994            } 
    950995            catch (std::bad_alloc) 
     
    10811126            case GET_NOTIFICATION: 
    10821127                LogFlowFunc(("GET_NOTIFICATION\n")); 
    1083                 rc = getNotification(callHandle, cParms, paParms, true); 
     1128                rc = getNotification(callHandle, cParms, paParms); 
    10841129                break; 
    10851130 
  • trunk/src/VBox/HostServices/GuestProperties/testcase/Makefile.kmk

    r13916 r14104  
    3434tstGuestPropSvc_SOURCES  = tstGuestPropSvc.cpp ../service.cpp 
    3535tstGuestPropSvc_LIBS     = $(LIB_RUNTIME) 
     36# For now! 
     37tstGuestPropSvc_CXXFLAGS.win = -EHsc 
    3638 
    3739# Set this in LocalConfig.kmk if you are working on the guest property service 
  • trunk/src/VBox/HostServices/GuestProperties/testcase/tstGuestPropSvc.cpp

    r13971 r14104  
    241241 
    242242/** Result string sizes for zeroth enumeration test */ 
    243 static const size_t cchEnumResult0[] = 
     243static const uint32_t cchEnumResult0[] = 
    244244{ 
    245245    sizeof("test/name/\0test/value/\0""0\0"), 
     
    254254 * the - 1 at the end is because of the hidden zero terminator 
    255255 */ 
    256 static const size_t cchEnumBuffer0 = 
     256static const uint32_t cchEnumBuffer0 = 
    257257sizeof("test/name/\0test/value/\0""0\0\0" 
    258258"test name\0test value\0""999\0TRANSIENT, READONLY\0" 
     
    269269 
    270270/** Result string sizes for first and second enumeration test */ 
    271 static const size_t cchEnumResult1[] = 
     271static const uint32_t cchEnumResult1[] = 
    272272{ 
    273273    sizeof("TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST"), 
     
    280280 * the - 1 at the end is because of the hidden zero terminator 
    281281 */ 
    282 static const size_t cchEnumBuffer1 = 
     282static const uint32_t cchEnumBuffer1 = 
    283283sizeof("TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST\0" 
    284284"/test/name\0/test/value\0""999999999999\0RDONLYGUEST\0\0\0\0\0") - 1; 
     
    289289    const char *pcszPatterns; 
    290290    /** The size of the pattern string */ 
    291     const size_t cchPatterns; 
     291    const uint32_t cchPatterns; 
    292292    /** The expected enumeration output strings */ 
    293293    const char **ppcchResult; 
    294294    /** The size of the output strings */ 
    295     const size_t *pcchResult; 
     295    const uint32_t *pcchResult; 
    296296    /** The size of the buffer needed for the enumeration */ 
    297     const size_t cchBuffer; 
     297    const uint32_t cchBuffer; 
    298298} 
    299299enumStrings[] = 
     
    693693    VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS }; 
    694694    char chBuffer[MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN]; 
     695    static char szPattern[] = ""; 
    695696 
    696697    RTPrintf("Testing the GET_NOTIFICATION call.\n"); 
    697     uint64_t u64Timestamp = 0
     698    uint64_t u64Timestamp
    698699    uint32_t u32Size = 0; 
    699     VBOXHGCMSVCPARM paParms[3]; 
     700    VBOXHGCMSVCPARM paParms[4]; 
    700701 
    701702    /* Test "buffer too small" */ 
    702     paParms[0].setUInt64 (u64Timestamp); 
    703     paParms[1].setPointer ((void *) chBuffer, getNotifications[0].cchBuffer - 1); 
     703    u64Timestamp = 1; 
     704    paParms[0].setPointer ((void *) szPattern, sizeof(szPattern)); 
     705    paParms[1].setUInt64 (u64Timestamp); 
     706    paParms[2].setPointer ((void *) chBuffer, getNotifications[0].cchBuffer - 1); 
    704707    pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, 
    705                     GET_NOTIFICATION, 3, paParms); 
     708                    GET_NOTIFICATION, 4, paParms); 
    706709    if (   callHandle.rc != VERR_BUFFER_OVERFLOW 
    707         || RT_FAILURE(paParms[2].getUInt32 (&u32Size)) 
     710        || RT_FAILURE(paParms[3].getUInt32 (&u32Size)) 
    708711        || u32Size != getNotifications[0].cchBuffer 
    709712       ) 
     
    714717    } 
    715718 
    716     /* Test successful notification queries */ 
     719    /* Test successful notification queries.  Start with an unknown timestamp 
     720     * to get the oldest available notification. */ 
     721    u64Timestamp = 1; 
    717722    for (unsigned i = 0; RT_SUCCESS(rc) && (getNotifications[i].pchBuffer != NULL); 
    718723         ++i) 
    719724    { 
    720         paParms[0].setUInt64 (u64Timestamp); 
    721         paParms[1].setPointer ((void *) chBuffer, sizeof(chBuffer)); 
     725        paParms[0].setPointer ((void *) szPattern, sizeof(szPattern)); 
     726        paParms[1].setUInt64 (u64Timestamp); 
     727        paParms[2].setPointer ((void *) chBuffer, sizeof(chBuffer)); 
    722728        pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, 
    723                         GET_NOTIFICATION, 3, paParms); 
     729                        GET_NOTIFICATION, 4, paParms); 
    724730        if (   RT_FAILURE(callHandle.rc) 
    725             || RT_FAILURE(paParms[0].getUInt64 (&u64Timestamp)) 
    726             || RT_FAILURE(paParms[2].getUInt32 (&u32Size)) 
     731            || (i == 0 && callHandle.rc != VWRN_NOT_FOUND) 
     732            || RT_FAILURE(paParms[1].getUInt64 (&u64Timestamp)) 
     733            || RT_FAILURE(paParms[3].getUInt32 (&u32Size)) 
    727734            || u32Size != getNotifications[i].cchBuffer 
    728735            || memcmp(chBuffer, getNotifications[i].pchBuffer, u32Size) != 0 
     
    734741        } 
    735742    } 
    736  
    737     /* Test a query with an unknown timestamp */ 
    738     paParms[0].setUInt64 (1); 
    739     paParms[1].setPointer ((void *) chBuffer, sizeof(chBuffer)); 
    740     if (RT_SUCCESS(rc)) 
    741         pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, 
    742                         GET_NOTIFICATION, 3, paParms); 
    743     if (   RT_SUCCESS(rc) 
    744         && (   callHandle.rc != VWRN_NOT_FOUND 
    745             || RT_FAILURE(callHandle.rc) 
    746             || RT_FAILURE(paParms[0].getUInt64 (&u64Timestamp)) 
    747             || RT_FAILURE(paParms[2].getUInt32 (&u32Size)) 
    748             || u32Size != getNotifications[0].cchBuffer 
    749             || memcmp(chBuffer, getNotifications[0].pchBuffer, u32Size) != 0 
    750            ) 
    751        ) 
    752     { 
    753         RTPrintf("Problem getting notification for property '%s' with unknown timestamp, rc=%Rrc.\n", 
    754                  getNotifications[0].pchBuffer, callHandle.rc); 
    755         rc = VERR_UNRESOLVED_ERROR; 
    756     } 
    757743    return rc; 
    758744} 
    759745 
    760 /** 
    761  * Test the GET_NOTIFICATION function when no notifications are available. 
     746/** Paramters for the asynchronous guest notification call */ 
     747struct asyncNotification_ 
     748
     749    /** Call parameters */ 
     750    VBOXHGCMSVCPARM aParms[4]; 
     751    /** Result buffer */ 
     752    char chBuffer[MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN]; 
     753    /** Return value */ 
     754    VBOXHGCMCALLHANDLE_TYPEDEF callHandle; 
     755} asyncNotification; 
     756 
     757/** 
     758 * Set up the test for the asynchronous GET_NOTIFICATION function. 
    762759 * @returns iprt status value to indicate whether the test went as expected. 
    763760 * @note    prints its own diagnostic information to stdout. 
    764761 */ 
    765 int testNoNotifications(VBOXHGCMSVCFNTABLE *pTable, VBOXHGCMCALLHANDLE_TYPEDEF *callHandle, 
    766                         VBOXHGCMSVCPARM *paParms, char *pchBuffer, size_t cchBuffer) 
     762int setupAsyncNotification(VBOXHGCMSVCFNTABLE *pTable) 
    767763{ 
    768764    int rc = VINF_SUCCESS; 
     
    771767    uint64_t u64Timestamp = 0; 
    772768    uint32_t u32Size = 0; 
    773  
    774     paParms[0].setUInt64 (u64Timestamp); 
    775     paParms[1].setPointer ((void *) pchBuffer, cchBuffer); 
    776     callHandle->rc = VINF_HGCM_ASYNC_EXECUTE; 
    777     pTable->pfnCall(pTable->pvService, callHandle, 0, NULL, 
    778                     GET_NOTIFICATION, 3, paParms); 
    779     if (callHandle->rc != VINF_HGCM_ASYNC_EXECUTE) 
    780     { 
    781         RTPrintf("GET_NOTIFICATION call completed when new notifications should be available.\n"); 
     769    static char szPattern[] = ""; 
     770 
     771    asyncNotification.aParms[0].setPointer ((void *) szPattern, sizeof(szPattern)); 
     772    asyncNotification.aParms[1].setUInt64 (u64Timestamp); 
     773    asyncNotification.aParms[2].setPointer ((void *) asyncNotification.chBuffer, 
     774                                            sizeof(asyncNotification.chBuffer)); 
     775    asyncNotification.callHandle.rc = VINF_HGCM_ASYNC_EXECUTE; 
     776    pTable->pfnCall(pTable->pvService, &asyncNotification.callHandle, 0, NULL, 
     777                    GET_NOTIFICATION, 4, asyncNotification.aParms); 
     778    if (RT_FAILURE(asyncNotification.callHandle.rc)) 
     779    { 
     780        RTPrintf("GET_NOTIFICATION call failed, rc=%Rrc.\n", asyncNotification.callHandle.rc); 
     781        rc = VERR_UNRESOLVED_ERROR; 
     782    } 
     783    else if (asyncNotification.callHandle.rc != VINF_HGCM_ASYNC_EXECUTE) 
     784    { 
     785        RTPrintf("GET_NOTIFICATION call completed when no new notifications should be available.\n"); 
     786        rc = VERR_UNRESOLVED_ERROR; 
     787    } 
     788    return rc; 
     789
     790 
     791/** 
     792 * Test the asynchronous GET_NOTIFICATION function. 
     793 * @returns iprt status value to indicate whether the test went as expected. 
     794 * @note    prints its own diagnostic information to stdout. 
     795 */ 
     796int testAsyncNotification(VBOXHGCMSVCFNTABLE *pTable) 
     797
     798    int rc = VINF_SUCCESS; 
     799    uint64_t u64Timestamp; 
     800    uint32_t u32Size; 
     801    if (   asyncNotification.callHandle.rc != VINF_SUCCESS 
     802        || RT_FAILURE(asyncNotification.aParms[1].getUInt64 (&u64Timestamp)) 
     803        || RT_FAILURE(asyncNotification.aParms[3].getUInt32 (&u32Size)) 
     804        || u32Size != getNotifications[0].cchBuffer 
     805        || memcmp(asyncNotification.chBuffer, getNotifications[0].pchBuffer, u32Size) != 0 
     806       ) 
     807    { 
     808        RTPrintf("Asynchronous GET_NOTIFICATION call did not complete as expected, rc=%Rrc\n", 
     809                 asyncNotification.callHandle.rc); 
    782810        rc = VERR_UNRESOLVED_ERROR; 
    783811    } 
     
    789817    VBOXHGCMSVCFNTABLE svcTable; 
    790818    VBOXHGCMSVCHELPERS svcHelpers; 
    791     /* Paramters for the asynchronous guest notification call */ 
    792     VBOXHGCMSVCPARM aParm[3]; 
    793     char chBuffer[MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN]; 
    794     VBOXHGCMCALLHANDLE_TYPEDEF callHandleStruct; 
    795819 
    796820    initTable(&svcTable, &svcHelpers); 
     
    808832    if (RT_FAILURE(testEnumPropsHost(&svcTable))) 
    809833        return 1; 
    810     /* Asynchronous notification call */ 
    811     if (RT_FAILURE(testNoNotifications(&svcTable, &callHandleStruct, aParm, 
    812                    chBuffer, sizeof(chBuffer)))) 
     834    /* Set up the asynchronous notification test */ 
     835    if (RT_FAILURE(setupAsyncNotification(&svcTable))) 
    813836        return 1; 
    814837    if (RT_FAILURE(testSetProp(&svcTable))) 
     
    816839    RTPrintf("Checking the data returned by the asynchronous notification call.\n"); 
    817840    /* Our previous notification call should have completed by now. */ 
    818     uint64_t u64Timestamp; 
    819     uint32_t u32Size; 
    820     if (   callHandleStruct.rc != VINF_SUCCESS 
    821         || RT_FAILURE(aParm[0].getUInt64 (&u64Timestamp)) 
    822         || RT_FAILURE(aParm[2].getUInt32 (&u32Size)) 
    823         || u32Size != getNotifications[0].cchBuffer 
    824         || memcmp(chBuffer, getNotifications[0].pchBuffer, u32Size) != 0 
    825        ) 
    826     { 
    827         RTPrintf("Asynchronous GET_NOTIFICATION call did not complete as expected, rc=%Rrc\n", 
    828                  callHandleStruct.rc); 
    829         return 1; 
    830     } 
     841    if (RT_FAILURE(testAsyncNotification(&svcTable))) 
     842        return 1; 
    831843    if (RT_FAILURE(testDelProp(&svcTable))) 
    832844        return 1; 

© 2008 Sun Microsystems, Inc.
ContactPrivacy policy