hostap/wpa_supplicant/dbus/dbus_new_introspect.c
Jouni Malinen ce4f7fdbdd dbus: Get rid of libxml2 dependency with introspection
The XML used in D-Bus introspection is simple and there is no need to use
libxml2 to generate it. This gets rid of the dependency on the large
library by using internal XML generation.
2010-01-01 17:51:15 +02:00

327 lines
8.6 KiB
C

/*
* wpa_supplicant - D-Bus introspection
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
* Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
* Copyright (c) 2010, Jouni Malinen <j@w1.fi>
*
* 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 "utils/includes.h"
#include "utils/common.h"
#include "utils/list.h"
#include "utils/wpabuf.h"
#include "dbus_common_i.h"
#include "dbus_new_helpers.h"
struct interfaces {
struct dl_list list;
char *dbus_interface;
struct wpabuf *xml;
};
static void add_interface(struct dl_list *list, const char *dbus_interface)
{
struct interfaces *iface;
dl_list_for_each(iface, list, struct interfaces, list) {
if (os_strcmp(iface->dbus_interface, dbus_interface) == 0)
return; /* already in the list */
}
iface = os_zalloc(sizeof(struct interfaces));
if (!iface)
return;
iface->xml = wpabuf_alloc(3000);
if (iface->xml == NULL) {
os_free(iface);
return;
}
wpabuf_printf(iface->xml, "<interface name=\"%s\">", dbus_interface);
dl_list_add_tail(list, &iface->list);
iface->dbus_interface = os_strdup(dbus_interface);
}
static void extract_interfaces_methods(struct dl_list *list,
struct wpa_dbus_method_desc *methods)
{
struct wpa_dbus_method_desc *dsc;
for (dsc = methods; dsc; dsc = dsc->next)
add_interface(list, dsc->dbus_interface);
}
static void extract_interfaces_signals(struct dl_list *list,
struct wpa_dbus_signal_desc *signals)
{
struct wpa_dbus_signal_desc *dsc;
for (dsc = signals; dsc; dsc = dsc->next)
add_interface(list, dsc->dbus_interface);
}
static void extract_interfaces_properties(
struct dl_list *list, struct wpa_dbus_property_desc *properties)
{
struct wpa_dbus_property_desc *dsc;
for (dsc = properties; dsc; dsc = dsc->next)
add_interface(list, dsc->dbus_interface);
}
/**
* extract_interfaces - Extract interfaces from methods, signals and props
* @list: Interface list to be filled
* @obj_dsc: Description of object from which interfaces will be extracted
*
* Iterates over all methods, signals, and properties registered with an
* object and collects all declared DBus interfaces and create interfaces'
* node in XML root node for each. Returned list elements contain interface
* name and XML node of corresponding interface.
*/
static void extract_interfaces(struct dl_list *list,
struct wpa_dbus_object_desc *obj_dsc)
{
extract_interfaces_methods(list, obj_dsc->methods);
extract_interfaces_signals(list, obj_dsc->signals);
extract_interfaces_properties(list, obj_dsc->properties);
}
static void add_interfaces(struct dl_list *list, struct wpabuf *xml)
{
struct interfaces *iface, *n;
dl_list_for_each_safe(iface, n, list, struct interfaces, list) {
wpabuf_put_buf(xml, iface->xml);
wpabuf_put_str(xml, "</interface>");
dl_list_del(&iface->list);
wpabuf_free(iface->xml);
os_free(iface->dbus_interface);
os_free(iface);
}
}
static struct interfaces * get_interface(struct dl_list *list,
const char *dbus_interface)
{
struct interfaces *iface;
dl_list_for_each(iface, list, struct interfaces, list) {
if (os_strcmp(iface->dbus_interface, dbus_interface) == 0)
return iface;
}
return NULL;
}
static void add_child_nodes(struct wpabuf *xml, DBusConnection *con,
const char *path)
{
char **children;
int i;
/* add child nodes to introspection tree */
dbus_connection_list_registered(con, path, &children);
for (i = 0; children[i]; i++)
wpabuf_printf(xml, "<node name=\"%s\"/>", children[i]);
dbus_free_string_array(children);
}
static void add_arg(struct wpabuf *xml, const char *name, const char *type,
const char *direction)
{
wpabuf_printf(xml, "<arg name=\"%s\"", name);
if (type)
wpabuf_printf(xml, " type=\"%s\"", type);
if (direction)
wpabuf_printf(xml, " direction=\"%s\"", direction);
wpabuf_put_str(xml, "/>");
}
static void add_introspectable_interface(struct wpabuf *xml)
{
wpabuf_printf(xml, "<interface name=\"%s\">"
"<method name=\"%s\">"
"<arg name=\"data\" type=\"s\" direction=\"out\"/>"
"</method>"
"</interface>",
WPA_DBUS_INTROSPECTION_INTERFACE,
WPA_DBUS_INTROSPECTION_METHOD);
}
static void add_properties_interface(struct wpabuf *xml)
{
wpabuf_printf(xml, "<interface name=\"%s\">",
WPA_DBUS_PROPERTIES_INTERFACE);
wpabuf_printf(xml, "<method name=\"%s\">", WPA_DBUS_PROPERTIES_GET);
add_arg(xml, "interface", "s", "in");
add_arg(xml, "propname", "s", "in");
add_arg(xml, "value", "v", "out");
wpabuf_put_str(xml, "</method>");
wpabuf_printf(xml, "<method name=\"%s\">", WPA_DBUS_PROPERTIES_GETALL);
add_arg(xml, "interface", "s", "in");
add_arg(xml, "props", "a{sv}", "out");
wpabuf_put_str(xml, "</method>");
wpabuf_printf(xml, "<method name=\"%s\">", WPA_DBUS_PROPERTIES_SET);
add_arg(xml, "interface", "s", "in");
add_arg(xml, "propname", "s", "in");
add_arg(xml, "value", "v", "in");
wpabuf_put_str(xml, "</method>");
wpabuf_put_str(xml, "</interface>");
}
static void add_entry(struct wpabuf *xml, char *type, char *name, int args_num,
struct wpa_dbus_argument *args, int include_dir)
{
int i;
if (args_num == 0) {
wpabuf_printf(xml, "<%s name=\"%s\"/>", type, name);
return;
}
wpabuf_printf(xml, "<%s name=\"%s\">", type, name);
for (i = 0; i < args_num; i++) {
struct wpa_dbus_argument *arg = &args[i];
add_arg(xml, arg->name, arg->type,
include_dir ? (arg->dir == ARG_IN ? "in" : "out") :
NULL);
}
wpabuf_printf(xml, "</%s>", type);
}
static void add_property(struct wpabuf *xml,
struct wpa_dbus_property_desc *dsc)
{
wpabuf_printf(xml, "<property name=\"%s\" type=\"%s\" access=\"%s\"/>",
dsc->dbus_property, dsc->type,
(dsc->access == R ? "read" :
(dsc->access == W ? "write" : "readwrite")));
}
static void create_method_nodes(struct dl_list *list,
struct wpa_dbus_method_desc *methods)
{
struct wpa_dbus_method_desc *dsc;
struct interfaces *iface;
for (dsc = methods; dsc; dsc = dsc->next) {
iface = get_interface(list, dsc->dbus_interface);
if (!iface)
continue;
add_entry(iface->xml, "method", dsc->dbus_method,
dsc->args_num, dsc->args, 1);
}
}
static void create_signal_nodes(struct dl_list *list,
struct wpa_dbus_signal_desc *signals)
{
struct wpa_dbus_signal_desc *dsc;
struct interfaces *iface;
for (dsc = signals; dsc; dsc = dsc->next) {
iface = get_interface(list, dsc->dbus_interface);
if (!iface)
continue;
add_entry(iface->xml, "signal", dsc->dbus_signal,
dsc->args_num, dsc->args, 0);
}
}
static void create_property_nodes(struct dl_list *list,
struct wpa_dbus_property_desc *properties)
{
struct wpa_dbus_property_desc *dsc;
struct interfaces *iface;
for (dsc = properties; dsc; dsc = dsc->next) {
iface = get_interface(list, dsc->dbus_interface);
if (!iface)
continue;
add_property(iface->xml, dsc);
}
}
static void add_wpas_interfaces(struct wpabuf *xml,
struct wpa_dbus_object_desc *obj_dsc)
{
struct dl_list ifaces;
dl_list_init(&ifaces);
extract_interfaces(&ifaces, obj_dsc);
create_method_nodes(&ifaces, obj_dsc->methods);
create_signal_nodes(&ifaces, obj_dsc->signals);
create_property_nodes(&ifaces, obj_dsc->properties);
add_interfaces(&ifaces, xml);
}
/**
* wpa_dbus_introspect - Responds for Introspect calls on object
* @message: Message with Introspect call
* @obj_dsc: Object description on which Introspect was called
* Returns: Message with introspection result XML string as only argument
*
* Iterates over all methods, signals and properties registered with
* object and generates introspection data for the object as XML string.
*/
DBusMessage * wpa_dbus_introspect(DBusMessage *message,
struct wpa_dbus_object_desc *obj_dsc)
{
DBusMessage *reply;
struct wpabuf *xml;
const char *intro_str;
xml = wpabuf_alloc(4000);
if (xml == NULL)
return NULL;
wpabuf_put_str(xml, "<?xml version=\"1.0\"?>\n");
wpabuf_put_str(xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE);
wpabuf_put_str(xml, "<node>");
add_introspectable_interface(xml);
add_properties_interface(xml);
add_wpas_interfaces(xml, obj_dsc);
add_child_nodes(xml, obj_dsc->connection,
dbus_message_get_path(message));
wpabuf_put_str(xml, "</node>\n");
reply = dbus_message_new_method_return(message);
if (reply == NULL) {
wpabuf_free(xml);
return NULL;
}
intro_str = wpabuf_head(xml);
dbus_message_append_args(reply, DBUS_TYPE_STRING, &intro_str,
DBUS_TYPE_INVALID);
wpabuf_free(xml);
return reply;
}