VirtualBox

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

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

iprt/cdefs.h: Refactored the typedef use of DECLCALLBACK as well as DECLCALLBACKMEMBER to wrap the whole expression, similar to the DECLR?CALLBACKMEMBER macros. This allows adding a throw() at the end when compiling with the VC++ compiler to indicate that the callbacks won't throw anything, so we can stop supressing the C5039 warning about passing functions that can potential throw C++ exceptions to extern C code that can't necessarily cope with such (unwind,++). Introduced a few _EX variations that allows specifying different/no calling convention too, as that's handy when dynamically resolving host APIs. Fixed numerous places missing DECLCALLBACK and such. Left two angry @todos regarding use of CreateThread. bugref:9794

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.0 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 <memory> /* for auto_ptr */
33
34#include <VBox/log.h>
35#include <VBox/hgcmsvc.h>
36
37#include <iprt/assert.h>
38#include <iprt/alloc.h>
39#include <iprt/cpp/utils.h>
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
68 Message(void);
69
70 Message(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM aParms[]);
71
72 virtual ~Message(void);
73
74 uint32_t GetParamCount(void) const;
75
76 int GetData(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM aParms[]) const;
77
78 int GetParmU32(uint32_t uParm, uint32_t *pu32Info) const;
79
80 int GetParmU64(uint32_t uParm, uint64_t *pu64Info) const;
81
82 int GetParmPtr(uint32_t uParm, void **ppvAddr, uint32_t *pcbSize) const;
83
84 uint32_t GetType(void) const;
85
86public:
87
88 static int CopyParms(PVBOXHGCMSVCPARM paParmsDst, uint32_t cParmsDst,
89 PVBOXHGCMSVCPARM paParmsSrc, uint32_t cParmsSrc,
90 bool fDeepCopy);
91
92protected:
93
94 int initData(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM aParms[]);
95
96 void reset();
97
98protected:
99
100 /** Stored message type. */
101 uint32_t m_uMsg;
102 /** Number of stored HGCM parameters. */
103 uint32_t m_cParms;
104 /** Stored HGCM parameters. */
105 PVBOXHGCMSVCPARM m_paParms;
106};
107
108/**
109 * Class for keeping and tracking a HGCM client.
110 */
111class Client
112{
113public:
114
115 Client(uint32_t uClientID);
116
117 virtual ~Client(void);
118
119public:
120
121 int Complete(VBOXHGCMCALLHANDLE hHandle, int rcOp = VINF_SUCCESS);
122
123 int CompleteDeferred(int rcOp = VINF_SUCCESS);
124
125 uint32_t GetClientID(void) const;
126
127 VBOXHGCMCALLHANDLE GetHandle(void) const;
128
129 uint32_t GetMsgType(void) const;
130
131 uint32_t GetMsgParamCount(void) const;
132
133 uint32_t GetProtocolVer(void) const;
134
135 bool IsDeferred(void) const;
136
137 void SetDeferred(VBOXHGCMCALLHANDLE hHandle, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
138
139 void SetProtocolVer(uint32_t uVersion);
140
141 void SetSvcContext(const VBOXHGCMSVCTX &SvcCtx);
142
143public:
144
145 int SetDeferredMsgInfo(uint32_t uMsg, uint32_t cParms);
146
147 int SetDeferredMsgInfo(const Message *pMessage);
148
149protected:
150
151 int completeInternal(VBOXHGCMCALLHANDLE hHandle, int rcOp);
152
153 void reset(void);
154
155protected:
156
157 /** The client's HGCM client ID. */
158 uint32_t m_uClientID;
159 /** Optional protocol version the client uses. Set to 0 by default. */
160 uint32_t m_uProtocolVer;
161 /** The HGCM service context this client is bound to. */
162 VBOXHGCMSVCTX m_SvcCtx;
163 /** Flag indicating whether this client currently is deferred mode,
164 * meaning that it did not return to the caller yet. */
165 bool m_fDeferred;
166 /** Structure for keeping the client's deferred state.
167 * A client is in a deferred state when it asks for the next HGCM message,
168 * but the service can't provide it yet. That way a client will block (on the guest side, does not return)
169 * until the service can complete the call. */
170 struct
171 {
172 /** The client's HGCM call handle. Needed for completing a deferred call. */
173 VBOXHGCMCALLHANDLE hHandle;
174 /** Message type (function number) to use when completing the deferred call. */
175 uint32_t uType;
176 /** Parameter count to use when completing the deferred call. */
177 uint32_t cParms;
178 /** Parameters to use when completing the deferred call. */
179 PVBOXHGCMSVCPARM paParms;
180 } m_Deferred;
181};
182
183template <class T>
184class AbstractService : public RTCNonCopyable
185{
186public:
187 /**
188 * @copydoc FNVBOXHGCMSVCLOAD
189 */
190 static DECLCALLBACK(int) svcLoad(VBOXHGCMSVCFNTABLE *pTable)
191 {
192 LogFlowFunc(("ptable = %p\n", pTable));
193 int rc = VINF_SUCCESS;
194
195 if (!VALID_PTR(pTable))
196 rc = VERR_INVALID_PARAMETER;
197 else
198 {
199 LogFlowFunc(("ptable->cbSize = %d, ptable->u32Version = 0x%08X\n", pTable->cbSize, pTable->u32Version));
200
201 if ( pTable->cbSize != sizeof (VBOXHGCMSVCFNTABLE)
202 || pTable->u32Version != VBOX_HGCM_SVC_VERSION)
203 rc = VERR_VERSION_MISMATCH;
204 else
205 {
206 RT_GCC_NO_WARN_DEPRECATED_BEGIN
207 std::auto_ptr<AbstractService> apService;
208 /* No exceptions may propagate outside. */
209 try
210 {
211 apService = std::auto_ptr<AbstractService>(new T(pTable->pHelpers));
212 } catch (int rcThrown)
213 {
214 rc = rcThrown;
215 } catch (...)
216 {
217 rc = VERR_UNRESOLVED_ERROR;
218 }
219 RT_GCC_NO_WARN_DEPRECATED_END
220 if (RT_SUCCESS(rc))
221 {
222 /*
223 * We don't need an additional client data area on the host,
224 * because we're a class which can have members for that :-).
225 */
226 pTable->cbClient = 0;
227
228 /* These functions are mandatory */
229 pTable->pfnUnload = svcUnload;
230 pTable->pfnConnect = svcConnect;
231 pTable->pfnDisconnect = svcDisconnect;
232 pTable->pfnCall = svcCall;
233 /* Clear obligatory functions. */
234 pTable->pfnHostCall = NULL;
235 pTable->pfnSaveState = NULL;
236 pTable->pfnLoadState = NULL;
237 pTable->pfnRegisterExtension = NULL;
238
239 /* Let the service itself initialize. */
240 rc = apService->init(pTable);
241
242 /* Only on success stop the auto release of the auto_ptr. */
243 if (RT_SUCCESS(rc))
244 pTable->pvService = apService.release();
245 }
246 }
247 }
248
249 LogFlowFunc(("returning %Rrc\n", rc));
250 return rc;
251 }
252 virtual ~AbstractService() {};
253
254protected:
255 explicit AbstractService(PVBOXHGCMSVCHELPERS pHelpers)
256 {
257 RT_ZERO(m_SvcCtx);
258 m_SvcCtx.pHelpers = pHelpers;
259 }
260 virtual int init(VBOXHGCMSVCFNTABLE *ptable) { RT_NOREF1(ptable); return VINF_SUCCESS; }
261 virtual int uninit() { return VINF_SUCCESS; }
262 virtual int clientConnect(uint32_t u32ClientID, void *pvClient) = 0;
263 virtual int clientDisconnect(uint32_t u32ClientID, void *pvClient) = 0;
264 virtual void guestCall(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, void *pvClient, uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) = 0;
265 virtual int hostCall(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
266 { RT_NOREF3(eFunction, cParms, paParms); return VINF_SUCCESS; }
267
268 /** Type definition for use in callback functions. */
269 typedef AbstractService SELF;
270 /** The HGCM service context this service is bound to. */
271 VBOXHGCMSVCTX m_SvcCtx;
272
273 /**
274 * @copydoc VBOXHGCMSVCFNTABLE::pfnUnload
275 * Simply deletes the service object
276 */
277 static DECLCALLBACK(int) svcUnload(void *pvService)
278 {
279 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
280 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
281 int rc = pSelf->uninit();
282 AssertRC(rc);
283 if (RT_SUCCESS(rc))
284 delete pSelf;
285 return rc;
286 }
287
288 /**
289 * @copydoc VBOXHGCMSVCFNTABLE::pfnConnect
290 * Stub implementation of pfnConnect and pfnDisconnect.
291 */
292 static DECLCALLBACK(int) svcConnect(void *pvService,
293 uint32_t u32ClientID,
294 void *pvClient,
295 uint32_t fRequestor,
296 bool fRestoring)
297 {
298 RT_NOREF(fRequestor, fRestoring);
299 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
300 LogFlowFunc(("pvService=%p, u32ClientID=%u, pvClient=%p\n", pvService, u32ClientID, pvClient));
301 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
302 int rc = pSelf->clientConnect(u32ClientID, pvClient);
303 LogFlowFunc(("rc=%Rrc\n", rc));
304 return rc;
305 }
306
307 /**
308 * @copydoc VBOXHGCMSVCFNTABLE::pfnConnect
309 * Stub implementation of pfnConnect and pfnDisconnect.
310 */
311 static DECLCALLBACK(int) svcDisconnect(void *pvService,
312 uint32_t u32ClientID,
313 void *pvClient)
314 {
315 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
316 LogFlowFunc(("pvService=%p, u32ClientID=%u, pvClient=%p\n", pvService, u32ClientID, pvClient));
317 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
318 int rc = pSelf->clientDisconnect(u32ClientID, pvClient);
319 LogFlowFunc(("rc=%Rrc\n", rc));
320 return rc;
321 }
322
323 /**
324 * @copydoc VBOXHGCMSVCFNTABLE::pfnCall
325 * Wraps to the call member function
326 */
327 static DECLCALLBACK(void) svcCall(void * pvService,
328 VBOXHGCMCALLHANDLE callHandle,
329 uint32_t u32ClientID,
330 void *pvClient,
331 uint32_t u32Function,
332 uint32_t cParms,
333 VBOXHGCMSVCPARM paParms[],
334 uint64_t tsArrival)
335 {
336 AssertLogRelReturnVoid(VALID_PTR(pvService));
337 LogFlowFunc(("pvService=%p, callHandle=%p, u32ClientID=%u, pvClient=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, callHandle, u32ClientID, pvClient, u32Function, cParms, paParms));
338 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
339 pSelf->guestCall(callHandle, u32ClientID, pvClient, u32Function, cParms, paParms);
340 LogFlowFunc(("returning\n"));
341 RT_NOREF_PV(tsArrival);
342 }
343
344 /**
345 * @copydoc VBOXHGCMSVCFNTABLE::pfnHostCall
346 * Wraps to the hostCall member function
347 */
348 static DECLCALLBACK(int) svcHostCall(void *pvService,
349 uint32_t u32Function,
350 uint32_t cParms,
351 VBOXHGCMSVCPARM paParms[])
352 {
353 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
354 LogFlowFunc(("pvService=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, u32Function, cParms, paParms));
355 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
356 int rc = pSelf->hostCall(u32Function, cParms, paParms);
357 LogFlowFunc(("rc=%Rrc\n", rc));
358 return rc;
359 }
360
361 /**
362 * @copydoc VBOXHGCMSVCFNTABLE::pfnRegisterExtension
363 * Installs a host callback for notifications of property changes.
364 */
365 static DECLCALLBACK(int) svcRegisterExtension(void *pvService,
366 PFNHGCMSVCEXT pfnExtension,
367 void *pvExtension)
368 {
369 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
370 LogFlowFunc(("pvService=%p, pfnExtension=%p, pvExtention=%p\n", pvService, pfnExtension, pvExtension));
371 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
372 pSelf->m_SvcCtx.pfnHostCallback = pfnExtension;
373 pSelf->m_SvcCtx.pvHostData = pvExtension;
374 return VINF_SUCCESS;
375 }
376
377 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AbstractService);
378};
379
380}
381#endif /* !VBOX_INCLUDED_HostServices_Service_h */
382
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