Currently DBus dict values must be passed inline
virDBusMessageEncode("a{ss}",
3,
"key1", "val1",
"key2", "val2",
"key3", "val3");
virDBusMessageDecode("a{ss}",
3,
&key1, &val1,
&key2, &val2,
&key3, &val3);
This allows them to be passed by reference
const char **dictin = {
"key1", "val1",
"key2", "val2",
"key3", "val3"
};
char **dictout;
size_t ndictout;
virDBusMessageEncode("a&{ss}",
ARRAY_CARDINALITY(dict) / 2,
dictin);
virDBusMessageDecode("a&{ss}",
&ndictout,
&dictout);
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
src/util/virdbus.c | 274 +++++++++++++++++++++++++++++++++++----------------
src/util/virstring.c | 14 +++
src/util/virstring.h | 2 +
tests/virdbustest.c | 218 +++++++++++++++++++++++++++++++++++++++-
4 files changed, 423 insertions(+), 85 deletions(-)
diff --git a/src/util/virdbus.c b/src/util/virdbus.c
index a63338a..dc3a535 100644
--- a/src/util/virdbus.c
+++ b/src/util/virdbus.c
@@ -313,15 +313,18 @@ virDBusSignatureLengthInternal(const char *s,
bool allowDict,
unsigned arrayDepth,
unsigned structDepth,
- size_t *l)
+ size_t *skiplen,
+ size_t *siglen)
{
if (virDBusIsBasicType(*s) || *s == DBUS_TYPE_VARIANT) {
- *l = 1;
+ *skiplen = *siglen = 1;
return 0;
}
if (*s == DBUS_TYPE_ARRAY) {
- size_t t;
+ size_t skiplencont;
+ size_t siglencont;
+ bool arrayref = false;
if (arrayDepth >= VIR_DBUS_TYPE_STACK_MAX_DEPTH) {
virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -330,14 +333,23 @@ virDBusSignatureLengthInternal(const char *s,
return -1;
}
+ if (*(s + 1) == '&') {
+ arrayref = true;
+ s++;
+ }
+
if (virDBusSignatureLengthInternal(s + 1,
true,
arrayDepth + 1,
structDepth,
- &t) < 0)
+ &skiplencont,
+ &siglencont) < 0)
return -1;
- *l = t + 1;
+ *skiplen = skiplencont + 1;
+ *siglen = siglencont + 1;
+ if (arrayref)
+ (*skiplen)++;
return 0;
}
@@ -351,20 +363,25 @@ virDBusSignatureLengthInternal(const char *s,
return -1;
}
+ *skiplen = *siglen = 2;
+
while (*p != DBUS_STRUCT_END_CHAR) {
- size_t t;
+ size_t skiplencont;
+ size_t siglencont;
if (virDBusSignatureLengthInternal(p,
false,
arrayDepth,
structDepth + 1,
- &t) < 0)
+ &skiplencont,
+ &siglencont) < 0)
return -1;
- p += t;
+ p += skiplencont;
+ *skiplen += skiplencont;
+ *siglen += siglencont;
}
- *l = p - s + 1;
return 0;
}
@@ -378,8 +395,11 @@ virDBusSignatureLengthInternal(const char *s,
return -1;
}
+ *skiplen = *siglen = 2;
+
while (*p != DBUS_DICT_ENTRY_END_CHAR) {
- size_t t;
+ size_t skiplencont;
+ size_t siglencont;
if (n == 0 && !virDBusIsBasicType(*p)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -392,10 +412,13 @@ virDBusSignatureLengthInternal(const char *s,
false,
arrayDepth,
structDepth + 1,
- &t) < 0)
+ &skiplencont,
+ &siglencont) < 0)
return -1;
- p += t;
+ p += skiplencont;
+ *skiplen += skiplencont;
+ *siglen += siglencont;
n++;
}
@@ -406,7 +429,6 @@ virDBusSignatureLengthInternal(const char *s,
return -1;
}
- *l = p - s + 1;
return 0;
}
@@ -416,12 +438,40 @@ virDBusSignatureLengthInternal(const char *s,
}
-static int virDBusSignatureLength(const char *s, size_t *l)
+static int virDBusSignatureLength(const char *s, size_t *skiplen, size_t *siglen)
{
- return virDBusSignatureLengthInternal(s, true, 0, 0, l);
+ return virDBusSignatureLengthInternal(s, true, 0, 0, skiplen, siglen);
}
+static char *virDBusCopyContainerSignature(const char *sig,
+ size_t *skiplen,
+ size_t *siglen)
+{
+ size_t i, j;
+ char *contsig;
+ bool isGroup;
+
+ isGroup = (sig[0] == DBUS_STRUCT_BEGIN_CHAR ||
+ sig[0] == DBUS_DICT_ENTRY_BEGIN_CHAR);
+
+ if (virDBusSignatureLength(isGroup ? sig : sig + 1, skiplen, siglen) < 0)
+ return NULL;
+
+ if (VIR_ALLOC_N(contsig, *siglen + 1) < 0)
+ return NULL;
+
+ for (i = 0, j = 0; i < *skiplen && j < *siglen; i++) {
+ if (sig[i + 1] == '&')
+ continue;
+ contsig[j] = sig[i + 1];
+ j++;
+ }
+ contsig[*siglen] = '\0';
+ VIR_DEBUG("Extracted '%s' from '%s'", contsig, sig);
+ return contsig;
+}
+
/* Ideally, we'd just call ourselves recursively on every
* complex type. However, the state of a va_list that is
@@ -458,7 +508,8 @@ static int virDBusTypeStackPush(virDBusTypeStack **stack,
(*stack)[(*nstack) - 1].types = types;
(*stack)[(*nstack) - 1].nstruct = nstruct;
(*stack)[(*nstack) - 1].narray = narray;
- VIR_DEBUG("Pushed types='%s' nstruct=%zu narray=%zu", types,
nstruct, narray);
+ VIR_DEBUG("Pushed types='%s' nstruct=%zu narray=%zd",
+ types, nstruct, (ssize_t)narray);
return 0;
}
@@ -480,7 +531,8 @@ static int virDBusTypeStackPop(virDBusTypeStack **stack,
*types = (*stack)[(*nstack) - 1].types;
*nstruct = (*stack)[(*nstack) - 1].nstruct;
*narray = (*stack)[(*nstack) - 1].narray;
- VIR_DEBUG("Popped types='%s' nstruct=%zu narray=%zu", *types,
*nstruct, *narray);
+ VIR_DEBUG("Popped types='%s' nstruct=%zu narray=%zd",
+ *types, *nstruct, (ssize_t)*narray);
VIR_SHRINK_N(*stack, *nstack, 1);
return 0;
@@ -501,6 +553,28 @@ static void virDBusTypeStackFree(virDBusTypeStack **stack,
}
+static bool
+virDBusIsAllowedRefType(const char *sig)
+{
+ if (*sig == '{') {
+ if (strlen(sig) != 4)
+ return false;
+ if (!virDBusIsBasicType(sig[1]) ||
+ !virDBusIsBasicType(sig[2]) ||
+ sig[1] != sig[2])
+ return false;
+ if (sig[3] != '}')
+ return false;
+ } else {
+ if (strlen(sig) != 1)
+ return false;
+ if (!virDBusIsBasicType(sig[0]))
+ return false;
+ }
+ return true;
+}
+
+
# define SET_NEXT_VAL(dbustype, vargtype, sigtype, fmt) \
do { \
dbustype x; \
@@ -535,6 +609,7 @@ virDBusMessageIterEncode(DBusMessageIter *rootiter,
virDBusTypeStack *stack = NULL;
size_t nstack = 0;
size_t siglen;
+ size_t skiplen;
char *contsig = NULL;
const char *vsig;
DBusMessageIter *newiter = NULL;
@@ -551,14 +626,17 @@ virDBusMessageIterEncode(DBusMessageIter *rootiter,
for (;;) {
const char *t;
- VIR_DEBUG("Loop stack=%zu array=%zu struct=%zu type='%s'",
- nstack, narray, nstruct, types);
+ VIR_DEBUG("Loop nstack=%zu narray=%zd nstruct=%zu types='%s'",
+ nstack, (ssize_t)narray, nstruct, types);
if (narray == 0 ||
(narray == (size_t)-1 &&
nstruct == 0)) {
DBusMessageIter *thisiter = iter;
- arrayref = false;
- arrayptr = NULL;
+ if (*types != '}') {
+ VIR_DEBUG("Reset array ref");
+ arrayref = false;
+ arrayptr = NULL;
+ }
VIR_DEBUG("Popping iter=%p", iter);
if (nstack == 0)
break;
@@ -643,28 +721,25 @@ virDBusMessageIterEncode(DBusMessageIter *rootiter,
arrayref = false;
}
- if (virDBusSignatureLength(t + 1, &siglen) < 0)
+ if (!(contsig = virDBusCopyContainerSignature(t, &skiplen,
&siglen)))
goto cleanup;
- if (VIR_STRNDUP(contsig, t + 1, siglen) < 0)
- goto cleanup;
-
- if (arrayref && (strlen(contsig) > 1 ||
- !virDBusIsBasicType(*contsig))) {
+ if (arrayref && !virDBusIsAllowedRefType(contsig)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Got array ref but '%s' is not a single
basic type"),
+ _("Got array ref but '%s' is not a single
basic type "
+ "or dict with matching key+value type"),
contsig);
goto cleanup;
}
if (narray == (size_t)-1) {
- types += siglen;
- nstruct -= siglen;
+ types += skiplen;
+ nstruct -= skiplen;
}
if (VIR_ALLOC(newiter) < 0)
goto cleanup;
- VIR_DEBUG("Contsig '%s' '%zu'", contsig, siglen);
+ VIR_DEBUG("Contsig '%s' skip='%zu'
len='%zu'", contsig, skiplen, siglen);
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
contsig, newiter))
goto cleanup;
@@ -678,7 +753,7 @@ virDBusMessageIterEncode(DBusMessageIter *rootiter,
iter = newiter;
newiter = NULL;
types = t + 1;
- nstruct = siglen;
+ nstruct = skiplen;
narray = (size_t)va_arg(args, int);
if (arrayref)
arrayptr = va_arg(args, void *);
@@ -711,23 +786,20 @@ virDBusMessageIterEncode(DBusMessageIter *rootiter,
case DBUS_STRUCT_BEGIN_CHAR:
case DBUS_DICT_ENTRY_BEGIN_CHAR:
- if (virDBusSignatureLength(t, &siglen) < 0)
- goto cleanup;
-
- if (VIR_STRNDUP(contsig, t + 1, siglen - 1) < 0)
+ if (!(contsig = virDBusCopyContainerSignature(t, &skiplen,
&siglen)))
goto cleanup;
if (VIR_ALLOC(newiter) < 0)
goto cleanup;
- VIR_DEBUG("Contsig '%s' '%zu'", contsig, siglen);
+ VIR_DEBUG("Contsig '%s' skip='%zu'
len='%zu'", contsig, skiplen, siglen);
if (!dbus_message_iter_open_container(iter,
*t == DBUS_STRUCT_BEGIN_CHAR ?
DBUS_TYPE_STRUCT :
DBUS_TYPE_DICT_ENTRY,
NULL, newiter))
goto cleanup;
if (narray == (size_t)-1) {
- types += siglen - 1;
- nstruct -= siglen - 1;
+ types += skiplen - 1;
+ nstruct -= skiplen - 1;
}
if (virDBusTypeStackPush(&stack, &nstack,
@@ -740,15 +812,15 @@ virDBusMessageIterEncode(DBusMessageIter *rootiter,
iter = newiter;
newiter = NULL;
types = t + 1;
- nstruct = siglen - 2;
+ nstruct = skiplen - 2;
narray = (size_t)-1;
break;
default:
virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Unknown type '%c' in signature
'%s'"),
- *t, types);
+ _("Unknown type '%x' in signature
'%s'"),
+ (int)*t, types);
goto cleanup;
}
}
@@ -779,6 +851,7 @@ virDBusMessageIterEncode(DBusMessageIter *rootiter,
do { \
dbustype *x; \
if (arrayref) { \
+ VIR_DEBUG("Use arrayref"); \
vargtype **xptrptr = arrayptr; \
if (VIR_EXPAND_N(*xptrptr, *narrayptr, 1) < 0) \
goto cleanup; \
@@ -806,6 +879,7 @@ virDBusMessageIterDecode(DBusMessageIter *rootiter,
size_t *narrayptr = 0;
virDBusTypeStack *stack = NULL;
size_t nstack = 0;
+ size_t skiplen;
size_t siglen;
char *contsig = NULL;
const char *vsig;
@@ -824,14 +898,12 @@ virDBusMessageIterDecode(DBusMessageIter *rootiter,
const char *t;
bool advanceiter = true;
- VIR_DEBUG("Loop stack=%zu array=%zu struct=%zu type='%s'",
- nstack, narray, nstruct, types);
+ VIR_DEBUG("Loop nstack=%zu narray=%zd nstruct=%zu type='%s'",
+ nstack, (ssize_t)narray, nstruct, types);
if (narray == 0 ||
(narray == (size_t)-1 &&
nstruct == 0)) {
DBusMessageIter *thisiter = iter;
- arrayref = false;
- arrayptr = NULL;
VIR_DEBUG("Popping iter=%p", iter);
if (nstack == 0)
break;
@@ -839,8 +911,20 @@ virDBusMessageIterDecode(DBusMessageIter *rootiter,
&types, &nstruct, &narray) < 0)
goto cleanup;
VIR_DEBUG("Popped iter=%p types=%s", iter, types);
+ if (strchr(types, '}') == NULL) {
+ arrayref = false;
+ arrayptr = NULL;
+ VIR_DEBUG("Clear array ref flag");
+ }
if (thisiter != rootiter)
VIR_FREE(thisiter);
+ if (arrayref) {
+ if (!dbus_message_iter_has_next(iter))
+ narray = 0;
+ else
+ narray = 1;
+ VIR_DEBUG("Pop set narray=%zd", (ssize_t)narray);
+ }
if (!(narray == 0 ||
(narray == (size_t)-1 &&
nstruct == 0)) &&
@@ -854,7 +938,8 @@ virDBusMessageIterDecode(DBusMessageIter *rootiter,
t = types;
if (narray != (size_t)-1) {
- narray--;
+ if (!arrayref)
+ narray--;
} else {
types++;
nstruct--;
@@ -934,28 +1019,25 @@ virDBusMessageIterDecode(DBusMessageIter *rootiter,
}
advanceiter = false;
- if (virDBusSignatureLength(t + 1, &siglen) < 0)
- goto cleanup;
-
- if (VIR_STRNDUP(contsig, t + 1, siglen) < 0)
+ if (!(contsig = virDBusCopyContainerSignature(t, &skiplen,
&siglen)))
goto cleanup;
- if (arrayref && (strlen(contsig) > 1 ||
- !virDBusIsBasicType(*contsig))) {
+ if (arrayref && !virDBusIsAllowedRefType(contsig)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Got array ref but '%s' is not a single
basic type"),
+ _("Got array ref but '%s' is not a single
basic type / dict"),
contsig);
goto cleanup;
}
if (narray == (size_t)-1) {
- types += siglen;
- nstruct -= siglen;
+ types += skiplen;
+ nstruct -= skiplen;
}
if (VIR_ALLOC(newiter) < 0)
goto cleanup;
- VIR_DEBUG("Contsig '%s' '%zu' '%s'",
contsig, siglen, types);
+ VIR_DEBUG("Array contsig='%s' skip=%'zu'
len='%zu' types='%s'",
+ contsig, skiplen, siglen, types);
dbus_message_iter_recurse(iter, newiter);
if (virDBusTypeStackPush(&stack, &nstack,
iter, types,
@@ -965,7 +1047,7 @@ virDBusMessageIterDecode(DBusMessageIter *rootiter,
iter = newiter;
newiter = NULL;
types = t + 1;
- nstruct = siglen;
+ nstruct = skiplen;
if (arrayref) {
narrayptr = va_arg(args, size_t *);
arrayptr = va_arg(args, void *);
@@ -1003,19 +1085,17 @@ virDBusMessageIterDecode(DBusMessageIter *rootiter,
case DBUS_STRUCT_BEGIN_CHAR:
case DBUS_DICT_ENTRY_BEGIN_CHAR:
advanceiter = false;
- if (virDBusSignatureLength(t, &siglen) < 0)
- goto cleanup;
-
- if (VIR_STRNDUP(contsig, t + 1, siglen - 1) < 0)
+ if (!(contsig = virDBusCopyContainerSignature(t, &skiplen,
&siglen)))
goto cleanup;
if (VIR_ALLOC(newiter) < 0)
goto cleanup;
- VIR_DEBUG("Contsig '%s' '%zu'", contsig, siglen);
+ VIR_DEBUG("Dict/struct contsig='%s' skip='%zu'
len='%zu' types='%s'",
+ contsig, skiplen, siglen, types);
dbus_message_iter_recurse(iter, newiter);
if (narray == (size_t)-1) {
- types += siglen - 1;
- nstruct -= siglen - 1;
+ types += skiplen - 1;
+ nstruct -= skiplen - 1;
}
if (virDBusTypeStackPush(&stack, &nstack,
@@ -1026,7 +1106,7 @@ virDBusMessageIterDecode(DBusMessageIter *rootiter,
iter = newiter;
newiter = NULL;
types = t + 1;
- nstruct = siglen - 2;
+ nstruct = skiplen - 2;
narray = (size_t)-1;
break;
@@ -1038,24 +1118,32 @@ virDBusMessageIterDecode(DBusMessageIter *rootiter,
goto cleanup;
}
+ VIR_DEBUG("After nstack=%zu narray=%zd nstruct=%zu
types='%s'",
+ nstack, (ssize_t)narray, nstruct, types);
+
if (arrayref) {
- if (*t == '&' ||
- dbus_message_iter_has_next(iter))
- narray = 1;
- else
+ if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_INVALID) {
narray = 0;
- }
-
- VIR_DEBUG("After stack=%zu array=%zu struct=%zu type='%s'",
- nstack, narray, nstruct, types);
- if (advanceiter &&
- !(narray == 0 ||
- (narray == (size_t)-1 &&
- nstruct == 0)) &&
- !dbus_message_iter_next(iter)) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("Not enough fields in message for signature"));
- goto cleanup;
+ } else {
+ if (advanceiter)
+ dbus_message_iter_next(iter);
+ if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_INVALID) {
+ narray = 0;
+ } else {
+ narray = 1;
+ }
+ }
+ VIR_DEBUG("Set narray=%zd", (ssize_t)narray);
+ } else {
+ if (advanceiter &&
+ !(narray == 0 ||
+ (narray == (size_t)-1 &&
+ nstruct == 0)) &&
+ !dbus_message_iter_next(iter)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Not enough fields in message for
signature"));
+ goto cleanup;
+ }
}
}
@@ -1217,7 +1305,27 @@ int virDBusMessageDecode(DBusMessage* msg,
*
* The first variadic arg for an array, is an 'int'
* specifying the number of elements in the array.
- * This is then followed by the values for the array
+ * This is then followed by additional variadic args,
+ * one for each element of the array.
+ *
+ * - Array reference: when 'a' appears in a type signature,
+ * followed by '&', this signifies an array passed by
+ * reference.
+ *
+ * Array references may only be used when the
+ * element values are basic types, or a dict
+ * entry where both keys and values are using
+ * the same basic type.
+ *
+ * The first variadic arg for an array, is an 'int'
+ * specifying the number of elements in the array.
+ * When the element is a basic type, the second
+ * variadic arg is a pointer to an array containing
+ * the element values. When the element is a dict
+ * entry, the second variadic arg is a pointer to
+ * an array containing the dict keys, and the
+ * third variadic arg is a pointer to an array
+ * containing the dict values.
*
* - Struct: when a '(' appears in a type signature,
* it must be followed by one or more types describing
diff --git a/src/util/virstring.c b/src/util/virstring.c
index b14f785..43eab91 100644
--- a/src/util/virstring.c
+++ b/src/util/virstring.c
@@ -205,6 +205,20 @@ virStringFreeListCount(char **strings,
}
+size_t virStringListLen(const char **strings)
+{
+ size_t i = 0;
+
+ if (!strings)
+ return 0;
+
+ while (strings[i] != NULL)
+ i++;
+
+ return i;
+}
+
+
bool
virStringArrayHasString(char **strings, const char *needle)
{
diff --git a/src/util/virstring.h b/src/util/virstring.h
index 267fbd0..b82ef2a 100644
--- a/src/util/virstring.h
+++ b/src/util/virstring.h
@@ -44,6 +44,8 @@ char *virStringJoin(const char **strings,
void virStringFreeList(char **strings);
void virStringFreeListCount(char **strings, size_t count);
+size_t virStringListLen(const char **strings);
+
bool virStringArrayHasString(char **strings, const char *needle);
char *virArgvToString(const char *const *argv);
diff --git a/tests/virdbustest.c b/tests/virdbustest.c
index 0079b41..002f904 100644
--- a/tests/virdbustest.c
+++ b/tests/virdbustest.c
@@ -228,6 +228,99 @@ static int testMessageArray(const void *args ATTRIBUTE_UNUSED)
return ret;
}
+static int testMessageEmptyArrayRef(const void *args ATTRIBUTE_UNUSED)
+{
+ DBusMessage *msg = NULL;
+ int ret = -1;
+ const char *in_strv1[] = {};
+ size_t out_nstrv1;
+ char **out_strv1 = 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,
+ "a&s",
+ 0, in_strv1) < 0) {
+ VIR_DEBUG("Failed to encode arguments");
+ goto cleanup;
+ }
+
+ if (virDBusMessageDecode(msg,
+ "a&s",
+ &out_nstrv1, &out_strv1) < 0) {
+ VIR_DEBUG("Failed to decode arguments");
+ goto cleanup;
+ }
+
+
+ if (out_nstrv1 != 0) {
+ fprintf(stderr, "Expected 0 string, but got %zu\n",
+ out_nstrv1);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ dbus_message_unref(msg);
+ return ret;
+}
+
+static int testMessageSingleArrayRef(const void *args ATTRIBUTE_UNUSED)
+{
+ DBusMessage *msg = NULL;
+ int ret = -1;
+ const char *in_strv1[] = {
+ "Fishfood",
+ };
+ char **out_strv1 = NULL;
+ size_t out_nstrv1 = 0;
+
+ 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,
+ "a&s",
+ 1, in_strv1) < 0) {
+ VIR_DEBUG("Failed to encode arguments");
+ goto cleanup;
+ }
+
+ if (virDBusMessageDecode(msg,
+ "a&s",
+ &out_nstrv1, &out_strv1) < 0) {
+ VIR_DEBUG("Failed to decode arguments");
+ goto cleanup;
+ }
+
+
+ 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");
+
+ ret = 0;
+
+ cleanup:
+ if (out_strv1)
+ VIR_FREE(out_strv1[0]);
+ dbus_message_unref(msg);
+ return ret;
+}
+
static int testMessageArrayRef(const void *args ATTRIBUTE_UNUSED)
{
DBusMessage *msg = NULL;
@@ -426,7 +519,7 @@ static int testMessageDict(const void *args ATTRIBUTE_UNUSED)
}
if (virDBusMessageEncode(msg,
- "sa{si}s",
+ "(sa{si}s)",
in_str1,
3,
in_key1, in_int32a,
@@ -438,7 +531,7 @@ static int testMessageDict(const void *args ATTRIBUTE_UNUSED)
}
if (virDBusMessageDecode(msg,
- "sa{si}s",
+ "(sa{si}s)",
&out_str1,
3,
&out_key1, &out_int32a,
@@ -471,6 +564,119 @@ static int testMessageDict(const void *args ATTRIBUTE_UNUSED)
return ret;
}
+static int testMessageDictRef(const void *args ATTRIBUTE_UNUSED)
+{
+ DBusMessage *msg = NULL;
+ int ret = -1;
+ const char *in_str1 = "Hello";
+ const char *in_strv1[] = {
+ "Fruit1", "Apple",
+ "Fruit2", "Orange",
+ "Fruit3", "Kiwi",
+ };
+ const char *in_str2 = "World";
+ char *out_str1 = NULL;
+ size_t out_nint32 = 0;
+ char **out_strv1 = NULL;
+ char *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&{ss}s)",
+ in_str1,
+ 3, in_strv1,
+ in_str2) < 0) {
+ VIR_DEBUG("Failed to encode arguments");
+ goto cleanup;
+ }
+
+ if (virDBusMessageDecode(msg,
+ "(sa&{ss}s)",
+ &out_str1,
+ &out_nint32,
+ &out_strv1,
+ &out_str2) < 0) {
+ VIR_DEBUG("Failed to decode arguments: '%s'",
virGetLastErrorMessage());
+ goto cleanup;
+ }
+
+
+ VERIFY_STR("str1", in_str1, out_str1, "%s");
+ VERIFY_STR("strv1[0]", in_strv1[0], out_strv1[0], "%s");
+ VERIFY_STR("strv1[1]", in_strv1[1], out_strv1[1], "%s");
+ VERIFY_STR("strv1[2]", in_strv1[2], out_strv1[2], "%s");
+ VERIFY_STR("strv1[3]", in_strv1[3], out_strv1[3], "%s");
+ VERIFY_STR("strv1[4]", in_strv1[4], out_strv1[4], "%s");
+ VERIFY_STR("strv1[5]", in_strv1[5], out_strv1[5], "%s");
+ VERIFY_STR("str2", in_str2, out_str2, "%s");
+
+ ret = 0;
+
+ cleanup:
+ VIR_FREE(out_str1);
+ VIR_FREE(out_str2);
+ if (out_strv1) {
+ VIR_FREE(out_strv1[0]);
+ VIR_FREE(out_strv1[1]);
+ VIR_FREE(out_strv1[2]);
+ VIR_FREE(out_strv1[3]);
+ VIR_FREE(out_strv1[4]);
+ VIR_FREE(out_strv1[5]);
+ }
+ VIR_FREE(out_strv1);
+ dbus_message_unref(msg);
+ return ret;
+}
+
+static int testMessageEmptyDictRef(const void *args ATTRIBUTE_UNUSED)
+{
+ DBusMessage *msg = NULL;
+ int ret = -1;
+ const char *in_strv1[] = {};
+ size_t out_nint32 = 0;
+ char **out_strv1 = 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,
+ "a&{ss}",
+ 0, in_strv1) < 0) {
+ VIR_DEBUG("Failed to encode arguments");
+ goto cleanup;
+ }
+
+ if (virDBusMessageDecode(msg,
+ "a&{ss}",
+ &out_nint32,
+ &out_strv1) < 0) {
+ VIR_DEBUG("Failed to decode arguments: '%s'",
virGetLastErrorMessage());
+ goto cleanup;
+ }
+
+ if (out_nint32 != 0) {
+ fprintf(stderr, "Unexpected dict entries\n");
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ dbus_message_unref(msg);
+ return ret;
+}
static int
mymain(void)
@@ -483,12 +689,20 @@ mymain(void)
ret = -1;
if (virtTestRun("Test message array ", testMessageArray, NULL) < 0)
ret = -1;
+ if (virtTestRun("Test message array empty ref ", testMessageEmptyArrayRef,
NULL) < 0)
+ ret = -1;
+ if (virtTestRun("Test message array single ref ",
testMessageSingleArrayRef, 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)
ret = -1;
+ if (virtTestRun("Test message dict empty ref ", testMessageEmptyDictRef,
NULL) < 0)
+ ret = -1;
+ if (virtTestRun("Test message dict ref ", testMessageDictRef, NULL) <
0)
+ ret = -1;
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
--
1.9.3