VirtualBox

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

Last change on this file since 96316 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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