VirtualBox

Changeset 90238 in vbox


Ignore:
Timestamp:
Jul 19, 2021 1:48:09 PM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
145776
Message:

HGCM,HostServices: Extended VBOXHGCMSVCFNTABLE with client and call limits. Tried to pick reasonable values for all services. bugref:9379

Location:
trunk
Files:
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/err.h

    r90161 r90238  
    16231623/** Requested service already exists. */
    16241624#define VERR_HGCM_SERVICE_EXISTS                    (-2907)
    1625 
     1625/** Too many clients for the service. */
     1626#define VERR_HGCM_TOO_MANY_CLIENTS                  (-2908)
     1627/** Too many calls to the service from a client. */
     1628#define VERR_HGCM_TOO_MANY_CLIENT_CALLS             (-2909)
    16261629/** @} */
    16271630
  • trunk/include/VBox/hgcmsvc.h

    r85121 r90238  
    8181 * 6.5->7.1 Because pfnNotify was added (VBox 6.0).
    8282 * 7.1->8.1 Because pfnCancelled & pfnIsCallCancelled were added (VBox 6.0).
     83 * 8.1->9.1 Because pfnDisconnectClient was (temporarily) removed, and
     84 *          acMaxClients and acMaxCallsPerClient added (VBox 6.1.26).
    8385 */
    84 #define VBOX_HGCM_SVC_VERSION_MAJOR (0x0008)
     86#define VBOX_HGCM_SVC_VERSION_MAJOR (0x0009)
    8587#define VBOX_HGCM_SVC_VERSION_MINOR (0x0001)
    8688#define VBOX_HGCM_SVC_VERSION ((VBOX_HGCM_SVC_VERSION_MAJOR << 16) + VBOX_HGCM_SVC_VERSION_MINOR)
     
    99101    void *pvInstance;
    100102
     103#if 0 /* Not thread safe. */
    101104    /** The service disconnects the client. */
    102105    DECLR3CALLBACKMEMBER(void, pfnDisconnectClient, (void *pvInstance, uint32_t u32ClientID));
     106#endif
    103107
    104108    /**
     
    594598} HGCMNOTIFYEVENT;
    595599
     600/** @name HGCM_CLIENT_CATEGORY_XXX - Client categories
     601 * @{ */
     602#define HGCM_CLIENT_CATEGORY_KERNEL 0   /**< Guest kernel mode and legacy client. */
     603#define HGCM_CLIENT_CATEGORY_ROOT   1   /**< Guest root or admin client. */
     604#define HGCM_CLIENT_CATEGORY_USER   2   /**< Regular guest user client. */
     605#define HGCM_CLIENT_CATEGORY_MAX    3   /**< Max number of categories. */
     606/** @} */
     607
    596608
    597609/** The Service DLL entry points.
     
    610622
    611623    /** Size of the structure. */
    612     uint32_t                 cbSize;
    613 
    614     /** Version of the structure, including the helpers. */
    615     uint32_t                 u32Version;
    616 
    617     PVBOXHGCMSVCHELPERS      pHelpers;
     624    uint32_t                cbSize;
     625
     626    /** Version of the structure, including the helpers. (VBOX_HGCM_SVC_VERSION) */
     627    uint32_t                u32Version;
     628
     629    PVBOXHGCMSVCHELPERS     pHelpers;
    618630    /** @} */
    619631
     
    622634
    623635    /** Size of client information the service want to have. */
    624     uint32_t                 cbClient;
    625 #if ARCH_BITS == 64
    626     /** Ensure that the following pointers are properly aligned on 64-bit system. */
    627     uint32_t                 u32Alignment0;
    628 #endif
     636    uint32_t                cbClient;
     637
     638    /** The maximum number of clients per category.  Leave entries as zero for defaults. */
     639    uint32_t                acMaxClients[HGCM_CLIENT_CATEGORY_MAX];
     640    /** The maximum number of concurrent calls per client for each category.
     641     *  Leave entries as as zero for default. */
     642    uint32_t                acMaxCallsPerClient[HGCM_CLIENT_CATEGORY_MAX];
     643    /** The HGCM_CLIENT_CATEGORY_XXX value for legacy clients.
     644     *  Defaults to HGCM_CLIENT_CATEGORY_KERNEL. */
     645    uint32_t                idxLegacyClientCategory;
    629646
    630647    /** Uninitialize service */
  • trunk/src/VBox/HostServices/DragAndDrop/VBoxDragAndDropSvc.cpp

    r86869 r90238  
    181181int DragAndDropService::init(VBOXHGCMSVCFNTABLE *pTable) RT_NOEXCEPT
    182182{
     183    /* Legacy clients map to the root category. */
     184    pTable->idxLegacyClientCategory = HGCM_CLIENT_CATEGORY_ROOT;
     185
     186    /* Limit to 255 clients (see also DragAndDropService::clientConnect). */
     187    for (uintptr_t i = 0; i < RT_ELEMENTS(pTable->acMaxClients); i++)
     188        pTable->acMaxClients[i] = UINT8_MAX;
     189
     190    /* Limit the number of concurrent calls to 256 (playing safe).  */
     191    /** @todo Properly determin the max number of pending/concurrent calls for DnD. */
     192    for (uintptr_t i = 0; i < RT_ELEMENTS(pTable->acMaxClients); i++)
     193        pTable->acMaxCallsPerClient[i] = 256;
     194
    183195    /* Register functions. */
    184196    pTable->pfnHostCall          = svcHostCall;
  • trunk/src/VBox/HostServices/GuestControl/VBoxGuestControlSvc.cpp

    r87624 r90238  
    25342534                pTable->cbClient = sizeof(ClientState);
    25352535
     2536                /* Limit pending calls to 8 pending per connection (doubt we need more than
     2537                   one).  Map legacy clients to the root and limit kernel to 1 (zero would
     2538                   be default) and use defaults for root and user clients. */
     2539                for (uintptr_t i = 0; i < RT_ELEMENTS(pTable->acMaxClients); i++)
     2540                    pTable->acMaxCallsPerClient[i] = 8;
     2541
     2542                pTable->idxLegacyClientCategory = HGCM_CLIENT_CATEGORY_ROOT;
     2543                pTable->acMaxClients[HGCM_CLIENT_CATEGORY_KERNEL] = 1;
     2544
    25362545                /* Register functions. */
    25372546                pTable->pfnUnload               = GstCtrlService::svcUnload;
  • trunk/src/VBox/HostServices/GuestProperties/VBoxGuestPropSvc.cpp

    r85121 r90238  
    18651865                ptable->cbClient = 0;
    18661866
     1867                /* Legacy clients map to the kernel category. */
     1868                ptable->idxLegacyClientCategory = HGCM_CLIENT_CATEGORY_KERNEL;
     1869
     1870                /* Go with default client limits, but we won't ever need more than
     1871                   16 pending calls per client I would think (1 should be enough). */
     1872                for (uintptr_t i = 0; i < RT_ELEMENTS(ptable->acMaxClients); i++)
     1873                    ptable->acMaxCallsPerClient[i] = 16;
     1874
    18671875                ptable->pfnUnload             = Service::svcUnload;
    18681876                ptable->pfnConnect            = Service::svcConnect;
  • trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-darwin.cpp

    r86889 r90238  
    119119
    120120
    121 int ShClBackendInit(void)
    122 {
     121int ShClBackendInit(VBOXHGCMSVCFNTABLE *pTable)
     122{
     123    RT_NOREF(pTable);
    123124    g_ctx.fTerminate = false;
    124125
  • trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-internal.h

    r87566 r90238  
    306306/**
    307307 * Called on initialization.
    308  */
    309 int ShClBackendInit(void);
     308 *
     309 * @param   pTable      The HGCM service call and parameter table.  Mainly for
     310 *                      adjusting the limits.
     311 */
     312int ShClBackendInit(VBOXHGCMSVCFNTABLE *pTable);
    310313
    311314/**
  • trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-win.cpp

    r90054 r90238  
    604604 */
    605605
    606 int ShClBackendInit(void)
    607 {
     606int ShClBackendInit(VBOXHGCMSVCFNTABLE *pTable)
     607{
     608    RT_NOREF(pTable);
    608609#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    609610    HRESULT hr = OleInitialize(NULL);
  • trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-x11-stubs.cpp

    r87566 r90238  
    4141 * Initialise the host side of the shared clipboard - called by the hgcm layer.
    4242 */
    43 int ShClBackendInit(void)
     43int ShClBackendInit(VBOXHGCMSVCFNTABLE *pTable)
    4444{
     45    RT_NOREF(pTable);
    4546    LogFlowFunc(("called, returning VINF_SUCCESS\n"));
    4647    return VINF_SUCCESS;
  • trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-x11.cpp

    r89948 r90238  
    6161
    6262
    63 int ShClBackendInit(void)
    64 {
    65     LogFlowFuncEnter();
     63int ShClBackendInit(VBOXHGCMSVCFNTABLE *pTable)
     64{
     65    LogFlowFuncEnter();
     66
     67    /* Override the connection limit. */
     68    for (uintptr_t i = 0; i < RT_ELEMENTS(pTable->acMaxClients); i++)
     69        pTable->acMaxClients[i] = RT_MIN(VBOX_SHARED_CLIPBOARD_X11_CONNECTIONS_MAX, pTable->acMaxClients[i]);
     70
    6671    return VINF_SUCCESS;
    6772}
  • trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc.cpp

    r89947 r90238  
    19321932}
    19331933
    1934 static int svcInit(void)
     1934static int svcInit(VBOXHGCMSVCFNTABLE *pTable)
    19351935{
    19361936    int rc = RTCritSectInit(&g_CritSect);
     
    19401940        shClSvcModeSet(VBOX_SHCL_MODE_OFF);
    19411941
    1942         rc = ShClBackendInit();
     1942        rc = ShClBackendInit(pTable);
    19431943
    19441944        /* Clean up on failure, because 'svnUnload' will not be called
     
    27222722            pTable->cbClient = sizeof(SHCLCLIENT);
    27232723
     2724            /* Map legacy clients to root. */
     2725            pTable->idxLegacyClientCategory = HGCM_CLIENT_CATEGORY_ROOT;
     2726
     2727            /* Limit the number of clients to 128 in each category (should be enough),
     2728               but set kernel clients to 1 (zero would be default). */
     2729            for (uintptr_t i = 0; i < RT_ELEMENTS(pTable->acMaxClients); i++)
     2730                pTable->acMaxClients[i] = 128;
     2731            pTable->acMaxClients[HGCM_CLIENT_CATEGORY_KERNEL] = 1;
     2732
     2733            /* Only 16 pending calls per client (1 should be enough). */
     2734            for (uintptr_t i = 0; i < RT_ELEMENTS(pTable->acMaxClients); i++)
     2735                pTable->acMaxCallsPerClient[i] = 16;
     2736
    27242737            pTable->pfnUnload            = svcUnload;
    27252738            pTable->pfnConnect           = svcConnect;
     
    27342747
    27352748            /* Service specific initialization. */
    2736             rc = svcInit();
     2749            rc = svcInit(pTable);
    27372750        }
    27382751    }
  • trunk/src/VBox/HostServices/SharedClipboard/testcase/tstClipboardServiceHost.cpp

    r86364 r90238  
    310310}
    311311
    312 int ShClBackendInit() { return VINF_SUCCESS; }
     312int ShClBackendInit(VBOXHGCMSVCFNTABLE *) { return VINF_SUCCESS; }
    313313void ShClBackendDestroy() { }
    314314int ShClBackendDisconnect(PSHCLCLIENT) { return VINF_SUCCESS; }
  • trunk/src/VBox/HostServices/SharedClipboard/testcase/tstClipboardServiceImpl.cpp

    r84142 r90238  
    5252}
    5353
    54 int ShClBackendInit(void) { return VINF_SUCCESS; }
     54int ShClBackendInit(VBOXHGCMSVCFNTABLE *) { return VINF_SUCCESS; }
    5555void ShClBackendDestroy(void) { }
    5656int ShClBackendDisconnect(PSHCLCLIENT) { return VINF_SUCCESS; }
  • trunk/src/VBox/HostServices/SharedFolders/VBoxSharedFoldersSvc.cpp

    r82968 r90238  
    18511851            ptable->cbClient = sizeof (SHFLCLIENTDATA);
    18521852
     1853            /* Map legacy clients to the kernel category. */
     1854            ptable->idxLegacyClientCategory = HGCM_CLIENT_CATEGORY_KERNEL;
     1855
     1856            /* Only 64K pending calls per kernel client, root gets 16K and regular users 1K. */
     1857            ptable->acMaxCallsPerClient[HGCM_CLIENT_CATEGORY_KERNEL] = _64K;
     1858            ptable->acMaxCallsPerClient[HGCM_CLIENT_CATEGORY_ROOT]   = _16K;
     1859            ptable->acMaxCallsPerClient[HGCM_CLIENT_CATEGORY_USER]   = _1K;
     1860
     1861            /* Reduce the number of clients to SHFL_MAX_MAPPINGS + 2 in each category,
     1862               so the increased calls-per-client value causes less trouble.
     1863               ((64 + 2) * 3 * 65536 = 12 976 128) */
     1864            for (uintptr_t i = 0; i < RT_ELEMENTS(ptable->acMaxClients); i++)
     1865                ptable->acMaxClients[i] = SHFL_MAX_MAPPINGS + 2;
     1866
    18531867            ptable->pfnUnload     = svcUnload;
    18541868            ptable->pfnConnect    = svcConnect;
  • trunk/src/VBox/Main/src-client/HGCM.cpp

    r90229 r90238  
    2727#include <VBox/vmm/stam.h>
    2828#include <VBox/sup.h>
     29#include <VBox/AssertGuest.h>
    2930
    3031#include <iprt/alloc.h>
     
    108109        VBOXHGCMSVCFNTABLE m_fntable;
    109110
     111        uint32_t m_acClients[HGCM_CLIENT_CATEGORY_MAX]; /**< Clients per category. */
    110112        uint32_t m_cClients;
    111113        uint32_t m_cClientsAllocated;
     
    121123         * @{ */
    122124        STAMPROFILE m_StatHandleMsg;
     125        STAMCOUNTER m_StatTooManyClients;
     126        STAMCOUNTER m_StatTooManyCalls;
    123127        /** @} */
    124128
     
    187191         */
    188192
    189         int GuestCall(PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientId,
     193        int GuestCall(PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientId, HGCMClient *pClient,
    190194                      uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM aParms[], uint64_t tsArrival);
    191195        void GuestCancelled(PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t idClient);
     
    196200{
    197201    public:
    198         HGCMClient(uint32_t a_fRequestor)
     202        HGCMClient(uint32_t a_fRequestor, uint32_t a_idxCategory)
    199203            : HGCMObject(HGCMOBJ_CLIENT)
    200204            , pService(NULL)
    201205            , pvData(NULL)
    202206            , fRequestor(a_fRequestor)
    203         {}
     207            , idxCategory(a_idxCategory)
     208            , cPendingCalls(0)
     209        {
     210            Assert(idxCategory < HGCM_CLIENT_CATEGORY_MAX);
     211        }
    204212        ~HGCMClient();
    205213
     
    215223         * @sa VMMDevRequestHeader::fRequestor */
    216224        uint32_t fRequestor;
     225
     226        /** The client category (HGCM_CLIENT_CATEGORY_XXX). */
     227        uint32_t idxCategory;
     228
     229        /** Number of pending calls. */
     230        uint32_t volatile cPendingCalls;
    217231
    218232    private: /* none of this: */
     
    275289    m_pHgcmPort  (NULL)
    276290{
     291    RT_ZERO(m_acClients);
    277292    RT_ZERO(m_fntable);
    278293}
     
    340355            if (RT_SUCCESS(rc))
    341356            {
    342                 if (   m_fntable.pfnUnload == NULL
    343                     || m_fntable.pfnConnect == NULL
    344                     || m_fntable.pfnDisconnect == NULL
    345                     || m_fntable.pfnCall == NULL
     357                if (   m_fntable.pfnUnload != NULL
     358                    && m_fntable.pfnConnect != NULL
     359                    && m_fntable.pfnDisconnect != NULL
     360                    && m_fntable.pfnCall != NULL
    346361                   )
     362                {
     363                    /*
     364                     * Set default limits if not filled in by the service.
     365                     *  Total max calls: (2048 + 1024 + 1024) * 8192 = 33 554 432
     366                     */
     367                    Assert(m_fntable.idxLegacyClientCategory < RT_ELEMENTS(m_fntable.acMaxClients));
     368
     369                    if (m_fntable.acMaxClients[HGCM_CLIENT_CATEGORY_KERNEL] == 0)
     370                        m_fntable.acMaxClients[HGCM_CLIENT_CATEGORY_KERNEL] = _2K;
     371                    if (m_fntable.acMaxClients[HGCM_CLIENT_CATEGORY_ROOT]   == 0)
     372                        m_fntable.acMaxClients[HGCM_CLIENT_CATEGORY_ROOT]   = _1K;
     373                    if (m_fntable.acMaxClients[HGCM_CLIENT_CATEGORY_USER]   == 0)
     374                        m_fntable.acMaxClients[HGCM_CLIENT_CATEGORY_USER]   = _1K;
     375
     376                    if (m_fntable.acMaxCallsPerClient[HGCM_CLIENT_CATEGORY_KERNEL] == 0)
     377                        m_fntable.acMaxCallsPerClient[HGCM_CLIENT_CATEGORY_KERNEL] = _8K;
     378                    if (m_fntable.acMaxCallsPerClient[HGCM_CLIENT_CATEGORY_ROOT]   == 0)
     379                        m_fntable.acMaxCallsPerClient[HGCM_CLIENT_CATEGORY_ROOT]   = _4K;
     380                    if (m_fntable.acMaxCallsPerClient[HGCM_CLIENT_CATEGORY_USER]   == 0)
     381                        m_fntable.acMaxCallsPerClient[HGCM_CLIENT_CATEGORY_USER]   = _2K;
     382
     383                    /** @todo provide way to configure different values via extra data.   */
     384
     385                    LogRel2(("HGCMService::loadServiceDLL: acMaxClients={%u,%u,%u} acMaxCallsPerClient={%u,%u,%u} => %RU64 calls; idxLegacyClientCategory=%d; %s\n",
     386                             m_fntable.acMaxClients[HGCM_CLIENT_CATEGORY_KERNEL],
     387                             m_fntable.acMaxClients[HGCM_CLIENT_CATEGORY_ROOT],
     388                             m_fntable.acMaxClients[HGCM_CLIENT_CATEGORY_USER],
     389                             m_fntable.acMaxCallsPerClient[HGCM_CLIENT_CATEGORY_KERNEL],
     390                             m_fntable.acMaxCallsPerClient[HGCM_CLIENT_CATEGORY_ROOT],
     391                             m_fntable.acMaxCallsPerClient[HGCM_CLIENT_CATEGORY_USER],
     392                                 (uint64_t)m_fntable.acMaxClients[HGCM_CLIENT_CATEGORY_KERNEL]
     393                               *    m_fntable.acMaxCallsPerClient[HGCM_CLIENT_CATEGORY_KERNEL]
     394                             +   (uint64_t)m_fntable.acMaxClients[HGCM_CLIENT_CATEGORY_ROOT]
     395                               *    m_fntable.acMaxCallsPerClient[HGCM_CLIENT_CATEGORY_ROOT]
     396                             +   (uint64_t)m_fntable.acMaxClients[HGCM_CLIENT_CATEGORY_USER]
     397                               *    m_fntable.acMaxCallsPerClient[HGCM_CLIENT_CATEGORY_USER],
     398                             m_fntable.idxLegacyClientCategory, m_pszSvcName));
     399                }
     400                else
    347401                {
    348402                    Log(("HGCMService::loadServiceDLL: at least one of function pointers is NULL\n"));
     
    455509{
    456510    public:
    457         HGCMMsgCall() {}
     511        HGCMMsgCall() : pcCounter(NULL)
     512        { }
    458513
    459514        HGCMMsgCall(HGCMThread *pThread)
     515            : pcCounter(NULL)
    460516        {
    461517            InitializeCore(SVC_MSG_GUESTCALL, pThread);
    462518            Initialize();
    463519        }
    464         ~HGCMMsgCall() { Log(("~HGCMMsgCall %p\n", this)); }
     520        ~HGCMMsgCall()
     521        {
     522            Log(("~HGCMMsgCall %p\n", this));
     523            Assert(!pcCounter);
     524        }
     525
     526        /** Points to HGCMClient::cPendingCalls if it needs to be decremented. */
     527        uint32_t volatile *pcCounter;
    465528
    466529        /* client identifier */
     
    861924}
    862925
     926#if 0 /* not thread safe */
    863927/**
    864928 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnDisconnectClient}
     
    876940     }
    877941}
     942#endif
    878943
    879944/**
     
    10511116            STAMR3RegisterFU(pUVM, &m_StatHandleMsg, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
    10521117                             "Message handling", "/HGCM/%s/Msg", pszServiceName);
     1118            STAMR3RegisterFU(pUVM, &m_StatTooManyCalls, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
     1119                             "Too many calls (per client)", "/HGCM/%s/TooManyCalls", pszServiceName);
     1120            STAMR3RegisterFU(pUVM, &m_StatTooManyClients, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
     1121                             "Too many clients", "/HGCM/%s/TooManyClients", pszServiceName);
     1122            STAMR3RegisterFU(pUVM, &m_cClients, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
     1123                             "Number of clients", "/HGCM/%s/Clients", pszServiceName);
     1124            STAMR3RegisterFU(pUVM, &m_acClients[HGCM_CLIENT_CATEGORY_KERNEL], STAMTYPE_U32, STAMVISIBILITY_ALWAYS,
     1125                             STAMUNIT_OCCURENCES, "Number of kernel clients", "/HGCM/%s/Clients/Kernel", pszServiceName);
     1126            STAMR3RegisterFU(pUVM, &m_acClients[HGCM_CLIENT_CATEGORY_ROOT], STAMTYPE_U32, STAMVISIBILITY_ALWAYS,
     1127                             STAMUNIT_OCCURENCES, "Number of root/admin clients", "/HGCM/%s/Clients/Root", pszServiceName);
     1128            STAMR3RegisterFU(pUVM, &m_acClients[HGCM_CLIENT_CATEGORY_USER], STAMTYPE_U32, STAMVISIBILITY_ALWAYS,
     1129                             STAMUNIT_OCCURENCES, "Number of regular user clients", "/HGCM/%s/Clients/User", pszServiceName);
     1130            STAMR3RegisterFU(pUVM, &m_fntable.acMaxClients[HGCM_CLIENT_CATEGORY_KERNEL], STAMTYPE_U32, STAMVISIBILITY_ALWAYS,
     1131                             STAMUNIT_OCCURENCES, "Max number of kernel clients", "/HGCM/%s/Clients/KernelMax", pszServiceName);
     1132            STAMR3RegisterFU(pUVM, &m_fntable.acMaxClients[HGCM_CLIENT_CATEGORY_ROOT], STAMTYPE_U32, STAMVISIBILITY_ALWAYS,
     1133                             STAMUNIT_OCCURENCES, "Max number of root clients", "/HGCM/%s/Clients/RootMax", pszServiceName);
     1134            STAMR3RegisterFU(pUVM, &m_fntable.acMaxClients[HGCM_CLIENT_CATEGORY_USER], STAMTYPE_U32, STAMVISIBILITY_ALWAYS,
     1135                             STAMUNIT_OCCURENCES, "Max number of user clients", "/HGCM/%s/Clients/UserMax", pszServiceName);
     1136            STAMR3RegisterFU(pUVM, &m_fntable.idxLegacyClientCategory, STAMTYPE_U32, STAMVISIBILITY_ALWAYS,
     1137                             STAMUNIT_OCCURENCES, "Legacy client mapping", "/HGCM/%s/Clients/LegacyClientMapping", pszServiceName);
     1138            STAMR3RegisterFU(pUVM, &m_fntable.acMaxCallsPerClient[HGCM_CLIENT_CATEGORY_KERNEL], STAMTYPE_U32, STAMVISIBILITY_ALWAYS,
     1139                             STAMUNIT_OCCURENCES, "Max number of call per kernel client", "/HGCM/%s/MaxCallsKernelClient", pszServiceName);
     1140            STAMR3RegisterFU(pUVM, &m_fntable.acMaxCallsPerClient[HGCM_CLIENT_CATEGORY_ROOT], STAMTYPE_U32, STAMVISIBILITY_ALWAYS,
     1141                             STAMUNIT_OCCURENCES, "Max number of call per root client", "/HGCM/%s/MaxCallsRootClient", pszServiceName);
     1142            STAMR3RegisterFU(pUVM, &m_fntable.acMaxCallsPerClient[HGCM_CLIENT_CATEGORY_USER], STAMTYPE_U32, STAMVISIBILITY_ALWAYS,
     1143                             STAMUNIT_OCCURENCES, "Max number of call per user client", "/HGCM/%s/MaxCallsUserClient", pszServiceName);
    10531144
    10541145            /* Initialize service helpers table. */
    10551146            m_svcHelpers.pfnCallComplete       = svcHlpCallComplete;
    10561147            m_svcHelpers.pvInstance            = this;
     1148#if 0 /* not thread safe */
    10571149            m_svcHelpers.pfnDisconnectClient   = svcHlpDisconnectClient;
     1150#endif
    10581151            m_svcHelpers.pfnIsCallRestored     = svcHlpIsCallRestored;
    10591152            m_svcHelpers.pfnIsCallCancelled    = svcHlpIsCallCancelled;
     
    15571650                 pu32ClientIdOut, u32ClientIdIn, fRequestor, fRestoring));
    15581651
     1652    /*
     1653     * Categorize the client (compress VMMDEV_REQUESTOR_USR_MASK)
     1654     * and check the respective client limit.
     1655     */
     1656    uint32_t idxClientCategory;
     1657    if (fRequestor == VMMDEV_REQUESTOR_LEGACY)
     1658    {
     1659        idxClientCategory = m_fntable.idxLegacyClientCategory;
     1660        AssertStmt(idxClientCategory < RT_ELEMENTS(m_acClients), idxClientCategory = HGCM_CLIENT_CATEGORY_KERNEL);
     1661    }
     1662    else
     1663        switch (fRequestor & VMMDEV_REQUESTOR_USR_MASK)
     1664        {
     1665            case VMMDEV_REQUESTOR_USR_DRV:
     1666            case VMMDEV_REQUESTOR_USR_DRV_OTHER:
     1667                idxClientCategory = HGCM_CLIENT_CATEGORY_KERNEL;
     1668                break;
     1669            case VMMDEV_REQUESTOR_USR_ROOT:
     1670            case VMMDEV_REQUESTOR_USR_SYSTEM:
     1671                idxClientCategory = HGCM_CLIENT_CATEGORY_ROOT;
     1672                break;
     1673            default:
     1674                idxClientCategory = HGCM_CLIENT_CATEGORY_USER;
     1675                break;
     1676        }
     1677
     1678    if (   m_acClients[idxClientCategory] < m_fntable.acMaxClients[idxClientCategory]
     1679        || fRestoring)
     1680    { }
     1681    else
     1682    {
     1683        LogRel2(("Too many concurrenct clients for HGCM service '%s': %u, max %u; category %u\n",
     1684                 m_pszSvcName, m_cClients, m_fntable.acMaxClients[idxClientCategory], idxClientCategory));
     1685        STAM_REL_COUNTER_INC(&m_StatTooManyClients);
     1686        return VERR_HGCM_TOO_MANY_CLIENTS;
     1687    }
     1688
    15591689    /* Allocate a client information structure. */
    1560     HGCMClient *pClient = new (std::nothrow) HGCMClient(fRequestor);
     1690    HGCMClient *pClient = new (std::nothrow) HGCMClient(fRequestor, idxClientCategory);
    15611691
    15621692    if (!pClient)
     
    16331763                }
    16341764
    1635                 m_paClientIds[m_cClients] = handle;
    1636                 m_cClients++;
     1765                if (RT_SUCCESS(rc))
     1766                {
     1767                    m_paClientIds[m_cClients] = handle;
     1768                    m_cClients++;
     1769                    m_acClients[idxClientCategory]++;
     1770                    LogFunc(("idClient=%u m_cClients=%u m_acClients[%u]=%u %s\n",
     1771                             handle, m_cClients, idxClientCategory, m_acClients[idxClientCategory]));
     1772                }
    16371773            }
    16381774        }
    16391775    }
    16401776
    1641     if (RT_FAILURE(rc))
     1777    if (RT_SUCCESS(rc))
     1778    {
     1779        if (pu32ClientIdOut != NULL)
     1780        {
     1781            *pu32ClientIdOut = handle;
     1782        }
     1783
     1784        ReferenceService();
     1785    }
     1786    else
    16421787    {
    16431788        hgcmObjDeleteHandle(handle);
    1644     }
    1645     else
    1646     {
    1647         if (pu32ClientIdOut != NULL)
    1648         {
    1649             *pu32ClientIdOut = handle;
    1650         }
    1651 
    1652         ReferenceService();
    16531789    }
    16541790
     
    16781814     * for further details.
    16791815     */
     1816    Assert(pClient->idxCategory < HGCM_CLIENT_CATEGORY_MAX);
     1817    Assert(m_acClients[pClient->idxCategory] > 0);
     1818
    16801819    bool fReleaseService = false;
    16811820    int  rc              = VERR_NOT_FOUND;
     
    16841823        if (m_paClientIds[i] == u32ClientId)
    16851824        {
     1825            if (m_acClients[pClient->idxCategory] > 0)
     1826                m_acClients[pClient->idxCategory]--;
     1827
    16861828            m_cClients--;
    16871829
     
    17021844    if (rc == VERR_NOT_FOUND && !fFromService)
    17031845    {
     1846        if (m_acClients[pClient->idxCategory] > 0)
     1847            m_acClients[pClient->idxCategory]--;
     1848
    17041849        hgcmObjDeleteHandle(u32ClientId);
    17051850        fReleaseService = true;
    17061851    }
     1852
     1853    if (pClient)
     1854        LogFunc(("idClient=%u m_cClients=%u m_acClients[%u]=%u %s (cPendingCalls=%u) rc=%Rrc\n",
     1855                 u32ClientId, m_cClients, pClient->idxCategory, m_acClients[pClient->idxCategory], pClient->cPendingCalls, rc));
    17071856
    17081857    /*
     
    17861935}
    17871936
     1937/** @callback_method_impl{FNHGCMMSGCALLBACK}   */
     1938static DECLCALLBACK(int) hgcmMsgCallCompletionCallback(int32_t result, HGCMMsgCore *pMsgCore)
     1939{
     1940    /*
     1941     * Do common message completion then decrement the call counter
     1942     * for the client if necessary.
     1943     */
     1944    int rc = hgcmMsgCompletionCallback(result, pMsgCore);
     1945
     1946    HGCMMsgCall *pMsg = (HGCMMsgCall *)pMsgCore;
     1947    if (pMsg->pcCounter)
     1948    {
     1949        uint32_t cCalls = ASMAtomicDecU32(pMsg->pcCounter);
     1950        AssertStmt(cCalls < UINT32_MAX / 2, ASMAtomicWriteU32(pMsg->pcCounter, 0));
     1951        pMsg->pcCounter = NULL;
     1952        Log3Func(("pMsg=%p cPendingCalls=%u / %u (fun %u, %u parms)\n",
     1953                  pMsg, cCalls, pMsg->u32ClientId, pMsg->u32Function, pMsg->cParms));
     1954    }
     1955
     1956    return rc;
     1957}
     1958
    17881959/** Perform a guest call to the service.
    17891960 *
     
    17911962 * @param pCmd           The VBox HGCM context.
    17921963 * @param u32ClientId    The client handle to be disconnected and deleted.
     1964 * @param pClient        The client data.
    17931965 * @param u32Function    The function number.
    17941966 * @param cParms         Number of parameters.
     
    17981970 * @retval VINF_HGCM_ASYNC_EXECUTE on success.
    17991971 */
    1800 int HGCMService::GuestCall(PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientId, uint32_t u32Function,
    1801                            uint32_t cParms, VBOXHGCMSVCPARM paParms[], uint64_t tsArrival)
     1972int HGCMService::GuestCall(PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientId, HGCMClient *pClient,
     1973                           uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[], uint64_t tsArrival)
    18021974{
    18031975    LogFlow(("MAIN::HGCMService::GuestCall\n"));
    18041976
    18051977    int rc;
    1806     HGCMMsgCall *pMsg = new (std::nothrow) HGCMMsgCall(m_pThread);
     1978    HGCMMsgCall *pMsg = new(std::nothrow) HGCMMsgCall(m_pThread);
    18071979    if (pMsg)
    18081980    {
    18091981        pMsg->Reference(); /** @todo starts out with zero references. */
    18101982
    1811         pMsg->pCmd        = pCmd;
    1812         pMsg->pHGCMPort   = pHGCMPort;
    1813         pMsg->u32ClientId = u32ClientId;
    1814         pMsg->u32Function = u32Function;
    1815         pMsg->cParms      = cParms;
    1816         pMsg->paParms     = paParms;
    1817         pMsg->tsArrival   = tsArrival;
    1818 
    1819         rc = hgcmMsgPost(pMsg, hgcmMsgCompletionCallback);
     1983        uint32_t cCalls = ASMAtomicIncU32(&pClient->cPendingCalls);
     1984        Assert(pClient->idxCategory < RT_ELEMENTS(m_fntable.acMaxCallsPerClient));
     1985        if (cCalls < m_fntable.acMaxCallsPerClient[pClient->idxCategory])
     1986        {
     1987            pMsg->pcCounter   = &pClient->cPendingCalls;
     1988            Log3(("MAIN::HGCMService::GuestCall: pMsg=%p cPendingCalls=%u / %u / %s (fun %u, %u parms)\n",
     1989                  pMsg, cCalls, u32ClientId, m_pszSvcName, u32Function, cParms));
     1990
     1991            pMsg->pCmd        = pCmd;
     1992            pMsg->pHGCMPort   = pHGCMPort;
     1993            pMsg->u32ClientId = u32ClientId;
     1994            pMsg->u32Function = u32Function;
     1995            pMsg->cParms      = cParms;
     1996            pMsg->paParms     = paParms;
     1997            pMsg->tsArrival   = tsArrival;
     1998
     1999            rc = hgcmMsgPost(pMsg, hgcmMsgCallCompletionCallback);
     2000
     2001            if (RT_SUCCESS(rc))
     2002            { /* Reference donated on success. */ }
     2003            else
     2004            {
     2005                ASMAtomicDecU32(&pClient->cPendingCalls);
     2006                pMsg->pcCounter = NULL;
     2007                Log(("MAIN::HGCMService::GuestCall: hgcmMsgPost failed: %Rrc\n", rc));
     2008                pMsg->Dereference();
     2009            }
     2010        }
     2011        else
     2012        {
     2013            ASMAtomicDecU32(&pClient->cPendingCalls);
     2014            LogRel2(("HGCM: Too many calls to '%s' from client %u: %u, max %u; category %u\n", m_pszSvcName, u32ClientId,
     2015                     cCalls, m_fntable.acMaxCallsPerClient[pClient->idxCategory], pClient->idxCategory));
     2016            pMsg->Dereference();
     2017            STAM_REL_COUNTER_INC(&m_StatTooManyCalls);
     2018            rc = VERR_HGCM_TOO_MANY_CLIENT_CALLS;
     2019        }
    18202020    }
    18212021    else
     
    18312031/** Guest cancelled a request (call, connection attempt, disconnect attempt).
    18322032 *
    1833  * @param   pHGCMPort      The port to be used for completion confirmation.
     2033 * @param   pHGCMPort      The port to be used for completion confirmation
    18342034 * @param   pCmd           The VBox HGCM context.
    18352035 * @param   idClient       The client handle to be disconnected and deleted.
     
    25722772
    25732773        /* Forward the message to the service thread. */
    2574         rc = pClient->pService->GuestCall(pHGCMPort, pCmd, u32ClientId, u32Function, cParms, paParms, tsArrival);
     2774        rc = pClient->pService->GuestCall(pHGCMPort, pCmd, u32ClientId, pClient, u32Function, cParms, paParms, tsArrival);
    25752775
    25762776        hgcmObjDereference(pClient);
Note: See TracChangeset for help on using the changeset viewer.

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