VirtualBox

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

Last change on this file since 85318 was 85318, checked in by vboxsync, 4 years ago

HostServices: Clang 11++ adjustments. Eliminated pointless auto_ptr. Added a whole bunch of RT_NOEXCEPT to the DnD service abstraction. Misc cleanups. bugref:9790

  • 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-2020 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 uint32_t GetProtocolVer(void) const RT_NOEXCEPT;
114 bool IsDeferred(void) const RT_NOEXCEPT;
115 void SetDeferred(VBOXHGCMCALLHANDLE hHandle, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT;
116 void SetProtocolVer(uint32_t uVersion) RT_NOEXCEPT;
117 void SetSvcContext(const VBOXHGCMSVCTX &SvcCtx) RT_NOEXCEPT;
118
119public:
120 int SetDeferredMsgInfo(uint32_t uMsg, uint32_t cParms) RT_NOEXCEPT;
121 int SetDeferredMsgInfo(const Message *pMessage) RT_NOEXCEPT;
122
123protected:
124 int completeInternal(VBOXHGCMCALLHANDLE hHandle, int rcOp) RT_NOEXCEPT;
125 void reset(void) RT_NOEXCEPT;
126
127protected:
128 /** The client's HGCM client ID. */
129 uint32_t m_idClient;
130 /** Optional protocol version the client uses. Set to 0 by default.
131 * @todo r=bird: This does not belong here. Whether a service has a "protocol
132 * version" isn't given and I've argued that it's an inflexible bad idea. */
133 uint32_t m_uProtocolVer;
134 /** The HGCM service context this client is bound to. */
135 VBOXHGCMSVCTX m_SvcCtx;
136 /** Flag indicating whether this client currently is deferred mode,
137 * meaning that it did not return to the caller yet. */
138 bool m_fDeferred;
139 /** Structure for keeping the client's deferred state.
140 * A client is in a deferred state when it asks for the next HGCM message,
141 * but the service can't provide it yet. That way a client will block (on the guest side, does not return)
142 * until the service can complete the call. */
143 struct
144 {
145 /** The client's HGCM call handle. Needed for completing a deferred call. */
146 VBOXHGCMCALLHANDLE hHandle;
147 /** Message type (function number) to use when completing the deferred call.
148 * @todo r=bird: uType or uMsg? Make up your mind (Message::m_uMsg). */
149 uint32_t uType;
150 /** Parameter count to use when completing the deferred call. */
151 uint32_t cParms;
152 /** Parameters to use when completing the deferred call. */
153 PVBOXHGCMSVCPARM paParms;
154 } m_Deferred;
155};
156
157template <class T>
158class AbstractService : public RTCNonCopyable
159{
160public:
161 /**
162 * @copydoc FNVBOXHGCMSVCLOAD
163 */
164 static DECLCALLBACK(int) svcLoad(VBOXHGCMSVCFNTABLE *pTable)
165 {
166 LogFlowFunc(("ptable = %p\n", pTable));
167 int rc = VINF_SUCCESS;
168
169 if (!VALID_PTR(pTable))
170 rc = VERR_INVALID_PARAMETER;
171 else
172 {
173 LogFlowFunc(("ptable->cbSize = %d, ptable->u32Version = 0x%08X\n", pTable->cbSize, pTable->u32Version));
174
175 if ( pTable->cbSize != sizeof (VBOXHGCMSVCFNTABLE)
176 || pTable->u32Version != VBOX_HGCM_SVC_VERSION)
177 rc = VERR_VERSION_MISMATCH;
178 else
179 {
180 AbstractService *pService = NULL;
181 /* No exceptions may propagate outside (callbacks like this one are nothrow/noexcept). */
182 try { pService = new T(pTable->pHelpers); }
183 catch (std::bad_alloc &) { rc = VERR_NO_MEMORY; }
184 catch (...) { rc = VERR_UNEXPECTED_EXCEPTION; }
185 if (RT_SUCCESS(rc))
186 {
187 /* We don't need an additional client data area on the host,
188 because we're a class which can have members for that :-). */
189 pTable->cbClient = 0;
190
191 /* These functions are mandatory */
192 pTable->pfnUnload = svcUnload;
193 pTable->pfnConnect = svcConnect;
194 pTable->pfnDisconnect = svcDisconnect;
195 pTable->pfnCall = svcCall;
196 /* Clear obligatory functions. */
197 pTable->pfnHostCall = NULL;
198 pTable->pfnSaveState = NULL;
199 pTable->pfnLoadState = NULL;
200 pTable->pfnRegisterExtension = NULL;
201
202 /* Let the service itself initialize. */
203 rc = pService->init(pTable);
204 if (RT_SUCCESS(rc))
205 pTable->pvService = pService;
206 else
207 delete pService;
208 }
209 }
210 }
211
212 LogFlowFunc(("returning %Rrc\n", rc));
213 return rc;
214 }
215 virtual ~AbstractService() {};
216
217protected:
218 explicit AbstractService(PVBOXHGCMSVCHELPERS pHelpers)
219 {
220 RT_ZERO(m_SvcCtx);
221 m_SvcCtx.pHelpers = pHelpers;
222 }
223 virtual int init(VBOXHGCMSVCFNTABLE *ptable) RT_NOEXCEPT
224 { RT_NOREF1(ptable); return VINF_SUCCESS; }
225 virtual int uninit() RT_NOEXCEPT
226 { return VINF_SUCCESS; }
227 virtual int clientConnect(uint32_t idClient, void *pvClient) RT_NOEXCEPT = 0;
228 virtual int clientDisconnect(uint32_t idClient, void *pvClient) RT_NOEXCEPT = 0;
229 virtual void guestCall(VBOXHGCMCALLHANDLE callHandle, uint32_t idClient, void *pvClient, uint32_t eFunction,
230 uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT = 0;
231 virtual int hostCall(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT
232 { RT_NOREF3(eFunction, cParms, paParms); return VINF_SUCCESS; }
233
234 /** Type definition for use in callback functions. */
235 typedef AbstractService SELF;
236 /** The HGCM service context this service is bound to. */
237 VBOXHGCMSVCTX m_SvcCtx;
238
239 /**
240 * @copydoc VBOXHGCMSVCFNTABLE::pfnUnload
241 * Simply deletes the service object
242 */
243 static DECLCALLBACK(int) svcUnload(void *pvService)
244 {
245 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
246 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
247 int rc = pSelf->uninit();
248 AssertRC(rc);
249 if (RT_SUCCESS(rc))
250 delete pSelf;
251 return rc;
252 }
253
254 /**
255 * @copydoc VBOXHGCMSVCFNTABLE::pfnConnect
256 * Stub implementation of pfnConnect and pfnDisconnect.
257 */
258 static DECLCALLBACK(int) svcConnect(void *pvService,
259 uint32_t idClient,
260 void *pvClient,
261 uint32_t fRequestor,
262 bool fRestoring)
263 {
264 RT_NOREF(fRequestor, fRestoring);
265 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
266 LogFlowFunc(("pvService=%p, idClient=%u, pvClient=%p\n", pvService, idClient, pvClient));
267 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
268 int rc = pSelf->clientConnect(idClient, pvClient);
269 LogFlowFunc(("rc=%Rrc\n", rc));
270 return rc;
271 }
272
273 /**
274 * @copydoc VBOXHGCMSVCFNTABLE::pfnConnect
275 * Stub implementation of pfnConnect and pfnDisconnect.
276 */
277 static DECLCALLBACK(int) svcDisconnect(void *pvService,
278 uint32_t idClient,
279 void *pvClient)
280 {
281 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
282 LogFlowFunc(("pvService=%p, idClient=%u, pvClient=%p\n", pvService, idClient, pvClient));
283 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
284 int rc = pSelf->clientDisconnect(idClient, pvClient);
285 LogFlowFunc(("rc=%Rrc\n", rc));
286 return rc;
287 }
288
289 /**
290 * @copydoc VBOXHGCMSVCFNTABLE::pfnCall
291 * Wraps to the call member function
292 */
293 static DECLCALLBACK(void) svcCall(void *pvService,
294 VBOXHGCMCALLHANDLE callHandle,
295 uint32_t idClient,
296 void *pvClient,
297 uint32_t u32Function,
298 uint32_t cParms,
299 VBOXHGCMSVCPARM paParms[],
300 uint64_t tsArrival)
301 {
302 AssertLogRelReturnVoid(VALID_PTR(pvService));
303 LogFlowFunc(("pvService=%p, callHandle=%p, idClient=%u, pvClient=%p, u32Function=%u, cParms=%u, paParms=%p\n",
304 pvService, callHandle, idClient, pvClient, u32Function, cParms, paParms));
305 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
306 pSelf->guestCall(callHandle, idClient, pvClient, u32Function, cParms, paParms);
307 LogFlowFunc(("returning\n"));
308 RT_NOREF_PV(tsArrival);
309 }
310
311 /**
312 * @copydoc VBOXHGCMSVCFNTABLE::pfnHostCall
313 * Wraps to the hostCall member function
314 */
315 static DECLCALLBACK(int) svcHostCall(void *pvService,
316 uint32_t u32Function,
317 uint32_t cParms,
318 VBOXHGCMSVCPARM paParms[])
319 {
320 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
321 LogFlowFunc(("pvService=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, u32Function, cParms, paParms));
322 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
323 int rc = pSelf->hostCall(u32Function, cParms, paParms);
324 LogFlowFunc(("rc=%Rrc\n", rc));
325 return rc;
326 }
327
328 /**
329 * @copydoc VBOXHGCMSVCFNTABLE::pfnRegisterExtension
330 * Installs a host callback for notifications of property changes.
331 */
332 static DECLCALLBACK(int) svcRegisterExtension(void *pvService,
333 PFNHGCMSVCEXT pfnExtension,
334 void *pvExtension)
335 {
336 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
337 LogFlowFunc(("pvService=%p, pfnExtension=%p, pvExtention=%p\n", pvService, pfnExtension, pvExtension));
338 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
339 pSelf->m_SvcCtx.pfnHostCallback = pfnExtension;
340 pSelf->m_SvcCtx.pvHostData = pvExtension;
341 return VINF_SUCCESS;
342 }
343
344 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AbstractService);
345};
346
347}
348#endif /* !VBOX_INCLUDED_HostServices_Service_h */
349
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