VirtualBox

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

Last change on this file since 74883 was 74205, checked in by vboxsync, 6 years ago

DnD/HostService: Refactored out more code to the common client and message classes, added documentation (also about deferred client states).

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