VirtualBox

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

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

HostServices/Service.h: Added another error check for copyParmsInternal().

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette