VirtualBox

source: vbox/trunk/include/VBox/HostServices/GuestPropertySvc.h@ 96316

Last change on this file since 96316 was 95338, checked in by vboxsync, 2 years ago

GuestPropertySvc.h,Main: Changed GuestPropValidateName and GuestPropValidateValue to take size_t instead of uint32_t, eliminating the need for a bunch of (uint32_t) casts. Call setErrorBoth when either of the two fails in Main. bugref:10185

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 19.6 KB
Line 
1/** @file
2 * Guest property service - Common header for host service and guest clients.
3 */
4
5/*
6 * Copyright (C) 2006-2022 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 *
16 * The contents of this file may alternatively be used under the terms
17 * of the Common Development and Distribution License Version 1.0
18 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
19 * VirtualBox OSE distribution, in which case the provisions of the
20 * CDDL are applicable instead of those of the GPL.
21 *
22 * You may elect to license modified versions of this file under the
23 * terms and conditions of either the GPL or the CDDL or both.
24 */
25
26#ifndef VBOX_INCLUDED_HostServices_GuestPropertySvc_h
27#define VBOX_INCLUDED_HostServices_GuestPropertySvc_h
28#ifndef RT_WITHOUT_PRAGMA_ONCE
29# pragma once
30#endif
31
32#include <VBox/VMMDevCoreTypes.h>
33#include <VBox/VBoxGuestCoreTypes.h>
34#include <VBox/log.h>
35#include <iprt/err.h>
36#include <iprt/assertcompile.h>
37#include <iprt/string.h>
38
39
40/** Maximum size for property names (including the terminator). */
41#define GUEST_PROP_MAX_NAME_LEN 64
42/** Maximum size for property values (including the terminator). */
43#define GUEST_PROP_MAX_VALUE_LEN 1024
44/** Maximum number of properties per guest. */
45#define GUEST_PROP_MAX_PROPS 256
46/** Maximum size for enumeration patterns (including the terminators). */
47#define GUEST_PROP_MAX_PATTERN_LEN 1024
48/** Maximum number of changes we remember for guest notifications. */
49#define GUEST_PROP_MAX_GUEST_NOTIFICATIONS 256
50/** Maximum number of current pending waits per client. */
51#define GUEST_PROP_MAX_GUEST_CONCURRENT_WAITS 16
52
53
54/** @name GUEST_PROP_F_XXX - The guest property flag values which are currently accepted.
55 * @{
56 */
57#define GUEST_PROP_F_NILFLAG UINT32_C(0)
58/** Transient until VM gets shut down. */
59#define GUEST_PROP_F_TRANSIENT RT_BIT_32(1)
60#define GUEST_PROP_F_RDONLYGUEST RT_BIT_32(2)
61#define GUEST_PROP_F_RDONLYHOST RT_BIT_32(3)
62/** Transient until VM gets a reset / restarts.
63 * Implies TRANSIENT. */
64#define GUEST_PROP_F_TRANSRESET RT_BIT_32(4)
65#define GUEST_PROP_F_READONLY (GUEST_PROP_F_RDONLYGUEST | GUEST_PROP_F_RDONLYHOST)
66#define GUEST_PROP_F_ALLFLAGS (GUEST_PROP_F_TRANSIENT | GUEST_PROP_F_READONLY | GUEST_PROP_F_TRANSRESET)
67/** @} */
68
69/**
70 * Check that a string fits our criteria for a property name.
71 *
72 * @returns IPRT status code
73 * @param pszName The string to check, must be valid Utf8
74 * @param cbName The number of bytes @a pszName points to, including the
75 * terminating character.
76 */
77DECLINLINE(int) GuestPropValidateName(const char *pszName, size_t cbName)
78{
79 /* Property name is expected to be at least 1 charecter long plus terminating character. */
80 AssertReturn(cbName >= 2, VERR_INVALID_PARAMETER);
81 AssertReturn(cbName <= GUEST_PROP_MAX_NAME_LEN, VERR_INVALID_PARAMETER);
82
83 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
84
85 AssertReturn(memchr(pszName, '*', cbName) == NULL, VERR_INVALID_PARAMETER);
86 AssertReturn(memchr(pszName, '?', cbName) == NULL, VERR_INVALID_PARAMETER);
87 AssertReturn(memchr(pszName, '|', cbName) == NULL, VERR_INVALID_PARAMETER);
88
89 return VINF_SUCCESS;
90}
91
92/**
93 * Check a string fits our criteria for the value of a guest property.
94 *
95 * @returns IPRT status code
96 * @retval VINF_SUCCESS if guest property value corresponds to all criteria.
97 * @retval VERR_TOO_MUCH_DATA if guest property value size exceeds limits.
98 * @retval VERR_INVALID_PARAMETER if guest property does not correspond to all other criteria.
99 * @param pszValue The string to check, must be valid utf-8.
100 * @param cbValue The size of of @a pszValue in bytes, including the
101 * terminator.
102 * @thread HGCM
103 */
104DECLINLINE(int) GuestPropValidateValue(const char *pszValue, size_t cbValue)
105{
106 AssertPtrReturn(pszValue, VERR_INVALID_POINTER);
107
108 /* Zero-length values are possible, however buffer should contain terminating character at least. */
109 AssertReturn(cbValue > 0, VERR_INVALID_PARAMETER);
110 AssertReturn(cbValue <= GUEST_PROP_MAX_VALUE_LEN, VERR_TOO_MUCH_DATA);
111
112 return VINF_SUCCESS;
113}
114
115/**
116 * Get the name of a flag as a string.
117 * @returns the name, or NULL if fFlag is invalid.
118 * @param fFlag The flag, GUEST_PROP_F_XXX.
119 * @param pcchName Where to return the name length.
120 */
121DECLINLINE(const char *) GuestPropFlagNameAndLen(uint32_t fFlag, size_t *pcchName)
122{
123 switch (fFlag)
124 {
125 case GUEST_PROP_F_TRANSIENT:
126 *pcchName = sizeof("TRANSIENT") - 1;
127 return "TRANSIENT";
128 case GUEST_PROP_F_RDONLYGUEST:
129 *pcchName = sizeof("RDONLYGUEST") - 1;
130 return "RDONLYGUEST";
131 case GUEST_PROP_F_RDONLYHOST:
132 *pcchName = sizeof("RDONLYHOST") - 1;
133 return "RDONLYHOST";
134 case GUEST_PROP_F_READONLY:
135 *pcchName = sizeof("READONLY") - 1;
136 return "READONLY";
137 case GUEST_PROP_F_TRANSRESET:
138 *pcchName = sizeof("TRANSRESET") - 1;
139 return "TRANSRESET";
140 default:
141 *pcchName = 0;
142 return NULL;
143 }
144}
145
146/**
147 * Maximum length for the property flags field. We only ever return one of
148 * RDONLYGUEST, RDONLYHOST and RDONLY
149 */
150#define GUEST_PROP_MAX_FLAGS_LEN sizeof("TRANSIENT, RDONLYGUEST, TRANSRESET")
151
152/**
153 * Parse a guest properties flags string for flag names and make sure that
154 * there is no junk text in the string.
155 *
156 * @returns IPRT status code
157 * @retval VERR_INVALID_PARAMETER if the flag string is not valid
158 * @param pcszFlags the flag string to parse
159 * @param pfFlags where to store the parse result. May not be NULL.
160 * @note This function is also inline because it must be accessible from
161 * several modules and it does not seem reasonable to put it into
162 * its own library.
163 */
164DECLINLINE(int) GuestPropValidateFlags(const char *pcszFlags, uint32_t *pfFlags)
165{
166 static const uint32_t s_aFlagList[] =
167 {
168 GUEST_PROP_F_TRANSIENT, GUEST_PROP_F_READONLY, GUEST_PROP_F_RDONLYGUEST, GUEST_PROP_F_RDONLYHOST, GUEST_PROP_F_TRANSRESET
169 };
170 const char *pcszNext = pcszFlags;
171 int rc = VINF_SUCCESS;
172 uint32_t fFlags = 0;
173 AssertLogRelReturn(RT_VALID_PTR(pfFlags), VERR_INVALID_POINTER);
174
175 if (pcszFlags)
176 {
177 while (*pcszNext == ' ')
178 ++pcszNext;
179 while ((*pcszNext != '\0') && RT_SUCCESS(rc))
180 {
181 unsigned i;
182 rc = VERR_PARSE_ERROR;
183 for (i = 0; i < RT_ELEMENTS(s_aFlagList); ++i)
184 {
185 size_t cchFlagName;
186 const char *pszFlagName = GuestPropFlagNameAndLen(s_aFlagList[i], &cchFlagName);
187 if (RTStrNICmpAscii(pcszNext, pszFlagName, cchFlagName) == 0)
188 {
189 char ch;
190 fFlags |= s_aFlagList[i];
191 pcszNext += cchFlagName;
192 while ((ch = *pcszNext) == ' ')
193 ++pcszNext;
194 rc = VINF_SUCCESS;
195 if (ch == ',')
196 {
197 ++pcszNext;
198 while (*pcszNext == ' ')
199 ++pcszNext;
200 }
201 else if (ch != '\0')
202 rc = VERR_PARSE_ERROR;
203 break;
204 }
205 }
206 }
207 }
208 if (RT_SUCCESS(rc))
209 *pfFlags = fFlags;
210 return rc;
211}
212
213
214/**
215 * Write out flags to a string.
216 * @returns IPRT status code
217 * @param fFlags the flags to write out
218 * @param pszFlags where to write the flags string. This must point to
219 * a buffer of size (at least) GUEST_PROP_MAX_FLAGS_LEN.
220 */
221DECLINLINE(int) GuestPropWriteFlags(uint32_t fFlags, char *pszFlags)
222{
223 /* Putting READONLY before the other RDONLY flags keeps the result short. */
224 static const uint32_t s_aFlagList[] =
225 {
226 GUEST_PROP_F_TRANSIENT, GUEST_PROP_F_READONLY, GUEST_PROP_F_RDONLYGUEST, GUEST_PROP_F_RDONLYHOST, GUEST_PROP_F_TRANSRESET
227 };
228 int rc = VINF_SUCCESS;
229
230 AssertLogRelReturn(RT_VALID_PTR(pszFlags), VERR_INVALID_POINTER);
231 if ((fFlags & ~GUEST_PROP_F_ALLFLAGS) == GUEST_PROP_F_NILFLAG)
232 {
233 char *pszNext;
234 unsigned i;
235
236 /* TRANSRESET implies TRANSIENT. For compatability with old clients we
237 always set TRANSIENT when TRANSRESET appears. */
238 if (fFlags & GUEST_PROP_F_TRANSRESET)
239 fFlags |= GUEST_PROP_F_TRANSIENT;
240
241 pszNext = pszFlags;
242 for (i = 0; i < RT_ELEMENTS(s_aFlagList); ++i)
243 {
244 if (s_aFlagList[i] == (fFlags & s_aFlagList[i]))
245 {
246 size_t cchFlagName;
247 const char *pszFlagName = GuestPropFlagNameAndLen(s_aFlagList[i], &cchFlagName);
248 memcpy(pszNext, pszFlagName, cchFlagName);
249 pszNext += cchFlagName;
250 fFlags &= ~s_aFlagList[i];
251 if (fFlags != GUEST_PROP_F_NILFLAG)
252 {
253 *pszNext++ = ',';
254 *pszNext++ = ' ';
255 }
256 }
257 }
258 *pszNext = '\0';
259
260 Assert((uintptr_t)(pszNext - pszFlags) < GUEST_PROP_MAX_FLAGS_LEN);
261 Assert(fFlags == GUEST_PROP_F_NILFLAG); /* bad s_aFlagList */
262 }
263 else
264 rc = VERR_INVALID_PARAMETER;
265 return rc;
266}
267
268
269/** @name The service functions which are callable by host.
270 * @{
271 */
272/** Set properties in a block.
273 * The parameters are pointers to NULL-terminated arrays containing the
274 * parameters. These are, in order, name, value, timestamp, flags. Strings are
275 * stored as pointers to mutable utf8 data. All parameters must be supplied. */
276#define GUEST_PROP_FN_HOST_SET_PROPS 1
277/** Get the value attached to a guest property.
278 * The parameter format matches that of GET_PROP. */
279#define GUEST_PROP_FN_HOST_GET_PROP 2
280/** Set the value attached to a guest property.
281 * The parameter format matches that of SET_PROP. */
282#define GUEST_PROP_FN_HOST_SET_PROP 3
283/** Set the value attached to a guest property.
284 * The parameter format matches that of SET_PROP_VALUE. */
285#define GUEST_PROP_FN_HOST_SET_PROP_VALUE 4
286/** Remove a guest property.
287 * The parameter format matches that of DEL_PROP. */
288#define GUEST_PROP_FN_HOST_DEL_PROP 5
289/** Enumerate guest properties.
290 * The parameter format matches that of ENUM_PROPS. */
291#define GUEST_PROP_FN_HOST_ENUM_PROPS 6
292/** Set global flags for the service.
293 * Currently RDONLYGUEST is supported. Takes one 32-bit unsigned integer
294 * parameter for the flags. */
295#define GUEST_PROP_FN_HOST_SET_GLOBAL_FLAGS 7
296/** @} */
297
298
299/** @name The service functions which are called by guest.
300 *
301 * @note The numbers may not change!
302 * @{
303 */
304/** Get a guest property */
305#define GUEST_PROP_FN_GET_PROP 1
306/** Set a guest property */
307#define GUEST_PROP_FN_SET_PROP 2
308/** Set just the value of a guest property */
309#define GUEST_PROP_FN_SET_PROP_VALUE 3
310/** Delete a guest property */
311#define GUEST_PROP_FN_DEL_PROP 4
312/** Enumerate guest properties */
313#define GUEST_PROP_FN_ENUM_PROPS 5
314/** Poll for guest notifications */
315#define GUEST_PROP_FN_GET_NOTIFICATION 6
316/** @} */
317
318
319/**
320 * Data structure to pass to the service extension callback.
321 * We use this to notify the host of changes to properties.
322 */
323typedef struct GUESTPROPHOSTCALLBACKDATA
324{
325 /** Magic number to identify the structure (GUESTPROPHOSTCALLBACKDATA_MAGIC). */
326 uint32_t u32Magic;
327 /** The name of the property that was changed */
328 const char *pcszName;
329 /** The new property value, or NULL if the property was deleted */
330 const char *pcszValue;
331 /** The timestamp of the modification */
332 uint64_t u64Timestamp;
333 /** The flags field of the modified property */
334 const char *pcszFlags;
335} GUESTPROPHOSTCALLBACKDATA;
336/** Poitner to a data structure to pass to the service extension callback. */
337typedef GUESTPROPHOSTCALLBACKDATA *PGUESTPROPHOSTCALLBACKDATA;
338
339/** Magic number for sanity checking the HOSTCALLBACKDATA structure */
340#define GUESTPROPHOSTCALLBACKDATA_MAGIC UINT32_C(0x69c87a78)
341
342/**
343 * HGCM parameter structures. Packing is explicitly defined as this is a wire format.
344 */
345/** The guest is requesting the value of a property */
346typedef struct GuestPropMsgGetProperty
347{
348 VBGLIOCHGCMCALL hdr;
349
350 /**
351 * The property name (IN pointer)
352 * This must fit to a number of criteria, namely
353 * - Only Utf8 strings are allowed
354 * - Less than or equal to MAX_NAME_LEN bytes in length
355 * - Zero terminated
356 */
357 HGCMFunctionParameter name;
358
359 /**
360 * The returned string data will be placed here. (OUT pointer)
361 * This call returns two null-terminated strings which will be placed one
362 * after another: value and flags.
363 */
364 HGCMFunctionParameter buffer;
365
366 /**
367 * The property timestamp. (OUT uint64_t)
368 */
369 HGCMFunctionParameter timestamp;
370
371 /**
372 * If the buffer provided was large enough this will contain the size of
373 * the returned data. Otherwise it will contain the size of the buffer
374 * needed to hold the data and VERR_BUFFER_OVERFLOW will be returned.
375 * (OUT uint32_t)
376 */
377 HGCMFunctionParameter size;
378} GuestPropMsgGetProperty;
379AssertCompileSize(GuestPropMsgGetProperty, 40 + 4 * (ARCH_BITS == 64 ? 16 : 12));
380
381/** The guest is requesting to change a property */
382typedef struct GuestPropMsgSetProperty
383{
384 VBGLIOCHGCMCALL hdr;
385
386 /**
387 * The property name. (IN pointer)
388 * This must fit to a number of criteria, namely
389 * - Only Utf8 strings are allowed
390 * - Less than or equal to MAX_NAME_LEN bytes in length
391 * - Zero terminated
392 */
393 HGCMFunctionParameter name;
394
395 /**
396 * The value of the property (IN pointer)
397 * Criteria as for the name parameter, but with length less than or equal to
398 * MAX_VALUE_LEN.
399 */
400 HGCMFunctionParameter value;
401
402 /**
403 * The property flags (IN pointer)
404 * This is a comma-separated list of the format flag=value
405 * The length must be less than or equal to GUEST_PROP_MAX_FLAGS_LEN and only
406 * known flag names and values will be accepted.
407 */
408 HGCMFunctionParameter flags;
409} GuestPropMsgSetProperty;
410AssertCompileSize(GuestPropMsgSetProperty, 40 + 3 * (ARCH_BITS == 64 ? 16 : 12));
411
412/** The guest is requesting to change the value of a property */
413typedef struct GuestPropMsgSetPropertyValue
414{
415 VBGLIOCHGCMCALL hdr;
416
417 /**
418 * The property name. (IN pointer)
419 * This must fit to a number of criteria, namely
420 * - Only Utf8 strings are allowed
421 * - Less than or equal to MAX_NAME_LEN bytes in length
422 * - Zero terminated
423 */
424 HGCMFunctionParameter name;
425
426 /**
427 * The value of the property (IN pointer)
428 * Criteria as for the name parameter, but with length less than or equal to
429 * MAX_VALUE_LEN.
430 */
431 HGCMFunctionParameter value;
432} GuestPropMsgSetPropertyValue;
433AssertCompileSize(GuestPropMsgSetPropertyValue, 40 + 2 * (ARCH_BITS == 64 ? 16 : 12));
434
435/** The guest is requesting to remove a property */
436typedef struct GuestPropMsgDelProperty
437{
438 VBGLIOCHGCMCALL hdr;
439
440 /**
441 * The property name. This must fit to a number of criteria, namely
442 * - Only Utf8 strings are allowed
443 * - Less than or equal to MAX_NAME_LEN bytes in length
444 * - Zero terminated
445 */
446 HGCMFunctionParameter name;
447} GuestPropMsgDelProperty;
448AssertCompileSize(GuestPropMsgDelProperty, 40 + 1 * (ARCH_BITS == 64 ? 16 : 12));
449
450/** The guest is requesting to enumerate properties */
451typedef struct GuestPropMsgEnumProperties
452{
453 VBGLIOCHGCMCALL hdr;
454
455 /**
456 * Array of patterns to match the properties against, separated by '|'
457 * characters. For backwards compatibility, '\\0' is also accepted
458 * as a separater.
459 * (IN pointer)
460 * If only a single, empty pattern is given then match all.
461 */
462 HGCMFunctionParameter patterns;
463 /**
464 * On success, null-separated array of strings in which the properties are
465 * returned. (OUT pointer)
466 * The number of strings in the array is always a multiple of four,
467 * and in sequences of name, value, timestamp (hexadecimal string) and the
468 * flags as a comma-separated list in the format "name=value". The list
469 * is terminated by an empty string after a "flags" entry (or at the
470 * start).
471 */
472 HGCMFunctionParameter strings;
473 /**
474 * On success, the size of the returned data. If the buffer provided is
475 * too small, the size of buffer needed. (OUT uint32_t)
476 */
477 HGCMFunctionParameter size;
478} GuestPropMsgEnumProperties;
479AssertCompileSize(GuestPropMsgEnumProperties, 40 + 3 * (ARCH_BITS == 64 ? 16 : 12));
480
481/**
482 * The guest is polling for notifications on changes to properties, specifying
483 * a set of patterns to match the names of changed properties against and
484 * optionally the timestamp of the last notification seen.
485 * On success, VINF_SUCCESS will be returned and the buffer will contain
486 * details of a property notification. If no new notification is available
487 * which matches one of the specified patterns, the call will block until one
488 * is.
489 * If the last notification could not be found by timestamp, VWRN_NOT_FOUND
490 * will be returned and the oldest available notification will be returned.
491 * If a zero timestamp is specified, the call will always wait for a new
492 * notification to arrive.
493 * If the buffer supplied was not large enough to hold the notification,
494 * VERR_BUFFER_OVERFLOW will be returned and the size parameter will contain
495 * the size of the buffer needed.
496 *
497 * The protocol for a guest to obtain notifications is to call
498 * GET_NOTIFICATION in a loop. On the first call, the ingoing timestamp
499 * parameter should be set to zero. On subsequent calls, it should be set to
500 * the outgoing timestamp from the previous call.
501 */
502typedef struct GuestPropMsgGetNotification
503{
504 VBGLIOCHGCMCALL hdr;
505
506 /**
507 * A list of patterns to match the guest event name against, separated by
508 * vertical bars (|) (IN pointer)
509 * An empty string means match all.
510 */
511 HGCMFunctionParameter patterns;
512 /**
513 * The timestamp of the last change seen (IN uint64_t)
514 * This may be zero, in which case the oldest available change will be
515 * sent. If the service does not remember an event matching the
516 * timestamp, then VWRN_NOT_FOUND will be returned, and the guest should
517 * assume that it has missed a certain number of notifications.
518 *
519 * The timestamp of the change being notified of (OUT uint64_t)
520 * Undefined on failure.
521 */
522 HGCMFunctionParameter timestamp;
523
524 /**
525 * The returned data, if any, will be placed here. (OUT pointer)
526 * This call returns three null-terminated strings which will be placed
527 * one after another: name, value and flags. For a delete notification,
528 * value and flags will be empty strings. Undefined on failure.
529 */
530 HGCMFunctionParameter buffer;
531
532 /**
533 * On success, the size of the returned data. (OUT uint32_t)
534 * On buffer overflow, the size of the buffer needed to hold the data.
535 * Undefined on failure.
536 */
537 HGCMFunctionParameter size;
538} GuestPropMsgGetNotification;
539AssertCompileSize(GuestPropMsgGetNotification, 40 + 4 * (ARCH_BITS == 64 ? 16 : 12));
540
541
542#endif /* !VBOX_INCLUDED_HostServices_GuestPropertySvc_h */
543
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