VirtualBox

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

Last change on this file since 98103 was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use