mirror of https://gitee.com/openkylin/libvirt.git
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:
parent
c754257347
commit
88a2dc1f4c
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue