VirtualBox

source: vbox/trunk/include/VBox/GuestHost/HGCMMock.h@ 97039

Last change on this file since 97039 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.9 KB
Line 
1/* $Id: HGCMMock.h 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * HGCMMock.h: Mocking framework for testing HGCM-based host services +
4 * Vbgl code on the host side.
5 *
6 * Goal is to run host service + Vbgl code as unmodified as
7 * possible as part of testcases to gain test coverage which
8 * otherwise wouldn't possible for heavily user-centric features
9 * like Shared Clipboard or drag'n drop (DnD).
10 */
11
12/*
13 * Copyright (C) 2022 Oracle and/or its affiliates.
14 *
15 * This file is part of VirtualBox base platform packages, as
16 * available from https://www.virtualbox.org.
17 *
18 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation, in version 3 of the
21 * License.
22 *
23 * This program is distributed in the hope that it will be useful, but
24 * WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 * General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, see <https://www.gnu.org/licenses>.
30 *
31 * The contents of this file may alternatively be used under the terms
32 * of the Common Development and Distribution License Version 1.0
33 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
34 * in the VirtualBox distribution, in which case the provisions of the
35 * CDDL are applicable instead of those of the GPL.
36 *
37 * You may elect to license modified versions of this file under the
38 * terms and conditions of either the GPL or the CDDL or both.
39 *
40 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
41 */
42
43#ifndef VBOX_INCLUDED_GuestHost_HGCMMock_h
44#define VBOX_INCLUDED_GuestHost_HGCMMock_h
45#ifndef RT_WITHOUT_PRAGMA_ONCE
46# pragma once
47#endif
48
49#include <iprt/types.h>
50
51#include <iprt/asm.h>
52#include <iprt/assert.h>
53#include <iprt/list.h>
54#include <iprt/mem.h>
55#include <iprt/rand.h>
56#include <iprt/semaphore.h>
57#include <iprt/test.h>
58#include <iprt/time.h>
59#include <iprt/thread.h>
60#include <iprt/utf16.h>
61
62#include <VBox/err.h>
63#include <VBox/VBoxGuestLib.h>
64#include <VBox/hgcmsvc.h>
65
66
67/*********************************************************************************************************************************
68* Definitions. *
69*********************************************************************************************************************************/
70
71#if defined(IN_RING3) /* Only R3 parts implemented so far. */
72
73RT_C_DECLS_BEGIN
74
75DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *ptable);
76
77RT_C_DECLS_END
78
79# define VBGLR3DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL
80
81/** Simple call handle structure for the guest call completion callback. */
82typedef struct VBOXHGCMCALLHANDLE_TYPEDEF
83{
84 /** Where to store the result code on call completion. */
85 int32_t rc;
86} VBOXHGCMCALLHANDLE_TYPEDEF;
87
88/**
89 * Enumeration for a HGCM mock function type.
90 */
91typedef enum TSTHGCMMOCKFNTYPE
92{
93 TSTHGCMMOCKFNTYPE_NONE = 0,
94 TSTHGCMMOCKFNTYPE_CONNECT,
95 TSTHGCMMOCKFNTYPE_DISCONNECT,
96 TSTHGCMMOCKFNTYPE_CALL,
97 TSTHGCMMOCKFNTYPE_HOST_CALL
98} TSTHGCMMOCKFNTYPE;
99
100/** Pointer to a mock HGCM service. */
101typedef struct TSTHGCMMOCKSVC *PTSTHGCMMOCKSVC;
102
103/**
104 * Structure for mocking a server-side HGCM client.
105 */
106typedef struct TSTHGCMMOCKCLIENT
107{
108 /** Pointer to to mock service instance this client belongs to. */
109 PTSTHGCMMOCKSVC pSvc;
110 /** Assigned HGCM client ID. */
111 uint32_t idClient;
112 /** Opaque pointer to service-specific client data.
113 * Can be NULL if not being used. */
114 void *pvClient;
115 /** Size (in bytes) of \a pvClient. */
116 size_t cbClient;
117 /** The client's current HGCM call handle. */
118 VBOXHGCMCALLHANDLE_TYPEDEF hCall;
119 /** Whether the current client call has an asynchronous
120 * call pending or not. */
121 bool fAsyncExec;
122 /** Event semaphore to signal call completion. */
123 RTSEMEVENT hEvent;
124} TSTHGCMMOCKCLIENT;
125/** Pointer to a mock HGCM client. */
126typedef TSTHGCMMOCKCLIENT *PTSTHGCMMOCKCLIENT;
127
128/**
129 * Structure for keeping HGCM mock function parameters.
130 */
131typedef struct TSTHGCMMOCKFN
132{
133 /** List node for storing this struct into a queue. */
134 RTLISTNODE Node;
135 /** Function type. */
136 TSTHGCMMOCKFNTYPE enmType;
137 /** Pointer to associated client. */
138 PTSTHGCMMOCKCLIENT pClient;
139 /** Union keeping function-specific parameters,
140 * depending on \a enmType. */
141 union
142 {
143 struct
144 {
145 int32_t iFunc;
146 uint32_t cParms;
147 PVBOXHGCMSVCPARM pParms;
148 VBOXHGCMCALLHANDLE hCall;
149 } Call;
150 struct
151 {
152 int32_t iFunc;
153 uint32_t cParms;
154 PVBOXHGCMSVCPARM pParms;
155 } HostCall;
156 } u;
157} TSTHGCMMOCKFN;
158/** Pointer to a HGCM mock function parameters structure. */
159typedef TSTHGCMMOCKFN *PTSTHGCMMOCKFN;
160
161/**
162 * Structure for keeping a HGCM mock service instance.
163 */
164typedef struct TSTHGCMMOCKSVC
165{
166 /** HGCM helper table to use. */
167 VBOXHGCMSVCHELPERS fnHelpers;
168 /** HGCM service function table to use. */
169 VBOXHGCMSVCFNTABLE fnTable;
170 /** Next HGCM client ID to assign.
171 * 0 is considered as being invalid. */
172 HGCMCLIENTID uNextClientId;
173 /** Size (in bytes) of opaque pvClient area to reserve
174 * for a connected client. */
175 size_t cbClient;
176 /** Array of connected HGCM mock clients.
177 * Currently limited to 4 clients maximum. */
178 TSTHGCMMOCKCLIENT aHgcmClient[4];
179 /** Thread handle for the service's main loop. */
180 RTTHREAD hThread;
181 /** Event semaphore for signalling a message
182 * queue change. */
183 RTSEMEVENT hEventQueue;
184 /** Event semaphore for waiting on events, such
185 * as clients connecting. */
186 RTSEMEVENT hEventWait;
187 /** Number of current host calls being served.
188 * Currently limited to one call at a time. */
189 uint8_t cHostCallers;
190 /** Result code of last returned host call. */
191 int rcHostCall;
192 /** Event semaphore for host calls. */
193 RTSEMEVENT hEventHostCall;
194 /** List (queue) of function calls to process. */
195 RTLISTANCHOR lstCall;
196 /** Shutdown indicator flag. */
197 volatile bool fShutdown;
198} TSTHGCMMOCKSVC;
199
200/** Static HGCM service to mock. */
201static TSTHGCMMOCKSVC s_tstHgcmSvc;
202
203/*********************************************************************************************************************************
204* Prototypes. *
205*********************************************************************************************************************************/
206PTSTHGCMMOCKSVC TstHgcmMockSvcInst(void);
207PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnectEx(PTSTHGCMMOCKSVC pSvc, RTMSINTERVAL msTimeout);
208PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnect(PTSTHGCMMOCKSVC pSvc);
209int TstHgcmMockSvcCreate(PTSTHGCMMOCKSVC pSvc, size_t cbClient);
210int TstHgcmMockSvcDestroy(PTSTHGCMMOCKSVC pSvc);
211int TstHgcmMockSvcStart(PTSTHGCMMOCKSVC pSvc);
212int TstHgcmMockSvcStop(PTSTHGCMMOCKSVC pSvc);
213
214int TstHgcmMockSvcHostCall(PTSTHGCMMOCKSVC pSvc, void *pvService, int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
215
216VBGLR3DECL(int) VbglR3HGCMConnect(const char *pszServiceName, HGCMCLIENTID *pidClient);
217VBGLR3DECL(int) VbglR3HGCMDisconnect(HGCMCLIENTID idClient);
218VBGLR3DECL(int) VbglR3HGCMCall(PVBGLIOCHGCMCALL pInfo, size_t cbInfo);
219
220
221
222/*********************************************************************************************************************************
223* Internal functions *
224*********************************************************************************************************************************/
225
226/**
227 * Initializes a HGCM mock client.
228 *
229 * @return VBox status code.
230 * @param pClient Client instance to initialize.
231 * @param idClient HGCM client ID to assign.
232 * @param cbClient Size (in bytes) of service-specific (opaque) client data to allocate.
233 */
234static int tstHgcmMockClientInit(PTSTHGCMMOCKCLIENT pClient, uint32_t idClient, size_t cbClient)
235{
236 RT_BZERO(pClient, sizeof(TSTHGCMMOCKCLIENT));
237
238 pClient->idClient = idClient;
239 if (cbClient)
240 {
241 pClient->pvClient = RTMemAllocZ(cbClient);
242 AssertPtrReturn(pClient->pvClient, VERR_NO_MEMORY);
243 pClient->cbClient = cbClient;
244 }
245
246 return RTSemEventCreate(&pClient->hEvent);
247}
248
249/**
250 * Destroys a HGCM mock client.
251 *
252 * @return VBox status code.
253 * @param pClient Client instance to destroy.
254 */
255static int tstHgcmMockClientDestroy(PTSTHGCMMOCKCLIENT pClient)
256{
257 int rc = RTSemEventDestroy(pClient->hEvent);
258 if (RT_SUCCESS(rc))
259 {
260 if (pClient->pvClient)
261 {
262 Assert(pClient->cbClient);
263 RTMemFree(pClient->pvClient);
264 pClient->pvClient = NULL;
265 pClient->cbClient = 0;
266 }
267
268 pClient->hEvent = NIL_RTSEMEVENT;
269 }
270
271 return rc;
272}
273
274/* @copydoc VBOXHGCMSVCFNTABLE::pfnConnect */
275static DECLCALLBACK(int) tstHgcmMockSvcConnect(PTSTHGCMMOCKSVC pSvc, void *pvService, uint32_t *pidClient)
276{
277 RT_NOREF(pvService);
278
279 PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));
280 AssertPtrReturn(pFn, VERR_NO_MEMORY);
281
282 PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[pSvc->uNextClientId];
283
284 int rc = tstHgcmMockClientInit(pClient, pSvc->uNextClientId, pSvc->cbClient);
285 if (RT_FAILURE(rc))
286 return rc;
287
288 pFn->enmType = TSTHGCMMOCKFNTYPE_CONNECT;
289 pFn->pClient = pClient;
290
291 RTListAppend(&pSvc->lstCall, &pFn->Node);
292 pFn = NULL; /* Thread takes ownership now. */
293
294 int rc2 = RTSemEventSignal(pSvc->hEventQueue);
295 AssertRCReturn(rc2, rc2);
296 rc2 = RTSemEventWait(pClient->hEvent, RT_MS_30SEC);
297 AssertRCReturn(rc2, rc2);
298
299 ASMAtomicIncU32(&pSvc->uNextClientId);
300
301 *pidClient = pClient->idClient;
302
303 return VINF_SUCCESS;
304}
305
306/* @copydoc VBOXHGCMSVCFNTABLE::pfnDisconnect */
307static DECLCALLBACK(int) tstHgcmMockSvcDisconnect(PTSTHGCMMOCKSVC pSvc, void *pvService, uint32_t idClient)
308{
309 RT_NOREF(pvService);
310
311 PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[idClient];
312
313 PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));
314 AssertPtrReturn(pFn, VERR_NO_MEMORY);
315
316 pFn->enmType = TSTHGCMMOCKFNTYPE_DISCONNECT;
317 pFn->pClient = pClient;
318
319 RTListAppend(&pSvc->lstCall, &pFn->Node);
320 pFn = NULL; /* Thread takes ownership now. */
321
322 int rc2 = RTSemEventSignal(pSvc->hEventQueue);
323 AssertRCReturn(rc2, rc2);
324
325 rc2 = RTSemEventWait(pClient->hEvent, RT_MS_30SEC);
326 AssertRCReturn(rc2, rc2);
327
328 return tstHgcmMockClientDestroy(pClient);
329}
330
331/* @copydoc VBOXHGCMSVCFNTABLE::pfnCall */
332static DECLCALLBACK(int) tstHgcmMockSvcCall(PTSTHGCMMOCKSVC pSvc, void *pvService, VBOXHGCMCALLHANDLE callHandle, uint32_t idClient, void *pvClient,
333 int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
334{
335 RT_NOREF(pvService, pvClient);
336
337 PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[idClient];
338
339 PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));
340 AssertPtrReturn(pFn, VERR_NO_MEMORY);
341
342 const size_t cbParms = cParms * sizeof(VBOXHGCMSVCPARM);
343
344 pFn->enmType = TSTHGCMMOCKFNTYPE_CALL;
345 pFn->pClient = pClient;
346
347 pFn->u.Call.hCall = callHandle;
348 pFn->u.Call.iFunc = function;
349 pFn->u.Call.pParms = (PVBOXHGCMSVCPARM)RTMemDup(paParms, cbParms);
350 AssertPtrReturn(pFn->u.Call.pParms, VERR_NO_MEMORY);
351 pFn->u.Call.cParms = cParms;
352
353 RTListAppend(&pSvc->lstCall, &pFn->Node);
354
355 int rc2 = RTSemEventSignal(pSvc->hEventQueue);
356 AssertRCReturn(rc2, rc2);
357
358 rc2 = RTSemEventWait(pClient->hEvent, RT_INDEFINITE_WAIT);
359 AssertRCReturn(rc2, rc2);
360
361 memcpy(paParms, pFn->u.Call.pParms, cbParms);
362
363 return VINF_SUCCESS; /** @todo Return host call rc */
364}
365
366/* @copydoc VBOXHGCMSVCFNTABLE::pfnHostCall */
367/** Note: Public for also being able to test host calls via testcases. */
368int TstHgcmMockSvcHostCall(PTSTHGCMMOCKSVC pSvc, void *pvService, int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
369{
370 RT_NOREF(pvService);
371 AssertReturn(pSvc->cHostCallers == 0, VERR_WRONG_ORDER); /* Only one host call at a time. */
372
373 pSvc->cHostCallers++;
374
375 PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));
376 AssertPtrReturn(pFn, VERR_INVALID_POINTER);
377
378 pFn->enmType = TSTHGCMMOCKFNTYPE_HOST_CALL;
379 pFn->u.HostCall.iFunc = function;
380 if (cParms)
381 {
382 pFn->u.HostCall.pParms = (PVBOXHGCMSVCPARM)RTMemDup(paParms, cParms * sizeof(VBOXHGCMSVCPARM));
383 AssertPtrReturn(pFn->u.HostCall.pParms, VERR_NO_MEMORY);
384 pFn->u.HostCall.cParms = cParms;
385 }
386
387 RTListAppend(&pSvc->lstCall, &pFn->Node);
388 pFn = NULL; /* Thread takes ownership now. */
389
390 int rc2 = RTSemEventSignal(pSvc->hEventQueue);
391 AssertRC(rc2);
392
393 rc2 = RTSemEventWait(pSvc->hEventHostCall, RT_INDEFINITE_WAIT);
394 AssertRCReturn(rc2, rc2);
395
396 Assert(pSvc->cHostCallers);
397 pSvc->cHostCallers--;
398
399 return pSvc->rcHostCall;
400}
401
402/**
403 * Call completion callback for guest calls.
404 *
405 * @return VBox status code.
406 * @param callHandle Call handle to complete.
407 * @param rc Return code to return to the caller.
408 */
409static DECLCALLBACK(int) tstHgcmMockSvcCallComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc)
410{
411 PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst();
412
413 size_t i = 0;
414 for (; RT_ELEMENTS(pSvc->aHgcmClient); i++)
415 {
416 PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[i];
417 if (&pClient->hCall == callHandle) /* Slow, but works for now. */
418 {
419 if (rc == VINF_HGCM_ASYNC_EXECUTE)
420 {
421 Assert(pClient->fAsyncExec == false);
422 }
423 else /* Complete call + notify client. */
424 {
425 callHandle->rc = rc;
426
427 int rc2 = RTSemEventSignal(pClient->hEvent);
428 AssertRCReturn(rc2, rc2);
429 }
430
431 return VINF_SUCCESS;
432 }
433 }
434
435 return VERR_NOT_FOUND;
436}
437
438/**
439 * Main thread of HGCM mock service.
440 *
441 * @return VBox status code.
442 * @param hThread Thread handle.
443 * @param pvUser User-supplied data of type PTSTHGCMMOCKSVC.
444 */
445static DECLCALLBACK(int) tstHgcmMockSvcThread(RTTHREAD hThread, void *pvUser)
446{
447 RT_NOREF(hThread);
448 PTSTHGCMMOCKSVC pSvc = (PTSTHGCMMOCKSVC)pvUser;
449
450 pSvc->uNextClientId = 0;
451
452 pSvc->fnTable.cbSize = sizeof(pSvc->fnTable);
453 pSvc->fnTable.u32Version = VBOX_HGCM_SVC_VERSION;
454
455 RT_ZERO(pSvc->fnHelpers);
456 pSvc->fnHelpers.pfnCallComplete = tstHgcmMockSvcCallComplete;
457 pSvc->fnTable.pHelpers = &pSvc->fnHelpers;
458
459 int rc = VBoxHGCMSvcLoad(&pSvc->fnTable);
460 if (RT_SUCCESS(rc))
461 {
462 RTThreadUserSignal(hThread);
463
464 for (;;)
465 {
466 rc = RTSemEventWait(pSvc->hEventQueue, 10 /* ms */);
467 if (ASMAtomicReadBool(&pSvc->fShutdown))
468 {
469 rc = VINF_SUCCESS;
470 break;
471 }
472 if (rc == VERR_TIMEOUT)
473 continue;
474
475 PTSTHGCMMOCKFN pFn = RTListGetFirst(&pSvc->lstCall, TSTHGCMMOCKFN, Node);
476 if (pFn)
477 {
478 switch (pFn->enmType)
479 {
480 case TSTHGCMMOCKFNTYPE_CONNECT:
481 {
482 rc = pSvc->fnTable.pfnConnect(pSvc->fnTable.pvService,
483 pFn->pClient->idClient, pFn->pClient->pvClient,
484 VMMDEV_REQUESTOR_USR_NOT_GIVEN /* fRequestor */, false /* fRestoring */);
485
486 int rc2 = RTSemEventSignal(pFn->pClient->hEvent);
487 AssertRC(rc2);
488 break;
489 }
490
491 case TSTHGCMMOCKFNTYPE_DISCONNECT:
492 {
493 rc = pSvc->fnTable.pfnDisconnect(pSvc->fnTable.pvService,
494 pFn->pClient->idClient, pFn->pClient->pvClient);
495
496 int rc2 = RTSemEventSignal(pFn->pClient->hEvent);
497 AssertRC(rc2);
498 break;
499 }
500
501 case TSTHGCMMOCKFNTYPE_CALL:
502 {
503 pSvc->fnTable.pfnCall(NULL, pFn->u.Call.hCall, pFn->pClient->idClient, pFn->pClient->pvClient,
504 pFn->u.Call.iFunc, pFn->u.Call.cParms, pFn->u.Call.pParms, RTTimeMilliTS());
505
506 /* Note: Call will be completed in the call completion callback. */
507 break;
508 }
509
510 case TSTHGCMMOCKFNTYPE_HOST_CALL:
511 {
512 pSvc->rcHostCall = pSvc->fnTable.pfnHostCall(NULL, pFn->u.HostCall.iFunc, pFn->u.HostCall.cParms, pFn->u.HostCall.pParms);
513
514 int rc2 = RTSemEventSignal(pSvc->hEventHostCall);
515 AssertRC(rc2);
516 break;
517 }
518
519 default:
520 AssertFailed();
521 break;
522 }
523 RTListNodeRemove(&pFn->Node);
524 RTMemFree(pFn);
525 }
526 }
527 }
528
529 return rc;
530}
531
532
533/*********************************************************************************************************************************
534* Public functions *
535*********************************************************************************************************************************/
536
537/**
538 * Returns the pointer to the HGCM mock service instance.
539 *
540 * @return Pointer to HGCM mock service instance.
541 */
542PTSTHGCMMOCKSVC TstHgcmMockSvcInst(void)
543{
544 return &s_tstHgcmSvc;
545}
546
547/**
548 * Waits for a HGCM mock client to connect, extended version.
549 *
550 * @return VBox status code.
551 * @param pSvc HGCM mock service instance.
552 * @param msTimeout Timeout (in ms) to wait for connection.
553 */
554PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnectEx(PTSTHGCMMOCKSVC pSvc, RTMSINTERVAL msTimeout)
555{
556 int rc = RTSemEventWait(pSvc->hEventWait, msTimeout);
557 if (RT_SUCCESS(rc))
558 {
559 Assert(pSvc->uNextClientId);
560 return &pSvc->aHgcmClient[pSvc->uNextClientId - 1];
561 }
562 return NULL;
563}
564
565/**
566 * Waits for a HGCM mock client to connect.
567 *
568 * @return VBox status code.
569 * @param pSvc HGCM mock service instance.
570 */
571PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnect(PTSTHGCMMOCKSVC pSvc)
572{
573 return TstHgcmMockSvcWaitForConnectEx(pSvc, RT_MS_30SEC);
574}
575
576/**
577 * Creates a HGCM mock service instance.
578 *
579 * @return VBox status code.
580 * @param pSvc HGCM mock service instance to create.
581 * @param cbClient Size (in bytes) of service-specific client data to
582 * allocate for a HGCM mock client.
583 */
584int TstHgcmMockSvcCreate(PTSTHGCMMOCKSVC pSvc, size_t cbClient)
585{
586 AssertReturn(cbClient, VERR_INVALID_PARAMETER);
587
588 RT_ZERO(pSvc->aHgcmClient);
589 pSvc->fShutdown = false;
590 int rc = RTSemEventCreate(&pSvc->hEventQueue);
591 if (RT_SUCCESS(rc))
592 {
593 rc = RTSemEventCreate(&pSvc->hEventHostCall);
594 if (RT_SUCCESS(rc))
595 {
596 rc = RTSemEventCreate(&pSvc->hEventWait);
597 if (RT_SUCCESS(rc))
598 {
599 RTListInit(&pSvc->lstCall);
600
601 pSvc->cbClient = cbClient;
602 }
603 }
604 }
605
606 return rc;
607}
608
609/**
610 * Destroys a HGCM mock service instance.
611 *
612 * @return VBox status code.
613 * @param pSvc HGCM mock service instance to destroy.
614 */
615int TstHgcmMockSvcDestroy(PTSTHGCMMOCKSVC pSvc)
616{
617 int rc = RTSemEventDestroy(pSvc->hEventQueue);
618 if (RT_SUCCESS(rc))
619 {
620 rc = RTSemEventDestroy(pSvc->hEventHostCall);
621 if (RT_SUCCESS(rc))
622 RTSemEventDestroy(pSvc->hEventWait);
623 }
624 return rc;
625}
626
627/**
628 * Starts a HGCM mock service instance.
629 *
630 * @return VBox status code.
631 * @param pSvc HGCM mock service instance to start.
632 */
633int TstHgcmMockSvcStart(PTSTHGCMMOCKSVC pSvc)
634{
635 int rc = RTThreadCreate(&pSvc->hThread, tstHgcmMockSvcThread, pSvc, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,
636 "MockSvc");
637 if (RT_SUCCESS(rc))
638 rc = RTThreadUserWait(pSvc->hThread, RT_MS_30SEC);
639
640 return rc;
641}
642
643/**
644 * Stops a HGCM mock service instance.
645 *
646 * @return VBox status code.
647 * @param pSvc HGCM mock service instance to stop.
648 */
649int TstHgcmMockSvcStop(PTSTHGCMMOCKSVC pSvc)
650{
651 ASMAtomicWriteBool(&pSvc->fShutdown, true);
652
653 int rcThread;
654 int rc = RTThreadWait(pSvc->hThread, RT_MS_30SEC, &rcThread);
655 if (RT_SUCCESS(rc))
656 rc = rcThread;
657 if (RT_SUCCESS(rc))
658 {
659 pSvc->hThread = NIL_RTTHREAD;
660 }
661
662 return rc;
663}
664
665
666/*********************************************************************************************************************************
667* VbglR3 stubs *
668*********************************************************************************************************************************/
669
670/**
671 * Connects to an HGCM mock service.
672 *
673 * @returns VBox status code
674 * @param pszServiceName Name of the host service.
675 * @param pidClient Where to put the client ID on success. The client ID
676 * must be passed to all the other calls to the service.
677 */
678VBGLR3DECL(int) VbglR3HGCMConnect(const char *pszServiceName, HGCMCLIENTID *pidClient)
679{
680 RT_NOREF(pszServiceName);
681
682 PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst();
683
684 return tstHgcmMockSvcConnect(pSvc, pSvc->fnTable.pvService, pidClient);
685}
686
687/**
688 * Disconnect from an HGCM mock service.
689 *
690 * @returns VBox status code.
691 * @param idClient The client id returned by VbglR3HGCMConnect().
692 */
693VBGLR3DECL(int) VbglR3HGCMDisconnect(HGCMCLIENTID idClient)
694{
695 PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst();
696
697 return tstHgcmMockSvcDisconnect(pSvc, pSvc->fnTable.pvService, idClient);
698}
699
700/**
701 * Makes a fully prepared HGCM call to an HGCM mock service.
702 *
703 * @returns VBox status code.
704 * @param pInfo Fully prepared HGCM call info.
705 * @param cbInfo Size of the info. This may sometimes be larger than
706 * what the parameter count indicates because of
707 * parameter changes between versions and such.
708 */
709VBGLR3DECL(int) VbglR3HGCMCall(PVBGLIOCHGCMCALL pInfo, size_t cbInfo)
710{
711 RT_NOREF(cbInfo);
712
713 AssertMsg(pInfo->Hdr.cbIn == cbInfo, ("cbIn=%#x cbInfo=%#zx\n", pInfo->Hdr.cbIn, cbInfo));
714 AssertMsg(pInfo->Hdr.cbOut == cbInfo, ("cbOut=%#x cbInfo=%#zx\n", pInfo->Hdr.cbOut, cbInfo));
715 Assert(sizeof(*pInfo) + pInfo->cParms * sizeof(HGCMFunctionParameter) <= cbInfo);
716
717 HGCMFunctionParameter *offSrcParms = VBGL_HGCM_GET_CALL_PARMS(pInfo);
718 PVBOXHGCMSVCPARM paDstParms = (PVBOXHGCMSVCPARM)RTMemAlloc(pInfo->cParms * sizeof(VBOXHGCMSVCPARM));
719
720 uint16_t i = 0;
721 for (; i < pInfo->cParms; i++)
722 {
723 switch (offSrcParms->type)
724 {
725 case VMMDevHGCMParmType_32bit:
726 {
727 paDstParms[i].type = VBOX_HGCM_SVC_PARM_32BIT;
728 paDstParms[i].u.uint32 = offSrcParms->u.value32;
729 break;
730 }
731
732 case VMMDevHGCMParmType_64bit:
733 {
734 paDstParms[i].type = VBOX_HGCM_SVC_PARM_64BIT;
735 paDstParms[i].u.uint64 = offSrcParms->u.value64;
736 break;
737 }
738
739 case VMMDevHGCMParmType_LinAddr:
740 {
741 paDstParms[i].type = VBOX_HGCM_SVC_PARM_PTR;
742 paDstParms[i].u.pointer.addr = (void *)offSrcParms->u.LinAddr.uAddr;
743 paDstParms[i].u.pointer.size = offSrcParms->u.LinAddr.cb;
744 break;
745 }
746
747 default:
748 AssertFailed();
749 break;
750 }
751
752 offSrcParms++;
753 }
754
755 PTSTHGCMMOCKSVC const pSvc = TstHgcmMockSvcInst();
756
757 int rc2 = tstHgcmMockSvcCall(pSvc, pSvc->fnTable.pvService, &pSvc->aHgcmClient[pInfo->u32ClientID].hCall,
758 pInfo->u32ClientID, pSvc->aHgcmClient[pInfo->u32ClientID].pvClient,
759 pInfo->u32Function, pInfo->cParms, paDstParms);
760 if (RT_SUCCESS(rc2))
761 {
762 offSrcParms = VBGL_HGCM_GET_CALL_PARMS(pInfo);
763
764 for (i = 0; i < pInfo->cParms; i++)
765 {
766 paDstParms[i].type = offSrcParms->type;
767 switch (paDstParms[i].type)
768 {
769 case VMMDevHGCMParmType_32bit:
770 offSrcParms->u.value32 = paDstParms[i].u.uint32;
771 break;
772
773 case VMMDevHGCMParmType_64bit:
774 offSrcParms->u.value64 = paDstParms[i].u.uint64;
775 break;
776
777 case VMMDevHGCMParmType_LinAddr:
778 {
779 offSrcParms->u.LinAddr.cb = paDstParms[i].u.pointer.size;
780 break;
781 }
782
783 default:
784 AssertFailed();
785 break;
786 }
787
788 offSrcParms++;
789 }
790 }
791
792 RTMemFree(paDstParms);
793
794 if (RT_SUCCESS(rc2))
795 rc2 = pSvc->aHgcmClient[pInfo->u32ClientID].hCall.rc;
796
797 return rc2;
798}
799
800#endif /* IN_RING3 */
801
802#endif /* !VBOX_INCLUDED_GuestHost_HGCMMock_h */
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