VirtualBox

source: vbox/trunk/src/VBox/HostServices/GuestProperties/testcase/tstGuestPropSvc.cpp@ 28417

Last change on this file since 28417 was 26247, checked in by vboxsync, 15 years ago

HostServices/GuestProperties: fixed the test case

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 38.8 KB
Line 
1/* $Id: tstGuestPropSvc.cpp 26247 2010-02-04 21:44:09Z vboxsync $ */
2/** @file
3 *
4 * Testcase for the guest property service.
5 */
6
7/*
8 * Copyright (C) 2008 Sun Microsystems, Inc.
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#include <VBox/HostServices/GuestPropertySvc.h>
27#include <iprt/initterm.h>
28#include <iprt/stream.h>
29
30using namespace guestProp;
31
32extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad (VBOXHGCMSVCFNTABLE *ptable);
33
34/** Simple call handle structure for the guest call completion callback */
35struct VBOXHGCMCALLHANDLE_TYPEDEF
36{
37 /** Where to store the result code */
38 int32_t rc;
39};
40
41/** Call completion callback for guest calls. */
42static void callComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc)
43{
44 callHandle->rc = rc;
45}
46
47/**
48 * Initialise the HGCM service table as much as we need to start the
49 * service
50 * @param pTable the table to initialise
51 */
52void initTable(VBOXHGCMSVCFNTABLE *pTable, VBOXHGCMSVCHELPERS *pHelpers)
53{
54 pTable->cbSize = sizeof (VBOXHGCMSVCFNTABLE);
55 pTable->u32Version = VBOX_HGCM_SVC_VERSION;
56 pHelpers->pfnCallComplete = callComplete;
57 pTable->pHelpers = pHelpers;
58}
59
60/**
61 * A list of valid flag strings for testConvertFlags. The flag conversion
62 * functions should accept these and convert them from string to a flag type
63 * and back without errors.
64 */
65struct flagStrings
66{
67 /** Flag string in a format the functions should recognise */
68 const char *pcszIn;
69 /** How the functions should output the string again */
70 const char *pcszOut;
71}
72validFlagStrings[] =
73{
74 { " ", "" },
75 { "transient, ", "TRANSIENT" },
76 { " rdOnLyHOST, transIENT , READONLY ", "TRANSIENT, READONLY" },
77 { " rdonlyguest", "RDONLYGUEST" },
78 { "rdonlyhost ", "RDONLYHOST" }
79};
80
81/**
82 * A list of invalid flag strings for testConvertFlags. The flag conversion
83 * functions should reject these.
84 */
85const char *invalidFlagStrings[] =
86{
87 "RDONLYHOST,,",
88 " TRANSIENT READONLY"
89};
90
91/**
92 * Test the flag conversion functions.
93 * @returns iprt status value to indicate whether the test went as expected.
94 * @note prints its own diagnostic information to stdout.
95 */
96int testConvertFlags()
97{
98 int rc = VINF_SUCCESS;
99 RTPrintf("tstGuestPropSvc: Testing conversion of valid flags strings.\n");
100 for (unsigned i = 0; i < RT_ELEMENTS(validFlagStrings) && RT_SUCCESS(rc); ++i)
101 {
102 char szFlagBuffer[MAX_FLAGS_LEN * 2];
103 uint32_t fFlags;
104 rc = validateFlags(validFlagStrings[i].pcszIn, &fFlags);
105 if (RT_FAILURE(rc))
106 RTPrintf("tstGuestPropSvc: FAILURE - Failed to validate flag string '%s'.\n", validFlagStrings[i].pcszIn);
107 if (RT_SUCCESS(rc))
108 {
109 rc = writeFlags(fFlags, szFlagBuffer);
110 if (RT_FAILURE(rc))
111 RTPrintf("tstGuestPropSvc: FAILURE - Failed to convert flag string '%s' back to a string.\n",
112 validFlagStrings[i].pcszIn);
113 }
114 if (RT_SUCCESS(rc) && (strlen(szFlagBuffer) > MAX_FLAGS_LEN - 1))
115 {
116 RTPrintf("tstGuestPropSvc: FAILURE - String '%s' converts back to a flag string which is too long.\n",
117 validFlagStrings[i].pcszIn);
118 rc = VERR_TOO_MUCH_DATA;
119 }
120 if (RT_SUCCESS(rc) && (strcmp(szFlagBuffer, validFlagStrings[i].pcszOut) != 0))
121 {
122 RTPrintf("tstGuestPropSvc: FAILURE - String '%s' converts back to '%s' instead of to '%s'\n",
123 validFlagStrings[i].pcszIn, szFlagBuffer,
124 validFlagStrings[i].pcszOut);
125 rc = VERR_PARSE_ERROR;
126 }
127 }
128 if (RT_SUCCESS(rc))
129 {
130 RTPrintf("Testing rejection of invalid flags strings.\n");
131 for (unsigned i = 0; i < RT_ELEMENTS(invalidFlagStrings) && RT_SUCCESS(rc); ++i)
132 {
133 uint32_t fFlags;
134 /* This is required to fail. */
135 if (RT_SUCCESS(validateFlags(invalidFlagStrings[i], &fFlags)))
136 {
137 RTPrintf("String '%s' was incorrectly accepted as a valid flag string.\n",
138 invalidFlagStrings[i]);
139 rc = VERR_PARSE_ERROR;
140 }
141 }
142 }
143 if (RT_SUCCESS(rc))
144 {
145 char szFlagBuffer[MAX_FLAGS_LEN * 2];
146 uint32_t u32BadFlags = ALLFLAGS << 1;
147 RTPrintf("Testing rejection of an invalid flags field.\n");
148 /* This is required to fail. */
149 if (RT_SUCCESS(writeFlags(u32BadFlags, szFlagBuffer)))
150 {
151 RTPrintf("Flags 0x%x were incorrectly written out as '%.*s'\n",
152 u32BadFlags, MAX_FLAGS_LEN, szFlagBuffer);
153 rc = VERR_PARSE_ERROR;
154 }
155 }
156 return rc;
157}
158
159/**
160 * List of property names for testSetPropsHost.
161 */
162const char *apcszNameBlock[] =
163{
164 "test/name/",
165 "test name",
166 "TEST NAME",
167 "/test/name",
168 NULL
169};
170
171/**
172 * List of property values for testSetPropsHost.
173 */
174const char *apcszValueBlock[] =
175{
176 "test/value/",
177 "test value",
178 "TEST VALUE",
179 "/test/value",
180 NULL
181};
182
183/**
184 * List of property timestamps for testSetPropsHost.
185 */
186uint64_t au64TimestampBlock[] =
187{
188 0, 999, 999999, UINT64_C(999999999999), 0
189};
190
191/**
192 * List of property flags for testSetPropsHost.
193 */
194const char *apcszFlagsBlock[] =
195{
196 "",
197 "readonly, transient",
198 "RDONLYHOST",
199 "RdOnlyGuest",
200 NULL
201};
202
203/**
204 * Test the SET_PROPS_HOST function.
205 * @returns iprt status value to indicate whether the test went as expected.
206 * @note prints its own diagnostic information to stdout.
207 */
208int testSetPropsHost(VBOXHGCMSVCFNTABLE *ptable)
209{
210 int rc = VINF_SUCCESS;
211 RTPrintf("Testing the SET_PROPS_HOST call.\n");
212 if (!VALID_PTR(ptable->pfnHostCall))
213 {
214 RTPrintf("Invalid pfnHostCall() pointer\n");
215 rc = VERR_INVALID_POINTER;
216 }
217 if (RT_SUCCESS(rc))
218 {
219 VBOXHGCMSVCPARM paParms[4];
220 paParms[0].setPointer ((void *) apcszNameBlock, 0);
221 paParms[1].setPointer ((void *) apcszValueBlock, 0);
222 paParms[2].setPointer ((void *) au64TimestampBlock, 0);
223 paParms[3].setPointer ((void *) apcszFlagsBlock, 0);
224 rc = ptable->pfnHostCall(ptable->pvService, SET_PROPS_HOST, 4,
225 paParms);
226 if (RT_FAILURE(rc))
227 RTPrintf("SET_PROPS_HOST call failed with rc=%Rrc\n", rc);
228 }
229 return rc;
230}
231
232/** Result strings for zeroth enumeration test */
233static const char *pcchEnumResult0[] =
234{
235 "test/name/\0test/value/\0""0\0",
236 "test name\0test value\0""999\0TRANSIENT, READONLY",
237 "TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST",
238 "/test/name\0/test/value\0""999999999999\0RDONLYGUEST",
239 NULL
240};
241
242/** Result string sizes for zeroth enumeration test */
243static const uint32_t cchEnumResult0[] =
244{
245 sizeof("test/name/\0test/value/\0""0\0"),
246 sizeof("test name\0test value\0""999\0TRANSIENT, READONLY"),
247 sizeof("TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST"),
248 sizeof("/test/name\0/test/value\0""999999999999\0RDONLYGUEST"),
249 0
250};
251
252/**
253 * The size of the buffer returned by the zeroth enumeration test -
254 * the - 1 at the end is because of the hidden zero terminator
255 */
256static const uint32_t cchEnumBuffer0 =
257sizeof("test/name/\0test/value/\0""0\0\0"
258"test name\0test value\0""999\0TRANSIENT, READONLY\0"
259"TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST\0"
260"/test/name\0/test/value\0""999999999999\0RDONLYGUEST\0\0\0\0\0") - 1;
261
262/** Result strings for first and second enumeration test */
263static const char *pcchEnumResult1[] =
264{
265 "TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST",
266 "/test/name\0/test/value\0""999999999999\0RDONLYGUEST",
267 NULL
268};
269
270/** Result string sizes for first and second enumeration test */
271static const uint32_t cchEnumResult1[] =
272{
273 sizeof("TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST"),
274 sizeof("/test/name\0/test/value\0""999999999999\0RDONLYGUEST"),
275 0
276};
277
278/**
279 * The size of the buffer returned by the first enumeration test -
280 * the - 1 at the end is because of the hidden zero terminator
281 */
282static const uint32_t cchEnumBuffer1 =
283sizeof("TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST\0"
284"/test/name\0/test/value\0""999999999999\0RDONLYGUEST\0\0\0\0\0") - 1;
285
286static const struct enumStringStruct
287{
288 /** The enumeration pattern to test */
289 const char *pcszPatterns;
290 /** The size of the pattern string */
291 const uint32_t cchPatterns;
292 /** The expected enumeration output strings */
293 const char **ppcchResult;
294 /** The size of the output strings */
295 const uint32_t *pcchResult;
296 /** The size of the buffer needed for the enumeration */
297 const uint32_t cchBuffer;
298}
299enumStrings[] =
300{
301 {
302 "", sizeof(""),
303 pcchEnumResult0,
304 cchEnumResult0,
305 cchEnumBuffer0
306 },
307 {
308 "/*\0?E*", sizeof("/*\0?E*"),
309 pcchEnumResult1,
310 cchEnumResult1,
311 cchEnumBuffer1
312 },
313 {
314 "/*|?E*", sizeof("/*|?E*"),
315 pcchEnumResult1,
316 cchEnumResult1,
317 cchEnumBuffer1
318 }
319};
320
321/**
322 * Test the ENUM_PROPS_HOST function.
323 * @returns iprt status value to indicate whether the test went as expected.
324 * @note prints its own diagnostic information to stdout.
325 */
326int testEnumPropsHost(VBOXHGCMSVCFNTABLE *ptable)
327{
328 int rc = VINF_SUCCESS;
329 RTPrintf("Testing the ENUM_PROPS_HOST call.\n");
330 if (!VALID_PTR(ptable->pfnHostCall))
331 {
332 RTPrintf("Invalid pfnHostCall() pointer\n");
333 rc = VERR_INVALID_POINTER;
334 }
335 for (unsigned i = 0; RT_SUCCESS(rc) && i < RT_ELEMENTS(enumStrings);
336 ++i)
337 {
338 char buffer[2048];
339 VBOXHGCMSVCPARM paParms[3];
340 paParms[0].setPointer ((void *) enumStrings[i].pcszPatterns,
341 enumStrings[i].cchPatterns);
342 paParms[1].setPointer ((void *) buffer,
343 enumStrings[i].cchBuffer - 1);
344 AssertBreakStmt(sizeof(buffer) > enumStrings[i].cchBuffer,
345 rc = VERR_INTERNAL_ERROR);
346 if (RT_SUCCESS(rc))
347 {
348 /* This should fail as the buffer is too small. */
349 int rc2 = ptable->pfnHostCall(ptable->pvService, ENUM_PROPS_HOST,
350 3, paParms);
351 if (rc2 != VERR_BUFFER_OVERFLOW)
352 {
353 RTPrintf("ENUM_PROPS_HOST returned %Rrc instead of VERR_BUFFER_OVERFLOW on too small buffer, pattern number %d\n", rc2, i);
354 rc = VERR_BUFFER_OVERFLOW;
355 }
356 else
357 {
358 uint32_t cchBufferActual;
359 rc = paParms[2].getUInt32 (&cchBufferActual);
360 if (RT_SUCCESS(rc) && cchBufferActual != enumStrings[i].cchBuffer)
361 {
362 RTPrintf("ENUM_PROPS_HOST requested a buffer size of %lu instead of %lu for pattern number %d\n", cchBufferActual, enumStrings[i].cchBuffer, i);
363 rc = VERR_OUT_OF_RANGE;
364 }
365 else if (RT_FAILURE(rc))
366 RTPrintf("ENUM_PROPS_HOST did not return the required buffer size properly for pattern %d\n", i);
367 }
368 }
369 if (RT_SUCCESS(rc))
370 {
371 paParms[1].setPointer ((void *) buffer, enumStrings[i].cchBuffer);
372 rc = ptable->pfnHostCall(ptable->pvService, ENUM_PROPS_HOST,
373 3, paParms);
374 if (RT_FAILURE(rc))
375 RTPrintf("ENUM_PROPS_HOST call failed for pattern %d with rc=%Rrc\n", i, rc);
376 else
377 /* Look for each of the result strings in the buffer which was returned */
378 for (unsigned j = 0; RT_SUCCESS(rc) && enumStrings[i].ppcchResult[j] != NULL;
379 ++j)
380 {
381 bool found = false;
382 for (unsigned k = 0; !found && k < enumStrings[i].cchBuffer
383 - enumStrings[i].pcchResult[j];
384 ++k)
385 if (memcmp(buffer + k, enumStrings[i].ppcchResult[j],
386 enumStrings[i].pcchResult[j]) == 0)
387 found = true;
388 if (!found)
389 {
390 RTPrintf("ENUM_PROPS_HOST did not produce the expected output for pattern %d\n",
391 i);
392 rc = VERR_UNRESOLVED_ERROR;
393 }
394 }
395 }
396 }
397 return rc;
398}
399
400/**
401 * Set a property by calling the service
402 * @returns the status returned by the call to the service
403 *
404 * @param pTable the service instance handle
405 * @param pcszName the name of the property to set
406 * @param pcszValue the value to set the property to
407 * @param pcszFlags the flag string to set if one of the SET_PROP[_HOST]
408 * commands is used
409 * @param isHost whether the SET_PROP[_VALUE]_HOST commands should be
410 * used, rather than the guest ones
411 * @param useSetProp whether SET_PROP[_HOST] should be used rather than
412 * SET_PROP_VALUE[_HOST]
413 */
414int doSetProperty(VBOXHGCMSVCFNTABLE *pTable, const char *pcszName,
415 const char *pcszValue, const char *pcszFlags, bool isHost,
416 bool useSetProp)
417{
418 VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
419 int command = SET_PROP_VALUE;
420 if (isHost)
421 {
422 if (useSetProp)
423 command = SET_PROP_HOST;
424 else
425 command = SET_PROP_VALUE_HOST;
426 }
427 else if (useSetProp)
428 command = SET_PROP;
429 VBOXHGCMSVCPARM paParms[3];
430 /* Work around silly constant issues - we ought to allow passing
431 * constant strings in the hgcm parameters. */
432 char szName[MAX_NAME_LEN];
433 char szValue[MAX_VALUE_LEN];
434 char szFlags[MAX_FLAGS_LEN];
435 RTStrPrintf(szName, sizeof(szName), "%s", pcszName);
436 RTStrPrintf(szValue, sizeof(szValue), "%s", pcszValue);
437 RTStrPrintf(szFlags, sizeof(szFlags), "%s", pcszFlags);
438 paParms[0].setPointer (szName, (uint32_t)strlen(szName) + 1);
439 paParms[1].setPointer (szValue, (uint32_t)strlen(szValue) + 1);
440 paParms[2].setPointer (szFlags, (uint32_t)strlen(szFlags) + 1);
441 if (isHost)
442 callHandle.rc = pTable->pfnHostCall(pTable->pvService, command,
443 useSetProp ? 3 : 2, paParms);
444 else
445 pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, command,
446 useSetProp ? 3 : 2, paParms);
447 return callHandle.rc;
448}
449
450
451/** Array of properties for testing SET_PROP_HOST and _GUEST. */
452static const struct
453{
454 /** Property name */
455 const char *pcszName;
456 /** Property value */
457 const char *pcszValue;
458 /** Property flags */
459 const char *pcszFlags;
460 /** Should this be set as the host or the guest? */
461 bool isHost;
462 /** Should we use SET_PROP or SET_PROP_VALUE? */
463 bool useSetProp;
464 /** Should this succeed or be rejected with VERR_PERMISSION_DENIED? */
465 bool isAllowed;
466}
467setProperties[] =
468{
469 { "Red", "Stop!", "transient", false, true, true },
470 { "Amber", "Caution!", "", false, false, true },
471 { "Green", "Go!", "readonly", true, true, true },
472 { "Blue", "What on earth...?", "", true, false, true },
473 { "/test/name", "test", "", false, true, false },
474 { "TEST NAME", "test", "", true, true, false },
475 { "Green", "gone out...", "", false, false, false },
476 { "Green", "gone out...", "", true, false, false },
477 { NULL, NULL, NULL, false, false, false }
478};
479
480/**
481 * Test the SET_PROP, SET_PROP_VALUE, SET_PROP_HOST and SET_PROP_VALUE_HOST
482 * functions.
483 * @returns iprt status value to indicate whether the test went as expected.
484 * @note prints its own diagnostic information to stdout.
485 */
486int testSetProp(VBOXHGCMSVCFNTABLE *pTable)
487{
488 int rc = VINF_SUCCESS;
489 RTPrintf("Testing the SET_PROP, SET_PROP_VALUE, SET_PROP_HOST and SET_PROP_VALUE_HOST calls.\n");
490 for (unsigned i = 0; RT_SUCCESS(rc) && (setProperties[i].pcszName != NULL);
491 ++i)
492 {
493 rc = doSetProperty(pTable, setProperties[i].pcszName,
494 setProperties[i].pcszValue,
495 setProperties[i].pcszFlags,
496 setProperties[i].isHost,
497 setProperties[i].useSetProp);
498 if (setProperties[i].isAllowed && RT_FAILURE(rc))
499 RTPrintf("Setting property '%s' failed with rc=%Rrc.\n",
500 setProperties[i].pcszName, rc);
501 else if ( !setProperties[i].isAllowed
502 && (rc != VERR_PERMISSION_DENIED))
503 {
504 RTPrintf("Setting property '%s' returned %Rrc instead of VERR_PERMISSION_DENIED.\n",
505 setProperties[i].pcszName, rc);
506 rc = VERR_IPE_UNEXPECTED_STATUS;
507 }
508 else
509 rc = VINF_SUCCESS;
510 }
511 return rc;
512}
513
514/**
515 * Delete a property by calling the service
516 * @returns the status returned by the call to the service
517 *
518 * @param pTable the service instance handle
519 * @param pcszName the name of the property to delete
520 * @param isHost whether the DEL_PROP_HOST command should be used, rather
521 * than the guest one
522 */
523int doDelProp(VBOXHGCMSVCFNTABLE *pTable, const char *pcszName, bool isHost)
524{
525 VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
526 int command = DEL_PROP;
527 if (isHost)
528 command = DEL_PROP_HOST;
529 VBOXHGCMSVCPARM paParms[1];
530 /* Work around silly constant issues - we ought to allow passing
531 * constant strings in the hgcm parameters. */
532 char szName[MAX_NAME_LEN];
533 RTStrPrintf(szName, sizeof(szName), "%s", pcszName);
534 paParms[0].setPointer (szName, (uint32_t)strlen(szName) + 1);
535 if (isHost)
536 callHandle.rc = pTable->pfnHostCall(pTable->pvService, command,
537 1, paParms);
538 else
539 pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, command,
540 1, paParms);
541 return callHandle.rc;
542}
543
544/** Array of properties for testing DEL_PROP_HOST and _GUEST. */
545static const struct
546{
547 /** Property name */
548 const char *pcszName;
549 /** Should this be set as the host or the guest? */
550 bool isHost;
551 /** Should this succeed or be rejected with VERR_PERMISSION_DENIED? */
552 bool isAllowed;
553}
554delProperties[] =
555{
556 { "Red", false, true },
557 { "Amber", true, true },
558 { "Red2", false, true },
559 { "Amber2", true, true },
560 { "Green", false, false },
561 { "Green", true, false },
562 { "/test/name", false, false },
563 { "TEST NAME", true, false },
564 { NULL, false, false }
565};
566
567/**
568 * Test the DEL_PROP, and DEL_PROP_HOST functions.
569 * @returns iprt status value to indicate whether the test went as expected.
570 * @note prints its own diagnostic information to stdout.
571 */
572int testDelProp(VBOXHGCMSVCFNTABLE *pTable)
573{
574 int rc = VINF_SUCCESS;
575 RTPrintf("Testing the DEL_PROP and DEL_PROP_HOST calls.\n");
576 for (unsigned i = 0; RT_SUCCESS(rc) && (delProperties[i].pcszName != NULL);
577 ++i)
578 {
579 rc = doDelProp(pTable, delProperties[i].pcszName,
580 delProperties[i].isHost);
581 if (delProperties[i].isAllowed && RT_FAILURE(rc))
582 RTPrintf("Deleting property '%s' failed with rc=%Rrc.\n",
583 delProperties[i].pcszName, rc);
584 else if ( !delProperties[i].isAllowed
585 && (rc != VERR_PERMISSION_DENIED)
586 )
587 {
588 RTPrintf("Deleting property '%s' returned %Rrc instead of VERR_PERMISSION_DENIED.\n",
589 delProperties[i].pcszName, rc);
590 rc = VERR_IPE_UNEXPECTED_STATUS;
591 }
592 else
593 rc = VINF_SUCCESS;
594 }
595 return rc;
596}
597
598/** Array of properties for testing GET_PROP_HOST. */
599static const struct
600{
601 /** Property name */
602 const char *pcszName;
603 /** What value/flags pattern do we expect back? */
604 const char *pcchValue;
605 /** What size should the value/flags array be? */
606 uint32_t cchValue;
607 /** Should this proeprty exist? */
608 bool exists;
609 /** Do we expect a particular timestamp? */
610 bool hasTimestamp;
611 /** What timestamp if any do ex expect? */
612 uint64_t u64Timestamp;
613}
614getProperties[] =
615{
616 { "test/name/", "test/value/\0", sizeof("test/value/\0"), true, true, 0 },
617 { "test name", "test value\0TRANSIENT, READONLY",
618 sizeof("test value\0TRANSIENT, READONLY"), true, true, 999 },
619 { "TEST NAME", "TEST VALUE\0RDONLYHOST", sizeof("TEST VALUE\0RDONLYHOST"),
620 true, true, 999999 },
621 { "/test/name", "/test/value\0RDONLYGUEST",
622 sizeof("/test/value\0RDONLYGUEST"), true, true, UINT64_C(999999999999) },
623 { "Green", "Go!\0READONLY", sizeof("Go!\0READONLY"), true, false, 0 },
624 { "Blue", "What on earth...?\0", sizeof("What on earth...?\0"), true,
625 false, 0 },
626 { "Red", "", 0, false, false, 0 },
627 { NULL, NULL, 0, false, false, 0 }
628};
629
630/**
631 * Test the GET_PROP_HOST function.
632 * @returns iprt status value to indicate whether the test went as expected.
633 * @note prints its own diagnostic information to stdout.
634 */
635int testGetProp(VBOXHGCMSVCFNTABLE *pTable)
636{
637 int rc = VINF_SUCCESS, rc2 = VINF_SUCCESS;
638 RTPrintf("Testing the GET_PROP_HOST call.\n");
639 for (unsigned i = 0; RT_SUCCESS(rc) && (getProperties[i].pcszName != NULL);
640 ++i)
641 {
642 VBOXHGCMSVCPARM paParms[4];
643 /* Work around silly constant issues - we ought to allow passing
644 * constant strings in the hgcm parameters. */
645 char szName[MAX_NAME_LEN] = "";
646 char szBuffer[MAX_VALUE_LEN + MAX_FLAGS_LEN];
647 AssertBreakStmt(sizeof(szBuffer) >= getProperties[i].cchValue,
648 rc = VERR_INTERNAL_ERROR);
649 RTStrPrintf(szName, sizeof(szName), "%s", getProperties[i].pcszName);
650 paParms[0].setPointer (szName, (uint32_t)strlen(szName) + 1);
651 paParms[1].setPointer (szBuffer, sizeof(szBuffer));
652 rc2 = pTable->pfnHostCall(pTable->pvService, GET_PROP_HOST, 4,
653 paParms);
654 if (getProperties[i].exists && RT_FAILURE(rc2))
655 {
656 RTPrintf("Getting property '%s' failed with rc=%Rrc.\n",
657 getProperties[i].pcszName, rc2);
658 rc = rc2;
659 }
660 else if (!getProperties[i].exists && (rc2 != VERR_NOT_FOUND))
661 {
662 RTPrintf("Getting property '%s' returned %Rrc instead of VERR_NOT_FOUND.\n",
663 getProperties[i].pcszName, rc2);
664 rc = VERR_IPE_UNEXPECTED_STATUS;
665 }
666 if (RT_SUCCESS(rc) && getProperties[i].exists)
667 {
668 uint32_t u32ValueLen;
669 rc = paParms[3].getUInt32 (&u32ValueLen);
670 if (RT_FAILURE(rc))
671 RTPrintf("Failed to get the size of the output buffer for property '%s'\n",
672 getProperties[i].pcszName);
673 if ( RT_SUCCESS(rc)
674 && (memcmp(szBuffer, getProperties[i].pcchValue,
675 getProperties[i].cchValue) != 0)
676 )
677 {
678 RTPrintf("Unexpected result '%.*s' for property '%s', expected '%.*s'.\n",
679 u32ValueLen, szBuffer, getProperties[i].pcszName,
680 getProperties[i].cchValue, getProperties[i].pcchValue);
681 rc = VERR_UNRESOLVED_ERROR;
682 }
683 if (RT_SUCCESS(rc) && getProperties[i].hasTimestamp)
684 {
685 uint64_t u64Timestamp;
686 rc = paParms[2].getUInt64 (&u64Timestamp);
687 if (RT_FAILURE(rc))
688 RTPrintf("Failed to get the timestamp for property '%s'\n",
689 getProperties[i].pcszName);
690 if ( RT_SUCCESS(rc)
691 && (u64Timestamp != getProperties[i].u64Timestamp)
692 )
693 {
694 RTPrintf("Bad timestamp %llu for property '%s', expected %llu.\n",
695 u64Timestamp, getProperties[i].pcszName,
696 getProperties[i].u64Timestamp);
697 rc = VERR_UNRESOLVED_ERROR;
698 }
699 }
700 }
701 }
702 return rc;
703}
704
705/** Array of properties for testing GET_PROP_HOST. */
706static const struct
707{
708 /** Buffer returned */
709 const char *pchBuffer;
710 /** What size should the buffer be? */
711 uint32_t cchBuffer;
712}
713getNotifications[] =
714{
715 { "Red\0Stop!\0TRANSIENT", sizeof("Red\0Stop!\0TRANSIENT") },
716 { "Amber\0Caution!\0", sizeof("Amber\0Caution!\0") },
717 { "Green\0Go!\0READONLY", sizeof("Green\0Go!\0READONLY") },
718 { "Blue\0What on earth...?\0", sizeof("Blue\0What on earth...?\0") },
719 { "Red\0\0", sizeof("Red\0\0") },
720 { "Amber\0\0", sizeof("Amber\0\0") },
721 { NULL, 0 }
722};
723
724/**
725 * Test the GET_NOTIFICATION function.
726 * @returns iprt status value to indicate whether the test went as expected.
727 * @note prints its own diagnostic information to stdout.
728 */
729int testGetNotification(VBOXHGCMSVCFNTABLE *pTable)
730{
731 int rc = VINF_SUCCESS;
732 VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
733 char chBuffer[MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN];
734 static char szPattern[] = "";
735
736 RTPrintf("Testing the GET_NOTIFICATION call.\n");
737 uint64_t u64Timestamp;
738 uint32_t u32Size = 0;
739 VBOXHGCMSVCPARM paParms[4];
740
741 /* Test "buffer too small" */
742 u64Timestamp = 1;
743 paParms[0].setPointer ((void *) szPattern, sizeof(szPattern));
744 paParms[1].setUInt64 (u64Timestamp);
745 paParms[2].setPointer ((void *) chBuffer, getNotifications[0].cchBuffer - 1);
746 pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL,
747 GET_NOTIFICATION, 4, paParms);
748 if ( callHandle.rc != VERR_BUFFER_OVERFLOW
749 || RT_FAILURE(paParms[3].getUInt32 (&u32Size))
750 || u32Size != getNotifications[0].cchBuffer
751 )
752 {
753 RTPrintf("Getting notification for property '%s' with a too small buffer did not fail correctly.\n",
754 getNotifications[0].pchBuffer);
755 rc = VERR_UNRESOLVED_ERROR;
756 }
757
758 /* Test successful notification queries. Start with an unknown timestamp
759 * to get the oldest available notification. */
760 u64Timestamp = 1;
761 for (unsigned i = 0; RT_SUCCESS(rc) && (getNotifications[i].pchBuffer != NULL);
762 ++i)
763 {
764 paParms[0].setPointer ((void *) szPattern, sizeof(szPattern));
765 paParms[1].setUInt64 (u64Timestamp);
766 paParms[2].setPointer ((void *) chBuffer, sizeof(chBuffer));
767 pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL,
768 GET_NOTIFICATION, 4, paParms);
769 if ( RT_FAILURE(callHandle.rc)
770 || (i == 0 && callHandle.rc != VWRN_NOT_FOUND)
771 || RT_FAILURE(paParms[1].getUInt64 (&u64Timestamp))
772 || RT_FAILURE(paParms[3].getUInt32 (&u32Size))
773 || u32Size != getNotifications[i].cchBuffer
774 || memcmp(chBuffer, getNotifications[i].pchBuffer, u32Size) != 0
775 )
776 {
777 RTPrintf("Failed to get notification for property '%s'.\n",
778 getNotifications[i].pchBuffer);
779 rc = VERR_UNRESOLVED_ERROR;
780 }
781 }
782 return rc;
783}
784
785/** Paramters for the asynchronous guest notification call */
786struct asyncNotification_
787{
788 /** Call parameters */
789 VBOXHGCMSVCPARM aParms[4];
790 /** Result buffer */
791 char chBuffer[MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN];
792 /** Return value */
793 VBOXHGCMCALLHANDLE_TYPEDEF callHandle;
794} asyncNotification;
795
796/**
797 * Set up the test for the asynchronous GET_NOTIFICATION function.
798 * @returns iprt status value to indicate whether the test went as expected.
799 * @note prints its own diagnostic information to stdout.
800 */
801int setupAsyncNotification(VBOXHGCMSVCFNTABLE *pTable)
802{
803 int rc = VINF_SUCCESS;
804
805 RTPrintf("Testing the asynchronous GET_NOTIFICATION call with no notifications are available.\n");
806 uint64_t u64Timestamp = 0;
807 uint32_t u32Size = 0;
808 static char szPattern[] = "";
809
810 asyncNotification.aParms[0].setPointer ((void *) szPattern, sizeof(szPattern));
811 asyncNotification.aParms[1].setUInt64 (u64Timestamp);
812 asyncNotification.aParms[2].setPointer ((void *) asyncNotification.chBuffer,
813 sizeof(asyncNotification.chBuffer));
814 asyncNotification.callHandle.rc = VINF_HGCM_ASYNC_EXECUTE;
815 pTable->pfnCall(pTable->pvService, &asyncNotification.callHandle, 0, NULL,
816 GET_NOTIFICATION, 4, asyncNotification.aParms);
817 if (RT_FAILURE(asyncNotification.callHandle.rc))
818 {
819 RTPrintf("GET_NOTIFICATION call failed, rc=%Rrc.\n", asyncNotification.callHandle.rc);
820 rc = VERR_UNRESOLVED_ERROR;
821 }
822 else if (asyncNotification.callHandle.rc != VINF_HGCM_ASYNC_EXECUTE)
823 {
824 RTPrintf("GET_NOTIFICATION call completed when no new notifications should be available.\n");
825 rc = VERR_UNRESOLVED_ERROR;
826 }
827 return rc;
828}
829
830/**
831 * Test the asynchronous GET_NOTIFICATION function.
832 * @returns iprt status value to indicate whether the test went as expected.
833 * @note prints its own diagnostic information to stdout.
834 */
835int testAsyncNotification(VBOXHGCMSVCFNTABLE *pTable)
836{
837 int rc = VINF_SUCCESS;
838 uint64_t u64Timestamp;
839 uint32_t u32Size;
840 if ( asyncNotification.callHandle.rc != VINF_SUCCESS
841 || RT_FAILURE(asyncNotification.aParms[1].getUInt64 (&u64Timestamp))
842 || RT_FAILURE(asyncNotification.aParms[3].getUInt32 (&u32Size))
843 || u32Size != getNotifications[0].cchBuffer
844 || memcmp(asyncNotification.chBuffer, getNotifications[0].pchBuffer, u32Size) != 0
845 )
846 {
847 RTPrintf("Asynchronous GET_NOTIFICATION call did not complete as expected, rc=%Rrc\n",
848 asyncNotification.callHandle.rc);
849 rc = VERR_UNRESOLVED_ERROR;
850 }
851 return rc;
852}
853
854/** Array of properties for testing SET_PROP_HOST and _GUEST with the
855 * READONLYGUEST global flag set. */
856static const struct
857{
858 /** Property name */
859 const char *pcszName;
860 /** Property value */
861 const char *pcszValue;
862 /** Property flags */
863 const char *pcszFlags;
864 /** Should this be set as the host or the guest? */
865 bool isHost;
866 /** Should we use SET_PROP or SET_PROP_VALUE? */
867 bool useSetProp;
868 /** Should this succeed or be rejected with VERR_ (NOT VINF_!)
869 * PERMISSION_DENIED? The global check is done after the property one. */
870 bool isAllowed;
871}
872setPropertiesROGuest[] =
873{
874 { "Red", "Stop!", "transient", false, true, true },
875 { "Amber", "Caution!", "", false, false, true },
876 { "Green", "Go!", "readonly", true, true, true },
877 { "Blue", "What on earth...?", "", true, false, true },
878 { "/test/name", "test", "", false, true, true },
879 { "TEST NAME", "test", "", true, true, true },
880 { "Green", "gone out...", "", false, false, false },
881 { "Green", "gone out....", "", true, false, false },
882 { NULL, NULL, NULL, false, false, true }
883};
884
885/**
886 * Set the global flags value by calling the service
887 * @returns the status returned by the call to the service
888 *
889 * @param pTable the service instance handle
890 * @param eFlags the flags to set
891 */
892int doSetGlobalFlags(VBOXHGCMSVCFNTABLE *pTable, ePropFlags eFlags)
893{
894 VBOXHGCMSVCPARM paParm;
895 paParm.setUInt32(eFlags);
896 int rc = pTable->pfnHostCall(pTable->pvService, SET_GLOBAL_FLAGS_HOST,
897 1, &paParm);
898 if (RT_FAILURE(rc))
899 {
900 char szFlags[MAX_FLAGS_LEN];
901 if (RT_FAILURE(writeFlags(eFlags, szFlags)))
902 RTPrintf("Failed to set the global flags.\n");
903 else
904 RTPrintf("Failed to set the global flags \"%s\".\n",
905 szFlags);
906 }
907 return rc;
908}
909
910/**
911 * Test the SET_PROP, SET_PROP_VALUE, SET_PROP_HOST and SET_PROP_VALUE_HOST
912 * functions.
913 * @returns iprt status value to indicate whether the test went as expected.
914 * @note prints its own diagnostic information to stdout.
915 */
916int testSetPropROGuest(VBOXHGCMSVCFNTABLE *pTable)
917{
918 int rc = VINF_SUCCESS;
919 RTPrintf("Testing the SET_PROP, SET_PROP_VALUE, SET_PROP_HOST and SET_PROP_VALUE_HOST calls with READONLYGUEST set globally.\n");
920 rc = VBoxHGCMSvcLoad(pTable);
921 if (RT_FAILURE(rc))
922 RTPrintf("Failed to start the HGCM service.\n");
923 if (RT_SUCCESS(rc))
924 rc = doSetGlobalFlags(pTable, RDONLYGUEST);
925 for (unsigned i = 0; RT_SUCCESS(rc) && (setPropertiesROGuest[i].pcszName != NULL);
926 ++i)
927 {
928 rc = doSetProperty(pTable, setPropertiesROGuest[i].pcszName,
929 setPropertiesROGuest[i].pcszValue,
930 setPropertiesROGuest[i].pcszFlags,
931 setPropertiesROGuest[i].isHost,
932 setPropertiesROGuest[i].useSetProp);
933 if (setPropertiesROGuest[i].isAllowed && RT_FAILURE(rc))
934 RTPrintf("Setting property '%s' to '%s' failed with rc=%Rrc.\n",
935 setPropertiesROGuest[i].pcszName,
936 setPropertiesROGuest[i].pcszValue, rc);
937 else if ( !setPropertiesROGuest[i].isAllowed
938 && (rc != VERR_PERMISSION_DENIED))
939 {
940 RTPrintf("Setting property '%s' to '%s' returned %Rrc instead of VERR_PERMISSION_DENIED.\n",
941 setPropertiesROGuest[i].pcszName,
942 setPropertiesROGuest[i].pcszValue, rc);
943 rc = VERR_IPE_UNEXPECTED_STATUS;
944 }
945 else if ( !setPropertiesROGuest[i].isHost
946 && setPropertiesROGuest[i].isAllowed
947 && (rc != VINF_PERMISSION_DENIED))
948 {
949 RTPrintf("Setting property '%s' to '%s' returned %Rrc instead of VINF_PERMISSION_DENIED.\n",
950 setPropertiesROGuest[i].pcszName,
951 setPropertiesROGuest[i].pcszValue, rc);
952 rc = VERR_IPE_UNEXPECTED_STATUS;
953 }
954 else
955 rc = VINF_SUCCESS;
956 }
957 if (RT_FAILURE(pTable->pfnUnload(pTable->pvService)))
958 RTPrintf("Failed to unload the HGCM service.\n");
959 return rc;
960}
961
962/** Array of properties for testing DEL_PROP_HOST and _GUEST with
963 * READONLYGUEST set globally. */
964static const struct
965{
966 /** Property name */
967 const char *pcszName;
968 /** Should this be deleted as the host (or the guest)? */
969 bool isHost;
970 /** Should this property be created first? (As host, obviously) */
971 bool shouldCreate;
972 /** And with what flags? */
973 const char *pcszFlags;
974 /** Should this succeed or be rejected with VERR_ (NOT VINF_!)
975 * PERMISSION_DENIED? The global check is done after the property one. */
976 bool isAllowed;
977}
978delPropertiesROGuest[] =
979{
980 { "Red", true, true, "", true },
981 { "Amber", false, true, "", true },
982 { "Red2", true, false, "", true },
983 { "Amber2", false, false, "", true },
984 { "Red3", true, true, "READONLY", false },
985 { "Amber3", false, true, "READONLY", false },
986 { "Red4", true, true, "RDONLYHOST", false },
987 { "Amber4", false, true, "RDONLYHOST", true },
988 { NULL, false, false, "", false }
989};
990
991/**
992 * Test the DEL_PROP, and DEL_PROP_HOST functions.
993 * @returns iprt status value to indicate whether the test went as expected.
994 * @note prints its own diagnostic information to stdout.
995 */
996int testDelPropROGuest(VBOXHGCMSVCFNTABLE *pTable)
997{
998 int rc = VINF_SUCCESS;
999 RTPrintf("Testing the DEL_PROP and DEL_PROP_HOST calls with RDONLYGUEST set globally.\n");
1000 rc = VBoxHGCMSvcLoad(pTable);
1001 if (RT_FAILURE(rc))
1002 RTPrintf("Failed to start the HGCM service.\n");
1003 if (RT_SUCCESS(rc))
1004 rc = doSetGlobalFlags(pTable, RDONLYGUEST);
1005 for (unsigned i = 0; RT_SUCCESS(rc)
1006 && (delPropertiesROGuest[i].pcszName != NULL); ++i)
1007 {
1008 if (RT_SUCCESS(rc) && delPropertiesROGuest[i].shouldCreate)
1009 rc = doSetProperty(pTable, delPropertiesROGuest[i].pcszName,
1010 "none", delPropertiesROGuest[i].pcszFlags,
1011 true, true);
1012 rc = doDelProp(pTable, delPropertiesROGuest[i].pcszName,
1013 delPropertiesROGuest[i].isHost);
1014 if (delPropertiesROGuest[i].isAllowed && RT_FAILURE(rc))
1015 RTPrintf("Deleting property '%s' failed with rc=%Rrc.\n",
1016 delPropertiesROGuest[i].pcszName, rc);
1017 else if ( !delPropertiesROGuest[i].isAllowed
1018 && (rc != VERR_PERMISSION_DENIED)
1019 )
1020 {
1021 RTPrintf("Deleting property '%s' returned %Rrc instead of VERR_PERMISSION_DENIED.\n",
1022 delPropertiesROGuest[i].pcszName, rc);
1023 rc = VERR_IPE_UNEXPECTED_STATUS;
1024 }
1025 else if ( !delPropertiesROGuest[i].isHost
1026 && delPropertiesROGuest[i].shouldCreate
1027 && delPropertiesROGuest[i].isAllowed
1028 && (rc != VINF_PERMISSION_DENIED))
1029 {
1030 RTPrintf("Deleting property '%s' as guest returned %Rrc instead of VINF_PERMISSION_DENIED.\n",
1031 delPropertiesROGuest[i].pcszName, rc);
1032 rc = VERR_IPE_UNEXPECTED_STATUS;
1033 }
1034 else
1035 rc = VINF_SUCCESS;
1036 }
1037 if (RT_FAILURE(pTable->pfnUnload(pTable->pvService)))
1038 RTPrintf("Failed to unload the HGCM service.\n");
1039 return rc;
1040}
1041
1042int main(int argc, char **argv)
1043{
1044 VBOXHGCMSVCFNTABLE svcTable;
1045 VBOXHGCMSVCHELPERS svcHelpers;
1046
1047 initTable(&svcTable, &svcHelpers);
1048 RTR3Init();
1049 if (RT_FAILURE(testConvertFlags()))
1050 return 1;
1051 /* The function is inside the service, not HGCM. */
1052 if (RT_FAILURE(VBoxHGCMSvcLoad(&svcTable)))
1053 {
1054 RTPrintf("Failed to start the HGCM service.\n");
1055 return 1;
1056 }
1057 if (RT_FAILURE(testSetPropsHost(&svcTable)))
1058 return 1;
1059 if (RT_FAILURE(testEnumPropsHost(&svcTable)))
1060 return 1;
1061 /* Set up the asynchronous notification test */
1062 if (RT_FAILURE(setupAsyncNotification(&svcTable)))
1063 return 1;
1064 if (RT_FAILURE(testSetProp(&svcTable)))
1065 return 1;
1066 RTPrintf("Checking the data returned by the asynchronous notification call.\n");
1067 /* Our previous notification call should have completed by now. */
1068 if (RT_FAILURE(testAsyncNotification(&svcTable)))
1069 return 1;
1070 if (RT_FAILURE(testDelProp(&svcTable)))
1071 return 1;
1072 if (RT_FAILURE(testGetProp(&svcTable)))
1073 return 1;
1074 if (RT_FAILURE(testGetNotification(&svcTable)))
1075 return 1;
1076 if (RT_FAILURE(svcTable.pfnUnload(svcTable.pvService)))
1077 {
1078 RTPrintf("Failed to unload the HGCM service.\n");
1079 return 1;
1080 }
1081 if (RT_FAILURE(testSetPropROGuest(&svcTable)))
1082 return 1;
1083 if (RT_FAILURE(testDelPropROGuest(&svcTable)))
1084 return 1;
1085 RTPrintf("tstGuestPropSvc: SUCCEEDED.\n");
1086 return 0;
1087}
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