]>
Commit | Line | Data |
---|---|---|
056a1eb7 SF |
1 | /** @file |
2 | * Host-Guest Communication Manager (HGCM) - Service library definitions. | |
3 | */ | |
4 | ||
5 | /* | |
6d209b23 | 6 | * Copyright (C) 2006-2017 Oracle Corporation |
056a1eb7 SF |
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 | #ifndef ___VBox_hgcm_h | |
27 | #define ___VBox_hgcm_h | |
28 | ||
29 | #include <iprt/assert.h> | |
30 | #include <iprt/string.h> | |
31 | #include <VBox/cdefs.h> | |
32 | #include <VBox/types.h> | |
33 | #include <VBox/err.h> | |
34 | #ifdef VBOX_TEST_HGCM_PARMS | |
35 | # include <iprt/test.h> | |
36 | #endif | |
37 | ||
38 | /** @todo proper comments. */ | |
39 | ||
40 | /** | |
41 | * Service interface version. | |
42 | * | |
43 | * Includes layout of both VBOXHGCMSVCFNTABLE and VBOXHGCMSVCHELPERS. | |
44 | * | |
45 | * A service can work with these structures if major version | |
46 | * is equal and minor version of service is <= version of the | |
47 | * structures. | |
48 | * | |
49 | * For example when a new helper is added at the end of helpers | |
50 | * structure, then the minor version will be increased. All older | |
51 | * services still can work because they have their old helpers | |
52 | * unchanged. | |
53 | * | |
54 | * Revision history. | |
55 | * 1.1->2.1 Because the pfnConnect now also has the pvClient parameter. | |
56 | * 2.1->2.2 Because pfnSaveState and pfnLoadState were added | |
57 | * 2.2->3.1 Because pfnHostCall is now synchronous, returns rc, and parameters were changed | |
58 | * 3.1->3.2 Because pfnRegisterExtension was added | |
59 | * 3.2->3.3 Because pfnDisconnectClient helper was added | |
60 | * 3.3->4.1 Because the pvService entry and parameter was added | |
61 | * 4.1->4.2 Because the VBOX_HGCM_SVC_PARM_CALLBACK parameter type was added | |
62 | * 4.2->5.1 Removed the VBOX_HGCM_SVC_PARM_CALLBACK parameter type, as | |
63 | * this problem is already solved by service extension callbacks | |
64 | */ | |
65 | #define VBOX_HGCM_SVC_VERSION_MAJOR (0x0005) | |
66 | #define VBOX_HGCM_SVC_VERSION_MINOR (0x0001) | |
67 | #define VBOX_HGCM_SVC_VERSION ((VBOX_HGCM_SVC_VERSION_MAJOR << 16) + VBOX_HGCM_SVC_VERSION_MINOR) | |
68 | ||
69 | ||
70 | /** Typed pointer to distinguish a call to service. */ | |
71 | struct VBOXHGCMCALLHANDLE_TYPEDEF; | |
72 | typedef struct VBOXHGCMCALLHANDLE_TYPEDEF *VBOXHGCMCALLHANDLE; | |
73 | ||
74 | /** Service helpers pointers table. */ | |
75 | typedef struct VBOXHGCMSVCHELPERS | |
76 | { | |
77 | /** The service has processed the Call request. */ | |
78 | DECLR3CALLBACKMEMBER(void, pfnCallComplete, (VBOXHGCMCALLHANDLE callHandle, int32_t rc)); | |
79 | ||
80 | void *pvInstance; | |
81 | ||
82 | /** The service disconnects the client. */ | |
83 | DECLR3CALLBACKMEMBER(void, pfnDisconnectClient, (void *pvInstance, uint32_t u32ClientID)); | |
84 | } VBOXHGCMSVCHELPERS; | |
85 | ||
86 | typedef VBOXHGCMSVCHELPERS *PVBOXHGCMSVCHELPERS; | |
87 | ||
88 | ||
89 | #define VBOX_HGCM_SVC_PARM_INVALID (0U) | |
90 | #define VBOX_HGCM_SVC_PARM_32BIT (1U) | |
91 | #define VBOX_HGCM_SVC_PARM_64BIT (2U) | |
92 | #define VBOX_HGCM_SVC_PARM_PTR (3U) | |
93 | ||
94 | typedef struct VBOXHGCMSVCPARM | |
95 | { | |
96 | /** VBOX_HGCM_SVC_PARM_* values. */ | |
97 | uint32_t type; | |
98 | ||
99 | union | |
100 | { | |
101 | uint32_t uint32; | |
102 | uint64_t uint64; | |
103 | struct | |
104 | { | |
105 | uint32_t size; | |
106 | void *addr; | |
107 | } pointer; | |
108 | } u; | |
109 | #ifdef __cplusplus | |
110 | /** Extract an uint32_t value from an HGCM parameter structure */ | |
111 | int getUInt32(uint32_t *u32) | |
112 | { | |
113 | AssertPtrReturn(u32, VERR_INVALID_POINTER); | |
114 | int rc = VINF_SUCCESS; | |
115 | if (type != VBOX_HGCM_SVC_PARM_32BIT) | |
116 | rc = VERR_INVALID_PARAMETER; | |
117 | if (RT_SUCCESS(rc)) | |
118 | *u32 = u.uint32; | |
119 | return rc; | |
120 | } | |
121 | ||
122 | /** Extract a uint64_t value from an HGCM parameter structure */ | |
123 | int getUInt64(uint64_t *u64) | |
124 | { | |
125 | AssertPtrReturn(u64, VERR_INVALID_POINTER); | |
126 | int rc = VINF_SUCCESS; | |
127 | if (type != VBOX_HGCM_SVC_PARM_64BIT) | |
128 | rc = VERR_INVALID_PARAMETER; | |
129 | if (RT_SUCCESS(rc)) | |
130 | *u64 = u.uint64; | |
131 | return rc; | |
132 | } | |
133 | ||
134 | /** Extract a pointer value from an HGCM parameter structure */ | |
135 | int getPointer(void **ppv, uint32_t *pcb) | |
136 | { | |
137 | AssertPtrReturn(ppv, VERR_INVALID_POINTER); | |
138 | AssertPtrReturn(pcb, VERR_INVALID_POINTER); | |
139 | if (type == VBOX_HGCM_SVC_PARM_PTR) | |
140 | { | |
141 | *ppv = u.pointer.addr; | |
142 | *pcb = u.pointer.size; | |
143 | return VINF_SUCCESS; | |
144 | } | |
145 | ||
146 | return VERR_INVALID_PARAMETER; | |
147 | } | |
148 | ||
149 | /** Extract a constant pointer value from an HGCM parameter structure */ | |
150 | int getPointer(const void **ppcv, uint32_t *pcb) | |
151 | { | |
152 | AssertPtrReturn(ppcv, VERR_INVALID_POINTER); | |
153 | AssertPtrReturn(pcb, VERR_INVALID_POINTER); | |
154 | void *pv; | |
155 | int rc = getPointer(&pv, pcb); | |
156 | *ppcv = pv; | |
157 | return rc; | |
158 | } | |
159 | ||
160 | /** Extract a pointer value to a non-empty buffer from an HGCM parameter | |
161 | * structure */ | |
162 | int getBuffer(void **ppv, uint32_t *pcb) | |
163 | { | |
164 | AssertPtrReturn(ppv, VERR_INVALID_POINTER); | |
165 | AssertPtrReturn(pcb, VERR_INVALID_POINTER); | |
166 | void *pv = NULL; | |
167 | uint32_t cb = 0; | |
168 | int rc = getPointer(&pv, &cb); | |
169 | if ( RT_SUCCESS(rc) | |
170 | && VALID_PTR(pv) | |
171 | && cb > 0) | |
172 | { | |
173 | *ppv = pv; | |
174 | *pcb = cb; | |
175 | return VINF_SUCCESS; | |
176 | } | |
177 | ||
178 | return VERR_INVALID_PARAMETER; | |
179 | } | |
180 | ||
181 | /** Extract a pointer value to a non-empty constant buffer from an HGCM | |
182 | * parameter structure */ | |
183 | int getBuffer(const void **ppcv, uint32_t *pcb) | |
184 | { | |
185 | AssertPtrReturn(ppcv, VERR_INVALID_POINTER); | |
186 | AssertPtrReturn(pcb, VERR_INVALID_POINTER); | |
187 | void *pcv = NULL; | |
188 | int rc = getBuffer(&pcv, pcb); | |
189 | *ppcv = pcv; | |
190 | return rc; | |
191 | } | |
192 | ||
193 | /** Extract a string value from an HGCM parameter structure */ | |
194 | int getString(char **ppch, uint32_t *pcb) | |
195 | { | |
196 | uint32_t cb = 0; | |
197 | char *pch = NULL; | |
198 | int rc = getBuffer((void **)&pch, &cb); | |
199 | if (RT_FAILURE(rc)) | |
200 | { | |
201 | *ppch = NULL; | |
202 | *pcb = 0; | |
203 | return rc; | |
204 | } | |
205 | rc = RTStrValidateEncodingEx(pch, cb, | |
206 | RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED); | |
207 | *ppch = pch; | |
208 | *pcb = cb; | |
209 | return rc; | |
210 | } | |
211 | ||
212 | /** Extract a constant string value from an HGCM parameter structure */ | |
213 | int getString(const char **ppch, uint32_t *pcb) | |
214 | { | |
215 | char *pch = NULL; | |
216 | int rc = getString(&pch, pcb); | |
217 | *ppch = pch; | |
218 | return rc; | |
219 | } | |
220 | ||
221 | /** Set a uint32_t value to an HGCM parameter structure */ | |
222 | void setUInt32(uint32_t u32) | |
223 | { | |
224 | type = VBOX_HGCM_SVC_PARM_32BIT; | |
225 | u.uint32 = u32; | |
226 | } | |
227 | ||
228 | /** Set a uint64_t value to an HGCM parameter structure */ | |
229 | void setUInt64(uint64_t u64) | |
230 | { | |
231 | type = VBOX_HGCM_SVC_PARM_64BIT; | |
232 | u.uint64 = u64; | |
233 | } | |
234 | ||
235 | /** Set a pointer value to an HGCM parameter structure */ | |
236 | void setPointer(void *pv, uint32_t cb) | |
237 | { | |
238 | type = VBOX_HGCM_SVC_PARM_PTR; | |
239 | u.pointer.addr = pv; | |
240 | u.pointer.size = cb; | |
241 | } | |
242 | ||
243 | /** Set a const string value to an HGCM parameter structure */ | |
244 | void setString(const char *psz) | |
245 | { | |
246 | type = VBOX_HGCM_SVC_PARM_PTR; | |
247 | u.pointer.addr = (void *)psz; | |
248 | u.pointer.size = (uint32_t)strlen(psz) + 1; | |
249 | } | |
250 | ||
251 | #ifdef ___iprt_cpp_ministring_h | |
252 | /** Set a const string value to an HGCM parameter structure */ | |
253 | void setCppString(const RTCString &rString) | |
254 | { | |
255 | type = VBOX_HGCM_SVC_PARM_PTR; | |
256 | u.pointer.addr = (void *)rString.c_str(); | |
257 | u.pointer.size = (uint32_t)rString.length() + 1; | |
258 | } | |
259 | #endif | |
260 | ||
261 | #ifdef VBOX_TEST_HGCM_PARMS | |
262 | /** Test the getString member function. Indirectly tests the getPointer | |
263 | * and getBuffer APIs. | |
264 | * @param hTest an running IPRT test | |
265 | * @param aType the type that the parameter should be set to before | |
266 | * calling getString | |
267 | * @param apcc the value that the parameter should be set to before | |
268 | * calling getString, and also the address (!) which we | |
269 | * expect getString to return. Stricter than needed of | |
270 | * course, but I was feeling lazy. | |
271 | * @param acb the size that the parameter should be set to before | |
272 | * calling getString, and also the size which we expect | |
273 | * getString to return. | |
274 | * @param rcExp the expected return value of the call to getString. | |
275 | */ | |
276 | void doTestGetString(RTTEST hTest, uint32_t aType, const char *apcc, | |
277 | uint32_t acb, int rcExp) | |
278 | { | |
279 | /* An RTTest API like this, which would print out an additional line | |
280 | * of context if a test failed, would be nice. This is because the | |
281 | * line number alone doesn't help much here, given that this is a | |
282 | * subroutine called many times. */ | |
283 | /* | |
284 | RTTestContextF(hTest, | |
285 | ("doTestGetString, aType=%u, apcc=%p, acp=%u, rcExp=%Rrc", | |
286 | aType, apcc, acp, rcExp)); | |
287 | */ | |
288 | setPointer((void *)apcc, acb); | |
289 | type = aType; /* in case we don't want VBOX_HGCM_SVC_PARM_PTR */ | |
290 | const char *pcc = NULL; | |
291 | uint32_t cb = 0; | |
292 | int rc = getString(&pcc, &cb); | |
293 | RTTEST_CHECK_RC(hTest, rc, rcExp); | |
294 | if (RT_SUCCESS(rcExp)) | |
295 | { | |
296 | RTTEST_CHECK_MSG_RETV(hTest, (pcc == apcc), | |
297 | (hTest, "expected %p, got %p", apcc, pcc)); | |
298 | RTTEST_CHECK_MSG_RETV(hTest, (cb == acb), | |
299 | (hTest, "expected %u, got %u", acb, cb)); | |
300 | } | |
301 | } | |
302 | ||
303 | /** Run some unit tests on the getString method and indirectly test | |
304 | * getPointer and getBuffer as well. */ | |
305 | void testGetString(RTTEST hTest) | |
306 | { | |
307 | RTTestSub(hTest, "HGCM string parameter handling"); | |
308 | doTestGetString(hTest, VBOX_HGCM_SVC_PARM_32BIT, "test", 3, | |
309 | VERR_INVALID_PARAMETER); | |
310 | doTestGetString(hTest, VBOX_HGCM_SVC_PARM_PTR, "test", 5, | |
311 | VINF_SUCCESS); | |
312 | doTestGetString(hTest, VBOX_HGCM_SVC_PARM_PTR, "test", 3, | |
313 | VERR_BUFFER_OVERFLOW); | |
314 | doTestGetString(hTest, VBOX_HGCM_SVC_PARM_PTR, "test\xf0", 6, | |
315 | VERR_INVALID_UTF8_ENCODING); | |
316 | doTestGetString(hTest, VBOX_HGCM_SVC_PARM_PTR, "test", 0, | |
317 | VERR_INVALID_PARAMETER); | |
318 | doTestGetString(hTest, VBOX_HGCM_SVC_PARM_PTR, (const char *)0x1, 5, | |
319 | VERR_INVALID_PARAMETER); | |
320 | RTTestSubDone(hTest); | |
321 | } | |
322 | #endif | |
323 | ||
324 | VBOXHGCMSVCPARM() : type(VBOX_HGCM_SVC_PARM_INVALID) {} | |
325 | #endif | |
326 | } VBOXHGCMSVCPARM; | |
327 | ||
328 | typedef VBOXHGCMSVCPARM *PVBOXHGCMSVCPARM; | |
329 | ||
330 | #ifdef VBOX_WITH_CRHGSMI | |
331 | typedef void * HGCMCVSHANDLE; | |
332 | ||
333 | typedef DECLCALLBACK(void) HGCMHOSTFASTCALLCB (int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext); | |
334 | typedef HGCMHOSTFASTCALLCB *PHGCMHOSTFASTCALLCB; | |
335 | #endif | |
336 | ||
337 | ||
338 | /** Service specific extension callback. | |
339 | * This callback is called by the service to perform service specific operation. | |
340 | * | |
341 | * @param pvExtension The extension pointer. | |
342 | * @param u32Function What the callback is supposed to do. | |
343 | * @param pvParm The function parameters. | |
344 | * @param cbParm The size of the function parameters. | |
345 | */ | |
346 | typedef DECLCALLBACK(int) FNHGCMSVCEXT(void *pvExtension, uint32_t u32Function, void *pvParm, uint32_t cbParms); | |
347 | typedef FNHGCMSVCEXT *PFNHGCMSVCEXT; | |
348 | ||
349 | /** The Service DLL entry points. | |
350 | * | |
351 | * HGCM will call the DLL "VBoxHGCMSvcLoad" | |
352 | * function and the DLL must fill in the VBOXHGCMSVCFNTABLE | |
353 | * with function pointers. | |
354 | */ | |
355 | ||
356 | /* The structure is used in separately compiled binaries so an explicit packing is required. */ | |
357 | #pragma pack(1) /** @todo r=bird: The pragma pack(1) is not at all required!! */ | |
358 | typedef struct VBOXHGCMSVCFNTABLE | |
359 | { | |
360 | /** @name Filled by HGCM | |
361 | * @{ */ | |
362 | ||
363 | /** Size of the structure. */ | |
364 | uint32_t cbSize; | |
365 | ||
366 | /** Version of the structure, including the helpers. */ | |
367 | uint32_t u32Version; | |
368 | ||
369 | PVBOXHGCMSVCHELPERS pHelpers; | |
370 | /** @} */ | |
371 | ||
372 | /** @name Filled in by the service. | |
373 | * @{ */ | |
374 | ||
375 | /** Size of client information the service want to have. */ | |
376 | uint32_t cbClient; | |
377 | #if ARCH_BITS == 64 | |
378 | /** Ensure that the following pointers are properly aligned on 64-bit system. */ | |
379 | uint32_t u32Alignment0; | |
380 | #endif | |
381 | ||
382 | /** Uninitialize service */ | |
383 | DECLR3CALLBACKMEMBER(int, pfnUnload, (void *pvService)); | |
384 | ||
385 | /** Inform the service about a client connection. */ | |
386 | DECLR3CALLBACKMEMBER(int, pfnConnect, (void *pvService, uint32_t u32ClientID, void *pvClient)); | |
387 | ||
388 | /** Inform the service that the client wants to disconnect. */ | |
389 | DECLR3CALLBACKMEMBER(int, pfnDisconnect, (void *pvService, uint32_t u32ClientID, void *pvClient)); | |
390 | ||
391 | /** Service entry point. | |
392 | * Return code is passed to pfnCallComplete callback. | |
393 | */ | |
394 | DECLR3CALLBACKMEMBER(void, pfnCall, (void *pvService, VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, void *pvClient, uint32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])); | |
395 | ||
396 | /** Host Service entry point meant for privileged features invisible to the guest. | |
397 | * Return code is passed to pfnCallComplete callback. | |
398 | */ | |
399 | DECLR3CALLBACKMEMBER(int, pfnHostCall, (void *pvService, uint32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])); | |
400 | ||
401 | /** Inform the service about a VM save operation. */ | |
402 | DECLR3CALLBACKMEMBER(int, pfnSaveState, (void *pvService, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM)); | |
403 | ||
404 | /** Inform the service about a VM load operation. */ | |
405 | DECLR3CALLBACKMEMBER(int, pfnLoadState, (void *pvService, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM)); | |
406 | ||
407 | /** Register a service extension callback. */ | |
408 | DECLR3CALLBACKMEMBER(int, pfnRegisterExtension, (void *pvService, PFNHGCMSVCEXT pfnExtension, void *pvExtension)); | |
409 | ||
410 | /** User/instance data pointer for the service. */ | |
411 | void *pvService; | |
412 | ||
413 | /** @} */ | |
414 | } VBOXHGCMSVCFNTABLE; | |
415 | #pragma pack() | |
416 | ||
417 | ||
418 | /** Service initialization entry point. */ | |
419 | typedef DECLCALLBACK(int) VBOXHGCMSVCLOAD(VBOXHGCMSVCFNTABLE *ptable); | |
420 | typedef VBOXHGCMSVCLOAD *PFNVBOXHGCMSVCLOAD; | |
421 | #define VBOX_HGCM_SVCLOAD_NAME "VBoxHGCMSvcLoad" | |
422 | ||
423 | #endif |