VirtualBox

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

Last change on this file since 97441 was 97268, checked in by vboxsync, 2 years ago

Validation Kit/HGCM: Renaming + signal the connect event when a HGCM client connected.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.0 KB
Line 
1/* $Id: HGCMMock.h 97268 2022-10-24 07:52:46Z 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 clients connecting to the server. */
185 RTSEMEVENT hEventConnect;
186 /** Number of current host calls being served.
187 * Currently limited to one call at a time. */
188 uint8_t cHostCallers;
189 /** Result code of last returned host call. */
190 int rcHostCall;
191 /** Event semaphore for host calls. */
192 RTSEMEVENT hEventHostCall;
193 /** List (queue) of function calls to process. */
194 RTLISTANCHOR lstCall;
195 /** Shutdown indicator flag. */
196 volatile bool fShutdown;
197} TSTHGCMMOCKSVC;
198
199/** Static HGCM service to mock. */
200static TSTHGCMMOCKSVC s_tstHgcmSvc;
201
202/*********************************************************************************************************************************
203* Prototypes. *
204*********************************************************************************************************************************/
205PTSTHGCMMOCKSVC TstHgcmMockSvcInst(void);
206PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnectEx(PTSTHGCMMOCKSVC pSvc, RTMSINTERVAL msTimeout);
207PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnect(PTSTHGCMMOCKSVC pSvc);
208int TstHgcmMockSvcCreate(PTSTHGCMMOCKSVC pSvc, size_t cbClient);
209int TstHgcmMockSvcDestroy(PTSTHGCMMOCKSVC pSvc);
210int TstHgcmMockSvcStart(PTSTHGCMMOCKSVC pSvc);
211int TstHgcmMockSvcStop(PTSTHGCMMOCKSVC pSvc);
212
213int TstHgcmMockSvcHostCall(PTSTHGCMMOCKSVC pSvc, void *pvService, int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
214
215VBGLR3DECL(int) VbglR3HGCMConnect(const char *pszServiceName, HGCMCLIENTID *pidClient);
216VBGLR3DECL(int) VbglR3HGCMDisconnect(HGCMCLIENTID idClient);
217VBGLR3DECL(int) VbglR3HGCMCall(PVBGLIOCHGCMCALL pInfo, size_t cbInfo);
218
219
220
221/*********************************************************************************************************************************
222* Internal functions *
223*********************************************************************************************************************************/
224
225/**
226 * Initializes a HGCM mock client.
227 *
228 * @return VBox status code.
229 * @param pClient Client instance to initialize.
230 * @param idClient HGCM client ID to assign.
231 * @param cbClient Size (in bytes) of service-specific (opaque) client data to allocate.
232 */
233static int tstHgcmMockClientInit(PTSTHGCMMOCKCLIENT pClient, uint32_t idClient, size_t cbClient)
234{
235 RT_BZERO(pClient, sizeof(TSTHGCMMOCKCLIENT));
236
237 pClient->idClient = idClient;
238 if (cbClient)
239 {
240 pClient->pvClient = RTMemAllocZ(cbClient);
241 AssertPtrReturn(pClient->pvClient, VERR_NO_MEMORY);
242 pClient->cbClient = cbClient;
243 }
244
245 return RTSemEventCreate(&pClient->hEvent);
246}
247
248/**
249 * Destroys a HGCM mock client.
250 *
251 * @return VBox status code.
252 * @param pClient Client instance to destroy.
253 */
254static int tstHgcmMockClientDestroy(PTSTHGCMMOCKCLIENT pClient)
255{
256 int rc = RTSemEventDestroy(pClient->hEvent);
257 if (RT_SUCCESS(rc))
258 {
259 if (pClient->pvClient)
260 {
261 Assert(pClient->cbClient);
262 RTMemFree(pClient->pvClient);
263 pClient->pvClient = NULL;
264 pClient->cbClient = 0;
265 }
266
267 pClient->hEvent = NIL_RTSEMEVENT;
268 }
269
270 return rc;
271}
272
273/* @copydoc VBOXHGCMSVCFNTABLE::pfnConnect */
274static DECLCALLBACK(int) tstHgcmMockSvcConnect(PTSTHGCMMOCKSVC pSvc, void *pvService, uint32_t *pidClient)
275{
276 RT_NOREF(pvService);
277
278 PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));
279 AssertPtrReturn(pFn, VERR_NO_MEMORY);
280
281 PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[pSvc->uNextClientId];
282
283 int rc = tstHgcmMockClientInit(pClient, pSvc->uNextClientId, pSvc->cbClient);
284 if (RT_FAILURE(rc))
285 return rc;
286
287 pFn->enmType = TSTHGCMMOCKFNTYPE_CONNECT;
288 pFn->pClient = pClient;
289
290 RTListAppend(&pSvc->lstCall, &pFn->Node);
291 pFn = NULL; /* Thread takes ownership now. */
292
293 int rc2 = RTSemEventSignal(pSvc->hEventQueue);
294 AssertRCReturn(rc2, rc2);
295 rc2 = RTSemEventWait(pClient->hEvent, RT_MS_30SEC);
296 AssertRCReturn(rc2, rc2);
297
298 ASMAtomicIncU32(&pSvc->uNextClientId);
299
300 rc2 = RTSemEventSignal(pSvc->hEventConnect);
301 AssertRCReturn(rc2, rc2);
302
303 *pidClient = pClient->idClient;
304
305 return VINF_SUCCESS;
306}
307
308/* @copydoc VBOXHGCMSVCFNTABLE::pfnDisconnect */
309static DECLCALLBACK(int) tstHgcmMockSvcDisconnect(PTSTHGCMMOCKSVC pSvc, void *pvService, uint32_t idClient)
310{
311 RT_NOREF(pvService);
312
313 PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[idClient];
314
315 PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));
316 AssertPtrReturn(pFn, VERR_NO_MEMORY);
317
318 pFn->enmType = TSTHGCMMOCKFNTYPE_DISCONNECT;
319 pFn->pClient = pClient;
320
321 RTListAppend(&pSvc->lstCall, &pFn->Node);
322 pFn = NULL; /* Thread takes ownership now. */
323
324 int rc2 = RTSemEventSignal(pSvc->hEventQueue);
325 AssertRCReturn(rc2, rc2);
326
327 rc2 = RTSemEventWait(pClient->hEvent, RT_MS_30SEC);
328 AssertRCReturn(rc2, rc2);
329
330 return tstHgcmMockClientDestroy(pClient);
331}
332
333/* @copydoc VBOXHGCMSVCFNTABLE::pfnCall */
334static DECLCALLBACK(int) tstHgcmMockSvcCall(PTSTHGCMMOCKSVC pSvc, void *pvService, VBOXHGCMCALLHANDLE callHandle, uint32_t idClient, void *pvClient,
335 int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
336{
337 RT_NOREF(pvService, pvClient);
338
339 PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[idClient];
340
341 PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));
342 AssertPtrReturn(pFn, VERR_NO_MEMORY);
343
344 const size_t cbParms = cParms * sizeof(VBOXHGCMSVCPARM);
345
346 pFn->enmType = TSTHGCMMOCKFNTYPE_CALL;
347 pFn->pClient = pClient;
348
349 pFn->u.Call.hCall = callHandle;
350 pFn->u.Call.iFunc = function;
351 pFn->u.Call.pParms = (PVBOXHGCMSVCPARM)RTMemDup(paParms, cbParms);
352 AssertPtrReturn(pFn->u.Call.pParms, VERR_NO_MEMORY);
353 pFn->u.Call.cParms = cParms;
354
355 RTListAppend(&pSvc->lstCall, &pFn->Node);
356
357 int rc2 = RTSemEventSignal(pSvc->hEventQueue);
358 AssertRCReturn(rc2, rc2);
359
360 rc2 = RTSemEventWait(pClient->hEvent, RT_INDEFINITE_WAIT);
361 AssertRCReturn(rc2, rc2);
362
363 memcpy(paParms, pFn->u.Call.pParms, cbParms);
364
365 return VINF_SUCCESS; /** @todo Return host call rc */
366}
367
368/* @copydoc VBOXHGCMSVCFNTABLE::pfnHostCall */
369/** Note: Public for also being able to test host calls via testcases. */
370int TstHgcmMockSvcHostCall(PTSTHGCMMOCKSVC pSvc, void *pvService, int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
371{
372 RT_NOREF(pvService);
373 AssertReturn(pSvc->cHostCallers == 0, VERR_WRONG_ORDER); /* Only one host call at a time. */
374
375 pSvc->cHostCallers++;
376
377 PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));
378 AssertPtrReturn(pFn, VERR_INVALID_POINTER);
379
380 pFn->enmType = TSTHGCMMOCKFNTYPE_HOST_CALL;
381 pFn->u.HostCall.iFunc = function;
382 if (cParms)
383 {
384 pFn->u.HostCall.pParms = (PVBOXHGCMSVCPARM)RTMemDup(paParms, cParms * sizeof(VBOXHGCMSVCPARM));
385 AssertPtrReturn(pFn->u.HostCall.pParms, VERR_NO_MEMORY);
386 pFn->u.HostCall.cParms = cParms;
387 }
388
389 RTListAppend(&pSvc->lstCall, &pFn->Node);
390 pFn = NULL; /* Thread takes ownership now. */
391
392 int rc2 = RTSemEventSignal(pSvc->hEventQueue);
393 AssertRC(rc2);
394
395 rc2 = RTSemEventWait(pSvc->hEventHostCall, RT_INDEFINITE_WAIT);
396 AssertRCReturn(rc2, rc2);
397
398 Assert(pSvc->cHostCallers);
399 pSvc->cHostCallers--;
400
401 return pSvc->rcHostCall;
402}
403
404/**
405 * Call completion callback for guest calls.
406 *
407 * @return VBox status code.
408 * @param callHandle Call handle to complete.
409 * @param rc Return code to return to the caller.
410 */
411static DECLCALLBACK(int) tstHgcmMockSvcCallComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc)
412{
413 PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst();
414
415 size_t i = 0;
416 for (; RT_ELEMENTS(pSvc->aHgcmClient); i++)
417 {
418 PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[i];
419 if (&pClient->hCall == callHandle) /* Slow, but works for now. */
420 {
421 if (rc == VINF_HGCM_ASYNC_EXECUTE)
422 {
423 Assert(pClient->fAsyncExec == false);
424 }
425 else /* Complete call + notify client. */
426 {
427 callHandle->rc = rc;
428
429 int rc2 = RTSemEventSignal(pClient->hEvent);
430 AssertRCReturn(rc2, rc2);
431 }
432
433 return VINF_SUCCESS;
434 }
435 }
436
437 return VERR_NOT_FOUND;
438}
439
440/**
441 * Main thread of HGCM mock service.
442 *
443 * @return VBox status code.
444 * @param hThread Thread handle.
445 * @param pvUser User-supplied data of type PTSTHGCMMOCKSVC.
446 */
447static DECLCALLBACK(int) tstHgcmMockSvcThread(RTTHREAD hThread, void *pvUser)
448{
449 RT_NOREF(hThread);
450 PTSTHGCMMOCKSVC pSvc = (PTSTHGCMMOCKSVC)pvUser;
451
452 pSvc->uNextClientId = 0;
453
454 pSvc->fnTable.cbSize = sizeof(pSvc->fnTable);
455 pSvc->fnTable.u32Version = VBOX_HGCM_SVC_VERSION;
456
457 RT_ZERO(pSvc->fnHelpers);
458 pSvc->fnHelpers.pfnCallComplete = tstHgcmMockSvcCallComplete;
459 pSvc->fnTable.pHelpers = &pSvc->fnHelpers;
460
461 int rc = VBoxHGCMSvcLoad(&pSvc->fnTable);
462 if (RT_SUCCESS(rc))
463 {
464 RTThreadUserSignal(hThread);
465
466 for (;;)
467 {
468 rc = RTSemEventWait(pSvc->hEventQueue, 10 /* ms */);
469 if (ASMAtomicReadBool(&pSvc->fShutdown))
470 {
471 rc = VINF_SUCCESS;
472 break;
473 }
474 if (rc == VERR_TIMEOUT)
475 continue;
476
477 PTSTHGCMMOCKFN pFn = RTListGetFirst(&pSvc->lstCall, TSTHGCMMOCKFN, Node);
478 if (pFn)
479 {
480 switch (pFn->enmType)
481 {
482 case TSTHGCMMOCKFNTYPE_CONNECT:
483 {
484 rc = pSvc->fnTable.pfnConnect(pSvc->fnTable.pvService,
485 pFn->pClient->idClient, pFn->pClient->pvClient,
486 VMMDEV_REQUESTOR_USR_NOT_GIVEN /* fRequestor */, false /* fRestoring */);
487
488 int rc2 = RTSemEventSignal(pFn->pClient->hEvent);
489 AssertRC(rc2);
490 break;
491 }
492
493 case TSTHGCMMOCKFNTYPE_DISCONNECT:
494 {
495 rc = pSvc->fnTable.pfnDisconnect(pSvc->fnTable.pvService,
496 pFn->pClient->idClient, pFn->pClient->pvClient);
497
498 int rc2 = RTSemEventSignal(pFn->pClient->hEvent);
499 AssertRC(rc2);
500 break;
501 }
502
503 case TSTHGCMMOCKFNTYPE_CALL:
504 {
505 pSvc->fnTable.pfnCall(NULL, pFn->u.Call.hCall, pFn->pClient->idClient, pFn->pClient->pvClient,
506 pFn->u.Call.iFunc, pFn->u.Call.cParms, pFn->u.Call.pParms, RTTimeMilliTS());
507
508 /* Note: Call will be completed in the call completion callback. */
509 break;
510 }
511
512 case TSTHGCMMOCKFNTYPE_HOST_CALL:
513 {
514 pSvc->rcHostCall = pSvc->fnTable.pfnHostCall(NULL, pFn->u.HostCall.iFunc, pFn->u.HostCall.cParms, pFn->u.HostCall.pParms);
515
516 int rc2 = RTSemEventSignal(pSvc->hEventHostCall);
517 AssertRC(rc2);
518 break;
519 }
520
521 default:
522 AssertFailed();
523 break;
524 }
525 RTListNodeRemove(&pFn->Node);
526 RTMemFree(pFn);
527 }
528 }
529 }
530
531 return rc;
532}
533
534
535/*********************************************************************************************************************************
536* Public functions *
537*********************************************************************************************************************************/
538
539/**
540 * Returns the pointer to the HGCM mock service instance.
541 *
542 * @return Pointer to HGCM mock service instance.
543 */
544PTSTHGCMMOCKSVC TstHgcmMockSvcInst(void)
545{
546 return &s_tstHgcmSvc;
547}
548
549/**
550 * Waits for a HGCM mock client to connect, extended version.
551 *
552 * @return Pointer to connected client, or NULL if ran into timeout.
553 * @param pSvc HGCM mock service instance.
554 * @param msTimeout Timeout (in ms) to wait for connection.
555 */
556PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnectEx(PTSTHGCMMOCKSVC pSvc, RTMSINTERVAL msTimeout)
557{
558 int rc = RTSemEventWait(pSvc->hEventConnect, msTimeout);
559 if (RT_SUCCESS(rc))
560 {
561 Assert(pSvc->uNextClientId);
562 return &pSvc->aHgcmClient[pSvc->uNextClientId - 1];
563 }
564 return NULL;
565}
566
567/**
568 * Waits for a HGCM mock client to connect.
569 *
570 * @return Pointer to connected client, or NULL if waiting for connection was aborted.
571 * @param pSvc HGCM mock service instance.
572 */
573PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnect(PTSTHGCMMOCKSVC pSvc)
574{
575 return TstHgcmMockSvcWaitForConnectEx(pSvc, RT_MS_30SEC);
576}
577
578/**
579 * Creates a HGCM mock service instance.
580 *
581 * @return VBox status code.
582 * @param pSvc HGCM mock service instance to create.
583 * @param cbClient Size (in bytes) of service-specific client data to
584 * allocate for a HGCM mock client.
585 */
586int TstHgcmMockSvcCreate(PTSTHGCMMOCKSVC pSvc, size_t cbClient)
587{
588 AssertReturn(cbClient, VERR_INVALID_PARAMETER);
589
590 RT_ZERO(pSvc->aHgcmClient);
591 pSvc->fShutdown = false;
592 int rc = RTSemEventCreate(&pSvc->hEventQueue);
593 if (RT_SUCCESS(rc))
594 {
595 rc = RTSemEventCreate(&pSvc->hEventHostCall);
596 if (RT_SUCCESS(rc))
597 {
598 rc = RTSemEventCreate(&pSvc->hEventConnect);
599 if (RT_SUCCESS(rc))
600 {
601 RTListInit(&pSvc->lstCall);
602
603 pSvc->cbClient = cbClient;
604 }
605 }
606 }
607
608 return rc;
609}
610
611/**
612 * Destroys a HGCM mock service instance.
613 *
614 * @return VBox status code.
615 * @param pSvc HGCM mock service instance to destroy.
616 */
617int TstHgcmMockSvcDestroy(PTSTHGCMMOCKSVC pSvc)
618{
619 int rc = RTSemEventDestroy(pSvc->hEventQueue);
620 if (RT_SUCCESS(rc))
621 {
622 rc = RTSemEventDestroy(pSvc->hEventHostCall);
623 if (RT_SUCCESS(rc))
624 RTSemEventDestroy(pSvc->hEventConnect);
625 }
626 return rc;
627}
628
629/**
630 * Starts a HGCM mock service instance.
631 *
632 * @return VBox status code.
633 * @param pSvc HGCM mock service instance to start.
634 */
635int TstHgcmMockSvcStart(PTSTHGCMMOCKSVC pSvc)
636{
637 int rc = RTThreadCreate(&pSvc->hThread, tstHgcmMockSvcThread, pSvc, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,
638 "MockSvc");
639 if (RT_SUCCESS(rc))
640 rc = RTThreadUserWait(pSvc->hThread, RT_MS_30SEC);
641
642 return rc;
643}
644
645/**
646 * Stops a HGCM mock service instance.
647 *
648 * @return VBox status code.
649 * @param pSvc HGCM mock service instance to stop.
650 */
651int TstHgcmMockSvcStop(PTSTHGCMMOCKSVC pSvc)
652{
653 ASMAtomicWriteBool(&pSvc->fShutdown, true);
654
655 int rcThread;
656 int rc = RTThreadWait(pSvc->hThread, RT_MS_30SEC, &rcThread);
657 if (RT_SUCCESS(rc))
658 rc = rcThread;
659 if (RT_SUCCESS(rc))
660 {
661 pSvc->hThread = NIL_RTTHREAD;
662 }
663
664 return rc;
665}
666
667
668/*********************************************************************************************************************************
669* VbglR3 stubs *
670*********************************************************************************************************************************/
671
672/**
673 * Connects to an HGCM mock service.
674 *
675 * @returns VBox status code
676 * @param pszServiceName Name of the host service.
677 * @param pidClient Where to put the client ID on success. The client ID
678 * must be passed to all the other calls to the service.
679 */
680VBGLR3DECL(int) VbglR3HGCMConnect(const char *pszServiceName, HGCMCLIENTID *pidClient)
681{
682 RT_NOREF(pszServiceName);
683
684 PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst();
685
686 return tstHgcmMockSvcConnect(pSvc, pSvc->fnTable.pvService, pidClient);
687}
688
689/**
690 * Disconnect from an HGCM mock service.
691 *
692 * @returns VBox status code.
693 * @param idClient The client id returned by VbglR3HGCMConnect().
694 */
695VBGLR3DECL(int) VbglR3HGCMDisconnect(HGCMCLIENTID idClient)
696{
697 PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst();
698
699 return tstHgcmMockSvcDisconnect(pSvc, pSvc->fnTable.pvService, idClient);
700}
701
702/**
703 * Makes a fully prepared HGCM call to an HGCM mock service.
704 *
705 * @returns VBox status code.
706 * @param pInfo Fully prepared HGCM call info.
707 * @param cbInfo Size of the info. This may sometimes be larger than
708 * what the parameter count indicates because of
709 * parameter changes between versions and such.
710 */
711VBGLR3DECL(int) VbglR3HGCMCall(PVBGLIOCHGCMCALL pInfo, size_t cbInfo)
712{
713 RT_NOREF(cbInfo);
714
715 AssertMsg(pInfo->Hdr.cbIn == cbInfo, ("cbIn=%#x cbInfo=%#zx\n", pInfo->Hdr.cbIn, cbInfo));
716 AssertMsg(pInfo->Hdr.cbOut == cbInfo, ("cbOut=%#x cbInfo=%#zx\n", pInfo->Hdr.cbOut, cbInfo));
717 Assert(sizeof(*pInfo) + pInfo->cParms * sizeof(HGCMFunctionParameter) <= cbInfo);
718
719 HGCMFunctionParameter *offSrcParms = VBGL_HGCM_GET_CALL_PARMS(pInfo);
720 PVBOXHGCMSVCPARM paDstParms = (PVBOXHGCMSVCPARM)RTMemAlloc(pInfo->cParms * sizeof(VBOXHGCMSVCPARM));
721
722 uint16_t i = 0;
723 for (; i < pInfo->cParms; i++)
724 {
725 switch (offSrcParms->type)
726 {
727 case VMMDevHGCMParmType_32bit:
728 {
729 paDstParms[i].type = VBOX_HGCM_SVC_PARM_32BIT;
730 paDstParms[i].u.uint32 = offSrcParms->u.value32;
731 break;
732 }
733
734 case VMMDevHGCMParmType_64bit:
735 {
736 paDstParms[i].type = VBOX_HGCM_SVC_PARM_64BIT;
737 paDstParms[i].u.uint64 = offSrcParms->u.value64;
738 break;
739 }
740
741 case VMMDevHGCMParmType_LinAddr:
742 {
743 paDstParms[i].type = VBOX_HGCM_SVC_PARM_PTR;
744 paDstParms[i].u.pointer.addr = (void *)offSrcParms->u.LinAddr.uAddr;
745 paDstParms[i].u.pointer.size = offSrcParms->u.LinAddr.cb;
746 break;
747 }
748
749 default:
750 AssertFailed();
751 break;
752 }
753
754 offSrcParms++;
755 }
756
757 PTSTHGCMMOCKSVC const pSvc = TstHgcmMockSvcInst();
758
759 int rc2 = tstHgcmMockSvcCall(pSvc, pSvc->fnTable.pvService, &pSvc->aHgcmClient[pInfo->u32ClientID].hCall,
760 pInfo->u32ClientID, pSvc->aHgcmClient[pInfo->u32ClientID].pvClient,
761 pInfo->u32Function, pInfo->cParms, paDstParms);
762 if (RT_SUCCESS(rc2))
763 {
764 offSrcParms = VBGL_HGCM_GET_CALL_PARMS(pInfo);
765
766 for (i = 0; i < pInfo->cParms; i++)
767 {
768 paDstParms[i].type = offSrcParms->type;
769 switch (paDstParms[i].type)
770 {
771 case VMMDevHGCMParmType_32bit:
772 offSrcParms->u.value32 = paDstParms[i].u.uint32;
773 break;
774
775 case VMMDevHGCMParmType_64bit:
776 offSrcParms->u.value64 = paDstParms[i].u.uint64;
777 break;
778
779 case VMMDevHGCMParmType_LinAddr:
780 {
781 offSrcParms->u.LinAddr.cb = paDstParms[i].u.pointer.size;
782 break;
783 }
784
785 default:
786 AssertFailed();
787 break;
788 }
789
790 offSrcParms++;
791 }
792 }
793
794 RTMemFree(paDstParms);
795
796 if (RT_SUCCESS(rc2))
797 rc2 = pSvc->aHgcmClient[pInfo->u32ClientID].hCall.rc;
798
799 return rc2;
800}
801
802#endif /* IN_RING3 */
803
804#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