VirtualBox

source: vbox/trunk/src/VBox/HostServices/GuestControl/testcase/tstGuestControlSvc.cpp

Last change on this file was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.0 KB
Line 
1/* $Id: tstGuestControlSvc.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * Testcase for the guest control service.
4 */
5
6/*
7 * Copyright (C) 2011-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#include <VBox/HostServices/GuestControlSvc.h>
33#include <iprt/initterm.h>
34#include <iprt/stream.h>
35#include <iprt/test.h>
36
37
38/*********************************************************************************************************************************
39* Global Variables *
40*********************************************************************************************************************************/
41static RTTEST g_hTest = NIL_RTTEST;
42
43using namespace guestControl;
44
45extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *pTable);
46
47/** Simple call handle structure for the guest call completion callback */
48struct VBOXHGCMCALLHANDLE_TYPEDEF
49{
50 /** Where to store the result code. */
51 int32_t rc;
52};
53
54/** Call completion callback for guest calls. */
55static DECLCALLBACK(int) callComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc)
56{
57 callHandle->rc = rc;
58 return VINF_SUCCESS;
59}
60
61/**
62 * Initialise the HGCM service table as much as we need to start the
63 * service.
64 *
65 * @return IPRT status code.
66 * @param pTable the table to initialise
67 */
68static int initTable(VBOXHGCMSVCFNTABLE *pTable, VBOXHGCMSVCHELPERS *pHelpers)
69{
70 pTable->cbSize = sizeof (VBOXHGCMSVCFNTABLE);
71 pTable->u32Version = VBOX_HGCM_SVC_VERSION;
72 pHelpers->pfnCallComplete = callComplete;
73 pTable->pHelpers = pHelpers;
74
75 return VINF_SUCCESS;
76}
77
78typedef struct CMDHOST
79{
80 /** The HGCM command to execute. */
81 int cmd;
82 /** Number of parameters. */
83 int num_parms;
84 /** The actual parameters. */
85 const PVBOXHGCMSVCPARM parms;
86 /** Flag indicating whether we need a connected client for this command. */
87 bool fNeedsClient;
88 /** The desired return value from the host. */
89 int rc;
90} CMDHOST, *PCMDHOST;
91
92typedef struct CMDCLIENT
93{
94 /** The client's ID. */
95 int client_id;
96 /** The HGCM command to execute. */
97 int cmd;
98 /** Number of parameters. */
99 int num_parms;
100 /** The actual parameters. */
101 const PVBOXHGCMSVCPARM parms;
102 /** The desired return value from the host. */
103 int rc;
104} CMDCLIENT, *PCMDCLIENT;
105
106/**
107 * Tests the HOST_EXEC_CMD function.
108 * @returns iprt status value to indicate whether the test went as expected.
109 * @note prints its own diagnostic information to stdout.
110 */
111static int testHostCmd(const VBOXHGCMSVCFNTABLE *pTable, const PCMDHOST pCmd, uint32_t uNumTests)
112{
113 int rc = VINF_SUCCESS;
114 if (!RT_VALID_PTR(pTable->pfnHostCall))
115 {
116 RTTestPrintf(g_hTest, RTTESTLVL_FAILURE, "Invalid pfnHostCall() pointer\n");
117 rc = VERR_INVALID_POINTER;
118 }
119 if (RT_SUCCESS(rc))
120 {
121 for (unsigned i = 0; (i < uNumTests) && RT_SUCCESS(rc); i++)
122 {
123 RTTestPrintf(g_hTest, RTTESTLVL_INFO, "Testing #%u (cmd: %d, num_parms: %d, parms: 0x%p\n",
124 i, pCmd[i].cmd, pCmd[i].num_parms, pCmd[i].parms);
125
126 if (pCmd[i].fNeedsClient)
127 {
128 int client_rc = pTable->pfnConnect(pTable->pvService, 1000 /* Client ID */, NULL /* pvClient */, 0, false);
129 if (RT_FAILURE(client_rc))
130 rc = client_rc;
131 }
132
133 if (RT_SUCCESS(rc))
134 {
135 int host_rc = pTable->pfnHostCall(pTable->pvService,
136 pCmd[i].cmd,
137 pCmd[i].num_parms,
138 pCmd[i].parms);
139 if (host_rc != pCmd[i].rc)
140 {
141 RTTestPrintf(g_hTest, RTTESTLVL_FAILURE, "Host call test #%u returned with rc=%Rrc instead of rc=%Rrc\n",
142 i, host_rc, pCmd[i].rc);
143 rc = host_rc;
144 if (RT_SUCCESS(rc))
145 rc = VERR_INVALID_PARAMETER;
146 }
147
148 if (pCmd[i].fNeedsClient)
149 {
150 int client_rc = pTable->pfnDisconnect(pTable->pvService, 1000 /* Client ID */, NULL /* pvClient */);
151 if (RT_SUCCESS(rc))
152 rc = client_rc;
153 }
154 }
155 }
156 }
157 return rc;
158}
159
160static int testHost(const VBOXHGCMSVCFNTABLE *pTable)
161{
162 RTTestSub(g_hTest, "Testing host commands ...");
163
164 VBOXHGCMSVCPARM aParms[1];
165 HGCMSvcSetU32(&aParms[0], 1000 /* Context ID */);
166
167 CMDHOST aCmdHostAll[] =
168 {
169#if 0
170 /** No client connected. */
171 { 1024 /* Not existing command */, 0, 0, false, VERR_NOT_FOUND },
172 { -1 /* Invalid command */, 0, 0, false, VERR_NOT_FOUND },
173 { HOST_CANCEL_PENDING_WAITS, 1024, 0, false, VERR_NOT_FOUND },
174 { HOST_CANCEL_PENDING_WAITS, 0, &aParms[0], false, VERR_NOT_FOUND },
175
176 /** No client connected, valid command. */
177 { HOST_CANCEL_PENDING_WAITS, 0, 0, false, VERR_NOT_FOUND },
178
179 /** Client connected, no parameters given. */
180 { HOST_EXEC_SET_INPUT, 0 /* No parameters given */, 0, true, VERR_INVALID_PARAMETER },
181 { 1024 /* Not existing command */, 0 /* No parameters given */, 0, true, VERR_INVALID_PARAMETER },
182 { -1 /* Invalid command */, 0 /* No parameters given */, 0, true, VERR_INVALID_PARAMETER },
183
184 /** Client connected, valid parameters given. */
185 { HOST_CANCEL_PENDING_WAITS, 0, 0, true, VINF_SUCCESS },
186 { HOST_CANCEL_PENDING_WAITS, 1024, &aParms[0], true, VINF_SUCCESS },
187 { HOST_CANCEL_PENDING_WAITS, 0, &aParms[0], true, VINF_SUCCESS},
188#endif
189
190 /** Client connected, invalid parameters given. */
191 { HOST_MSG_EXEC_CMD, 1024, 0, true, VERR_INVALID_POINTER },
192 { HOST_MSG_EXEC_CMD, 1, 0, true, VERR_INVALID_POINTER },
193 { HOST_MSG_EXEC_CMD, -1, 0, true, VERR_INVALID_POINTER },
194
195 /** Client connected, parameters given. */
196 { HOST_MSG_CANCEL_PENDING_WAITS, 1, &aParms[0], true, VINF_SUCCESS },
197 { HOST_MSG_EXEC_CMD, 1, &aParms[0], true, VINF_SUCCESS },
198 { HOST_MSG_EXEC_SET_INPUT, 1, &aParms[0], true, VINF_SUCCESS },
199 { HOST_MSG_EXEC_GET_OUTPUT, 1, &aParms[0], true, VINF_SUCCESS },
200
201 /** Client connected, unknown command + valid parameters given. */
202 { -1, 1, &aParms[0], true, VINF_SUCCESS }
203 };
204
205 int rc = testHostCmd(pTable, &aCmdHostAll[0], RT_ELEMENTS(aCmdHostAll));
206 RTTestSubDone(g_hTest);
207 return rc;
208}
209
210static int testClient(const VBOXHGCMSVCFNTABLE *pTable)
211{
212 RTTestSub(g_hTest, "Testing client commands ...");
213
214 int rc = pTable->pfnConnect(pTable->pvService, 1 /* Client ID */, NULL /* pvClient */, 0, false);
215 if (RT_SUCCESS(rc))
216 {
217 VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
218
219 /* No commands from host yet. */
220 VBOXHGCMSVCPARM aParmsGuest[8];
221 HGCMSvcSetU32(&aParmsGuest[0], 0 /* Msg type */);
222 HGCMSvcSetU32(&aParmsGuest[1], 0 /* Parameters */);
223 pTable->pfnCall(pTable->pvService, &callHandle, 1 /* Client ID */, NULL /* pvClient */,
224 GUEST_MSG_WAIT, 2, &aParmsGuest[0], 0);
225 RTTEST_CHECK_RC_RET(g_hTest, callHandle.rc, VINF_SUCCESS, callHandle.rc);
226
227 /* Host: Add a dummy command. */
228 VBOXHGCMSVCPARM aParmsHost[8];
229 HGCMSvcSetU32(&aParmsHost[0], 1000 /* Context ID */);
230 HGCMSvcSetStr(&aParmsHost[1], "foo.bar");
231 HGCMSvcSetStr(&aParmsHost[2], "baz");
232
233 rc = pTable->pfnHostCall(pTable->pvService, HOST_MSG_EXEC_CMD, 3, &aParmsHost[0]);
234 RTTEST_CHECK_RC_RET(g_hTest, rc, VINF_SUCCESS, rc);
235
236 /* Client: Disconnect again. */
237 int rc2 = pTable->pfnDisconnect(pTable->pvService, 1000 /* Client ID */, NULL /* pvClient */);
238 if (RT_SUCCESS(rc))
239 rc = rc2;
240 }
241
242 RTTestSubDone(g_hTest);
243 return rc;
244}
245
246/*
247 * Set environment variable "IPRT_TEST_MAX_LEVEL=all" to get more debug output!
248 */
249int main()
250{
251 RTEXITCODE rcExit = RTTestInitAndCreate("tstGuestControlSvc", &g_hTest);
252 if (rcExit != RTEXITCODE_SUCCESS)
253 return rcExit;
254 RTTestBanner(g_hTest);
255
256 /* Some host info. */
257 RTTestIPrintf(RTTESTLVL_ALWAYS, "sizeof(void*)=%d\n", sizeof(void*));
258
259 /* Do the tests. */
260 VBOXHGCMSVCFNTABLE svcTable;
261 VBOXHGCMSVCHELPERS svcHelpers;
262 RTTEST_CHECK_RC_RET(g_hTest, initTable(&svcTable, &svcHelpers), VINF_SUCCESS, 1);
263
264 do
265 {
266 RTTESTI_CHECK_RC_BREAK(VBoxHGCMSvcLoad(&svcTable), VINF_SUCCESS);
267
268 RTTESTI_CHECK_RC_BREAK(testHost(&svcTable), VINF_SUCCESS);
269
270 RTTESTI_CHECK_RC_BREAK(svcTable.pfnUnload(svcTable.pvService), VINF_SUCCESS);
271
272 RTTESTI_CHECK_RC_BREAK(VBoxHGCMSvcLoad(&svcTable), VINF_SUCCESS);
273
274 RTTESTI_CHECK_RC_BREAK(testClient(&svcTable), VINF_SUCCESS);
275
276 RTTESTI_CHECK_RC_BREAK(svcTable.pfnUnload(svcTable.pvService), VINF_SUCCESS);
277
278 } while (0);
279
280 return RTTestSummaryAndDestroy(g_hTest);
281}
282
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