~ubuntu-branches/ubuntu/vivid/virtualbox/vivid

« back to all changes in this revision

Viewing changes to src/VBox/HostServices/GuestProperties/service.cpp

  • Committer: Package Import Robot
  • Author(s): Felix Geyer
  • Date: 2011-12-29 12:29:25 UTC
  • mfrom: (3.1.8 sid)
  • Revision ID: package-import@ubuntu.com-20111229122925-8ota2o33fuk0bkf8
Tags: 4.1.8-dfsg-1
* New upstream release.
* Move all transitional packages to section oldlibs and priority extra.
* Refresh 16-no-update.patch.
* Drop 36-kernel-3.2.patch, applied upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
63
63
 */
64
64
struct Property
65
65
{
 
66
    /** The string space core record. */
 
67
    RTSTRSPACECORE mStrCore;
66
68
    /** The name of the property */
67
69
    std::string mName;
68
70
    /** The property value */
73
75
    uint32_t mFlags;
74
76
 
75
77
    /** Default constructor */
76
 
    Property() : mTimestamp(0), mFlags(NILFLAG) {}
 
78
    Property() : mTimestamp(0), mFlags(NILFLAG)
 
79
    {
 
80
        RT_ZERO(mStrCore);
 
81
    }
77
82
    /** Constructor with const char * */
78
83
    Property(const char *pcszName, const char *pcszValue,
79
84
             uint64_t u64Timestamp, uint32_t u32Flags)
80
85
        : mName(pcszName), mValue(pcszValue), mTimestamp(u64Timestamp),
81
 
          mFlags(u32Flags) {}
 
86
          mFlags(u32Flags)
 
87
    {
 
88
        RT_ZERO(mStrCore);
 
89
        mStrCore.pszString = mName.c_str();
 
90
    }
82
91
    /** Constructor with std::string */
83
92
    Property(std::string name, std::string value, uint64_t u64Timestamp,
84
93
             uint32_t u32Flags)
155
164
    PVBOXHGCMSVCHELPERS mpHelpers;
156
165
    /** Global flags for the service */
157
166
    ePropFlags meGlobalFlags;
158
 
    /** The property list */
159
 
    PropertyList mProperties;
 
167
    /** The property string space handle. */
 
168
    RTSTRSPACE mhProperties;
 
169
    /** The number of properties. */
 
170
    unsigned mcProperties;
160
171
    /** The list of property changes for guest notifications */
161
172
    PropertyList mGuestNotifications;
162
173
    /** The list of outstanding guest notification calls */
247
258
        return VINF_SUCCESS;
248
259
    }
249
260
 
 
261
    /**
 
262
     * Gets a property.
 
263
     *
 
264
     * @returns Pointer to the property if found, NULL if not.
 
265
     *
 
266
     * @param   pszName     The name of the property to get.
 
267
     */
 
268
    Property *getPropertyInternal(const char *pszName)
 
269
    {
 
270
        return (Property *)RTStrSpaceGet(&mhProperties, pszName);
 
271
    }
 
272
 
250
273
public:
251
274
    explicit Service(PVBOXHGCMSVCHELPERS pHelpers)
252
275
        : mpHelpers(pHelpers)
253
276
        , meGlobalFlags(NILFLAG)
 
277
        , mhProperties(NULL)
 
278
        , mcProperties(0)
254
279
        , mpfnHostCallback(NULL)
255
280
        , mpvHostData(NULL)
256
281
        , mPrevTimestamp(0)
261
286
     * @copydoc VBOXHGCMSVCHELPERS::pfnUnload
262
287
     * Simply deletes the service object
263
288
     */
264
 
    static DECLCALLBACK(int) svcUnload (void *pvService)
 
289
    static DECLCALLBACK(int) svcUnload(void *pvService)
265
290
    {
266
291
        AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
267
292
        SELF *pSelf = reinterpret_cast<SELF *>(pvService);
276
301
     * @copydoc VBOXHGCMSVCHELPERS::pfnConnect
277
302
     * Stub implementation of pfnConnect and pfnDisconnect.
278
303
     */
279
 
    static DECLCALLBACK(int) svcConnectDisconnect (void * /* pvService */,
280
 
                                                   uint32_t /* u32ClientID */,
281
 
                                                   void * /* pvClient */)
 
304
    static DECLCALLBACK(int) svcConnectDisconnect(void * /* pvService */,
 
305
                                                  uint32_t /* u32ClientID */,
 
306
                                                  void * /* pvClient */)
282
307
    {
283
308
        return VINF_SUCCESS;
284
309
    }
287
312
     * @copydoc VBOXHGCMSVCHELPERS::pfnCall
288
313
     * Wraps to the call member function
289
314
     */
290
 
    static DECLCALLBACK(void) svcCall (void * pvService,
291
 
                                       VBOXHGCMCALLHANDLE callHandle,
292
 
                                       uint32_t u32ClientID,
293
 
                                       void *pvClient,
294
 
                                       uint32_t u32Function,
295
 
                                       uint32_t cParms,
296
 
                                       VBOXHGCMSVCPARM paParms[])
 
315
    static DECLCALLBACK(void) svcCall(void * pvService,
 
316
                                      VBOXHGCMCALLHANDLE callHandle,
 
317
                                      uint32_t u32ClientID,
 
318
                                      void *pvClient,
 
319
                                      uint32_t u32Function,
 
320
                                      uint32_t cParms,
 
321
                                      VBOXHGCMSVCPARM paParms[])
297
322
    {
298
323
        AssertLogRelReturnVoid(VALID_PTR(pvService));
299
 
        LogFlowFunc (("pvService=%p, callHandle=%p, u32ClientID=%u, pvClient=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, callHandle, u32ClientID, pvClient, u32Function, cParms, paParms));
 
324
        LogFlowFunc(("pvService=%p, callHandle=%p, u32ClientID=%u, pvClient=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, callHandle, u32ClientID, pvClient, u32Function, cParms, paParms));
300
325
        SELF *pSelf = reinterpret_cast<SELF *>(pvService);
301
326
        pSelf->call(callHandle, u32ClientID, pvClient, u32Function, cParms, paParms);
302
 
        LogFlowFunc (("returning\n"));
 
327
        LogFlowFunc(("returning\n"));
303
328
    }
304
329
 
305
330
    /**
306
331
     * @copydoc VBOXHGCMSVCHELPERS::pfnHostCall
307
332
     * Wraps to the hostCall member function
308
333
     */
309
 
    static DECLCALLBACK(int) svcHostCall (void *pvService,
310
 
                                          uint32_t u32Function,
311
 
                                          uint32_t cParms,
312
 
                                          VBOXHGCMSVCPARM paParms[])
 
334
    static DECLCALLBACK(int) svcHostCall(void *pvService,
 
335
                                         uint32_t u32Function,
 
336
                                         uint32_t cParms,
 
337
                                         VBOXHGCMSVCPARM paParms[])
313
338
    {
314
339
        AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
315
 
        LogFlowFunc (("pvService=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, u32Function, cParms, paParms));
 
340
        LogFlowFunc(("pvService=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, u32Function, cParms, paParms));
316
341
        SELF *pSelf = reinterpret_cast<SELF *>(pvService);
317
342
        int rc = pSelf->hostCall(u32Function, cParms, paParms);
318
 
        LogFlowFunc (("rc=%Rrc\n", rc));
 
343
        LogFlowFunc(("rc=%Rrc\n", rc));
319
344
        return rc;
320
345
    }
321
346
 
323
348
     * @copydoc VBOXHGCMSVCHELPERS::pfnRegisterExtension
324
349
     * Installs a host callback for notifications of property changes.
325
350
     */
326
 
    static DECLCALLBACK(int) svcRegisterExtension (void *pvService,
327
 
                                                   PFNHGCMSVCEXT pfnExtension,
328
 
                                                   void *pvExtension)
 
351
    static DECLCALLBACK(int) svcRegisterExtension(void *pvService,
 
352
                                                  PFNHGCMSVCEXT pfnExtension,
 
353
                                                  void *pvExtension)
329
354
    {
330
355
        AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
331
356
        SELF *pSelf = reinterpret_cast<SELF *>(pvService);
352
377
    int notifyHost(const char *pszName, const char *pszValue,
353
378
                   uint64_t u64Timestamp, const char *pszFlags);
354
379
 
355
 
    void call (VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID,
356
 
               void *pvClient, uint32_t eFunction, uint32_t cParms,
357
 
               VBOXHGCMSVCPARM paParms[]);
358
 
    int hostCall (uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
359
 
    int uninit ();
 
380
    void call(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID,
 
381
              void *pvClient, uint32_t eFunction, uint32_t cParms,
 
382
              VBOXHGCMSVCPARM paParms[]);
 
383
    int hostCall(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
 
384
    int uninit();
360
385
};
361
386
 
362
387
 
441
466
 */
442
467
int Service::setPropertyBlock(uint32_t cParms, VBOXHGCMSVCPARM paParms[])
443
468
{
444
 
    char **ppNames, **ppValues, **ppFlags;
445
 
    uint64_t *pTimestamps;
446
 
    uint32_t cbDummy;
447
 
    int rc = VINF_SUCCESS;
 
469
    const char **papszNames;
 
470
    const char **papszValues;
 
471
    const char **papszFlags;
 
472
    uint64_t    *pau64Timestamps;
 
473
    uint32_t     cbDummy;
 
474
    int          rc = VINF_SUCCESS;
448
475
 
449
476
    /*
450
477
     * Get and validate the parameters
451
478
     */
452
 
    if (   (cParms != 4)
453
 
        || RT_FAILURE(paParms[0].getPointer ((void **) &ppNames, &cbDummy))
454
 
        || RT_FAILURE(paParms[1].getPointer ((void **) &ppValues, &cbDummy))
455
 
        || RT_FAILURE(paParms[2].getPointer ((void **) &pTimestamps, &cbDummy))
456
 
        || RT_FAILURE(paParms[3].getPointer ((void **) &ppFlags, &cbDummy))
 
479
    if (   cParms != 4
 
480
        || RT_FAILURE(paParms[0].getPointer((void **)&papszNames, &cbDummy))
 
481
        || RT_FAILURE(paParms[1].getPointer((void **)&papszValues, &cbDummy))
 
482
        || RT_FAILURE(paParms[2].getPointer((void **)&pau64Timestamps, &cbDummy))
 
483
        || RT_FAILURE(paParms[3].getPointer((void **)&papszFlags, &cbDummy))
457
484
        )
458
485
        rc = VERR_INVALID_PARAMETER;
459
 
 
460
 
    /*
461
 
     * Add the properties to the end of the list.  If we succeed then we
462
 
     * will remove duplicates afterwards.
463
 
     */
464
 
    /* Remember the last property before we started adding, for rollback or
465
 
     * cleanup. */
466
 
    PropertyList::iterator itEnd = mProperties.end();
467
 
    if (!mProperties.empty())
468
 
        --itEnd;
469
 
    try
470
 
    {
471
 
        for (unsigned i = 0; RT_SUCCESS(rc) && ppNames[i] != NULL; ++i)
 
486
    /** @todo validate the array sizes... */
 
487
 
 
488
    for (unsigned i = 0; RT_SUCCESS(rc) && papszNames[i] != NULL; ++i)
 
489
    {
 
490
        if (   !RT_VALID_PTR(papszNames[i])
 
491
            || !RT_VALID_PTR(papszValues[i])
 
492
            || !RT_VALID_PTR(papszFlags[i])
 
493
            )
 
494
            rc = VERR_INVALID_POINTER;
 
495
        else
 
496
        {
 
497
            uint32_t fFlagsIgn;
 
498
            rc = validateFlags(papszFlags[i], &fFlagsIgn);
 
499
        }
 
500
    }
 
501
 
 
502
    if (RT_SUCCESS(rc))
 
503
    {
 
504
        /*
 
505
         * Add the properties.  No way to roll back here.
 
506
         */
 
507
        for (unsigned i = 0; papszNames[i] != NULL; ++i)
472
508
        {
473
509
            uint32_t fFlags;
474
 
            if (   !VALID_PTR(ppNames[i])
475
 
                || !VALID_PTR(ppValues[i])
476
 
                || !VALID_PTR(ppFlags[i])
477
 
              )
478
 
                rc = VERR_INVALID_POINTER;
479
 
            if (RT_SUCCESS(rc))
480
 
                rc = validateFlags(ppFlags[i], &fFlags);
481
 
            if (RT_SUCCESS(rc))
482
 
                mProperties.push_back(Property(ppNames[i], ppValues[i],
483
 
                                               pTimestamps[i], fFlags));
484
 
        }
485
 
    }
486
 
    catch (std::bad_alloc)
487
 
    {
488
 
        rc = VERR_NO_MEMORY;
489
 
    }
 
510
            rc = validateFlags(papszFlags[i], &fFlags);
 
511
            AssertRCBreak(rc);
490
512
 
491
 
    /*
492
 
     * If all went well then remove the duplicate elements.
493
 
     */
494
 
    if (RT_SUCCESS(rc) && itEnd != mProperties.end())
495
 
    {
496
 
        ++itEnd;
497
 
        for (unsigned i = 0; ppNames[i] != NULL; ++i)
498
 
            for (PropertyList::iterator it = mProperties.begin(); it != itEnd; ++it)
499
 
                if (it->mName.compare(ppNames[i]) == 0)
 
513
            Property *pProp = getPropertyInternal(papszNames[i]);
 
514
            if (pProp)
 
515
            {
 
516
                /* Update existing property. */
 
517
                pProp->mValue     = papszValues[i];
 
518
                pProp->mTimestamp = pau64Timestamps[i];
 
519
                pProp->mFlags     = fFlags;
 
520
            }
 
521
            else
 
522
            {
 
523
                /* Create a new property */
 
524
                pProp = new Property(papszNames[i], papszValues[i], pau64Timestamps[i], fFlags);
 
525
                if (!pProp)
500
526
                {
501
 
                    mProperties.erase(it);
 
527
                    rc = VERR_NO_MEMORY;
502
528
                    break;
503
529
                }
 
530
                if (RTStrSpaceInsert(&mhProperties, &pProp->mStrCore))
 
531
                    mcProperties++;
 
532
                else
 
533
                {
 
534
                    delete pProp;
 
535
                    rc = VERR_INTERNAL_ERROR_3;
 
536
                    AssertFailedBreak();
 
537
                }
 
538
            }
 
539
        }
504
540
    }
505
541
 
506
 
    /*
507
 
     * If something went wrong then rollback.  This is possible because we
508
 
     * haven't deleted anything yet.
509
 
     */
510
 
    if (RT_FAILURE(rc))
511
 
    {
512
 
        if (itEnd != mProperties.end())
513
 
            ++itEnd;
514
 
        mProperties.erase(itEnd, mProperties.end());
515
 
    }
516
542
    return rc;
517
543
}
518
544
 
530
556
 */
531
557
int Service::getProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[])
532
558
{
533
 
    int rc = VINF_SUCCESS;
 
559
    int         rc;
534
560
    const char *pcszName = NULL;        /* shut up gcc */
535
 
    char *pchBuf;
536
 
    uint32_t cchName, cchBuf;
537
 
    char szFlags[MAX_FLAGS_LEN];
 
561
    char       *pchBuf;
 
562
    uint32_t    cbName, cbBuf;
538
563
 
539
564
    /*
540
565
     * Get and validate the parameters
541
566
     */
542
567
    LogFlowThisFunc(("\n"));
543
568
    if (   cParms != 4  /* Hardcoded value as the next lines depend on it. */
544
 
        || RT_FAILURE (paParms[0].getString(&pcszName, &cchName))  /* name */
545
 
        || RT_FAILURE (paParms[1].getBuffer((void **) &pchBuf, &cchBuf))  /* buffer */
 
569
        || RT_FAILURE(paParms[0].getString(&pcszName, &cbName))  /* name */
 
570
        || RT_FAILURE(paParms[1].getBuffer((void **)&pchBuf, &cbBuf))  /* buffer */
546
571
       )
547
572
        rc = VERR_INVALID_PARAMETER;
548
573
    else
549
 
        rc = validateName(pcszName, cchName);
 
574
        rc = validateName(pcszName, cbName);
 
575
    if (RT_FAILURE(rc))
 
576
    {
 
577
        LogFlowThisFunc(("rc = %Rrc\n", rc));
 
578
        return rc;
 
579
    }
550
580
 
551
581
    /*
552
582
     * Read and set the values we will return
553
583
     */
554
584
 
555
 
    /* Get the value size */
556
 
    PropertyList::const_iterator it;
557
 
    if (RT_SUCCESS(rc))
 
585
    /* Get the property. */
 
586
    Property *pProp = getPropertyInternal(pcszName);
 
587
    if (pProp)
558
588
    {
 
589
        char szFlags[MAX_FLAGS_LEN];
 
590
        rc = writeFlags(pProp->mFlags, szFlags);
 
591
        if (RT_SUCCESS(rc))
 
592
        {
 
593
            /* Check that the buffer is big enough */
 
594
            size_t const cbFlags  = strlen(szFlags) + 1;
 
595
            size_t const cbValue  = pProp->mValue.size() + 1;
 
596
            size_t const cbNeeded = cbValue + cbFlags;
 
597
            paParms[3].setUInt32((uint32_t)cbNeeded);
 
598
            if (cbBuf >= cbNeeded)
 
599
            {
 
600
                /* Write the value, flags and timestamp */
 
601
                memcpy(pchBuf, pProp->mValue.c_str(), cbValue);
 
602
                memcpy(pchBuf + cbValue, szFlags, cbFlags);
 
603
 
 
604
                paParms[2].setUInt64(pProp->mTimestamp);
 
605
 
 
606
                /*
 
607
                 * Done!  Do exit logging and return.
 
608
                 */
 
609
                Log2(("Queried string %s, value=%s, timestamp=%lld, flags=%s\n",
 
610
                      pcszName, pProp->mValue.c_str(), pProp->mTimestamp, szFlags));
 
611
            }
 
612
            else
 
613
                rc = VERR_BUFFER_OVERFLOW;
 
614
        }
 
615
    }
 
616
    else
559
617
        rc = VERR_NOT_FOUND;
560
 
        for (it = mProperties.begin(); it != mProperties.end(); ++it)
561
 
            if (it->mName.compare(pcszName) == 0)
562
 
            {
563
 
                rc = VINF_SUCCESS;
564
 
                break;
565
 
            }
566
 
    }
567
 
    if (RT_SUCCESS(rc))
568
 
        rc = writeFlags(it->mFlags, szFlags);
569
 
    if (RT_SUCCESS(rc))
570
 
    {
571
 
        /* Check that the buffer is big enough */
572
 
        size_t cchBufActual = it->mValue.size() + 1 + strlen(szFlags);
573
 
        paParms[3].setUInt32 ((uint32_t)cchBufActual);
574
 
        if (cchBufActual <= cchBuf)
575
 
        {
576
 
            /* Write the value, flags and timestamp */
577
 
            it->mValue.copy(pchBuf, cchBuf, 0);
578
 
            pchBuf[it->mValue.size()] = '\0'; /* Terminate the value */
579
 
            strcpy(pchBuf + it->mValue.size() + 1, szFlags);
580
 
            paParms[2].setUInt64 (it->mTimestamp);
581
 
 
582
 
            /*
583
 
             * Done!  Do exit logging and return.
584
 
             */
585
 
            Log2(("Queried string %s, value=%s, timestamp=%lld, flags=%s\n",
586
 
                  pcszName, it->mValue.c_str(), it->mTimestamp, szFlags));
587
 
        }
588
 
        else
589
 
            rc = VERR_BUFFER_OVERFLOW;
590
 
    }
591
 
 
592
 
    LogFlowThisFunc(("rc = %Rrc\n", rc));
 
618
 
 
619
    LogFlowThisFunc(("rc = %Rrc (%s)\n", rc, pcszName));
593
620
    return rc;
594
621
}
595
622
 
617
644
    uint64_t u64TimeNano = getCurrentTimestamp();
618
645
 
619
646
    LogFlowThisFunc(("\n"));
620
 
    /*
621
 
     * First of all, make sure that we won't exceed the maximum number of properties.
622
 
     */
623
 
    if (mProperties.size() >= MAX_PROPS)
624
 
        rc = VERR_TOO_MUCH_DATA;
625
647
 
626
648
    /*
627
649
     * General parameter correctness checking.
649
671
                                     RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED);
650
672
    if ((3 == cParms) && RT_SUCCESS(rc))
651
673
        rc = validateFlags(pcszFlags, &fFlags);
652
 
    if (RT_SUCCESS(rc))
653
 
    {
654
 
        /*
655
 
         * If the property already exists, check its flags to see if we are allowed
656
 
         * to change it.
657
 
         */
658
 
        PropertyList::iterator it;
659
 
        bool found = false;
660
 
        for (it = mProperties.begin(); it != mProperties.end(); ++it)
661
 
            if (it->mName.compare(pcszName) == 0)
662
 
            {
663
 
                found = true;
664
 
                break;
665
 
            }
666
 
 
667
 
        rc = checkPermission(found ? (ePropFlags)it->mFlags : NILFLAG,
668
 
                             isGuest);
669
 
        if (rc == VINF_SUCCESS)
670
 
        {
671
 
            /*
672
 
             * Set the actual value
673
 
             */
674
 
            if (found)
675
 
            {
676
 
                it->mValue = pcszValue;
677
 
                it->mTimestamp = u64TimeNano;
678
 
                it->mFlags = fFlags;
679
 
            }
680
 
            else  /* This can throw.  No problem as we have nothing to roll back. */
681
 
                mProperties.push_back(Property(pcszName, pcszValue, u64TimeNano, fFlags));
682
 
 
683
 
            /*
684
 
             * Send a notification to the host and return.
685
 
             */
686
 
            // if (isGuest)  /* Notify the host even for properties that the host
687
 
            //                * changed.  Less efficient, but ensures consistency. */
688
 
                doNotifications(pcszName, u64TimeNano);
689
 
            Log2(("Set string %s, rc=%Rrc, value=%s\n", pcszName, rc, pcszValue));
690
 
        }
691
 
    }
692
 
 
693
 
    LogFlowThisFunc(("rc = %Rrc\n", rc));
 
674
    if (RT_FAILURE(rc))
 
675
    {
 
676
        LogFlowThisFunc(("rc = %Rrc\n", rc));
 
677
        return rc;
 
678
    }
 
679
 
 
680
    /*
 
681
     * If the property already exists, check its flags to see if we are allowed
 
682
     * to change it.
 
683
     */
 
684
    Property *pProp = getPropertyInternal(pcszName);
 
685
    rc = checkPermission(pProp ? (ePropFlags)pProp->mFlags : NILFLAG, isGuest);
 
686
    if (rc == VINF_SUCCESS)
 
687
    {
 
688
        /*
 
689
         * Set the actual value
 
690
         */
 
691
        if (pProp)
 
692
        {
 
693
            pProp->mValue = pcszValue;
 
694
            pProp->mTimestamp = u64TimeNano;
 
695
            pProp->mFlags = fFlags;
 
696
        }
 
697
        else if (mcProperties < MAX_PROPS)
 
698
        {
 
699
            /* Create a new string space record. */
 
700
            pProp = new Property(pcszName, pcszValue, u64TimeNano, fFlags);
 
701
            if (pProp)
 
702
            {
 
703
                if (RTStrSpaceInsert(&mhProperties, &pProp->mStrCore))
 
704
                    mcProperties++;
 
705
                else
 
706
                {
 
707
                    AssertFailed();
 
708
                    delete pProp;
 
709
                    rc = VERR_INTERNAL_ERROR_3;
 
710
                }
 
711
            }
 
712
            else
 
713
                rc = VERR_NO_MEMORY;
 
714
        }
 
715
        else
 
716
            rc = VERR_TOO_MUCH_DATA;
 
717
 
 
718
        /*
 
719
         * Send a notification to the host and return.
 
720
         */
 
721
        // if (isGuest)  /* Notify the host even for properties that the host
 
722
        //                * changed.  Less efficient, but ensures consistency. */
 
723
            doNotifications(pcszName, u64TimeNano);
 
724
        Log2(("Set string %s, rc=%Rrc, value=%s\n", pcszName, rc, pcszValue));
 
725
    }
 
726
 
 
727
    LogFlowThisFunc(("rc = %Rrc (%s = %s)\n", rc, pcszName, pcszValue));
694
728
    return rc;
695
729
}
696
730
 
707
741
 */
708
742
int Service::delProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest)
709
743
{
710
 
    int rc = VINF_SUCCESS;
 
744
    int         rc;
711
745
    const char *pcszName = NULL;        /* shut up gcc */
712
 
    uint32_t cbName;
 
746
    uint32_t    cbName;
713
747
 
714
748
    LogFlowThisFunc(("\n"));
715
749
 
722
756
        rc = validateName(pcszName, cbName);
723
757
    else
724
758
        rc = VERR_INVALID_PARAMETER;
725
 
    if (RT_SUCCESS(rc))
726
 
    {
727
 
        /*
728
 
         * If the property exists, check its flags to see if we are allowed
729
 
         * to change it.
730
 
         */
731
 
        PropertyList::iterator it;
732
 
        bool found = false;
733
 
        for (it = mProperties.begin(); it != mProperties.end(); ++it)
734
 
            if (it->mName.compare(pcszName) == 0)
735
 
            {
736
 
                found = true;
737
 
                rc = checkPermission((ePropFlags)it->mFlags, isGuest);
738
 
                break;
739
 
            }
740
 
 
741
 
        /*
742
 
         * And delete the property if all is well.
743
 
         */
744
 
        if (rc == VINF_SUCCESS && found)
745
 
        {
746
 
            uint64_t u64Timestamp = getCurrentTimestamp();
747
 
            mProperties.erase(it);
748
 
            // if (isGuest)  /* Notify the host even for properties that the host
749
 
            //                * changed.  Less efficient, but ensures consistency. */
750
 
                doNotifications(pcszName, u64Timestamp);
751
 
        }
752
 
    }
753
 
 
754
 
    LogFlowThisFunc(("rc = %Rrc\n", rc));
 
759
    if (RT_FAILURE(rc))
 
760
    {
 
761
        LogFlowThisFunc(("rc = %Rrc\n", rc));
 
762
        return rc;
 
763
    }
 
764
 
 
765
    /*
 
766
     * If the property exists, check its flags to see if we are allowed
 
767
     * to change it.
 
768
     */
 
769
    Property *pProp = getPropertyInternal(pcszName);
 
770
    if (pProp)
 
771
        rc = checkPermission((ePropFlags)pProp->mFlags, isGuest);
 
772
 
 
773
    /*
 
774
     * And delete the property if all is well.
 
775
     */
 
776
    if (rc == VINF_SUCCESS && pProp)
 
777
    {
 
778
        uint64_t u64Timestamp = getCurrentTimestamp();
 
779
        bool fRc = RTStrSpaceRemove(&mhProperties, pProp->mStrCore.pszString);
 
780
        Assert(fRc); NOREF(fRc);
 
781
        mcProperties--;
 
782
        delete pProp;
 
783
        // if (isGuest)  /* Notify the host even for properties that the host
 
784
        //                * changed.  Less efficient, but ensures consistency. */
 
785
            doNotifications(pcszName, u64Timestamp);
 
786
    }
 
787
 
 
788
    LogFlowThisFunc(("rc = %Rrc (%s)\n", rc, pcszName));
755
789
    return rc;
756
790
}
757
791
 
758
792
/**
 
793
 * Enumeration data shared between enumPropsCallback and Service::enumProps.
 
794
 */
 
795
typedef struct EnumData
 
796
{
 
797
    const char *pszPattern; /**< The pattern to match properties against. */
 
798
    char       *pchCur;     /**< The current buffer postion. */
 
799
    size_t      cbLeft;     /**< The amount of available buffer space. */
 
800
    size_t      cbNeeded;   /**< The amount of needed buffer space. */
 
801
} EnumData;
 
802
 
 
803
/**
 
804
 * @callback_method_impl{FNRTSTRSPACECALLBACK}
 
805
 */
 
806
static DECLCALLBACK(int) enumPropsCallback(PRTSTRSPACECORE pStr, void *pvUser)
 
807
{
 
808
    Property *pProp = (Property *)pStr;
 
809
    EnumData *pEnum = (EnumData *)pvUser;
 
810
 
 
811
    /* Included in the enumeration? */
 
812
    if (!pProp->Matches(pEnum->pszPattern))
 
813
        return 0;
 
814
 
 
815
    /* Convert the non-string members into strings. */
 
816
    char            szTimestamp[256];
 
817
    size_t const    cbTimestamp = RTStrFormatNumber(szTimestamp, pProp->mTimestamp, 10, 0, 0, 0) + 1;
 
818
 
 
819
    char            szFlags[MAX_FLAGS_LEN];
 
820
    int rc = writeFlags(pProp->mFlags, szFlags);
 
821
    if (RT_FAILURE(rc))
 
822
        return rc;
 
823
    size_t const    cbFlags = strlen(szFlags) + 1;
 
824
 
 
825
    /* Calculate the buffer space requirements. */
 
826
    size_t const    cbName     = pProp->mName.length() + 1;
 
827
    size_t const    cbValue    = pProp->mValue.length() + 1;
 
828
    size_t const    cbRequired = cbName + cbValue + cbTimestamp + cbFlags;
 
829
    pEnum->cbNeeded += cbRequired;
 
830
 
 
831
    /* Sufficient buffer space? */
 
832
    if (cbRequired > pEnum->cbLeft)
 
833
    {
 
834
        pEnum->cbLeft = 0;
 
835
        return 0; /* don't quit */
 
836
    }
 
837
    pEnum->cbLeft -= cbRequired;
 
838
 
 
839
    /* Append the property to the buffer. */
 
840
    char *pchCur = pEnum->pchCur;
 
841
    pEnum->pchCur += cbRequired;
 
842
 
 
843
    memcpy(pchCur, pProp->mName.c_str(), cbName);
 
844
    pchCur += cbName;
 
845
 
 
846
    memcpy(pchCur, pProp->mValue.c_str(), cbValue);
 
847
    pchCur += cbValue;
 
848
 
 
849
    memcpy(pchCur, szTimestamp, cbTimestamp);
 
850
    pchCur += cbTimestamp;
 
851
 
 
852
    memcpy(pchCur, szFlags, cbFlags);
 
853
    pchCur += cbFlags;
 
854
 
 
855
    Assert(pchCur == pEnum->pchCur);
 
856
    return 0;
 
857
}
 
858
 
 
859
/**
759
860
 * Enumerate guest properties by mask, checking the validity
760
861
 * of the arguments passed.
761
862
 *
771
872
    /*
772
873
     * Get the HGCM function arguments.
773
874
     */
774
 
    char *pcchPatterns = NULL, *pchBuf = NULL;
775
 
    uint32_t cchPatterns = 0, cchBuf = 0;
 
875
    char const *pchPatterns = NULL;
 
876
    char *pchBuf = NULL;
 
877
    uint32_t cbPatterns = 0;
 
878
    uint32_t cbBuf = 0;
776
879
    LogFlowThisFunc(("\n"));
777
880
    if (   (cParms != 3)  /* Hardcoded value as the next lines depend on it. */
778
 
        || RT_FAILURE(paParms[0].getString(&pcchPatterns, &cchPatterns))  /* patterns */
779
 
        || RT_FAILURE(paParms[1].getBuffer((void **) &pchBuf, &cchBuf))  /* return buffer */
 
881
        || RT_FAILURE(paParms[0].getString(&pchPatterns, &cbPatterns))  /* patterns */
 
882
        || RT_FAILURE(paParms[1].getBuffer((void **)&pchBuf, &cbBuf))  /* return buffer */
780
883
       )
781
884
        rc = VERR_INVALID_PARAMETER;
782
 
    if (RT_SUCCESS(rc) && cchPatterns > MAX_PATTERN_LEN)
 
885
    if (RT_SUCCESS(rc) && cbPatterns > MAX_PATTERN_LEN)
783
886
        rc = VERR_TOO_MUCH_DATA;
784
887
 
785
888
    /*
786
889
     * First repack the patterns into the format expected by RTStrSimplePatternMatch()
787
890
     */
788
 
    char pszPatterns[MAX_PATTERN_LEN];
 
891
    char szPatterns[MAX_PATTERN_LEN];
789
892
    if (RT_SUCCESS(rc))
790
893
    {
791
 
        for (unsigned i = 0; i < cchPatterns - 1; ++i)
792
 
            if (pcchPatterns[i] != '\0')
793
 
                pszPatterns[i] = pcchPatterns[i];
 
894
        for (unsigned i = 0; i < cbPatterns - 1; ++i)
 
895
            if (pchPatterns[i] != '\0')
 
896
                szPatterns[i] = pchPatterns[i];
794
897
            else
795
 
                pszPatterns[i] = '|';
796
 
        pszPatterns[cchPatterns - 1] = '\0';
 
898
                szPatterns[i] = '|';
 
899
        szPatterns[cbPatterns - 1] = '\0';
797
900
    }
798
901
 
799
902
    /*
800
 
     * Next enumerate into a temporary buffer.  This can throw, but this is
801
 
     * not a problem as we have nothing to roll back.
 
903
     * Next enumerate into the buffer.
802
904
     */
803
 
    std::string buffer;
804
 
    for (PropertyList::const_iterator it = mProperties.begin();
805
 
         RT_SUCCESS(rc) && (it != mProperties.end()); ++it)
 
905
    if (RT_SUCCESS(rc))
806
906
    {
807
 
        if (it->Matches(pszPatterns))
 
907
        EnumData EnumData;
 
908
        EnumData.pszPattern = szPatterns;
 
909
        EnumData.pchCur     = pchBuf;
 
910
        EnumData.cbLeft     = cbBuf;
 
911
        EnumData.cbNeeded   = 0;
 
912
        rc = RTStrSpaceEnumerate(&mhProperties, enumPropsCallback, &EnumData);
 
913
        AssertRCSuccess(rc);
 
914
        if (RT_SUCCESS(rc))
808
915
        {
809
 
            char szFlags[MAX_FLAGS_LEN];
810
 
            char szTimestamp[256];
811
 
            uint32_t cchTimestamp;
812
 
            buffer += it->mName;
813
 
            buffer += '\0';
814
 
            buffer += it->mValue;
815
 
            buffer += '\0';
816
 
            cchTimestamp = RTStrFormatNumber(szTimestamp, it->mTimestamp,
817
 
                                             10, 0, 0, 0);
818
 
            buffer.append(szTimestamp, cchTimestamp);
819
 
            buffer += '\0';
820
 
            rc = writeFlags(it->mFlags, szFlags);
821
 
            if (RT_SUCCESS(rc))
822
 
                buffer += szFlags;
823
 
            buffer += '\0';
 
916
            paParms[2].setUInt32((uint32_t)(EnumData.cbNeeded + 4));
 
917
            if (EnumData.cbLeft >= 4)
 
918
            {
 
919
                /* The final terminators. */
 
920
                EnumData.pchCur[0] = '\0';
 
921
                EnumData.pchCur[1] = '\0';
 
922
                EnumData.pchCur[2] = '\0';
 
923
                EnumData.pchCur[3] = '\0';
 
924
            }
 
925
            else
 
926
                rc = VERR_BUFFER_OVERFLOW;
824
927
        }
825
928
    }
826
 
    if (RT_SUCCESS(rc))
827
 
        buffer.append(4, '\0');  /* The final terminators */
828
929
 
829
 
    /*
830
 
     * Finally write out the temporary buffer to the real one if it is not too
831
 
     * small.
832
 
     */
833
 
    if (RT_SUCCESS(rc))
834
 
    {
835
 
        paParms[2].setUInt32 ((uint32_t)buffer.size());
836
 
        /* Copy the memory if it fits into the guest buffer */
837
 
        if (buffer.size() <= cchBuf)
838
 
            buffer.copy(pchBuf, cchBuf);
839
 
        else
840
 
            rc = VERR_BUFFER_OVERFLOW;
841
 
    }
842
930
    return rc;
843
931
}
844
932
 
881
969
    std::string buffer;
882
970
    uint64_t u64Timestamp;
883
971
    char *pchBuf;
884
 
    uint32_t cchBuf;
885
 
    rc = paParms[2].getBuffer((void **) &pchBuf, &cchBuf);
 
972
    uint32_t cbBuf;
 
973
    rc = paParms[2].getBuffer((void **)&pchBuf, &cbBuf);
886
974
    if (RT_SUCCESS(rc))
887
975
    {
888
976
        char szFlags[MAX_FLAGS_LEN];
903
991
    {
904
992
        paParms[1].setUInt64(u64Timestamp);
905
993
        paParms[3].setUInt32((uint32_t)buffer.size());
906
 
        if (buffer.size() <= cchBuf)
907
 
            buffer.copy(pchBuf, cchBuf);
 
994
        if (buffer.size() <= cbBuf)
 
995
            buffer.copy(pchBuf, cbBuf);
908
996
        else
909
997
            rc = VERR_BUFFER_OVERFLOW;
910
998
    }
928
1016
    char *pszPatterns = NULL;           /* shut up gcc */
929
1017
    char *pchBuf;
930
1018
    uint32_t cchPatterns = 0;
931
 
    uint32_t cchBuf = 0;
 
1019
    uint32_t cbBuf = 0;
932
1020
    uint64_t u64Timestamp;
933
1021
 
934
1022
    /*
938
1026
    if (   (cParms != 4)  /* Hardcoded value as the next lines depend on it. */
939
1027
        || RT_FAILURE(paParms[0].getString(&pszPatterns, &cchPatterns))  /* patterns */
940
1028
        || RT_FAILURE(paParms[1].getUInt64(&u64Timestamp))  /* timestamp */
941
 
        || RT_FAILURE(paParms[2].getBuffer((void **) &pchBuf, &cchBuf))  /* return buffer */
 
1029
        || RT_FAILURE(paParms[2].getBuffer((void **)&pchBuf, &cbBuf))  /* return buffer */
942
1030
       )
943
1031
        rc = VERR_INVALID_PARAMETER;
944
1032
    if (RT_SUCCESS(rc))
981
1069
 */
982
1070
void Service::doNotifications(const char *pszProperty, uint64_t u64Timestamp)
983
1071
{
984
 
    int rc = VINF_SUCCESS;
985
 
 
986
1072
    AssertPtrReturnVoid(pszProperty);
987
1073
    LogFlowThisFunc (("pszProperty=%s, u64Timestamp=%llu\n", pszProperty, u64Timestamp));
988
1074
    /* Ensure that our timestamp is different to the last one. */
998
1084
    prop.mName = pszProperty;
999
1085
    prop.mTimestamp = u64Timestamp;
1000
1086
    /* prop is currently a delete event for pszProperty */
1001
 
    bool found = false;
1002
 
    if (RT_SUCCESS(rc))
1003
 
        for (PropertyList::const_iterator it = mProperties.begin();
1004
 
             !found && it != mProperties.end(); ++it)
1005
 
            if (it->mName.compare(pszProperty) == 0)
1006
 
            {
1007
 
                found = true;
1008
 
                /* Make prop into a change event. */
1009
 
                prop.mValue = it->mValue;
1010
 
                prop.mFlags = it->mFlags;
1011
 
            }
1012
 
 
 
1087
    Property const * const pProp = getPropertyInternal(pszProperty);
 
1088
    if (pProp)
 
1089
    {
 
1090
        /* Make prop into a change event. */
 
1091
        prop.mValue = pProp->mValue;
 
1092
        prop.mFlags = pProp->mFlags;
 
1093
    }
1013
1094
 
1014
1095
    /* Release waiters if applicable and add the event to the queue for
1015
1096
     * guest notifications */
1016
 
    if (RT_SUCCESS(rc))
 
1097
    int rc = VINF_SUCCESS;
 
1098
    try
1017
1099
    {
1018
 
        try
 
1100
        CallList::iterator it = mGuestWaiters.begin();
 
1101
        while (it != mGuestWaiters.end())
1019
1102
        {
1020
 
            CallList::iterator it = mGuestWaiters.begin();
1021
 
            while (it != mGuestWaiters.end())
 
1103
            const char *pszPatterns;
 
1104
            uint32_t cchPatterns;
 
1105
            it->mParms[0].getString(&pszPatterns, &cchPatterns);
 
1106
            if (prop.Matches(pszPatterns))
1022
1107
            {
1023
 
                const char *pszPatterns;
1024
 
                uint32_t cchPatterns;
1025
 
                it->mParms[0].getString(&pszPatterns, &cchPatterns);
1026
 
                if (prop.Matches(pszPatterns))
1027
 
                {
1028
 
                    GuestCall curCall = *it;
1029
 
                    int rc2 = getNotificationWriteOut(curCall.mParms, prop);
1030
 
                    if (RT_SUCCESS(rc2))
1031
 
                        rc2 = curCall.mRc;
1032
 
                    mpHelpers->pfnCallComplete(curCall.mHandle, rc2);
1033
 
                    it = mGuestWaiters.erase(it);
1034
 
                }
1035
 
                else
1036
 
                    ++it;
 
1108
                GuestCall curCall = *it;
 
1109
                int rc2 = getNotificationWriteOut(curCall.mParms, prop);
 
1110
                if (RT_SUCCESS(rc2))
 
1111
                    rc2 = curCall.mRc;
 
1112
                mpHelpers->pfnCallComplete(curCall.mHandle, rc2);
 
1113
                it = mGuestWaiters.erase(it);
1037
1114
            }
1038
 
            mGuestNotifications.push_back(prop);
1039
 
        }
1040
 
        catch (std::bad_alloc)
1041
 
        {
1042
 
            rc = VERR_NO_MEMORY;
1043
 
        }
 
1115
            else
 
1116
                ++it;
 
1117
        }
 
1118
        mGuestNotifications.push_back(prop);
 
1119
    }
 
1120
    catch (std::bad_alloc)
 
1121
    {
 
1122
        rc = VERR_NO_MEMORY;
1044
1123
    }
1045
1124
    if (mGuestNotifications.size() > MAX_GUEST_NOTIFICATIONS)
1046
1125
        mGuestNotifications.pop_front();
1049
1128
     * Host notifications - first case: if the property exists then send its
1050
1129
     * current value
1051
1130
     */
1052
 
    if (found && mpfnHostCallback != NULL)
 
1131
    if (pProp && mpfnHostCallback != NULL)
1053
1132
    {
1054
1133
        char szFlags[MAX_FLAGS_LEN];
1055
1134
        /* Send out a host notification */
1064
1143
     * Host notifications - second case: if the property does not exist then
1065
1144
     * send the host an empty value
1066
1145
     */
1067
 
    if (!found && mpfnHostCallback != NULL)
 
1146
    if (!pProp && mpfnHostCallback != NULL)
1068
1147
    {
1069
1148
        /* Send out a host notification */
1070
1149
        if (RT_SUCCESS(rc))
1071
1150
            rc = notifyHost(pszProperty, NULL, u64Timestamp, NULL);
1072
1151
    }
1073
 
    LogFlowThisFunc (("returning\n"));
 
1152
    LogFlowThisFunc(("returning\n"));
1074
1153
}
1075
1154
 
1076
1155
/**
1084
1163
int Service::notifyHost(const char *pszName, const char *pszValue,
1085
1164
                        uint64_t u64Timestamp, const char *pszFlags)
1086
1165
{
1087
 
    LogFlowFunc (("pszName=%s, pszValue=%s, u64Timestamp=%llu, pszFlags=%s\n",
1088
 
                  pszName, pszValue, u64Timestamp, pszFlags));
 
1166
    LogFlowFunc(("pszName=%s, pszValue=%s, u64Timestamp=%llu, pszFlags=%s\n",
 
1167
                 pszName, pszValue, u64Timestamp, pszFlags));
1089
1168
    HOSTCALLBACKDATA HostCallbackData;
1090
1169
    HostCallbackData.u32Magic     = HOSTCALLBACKMAGIC;
1091
1170
    HostCallbackData.pcszName     = pszName;
1114
1193
                    VBOXHGCMSVCPARM paParms[])
1115
1194
{
1116
1195
    int rc = VINF_SUCCESS;
1117
 
    LogFlowFunc(("u32ClientID = %d, fn = %d, cParms = %d, pparms = %d\n",
 
1196
    LogFlowFunc(("u32ClientID = %d, fn = %d, cParms = %d, pparms = %p\n",
1118
1197
                 u32ClientID, eFunction, cParms, paParms));
1119
1198
 
1120
1199
    try
1182
1261
{
1183
1262
    int rc = VINF_SUCCESS;
1184
1263
 
1185
 
    LogFlowFunc(("fn = %d, cParms = %d, pparms = %d\n",
 
1264
    LogFlowFunc(("fn = %d, cParms = %d, pparms = %p\n",
1186
1265
                 eFunction, cParms, paParms));
1187
1266
 
1188
1267
    try
1267
1346
 */
1268
1347
extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad (VBOXHGCMSVCFNTABLE *ptable)
1269
1348
{
1270
 
    int rc = VINF_SUCCESS;
 
1349
    int rc = VERR_IPE_UNINITIALIZED_STATUS;
1271
1350
 
1272
1351
    LogFlowFunc(("ptable = %p\n", ptable));
1273
1352
 
1274
 
    if (!VALID_PTR(ptable))
1275
 
    {
 
1353
    if (!RT_VALID_PTR(ptable))
1276
1354
        rc = VERR_INVALID_PARAMETER;
1277
 
    }
1278
1355
    else
1279
1356
    {
1280
1357
        LogFlowFunc(("ptable->cbSize = %d, ptable->u32Version = 0x%08X\n", ptable->cbSize, ptable->u32Version));
1281
1358
 
1282
 
        if (   ptable->cbSize != sizeof (VBOXHGCMSVCFNTABLE)
 
1359
        if (   ptable->cbSize != sizeof(VBOXHGCMSVCFNTABLE)
1283
1360
            || ptable->u32Version != VBOX_HGCM_SVC_VERSION)
1284
 
        {
1285
1361
            rc = VERR_VERSION_MISMATCH;
1286
 
        }
1287
1362
        else
1288
1363
        {
1289
 
            std::auto_ptr<Service> apService;
 
1364
            Service *pService = NULL;
1290
1365
            /* No exceptions may propagate outside. */
1291
 
            try {
1292
 
                apService = std::auto_ptr<Service>(new Service(ptable->pHelpers));
1293
 
            } catch (int rcThrown) {
 
1366
            try
 
1367
            {
 
1368
                pService = new Service(ptable->pHelpers);
 
1369
                rc = VINF_SUCCESS;
 
1370
            }
 
1371
            catch (int rcThrown)
 
1372
            {
1294
1373
                rc = rcThrown;
1295
 
            } catch (...) {
1296
 
                rc = VERR_UNRESOLVED_ERROR;
 
1374
            }
 
1375
            catch (...)
 
1376
            {
 
1377
                rc = VERR_UNEXPECTED_EXCEPTION;
1297
1378
            }
1298
1379
 
1299
1380
            if (RT_SUCCESS(rc))
1311
1392
                ptable->pfnRegisterExtension  = Service::svcRegisterExtension;
1312
1393
 
1313
1394
                /* Service specific initialization. */
1314
 
                ptable->pvService = apService.release();
 
1395
                ptable->pvService = pService;
1315
1396
            }
 
1397
            else
 
1398
                Assert(!pService);
1316
1399
        }
1317
1400
    }
1318
1401