VirtualBox

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

Last change on this file since 73768 was 69107, checked in by vboxsync, 7 years ago

include/VBox/: (C) year

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

© 2023 Oracle
ContactPrivacy policyTerms of Use