VirtualBox

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

Last change on this file since 103224 was 98103, checked in by vboxsync, 23 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
Line 
1/** @file
2 * Base class for an host-guest service.
3 */
4
5/*
6 * Copyright (C) 2011-2023 Oracle and/or its affiliates.
7 *
8 * This file is part of VirtualBox base platform packages, as
9 * available from https://www.virtualbox.org.
10 *
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 *
24 * The contents of this file may alternatively be used under the terms
25 * of the Common Development and Distribution License Version 1.0
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
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.
32 *
33 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
34 */
35
36#ifndef VBOX_INCLUDED_HostServices_Service_h
37#define VBOX_INCLUDED_HostServices_Service_h
38#ifndef RT_WITHOUT_PRAGMA_ONCE
39# pragma once
40#endif
41
42#include <VBox/log.h>
43#include <VBox/hgcmsvc.h>
44
45#include <iprt/assert.h>
46#include <iprt/alloc.h>
47#include <iprt/cpp/utils.h>
48
49#include <new>
50
51
52namespace HGCM
53{
54
55/**
56 * Structure for keeping a HGCM service context.
57 */
58typedef struct VBOXHGCMSVCTX
59{
60 /** HGCM helper functions. */
61 PVBOXHGCMSVCHELPERS pHelpers;
62 /**
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 */
74class Message
75{
76public:
77 Message(void);
78 Message(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM aParms[]);
79 virtual ~Message(void);
80
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;
87
88public:
89 static int CopyParms(PVBOXHGCMSVCPARM paParmsDst, uint32_t cParmsDst,
90 PVBOXHGCMSVCPARM paParmsSrc, uint32_t cParmsSrc,
91 bool fDeepCopy) RT_NOEXCEPT;
92
93protected:
94 int initData(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM aParms[]) RT_NOEXCEPT;
95 void reset() RT_NOEXCEPT;
96
97protected:
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;
105};
106
107/**
108 * Class for keeping and tracking a HGCM client.
109 */
110class Client
111{
112public:
113 Client(uint32_t idClient);
114 virtual ~Client(void);
115
116public:
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;
126
127public:
128 int SetDeferredMsgInfo(uint32_t uMsg, uint32_t cParms) RT_NOEXCEPT;
129 int SetDeferredMsgInfo(const Message *pMessage) RT_NOEXCEPT;
130
131protected:
132 int completeInternal(VBOXHGCMCALLHANDLE hHandle, int rcOp) RT_NOEXCEPT;
133 void reset(void) RT_NOEXCEPT;
134
135protected:
136 /** The client's HGCM client ID. */
137 uint32_t m_idClient;
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;
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). */
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;
159};
160
161template <class T>
162class AbstractService : public RTCNonCopyable
163{
164public:
165 /**
166 * @copydoc FNVBOXHGCMSVCLOAD
167 */
168 static DECLCALLBACK(int) svcLoad(VBOXHGCMSVCFNTABLE *pTable)
169 {
170 LogFlowFunc(("ptable = %p\n", pTable));
171 int rc = VINF_SUCCESS;
172
173 if (!RT_VALID_PTR(pTable))
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 {
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; }
189 if (RT_SUCCESS(rc))
190 {
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 :-). */
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. */
198 pTable->cbClient = 0;
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. */
212 rc = pService->init(pTable);
213 if (RT_SUCCESS(rc))
214 pTable->pvService = pService;
215 else
216 delete pService;
217 }
218 }
219 }
220
221 LogFlowFunc(("returning %Rrc\n", rc));
222 return rc;
223 }
224 virtual ~AbstractService() {};
225
226protected:
227 explicit AbstractService(PVBOXHGCMSVCHELPERS pHelpers)
228 {
229 RT_ZERO(m_SvcCtx);
230 m_SvcCtx.pHelpers = pHelpers;
231 }
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
241 { RT_NOREF3(eFunction, cParms, paParms); return VINF_SUCCESS; }
242
243 /** Type definition for use in callback functions. */
244 typedef AbstractService SELF;
245 /** The HGCM service context this service is bound to. */
246 VBOXHGCMSVCTX m_SvcCtx;
247
248 /**
249 * @copydoc VBOXHGCMSVCFNTABLE::pfnUnload
250 * Simply deletes the service object
251 */
252 static DECLCALLBACK(int) svcUnload(void *pvService)
253 {
254 AssertLogRelReturn(RT_VALID_PTR(pvService), VERR_INVALID_PARAMETER);
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 /**
264 * @copydoc VBOXHGCMSVCFNTABLE::pfnConnect
265 * Stub implementation of pfnConnect and pfnDisconnect.
266 */
267 static DECLCALLBACK(int) svcConnect(void *pvService,
268 uint32_t idClient,
269 void *pvClient,
270 uint32_t fRequestor,
271 bool fRestoring)
272 {
273 RT_NOREF(fRequestor, fRestoring);
274 AssertLogRelReturn(RT_VALID_PTR(pvService), VERR_INVALID_PARAMETER);
275 LogFlowFunc(("pvService=%p, idClient=%u, pvClient=%p\n", pvService, idClient, pvClient));
276 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
277 int rc = pSelf->clientConnect(idClient, pvClient);
278 LogFlowFunc(("rc=%Rrc\n", rc));
279 return rc;
280 }
281
282 /**
283 * @copydoc VBOXHGCMSVCFNTABLE::pfnConnect
284 * Stub implementation of pfnConnect and pfnDisconnect.
285 */
286 static DECLCALLBACK(int) svcDisconnect(void *pvService,
287 uint32_t idClient,
288 void *pvClient)
289 {
290 AssertLogRelReturn(RT_VALID_PTR(pvService), VERR_INVALID_PARAMETER);
291 LogFlowFunc(("pvService=%p, idClient=%u, pvClient=%p\n", pvService, idClient, pvClient));
292 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
293 int rc = pSelf->clientDisconnect(idClient, pvClient);
294 LogFlowFunc(("rc=%Rrc\n", rc));
295 return rc;
296 }
297
298 /**
299 * @copydoc VBOXHGCMSVCFNTABLE::pfnCall
300 * Wraps to the call member function
301 */
302 static DECLCALLBACK(void) svcCall(void *pvService,
303 VBOXHGCMCALLHANDLE callHandle,
304 uint32_t idClient,
305 void *pvClient,
306 uint32_t u32Function,
307 uint32_t cParms,
308 VBOXHGCMSVCPARM paParms[],
309 uint64_t tsArrival)
310 {
311 AssertLogRelReturnVoid(RT_VALID_PTR(pvService));
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));
314 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
315 pSelf->guestCall(callHandle, idClient, pvClient, u32Function, cParms, paParms);
316 LogFlowFunc(("returning\n"));
317 RT_NOREF_PV(tsArrival);
318 }
319
320 /**
321 * @copydoc VBOXHGCMSVCFNTABLE::pfnHostCall
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 {
329 AssertLogRelReturn(RT_VALID_PTR(pvService), VERR_INVALID_PARAMETER);
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 /**
338 * @copydoc VBOXHGCMSVCFNTABLE::pfnRegisterExtension
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 {
345 AssertLogRelReturn(RT_VALID_PTR(pvService), VERR_INVALID_PARAMETER);
346 LogFlowFunc(("pvService=%p, pfnExtension=%p, pvExtention=%p\n", pvService, pfnExtension, pvExtension));
347 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
348 pSelf->m_SvcCtx.pfnHostCallback = pfnExtension;
349 pSelf->m_SvcCtx.pvHostData = pvExtension;
350 return VINF_SUCCESS;
351 }
352
353 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AbstractService);
354};
355
356}
357#endif /* !VBOX_INCLUDED_HostServices_Service_h */
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