VirtualBox

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

Last change on this file since 56323 was 56323, checked in by vboxsync, 9 years ago

whitespace

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