VirtualBox

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

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

DnD: Protocol overhaul with versioning added which now can communicate with Main.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.1 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 ( paParmsDst[i].u.pointer.addr
201 && paParmsSrc[i].u.pointer.size > 0
202 && paParmsDst[i].u.pointer.size > 0)
203 {
204 memcpy(paParmsDst[i].u.pointer.addr,
205 paParmsSrc[i].u.pointer.addr,
206 RT_MIN(paParmsDst[i].u.pointer.size, paParmsSrc[i].u.pointer.size));
207 }
208 break;
209 }
210 default:
211 {
212 AssertMsgFailed(("Unknown HGCM type %u\n", paParmsSrc[i].type));
213 rc = VERR_INVALID_PARAMETER;
214 break;
215 }
216 }
217 if (RT_FAILURE(rc))
218 break;
219 }
220 return rc;
221 }
222
223 void cleanup()
224 {
225 if (m_paParms)
226 {
227 for (uint32_t i = 0; i < m_cParms; ++i)
228 {
229 switch (m_paParms[i].type)
230 {
231 case VBOX_HGCM_SVC_PARM_PTR:
232 if (m_paParms[i].u.pointer.size)
233 RTMemFree(m_paParms[i].u.pointer.addr);
234 break;
235 }
236 }
237 RTMemFree(m_paParms);
238 m_paParms = 0;
239 }
240 m_cParms = 0;
241 m_uMsg = 0;
242 }
243};
244
245class Client
246{
247public:
248 Client(uint32_t uClientId, VBOXHGCMCALLHANDLE hHandle = NULL,
249 uint32_t uMsg = 0, uint32_t cParms = 0, VBOXHGCMSVCPARM aParms[] = NULL)
250 : m_uClientId(uClientId)
251 , m_uProtocol(0)
252 , m_hHandle(hHandle)
253 , m_uMsg(uMsg)
254 , m_cParms(cParms)
255 , m_paParms(aParms) {}
256
257public:
258
259 VBOXHGCMCALLHANDLE handle(void) const { return m_hHandle; }
260 uint32_t message(void) const { return m_uMsg; }
261 uint32_t clientId(void) const { return m_uClientId; }
262 uint32_t protocol(void) const { return m_uProtocol; }
263
264public:
265
266 int setProtocol(uint32_t uProtocol) { m_uProtocol = uProtocol; return VINF_SUCCESS; }
267
268public:
269
270 int addMessageInfo(uint32_t uMsg, uint32_t cParms)
271 {
272 if (m_cParms != 3)
273 return VERR_INVALID_PARAMETER;
274
275 m_paParms[0].setUInt32(uMsg);
276 m_paParms[1].setUInt32(cParms);
277
278 return VINF_SUCCESS;
279 }
280 int addMessageInfo(const Message *pMessage)
281 {
282 AssertPtrReturn(pMessage, VERR_INVALID_POINTER);
283 if (m_cParms != 3)
284 return VERR_INVALID_PARAMETER;
285
286 m_paParms[0].setUInt32(pMessage->message());
287 m_paParms[1].setUInt32(pMessage->paramsCount());
288
289 return VINF_SUCCESS;
290 }
291 int addMessage(const Message *pMessage)
292 {
293 AssertPtrReturn(pMessage, VERR_INVALID_POINTER);
294 return pMessage->getData(m_uMsg, m_cParms, m_paParms);
295 }
296
297private:
298
299 uint32_t m_uClientId;
300 /** Optional protocol version the client uses. */
301 uint32_t m_uProtocol;
302 VBOXHGCMCALLHANDLE m_hHandle;
303 uint32_t m_uMsg;
304 uint32_t m_cParms;
305 PVBOXHGCMSVCPARM m_paParms;
306};
307
308template <class T>
309class AbstractService: public RTCNonCopyable
310{
311public:
312 /**
313 * @copydoc VBOXHGCMSVCLOAD
314 */
315 static DECLCALLBACK(int) svcLoad(VBOXHGCMSVCFNTABLE *pTable)
316 {
317 LogFlowFunc(("ptable = %p\n", pTable));
318 int rc = VINF_SUCCESS;
319
320 if (!VALID_PTR(pTable))
321 rc = VERR_INVALID_PARAMETER;
322 else
323 {
324 LogFlowFunc(("ptable->cbSize = %d, ptable->u32Version = 0x%08X\n", pTable->cbSize, pTable->u32Version));
325
326 if ( pTable->cbSize != sizeof (VBOXHGCMSVCFNTABLE)
327 || pTable->u32Version != VBOX_HGCM_SVC_VERSION)
328 rc = VERR_VERSION_MISMATCH;
329 else
330 {
331 std::auto_ptr<AbstractService> apService;
332 /* No exceptions may propagate outside. */
333 try
334 {
335 apService = std::auto_ptr<AbstractService>(new T(pTable->pHelpers));
336 } catch (int rcThrown)
337 {
338 rc = rcThrown;
339 } catch (...)
340 {
341 rc = VERR_UNRESOLVED_ERROR;
342 }
343
344 if (RT_SUCCESS(rc))
345 {
346 /*
347 * We don't need an additional client data area on the host,
348 * because we're a class which can have members for that :-).
349 */
350 pTable->cbClient = 0;
351
352 /* These functions are mandatory */
353 pTable->pfnUnload = svcUnload;
354 pTable->pfnConnect = svcConnect;
355 pTable->pfnDisconnect = svcDisconnect;
356 pTable->pfnCall = svcCall;
357 /* Clear obligatory functions. */
358 pTable->pfnHostCall = NULL;
359 pTable->pfnSaveState = NULL;
360 pTable->pfnLoadState = NULL;
361 pTable->pfnRegisterExtension = NULL;
362
363 /* Let the service itself initialize. */
364 rc = apService->init(pTable);
365
366 /* Only on success stop the auto release of the auto_ptr. */
367 if (RT_SUCCESS(rc))
368 pTable->pvService = apService.release();
369 }
370 }
371 }
372
373 LogFlowFunc(("returning %Rrc\n", rc));
374 return rc;
375 }
376 virtual ~AbstractService() {};
377
378protected:
379 explicit AbstractService(PVBOXHGCMSVCHELPERS pHelpers)
380 : m_pHelpers(pHelpers)
381 , m_pfnHostCallback(NULL)
382 , m_pvHostData(NULL)
383 {}
384 virtual int init(VBOXHGCMSVCFNTABLE *ptable) { return VINF_SUCCESS; }
385 virtual int uninit() { return VINF_SUCCESS; }
386 virtual int clientConnect(uint32_t u32ClientID, void *pvClient) = 0;
387 virtual int clientDisconnect(uint32_t u32ClientID, void *pvClient) = 0;
388 virtual void guestCall(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, void *pvClient, uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) = 0;
389 virtual int hostCall(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) { return VINF_SUCCESS; }
390
391 /** Type definition for use in callback functions. */
392 typedef AbstractService SELF;
393 /** HGCM helper functions. */
394 PVBOXHGCMSVCHELPERS m_pHelpers;
395 /*
396 * Callback function supplied by the host for notification of updates
397 * to properties.
398 */
399 PFNHGCMSVCEXT m_pfnHostCallback;
400 /** User data pointer to be supplied to the host callback function. */
401 void *m_pvHostData;
402
403 /**
404 * @copydoc VBOXHGCMSVCHELPERS::pfnUnload
405 * Simply deletes the service object
406 */
407 static DECLCALLBACK(int) svcUnload(void *pvService)
408 {
409 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
410 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
411 int rc = pSelf->uninit();
412 AssertRC(rc);
413 if (RT_SUCCESS(rc))
414 delete pSelf;
415 return rc;
416 }
417
418 /**
419 * @copydoc VBOXHGCMSVCHELPERS::pfnConnect
420 * Stub implementation of pfnConnect and pfnDisconnect.
421 */
422 static DECLCALLBACK(int) svcConnect(void *pvService,
423 uint32_t u32ClientID,
424 void *pvClient)
425 {
426 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
427 LogFlowFunc(("pvService=%p, u32ClientID=%u, pvClient=%p\n", pvService, u32ClientID, pvClient));
428 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
429 int rc = pSelf->clientConnect(u32ClientID, pvClient);
430 LogFlowFunc(("rc=%Rrc\n", rc));
431 return rc;
432 }
433
434 /**
435 * @copydoc VBOXHGCMSVCHELPERS::pfnConnect
436 * Stub implementation of pfnConnect and pfnDisconnect.
437 */
438 static DECLCALLBACK(int) svcDisconnect(void *pvService,
439 uint32_t u32ClientID,
440 void *pvClient)
441 {
442 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
443 LogFlowFunc(("pvService=%p, u32ClientID=%u, pvClient=%p\n", pvService, u32ClientID, pvClient));
444 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
445 int rc = pSelf->clientDisconnect(u32ClientID, pvClient);
446 LogFlowFunc(("rc=%Rrc\n", rc));
447 return rc;
448 }
449
450 /**
451 * @copydoc VBOXHGCMSVCHELPERS::pfnCall
452 * Wraps to the call member function
453 */
454 static DECLCALLBACK(void) svcCall(void * pvService,
455 VBOXHGCMCALLHANDLE callHandle,
456 uint32_t u32ClientID,
457 void *pvClient,
458 uint32_t u32Function,
459 uint32_t cParms,
460 VBOXHGCMSVCPARM paParms[])
461 {
462 AssertLogRelReturnVoid(VALID_PTR(pvService));
463 LogFlowFunc(("pvService=%p, callHandle=%p, u32ClientID=%u, pvClient=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, callHandle, u32ClientID, pvClient, u32Function, cParms, paParms));
464 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
465 pSelf->guestCall(callHandle, u32ClientID, pvClient, u32Function, cParms, paParms);
466 LogFlowFunc(("returning\n"));
467 }
468
469 /**
470 * @copydoc VBOXHGCMSVCHELPERS::pfnHostCall
471 * Wraps to the hostCall member function
472 */
473 static DECLCALLBACK(int) svcHostCall(void *pvService,
474 uint32_t u32Function,
475 uint32_t cParms,
476 VBOXHGCMSVCPARM paParms[])
477 {
478 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
479 LogFlowFunc(("pvService=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, u32Function, cParms, paParms));
480 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
481 int rc = pSelf->hostCall(u32Function, cParms, paParms);
482 LogFlowFunc(("rc=%Rrc\n", rc));
483 return rc;
484 }
485
486 /**
487 * @copydoc VBOXHGCMSVCHELPERS::pfnRegisterExtension
488 * Installs a host callback for notifications of property changes.
489 */
490 static DECLCALLBACK(int) svcRegisterExtension(void *pvService,
491 PFNHGCMSVCEXT pfnExtension,
492 void *pvExtension)
493 {
494 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
495 LogFlowFunc(("pvService=%p, pfnExtension=%p, pvExtention=%p\n", pvService, pfnExtension, pvExtension));
496 SELF *pSelf = reinterpret_cast<SELF *>(pvService);
497 pSelf->m_pfnHostCallback = pfnExtension;
498 pSelf->m_pvHostData = pvExtension;
499 return VINF_SUCCESS;
500 }
501};
502
503}
504
505#endif /* !___VBox_HostService_Service_h */
506
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