VirtualBox

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

Last change on this file since 19796 was 16337, checked in by vboxsync, 16 years ago

gcc warning (strncat may overflow)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 30.1 KB
Line 
1/* $Id: tstGuestPropSvc.cpp 16337 2009-01-28 21:03:49Z 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/** Array of properties for testing SET_PROP_HOST and _GUEST. */
401static const struct
402{
403 /** Property name */
404 const char *pcszName;
405 /** Property value */
406 const char *pcszValue;
407 /** Property flags */
408 const char *pcszFlags;
409 /** Should this be set as the host or the guest? */
410 bool isHost;
411 /** Should we use SET_PROP or SET_PROP_VALUE? */
412 bool useSetProp;
413 /** Should this succeed or be rejected with VERR_PERMISSION_DENIED? */
414 bool isAllowed;
415}
416setProperties[] =
417{
418 { "Red", "Stop!", "transient", false, true, true },
419 { "Amber", "Caution!", "", false, false, true },
420 { "Green", "Go!", "readonly", true, true, true },
421 { "Blue", "What on earth...?", "", true, false, true },
422 { "/test/name", "test", "", false, true, false },
423 { "TEST NAME", "test", "", true, true, false },
424 { "Green", "gone out...", "", false, false, false },
425 { "Green", "gone out...", "", true, false, false },
426 { NULL, NULL, NULL, false, false, false }
427};
428
429/**
430 * Test the SET_PROP, SET_PROP_VALUE, SET_PROP_HOST and SET_PROP_VALUE_HOST
431 * functions.
432 * @returns iprt status value to indicate whether the test went as expected.
433 * @note prints its own diagnostic information to stdout.
434 */
435int testSetProp(VBOXHGCMSVCFNTABLE *pTable)
436{
437 int rc = VINF_SUCCESS;
438 VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
439 RTPrintf("Testing the SET_PROP, SET_PROP_VALUE, SET_PROP_HOST and SET_PROP_VALUE_HOST calls.\n");
440 for (unsigned i = 0; RT_SUCCESS(rc) && (setProperties[i].pcszName != NULL);
441 ++i)
442 {
443 int command = SET_PROP_VALUE;
444 if (setProperties[i].isHost)
445 {
446 if (setProperties[i].useSetProp)
447 command = SET_PROP_HOST;
448 else
449 command = SET_PROP_VALUE_HOST;
450 }
451 else if (setProperties[i].useSetProp)
452 command = SET_PROP;
453 VBOXHGCMSVCPARM paParms[3];
454 /* Work around silly constant issues - we ought to allow passing
455 * constant strings in the hgcm parameters. */
456 char szName[MAX_NAME_LEN];
457 char szValue[MAX_VALUE_LEN];
458 char szFlags[MAX_FLAGS_LEN];
459 RTStrPrintf(szName, sizeof(szName), "%s", setProperties[i].pcszName);
460 RTStrPrintf(szValue, sizeof(szValue), "%s", setProperties[i].pcszValue);
461 RTStrPrintf(szFlags, sizeof(szFlags), "%s", setProperties[i].pcszFlags);
462 paParms[0].setPointer (szName, (uint32_t)strlen(szName) + 1);
463 paParms[1].setPointer (szValue, (uint32_t)strlen(szValue) + 1);
464 paParms[2].setPointer (szFlags, (uint32_t)strlen(szFlags) + 1);
465 if (setProperties[i].isHost)
466 callHandle.rc = pTable->pfnHostCall(pTable->pvService, command,
467 setProperties[i].useSetProp
468 ? 3 : 2, paParms);
469 else
470 pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, command,
471 setProperties[i].useSetProp ? 3 : 2, paParms);
472 if (setProperties[i].isAllowed && RT_FAILURE(callHandle.rc))
473 {
474 RTPrintf("Setting property '%s' failed with rc=%Rrc.\n",
475 setProperties[i].pcszName, callHandle.rc);
476 rc = callHandle.rc;
477 }
478 else if ( !setProperties[i].isAllowed
479 && (callHandle.rc != VERR_PERMISSION_DENIED)
480 )
481 {
482 RTPrintf("Setting property '%s' returned %Rrc instead of VERR_PERMISSION_DENIED.\n",
483 setProperties[i].pcszName, callHandle.rc);
484 rc = VERR_UNRESOLVED_ERROR;
485 }
486 }
487 return rc;
488}
489
490/** Array of properties for testing DEL_PROP_HOST and _GUEST. */
491static const struct
492{
493 /** Property name */
494 const char *pcszName;
495 /** Should this be set as the host or the guest? */
496 bool isHost;
497 /** Should this succeed or be rejected with VERR_PERMISSION_DENIED? */
498 bool isAllowed;
499}
500delProperties[] =
501{
502 { "Red", false, true },
503 { "Amber", true, true },
504 { "Red2", false, true },
505 { "Amber2", true, true },
506 { "Green", false, false },
507 { "Green", true, false },
508 { "/test/name", false, false },
509 { "TEST NAME", true, false },
510 { NULL, false, false }
511};
512
513/**
514 * Test the DEL_PROP, and DEL_PROP_HOST functions.
515 * @returns iprt status value to indicate whether the test went as expected.
516 * @note prints its own diagnostic information to stdout.
517 */
518int testDelProp(VBOXHGCMSVCFNTABLE *pTable)
519{
520 int rc = VINF_SUCCESS;
521 VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
522 RTPrintf("Testing the DEL_PROP and DEL_PROP_HOST calls.\n");
523 for (unsigned i = 0; RT_SUCCESS(rc) && (delProperties[i].pcszName != NULL);
524 ++i)
525 {
526 int command = DEL_PROP;
527 if (delProperties[i].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", delProperties[i].pcszName);
534 paParms[0].setPointer (szName, (uint32_t)strlen(szName) + 1);
535 if (delProperties[i].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 if (delProperties[i].isAllowed && RT_FAILURE(callHandle.rc))
542 {
543 RTPrintf("Deleting property '%s' failed with rc=%Rrc.\n",
544 delProperties[i].pcszName, callHandle.rc);
545 rc = callHandle.rc;
546 }
547 else if ( !delProperties[i].isAllowed
548 && (callHandle.rc != VERR_PERMISSION_DENIED)
549 )
550 {
551 RTPrintf("Deleting property '%s' returned %Rrc instead of VERR_PERMISSION_DENIED.\n",
552 delProperties[i].pcszName, callHandle.rc);
553 rc = VERR_UNRESOLVED_ERROR;
554 }
555 }
556 return rc;
557}
558
559/** Array of properties for testing GET_PROP_HOST. */
560static const struct
561{
562 /** Property name */
563 const char *pcszName;
564 /** What value/flags pattern do we expect back? */
565 const char *pcchValue;
566 /** What size should the value/flags array be? */
567 uint32_t cchValue;
568 /** Should this proeprty exist? */
569 bool exists;
570 /** Do we expect a particular timestamp? */
571 bool hasTimestamp;
572 /** What timestamp if any do ex expect? */
573 uint64_t u64Timestamp;
574}
575getProperties[] =
576{
577 { "test/name/", "test/value/\0", sizeof("test/value/\0"), true, true, 0 },
578 { "test name", "test value\0TRANSIENT, READONLY",
579 sizeof("test value\0TRANSIENT, READONLY"), true, true, 999 },
580 { "TEST NAME", "TEST VALUE\0RDONLYHOST", sizeof("TEST VALUE\0RDONLYHOST"),
581 true, true, 999999 },
582 { "/test/name", "/test/value\0RDONLYGUEST",
583 sizeof("/test/value\0RDONLYGUEST"), true, true, UINT64_C(999999999999) },
584 { "Green", "Go!\0READONLY", sizeof("Go!\0READONLY"), true, false, 0 },
585 { "Blue", "What on earth...?\0", sizeof("What on earth...?\0"), true,
586 false, 0 },
587 { "Red", "", 0, false, false, 0 },
588 { NULL, NULL, 0, false, false, 0 }
589};
590
591/**
592 * Test the GET_PROP_HOST function.
593 * @returns iprt status value to indicate whether the test went as expected.
594 * @note prints its own diagnostic information to stdout.
595 */
596int testGetProp(VBOXHGCMSVCFNTABLE *pTable)
597{
598 int rc = VINF_SUCCESS, rc2 = VINF_SUCCESS;
599 RTPrintf("Testing the GET_PROP_HOST call.\n");
600 for (unsigned i = 0; RT_SUCCESS(rc) && (getProperties[i].pcszName != NULL);
601 ++i)
602 {
603 VBOXHGCMSVCPARM paParms[4];
604 /* Work around silly constant issues - we ought to allow passing
605 * constant strings in the hgcm parameters. */
606 char szName[MAX_NAME_LEN] = "";
607 char szBuffer[MAX_VALUE_LEN + MAX_FLAGS_LEN];
608 AssertBreakStmt(sizeof(szBuffer) >= getProperties[i].cchValue,
609 rc = VERR_INTERNAL_ERROR);
610 RTStrPrintf(szName, sizeof(szName), "%s", getProperties[i].pcszName);
611 paParms[0].setPointer (szName, (uint32_t)strlen(szName) + 1);
612 paParms[1].setPointer (szBuffer, sizeof(szBuffer));
613 rc2 = pTable->pfnHostCall(pTable->pvService, GET_PROP_HOST, 4,
614 paParms);
615 if (getProperties[i].exists && RT_FAILURE(rc2))
616 {
617 RTPrintf("Getting property '%s' failed with rc=%Rrc.\n",
618 getProperties[i].pcszName, rc2);
619 rc = rc2;
620 }
621 else if (!getProperties[i].exists && (rc2 != VERR_NOT_FOUND))
622 {
623 RTPrintf("Getting property '%s' returned %Rrc instead of VERR_NOT_FOUND.\n",
624 getProperties[i].pcszName, rc2);
625 rc = VERR_UNRESOLVED_ERROR;
626 }
627 if (RT_SUCCESS(rc) && getProperties[i].exists)
628 {
629 uint32_t u32ValueLen;
630 rc = paParms[3].getUInt32 (&u32ValueLen);
631 if (RT_FAILURE(rc))
632 RTPrintf("Failed to get the size of the output buffer for property '%s'\n",
633 getProperties[i].pcszName);
634 if ( RT_SUCCESS(rc)
635 && (memcmp(szBuffer, getProperties[i].pcchValue,
636 getProperties[i].cchValue) != 0)
637 )
638 {
639 RTPrintf("Unexpected result '%.*s' for property '%s', expected '%.*s'.\n",
640 u32ValueLen, szBuffer, getProperties[i].pcszName,
641 getProperties[i].cchValue, getProperties[i].pcchValue);
642 rc = VERR_UNRESOLVED_ERROR;
643 }
644 if (RT_SUCCESS(rc) && getProperties[i].hasTimestamp)
645 {
646 uint64_t u64Timestamp;
647 rc = paParms[2].getUInt64 (&u64Timestamp);
648 if (RT_FAILURE(rc))
649 RTPrintf("Failed to get the timestamp for property '%s'\n",
650 getProperties[i].pcszName);
651 if ( RT_SUCCESS(rc)
652 && (u64Timestamp != getProperties[i].u64Timestamp)
653 )
654 {
655 RTPrintf("Bad timestamp %llu for property '%s', expected %llu.\n",
656 u64Timestamp, getProperties[i].pcszName,
657 getProperties[i].u64Timestamp);
658 rc = VERR_UNRESOLVED_ERROR;
659 }
660 }
661 }
662 }
663 return rc;
664}
665
666/** Array of properties for testing GET_PROP_HOST. */
667static const struct
668{
669 /** Buffer returned */
670 const char *pchBuffer;
671 /** What size should the buffer be? */
672 uint32_t cchBuffer;
673}
674getNotifications[] =
675{
676 { "Red\0Stop!\0TRANSIENT", sizeof("Red\0Stop!\0TRANSIENT") },
677 { "Amber\0Caution!\0", sizeof("Amber\0Caution!\0") },
678 { "Green\0Go!\0READONLY", sizeof("Green\0Go!\0READONLY") },
679 { "Blue\0What on earth...?\0", sizeof("Blue\0What on earth...?\0") },
680 { "Red\0\0", sizeof("Red\0\0") },
681 { "Amber\0\0", sizeof("Amber\0\0") },
682 { NULL, 0 }
683};
684
685/**
686 * Test the GET_NOTIFICATION function.
687 * @returns iprt status value to indicate whether the test went as expected.
688 * @note prints its own diagnostic information to stdout.
689 */
690int testGetNotification(VBOXHGCMSVCFNTABLE *pTable)
691{
692 int rc = VINF_SUCCESS;
693 VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
694 char chBuffer[MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN];
695 static char szPattern[] = "";
696
697 RTPrintf("Testing the GET_NOTIFICATION call.\n");
698 uint64_t u64Timestamp;
699 uint32_t u32Size = 0;
700 VBOXHGCMSVCPARM paParms[4];
701
702 /* Test "buffer too small" */
703 u64Timestamp = 1;
704 paParms[0].setPointer ((void *) szPattern, sizeof(szPattern));
705 paParms[1].setUInt64 (u64Timestamp);
706 paParms[2].setPointer ((void *) chBuffer, getNotifications[0].cchBuffer - 1);
707 pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL,
708 GET_NOTIFICATION, 4, paParms);
709 if ( callHandle.rc != VERR_BUFFER_OVERFLOW
710 || RT_FAILURE(paParms[3].getUInt32 (&u32Size))
711 || u32Size != getNotifications[0].cchBuffer
712 )
713 {
714 RTPrintf("Getting notification for property '%s' with a too small buffer did not fail correctly.\n",
715 getNotifications[0].pchBuffer);
716 rc = VERR_UNRESOLVED_ERROR;
717 }
718
719 /* Test successful notification queries. Start with an unknown timestamp
720 * to get the oldest available notification. */
721 u64Timestamp = 1;
722 for (unsigned i = 0; RT_SUCCESS(rc) && (getNotifications[i].pchBuffer != NULL);
723 ++i)
724 {
725 paParms[0].setPointer ((void *) szPattern, sizeof(szPattern));
726 paParms[1].setUInt64 (u64Timestamp);
727 paParms[2].setPointer ((void *) chBuffer, sizeof(chBuffer));
728 pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL,
729 GET_NOTIFICATION, 4, paParms);
730 if ( RT_FAILURE(callHandle.rc)
731 || (i == 0 && callHandle.rc != VWRN_NOT_FOUND)
732 || RT_FAILURE(paParms[1].getUInt64 (&u64Timestamp))
733 || RT_FAILURE(paParms[3].getUInt32 (&u32Size))
734 || u32Size != getNotifications[i].cchBuffer
735 || memcmp(chBuffer, getNotifications[i].pchBuffer, u32Size) != 0
736 )
737 {
738 RTPrintf("Failed to get notification for property '%s'.\n",
739 getNotifications[i].pchBuffer);
740 rc = VERR_UNRESOLVED_ERROR;
741 }
742 }
743 return rc;
744}
745
746/** Paramters for the asynchronous guest notification call */
747struct asyncNotification_
748{
749 /** Call parameters */
750 VBOXHGCMSVCPARM aParms[4];
751 /** Result buffer */
752 char chBuffer[MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN];
753 /** Return value */
754 VBOXHGCMCALLHANDLE_TYPEDEF callHandle;
755} asyncNotification;
756
757/**
758 * Set up the test for the asynchronous GET_NOTIFICATION function.
759 * @returns iprt status value to indicate whether the test went as expected.
760 * @note prints its own diagnostic information to stdout.
761 */
762int setupAsyncNotification(VBOXHGCMSVCFNTABLE *pTable)
763{
764 int rc = VINF_SUCCESS;
765
766 RTPrintf("Testing the asynchronous GET_NOTIFICATION call with no notifications are available.\n");
767 uint64_t u64Timestamp = 0;
768 uint32_t u32Size = 0;
769 static char szPattern[] = "";
770
771 asyncNotification.aParms[0].setPointer ((void *) szPattern, sizeof(szPattern));
772 asyncNotification.aParms[1].setUInt64 (u64Timestamp);
773 asyncNotification.aParms[2].setPointer ((void *) asyncNotification.chBuffer,
774 sizeof(asyncNotification.chBuffer));
775 asyncNotification.callHandle.rc = VINF_HGCM_ASYNC_EXECUTE;
776 pTable->pfnCall(pTable->pvService, &asyncNotification.callHandle, 0, NULL,
777 GET_NOTIFICATION, 4, asyncNotification.aParms);
778 if (RT_FAILURE(asyncNotification.callHandle.rc))
779 {
780 RTPrintf("GET_NOTIFICATION call failed, rc=%Rrc.\n", asyncNotification.callHandle.rc);
781 rc = VERR_UNRESOLVED_ERROR;
782 }
783 else if (asyncNotification.callHandle.rc != VINF_HGCM_ASYNC_EXECUTE)
784 {
785 RTPrintf("GET_NOTIFICATION call completed when no new notifications should be available.\n");
786 rc = VERR_UNRESOLVED_ERROR;
787 }
788 return rc;
789}
790
791/**
792 * Test the asynchronous GET_NOTIFICATION function.
793 * @returns iprt status value to indicate whether the test went as expected.
794 * @note prints its own diagnostic information to stdout.
795 */
796int testAsyncNotification(VBOXHGCMSVCFNTABLE *pTable)
797{
798 int rc = VINF_SUCCESS;
799 uint64_t u64Timestamp;
800 uint32_t u32Size;
801 if ( asyncNotification.callHandle.rc != VINF_SUCCESS
802 || RT_FAILURE(asyncNotification.aParms[1].getUInt64 (&u64Timestamp))
803 || RT_FAILURE(asyncNotification.aParms[3].getUInt32 (&u32Size))
804 || u32Size != getNotifications[0].cchBuffer
805 || memcmp(asyncNotification.chBuffer, getNotifications[0].pchBuffer, u32Size) != 0
806 )
807 {
808 RTPrintf("Asynchronous GET_NOTIFICATION call did not complete as expected, rc=%Rrc\n",
809 asyncNotification.callHandle.rc);
810 rc = VERR_UNRESOLVED_ERROR;
811 }
812 return rc;
813}
814
815int main(int argc, char **argv)
816{
817 VBOXHGCMSVCFNTABLE svcTable;
818 VBOXHGCMSVCHELPERS svcHelpers;
819
820 initTable(&svcTable, &svcHelpers);
821 RTR3Init();
822 if (RT_FAILURE(testConvertFlags()))
823 return 1;
824 /* The function is inside the service, not HGCM. */
825 if (RT_FAILURE(VBoxHGCMSvcLoad(&svcTable)))
826 {
827 RTPrintf("Failed to start HGCM service.\n");
828 return 1;
829 }
830 if (RT_FAILURE(testSetPropsHost(&svcTable)))
831 return 1;
832 if (RT_FAILURE(testEnumPropsHost(&svcTable)))
833 return 1;
834 /* Set up the asynchronous notification test */
835 if (RT_FAILURE(setupAsyncNotification(&svcTable)))
836 return 1;
837 if (RT_FAILURE(testSetProp(&svcTable)))
838 return 1;
839 RTPrintf("Checking the data returned by the asynchronous notification call.\n");
840 /* Our previous notification call should have completed by now. */
841 if (RT_FAILURE(testAsyncNotification(&svcTable)))
842 return 1;
843 if (RT_FAILURE(testDelProp(&svcTable)))
844 return 1;
845 if (RT_FAILURE(testGetProp(&svcTable)))
846 return 1;
847 if (RT_FAILURE(testGetNotification(&svcTable)))
848 return 1;
849 RTPrintf("tstGuestPropSvc: SUCCEEDED.\n");
850 return 0;
851}
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