VirtualBox

source: vbox/trunk/include/VBox/HostServices/Service.h@ 104429

Last change on this file since 104429 was 98103, checked in by vboxsync, 22 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.8 KB
RevLine 
[42266]1/** @file
2 * Base class for an host-guest service.
3 */
4
5/*
[98103]6 * Copyright (C) 2011-2023 Oracle and/or its affiliates.
[42266]7 *
[96407]8 * This file is part of VirtualBox base platform packages, as
9 * available from https://www.virtualbox.org.
[42266]10 *
[96407]11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation, in version 3 of the
14 * License.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, see <https://www.gnu.org/licenses>.
23 *
[42266]24 * The contents of this file may alternatively be used under the terms
25 * of the Common Development and Distribution License Version 1.0
[96407]26 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
27 * in the VirtualBox distribution, in which case the provisions of the
[42266]28 * CDDL are applicable instead of those of the GPL.
29 *
30 * You may elect to license modified versions of this file under the
31 * terms and conditions of either the GPL or the CDDL or both.
[96407]32 *
33 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
[42266]34 */
35
[76558]36#ifndef VBOX_INCLUDED_HostServices_Service_h
37#define VBOX_INCLUDED_HostServices_Service_h
[76507]38#ifndef RT_WITHOUT_PRAGMA_ONCE
39# pragma once
40#endif
[42266]41
42#include <VBox/log.h>
43#include <VBox/hgcmsvc.h>
[74205]44
[42266]45#include <iprt/assert.h>
46#include <iprt/alloc.h>
47#include <iprt/cpp/utils.h>
48
[85318]49#include <new>
[42266]50
[85318]51
[42266]52namespace HGCM
53{
54
[73939]55/**
[74205]56 * Structure for keeping a HGCM service context.
[73939]57 */
[74205]58typedef struct VBOXHGCMSVCTX
59{
60 /** HGCM helper functions. */
61 PVBOXHGCMSVCHELPERS pHelpers;
[85318]62 /**
[74205]63 * Callback function supplied by the host for notification of updates
64 * to properties.
65 */
66 PFNHGCMSVCEXT pfnHostCallback;
67 /** User data pointer to be supplied to the host callback function. */
68 void *pvHostData;
69} VBOXHGCMSVCTX, *PVBOXHGCMSVCTX;
70
71/**
72 * Base class encapsulating and working with a HGCM message.
73 */
[42266]74class Message
75{
76public:
[74205]77 Message(void);
78 Message(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM aParms[]);
79 virtual ~Message(void);
[42266]80
[85318]81 uint32_t GetParamCount(void) const RT_NOEXCEPT;
82 int GetData(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM aParms[]) const RT_NOEXCEPT;
83 int GetParmU32(uint32_t uParm, uint32_t *pu32Info) const RT_NOEXCEPT;
84 int GetParmU64(uint32_t uParm, uint64_t *pu64Info) const RT_NOEXCEPT;
85 int GetParmPtr(uint32_t uParm, void **ppvAddr, uint32_t *pcbSize) const RT_NOEXCEPT;
86 uint32_t GetType(void) const RT_NOEXCEPT;
[73939]87
[74205]88public:
[85318]89 static int CopyParms(PVBOXHGCMSVCPARM paParmsDst, uint32_t cParmsDst,
90 PVBOXHGCMSVCPARM paParmsSrc, uint32_t cParmsSrc,
91 bool fDeepCopy) RT_NOEXCEPT;
[42266]92
[74205]93protected:
[85318]94 int initData(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM aParms[]) RT_NOEXCEPT;
95 void reset() RT_NOEXCEPT;
[59830]96
[74205]97protected:
[73940]98
99 /** Stored message type. */
100 uint32_t m_uMsg;
101 /** Number of stored HGCM parameters. */
102 uint32_t m_cParms;
103 /** Stored HGCM parameters. */
104 PVBOXHGCMSVCPARM m_paParms;
[42266]105};
106
[73939]107/**
108 * Class for keeping and tracking a HGCM client.
109 */
[42266]110class Client
111{
112public:
[85318]113 Client(uint32_t idClient);
[74205]114 virtual ~Client(void);
115
[55422]116public:
[85318]117 int Complete(VBOXHGCMCALLHANDLE hHandle, int rcOp = VINF_SUCCESS) RT_NOEXCEPT;
118 int CompleteDeferred(int rcOp = VINF_SUCCESS) RT_NOEXCEPT;
119 uint32_t GetClientID(void) const RT_NOEXCEPT;
120 VBOXHGCMCALLHANDLE GetHandle(void) const RT_NOEXCEPT;
121 uint32_t GetMsgType(void) const RT_NOEXCEPT;
122 uint32_t GetMsgParamCount(void) const RT_NOEXCEPT;
123 bool IsDeferred(void) const RT_NOEXCEPT;
124 void SetDeferred(VBOXHGCMCALLHANDLE hHandle, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT;
125 void SetSvcContext(const VBOXHGCMSVCTX &SvcCtx) RT_NOEXCEPT;
[42266]126
[55422]127public:
[85318]128 int SetDeferredMsgInfo(uint32_t uMsg, uint32_t cParms) RT_NOEXCEPT;
129 int SetDeferredMsgInfo(const Message *pMessage) RT_NOEXCEPT;
[55422]130
[74205]131protected:
[85318]132 int completeInternal(VBOXHGCMCALLHANDLE hHandle, int rcOp) RT_NOEXCEPT;
133 void reset(void) RT_NOEXCEPT;
[42266]134
[58329]135protected:
[74205]136 /** The client's HGCM client ID. */
[85318]137 uint32_t m_idClient;
[74205]138 /** The HGCM service context this client is bound to. */
139 VBOXHGCMSVCTX m_SvcCtx;
140 /** Flag indicating whether this client currently is deferred mode,
141 * meaning that it did not return to the caller yet. */
142 bool m_fDeferred;
143 /** Structure for keeping the client's deferred state.
144 * A client is in a deferred state when it asks for the next HGCM message,
145 * but the service can't provide it yet. That way a client will block (on the guest side, does not return)
146 * until the service can complete the call. */
147 struct
148 {
149 /** The client's HGCM call handle. Needed for completing a deferred call. */
150 VBOXHGCMCALLHANDLE hHandle;
[85318]151 /** Message type (function number) to use when completing the deferred call.
152 * @todo r=bird: uType or uMsg? Make up your mind (Message::m_uMsg). */
[74205]153 uint32_t uType;
154 /** Parameter count to use when completing the deferred call. */
155 uint32_t cParms;
156 /** Parameters to use when completing the deferred call. */
157 PVBOXHGCMSVCPARM paParms;
158 } m_Deferred;
[42266]159};
160
161template <class T>
[85121]162class AbstractService : public RTCNonCopyable
[42266]163{
164public:
165 /**
[85121]166 * @copydoc FNVBOXHGCMSVCLOAD
[42266]167 */
168 static DECLCALLBACK(int) svcLoad(VBOXHGCMSVCFNTABLE *pTable)
169 {
170 LogFlowFunc(("ptable = %p\n", pTable));
171 int rc = VINF_SUCCESS;
172
[90792]173 if (!RT_VALID_PTR(pTable))
[42266]174 rc = VERR_INVALID_PARAMETER;
175 else
176 {
177 LogFlowFunc(("ptable->cbSize = %d, ptable->u32Version = 0x%08X\n", pTable->cbSize, pTable->u32Version));
178
179 if ( pTable->cbSize != sizeof (VBOXHGCMSVCFNTABLE)
180 || pTable->u32Version != VBOX_HGCM_SVC_VERSION)
181 rc = VERR_VERSION_MISMATCH;
182 else
183 {
[85318]184 AbstractService *pService = NULL;
185 /* No exceptions may propagate outside (callbacks like this one are nothrow/noexcept). */
186 try { pService = new T(pTable->pHelpers); }
187 catch (std::bad_alloc &) { rc = VERR_NO_MEMORY; }
188 catch (...) { rc = VERR_UNEXPECTED_EXCEPTION; }
[42266]189 if (RT_SUCCESS(rc))
190 {
[85318]191 /* We don't need an additional client data area on the host,
192 because we're a class which can have members for that :-). */
[90237]193 /** @todo r=bird: What the comment above says is that we can duplicate the
194 * work of associating data with a client ID already done by the HGCM and create
195 * additional bugs because we think that's cool. It's not. Utterly
196 * appalling as well as inefficient. Just a structure with a pointer to a
197 * client base class would go a long way here. */
[85318]198 pTable->cbClient = 0;
[42266]199
200 /* These functions are mandatory */
201 pTable->pfnUnload = svcUnload;
202 pTable->pfnConnect = svcConnect;
203 pTable->pfnDisconnect = svcDisconnect;
204 pTable->pfnCall = svcCall;
205 /* Clear obligatory functions. */
206 pTable->pfnHostCall = NULL;
207 pTable->pfnSaveState = NULL;
208 pTable->pfnLoadState = NULL;
209 pTable->pfnRegisterExtension = NULL;
210
211 /* Let the service itself initialize. */
[85318]212 rc = pService->init(pTable);
[42266]213 if (RT_SUCCESS(rc))
[85318]214 pTable->pvService = pService;
215 else
216 delete pService;
[42266]217 }
218 }
219 }
220
221 LogFlowFunc(("returning %Rrc\n", rc));
222 return rc;
223 }
224 virtual ~AbstractService() {};
225
226protected:
227 explicit AbstractService(PVBOXHGCMSVCHELPERS pHelpers)
[58329]228 {
229 RT_ZERO(m_SvcCtx);
230 m_SvcCtx.pHelpers = pHelpers;
231 }
[85318]232 virtual int init(VBOXHGCMSVCFNTABLE *ptable) RT_NOEXCEPT
233 { RT_NOREF1(ptable); return VINF_SUCCESS; }
234 virtual int uninit() RT_NOEXCEPT
235 { return VINF_SUCCESS; }
236 virtual int clientConnect(uint32_t idClient, void *pvClient) RT_NOEXCEPT = 0;
237 virtual int clientDisconnect(uint32_t idClient, void *pvClient) RT_NOEXCEPT = 0;
238 virtual void guestCall(VBOXHGCMCALLHANDLE callHandle, uint32_t idClient, void *pvClient, uint32_t eFunction,
239 uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT = 0;
240 virtual int hostCall(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT
[62802]241 { RT_NOREF3(eFunction, cParms, paParms); return VINF_SUCCESS; }
[42266]242
243 /** Type definition for use in callback functions. */
244 typedef AbstractService SELF;
[58329]245 /** The HGCM service context this service is bound to. */
246 VBOXHGCMSVCTX m_SvcCtx;
[42266]247
248 /**
[58106]249 * @copydoc VBOXHGCMSVCFNTABLE::pfnUnload
[42266]250 * Simply deletes the service object
251 */
252 static DECLCALLBACK(int) svcUnload(void *pvService)
253 {
[90792]254 AssertLogRelReturn(RT_VALID_PTR(pvService), VERR_INVALID_PARAMETER);
[42266]255 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
256 int rc = pSelf->uninit();
257 AssertRC(rc);
258 if (RT_SUCCESS(rc))
259 delete pSelf;
260 return rc;
261 }
262
263 /**
[58106]264 * @copydoc VBOXHGCMSVCFNTABLE::pfnConnect
[42266]265 * Stub implementation of pfnConnect and pfnDisconnect.
266 */
267 static DECLCALLBACK(int) svcConnect(void *pvService,
[85318]268 uint32_t idClient,
[75773]269 void *pvClient,
270 uint32_t fRequestor,
271 bool fRestoring)
[42266]272 {
[75773]273 RT_NOREF(fRequestor, fRestoring);
[90792]274 AssertLogRelReturn(RT_VALID_PTR(pvService), VERR_INVALID_PARAMETER);
[85318]275 LogFlowFunc(("pvService=%p, idClient=%u, pvClient=%p\n", pvService, idClient, pvClient));
[42266]276 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
[85318]277 int rc = pSelf->clientConnect(idClient, pvClient);
[42266]278 LogFlowFunc(("rc=%Rrc\n", rc));
279 return rc;
280 }
281
282 /**
[58106]283 * @copydoc VBOXHGCMSVCFNTABLE::pfnConnect
[42266]284 * Stub implementation of pfnConnect and pfnDisconnect.
285 */
286 static DECLCALLBACK(int) svcDisconnect(void *pvService,
[85318]287 uint32_t idClient,
[42266]288 void *pvClient)
289 {
[90792]290 AssertLogRelReturn(RT_VALID_PTR(pvService), VERR_INVALID_PARAMETER);
[85318]291 LogFlowFunc(("pvService=%p, idClient=%u, pvClient=%p\n", pvService, idClient, pvClient));
[42266]292 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
[85318]293 int rc = pSelf->clientDisconnect(idClient, pvClient);
[42266]294 LogFlowFunc(("rc=%Rrc\n", rc));
295 return rc;
296 }
297
298 /**
[58106]299 * @copydoc VBOXHGCMSVCFNTABLE::pfnCall
[42266]300 * Wraps to the call member function
301 */
[85318]302 static DECLCALLBACK(void) svcCall(void *pvService,
[42266]303 VBOXHGCMCALLHANDLE callHandle,
[85318]304 uint32_t idClient,
[42266]305 void *pvClient,
306 uint32_t u32Function,
307 uint32_t cParms,
[75500]308 VBOXHGCMSVCPARM paParms[],
309 uint64_t tsArrival)
[42266]310 {
[90792]311 AssertLogRelReturnVoid(RT_VALID_PTR(pvService));
[85318]312 LogFlowFunc(("pvService=%p, callHandle=%p, idClient=%u, pvClient=%p, u32Function=%u, cParms=%u, paParms=%p\n",
313 pvService, callHandle, idClient, pvClient, u32Function, cParms, paParms));
[42266]314 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
[85318]315 pSelf->guestCall(callHandle, idClient, pvClient, u32Function, cParms, paParms);
[42266]316 LogFlowFunc(("returning\n"));
[75500]317 RT_NOREF_PV(tsArrival);
[42266]318 }
319
320 /**
[58106]321 * @copydoc VBOXHGCMSVCFNTABLE::pfnHostCall
[42266]322 * Wraps to the hostCall member function
323 */
324 static DECLCALLBACK(int) svcHostCall(void *pvService,
325 uint32_t u32Function,
326 uint32_t cParms,
327 VBOXHGCMSVCPARM paParms[])
328 {
[90792]329 AssertLogRelReturn(RT_VALID_PTR(pvService), VERR_INVALID_PARAMETER);
[42266]330 LogFlowFunc(("pvService=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, u32Function, cParms, paParms));
331 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
332 int rc = pSelf->hostCall(u32Function, cParms, paParms);
333 LogFlowFunc(("rc=%Rrc\n", rc));
334 return rc;
335 }
336
337 /**
[58106]338 * @copydoc VBOXHGCMSVCFNTABLE::pfnRegisterExtension
[42266]339 * Installs a host callback for notifications of property changes.
340 */
341 static DECLCALLBACK(int) svcRegisterExtension(void *pvService,
342 PFNHGCMSVCEXT pfnExtension,
343 void *pvExtension)
344 {
[90792]345 AssertLogRelReturn(RT_VALID_PTR(pvService), VERR_INVALID_PARAMETER);
[42266]346 LogFlowFunc(("pvService=%p, pfnExtension=%p, pvExtention=%p\n", pvService, pfnExtension, pvExtension));
347 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
[58329]348 pSelf->m_SvcCtx.pfnHostCallback = pfnExtension;
349 pSelf->m_SvcCtx.pvHostData = pvExtension;
[42266]350 return VINF_SUCCESS;
351 }
[62802]352
353 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AbstractService);
[42266]354};
355
356}
[76585]357#endif /* !VBOX_INCLUDED_HostServices_Service_h */
[42266]358
Note: See TracBrowser for help on using the repository browser.

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