hostapd/wpa_supplicant/dbus/dbus_dict_helpers.c
Johannes Berg 911e97e400 DBus: Refactor array adding, add binary arrays
Some new code we're working on will require the dbus type "aay" (an
array of arrays of bytes). To add this, refactor the array code to
reduce code duplication by given a type string to the array starting
code, and also add code to create and parse such arrays from or into an
array of struct wpabuf respectively.

Since there's no unique DBus type for this, add a "fake"
WPAS_DBUS_TYPE_BINARRAY type that is separate from the regular DBus
types for parsing.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2011-06-12 14:47:49 -07:00

1100 lines
28 KiB
C

/*
* WPA Supplicant / dbus-based control interface
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include <dbus/dbus.h>
#include "common.h"
#include "wpabuf.h"
#include "dbus_dict_helpers.h"
/**
* Start a dict in a dbus message. Should be paired with a call to
* wpa_dbus_dict_close_write().
*
* @param iter A valid dbus message iterator
* @param iter_dict (out) A dict iterator to pass to further dict functions
* @return TRUE on success, FALSE on failure
*
*/
dbus_bool_t wpa_dbus_dict_open_write(DBusMessageIter *iter,
DBusMessageIter *iter_dict)
{
dbus_bool_t result;
if (!iter || !iter_dict)
return FALSE;
result = dbus_message_iter_open_container(
iter,
DBUS_TYPE_ARRAY,
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
DBUS_TYPE_STRING_AS_STRING
DBUS_TYPE_VARIANT_AS_STRING
DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
iter_dict);
return result;
}
/**
* End a dict element in a dbus message. Should be paired with
* a call to wpa_dbus_dict_open_write().
*
* @param iter valid dbus message iterator, same as passed to
* wpa_dbus_dict_open_write()
* @param iter_dict a dbus dict iterator returned from
* wpa_dbus_dict_open_write()
* @return TRUE on success, FALSE on failure
*
*/
dbus_bool_t wpa_dbus_dict_close_write(DBusMessageIter *iter,
DBusMessageIter *iter_dict)
{
if (!iter || !iter_dict)
return FALSE;
return dbus_message_iter_close_container(iter, iter_dict);
}
const char * wpa_dbus_type_as_string(const int type)
{
switch(type) {
case DBUS_TYPE_BYTE:
return DBUS_TYPE_BYTE_AS_STRING;
case DBUS_TYPE_BOOLEAN:
return DBUS_TYPE_BOOLEAN_AS_STRING;
case DBUS_TYPE_INT16:
return DBUS_TYPE_INT16_AS_STRING;
case DBUS_TYPE_UINT16:
return DBUS_TYPE_UINT16_AS_STRING;
case DBUS_TYPE_INT32:
return DBUS_TYPE_INT32_AS_STRING;
case DBUS_TYPE_UINT32:
return DBUS_TYPE_UINT32_AS_STRING;
case DBUS_TYPE_INT64:
return DBUS_TYPE_INT64_AS_STRING;
case DBUS_TYPE_UINT64:
return DBUS_TYPE_UINT64_AS_STRING;
case DBUS_TYPE_DOUBLE:
return DBUS_TYPE_DOUBLE_AS_STRING;
case DBUS_TYPE_STRING:
return DBUS_TYPE_STRING_AS_STRING;
case DBUS_TYPE_OBJECT_PATH:
return DBUS_TYPE_OBJECT_PATH_AS_STRING;
case DBUS_TYPE_ARRAY:
return DBUS_TYPE_ARRAY_AS_STRING;
default:
return NULL;
}
}
static dbus_bool_t _wpa_dbus_add_dict_entry_start(
DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry,
const char *key, const int value_type)
{
if (!dbus_message_iter_open_container(iter_dict,
DBUS_TYPE_DICT_ENTRY, NULL,
iter_dict_entry))
return FALSE;
if (!dbus_message_iter_append_basic(iter_dict_entry, DBUS_TYPE_STRING,
&key))
return FALSE;
return TRUE;
}
static dbus_bool_t _wpa_dbus_add_dict_entry_end(
DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry,
DBusMessageIter *iter_dict_val)
{
if (!dbus_message_iter_close_container(iter_dict_entry, iter_dict_val))
return FALSE;
if (!dbus_message_iter_close_container(iter_dict, iter_dict_entry))
return FALSE;
return TRUE;
}
static dbus_bool_t _wpa_dbus_add_dict_entry_basic(DBusMessageIter *iter_dict,
const char *key,
const int value_type,
const void *value)
{
DBusMessageIter iter_dict_entry, iter_dict_val;
const char *type_as_string = NULL;
if (key == NULL)
return FALSE;
type_as_string = wpa_dbus_type_as_string(value_type);
if (!type_as_string)
return FALSE;
if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry,
key, value_type))
return FALSE;
if (!dbus_message_iter_open_container(&iter_dict_entry,
DBUS_TYPE_VARIANT,
type_as_string, &iter_dict_val))
return FALSE;
if (!dbus_message_iter_append_basic(&iter_dict_val, value_type, value))
return FALSE;
if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
&iter_dict_val))
return FALSE;
return TRUE;
}
static dbus_bool_t _wpa_dbus_add_dict_entry_byte_array(
DBusMessageIter *iter_dict, const char *key,
const char *value, const dbus_uint32_t value_len)
{
DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
dbus_uint32_t i;
if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry,
key, DBUS_TYPE_ARRAY))
return FALSE;
if (!dbus_message_iter_open_container(&iter_dict_entry,
DBUS_TYPE_VARIANT,
DBUS_TYPE_ARRAY_AS_STRING
DBUS_TYPE_BYTE_AS_STRING,
&iter_dict_val))
return FALSE;
if (!dbus_message_iter_open_container(&iter_dict_val, DBUS_TYPE_ARRAY,
DBUS_TYPE_BYTE_AS_STRING,
&iter_array))
return FALSE;
for (i = 0; i < value_len; i++) {
if (!dbus_message_iter_append_basic(&iter_array,
DBUS_TYPE_BYTE,
&(value[i])))
return FALSE;
}
if (!dbus_message_iter_close_container(&iter_dict_val, &iter_array))
return FALSE;
if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
&iter_dict_val))
return FALSE;
return TRUE;
}
/**
* Add a string entry to the dict.
*
* @param iter_dict A valid DBusMessageIter returned from
* wpa_dbus_dict_open_write()
* @param key The key of the dict item
* @param value The string value
* @return TRUE on success, FALSE on failure
*
*/
dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict,
const char *key, const char *value)
{
if (!value)
return FALSE;
return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_STRING,
&value);
}
/**
* Add a byte entry to the dict.
*
* @param iter_dict A valid DBusMessageIter returned from
* wpa_dbus_dict_open_write()
* @param key The key of the dict item
* @param value The byte value
* @return TRUE on success, FALSE on failure
*
*/
dbus_bool_t wpa_dbus_dict_append_byte(DBusMessageIter *iter_dict,
const char *key, const char value)
{
return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_BYTE,
&value);
}
/**
* Add a boolean entry to the dict.
*
* @param iter_dict A valid DBusMessageIter returned from
* wpa_dbus_dict_open_write()
* @param key The key of the dict item
* @param value The boolean value
* @return TRUE on success, FALSE on failure
*
*/
dbus_bool_t wpa_dbus_dict_append_bool(DBusMessageIter *iter_dict,
const char *key, const dbus_bool_t value)
{
return _wpa_dbus_add_dict_entry_basic(iter_dict, key,
DBUS_TYPE_BOOLEAN, &value);
}
/**
* Add a 16-bit signed integer entry to the dict.
*
* @param iter_dict A valid DBusMessageIter returned from
* wpa_dbus_dict_open_write()
* @param key The key of the dict item
* @param value The 16-bit signed integer value
* @return TRUE on success, FALSE on failure
*
*/
dbus_bool_t wpa_dbus_dict_append_int16(DBusMessageIter *iter_dict,
const char *key,
const dbus_int16_t value)
{
return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT16,
&value);
}
/**
* Add a 16-bit unsigned integer entry to the dict.
*
* @param iter_dict A valid DBusMessageIter returned from
* wpa_dbus_dict_open_write()
* @param key The key of the dict item
* @param value The 16-bit unsigned integer value
* @return TRUE on success, FALSE on failure
*
*/
dbus_bool_t wpa_dbus_dict_append_uint16(DBusMessageIter *iter_dict,
const char *key,
const dbus_uint16_t value)
{
return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT16,
&value);
}
/**
* Add a 32-bit signed integer to the dict.
*
* @param iter_dict A valid DBusMessageIter returned from
* wpa_dbus_dict_open_write()
* @param key The key of the dict item
* @param value The 32-bit signed integer value
* @return TRUE on success, FALSE on failure
*
*/
dbus_bool_t wpa_dbus_dict_append_int32(DBusMessageIter *iter_dict,
const char *key,
const dbus_int32_t value)
{
return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT32,
&value);
}
/**
* Add a 32-bit unsigned integer entry to the dict.
*
* @param iter_dict A valid DBusMessageIter returned from
* wpa_dbus_dict_open_write()
* @param key The key of the dict item
* @param value The 32-bit unsigned integer value
* @return TRUE on success, FALSE on failure
*
*/
dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict,
const char *key,
const dbus_uint32_t value)
{
return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT32,
&value);
}
/**
* Add a 64-bit integer entry to the dict.
*
* @param iter_dict A valid DBusMessageIter returned from
* wpa_dbus_dict_open_write()
* @param key The key of the dict item
* @param value The 64-bit integer value
* @return TRUE on success, FALSE on failure
*
*/
dbus_bool_t wpa_dbus_dict_append_int64(DBusMessageIter *iter_dict,
const char *key,
const dbus_int64_t value)
{
return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT64,
&value);
}
/**
* Add a 64-bit unsigned integer entry to the dict.
*
* @param iter_dict A valid DBusMessageIter returned from
* wpa_dbus_dict_open_write()
* @param key The key of the dict item
* @param value The 64-bit unsigned integer value
* @return TRUE on success, FALSE on failure
*
*/
dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict,
const char *key,
const dbus_uint64_t value)
{
return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT64,
&value);
}
/**
* Add a double-precision floating point entry to the dict.
*
* @param iter_dict A valid DBusMessageIter returned from
* wpa_dbus_dict_open_write()
* @param key The key of the dict item
* @param value The double-precision floating point value
* @return TRUE on success, FALSE on failure
*
*/
dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict,
const char *key, const double value)
{
return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_DOUBLE,
&value);
}
/**
* Add a DBus object path entry to the dict.
*
* @param iter_dict A valid DBusMessageIter returned from
* wpa_dbus_dict_open_write()
* @param key The key of the dict item
* @param value The DBus object path value
* @return TRUE on success, FALSE on failure
*
*/
dbus_bool_t wpa_dbus_dict_append_object_path(DBusMessageIter *iter_dict,
const char *key,
const char *value)
{
if (!value)
return FALSE;
return _wpa_dbus_add_dict_entry_basic(iter_dict, key,
DBUS_TYPE_OBJECT_PATH, &value);
}
/**
* Add a byte array entry to the dict.
*
* @param iter_dict A valid DBusMessageIter returned from
* wpa_dbus_dict_open_write()
* @param key The key of the dict item
* @param value The byte array
* @param value_len The length of the byte array, in bytes
* @return TRUE on success, FALSE on failure
*
*/
dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict,
const char *key,
const char *value,
const dbus_uint32_t value_len)
{
if (!key)
return FALSE;
if (!value && (value_len != 0))
return FALSE;
return _wpa_dbus_add_dict_entry_byte_array(iter_dict, key, value,
value_len);
}
/**
* Begin an array entry in the dict
*
* @param iter_dict A valid DBusMessageIter returned from
* wpa_dbus_dict_open_write()
* @param key The key of the dict item
* @param type The type of the contained data
* @param iter_dict_entry A private DBusMessageIter provided by the caller to
* be passed to wpa_dbus_dict_end_string_array()
* @param iter_dict_val A private DBusMessageIter provided by the caller to
* be passed to wpa_dbus_dict_end_string_array()
* @param iter_array On return, the DBusMessageIter to be passed to
* wpa_dbus_dict_string_array_add_element()
* @return TRUE on success, FALSE on failure
*
*/
dbus_bool_t wpa_dbus_dict_begin_array(DBusMessageIter *iter_dict,
const char *key, const char *type,
DBusMessageIter *iter_dict_entry,
DBusMessageIter *iter_dict_val,
DBusMessageIter *iter_array)
{
char array_type[10];
int err;
err = os_snprintf(array_type, sizeof(array_type),
DBUS_TYPE_ARRAY_AS_STRING "%s",
type);
if (err < 0 || err > (int) sizeof(array_type))
return FALSE;
if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
return FALSE;
if (!_wpa_dbus_add_dict_entry_start(iter_dict, iter_dict_entry,
key, DBUS_TYPE_ARRAY))
return FALSE;
if (!dbus_message_iter_open_container(iter_dict_entry,
DBUS_TYPE_VARIANT,
array_type,
iter_dict_val))
return FALSE;
if (!dbus_message_iter_open_container(iter_dict_val, DBUS_TYPE_ARRAY,
type, iter_array))
return FALSE;
return TRUE;
}
dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
const char *key,
DBusMessageIter *iter_dict_entry,
DBusMessageIter *iter_dict_val,
DBusMessageIter *iter_array)
{
return wpa_dbus_dict_begin_array(
iter_dict, key,
DBUS_TYPE_STRING_AS_STRING,
iter_dict_entry, iter_dict_val, iter_array);
}
/**
* Add a single string element to a string array dict entry
*
* @param iter_array A valid DBusMessageIter returned from
* wpa_dbus_dict_begin_string_array()'s
* iter_array parameter
* @param elem The string element to be added to the dict entry's string array
* @return TRUE on success, FALSE on failure
*
*/
dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array,
const char *elem)
{
if (!iter_array || !elem)
return FALSE;
return dbus_message_iter_append_basic(iter_array, DBUS_TYPE_STRING,
&elem);
}
/**
* Add a single byte array element to a string array dict entry
*
* @param iter_array A valid DBusMessageIter returned from
* wpa_dbus_dict_begin_array()'s iter_array
* parameter -- note that wpa_dbus_dict_begin_array()
* must have been called with "ay" as the type
* @param value The data to be added to the dict entry's array
* @param value_len The length of the data
* @return TRUE on success, FALSE on failure
*
*/
dbus_bool_t wpa_dbus_dict_bin_array_add_element(DBusMessageIter *iter_array,
const u8 *value,
size_t value_len)
{
DBusMessageIter iter_bytes;
size_t i;
if (!iter_array || !value)
return FALSE;
if (!dbus_message_iter_open_container(iter_array, DBUS_TYPE_ARRAY,
DBUS_TYPE_BYTE_AS_STRING,
&iter_bytes))
return FALSE;
for (i = 0; i < value_len; i++) {
if (!dbus_message_iter_append_basic(&iter_bytes,
DBUS_TYPE_BYTE,
&(value[i])))
return FALSE;
}
if (!dbus_message_iter_close_container(iter_array, &iter_bytes))
return FALSE;
return TRUE;
}
/**
* End an array dict entry
*
* @param iter_dict A valid DBusMessageIter returned from
* wpa_dbus_dict_open_write()
* @param iter_dict_entry A private DBusMessageIter returned from
* wpa_dbus_dict_begin_string_array() or
* wpa_dbus_dict_begin_array()
* @param iter_dict_val A private DBusMessageIter returned from
* wpa_dbus_dict_begin_string_array() or
* wpa_dbus_dict_begin_array()
* @param iter_array A DBusMessageIter returned from
* wpa_dbus_dict_begin_string_array() or
* wpa_dbus_dict_begin_array()
* @return TRUE on success, FALSE on failure
*
*/
dbus_bool_t wpa_dbus_dict_end_array(DBusMessageIter *iter_dict,
DBusMessageIter *iter_dict_entry,
DBusMessageIter *iter_dict_val,
DBusMessageIter *iter_array)
{
if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
return FALSE;
if (!dbus_message_iter_close_container(iter_dict_val, iter_array))
return FALSE;
if (!_wpa_dbus_add_dict_entry_end(iter_dict, iter_dict_entry,
iter_dict_val))
return FALSE;
return TRUE;
}
/**
* Convenience function to add an entire string array to the dict.
*
* @param iter_dict A valid DBusMessageIter returned from
* wpa_dbus_dict_open_write()
* @param key The key of the dict item
* @param items The array of strings
* @param num_items The number of strings in the array
* @return TRUE on success, FALSE on failure
*
*/
dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict,
const char *key,
const char **items,
const dbus_uint32_t num_items)
{
DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
dbus_uint32_t i;
if (!key)
return FALSE;
if (!items && (num_items != 0))
return FALSE;
if (!wpa_dbus_dict_begin_string_array(iter_dict, key,
&iter_dict_entry, &iter_dict_val,
&iter_array))
return FALSE;
for (i = 0; i < num_items; i++) {
if (!wpa_dbus_dict_string_array_add_element(&iter_array,
items[i]))
return FALSE;
}
if (!wpa_dbus_dict_end_string_array(iter_dict, &iter_dict_entry,
&iter_dict_val, &iter_array))
return FALSE;
return TRUE;
}
/**
* Convenience function to add an wpabuf binary array to the dict.
*
* @param iter_dict A valid DBusMessageIter returned from
* wpa_dbus_dict_open_write()
* @param key The key of the dict item
* @param items The array of wpabuf structures
* @param num_items The number of strings in the array
* @return TRUE on success, FALSE on failure
*
*/
dbus_bool_t wpa_dbus_dict_append_wpabuf_array(DBusMessageIter *iter_dict,
const char *key,
const struct wpabuf **items,
const dbus_uint32_t num_items)
{
DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
dbus_uint32_t i;
if (!key)
return FALSE;
if (!items && (num_items != 0))
return FALSE;
if (!wpa_dbus_dict_begin_array(iter_dict, key,
DBUS_TYPE_ARRAY_AS_STRING
DBUS_TYPE_BYTE_AS_STRING,
&iter_dict_entry, &iter_dict_val,
&iter_array))
return FALSE;
for (i = 0; i < num_items; i++) {
if (!wpa_dbus_dict_bin_array_add_element(&iter_array,
wpabuf_head(items[i]),
wpabuf_len(items[i])))
return FALSE;
}
if (!wpa_dbus_dict_end_array(iter_dict, &iter_dict_entry,
&iter_dict_val, &iter_array))
return FALSE;
return TRUE;
}
/*****************************************************/
/* Stuff for reading dicts */
/*****************************************************/
/**
* Start reading from a dbus dict.
*
* @param iter A valid DBusMessageIter pointing to the start of the dict
* @param iter_dict (out) A DBusMessageIter to be passed to
* wpa_dbus_dict_read_next_entry()
* @return TRUE on success, FALSE on failure
*
*/
dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter,
DBusMessageIter *iter_dict)
{
if (!iter || !iter_dict)
return FALSE;
if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
dbus_message_iter_get_element_type(iter) != DBUS_TYPE_DICT_ENTRY)
return FALSE;
dbus_message_iter_recurse(iter, iter_dict);
return TRUE;
}
#define BYTE_ARRAY_CHUNK_SIZE 34
#define BYTE_ARRAY_ITEM_SIZE (sizeof(char))
static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array(
DBusMessageIter *iter, struct wpa_dbus_dict_entry *entry)
{
dbus_uint32_t count = 0;
dbus_bool_t success = FALSE;
char *buffer, *nbuffer;;
entry->bytearray_value = NULL;
entry->array_type = DBUS_TYPE_BYTE;
buffer = os_zalloc(BYTE_ARRAY_ITEM_SIZE * BYTE_ARRAY_CHUNK_SIZE);
if (!buffer)
return FALSE;
entry->bytearray_value = buffer;
entry->array_len = 0;
while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_BYTE) {
char byte;
if ((count % BYTE_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
nbuffer = os_realloc(buffer, BYTE_ARRAY_ITEM_SIZE *
(count + BYTE_ARRAY_CHUNK_SIZE));
if (nbuffer == NULL) {
os_free(buffer);
wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_"
"entry_get_byte_array out of "
"memory trying to retrieve the "
"string array");
goto done;
}
buffer = nbuffer;
}
entry->bytearray_value = buffer;
dbus_message_iter_get_basic(iter, &byte);
entry->bytearray_value[count] = byte;
entry->array_len = ++count;
dbus_message_iter_next(iter);
}
/* Zero-length arrays are valid. */
if (entry->array_len == 0) {
os_free(entry->bytearray_value);
entry->bytearray_value = NULL;
}
success = TRUE;
done:
return success;
}
#define STR_ARRAY_CHUNK_SIZE 8
#define STR_ARRAY_ITEM_SIZE (sizeof(char *))
static dbus_bool_t _wpa_dbus_dict_entry_get_string_array(
DBusMessageIter *iter, int array_type,
struct wpa_dbus_dict_entry *entry)
{
dbus_uint32_t count = 0;
dbus_bool_t success = FALSE;
char **buffer, **nbuffer;
entry->strarray_value = NULL;
entry->array_type = DBUS_TYPE_STRING;
buffer = os_zalloc(STR_ARRAY_ITEM_SIZE * STR_ARRAY_CHUNK_SIZE);
if (buffer == NULL)
return FALSE;
entry->strarray_value = buffer;
entry->array_len = 0;
while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
const char *value;
char *str;
if ((count % STR_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
nbuffer = os_realloc(buffer, STR_ARRAY_ITEM_SIZE *
(count + STR_ARRAY_CHUNK_SIZE));
if (nbuffer == NULL) {
os_free(buffer);
wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_"
"entry_get_string_array out of "
"memory trying to retrieve the "
"string array");
goto done;
}
buffer = nbuffer;
}
entry->strarray_value = buffer;
dbus_message_iter_get_basic(iter, &value);
str = os_strdup(value);
if (str == NULL) {
wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_entry_get_"
"string_array out of memory trying to "
"duplicate the string array");
goto done;
}
entry->strarray_value[count] = str;
entry->array_len = ++count;
dbus_message_iter_next(iter);
}
/* Zero-length arrays are valid. */
if (entry->array_len == 0) {
os_free(entry->strarray_value);
entry->strarray_value = NULL;
}
success = TRUE;
done:
return success;
}
#define BIN_ARRAY_CHUNK_SIZE 10
#define BIN_ARRAY_ITEM_SIZE (sizeof(struct wpabuf *))
static dbus_bool_t _wpa_dbus_dict_entry_get_binarray(
DBusMessageIter *iter, struct wpa_dbus_dict_entry *entry)
{
struct wpa_dbus_dict_entry tmpentry;
size_t buflen = 0;
int i;
if (dbus_message_iter_get_element_type(iter) != DBUS_TYPE_BYTE)
return FALSE;
entry->array_type = WPAS_DBUS_TYPE_BINARRAY;
entry->array_len = 0;
entry->binarray_value = NULL;
while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_ARRAY) {
DBusMessageIter iter_array;
if (entry->array_len == buflen) {
struct wpabuf **newbuf;
buflen += BIN_ARRAY_CHUNK_SIZE;
newbuf = os_realloc(entry->binarray_value,
buflen * BIN_ARRAY_ITEM_SIZE);
if (!newbuf)
goto cleanup;
entry->binarray_value = newbuf;
}
dbus_message_iter_recurse(iter, &iter_array);
if (_wpa_dbus_dict_entry_get_byte_array(&iter_array, &tmpentry)
== FALSE)
goto cleanup;
entry->binarray_value[entry->array_len] =
wpabuf_alloc_ext_data((u8 *) tmpentry.bytearray_value,
tmpentry.array_len);
if (entry->binarray_value[entry->array_len] == NULL) {
wpa_dbus_dict_entry_clear(&tmpentry);
goto cleanup;
}
entry->array_len++;
dbus_message_iter_next(iter);
}
return TRUE;
cleanup:
for (i = 0; i < (int) entry->array_len; i++)
wpabuf_free(entry->binarray_value[i]);
os_free(entry->binarray_value);
entry->array_len = 0;
entry->binarray_value = NULL;
return FALSE;
}
static dbus_bool_t _wpa_dbus_dict_entry_get_array(
DBusMessageIter *iter_dict_val, struct wpa_dbus_dict_entry *entry)
{
int array_type = dbus_message_iter_get_element_type(iter_dict_val);
dbus_bool_t success = FALSE;
DBusMessageIter iter_array;
if (!entry)
return FALSE;
dbus_message_iter_recurse(iter_dict_val, &iter_array);
switch (array_type) {
case DBUS_TYPE_BYTE:
success = _wpa_dbus_dict_entry_get_byte_array(&iter_array,
entry);
break;
case DBUS_TYPE_STRING:
success = _wpa_dbus_dict_entry_get_string_array(&iter_array,
array_type,
entry);
break;
case DBUS_TYPE_ARRAY:
success = _wpa_dbus_dict_entry_get_binarray(&iter_array, entry);
default:
break;
}
return success;
}
static dbus_bool_t _wpa_dbus_dict_fill_value_from_variant(
struct wpa_dbus_dict_entry *entry, DBusMessageIter *iter)
{
const char *v;
switch (entry->type) {
case DBUS_TYPE_OBJECT_PATH:
case DBUS_TYPE_STRING:
dbus_message_iter_get_basic(iter, &v);
entry->str_value = os_strdup(v);
if (entry->str_value == NULL)
return FALSE;
break;
case DBUS_TYPE_BOOLEAN:
dbus_message_iter_get_basic(iter, &entry->bool_value);
break;
case DBUS_TYPE_BYTE:
dbus_message_iter_get_basic(iter, &entry->byte_value);
break;
case DBUS_TYPE_INT16:
dbus_message_iter_get_basic(iter, &entry->int16_value);
break;
case DBUS_TYPE_UINT16:
dbus_message_iter_get_basic(iter, &entry->uint16_value);
break;
case DBUS_TYPE_INT32:
dbus_message_iter_get_basic(iter, &entry->int32_value);
break;
case DBUS_TYPE_UINT32:
dbus_message_iter_get_basic(iter, &entry->uint32_value);
break;
case DBUS_TYPE_INT64:
dbus_message_iter_get_basic(iter, &entry->int64_value);
break;
case DBUS_TYPE_UINT64:
dbus_message_iter_get_basic(iter, &entry->uint64_value);
break;
case DBUS_TYPE_DOUBLE:
dbus_message_iter_get_basic(iter, &entry->double_value);
break;
case DBUS_TYPE_ARRAY:
return _wpa_dbus_dict_entry_get_array(iter, entry);
default:
return FALSE;
}
return TRUE;
}
/**
* Read the current key/value entry from the dict. Entries are dynamically
* allocated when needed and must be freed after use with the
* wpa_dbus_dict_entry_clear() function.
*
* The returned entry object will be filled with the type and value of the next
* entry in the dict, or the type will be DBUS_TYPE_INVALID if an error
* occurred.
*
* @param iter_dict A valid DBusMessageIter returned from
* wpa_dbus_dict_open_read()
* @param entry A valid dict entry object into which the dict key and value
* will be placed
* @return TRUE on success, FALSE on failure
*
*/
dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict,
struct wpa_dbus_dict_entry * entry)
{
DBusMessageIter iter_dict_entry, iter_dict_val;
int type;
const char *key;
if (!iter_dict || !entry)
goto error;
if (dbus_message_iter_get_arg_type(iter_dict) != DBUS_TYPE_DICT_ENTRY)
goto error;
dbus_message_iter_recurse(iter_dict, &iter_dict_entry);
dbus_message_iter_get_basic(&iter_dict_entry, &key);
entry->key = key;
if (!dbus_message_iter_next(&iter_dict_entry))
goto error;
type = dbus_message_iter_get_arg_type(&iter_dict_entry);
if (type != DBUS_TYPE_VARIANT)
goto error;
dbus_message_iter_recurse(&iter_dict_entry, &iter_dict_val);
entry->type = dbus_message_iter_get_arg_type(&iter_dict_val);
if (!_wpa_dbus_dict_fill_value_from_variant(entry, &iter_dict_val))
goto error;
dbus_message_iter_next(iter_dict);
return TRUE;
error:
if (entry) {
wpa_dbus_dict_entry_clear(entry);
entry->type = DBUS_TYPE_INVALID;
entry->array_type = DBUS_TYPE_INVALID;
}
return FALSE;
}
/**
* Return whether or not there are additional dictionary entries.
*
* @param iter_dict A valid DBusMessageIter returned from
* wpa_dbus_dict_open_read()
* @return TRUE if more dict entries exists, FALSE if no more dict entries
* exist
*/
dbus_bool_t wpa_dbus_dict_has_dict_entry(DBusMessageIter *iter_dict)
{
if (!iter_dict)
return FALSE;
return dbus_message_iter_get_arg_type(iter_dict) ==
DBUS_TYPE_DICT_ENTRY;
}
/**
* Free any memory used by the entry object.
*
* @param entry The entry object
*/
void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry)
{
unsigned int i;
if (!entry)
return;
switch (entry->type) {
case DBUS_TYPE_OBJECT_PATH:
case DBUS_TYPE_STRING:
os_free(entry->str_value);
break;
case DBUS_TYPE_ARRAY:
switch (entry->array_type) {
case DBUS_TYPE_BYTE:
os_free(entry->bytearray_value);
break;
case DBUS_TYPE_STRING:
for (i = 0; i < entry->array_len; i++)
os_free(entry->strarray_value[i]);
os_free(entry->strarray_value);
break;
}
break;
case WPAS_DBUS_TYPE_BINARRAY:
for (i = 0; i < entry->array_len; i++)
wpabuf_free(entry->binarray_value[i]);
os_free(entry->binarray_value);
break;
}
memset(entry, 0, sizeof(struct wpa_dbus_dict_entry));
}