VirtualBox

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

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

DnD: Updates/bugfixes:

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