VirtualBox

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

Last change on this file since 52664 was 50561, checked in by vboxsync, 11 years ago

DnD: Update, bugfixes.

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