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@xxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list