dbus: Move introspection support into a separate file
authorJouni Malinen <j@w1.fi>
Fri, 1 Jan 2010 12:03:00 +0000 (14:03 +0200)
committerJouni Malinen <j@w1.fi>
Fri, 1 Jan 2010 12:03:00 +0000 (14:03 +0200)
wpa_supplicant/Makefile
wpa_supplicant/dbus/Makefile
wpa_supplicant/dbus/dbus_new_helpers.c
wpa_supplicant/dbus/dbus_new_helpers.h
wpa_supplicant/dbus/dbus_new_introspect.c [new file with mode: 0644]

index 9385485..723f9c0 100644 (file)
@@ -1083,6 +1083,7 @@ ifndef DBUS_INCLUDE
 DBUS_INCLUDE := $(shell pkg-config --cflags dbus-1)
 endif
 ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
+DBUS_OBJS += dbus/dbus_new_introspect.o
 DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO
 DBUS_INCLUDE += $(shell xml2-config --cflags)
 DBUS_LIBS += $(shell xml2-config --libs)
index 4d7a4d8..cfaf58d 100644 (file)
@@ -70,6 +70,7 @@ LIB_OBJS= \
        dbus_new.o \
        dbus_new_handlers.o \
        dbus_new_helpers.o \
+       dbus_new_introspect.o \
        dbus_dict_helpers.o
 
 ifdef CONFIG_WPS
index e71aba7..d172a15 100644 (file)
 #include "includes.h"
 
 #include "common.h"
-#include "eloop.h"
 #include "dbus_common.h"
 #include "dbus_common_i.h"
 #include "dbus_new_helpers.h"
 
-/**
- * struct wpa_dbus_method_desc - DBus method description
- */
-struct wpa_dbus_method_desc {
-       /* pointer to next description in list */
-       struct wpa_dbus_method_desc *next;
-
-       /* method interface */
-       char *dbus_interface;
-       /* method name */
-       char *dbus_method;
-
-       /* method handling function */
-       WPADBusMethodHandler method_handler;
-
-       /* number of method arguments */
-       int args_num;
-       /* array of arguments */
-       struct wpa_dbus_argument args[];
-};
-
-
-/**
- * struct wpa_dbus_signal_desc - DBus signal description
- */
-struct wpa_dbus_signal_desc {
-       /* pointer to next description in list */
-       struct wpa_dbus_signal_desc *next;
-
-       /* signal interface */
-       char *dbus_interface;
-       /* signal name */
-       char *dbus_signal;
-
-       /* number of signal arguments */
-       int args_num;
-       /* array of arguments */
-       struct wpa_dbus_argument args[0];
-};
-
-
-/**
- * struct wpa_dbus_property_desc - DBus property description
- */
-struct wpa_dbus_property_desc {
-       /* pointer to next description in list */
-       struct wpa_dbus_property_desc *next;
-
-       /* property interface */
-       char *dbus_interface;
-       /* property name */
-       char *dbus_property;
-       /* property type signature in DBus type notation */
-       char *type;
-
-       /* property access permissions */
-       enum dbus_prop_access access;
-
-       /* property getter function */
-       WPADBusPropertyAccessor getter;
-       /* property setter function */
-       WPADBusPropertyAccessor setter;
-};
-
-
-#ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
-#include <libxml/tree.h>
-
-struct interfaces {
-       struct interfaces *next;
-       char *dbus_interface;
-       xmlNodePtr interface_node;
-};
-#endif /* CONFIG_CTRL_IFACE_DBUS_INTRO */
-
-
-#ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
-
-/**
- * extract_interfaces - Extract interfaces from methods, signals and props
- * @obj_dsc: Description of object from which interfaces will be extracted
- * @root_node: root node of XML introspection document
- * Returns: List of interfaces found in object description
- *
- * Iterates over all methods, signals and properties registered with
- * object and collects all declared DBus interfaces and create interface's
- * node in XML root node for each. Returned list elements contains interface
- * name and XML node of corresponding interface.
- */
-static struct interfaces * extract_interfaces(
-       struct wpa_dbus_object_desc *obj_dsc, xmlNodePtr root_node)
-{
-       struct wpa_dbus_method_desc *method_dsc = obj_dsc->methods;
-       struct wpa_dbus_signal_desc *signal_dsc = obj_dsc->signals;
-       struct wpa_dbus_property_desc *property_dsc = obj_dsc->properties;
-       struct interfaces *head = NULL;
-       struct interfaces *iface, *last;
-       int len;
-
-       /* extract interfaces from methods */
-       while (method_dsc) {
-               iface = head;
-               last = NULL;
-
-               /* go to next method if its interface is already extracted */
-               while (iface) {
-                       if (!os_strcmp(iface->dbus_interface,
-                                      method_dsc->dbus_interface))
-                               break;
-                       last = iface;
-                       iface = iface->next;
-               }
-               if (iface) {
-                       method_dsc = method_dsc->next;
-                       continue;
-               }
-
-               iface = os_zalloc(sizeof(struct interfaces));
-               if (!iface) {
-                       wpa_printf(MSG_ERROR, "Not enough memory to create "
-                               "interface introspection data");
-                       method_dsc = method_dsc->next;
-                       continue;
-               }
-
-               if (last)
-                       last->next = iface;
-               else
-                       head = iface;
-
-               len = os_strlen(method_dsc->dbus_interface) + 1;
-               iface->dbus_interface = os_malloc(len);
-               if (!iface->dbus_interface) {
-                       wpa_printf(MSG_ERROR, "Not enough memory to create "
-                                  "interface introspection data (interface "
-                                  "name)");
-                       method_dsc = method_dsc->next;
-                       continue;
-               }
-               os_strncpy(iface->dbus_interface, method_dsc->dbus_interface,
-                          len);
-
-               iface->interface_node = xmlNewChild(root_node, NULL,
-                                                   BAD_CAST "interface",
-                                                   NULL);
-               xmlNewProp(iface->interface_node, BAD_CAST "name",
-                          BAD_CAST method_dsc->dbus_interface);
-
-               method_dsc = method_dsc->next;
-       }
-
-       /* extract interfaces from signals */
-       while (signal_dsc) {
-               iface = head;
-               last = NULL;
-
-               /* go to next signal if its interface is already extracted */
-               while (iface) {
-                       if (!os_strcmp(iface->dbus_interface,
-                                      signal_dsc->dbus_interface))
-                               break;
-                       last = iface;
-                       iface = iface->next;
-               }
-               if (iface) {
-                       signal_dsc = signal_dsc->next;
-                       continue;
-               }
-
-               iface = os_zalloc(sizeof(struct interfaces));
-               if (!iface) {
-                       wpa_printf(MSG_ERROR, "Not enough memory to create "
-                                  "interface introspection data");
-                       signal_dsc = signal_dsc->next;
-                       continue;
-               }
-
-               if (last)
-                       last->next = iface;
-               else
-                       head = iface;
-
-               len = os_strlen(signal_dsc->dbus_interface) + 1;
-               iface->dbus_interface = os_malloc(len);
-               if (!iface->dbus_interface) {
-                       wpa_printf(MSG_ERROR, "Not enough memory to create "
-                                  "interface introspection data (interface "
-                                  "name)");
-                       signal_dsc = signal_dsc->next;
-                       continue;
-               }
-               os_strncpy(iface->dbus_interface, signal_dsc->dbus_interface,
-                          len);
-
-               iface->interface_node = xmlNewChild(root_node, NULL,
-                                                   BAD_CAST "interface",
-                                                   NULL);
-               xmlNewProp(iface->interface_node, BAD_CAST "name",
-                          BAD_CAST signal_dsc->dbus_interface);
-
-               signal_dsc = signal_dsc->next;
-       }
-
-       /* extract interfaces from properties */
-       while (property_dsc) {
-               iface = head;
-               last = NULL;
-
-               /* go to next property if its interface is already extracted */
-               while (iface) {
-                       if (!os_strcmp(iface->dbus_interface,
-                                      property_dsc->dbus_interface))
-                               break;
-                       last = iface;
-                       iface = iface->next;
-               }
-               if (iface) {
-                       property_dsc = property_dsc->next;
-                       continue;
-               }
-
-               iface = os_zalloc(sizeof(struct interfaces));
-               if (!iface) {
-                       wpa_printf(MSG_ERROR, "Not enough memory to create "
-                                  "interface introspection data");
-                       property_dsc = property_dsc->next;
-                       continue;
-               }
-
-               if (last)
-                       last->next = iface;
-               else
-                       head = iface;
-
-               len = os_strlen(property_dsc->dbus_interface) + 1;
-               iface->dbus_interface = os_malloc(len);
-               if (!iface->dbus_interface) {
-                       wpa_printf(MSG_ERROR, "Not enough memory to create "
-                                  "interface introspection data (interface "
-                                  "name)");
-                       property_dsc = property_dsc->next;
-                       continue;
-               }
-               os_strncpy(iface->dbus_interface, property_dsc->dbus_interface,
-                          len);
-
-               iface->interface_node = xmlNewChild(root_node, NULL,
-                                                   BAD_CAST "interface",
-                                                   NULL);
-               xmlNewProp(iface->interface_node, BAD_CAST "name",
-                          BAD_CAST property_dsc->dbus_interface);
-
-               property_dsc = property_dsc->next;
-       }
-
-       return head;
-}
-
-
-/**
- * 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.
- */
-static DBusMessage * introspect(DBusMessage *message,
-                               struct wpa_dbus_object_desc *obj_dsc)
-{
-
-       DBusMessage *reply;
-       struct interfaces *ifaces, *tmp;
-       struct wpa_dbus_signal_desc *signal_dsc;
-       struct wpa_dbus_method_desc *method_dsc;
-       struct wpa_dbus_property_desc *property_dsc;
-       xmlChar *intro_str;
-       char **children;
-       int i, s;
-
-       xmlDocPtr doc = NULL;
-       xmlNodePtr root_node = NULL, node = NULL, iface_node = NULL;
-       xmlNodePtr method_node = NULL, signal_node = NULL;
-       xmlNodePtr property_node = NULL, arg_node = NULL;
-
-       /* root node and dtd */
-       doc = xmlNewDoc(BAD_CAST "1.0");
-       root_node = xmlNewNode(NULL, BAD_CAST "node");
-       xmlDocSetRootElement(doc, root_node);
-       xmlCreateIntSubset(doc, BAD_CAST "node",
-                          BAD_CAST DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER,
-                          BAD_CAST DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER);
-
-       /* Add Introspectable interface */
-       iface_node = xmlNewChild(root_node, NULL, BAD_CAST "interface", NULL);
-       xmlNewProp(iface_node, BAD_CAST "name",
-                  BAD_CAST WPA_DBUS_INTROSPECTION_INTERFACE);
-
-       /* Add Introspect method */
-       method_node = xmlNewChild(iface_node, NULL, BAD_CAST "method", NULL);
-       xmlNewProp(method_node, BAD_CAST "name",
-                  BAD_CAST WPA_DBUS_INTROSPECTION_METHOD);
-       arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
-       xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "data");
-       xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s");
-       xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "out");
-
-
-       /* Add Properties interface */
-       iface_node = xmlNewChild(root_node, NULL,
-                                BAD_CAST "interface", NULL);
-       xmlNewProp(iface_node, BAD_CAST "name",
-                  BAD_CAST WPA_DBUS_PROPERTIES_INTERFACE);
-
-       /* Add Get method */
-       method_node = xmlNewChild(iface_node, NULL, BAD_CAST "method", NULL);
-       xmlNewProp(method_node, BAD_CAST "name",
-                  BAD_CAST WPA_DBUS_PROPERTIES_GET);
-       arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
-       xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "interface");
-       xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s");
-       xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in");
-       arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
-       xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "propname");
-       xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s");
-       xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in");
-       arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
-       xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "value");
-       xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "v");
-       xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "out");
-       method_node = xmlNewChild(iface_node, NULL, BAD_CAST "method", NULL);
-
-       /* Add GetAll method */
-       xmlNewProp(method_node, BAD_CAST "name",
-                  BAD_CAST WPA_DBUS_PROPERTIES_GETALL);
-       arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
-       xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "interface");
-       xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s");
-       xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in");
-       arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
-       xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "props");
-       xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "a{sv}");
-       xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "out");
-       method_node = xmlNewChild(iface_node, NULL, BAD_CAST "method", NULL);
-
-       /* Add Set method */
-       xmlNewProp(method_node, BAD_CAST "name",
-                  BAD_CAST WPA_DBUS_PROPERTIES_SET);
-       arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
-       xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "interface");
-       xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s");
-       xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in");
-       arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
-       xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "propname");
-       xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s");
-       xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in");
-       arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
-       xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "value");
-       xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "v");
-       xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in");
-
-       /* get all interfaces registered with object */
-       ifaces = extract_interfaces(obj_dsc, root_node);
-
-       /* create methods' nodes */
-       method_dsc = obj_dsc->methods;
-       while (method_dsc) {
-
-               struct interfaces *iface = ifaces;
-               while (iface) {
-                       if (!os_strcmp(iface->dbus_interface,
-                                      method_dsc->dbus_interface))
-                               break;
-                       iface = iface->next;
-               }
-               if (!iface)
-                       continue;
-
-               iface_node = iface->interface_node;
-               method_node = xmlNewChild(iface_node, NULL, BAD_CAST "method",
-                                         NULL);
-               xmlNewProp(method_node, BAD_CAST "name",
-                          BAD_CAST method_dsc->dbus_method);
-
-               /* create args' nodes */
-               for (i = 0; i < method_dsc->args_num; i++) {
-                       struct wpa_dbus_argument arg = method_dsc->args[i];
-                       arg_node = xmlNewChild(method_node, NULL,
-                                              BAD_CAST "arg", NULL);
-                       if (arg.name && strlen(arg.name)) {
-                               xmlNewProp(arg_node, BAD_CAST "name",
-                                          BAD_CAST arg.name);
-                       }
-                       xmlNewProp(arg_node, BAD_CAST "type",
-                                  BAD_CAST arg.type);
-                       xmlNewProp(arg_node, BAD_CAST "direction",
-                                  BAD_CAST (arg.dir == ARG_IN ?
-                                            "in" : "out"));
-               }
-               method_dsc = method_dsc->next;
-       }
-
-       /* create signals' nodes */
-       signal_dsc = obj_dsc->signals;
-       while (signal_dsc) {
-
-               struct interfaces *iface = ifaces;
-               while (iface) {
-                       if (!os_strcmp(iface->dbus_interface,
-                                      signal_dsc->dbus_interface))
-                               break;
-                       iface = iface->next;
-               }
-               if (!iface)
-                       continue;
-
-               iface_node = iface->interface_node;
-               signal_node = xmlNewChild(iface_node, NULL, BAD_CAST "signal",
-                                         NULL);
-               xmlNewProp(signal_node, BAD_CAST "name",
-                          BAD_CAST signal_dsc->dbus_signal);
-
-               /* create args' nodes */
-               for (i = 0; i < signal_dsc->args_num; i++) {
-                       struct wpa_dbus_argument arg = signal_dsc->args[i];
-                       arg_node = xmlNewChild(signal_node, NULL,
-                                              BAD_CAST "arg", NULL);
-                       if (arg.name && strlen(arg.name)) {
-                               xmlNewProp(arg_node, BAD_CAST "name",
-                                          BAD_CAST arg.name);
-                       }
-                       xmlNewProp(arg_node, BAD_CAST "type",
-                                  BAD_CAST arg.type);
-               }
-               signal_dsc = signal_dsc->next;
-       }
-
-       /* create properties' nodes */
-       property_dsc = obj_dsc->properties;
-       while (property_dsc) {
-
-               struct interfaces *iface = ifaces;
-               while (iface) {
-                       if (!os_strcmp(iface->dbus_interface,
-                                      property_dsc->dbus_interface))
-                               break;
-                       iface = iface->next;
-               }
-               if (!iface)
-                       continue;
-
-               iface_node = iface->interface_node;
-               property_node = xmlNewChild(iface_node, NULL,
-                                           BAD_CAST "property", NULL);
-               xmlNewProp(property_node, BAD_CAST "name",
-                          BAD_CAST property_dsc->dbus_property);
-               xmlNewProp(property_node, BAD_CAST "type",
-                          BAD_CAST property_dsc->type);
-               xmlNewProp(property_node, BAD_CAST "access", BAD_CAST
-                          (property_dsc->access == R ? "read" :
-                           (property_dsc->access == W ?
-                            "write" : "readwrite")));
-
-               property_dsc = property_dsc->next;
-       }
-
-       /* add child nodes to introspection tree; */
-       dbus_connection_list_registered(obj_dsc->connection,
-                                       dbus_message_get_path(message),
-                                       &children);
-       for (i = 0; children[i]; i++) {
-               node = xmlNewChild(root_node, NULL, BAD_CAST "node", NULL);
-               xmlNewProp(node, BAD_CAST "name", BAD_CAST children[i]);
-       }
-       dbus_free_string_array(children);
-
-
-       xmlDocDumpFormatMemory(doc, &intro_str, &s, 1);
-
-       xmlFreeDoc(doc);
-
-       while (ifaces) {
-               tmp = ifaces;
-               ifaces = ifaces->next;
-               os_free(tmp->dbus_interface);
-               os_free(tmp);
-       }
-
-       reply = dbus_message_new_method_return(message);
-       if (reply == NULL) {
-               xmlFree(intro_str);
-               return NULL;
-       }
-
-       dbus_message_append_args(reply, DBUS_TYPE_STRING, &intro_str,
-                                DBUS_TYPE_INVALID);
-
-       xmlFree(intro_str);
-
-       return reply;
-}
-
-#else /* CONFIG_CTRL_IFACE_DBUS_INTRO */
-
-/**
- * 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
- *
- * Returns error informing that introspection support was not compiled.
- */
-static DBusMessage * introspect(DBusMessage *message,
-                               struct wpa_dbus_object_desc *obj_dsc)
-{
-       return dbus_message_new_error(message, DBUS_ERROR_UNKNOWN_METHOD,
-                                     "wpa_supplicant was compiled without "
-                                     "introspection support.");
-}
-
-#endif /* CONFIG_CTRL_IFACE_DBUS_INTRO */
-
 
 /**
  * recursive_iter_copy - Reads arguments from one iterator and
@@ -935,9 +411,16 @@ static DBusHandlerResult message_handler(DBusConnection *connection,
        if (!os_strncmp(WPA_DBUS_INTROSPECTION_METHOD, method,
                        WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
            !os_strncmp(WPA_DBUS_INTROSPECTION_INTERFACE, msg_interface,
-                       WPAS_DBUS_INTERFACE_MAX))
-               reply = introspect(message, obj_dsc);
-       else if (!os_strncmp(WPA_DBUS_PROPERTIES_INTERFACE, msg_interface,
+                       WPAS_DBUS_INTERFACE_MAX)) {
+#ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
+               reply = wpa_dbus_introspect(message, obj_dsc);
+#else /* CONFIG_CTRL_IFACE_DBUS_INTRO */
+               reply = dbus_message_new_error(
+                       message, DBUS_ERROR_UNKNOWN_METHOD,
+                       "wpa_supplicant was compiled without "
+                       "introspection support.");
+#endif /* CONFIG_CTRL_IFACE_DBUS_INTRO */
+       } else if (!os_strncmp(WPA_DBUS_PROPERTIES_INTERFACE, msg_interface,
                             WPAS_DBUS_INTERFACE_MAX)) {
                /* if message is properties method call */
                reply = properties_handler(message, obj_dsc);
index c528976..0fc742a 100644 (file)
@@ -52,6 +52,69 @@ struct wpa_dbus_argument {
 
 #define END_ARGS { NULL, NULL, ARG_IN }
 
+/**
+ * struct wpa_dbus_method_desc - DBus method description
+ */
+struct wpa_dbus_method_desc {
+       /* pointer to next description in list */
+       struct wpa_dbus_method_desc *next;
+
+       /* method interface */
+       char *dbus_interface;
+       /* method name */
+       char *dbus_method;
+
+       /* method handling function */
+       WPADBusMethodHandler method_handler;
+
+       /* number of method arguments */
+       int args_num;
+       /* array of arguments */
+       struct wpa_dbus_argument args[];
+};
+
+/**
+ * struct wpa_dbus_signal_desc - DBus signal description
+ */
+struct wpa_dbus_signal_desc {
+       /* pointer to next description in list */
+       struct wpa_dbus_signal_desc *next;
+
+       /* signal interface */
+       char *dbus_interface;
+       /* signal name */
+       char *dbus_signal;
+
+       /* number of signal arguments */
+       int args_num;
+       /* array of arguments */
+       struct wpa_dbus_argument args[0];
+};
+
+/**
+ * struct wpa_dbus_property_desc - DBus property description
+ */
+struct wpa_dbus_property_desc {
+       /* pointer to next description in list */
+       struct wpa_dbus_property_desc *next;
+
+       /* property interface */
+       char *dbus_interface;
+       /* property name */
+       char *dbus_property;
+       /* property type signature in DBus type notation */
+       char *type;
+
+       /* property access permissions */
+       enum dbus_prop_access access;
+
+       /* property getter function */
+       WPADBusPropertyAccessor getter;
+       /* property setter function */
+       WPADBusPropertyAccessor setter;
+};
+
+
 #ifndef SIGPOLL
 #ifdef SIGIO
 /*
@@ -118,4 +181,7 @@ void wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface,
                                    const char *path, const char *interface,
                                    DBusMessageIter *dict_iter);
 
+DBusMessage * wpa_dbus_introspect(DBusMessage *message,
+                                 struct wpa_dbus_object_desc *obj_dsc);
+
 #endif /* WPA_DBUS_CTRL_H */
diff --git a/wpa_supplicant/dbus/dbus_new_introspect.c b/wpa_supplicant/dbus/dbus_new_introspect.c
new file mode 100644 (file)
index 0000000..2cd7c88
--- /dev/null
@@ -0,0 +1,454 @@
+/*
+ * WPA Supplicant / dbus-based control interface
+ * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
+ * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
+ *
+ * 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 <libxml/tree.h>
+
+#include "utils/common.h"
+#include "dbus_common_i.h"
+#include "dbus_new_helpers.h"
+
+
+struct interfaces {
+       struct interfaces *next;
+       char *dbus_interface;
+       xmlNodePtr interface_node;
+};
+
+/**
+ * extract_interfaces - Extract interfaces from methods, signals and props
+ * @obj_dsc: Description of object from which interfaces will be extracted
+ * @root_node: root node of XML introspection document
+ * Returns: List of interfaces found in object description
+ *
+ * Iterates over all methods, signals and properties registered with
+ * object and collects all declared DBus interfaces and create interface's
+ * node in XML root node for each. Returned list elements contains interface
+ * name and XML node of corresponding interface.
+ */
+static struct interfaces * extract_interfaces(
+       struct wpa_dbus_object_desc *obj_dsc, xmlNodePtr root_node)
+{
+       struct wpa_dbus_method_desc *method_dsc = obj_dsc->methods;
+       struct wpa_dbus_signal_desc *signal_dsc = obj_dsc->signals;
+       struct wpa_dbus_property_desc *property_dsc = obj_dsc->properties;
+       struct interfaces *head = NULL;
+       struct interfaces *iface, *last;
+       int len;
+
+       /* extract interfaces from methods */
+       while (method_dsc) {
+               iface = head;
+               last = NULL;
+
+               /* go to next method if its interface is already extracted */
+               while (iface) {
+                       if (!os_strcmp(iface->dbus_interface,
+                                      method_dsc->dbus_interface))
+                               break;
+                       last = iface;
+                       iface = iface->next;
+               }
+               if (iface) {
+                       method_dsc = method_dsc->next;
+                       continue;
+               }
+
+               iface = os_zalloc(sizeof(struct interfaces));
+               if (!iface) {
+                       wpa_printf(MSG_ERROR, "Not enough memory to create "
+                               "interface introspection data");
+                       method_dsc = method_dsc->next;
+                       continue;
+               }
+
+               if (last)
+                       last->next = iface;
+               else
+                       head = iface;
+
+               len = os_strlen(method_dsc->dbus_interface) + 1;
+               iface->dbus_interface = os_malloc(len);
+               if (!iface->dbus_interface) {
+                       wpa_printf(MSG_ERROR, "Not enough memory to create "
+                                  "interface introspection data (interface "
+                                  "name)");
+                       method_dsc = method_dsc->next;
+                       continue;
+               }
+               os_strncpy(iface->dbus_interface, method_dsc->dbus_interface,
+                          len);
+
+               iface->interface_node = xmlNewChild(root_node, NULL,
+                                                   BAD_CAST "interface",
+                                                   NULL);
+               xmlNewProp(iface->interface_node, BAD_CAST "name",
+                          BAD_CAST method_dsc->dbus_interface);
+
+               method_dsc = method_dsc->next;
+       }
+
+       /* extract interfaces from signals */
+       while (signal_dsc) {
+               iface = head;
+               last = NULL;
+
+               /* go to next signal if its interface is already extracted */
+               while (iface) {
+                       if (!os_strcmp(iface->dbus_interface,
+                                      signal_dsc->dbus_interface))
+                               break;
+                       last = iface;
+                       iface = iface->next;
+               }
+               if (iface) {
+                       signal_dsc = signal_dsc->next;
+                       continue;
+               }
+
+               iface = os_zalloc(sizeof(struct interfaces));
+               if (!iface) {
+                       wpa_printf(MSG_ERROR, "Not enough memory to create "
+                                  "interface introspection data");
+                       signal_dsc = signal_dsc->next;
+                       continue;
+               }
+
+               if (last)
+                       last->next = iface;
+               else
+                       head = iface;
+
+               len = os_strlen(signal_dsc->dbus_interface) + 1;
+               iface->dbus_interface = os_malloc(len);
+               if (!iface->dbus_interface) {
+                       wpa_printf(MSG_ERROR, "Not enough memory to create "
+                                  "interface introspection data (interface "
+                                  "name)");
+                       signal_dsc = signal_dsc->next;
+                       continue;
+               }
+               os_strncpy(iface->dbus_interface, signal_dsc->dbus_interface,
+                          len);
+
+               iface->interface_node = xmlNewChild(root_node, NULL,
+                                                   BAD_CAST "interface",
+                                                   NULL);
+               xmlNewProp(iface->interface_node, BAD_CAST "name",
+                          BAD_CAST signal_dsc->dbus_interface);
+
+               signal_dsc = signal_dsc->next;
+       }
+
+       /* extract interfaces from properties */
+       while (property_dsc) {
+               iface = head;
+               last = NULL;
+
+               /* go to next property if its interface is already extracted */
+               while (iface) {
+                       if (!os_strcmp(iface->dbus_interface,
+                                      property_dsc->dbus_interface))
+                               break;
+                       last = iface;
+                       iface = iface->next;
+               }
+               if (iface) {
+                       property_dsc = property_dsc->next;
+                       continue;
+               }
+
+               iface = os_zalloc(sizeof(struct interfaces));
+               if (!iface) {
+                       wpa_printf(MSG_ERROR, "Not enough memory to create "
+                                  "interface introspection data");
+                       property_dsc = property_dsc->next;
+                       continue;
+               }
+
+               if (last)
+                       last->next = iface;
+               else
+                       head = iface;
+
+               len = os_strlen(property_dsc->dbus_interface) + 1;
+               iface->dbus_interface = os_malloc(len);
+               if (!iface->dbus_interface) {
+                       wpa_printf(MSG_ERROR, "Not enough memory to create "
+                                  "interface introspection data (interface "
+                                  "name)");
+                       property_dsc = property_dsc->next;
+                       continue;
+               }
+               os_strncpy(iface->dbus_interface, property_dsc->dbus_interface,
+                          len);
+
+               iface->interface_node = xmlNewChild(root_node, NULL,
+                                                   BAD_CAST "interface",
+                                                   NULL);
+               xmlNewProp(iface->interface_node, BAD_CAST "name",
+                          BAD_CAST property_dsc->dbus_interface);
+
+               property_dsc = property_dsc->next;
+       }
+
+       return head;
+}
+
+
+/**
+ * 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 interfaces *ifaces, *tmp;
+       struct wpa_dbus_signal_desc *signal_dsc;
+       struct wpa_dbus_method_desc *method_dsc;
+       struct wpa_dbus_property_desc *property_dsc;
+       xmlChar *intro_str;
+       char **children;
+       int i, s;
+
+       xmlDocPtr doc = NULL;
+       xmlNodePtr root_node = NULL, node = NULL, iface_node = NULL;
+       xmlNodePtr method_node = NULL, signal_node = NULL;
+       xmlNodePtr property_node = NULL, arg_node = NULL;
+
+       /* root node and dtd */
+       doc = xmlNewDoc(BAD_CAST "1.0");
+       root_node = xmlNewNode(NULL, BAD_CAST "node");
+       xmlDocSetRootElement(doc, root_node);
+       xmlCreateIntSubset(doc, BAD_CAST "node",
+                          BAD_CAST DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER,
+                          BAD_CAST DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER);
+
+       /* Add Introspectable interface */
+       iface_node = xmlNewChild(root_node, NULL, BAD_CAST "interface", NULL);
+       xmlNewProp(iface_node, BAD_CAST "name",
+                  BAD_CAST WPA_DBUS_INTROSPECTION_INTERFACE);
+
+       /* Add Introspect method */
+       method_node = xmlNewChild(iface_node, NULL, BAD_CAST "method", NULL);
+       xmlNewProp(method_node, BAD_CAST "name",
+                  BAD_CAST WPA_DBUS_INTROSPECTION_METHOD);
+       arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
+       xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "data");
+       xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s");
+       xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "out");
+
+
+       /* Add Properties interface */
+       iface_node = xmlNewChild(root_node, NULL,
+                                BAD_CAST "interface", NULL);
+       xmlNewProp(iface_node, BAD_CAST "name",
+                  BAD_CAST WPA_DBUS_PROPERTIES_INTERFACE);
+
+       /* Add Get method */
+       method_node = xmlNewChild(iface_node, NULL, BAD_CAST "method", NULL);
+       xmlNewProp(method_node, BAD_CAST "name",
+                  BAD_CAST WPA_DBUS_PROPERTIES_GET);
+       arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
+       xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "interface");
+       xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s");
+       xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in");
+       arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
+       xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "propname");
+       xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s");
+       xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in");
+       arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
+       xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "value");
+       xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "v");
+       xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "out");
+       method_node = xmlNewChild(iface_node, NULL, BAD_CAST "method", NULL);
+
+       /* Add GetAll method */
+       xmlNewProp(method_node, BAD_CAST "name",
+                  BAD_CAST WPA_DBUS_PROPERTIES_GETALL);
+       arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
+       xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "interface");
+       xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s");
+       xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in");
+       arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
+       xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "props");
+       xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "a{sv}");
+       xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "out");
+       method_node = xmlNewChild(iface_node, NULL, BAD_CAST "method", NULL);
+
+       /* Add Set method */
+       xmlNewProp(method_node, BAD_CAST "name",
+                  BAD_CAST WPA_DBUS_PROPERTIES_SET);
+       arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
+       xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "interface");
+       xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s");
+       xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in");
+       arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
+       xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "propname");
+       xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "s");
+       xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in");
+       arg_node = xmlNewChild(method_node, NULL, BAD_CAST "arg", NULL);
+       xmlNewProp(arg_node, BAD_CAST "name", BAD_CAST "value");
+       xmlNewProp(arg_node, BAD_CAST "type", BAD_CAST "v");
+       xmlNewProp(arg_node, BAD_CAST "direction", BAD_CAST "in");
+
+       /* get all interfaces registered with object */
+       ifaces = extract_interfaces(obj_dsc, root_node);
+
+       /* create methods' nodes */
+       method_dsc = obj_dsc->methods;
+       while (method_dsc) {
+
+               struct interfaces *iface = ifaces;
+               while (iface) {
+                       if (!os_strcmp(iface->dbus_interface,
+                                      method_dsc->dbus_interface))
+                               break;
+                       iface = iface->next;
+               }
+               if (!iface)
+                       continue;
+
+               iface_node = iface->interface_node;
+               method_node = xmlNewChild(iface_node, NULL, BAD_CAST "method",
+                                         NULL);
+               xmlNewProp(method_node, BAD_CAST "name",
+                          BAD_CAST method_dsc->dbus_method);
+
+               /* create args' nodes */
+               for (i = 0; i < method_dsc->args_num; i++) {
+                       struct wpa_dbus_argument arg = method_dsc->args[i];
+                       arg_node = xmlNewChild(method_node, NULL,
+                                              BAD_CAST "arg", NULL);
+                       if (arg.name && strlen(arg.name)) {
+                               xmlNewProp(arg_node, BAD_CAST "name",
+                                          BAD_CAST arg.name);
+                       }
+                       xmlNewProp(arg_node, BAD_CAST "type",
+                                  BAD_CAST arg.type);
+                       xmlNewProp(arg_node, BAD_CAST "direction",
+                                  BAD_CAST (arg.dir == ARG_IN ?
+                                            "in" : "out"));
+               }
+               method_dsc = method_dsc->next;
+       }
+
+       /* create signals' nodes */
+       signal_dsc = obj_dsc->signals;
+       while (signal_dsc) {
+
+               struct interfaces *iface = ifaces;
+               while (iface) {
+                       if (!os_strcmp(iface->dbus_interface,
+                                      signal_dsc->dbus_interface))
+                               break;
+                       iface = iface->next;
+               }
+               if (!iface)
+                       continue;
+
+               iface_node = iface->interface_node;
+               signal_node = xmlNewChild(iface_node, NULL, BAD_CAST "signal",
+                                         NULL);
+               xmlNewProp(signal_node, BAD_CAST "name",
+                          BAD_CAST signal_dsc->dbus_signal);
+
+               /* create args' nodes */
+               for (i = 0; i < signal_dsc->args_num; i++) {
+                       struct wpa_dbus_argument arg = signal_dsc->args[i];
+                       arg_node = xmlNewChild(signal_node, NULL,
+                                              BAD_CAST "arg", NULL);
+                       if (arg.name && strlen(arg.name)) {
+                               xmlNewProp(arg_node, BAD_CAST "name",
+                                          BAD_CAST arg.name);
+                       }
+                       xmlNewProp(arg_node, BAD_CAST "type",
+                                  BAD_CAST arg.type);
+               }
+               signal_dsc = signal_dsc->next;
+       }
+
+       /* create properties' nodes */
+       property_dsc = obj_dsc->properties;
+       while (property_dsc) {
+
+               struct interfaces *iface = ifaces;
+               while (iface) {
+                       if (!os_strcmp(iface->dbus_interface,
+                                      property_dsc->dbus_interface))
+                               break;
+                       iface = iface->next;
+               }
+               if (!iface)
+                       continue;
+
+               iface_node = iface->interface_node;
+               property_node = xmlNewChild(iface_node, NULL,
+                                           BAD_CAST "property", NULL);
+               xmlNewProp(property_node, BAD_CAST "name",
+                          BAD_CAST property_dsc->dbus_property);
+               xmlNewProp(property_node, BAD_CAST "type",
+                          BAD_CAST property_dsc->type);
+               xmlNewProp(property_node, BAD_CAST "access", BAD_CAST
+                          (property_dsc->access == R ? "read" :
+                           (property_dsc->access == W ?
+                            "write" : "readwrite")));
+
+               property_dsc = property_dsc->next;
+       }
+
+       /* add child nodes to introspection tree; */
+       dbus_connection_list_registered(obj_dsc->connection,
+                                       dbus_message_get_path(message),
+                                       &children);
+       for (i = 0; children[i]; i++) {
+               node = xmlNewChild(root_node, NULL, BAD_CAST "node", NULL);
+               xmlNewProp(node, BAD_CAST "name", BAD_CAST children[i]);
+       }
+       dbus_free_string_array(children);
+
+
+       xmlDocDumpFormatMemory(doc, &intro_str, &s, 1);
+
+       xmlFreeDoc(doc);
+
+       while (ifaces) {
+               tmp = ifaces;
+               ifaces = ifaces->next;
+               os_free(tmp->dbus_interface);
+               os_free(tmp);
+       }
+
+       reply = dbus_message_new_method_return(message);
+       if (reply == NULL) {
+               xmlFree(intro_str);
+               return NULL;
+       }
+
+       dbus_message_append_args(reply, DBUS_TYPE_STRING, &intro_str,
+                                DBUS_TYPE_INVALID);
+
+       xmlFree(intro_str);
+
+       return reply;
+}
+