mirror of https://gitee.com/openkylin/libvirt.git
Introduce alternate way to encode/decode arrays in DBus messages
Currently the DBus helper APIs require the values for an array to be passed inline in the variadic argument list. This change introduces support for passing arrays using a pointer to a plain C array of the basic type. This is of particular benefit for decoding messages when you don't know how many array elements are being received. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
parent
217ac43e03
commit
2c64603366
|
@ -458,7 +458,7 @@ static int virDBusTypeStackPush(virDBusTypeStack **stack,
|
|||
(*stack)[(*nstack) - 1].types = types;
|
||||
(*stack)[(*nstack) - 1].nstruct = nstruct;
|
||||
(*stack)[(*nstack) - 1].narray = narray;
|
||||
VIR_DEBUG("Pushed '%s'", types);
|
||||
VIR_DEBUG("Pushed types='%s' nstruct=%zu narray=%zu", types, nstruct, narray);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -480,7 +480,7 @@ static int virDBusTypeStackPop(virDBusTypeStack **stack,
|
|||
*types = (*stack)[(*nstack) - 1].types;
|
||||
*nstruct = (*stack)[(*nstack) - 1].nstruct;
|
||||
*narray = (*stack)[(*nstack) - 1].narray;
|
||||
VIR_DEBUG("Popped '%s'", *types);
|
||||
VIR_DEBUG("Popped types='%s' nstruct=%zu narray=%zu", *types, *nstruct, *narray);
|
||||
VIR_SHRINK_N(*stack, *nstack, 1);
|
||||
|
||||
return 0;
|
||||
|
@ -503,16 +503,25 @@ static void virDBusTypeStackFree(virDBusTypeStack **stack,
|
|||
|
||||
# define SET_NEXT_VAL(dbustype, vargtype, sigtype, fmt) \
|
||||
do { \
|
||||
dbustype x = (dbustype)va_arg(args, vargtype); \
|
||||
dbustype x; \
|
||||
if (arrayref) { \
|
||||
vargtype *valarray = arrayptr; \
|
||||
x = (dbustype)*valarray; \
|
||||
valarray++; \
|
||||
arrayptr = valarray; \
|
||||
} else { \
|
||||
x = (dbustype)va_arg(args, vargtype); \
|
||||
} \
|
||||
if (!dbus_message_iter_append_basic(iter, sigtype, &x)) { \
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, \
|
||||
_("Cannot append basic type %s"), #vargtype); \
|
||||
_("Cannot append basic type %s"), #vargtype);\
|
||||
goto cleanup; \
|
||||
} \
|
||||
VIR_DEBUG("Appended basic type '" #dbustype "' varg '" #vargtype \
|
||||
VIR_DEBUG("Appended basic type '" #dbustype "' varg '" #vargtype\
|
||||
"' sig '%c' val '" fmt "'", sigtype, (vargtype)x); \
|
||||
} while (0)
|
||||
|
||||
|
||||
static int
|
||||
virDBusMessageIterEncode(DBusMessageIter *rootiter,
|
||||
const char *types,
|
||||
|
@ -521,6 +530,8 @@ virDBusMessageIterEncode(DBusMessageIter *rootiter,
|
|||
int ret = -1;
|
||||
size_t narray;
|
||||
size_t nstruct;
|
||||
bool arrayref = false;
|
||||
void *arrayptr = NULL;
|
||||
virDBusTypeStack *stack = NULL;
|
||||
size_t nstack = 0;
|
||||
size_t siglen;
|
||||
|
@ -546,6 +557,8 @@ virDBusMessageIterEncode(DBusMessageIter *rootiter,
|
|||
(narray == (size_t)-1 &&
|
||||
nstruct == 0)) {
|
||||
DBusMessageIter *thisiter = iter;
|
||||
arrayref = false;
|
||||
arrayptr = NULL;
|
||||
VIR_DEBUG("Popping iter=%p", iter);
|
||||
if (nstack == 0)
|
||||
break;
|
||||
|
@ -618,12 +631,32 @@ virDBusMessageIterEncode(DBusMessageIter *rootiter,
|
|||
break;
|
||||
|
||||
case DBUS_TYPE_ARRAY:
|
||||
arrayptr = NULL;
|
||||
if (t[1] == '&') {
|
||||
VIR_DEBUG("Got array ref");
|
||||
t++;
|
||||
types++;
|
||||
nstruct--;
|
||||
arrayref = true;
|
||||
} else {
|
||||
VIR_DEBUG("Got array non-ref");
|
||||
arrayref = false;
|
||||
}
|
||||
|
||||
if (virDBusSignatureLength(t + 1, &siglen) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (VIR_STRNDUP(contsig, t + 1, siglen) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (arrayref && (strlen(contsig) > 1 ||
|
||||
!virDBusIsBasicType(*contsig))) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Got array ref but '%s' is not a single basic type"),
|
||||
contsig);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (narray == (size_t)-1) {
|
||||
types += siglen;
|
||||
nstruct -= siglen;
|
||||
|
@ -646,7 +679,9 @@ virDBusMessageIterEncode(DBusMessageIter *rootiter,
|
|||
newiter = NULL;
|
||||
types = t + 1;
|
||||
nstruct = siglen;
|
||||
narray = va_arg(args, int);
|
||||
narray = (size_t)va_arg(args, int);
|
||||
if (arrayref)
|
||||
arrayptr = va_arg(args, void *);
|
||||
break;
|
||||
|
||||
case DBUS_TYPE_VARIANT:
|
||||
|
@ -712,8 +747,9 @@ virDBusMessageIterEncode(DBusMessageIter *rootiter,
|
|||
|
||||
default:
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Unknown type in signature '%s'"),
|
||||
types);
|
||||
_("Unknown type '%c' in signature '%s'"),
|
||||
*t, types);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -741,7 +777,16 @@ cleanup:
|
|||
|
||||
# define GET_NEXT_VAL(dbustype, vargtype, fmt) \
|
||||
do { \
|
||||
dbustype *x = (dbustype *)va_arg(args, vargtype *); \
|
||||
dbustype *x; \
|
||||
if (arrayref) { \
|
||||
vargtype **xptrptr = arrayptr; \
|
||||
if (VIR_EXPAND_N(*xptrptr, *narrayptr, 1) < 0) \
|
||||
goto cleanup; \
|
||||
x = (dbustype *)(*xptrptr + (*narrayptr - 1)); \
|
||||
VIR_DEBUG("Expanded to %zu", *narrayptr); \
|
||||
} else { \
|
||||
x = (dbustype *)va_arg(args, vargtype *); \
|
||||
} \
|
||||
dbus_message_iter_get_basic(iter, x); \
|
||||
VIR_DEBUG("Read basic type '" #dbustype "' varg '" #vargtype \
|
||||
"' val '" fmt "'", (vargtype)*x); \
|
||||
|
@ -756,6 +801,9 @@ virDBusMessageIterDecode(DBusMessageIter *rootiter,
|
|||
int ret = -1;
|
||||
size_t narray;
|
||||
size_t nstruct;
|
||||
bool arrayref = false;
|
||||
void *arrayptr = NULL;
|
||||
size_t *narrayptr = 0;
|
||||
virDBusTypeStack *stack = NULL;
|
||||
size_t nstack = 0;
|
||||
size_t siglen;
|
||||
|
@ -782,6 +830,8 @@ virDBusMessageIterDecode(DBusMessageIter *rootiter,
|
|||
(narray == (size_t)-1 &&
|
||||
nstruct == 0)) {
|
||||
DBusMessageIter *thisiter = iter;
|
||||
arrayref = false;
|
||||
arrayptr = NULL;
|
||||
VIR_DEBUG("Popping iter=%p", iter);
|
||||
if (nstack == 0)
|
||||
break;
|
||||
|
@ -851,7 +901,16 @@ virDBusMessageIterDecode(DBusMessageIter *rootiter,
|
|||
case DBUS_TYPE_OBJECT_PATH:
|
||||
case DBUS_TYPE_SIGNATURE:
|
||||
do {
|
||||
char **x = (char **)va_arg(args, char **);
|
||||
char **x;
|
||||
if (arrayref) {
|
||||
char ***xptrptr = arrayptr;
|
||||
if (VIR_EXPAND_N(*xptrptr, *narrayptr, 1) < 0)
|
||||
goto cleanup;
|
||||
x = (char **)(*xptrptr + (*narrayptr - 1));
|
||||
VIR_DEBUG("Expanded to %zu", *narrayptr);
|
||||
} else {
|
||||
x = (char **)va_arg(args, char **);
|
||||
}
|
||||
char *s;
|
||||
dbus_message_iter_get_basic(iter, &s);
|
||||
if (VIR_STRDUP(*x, s) < 0)
|
||||
|
@ -862,6 +921,18 @@ virDBusMessageIterDecode(DBusMessageIter *rootiter,
|
|||
break;
|
||||
|
||||
case DBUS_TYPE_ARRAY:
|
||||
arrayptr = NULL;
|
||||
if (t[1] == '&') {
|
||||
VIR_DEBUG("Got array ref");
|
||||
t++;
|
||||
types++;
|
||||
nstruct--;
|
||||
arrayref = true;
|
||||
} else {
|
||||
VIR_DEBUG("Got array non-ref");
|
||||
arrayref = false;
|
||||
}
|
||||
|
||||
advanceiter = false;
|
||||
if (virDBusSignatureLength(t + 1, &siglen) < 0)
|
||||
goto cleanup;
|
||||
|
@ -869,6 +940,14 @@ virDBusMessageIterDecode(DBusMessageIter *rootiter,
|
|||
if (VIR_STRNDUP(contsig, t + 1, siglen) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (arrayref && (strlen(contsig) > 1 ||
|
||||
!virDBusIsBasicType(*contsig))) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Got array ref but '%s' is not a single basic type"),
|
||||
contsig);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (narray == (size_t)-1) {
|
||||
types += siglen;
|
||||
nstruct -= siglen;
|
||||
|
@ -887,7 +966,14 @@ virDBusMessageIterDecode(DBusMessageIter *rootiter,
|
|||
newiter = NULL;
|
||||
types = t + 1;
|
||||
nstruct = siglen;
|
||||
narray = va_arg(args, int);
|
||||
if (arrayref) {
|
||||
narrayptr = va_arg(args, size_t *);
|
||||
arrayptr = va_arg(args, void *);
|
||||
*narrayptr = 0;
|
||||
*(char **)arrayptr = NULL;
|
||||
} else {
|
||||
narray = va_arg(args, int);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBUS_TYPE_VARIANT:
|
||||
|
@ -947,8 +1033,17 @@ virDBusMessageIterDecode(DBusMessageIter *rootiter,
|
|||
|
||||
default:
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Unknown type in signature '%s'"),
|
||||
types);
|
||||
_("Unknown type '%c' in signature '%s'"),
|
||||
*t, types);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (arrayref) {
|
||||
if (*t == '&' ||
|
||||
dbus_message_iter_has_next(iter))
|
||||
narray = 1;
|
||||
else
|
||||
narray = 0;
|
||||
}
|
||||
|
||||
VIR_DEBUG("After stack=%zu array=%zu struct=%zu type='%s'",
|
||||
|
|
|
@ -228,6 +228,97 @@ cleanup:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int testMessageArrayRef(const void *args ATTRIBUTE_UNUSED)
|
||||
{
|
||||
DBusMessage *msg = NULL;
|
||||
int ret = -1;
|
||||
const char *in_str1 = "Hello";
|
||||
int in_int32[] = {
|
||||
100000000, 2000000000, -2000000000
|
||||
};
|
||||
const char *in_strv1[] = {
|
||||
"Fishfood",
|
||||
};
|
||||
const char *in_strv2[] = {
|
||||
"Hello", "World",
|
||||
};
|
||||
int *out_int32 = NULL;
|
||||
size_t out_nint32 = 0;
|
||||
char **out_strv1 = NULL;
|
||||
char **out_strv2 = NULL;
|
||||
size_t out_nstrv1 = 0;
|
||||
size_t out_nstrv2 = 0;
|
||||
const char *in_str2 = "World";
|
||||
char *out_str1 = NULL, *out_str2 = NULL;
|
||||
|
||||
if (!(msg = dbus_message_new_method_call("org.libvirt.test",
|
||||
"/org/libvirt/test",
|
||||
"org.libvirt.test.astrochicken",
|
||||
"cluck"))) {
|
||||
VIR_DEBUG("Failed to allocate method call");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (virDBusMessageEncode(msg,
|
||||
"sa&sa&ia&ss",
|
||||
in_str1,
|
||||
1, in_strv1,
|
||||
3, in_int32,
|
||||
2, in_strv2,
|
||||
in_str2) < 0) {
|
||||
VIR_DEBUG("Failed to encode arguments");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (virDBusMessageDecode(msg,
|
||||
"sa&sa&ia&ss",
|
||||
&out_str1,
|
||||
&out_nstrv1, &out_strv1,
|
||||
&out_nint32, &out_int32,
|
||||
&out_nstrv2, &out_strv2,
|
||||
&out_str2) < 0) {
|
||||
VIR_DEBUG("Failed to decode arguments");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
VERIFY_STR("str1", in_str1, out_str1, "%s");
|
||||
if (out_nstrv1 != 1) {
|
||||
fprintf(stderr, "Expected 1 string, but got %zu\n",
|
||||
out_nstrv1);
|
||||
goto cleanup;
|
||||
}
|
||||
VERIFY_STR("strv1[0]", in_strv1[0], out_strv1[0], "%s");
|
||||
|
||||
if (out_nint32 != 3) {
|
||||
fprintf(stderr, "Expected 3 integers, but got %zu\n",
|
||||
out_nint32);
|
||||
goto cleanup;
|
||||
}
|
||||
VERIFY("int32a", in_int32[0], out_int32[0], "%d");
|
||||
VERIFY("int32b", in_int32[1], out_int32[1], "%d");
|
||||
VERIFY("int32c", in_int32[2], out_int32[2], "%d");
|
||||
|
||||
if (out_nstrv2 != 2) {
|
||||
fprintf(stderr, "Expected 2 strings, but got %zu\n",
|
||||
out_nstrv2);
|
||||
goto cleanup;
|
||||
}
|
||||
VERIFY_STR("strv2[0]", in_strv2[0], out_strv2[0], "%s");
|
||||
VERIFY_STR("strv2[1]", in_strv2[1], out_strv2[1], "%s");
|
||||
|
||||
VERIFY_STR("str2", in_str2, out_str2, "%s");
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
VIR_FREE(out_int32);
|
||||
VIR_FREE(out_str1);
|
||||
VIR_FREE(out_str2);
|
||||
dbus_message_unref(msg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int testMessageStruct(const void *args ATTRIBUTE_UNUSED)
|
||||
{
|
||||
DBusMessage *msg = NULL;
|
||||
|
@ -385,6 +476,8 @@ mymain(void)
|
|||
ret = -1;
|
||||
if (virtTestRun("Test message array ", testMessageArray, NULL) < 0)
|
||||
ret = -1;
|
||||
if (virtTestRun("Test message array ref ", testMessageArrayRef, NULL) < 0)
|
||||
ret = -1;
|
||||
if (virtTestRun("Test message struct ", testMessageStruct, NULL) < 0)
|
||||
ret = -1;
|
||||
if (virtTestRun("Test message dict ", testMessageDict, NULL) < 0)
|
||||
|
|
Loading…
Reference in New Issue