VirtualBox

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

Last change on this file since 73939 was 73939, checked in by vboxsync, 6 years ago

DnD/HostService: Renaming, docs.

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