Support passing dict by reference for dbus messages

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@redhat.com>
This commit is contained in:
Daniel P. Berrange 2014-09-09 15:19:58 +01:00
parent c754257347
commit 88a2dc1f4c
4 changed files with 424 additions and 86 deletions

View File

@ -313,15 +313,18 @@ virDBusSignatureLengthInternal(const char *s,
bool allowDict, bool allowDict,
unsigned arrayDepth, unsigned arrayDepth,
unsigned structDepth, unsigned structDepth,
size_t *l) size_t *skiplen,
size_t *siglen)
{ {
if (virDBusIsBasicType(*s) || *s == DBUS_TYPE_VARIANT) { if (virDBusIsBasicType(*s) || *s == DBUS_TYPE_VARIANT) {
*l = 1; *skiplen = *siglen = 1;
return 0; return 0;
} }
if (*s == DBUS_TYPE_ARRAY) { 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) { if (arrayDepth >= VIR_DBUS_TYPE_STACK_MAX_DEPTH) {
virReportError(VIR_ERR_INTERNAL_ERROR, virReportError(VIR_ERR_INTERNAL_ERROR,
@ -330,14 +333,23 @@ virDBusSignatureLengthInternal(const char *s,
return -1; return -1;
} }
if (*(s + 1) == '&') {
arrayref = true;
s++;
}
if (virDBusSignatureLengthInternal(s + 1, if (virDBusSignatureLengthInternal(s + 1,
true, true,
arrayDepth + 1, arrayDepth + 1,
structDepth, structDepth,
&t) < 0) &skiplencont,
&siglencont) < 0)
return -1; return -1;
*l = t + 1; *skiplen = skiplencont + 1;
*siglen = siglencont + 1;
if (arrayref)
(*skiplen)++;
return 0; return 0;
} }
@ -351,20 +363,25 @@ virDBusSignatureLengthInternal(const char *s,
return -1; return -1;
} }
*skiplen = *siglen = 2;
while (*p != DBUS_STRUCT_END_CHAR) { while (*p != DBUS_STRUCT_END_CHAR) {
size_t t; size_t skiplencont;
size_t siglencont;
if (virDBusSignatureLengthInternal(p, if (virDBusSignatureLengthInternal(p,
false, false,
arrayDepth, arrayDepth,
structDepth + 1, structDepth + 1,
&t) < 0) &skiplencont,
&siglencont) < 0)
return -1; return -1;
p += t; p += skiplencont;
*skiplen += skiplencont;
*siglen += siglencont;
} }
*l = p - s + 1;
return 0; return 0;
} }
@ -378,8 +395,11 @@ virDBusSignatureLengthInternal(const char *s,
return -1; return -1;
} }
*skiplen = *siglen = 2;
while (*p != DBUS_DICT_ENTRY_END_CHAR) { while (*p != DBUS_DICT_ENTRY_END_CHAR) {
size_t t; size_t skiplencont;
size_t siglencont;
if (n == 0 && !virDBusIsBasicType(*p)) { if (n == 0 && !virDBusIsBasicType(*p)) {
virReportError(VIR_ERR_INTERNAL_ERROR, virReportError(VIR_ERR_INTERNAL_ERROR,
@ -392,10 +412,13 @@ virDBusSignatureLengthInternal(const char *s,
false, false,
arrayDepth, arrayDepth,
structDepth + 1, structDepth + 1,
&t) < 0) &skiplencont,
&siglencont) < 0)
return -1; return -1;
p += t; p += skiplencont;
*skiplen += skiplencont;
*siglen += siglencont;
n++; n++;
} }
@ -406,7 +429,6 @@ virDBusSignatureLengthInternal(const char *s,
return -1; return -1;
} }
*l = p - s + 1;
return 0; 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 /* Ideally, we'd just call ourselves recursively on every
* complex type. However, the state of a va_list that is * 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].types = types;
(*stack)[(*nstack) - 1].nstruct = nstruct; (*stack)[(*nstack) - 1].nstruct = nstruct;
(*stack)[(*nstack) - 1].narray = narray; (*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; return 0;
} }
@ -480,7 +531,8 @@ static int virDBusTypeStackPop(virDBusTypeStack **stack,
*types = (*stack)[(*nstack) - 1].types; *types = (*stack)[(*nstack) - 1].types;
*nstruct = (*stack)[(*nstack) - 1].nstruct; *nstruct = (*stack)[(*nstack) - 1].nstruct;
*narray = (*stack)[(*nstack) - 1].narray; *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); VIR_SHRINK_N(*stack, *nstack, 1);
return 0; 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) \ # define SET_NEXT_VAL(dbustype, vargtype, sigtype, fmt) \
do { \ do { \
dbustype x; \ dbustype x; \
@ -535,6 +609,7 @@ virDBusMessageIterEncode(DBusMessageIter *rootiter,
virDBusTypeStack *stack = NULL; virDBusTypeStack *stack = NULL;
size_t nstack = 0; size_t nstack = 0;
size_t siglen; size_t siglen;
size_t skiplen;
char *contsig = NULL; char *contsig = NULL;
const char *vsig; const char *vsig;
DBusMessageIter *newiter = NULL; DBusMessageIter *newiter = NULL;
@ -551,14 +626,17 @@ virDBusMessageIterEncode(DBusMessageIter *rootiter,
for (;;) { for (;;) {
const char *t; const char *t;
VIR_DEBUG("Loop stack=%zu array=%zu struct=%zu type='%s'", VIR_DEBUG("Loop nstack=%zu narray=%zd nstruct=%zu types='%s'",
nstack, narray, nstruct, types); nstack, (ssize_t)narray, nstruct, types);
if (narray == 0 || if (narray == 0 ||
(narray == (size_t)-1 && (narray == (size_t)-1 &&
nstruct == 0)) { nstruct == 0)) {
DBusMessageIter *thisiter = iter; DBusMessageIter *thisiter = iter;
arrayref = false; if (*types != '}') {
arrayptr = NULL; VIR_DEBUG("Reset array ref");
arrayref = false;
arrayptr = NULL;
}
VIR_DEBUG("Popping iter=%p", iter); VIR_DEBUG("Popping iter=%p", iter);
if (nstack == 0) if (nstack == 0)
break; break;
@ -643,28 +721,25 @@ virDBusMessageIterEncode(DBusMessageIter *rootiter,
arrayref = false; arrayref = false;
} }
if (virDBusSignatureLength(t + 1, &siglen) < 0) if (!(contsig = virDBusCopyContainerSignature(t, &skiplen, &siglen)))
goto cleanup; goto cleanup;
if (VIR_STRNDUP(contsig, t + 1, siglen) < 0) if (arrayref && !virDBusIsAllowedRefType(contsig)) {
goto cleanup;
if (arrayref && (strlen(contsig) > 1 ||
!virDBusIsBasicType(*contsig))) {
virReportError(VIR_ERR_INTERNAL_ERROR, 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); contsig);
goto cleanup; goto cleanup;
} }
if (narray == (size_t)-1) { if (narray == (size_t)-1) {
types += siglen; types += skiplen;
nstruct -= siglen; nstruct -= skiplen;
} }
if (VIR_ALLOC(newiter) < 0) if (VIR_ALLOC(newiter) < 0)
goto cleanup; 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, if (!dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
contsig, newiter)) contsig, newiter))
goto cleanup; goto cleanup;
@ -678,7 +753,7 @@ virDBusMessageIterEncode(DBusMessageIter *rootiter,
iter = newiter; iter = newiter;
newiter = NULL; newiter = NULL;
types = t + 1; types = t + 1;
nstruct = siglen; nstruct = skiplen;
narray = (size_t)va_arg(args, int); narray = (size_t)va_arg(args, int);
if (arrayref) if (arrayref)
arrayptr = va_arg(args, void *); arrayptr = va_arg(args, void *);
@ -711,23 +786,20 @@ virDBusMessageIterEncode(DBusMessageIter *rootiter,
case DBUS_STRUCT_BEGIN_CHAR: case DBUS_STRUCT_BEGIN_CHAR:
case DBUS_DICT_ENTRY_BEGIN_CHAR: case DBUS_DICT_ENTRY_BEGIN_CHAR:
if (virDBusSignatureLength(t, &siglen) < 0) if (!(contsig = virDBusCopyContainerSignature(t, &skiplen, &siglen)))
goto cleanup;
if (VIR_STRNDUP(contsig, t + 1, siglen - 1) < 0)
goto cleanup; goto cleanup;
if (VIR_ALLOC(newiter) < 0) if (VIR_ALLOC(newiter) < 0)
goto cleanup; 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, if (!dbus_message_iter_open_container(iter,
*t == DBUS_STRUCT_BEGIN_CHAR ? *t == DBUS_STRUCT_BEGIN_CHAR ?
DBUS_TYPE_STRUCT : DBUS_TYPE_DICT_ENTRY, DBUS_TYPE_STRUCT : DBUS_TYPE_DICT_ENTRY,
NULL, newiter)) NULL, newiter))
goto cleanup; goto cleanup;
if (narray == (size_t)-1) { if (narray == (size_t)-1) {
types += siglen - 1; types += skiplen - 1;
nstruct -= siglen - 1; nstruct -= skiplen - 1;
} }
if (virDBusTypeStackPush(&stack, &nstack, if (virDBusTypeStackPush(&stack, &nstack,
@ -740,15 +812,15 @@ virDBusMessageIterEncode(DBusMessageIter *rootiter,
iter = newiter; iter = newiter;
newiter = NULL; newiter = NULL;
types = t + 1; types = t + 1;
nstruct = siglen - 2; nstruct = skiplen - 2;
narray = (size_t)-1; narray = (size_t)-1;
break; break;
default: default:
virReportError(VIR_ERR_INTERNAL_ERROR, virReportError(VIR_ERR_INTERNAL_ERROR,
_("Unknown type '%c' in signature '%s'"), _("Unknown type '%x' in signature '%s'"),
*t, types); (int)*t, types);
goto cleanup; goto cleanup;
} }
} }
@ -779,6 +851,7 @@ virDBusMessageIterEncode(DBusMessageIter *rootiter,
do { \ do { \
dbustype *x; \ dbustype *x; \
if (arrayref) { \ if (arrayref) { \
VIR_DEBUG("Use arrayref"); \
vargtype **xptrptr = arrayptr; \ vargtype **xptrptr = arrayptr; \
if (VIR_EXPAND_N(*xptrptr, *narrayptr, 1) < 0) \ if (VIR_EXPAND_N(*xptrptr, *narrayptr, 1) < 0) \
goto cleanup; \ goto cleanup; \
@ -806,6 +879,7 @@ virDBusMessageIterDecode(DBusMessageIter *rootiter,
size_t *narrayptr = 0; size_t *narrayptr = 0;
virDBusTypeStack *stack = NULL; virDBusTypeStack *stack = NULL;
size_t nstack = 0; size_t nstack = 0;
size_t skiplen;
size_t siglen; size_t siglen;
char *contsig = NULL; char *contsig = NULL;
const char *vsig; const char *vsig;
@ -824,14 +898,12 @@ virDBusMessageIterDecode(DBusMessageIter *rootiter,
const char *t; const char *t;
bool advanceiter = true; bool advanceiter = true;
VIR_DEBUG("Loop stack=%zu array=%zu struct=%zu type='%s'", VIR_DEBUG("Loop nstack=%zu narray=%zd nstruct=%zu type='%s'",
nstack, narray, nstruct, types); nstack, (ssize_t)narray, nstruct, types);
if (narray == 0 || if (narray == 0 ||
(narray == (size_t)-1 && (narray == (size_t)-1 &&
nstruct == 0)) { nstruct == 0)) {
DBusMessageIter *thisiter = iter; DBusMessageIter *thisiter = iter;
arrayref = false;
arrayptr = NULL;
VIR_DEBUG("Popping iter=%p", iter); VIR_DEBUG("Popping iter=%p", iter);
if (nstack == 0) if (nstack == 0)
break; break;
@ -839,8 +911,20 @@ virDBusMessageIterDecode(DBusMessageIter *rootiter,
&types, &nstruct, &narray) < 0) &types, &nstruct, &narray) < 0)
goto cleanup; goto cleanup;
VIR_DEBUG("Popped iter=%p types=%s", iter, types); 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) if (thisiter != rootiter)
VIR_FREE(thisiter); 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 || if (!(narray == 0 ||
(narray == (size_t)-1 && (narray == (size_t)-1 &&
nstruct == 0)) && nstruct == 0)) &&
@ -854,7 +938,8 @@ virDBusMessageIterDecode(DBusMessageIter *rootiter,
t = types; t = types;
if (narray != (size_t)-1) { if (narray != (size_t)-1) {
narray--; if (!arrayref)
narray--;
} else { } else {
types++; types++;
nstruct--; nstruct--;
@ -934,28 +1019,25 @@ virDBusMessageIterDecode(DBusMessageIter *rootiter,
} }
advanceiter = false; advanceiter = false;
if (virDBusSignatureLength(t + 1, &siglen) < 0) if (!(contsig = virDBusCopyContainerSignature(t, &skiplen, &siglen)))
goto cleanup; goto cleanup;
if (VIR_STRNDUP(contsig, t + 1, siglen) < 0) if (arrayref && !virDBusIsAllowedRefType(contsig)) {
goto cleanup;
if (arrayref && (strlen(contsig) > 1 ||
!virDBusIsBasicType(*contsig))) {
virReportError(VIR_ERR_INTERNAL_ERROR, 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); contsig);
goto cleanup; goto cleanup;
} }
if (narray == (size_t)-1) { if (narray == (size_t)-1) {
types += siglen; types += skiplen;
nstruct -= siglen; nstruct -= skiplen;
} }
if (VIR_ALLOC(newiter) < 0) if (VIR_ALLOC(newiter) < 0)
goto cleanup; 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); dbus_message_iter_recurse(iter, newiter);
if (virDBusTypeStackPush(&stack, &nstack, if (virDBusTypeStackPush(&stack, &nstack,
iter, types, iter, types,
@ -965,7 +1047,7 @@ virDBusMessageIterDecode(DBusMessageIter *rootiter,
iter = newiter; iter = newiter;
newiter = NULL; newiter = NULL;
types = t + 1; types = t + 1;
nstruct = siglen; nstruct = skiplen;
if (arrayref) { if (arrayref) {
narrayptr = va_arg(args, size_t *); narrayptr = va_arg(args, size_t *);
arrayptr = va_arg(args, void *); arrayptr = va_arg(args, void *);
@ -1003,19 +1085,17 @@ virDBusMessageIterDecode(DBusMessageIter *rootiter,
case DBUS_STRUCT_BEGIN_CHAR: case DBUS_STRUCT_BEGIN_CHAR:
case DBUS_DICT_ENTRY_BEGIN_CHAR: case DBUS_DICT_ENTRY_BEGIN_CHAR:
advanceiter = false; advanceiter = false;
if (virDBusSignatureLength(t, &siglen) < 0) if (!(contsig = virDBusCopyContainerSignature(t, &skiplen, &siglen)))
goto cleanup;
if (VIR_STRNDUP(contsig, t + 1, siglen - 1) < 0)
goto cleanup; goto cleanup;
if (VIR_ALLOC(newiter) < 0) if (VIR_ALLOC(newiter) < 0)
goto cleanup; 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); dbus_message_iter_recurse(iter, newiter);
if (narray == (size_t)-1) { if (narray == (size_t)-1) {
types += siglen - 1; types += skiplen - 1;
nstruct -= siglen - 1; nstruct -= skiplen - 1;
} }
if (virDBusTypeStackPush(&stack, &nstack, if (virDBusTypeStackPush(&stack, &nstack,
@ -1026,7 +1106,7 @@ virDBusMessageIterDecode(DBusMessageIter *rootiter,
iter = newiter; iter = newiter;
newiter = NULL; newiter = NULL;
types = t + 1; types = t + 1;
nstruct = siglen - 2; nstruct = skiplen - 2;
narray = (size_t)-1; narray = (size_t)-1;
break; break;
@ -1038,24 +1118,32 @@ virDBusMessageIterDecode(DBusMessageIter *rootiter,
goto cleanup; goto cleanup;
} }
if (arrayref) { VIR_DEBUG("After nstack=%zu narray=%zd nstruct=%zu types='%s'",
if (*t == '&' || nstack, (ssize_t)narray, nstruct, types);
dbus_message_iter_has_next(iter))
narray = 1;
else
narray = 0;
}
VIR_DEBUG("After stack=%zu array=%zu struct=%zu type='%s'", if (arrayref) {
nstack, narray, nstruct, types); if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_INVALID) {
if (advanceiter && narray = 0;
!(narray == 0 || } else {
(narray == (size_t)-1 && if (advanceiter)
nstruct == 0)) && dbus_message_iter_next(iter);
!dbus_message_iter_next(iter)) { if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_INVALID) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", narray = 0;
_("Not enough fields in message for signature")); } else {
goto cleanup; 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' * The first variadic arg for an array, is an 'int'
* specifying the number of elements in the array. * 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, * - Struct: when a '(' appears in a type signature,
* it must be followed by one or more types describing * it must be followed by one or more types describing

View File

@ -208,6 +208,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 bool
virStringArrayHasString(char **strings, const char *needle) virStringArrayHasString(char **strings, const char *needle)
{ {

View File

@ -44,6 +44,8 @@ char *virStringJoin(const char **strings,
void virStringFreeList(char **strings); void virStringFreeList(char **strings);
void virStringFreeListCount(char **strings, size_t count); void virStringFreeListCount(char **strings, size_t count);
size_t virStringListLen(const char **strings);
bool virStringArrayHasString(char **strings, const char *needle); bool virStringArrayHasString(char **strings, const char *needle);
char *virArgvToString(const char *const *argv); char *virArgvToString(const char *const *argv);

View File

@ -228,6 +228,99 @@ static int testMessageArray(const void *args ATTRIBUTE_UNUSED)
return ret; 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) static int testMessageArrayRef(const void *args ATTRIBUTE_UNUSED)
{ {
DBusMessage *msg = NULL; DBusMessage *msg = NULL;
@ -426,7 +519,7 @@ static int testMessageDict(const void *args ATTRIBUTE_UNUSED)
} }
if (virDBusMessageEncode(msg, if (virDBusMessageEncode(msg,
"sa{si}s", "(sa{si}s)",
in_str1, in_str1,
3, 3,
in_key1, in_int32a, in_key1, in_int32a,
@ -438,7 +531,7 @@ static int testMessageDict(const void *args ATTRIBUTE_UNUSED)
} }
if (virDBusMessageDecode(msg, if (virDBusMessageDecode(msg,
"sa{si}s", "(sa{si}s)",
&out_str1, &out_str1,
3, 3,
&out_key1, &out_int32a, &out_key1, &out_int32a,
@ -471,6 +564,119 @@ static int testMessageDict(const void *args ATTRIBUTE_UNUSED)
return ret; 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 static int
mymain(void) mymain(void)
@ -483,12 +689,20 @@ mymain(void)
ret = -1; ret = -1;
if (virtTestRun("Test message array ", testMessageArray, NULL) < 0) if (virtTestRun("Test message array ", testMessageArray, NULL) < 0)
ret = -1; 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) if (virtTestRun("Test message array ref ", testMessageArrayRef, NULL) < 0)
ret = -1; ret = -1;
if (virtTestRun("Test message struct ", testMessageStruct, NULL) < 0) if (virtTestRun("Test message struct ", testMessageStruct, NULL) < 0)
ret = -1; ret = -1;
if (virtTestRun("Test message dict ", testMessageDict, NULL) < 0) if (virtTestRun("Test message dict ", testMessageDict, NULL) < 0)
ret = -1; 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; return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
} }