VirtualBox

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

Last change on this file since 55410 was 55353, checked in by vboxsync, 10 years ago

include/VBox/HostServices/Service.h: adjusted Message implementation to not allow callers to reallocate HGCM pointers.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.5 KB
Line 
1/** @file
2 * Base class for an host-guest service.
3 */
4
5/*
6 * Copyright (C) 2011-2012 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
27#ifndef ___VBox_HostService_Service_h
28#define ___VBox_HostService_Service_h
29
30#include <VBox/log.h>
31#include <VBox/hgcmsvc.h>
32#include <iprt/assert.h>
33#include <iprt/alloc.h>
34#include <iprt/cpp/utils.h>
35
36#include <memory> /* for auto_ptr */
37
38namespace HGCM
39{
40
41class Message
42{
43 /* Contains a copy of HGCM parameters. */
44public:
45 Message(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM aParms[])
46 : m_uMsg(0)
47 , m_cParms(0)
48 , m_paParms(0)
49 {
50 initData(uMsg, cParms, aParms);
51 }
52 ~Message()
53 {
54 cleanup();
55 }
56
57 uint32_t message() const { return m_uMsg; }
58 uint32_t paramsCount() const { return m_cParms; }
59
60 int getData(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM aParms[]) const
61 {
62 if (m_uMsg != uMsg)
63 {
64 LogFlowFunc(("Message type does not match (%u (buffer), %u (guest))\n",
65 m_uMsg, uMsg));
66 return VERR_INVALID_PARAMETER;
67 }
68 if (m_cParms != cParms)
69 {
70 LogFlowFunc(("Parameter count does not match (%u (buffer), %u (guest))\n",
71 m_cParms, cParms));
72 return VERR_INVALID_PARAMETER;
73 }
74
75 int rc = copyParmsInternal(cParms, m_paParms, &aParms[0], false /* fCreatePtrs */);
76
77// if (RT_FAILURE(rc))
78// cleanup(aParms);
79 return rc;
80 }
81
82 int getParmU32Info(uint32_t iParm, uint32_t *pu32Info) const
83 {
84 AssertPtrNullReturn(pu32Info, VERR_INVALID_PARAMETER);
85 AssertReturn(iParm < m_cParms, VERR_INVALID_PARAMETER);
86 AssertReturn(m_paParms[iParm].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_INVALID_PARAMETER);
87
88 *pu32Info = m_paParms[iParm].u.uint32;
89
90 return VINF_SUCCESS;
91 }
92 int getParmU64Info(uint32_t iParm, uint64_t *pu64Info) const
93 {
94 AssertPtrNullReturn(pu64Info, VERR_INVALID_PARAMETER);
95 AssertReturn(iParm < m_cParms, VERR_INVALID_PARAMETER);
96 AssertReturn(m_paParms[iParm].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_INVALID_PARAMETER);
97
98 *pu64Info = m_paParms[iParm].u.uint64;
99
100 return VINF_SUCCESS;
101 }
102 int getParmPtrInfo(uint32_t iParm, void **ppvAddr, uint32_t *pcSize) const
103 {
104 AssertPtrNullReturn(ppvAddr, VERR_INVALID_PARAMETER);
105 AssertPtrNullReturn(pcSize, VERR_INVALID_PARAMETER);
106 AssertReturn(iParm < m_cParms, VERR_INVALID_PARAMETER);
107 AssertReturn(m_paParms[iParm].type == VBOX_HGCM_SVC_PARM_PTR, VERR_INVALID_PARAMETER);
108
109 *ppvAddr = m_paParms[iParm].u.pointer.addr;
110 *pcSize = m_paParms[iParm].u.pointer.size;
111
112 return VINF_SUCCESS;
113 }
114
115 int copyParms(uint32_t cParms, PVBOXHGCMSVCPARM paParmsSrc, PVBOXHGCMSVCPARM paParmsDst) const
116 {
117 return copyParmsInternal(cParms, paParmsSrc, paParmsDst, false /* fCreatePtrs */);
118 }
119
120private:
121 uint32_t m_uMsg;
122 uint32_t m_cParms;
123 PVBOXHGCMSVCPARM m_paParms;
124
125 int initData(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM aParms[])
126 {
127 AssertReturn(cParms < 256, VERR_INVALID_PARAMETER);
128 AssertPtrNullReturn(aParms, VERR_INVALID_PARAMETER);
129
130 /* Cleanup old messages. */
131 cleanup();
132
133 m_uMsg = uMsg;
134 m_cParms = cParms;
135
136 if (cParms > 0)
137 {
138 m_paParms = (VBOXHGCMSVCPARM*)RTMemAllocZ(sizeof(VBOXHGCMSVCPARM) * m_cParms);
139 if (!m_paParms)
140 return VERR_NO_MEMORY;
141 }
142
143 int rc = copyParmsInternal(cParms, &aParms[0], m_paParms, true /* fCreatePtrs */);
144
145 if (RT_FAILURE(rc))
146 cleanup();
147
148 return rc;
149 }
150
151 int copyParmsInternal(uint32_t cParms, PVBOXHGCMSVCPARM paParmsSrc, PVBOXHGCMSVCPARM paParmsDst, bool fCreatePtrs) const
152 {
153 int rc = VINF_SUCCESS;
154 for (uint32_t i = 0; i < cParms; ++i)
155 {
156 paParmsDst[i].type = paParmsSrc[i].type;
157 switch (paParmsSrc[i].type)
158 {
159 case VBOX_HGCM_SVC_PARM_32BIT:
160 {
161 paParmsDst[i].u.uint32 = paParmsSrc[i].u.uint32;
162 break;
163 }
164 case VBOX_HGCM_SVC_PARM_64BIT:
165 {
166 paParmsDst[i].u.uint64 = paParmsSrc[i].u.uint64;
167 break;
168 }
169 case VBOX_HGCM_SVC_PARM_PTR:
170 {
171 /* Do we have to recreate the memory? */
172 if (fCreatePtrs)
173 {
174 /* Yes, do so. */
175 paParmsDst[i].u.pointer.size = paParmsSrc[i].u.pointer.size;
176 if (paParmsDst[i].u.pointer.size > 0)
177 {
178 paParmsDst[i].u.pointer.addr = RTMemAlloc(paParmsDst[i].u.pointer.size);
179 if (!paParmsDst[i].u.pointer.addr)
180 {
181 rc = VERR_NO_MEMORY;
182 break;
183 }
184 }
185 }
186 else
187 {
188 /* No, but we have to check if there is enough room. */
189 if (paParmsDst[i].u.pointer.size < paParmsSrc[i].u.pointer.size)
190 rc = VERR_BUFFER_OVERFLOW;
191 }
192 if ( paParmsDst[i].u.pointer.addr
193 && paParmsSrc[i].u.pointer.size > 0
194 && paParmsDst[i].u.pointer.size > 0)
195 memcpy(paParmsDst[i].u.pointer.addr,
196 paParmsSrc[i].u.pointer.addr,
197 RT_MIN(paParmsDst[i].u.pointer.size, paParmsSrc[i].u.pointer.size));
198 break;
199 }
200 default:
201 {
202 AssertMsgFailed(("Unknown HGCM type %u\n", paParmsSrc[i].type));
203 rc = VERR_INVALID_PARAMETER;
204 break;
205 }
206 }
207 if (RT_FAILURE(rc))
208 break;
209 }
210 return rc;
211 }
212
213 void cleanup()
214 {
215 if (m_paParms)
216 {
217 for (uint32_t i = 0; i < m_cParms; ++i)
218 {
219 switch (m_paParms[i].type)
220 {
221 case VBOX_HGCM_SVC_PARM_PTR:
222 if (m_paParms[i].u.pointer.size)
223 RTMemFree(m_paParms[i].u.pointer.addr);
224 break;
225 }
226 }
227 RTMemFree(m_paParms);
228 m_paParms = 0;
229 }
230 m_cParms = 0;
231 m_uMsg = 0;
232 }
233};
234
235class Client
236{
237public:
238 Client(uint32_t uClientId, VBOXHGCMCALLHANDLE hHandle, uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM aParms[])
239 : m_uClientId(uClientId)
240 , m_hHandle(hHandle)
241 , m_uMsg(uMsg)
242 , m_cParms(cParms)
243 , m_paParms(aParms) {}
244
245 VBOXHGCMCALLHANDLE handle() const { return m_hHandle; }
246 uint32_t message() const { return m_uMsg; }
247 uint32_t clientId() const { return m_uClientId; }
248
249 int addMessageInfo(uint32_t uMsg, uint32_t cParms)
250 {
251 if (m_cParms != 3)
252 return VERR_INVALID_PARAMETER;
253
254 m_paParms[0].setUInt32(uMsg);
255 m_paParms[1].setUInt32(cParms);
256
257 return VINF_SUCCESS;
258 }
259 int addMessageInfo(const Message *pMessage)
260 {
261 if (m_cParms != 3)
262 return VERR_INVALID_PARAMETER;
263
264 m_paParms[0].setUInt32(pMessage->message());
265 m_paParms[1].setUInt32(pMessage->paramsCount());
266
267 return VINF_SUCCESS;
268 }
269 int addMessage(const Message *pMessage)
270 {
271 return pMessage->getData(m_uMsg, m_cParms, m_paParms);
272 }
273private:
274 uint32_t m_uClientId;
275 VBOXHGCMCALLHANDLE m_hHandle;
276 uint32_t m_uMsg;
277 uint32_t m_cParms;
278 PVBOXHGCMSVCPARM m_paParms;
279};
280
281template <class T>
282class AbstractService: public RTCNonCopyable
283{
284public:
285 /**
286 * @copydoc VBOXHGCMSVCLOAD
287 */
288 static DECLCALLBACK(int) svcLoad(VBOXHGCMSVCFNTABLE *pTable)
289 {
290 LogFlowFunc(("ptable = %p\n", pTable));
291 int rc = VINF_SUCCESS;
292
293 if (!VALID_PTR(pTable))
294 rc = VERR_INVALID_PARAMETER;
295 else
296 {
297 LogFlowFunc(("ptable->cbSize = %d, ptable->u32Version = 0x%08X\n", pTable->cbSize, pTable->u32Version));
298
299 if ( pTable->cbSize != sizeof (VBOXHGCMSVCFNTABLE)
300 || pTable->u32Version != VBOX_HGCM_SVC_VERSION)
301 rc = VERR_VERSION_MISMATCH;
302 else
303 {
304 std::auto_ptr<AbstractService> apService;
305 /* No exceptions may propagate outside. */
306 try
307 {
308 apService = std::auto_ptr<AbstractService>(new T(pTable->pHelpers));
309 } catch (int rcThrown)
310 {
311 rc = rcThrown;
312 } catch (...)
313 {
314 rc = VERR_UNRESOLVED_ERROR;
315 }
316
317 if (RT_SUCCESS(rc))
318 {
319 /*
320 * We don't need an additional client data area on the host,
321 * because we're a class which can have members for that :-).
322 */
323 pTable->cbClient = 0;
324
325 /* These functions are mandatory */
326 pTable->pfnUnload = svcUnload;
327 pTable->pfnConnect = svcConnect;
328 pTable->pfnDisconnect = svcDisconnect;
329 pTable->pfnCall = svcCall;
330 /* Clear obligatory functions. */
331 pTable->pfnHostCall = NULL;
332 pTable->pfnSaveState = NULL;
333 pTable->pfnLoadState = NULL;
334 pTable->pfnRegisterExtension = NULL;
335
336 /* Let the service itself initialize. */
337 rc = apService->init(pTable);
338
339 /* Only on success stop the auto release of the auto_ptr. */
340 if (RT_SUCCESS(rc))
341 pTable->pvService = apService.release();
342 }
343 }
344 }
345
346 LogFlowFunc(("returning %Rrc\n", rc));
347 return rc;
348 }
349 virtual ~AbstractService() {};
350
351protected:
352 explicit AbstractService(PVBOXHGCMSVCHELPERS pHelpers)
353 : m_pHelpers(pHelpers)
354 , m_pfnHostCallback(NULL)
355 , m_pvHostData(NULL)
356 {}
357 virtual int init(VBOXHGCMSVCFNTABLE *ptable) { return VINF_SUCCESS; }
358 virtual int uninit() { return VINF_SUCCESS; }
359 virtual int clientConnect(uint32_t u32ClientID, void *pvClient) = 0;
360 virtual int clientDisconnect(uint32_t u32ClientID, void *pvClient) = 0;
361 virtual void guestCall(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, void *pvClient, uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) = 0;
362 virtual int hostCall(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) { return VINF_SUCCESS; }
363
364 /** Type definition for use in callback functions. */
365 typedef AbstractService SELF;
366 /** HGCM helper functions. */
367 PVBOXHGCMSVCHELPERS m_pHelpers;
368 /*
369 * Callback function supplied by the host for notification of updates
370 * to properties.
371 */
372 PFNHGCMSVCEXT m_pfnHostCallback;
373 /** User data pointer to be supplied to the host callback function. */
374 void *m_pvHostData;
375
376 /**
377 * @copydoc VBOXHGCMSVCHELPERS::pfnUnload
378 * Simply deletes the service object
379 */
380 static DECLCALLBACK(int) svcUnload(void *pvService)
381 {
382 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
383 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
384 int rc = pSelf->uninit();
385 AssertRC(rc);
386 if (RT_SUCCESS(rc))
387 delete pSelf;
388 return rc;
389 }
390
391 /**
392 * @copydoc VBOXHGCMSVCHELPERS::pfnConnect
393 * Stub implementation of pfnConnect and pfnDisconnect.
394 */
395 static DECLCALLBACK(int) svcConnect(void *pvService,
396 uint32_t u32ClientID,
397 void *pvClient)
398 {
399 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
400 LogFlowFunc(("pvService=%p, u32ClientID=%u, pvClient=%p\n", pvService, u32ClientID, pvClient));
401 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
402 int rc = pSelf->clientConnect(u32ClientID, pvClient);
403 LogFlowFunc(("rc=%Rrc\n", rc));
404 return rc;
405 }
406
407 /**
408 * @copydoc VBOXHGCMSVCHELPERS::pfnConnect
409 * Stub implementation of pfnConnect and pfnDisconnect.
410 */
411 static DECLCALLBACK(int) svcDisconnect(void *pvService,
412 uint32_t u32ClientID,
413 void *pvClient)
414 {
415 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
416 LogFlowFunc(("pvService=%p, u32ClientID=%u, pvClient=%p\n", pvService, u32ClientID, pvClient));
417 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
418 int rc = pSelf->clientDisconnect(u32ClientID, pvClient);
419 LogFlowFunc(("rc=%Rrc\n", rc));
420 return rc;
421 }
422
423 /**
424 * @copydoc VBOXHGCMSVCHELPERS::pfnCall
425 * Wraps to the call member function
426 */
427 static DECLCALLBACK(void) svcCall(void * pvService,
428 VBOXHGCMCALLHANDLE callHandle,
429 uint32_t u32ClientID,
430 void *pvClient,
431 uint32_t u32Function,
432 uint32_t cParms,
433 VBOXHGCMSVCPARM paParms[])
434 {
435 AssertLogRelReturnVoid(VALID_PTR(pvService));
436 LogFlowFunc(("pvService=%p, callHandle=%p, u32ClientID=%u, pvClient=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, callHandle, u32ClientID, pvClient, u32Function, cParms, paParms));
437 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
438 pSelf->guestCall(callHandle, u32ClientID, pvClient, u32Function, cParms, paParms);
439 LogFlowFunc(("returning\n"));
440 }
441
442 /**
443 * @copydoc VBOXHGCMSVCHELPERS::pfnHostCall
444 * Wraps to the hostCall member function
445 */
446 static DECLCALLBACK(int) svcHostCall(void *pvService,
447 uint32_t u32Function,
448 uint32_t cParms,
449 VBOXHGCMSVCPARM paParms[])
450 {
451 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
452 LogFlowFunc(("pvService=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, u32Function, cParms, paParms));
453 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
454 int rc = pSelf->hostCall(u32Function, cParms, paParms);
455 LogFlowFunc(("rc=%Rrc\n", rc));
456 return rc;
457 }
458
459 /**
460 * @copydoc VBOXHGCMSVCHELPERS::pfnRegisterExtension
461 * Installs a host callback for notifications of property changes.
462 */
463 static DECLCALLBACK(int) svcRegisterExtension(void *pvService,
464 PFNHGCMSVCEXT pfnExtension,
465 void *pvExtension)
466 {
467 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
468 LogFlowFunc(("pvService=%p, pfnExtension=%p, pvExtention=%p\n", pvService, pfnExtension, pvExtension));
469 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
470 pSelf->m_pfnHostCallback = pfnExtension;
471 pSelf->m_pvHostData = pvExtension;
472 return VINF_SUCCESS;
473 }
474};
475
476}
477
478#endif /* !___VBox_HostService_Service_h */
479
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