diff options
author | Søren Sandmann <sandmann@redhat.com> | 2008-09-07 10:26:19 -0400 |
---|---|---|
committer | Søren Sandmann <sandmann@redhat.com> | 2008-09-07 10:26:19 -0400 |
commit | 51acedbb6059e3d413a449fb9239d67557588067 (patch) | |
tree | f6f56119c79cea5907269eb6036c908cedb1eb2a | |
parent | 3605605c046d34131a177d0c40bfe73d0acee48d (diff) |
Update to latest dbw/invoke
-rw-r--r-- | dbw-example.c | 143 | ||||
-rw-r--r-- | dbw.c | 753 | ||||
-rw-r--r-- | example.c | 4 | ||||
-rw-r--r-- | invoke.c | 10 | ||||
-rw-r--r-- | libnul.h | 21 |
5 files changed, 631 insertions, 300 deletions
diff --git a/dbw-example.c b/dbw-example.c index 507269a..cf63372 100644 --- a/dbw-example.c +++ b/dbw-example.c @@ -1,14 +1,37 @@ +#include <stdio.h> #include "libnul.h" +#if 0 +/* This may be a better way of doing it */ + /* Better: + * + * dbw_return + */ + +static gboolean +on_do_stuff (DbwContext *context, int32_t birnan, uint32_t fish, gpointer data) +{ + g_print ("do stuff called: ..."); + + x = g_strdup_printf ("asdf frasdf %d", fish); + + dbw_return (context, "Birnan was", x); + + g_free (x); + + return TRUE; +} +#endif + static gboolean on_do_stuff (gpointer data, - int32_t birnan, char **emfle, - uint32_t fish, char **str) + int32_t birnan, uint32_t fish, + char **emfle, char **str) { g_print ("do stuff called: birnan: %d fish: %u\n", birnan, fish); *emfle = g_strdup_printf ("Birnan was: %d", birnan); - *str = g_strdup_printf ("Fish was %u\n", fish); + *str = g_strdup_printf ("Fish was %u", fish); return TRUE; } @@ -17,26 +40,24 @@ static gboolean on_another_method (gpointer data, uint32_t x) { g_print ("another_method() called in (%s) with parameter %u\n", (char *)data, x); - + return TRUE; } static void load_image (gpointer data, const char *image, int *result) { - g_print ("You should like load an image: %s\n", image); - + g_print ("I should like load an image: %s\n", image); + *result = 87; } -int -main () +static DbwService * +make_service1 (void) { - GMainLoop *loop = g_main_loop_new (NULL, TRUE); - - DbwService *service = dbw_session_service ( + return dbw_session_service ( "com.ssp.whatever", - + dbw_object ( "/com/ssp/whatever/birnan/emfle", "object_info", @@ -52,7 +73,7 @@ main () dbw_parameter_out ("emfle", dbw_type_string()), dbw_parameter_out ("str", dbw_type_string()), NULL), - + dbw_method ( "another_method", (DbwFunction)on_another_method, @@ -64,10 +85,14 @@ main () NULL), NULL); +} - DbwService *service2 = dbw_session_service ( +static DbwService * +make_service2 (void) +{ + return dbw_session_service ( "org.gnome.siv", - + dbw_object ( "/org/gnome/siv", NULL, @@ -87,7 +112,64 @@ main () NULL), NULL); +} +static void +on_do_stuff_reply (const char *emfle, const char *str, const GError *err, gpointer data) +{ + g_print ("do stuff reply: \"%s\", \"%s\"\n", emfle, str); +} + +static void +on_reply (int result, const GError *err, DbwService *service) +{ + if (!err) + g_print ("The result was %d\n", result); + else + g_print ("An error occurred\n"); + + dbw_invoke (service, + "/com/ssp/whatever/birnan/emfle/com.ssp.interface.do_stuff", + (DbwFunction)on_do_stuff_reply, NULL, + 100, 200); +} + +DbwService *service; +DbwService *service2; + +static gboolean +invokes (gpointer data) +{ + int i; + + printf ("idle\n"); + + for (i = 0; i < 30000; ++i) + { +#if 0 + dbw_service_stop (service); + dbw_service_start (service); + dbw_service_stop (service); + dbw_service_start (service); +#endif + + dbw_invoke (service2, + "/org/gnome/siv/org.gnome.siv.load_image", + (DbwFunction)on_reply, service, + "LOLCAT.PNG"); + } + + return FALSE; +} + +int +main () +{ + GMainLoop *loop = g_main_loop_new (NULL, TRUE); + + service = make_service1 (); + service2 = make_service2 (); + if (!dbw_service_start (service2)) { g_print ("siv already exists, asking it to load the images instead\n"); @@ -97,19 +179,12 @@ main () { g_print ("Couldn't start the service\n"); } - dbw_service_stop (service); - dbw_service_start (service); - dbw_service_stop (service); - dbw_service_start (service); - dbw_invoke (service2, - "/org/gnome/siv/org.gnome.siv.load_image", - NULL, - NULL, - "This is the image"); + g_idle_add (invokes, service); + g_idle_add (g_main_loop_quit, loop); g_main_loop_run (loop); - + return 0; } @@ -121,10 +196,10 @@ bah() "org.gnome.ScreenSaver", dbw_object ( "/", - + dbw_interface ( "org.gnome.ScreenSaver", - + dbw_method ( "Throttle", NULL, NULL, @@ -132,27 +207,27 @@ bah() dbw_parameter_in ("reason", dbw_type_string()), dbw_parameter_out ("cookie", dbw_type_uint32()), NULL), - + dbw_signal ( "ActiveChanged", dbw_parameter_in ("new_value", dbw_type_bool()), NULL), - + NULL), - + NULL), - + NULL); - + dbw_invoke (service, "/org.gnome.ScreenSaver.Throttle", reponse, NULL, "MyApplication", "None of your business"); - + if (!dbw_invoke_wait (service, "/org.gnome.ScreenSaver.Throttle", 1000, &err, "MyApplication", "None of your business", &cookie)) { g_print ("timeout\n"); } - + dbw_connect (service, "/org.gnome.ScreenSaver.ActiveChanged", on_active_changed, data); } #endif @@ -1,7 +1,6 @@ #include <stdarg.h> #include <dbus/dbus.h> #include <string.h> -#include <glib.h> #include "libnul.h" #define INTROSPECT_INTERFACE "org.freedesktop.DBus.Introspectable" @@ -13,6 +12,7 @@ struct DbwService GPtrArray *objects; DBusConnection *connection; gboolean running; + DBusBusType type; }; struct DbwObject @@ -30,17 +30,21 @@ struct DbwInterface struct DbwMember { + char * name; + /* For now only methods are supported, although * later we may also have properties and signals */ - DbwInterface * interface; - + DbwInterface * interface; /* containing interface */ + DbwFunction function; - char * name; GPtrArray * parameters; + int n_inputs; + int n_outputs; FunDef * fun_def; + FunDef * reply_fun; }; struct DbwParameter @@ -69,9 +73,9 @@ process_watch (DBusWatch *watch, int flags) DBusMessage *msg; dbus_watch_handle (watch, flags); - + connection = dbus_watch_get_data (watch); - + while ((msg = dbus_connection_borrow_message (connection))) { dbus_connection_return_message (connection, msg); @@ -84,7 +88,7 @@ static void on_hangup (gpointer data) { DBusWatch *watch = data; - + process_watch (watch, DBUS_WATCH_HANGUP); } @@ -92,7 +96,7 @@ static void on_error (gpointer data) { DBusWatch *watch = data; - + process_watch (watch, DBUS_WATCH_ERROR); } @@ -100,11 +104,11 @@ static void on_read (gpointer data) { GList *list = data; - + for (list = data; list != NULL; list = list->next) { DBusWatch *watch = list->data; - + if (dbus_watch_get_enabled (watch) && (dbus_watch_get_flags (watch) & DBUS_WATCH_READABLE)) { @@ -117,11 +121,11 @@ static void on_write (gpointer data) { GList *list = data; - + for (list = data; list != NULL; list = list->next) { DBusWatch *watch = list->data; - + if (dbus_watch_get_enabled (watch) && (dbus_watch_get_flags (watch) & DBUS_WATCH_WRITABLE)) { @@ -135,33 +139,33 @@ update_fd (int fd) { int enabled, flags; GList *watches, *list; - + watches = fd_get_data (fd); - + enabled = FALSE; flags = 0; for (list = watches; list != NULL; list = list->next) { DBusWatch *watch = list->data; - + if (dbus_watch_get_enabled (watch)) { enabled = TRUE; flags |= dbus_watch_get_flags (watch); } } - + if (enabled) { fd_set_error_callback (fd, on_hangup); fd_set_hangup_callback (fd, on_error); - + if (flags & DBUS_WATCH_READABLE) fd_set_read_callback (fd, on_read); else fd_set_read_callback (fd, NULL); - + if (flags & DBUS_WATCH_WRITABLE) fd_set_write_callback (fd, on_write); else @@ -181,7 +185,7 @@ add_watch (DBusWatch *watch, void *data) { DBusConnection *connection = data; int fd = dbus_watch_get_unix_fd (watch); - + dbus_watch_set_data (watch, connection, NULL); /* DBus apparently will create multiple watches for @@ -190,18 +194,18 @@ add_watch (DBusWatch *watch, void *data) if (fd_is_watched (fd)) { GList *watches = fd_get_data (fd); - + watches = g_list_prepend (watches, watch); - + fd_set_data (fd, watches); } else { fd_add_watch (fd, g_list_prepend (NULL, watch)); } - + update_fd (fd); - + return TRUE; } @@ -210,9 +214,9 @@ remove_watch (DBusWatch *watch, void *data) { int fd = dbus_watch_get_unix_fd (watch); GList *watches = fd_get_data (fd); - + watches = g_list_remove (watches, watch); - + if (!watches) { fd_remove_watch (fd); @@ -234,7 +238,7 @@ static gboolean on_timeout (gpointer data) { DBusTimeout *timeout = data; - + dbus_timeout_handle (timeout); return TRUE; @@ -244,14 +248,14 @@ static dbus_bool_t add_timeout (DBusTimeout *timeout, void *data) { dbus_timeout_set_data (timeout, GINT_TO_POINTER (0), NULL); - + if (dbus_timeout_get_enabled (timeout)) { int id; id = g_timeout_add (dbus_timeout_get_interval (timeout), on_timeout, timeout); - + dbus_timeout_set_data (timeout, GINT_TO_POINTER (id), NULL); } @@ -262,11 +266,11 @@ static void remove_timeout (DBusTimeout *timeout, void *data) { int id = GPOINTER_TO_INT (dbus_timeout_get_data (timeout)); - + if (id) { g_source_remove (id); - + dbus_timeout_set_data (timeout, GINT_TO_POINTER (0), NULL); } } @@ -275,7 +279,7 @@ static void toggle_timeout (DBusTimeout *timeout, void *data) { remove_timeout (timeout, NULL); - + add_timeout (timeout, NULL); } @@ -293,13 +297,13 @@ static gboolean do_free (gpointer data) { int i; - + for (i = 0; i < free_us->len; ++i) g_free (free_us->pdata[i]); - + g_ptr_array_free (free_us, TRUE); free_us = g_ptr_array_new (); - + idle_handler = 0; return FALSE; @@ -310,12 +314,12 @@ idle_free (gpointer p) { if (!free_us) free_us = g_ptr_array_new (); - + g_ptr_array_add (free_us, p); - + if (!idle_handler) idle_handler = g_idle_add (do_free, NULL); - + return p; } @@ -354,14 +358,14 @@ introspect (DbwObject *object) { DbwMember *member = interface->members->pdata[j]; int k; - + g_string_append_printf ( xml, " <method name=\"%s\">\n", member->name); - + for (k = 0; k < member->parameters->len; ++k) { DbwParameter *parameter = member->parameters->pdata[k]; - + g_string_append_printf ( xml, " <arg name=\"%s\" direction=\"%s\" type=\"%s\"/>\n", @@ -369,153 +373,177 @@ introspect (DbwObject *object) parameter->out? "out" : "in", make_signature (parameter->type)); } - + g_string_append_printf ( xml, " </method>\n"); } g_string_append_printf (xml, " </interface>\n"); } - + g_string_append_printf (xml, "</node>\n"); - + return idle_free (g_string_free (xml, FALSE)); } -static DBusHandlerResult -invoke (DBusConnection *connection, - DbwObject *object, - DbwMember *member, - DBusMessage *message) +static gboolean +decode_message (DBusMessage *message, + int n_parameters, + DbwParameter **parameters, + Arg *args) { - Arg *args = idle_free (g_new0 (Arg, member->parameters->len + 1)); - DBusMessage *error_reply; - DBusMessageIter iter; - Arg result; - dbus_bool_t has_args; + gboolean has_args; int i; + DBusMessageIter iter; const char *error; - - /* Add the data pointer */ - args[0].v_pointer = object->data; - - args++; /* skip object data */ has_args = dbus_message_iter_init (message, &iter); + + /* FIXME: this function should make sure args are initialized to NULL values + * when it fails + */ - for (i = 0; i < member->parameters->len; ++i) + for (i = 0; i < n_parameters; ++i) { - DbwParameter *parameter = member->parameters->pdata[i]; + int dbus_type; - if (parameter->out) + if (!has_args) { - switch (parameter->type->type) - { - case UINT32: - args[i].v_pointer = &(args[i].v_uint32); - break; - - case INT32: - args[i].v_pointer = &(args[i].v_int32); - break; - - case STRING: - args[i].v_pointer = &(args[i].v_pointer); - break; - } + error = "Received too few arguments method\n"; + goto fail; } - else + + dbus_type = dbus_message_iter_get_arg_type (&iter); + + switch (parameters[i]->type->type) { - int dbus_type; + case UINT32: + if (dbus_type != DBUS_TYPE_UINT32) + { + error = "Received wrong type, should be UINT32"; + goto fail; + } + dbus_message_iter_get_basic (&iter, &(args[i].v_uint32)); + break; - if (!has_args) + case INT32: + if (dbus_type != DBUS_TYPE_INT32) { - error = "Received too few arguments method\n"; + error = "Received wrong type, should be INT32"; goto fail; } - - dbus_type = dbus_message_iter_get_arg_type (&iter); - - switch (parameter->type->type) + dbus_message_iter_get_basic (&iter, &(args[i].v_int32)); + break; + + case STRING: + if (dbus_type != DBUS_TYPE_STRING) { - case UINT32: - if (dbus_type != DBUS_TYPE_UINT32) - { - error = "Received wrong type, should be UINT32"; - goto fail; - } - dbus_message_iter_get_basic (&iter, &(args[i].v_uint32)); - break; - - case INT32: - if (dbus_type != DBUS_TYPE_INT32) - { - error = "Received wrong type, should be INT32"; - goto fail; - } - dbus_message_iter_get_basic (&iter, &(args[i].v_int32)); - break; - - case STRING: - if (dbus_type != DBUS_TYPE_STRING) - { - error = "Received wrong type, should be STRING"; - goto fail; - } - dbus_message_iter_get_basic (&iter, &(args[i].v_pointer)); - break; + error = "Received wrong type, should be STRING"; + goto fail; } + dbus_message_iter_get_basic (&iter, &(args[i].v_pointer)); + break; + } + + if (dbus_type == DBUS_TYPE_INVALID) + has_args = FALSE; + + dbus_message_iter_next (&iter); + } - if (dbus_type == DBUS_TYPE_INVALID) - has_args = FALSE; + return TRUE; - dbus_message_iter_next (&iter); +fail: + g_print ("ERROR: %s\n", error); + return FALSE; +} + +static void +encode_message (DBusMessage *message, + int n_parameters, + DbwParameter **parameters, + Arg *args) +{ + DBusMessageIter iter; + int i; + + dbus_message_iter_init_append (message, &iter); + + for (i = 0; i < n_parameters; ++i) + { + DbwParameter *parameter = parameters[i]; + + switch (parameter->type->type) + { + case UINT32: + dbus_message_iter_append_basic ( + &iter, DBUS_TYPE_UINT32, &(args[i].v_uint32)); + break; + + case INT32: + dbus_message_iter_append_basic ( + &iter, DBUS_TYPE_INT32, &(args[i].v_int32)); + break; + + case STRING: + dbus_message_iter_append_basic ( + &iter, DBUS_TYPE_STRING, &(args[i].v_pointer)); + + /* FIXME: it feels wrong that we are freeing data + * passed in by the user. Maybe we should just make the + * user idle_free it. + * + * Even better actually: Have a dbw_return (...) that + * the user is expected to call. + */ + g_free (args[i].v_pointer); + break; } } +} + +static DBusHandlerResult +invoke (DBusConnection *connection, + DbwObject *object, + DbwMember *member, + DBusMessage *message) +{ + Arg *args = idle_free (g_new0 (Arg, member->parameters->len + 1)); + DBusMessage *error_reply; + Arg result; + int i; + + /* Add the data pointer */ + args[0].v_pointer = object->data; + + if (!decode_message (message, member->n_inputs, (DbwParameter **)member->parameters->pdata, &(args[1]))) + { + error_reply = dbus_message_new_error (message, DBUS_ERROR_FAILED, "FIXME: generate a real error"); + + dbus_connection_send (connection, error_reply, NULL); + + return DBUS_HANDLER_RESULT_HANDLED; + } + + for (i = member->n_inputs; i < member->parameters->len; ++i) + { + DbwParameter *parameter = member->parameters->pdata[i]; - args--; /* Include object data */ - result = fun_def_invoke (member->fun_def, args); + g_assert (parameter->out); + + args[i + 1].v_pointer = &(args[i + 1]); + } + + result = fun_def_invoke (member->fun_def, (Function)member->function, args); if (result.v_int32) { DBusMessage *reply = dbus_message_new_method_return (message); - DBusMessageIter iter; - int i; - args++; /* Skip object data */ - - dbus_message_iter_init_append (reply, &iter); - - for (i = 0; i < member->parameters->len; ++i) - { - DbwParameter *parameter = member->parameters->pdata[i]; - - if (parameter->out) - { - switch (parameter->type->type) - { - case UINT32: - dbus_message_iter_append_basic ( - &iter, DBUS_TYPE_UINT32, &(args[i].v_uint32)); - break; - - case INT32: - dbus_message_iter_append_basic ( - &iter, DBUS_TYPE_INT32, &(args[i].v_int32)); - break; - - case STRING: - dbus_message_iter_append_basic ( - &iter, DBUS_TYPE_STRING, &(args[i].v_pointer)); - - /* FIXME: it feels wrong that we are freeing data - * passed by the user. Maybe we should just make the - * user idle_free it. - */ - g_free (args[i].v_pointer); - break; - } - } - } + + encode_message (reply, + member->n_outputs, + (DbwParameter **)&(member->parameters->pdata[member->n_inputs]), + &(args[member->n_inputs + 1])); dbus_connection_send (connection, reply, NULL); dbus_message_unref (reply); @@ -525,13 +553,7 @@ invoke (DBusConnection *connection, { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } - -fail: - error_reply = dbus_message_new_error (message, DBUS_ERROR_FAILED, error); - - dbus_connection_send (connection, error_reply, NULL); - return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult @@ -546,7 +568,7 @@ message_function (DBusConnection *connection, int i; g_assert (strcmp (object->name, msg_path) == 0); - + /* Introspection */ if (strcmp (msg_interface, INTROSPECT_INTERFACE) == 0 && strcmp (msg_member, INTROSPECT_METHOD) == 0) @@ -557,31 +579,31 @@ message_function (DBusConnection *connection, dbus_message_append_args (reply, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID); - + dbus_connection_send (connection, reply, NULL); return DBUS_HANDLER_RESULT_HANDLED; } - + /* Normal method */ for (i = 0; i < object->interfaces->len; ++i) { DbwInterface *interface = object->interfaces->pdata[i]; - + if (strcmp (msg_interface, interface->name) == 0) { int j; - + for (j = 0; j < interface->members->len; ++j) { DbwMember *member = interface->members->pdata[j]; - + if (strcmp (member->name, msg_member) == 0) return invoke (connection, object, member, message); } } } - + g_print ("got unknown message\n"); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; @@ -598,7 +620,7 @@ make_ptr_array (gpointer first, va_list parameters) { GPtrArray *array = g_ptr_array_new (); gpointer v; - + if (first) { g_ptr_array_add (array, first); @@ -611,7 +633,7 @@ make_ptr_array (gpointer first, va_list parameters) v = va_arg (parameters, gpointer); } } - + return array; } @@ -637,7 +659,7 @@ ensure_connection (DBusConnection **connection, *connection, NULL); } } - + return *connection; } @@ -655,22 +677,22 @@ get_connection (DBusBusType type, DBusError *err) return NULL; } -DbwService * -dbw_session_service (const char *name, - DbwObject *object1, - ...) +static DbwService * +make_service (const char *name, + DBusBusType type, + DbwObject *object1, + va_list args) { DbwService *service = g_new0 (DbwService, 1); - va_list parameters; - DBusError err = DBUS_ERROR_INIT; - + service->name = g_strdup (name); - - va_start (parameters, object1); - service->objects = make_ptr_array (object1, parameters); - va_end (parameters); - - service->connection = get_connection (DBUS_BUS_SESSION, &err); + + service->objects = make_ptr_array (object1, args); + + service->type = type; + + service->connection = get_connection (type, NULL); + if (!service->connection) { /* FIXME */ @@ -680,13 +702,30 @@ dbw_session_service (const char *name, return service; } +DbwService * +dbw_session_service (const char *name, + DbwObject *object1, + ...) +{ + va_list args; + DbwService *service; + + va_start (args, object1); + + service = make_service (name, DBUS_BUS_SESSION, object1, args); + + va_end (args); + + return service; +} + gboolean dbw_service_start (DbwService *service) { DBusError err = DBUS_ERROR_INIT; int i; int result; - + if (service->running) return FALSE; @@ -700,7 +739,7 @@ dbw_service_start (DbwService *service) service->name, DBUS_NAME_FLAG_DO_NOT_QUEUE, &err); - + if (result == -1) { /* FIXME: handle error */ @@ -712,17 +751,17 @@ dbw_service_start (DbwService *service) case DBUS_REQUEST_NAME_REPLY_IN_QUEUE: g_assert_not_reached(); break; - + case DBUS_REQUEST_NAME_REPLY_EXISTS: g_print ("Couldn't get name\n"); return FALSE; break; - + case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER: g_print ("We own this already (?)\n"); return FALSE; break; - + case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER: break; } @@ -731,13 +770,13 @@ dbw_service_start (DbwService *service) for (i = 0; i < service->objects->len; ++i) { DbwObject *object = service->objects->pdata[i]; - + dbus_connection_register_object_path ( service->connection, object->name, &vtable, object); } - + service->running = TRUE; - + return TRUE; } @@ -745,20 +784,20 @@ void dbw_service_stop (DbwService *service) { int i; - + if (!service->running) return; for (i = 0; i < service->objects->len; ++i) { DbwObject *object = service->objects->pdata[i]; - + dbus_connection_unregister_object_path ( service->connection, object->name); } - + dbus_bus_release_name (service->connection, service->name, NULL); - + service->running = FALSE; } @@ -769,15 +808,15 @@ dbw_object (const char *name, ...) { DbwObject *object = g_new0 (DbwObject, 1); - va_list parameters; - + va_list args; + object->name = g_strdup (name); object->data = data; - va_start (parameters, interface1); - object->interfaces = make_ptr_array (interface1, parameters); - va_end (parameters); - + va_start (args, interface1); + object->interfaces = make_ptr_array (interface1, args); + va_end (args); + /* Add introspection interface */ /* Note: the actual introspection is special cased in invoke(), but we @@ -806,17 +845,17 @@ dbw_interface (const char *name, DbwInterface *interface = g_new0 (DbwInterface, 1); va_list parameters; int i; - + interface->name = g_strdup (name); va_start (parameters, member1); interface->members = make_ptr_array (member1, parameters); va_end (parameters); - + for (i = 0; i < interface->members->len; ++i) { DbwMember *member = interface->members->pdata[i]; - + member->interface = interface; } @@ -827,12 +866,75 @@ static DbwType * type_copy (const DbwType *type) { DbwType *copy = g_new0 (DbwType, 1); - + copy->type = type->type; return copy; } +static Type +invoke_type_from_dbw_type (DbwType *t) +{ + switch (t->type) + { + case INT32: + return TYPE_INT32; + case UINT32: + return TYPE_UINT32; + case STRING: + return TYPE_POINTER; + } + + g_warning ("Unknown type %d\n", t->type); + return -1; +} + +static FunDef * +make_fun_def (DbwMember *member) +{ + Type *types; + int i; + + types = idle_free (g_new0 (Type, member->parameters->len + 1)); + types[0] = TYPE_POINTER; /* For object->data */ + + for (i = 1; i < member->parameters->len; ++i) + { + DbwParameter *par = member->parameters->pdata[i - 1]; + + if (par->out) + types[i] = TYPE_POINTER; + else + types[i] = invoke_type_from_dbw_type (par->type); + } + + return fun_def_new (TYPE_INT, + member->parameters->len + 1, + types); +} + +static FunDef * +make_reply_fun (DbwMember *member) +{ + Type *types; + int i, n; + + types = idle_free (g_new0 (Type, member->parameters->len + 2)); + + n = 0; + for (i = 0; i < member->parameters->len; ++i) + { + DbwParameter *par = member->parameters->pdata[i]; + + if (par->out) + types[n++] = invoke_type_from_dbw_type (par->type); + } + + types[n++] = TYPE_POINTER; /* data */ + types[n++] = TYPE_POINTER; /* const GError *err */ + + return fun_def_new (TYPE_VOID, n, types); +} DbwMember * dbw_method (const char *name, @@ -842,9 +944,8 @@ dbw_method (const char *name, { DbwMember *member = g_new0 (DbwMember, 1); va_list parameters; - Type *types; int i; - + member->name = g_strdup (name); member->function = function; @@ -852,38 +953,30 @@ dbw_method (const char *name, member->parameters = make_ptr_array ((DbwType *)parameter1, parameters); va_end (parameters); - types = g_new0 (Type, member->parameters->len + 1); - types[0] = TYPE_POINTER; /* For object->data */ - - for (i = 1; i < member->parameters->len; ++i) + member->n_inputs = 0; + member->n_outputs = 0; + for (i = 0; i < member->parameters->len; ++i) { - DbwParameter *par = member->parameters->pdata[i - 1]; + DbwParameter *par = member->parameters->pdata[i]; if (par->out) { - types[i] = TYPE_POINTER; + member->n_outputs++; } else { - switch (par->type->type) + member->n_inputs++; + + if (member->n_outputs) { - case INT32: - types[i] = TYPE_INT32; - break; - case UINT32: - types[i] = TYPE_UINT32; - break; - case STRING: - types[i] = TYPE_POINTER; - break; + g_critical ("All output parameters must be specified after the input parameters"); + return NULL; } } } - - member->fun_def = fun_def_new ((Function)member->function, - TYPE_INT, - member->parameters->len + 1, - types); + + member->fun_def = make_fun_def (member); + member->reply_fun = make_reply_fun (member); return member; } @@ -894,7 +987,7 @@ make_parameter (const char *name, gboolean out) { DbwParameter *parameter = g_new0 (DbwParameter, 1); - + parameter->name = g_strdup (name); parameter->type = type_copy (type); parameter->out = out; @@ -920,7 +1013,7 @@ static DbwType * make_type (Type t) { DbwType *type = idle_free (g_new0 (DbwType, 1)); - + type->type = t; return type; @@ -944,23 +1037,67 @@ dbw_type_string (void) return make_type (STRING); } -/* Decomposes strings like this: +typedef struct +{ + DbwFunction callback; + gpointer data; + DbwMember *method; +} InvokeInfo; + +static void +on_reply (DBusPendingCall *pending, + gpointer data) +{ + InvokeInfo *info = data; + int n_outputs = info->method->n_outputs; + Arg *args = idle_free (g_new0 (Arg, n_outputs + 2)); + DBusMessage *reply; + + if (!info->callback) + return; + + reply = dbus_pending_call_steal_reply (pending); + + if (!reply) + { + /* FIXME: can this happen? If it can, we should + * generate an error. + */ + return; + } + + args[n_outputs].v_pointer = NULL; /* GError */ + if (!decode_message (reply, + n_outputs, + (DbwParameter **)&(info->method->parameters->pdata[info->method->n_inputs]), + args)) + { + /* FIXME: generate an error into args[n_outputs + 1] */ + args[n_outputs].v_pointer = "ERR"; + } + + args[n_outputs + 1].v_pointer = info->data; + + fun_def_invoke (info->method->reply_fun, (Function)info->callback, args); +} + +/* Decodes strings like this: * * /org.gnome.ScreenSaver.Throttle * */ static gboolean -decompose_method (const char *method_desc, - char **object_path, - char **interface, - char **method) +decode_method_desc (const char *method_desc, + char **object_path, + char **interface, + char **method) { char *m; - + g_return_val_if_fail (method_desc != NULL, FALSE); g_return_val_if_fail (strchr (method_desc, '/') != NULL, FALSE); g_return_val_if_fail (strchr (method_desc, '.') != NULL, FALSE); - + m = strrchr (method_desc, '/'); *object_path = g_strndup (method_desc, m - method_desc); method_desc = m + 1; @@ -968,11 +1105,59 @@ decompose_method (const char *method_desc, m = strrchr (method_desc, '.'); *interface = g_strndup (method_desc, m - method_desc); method_desc = m; - + *method = g_strdup (m + 1); return TRUE; } +static DbwObject * +find_object (DbwService *service, const char *name) +{ + int i; + + for (i = 0; i < service->objects->len; ++i) + { + DbwObject *object = service->objects->pdata[i]; + + if (strcmp (object->name, name) == 0) + return object; + } + + return NULL; +} + +static DbwInterface * +find_interface (DbwObject *object, const char *name) +{ + int i; + + for (i = 0; i < object->interfaces->len; ++i) + { + DbwInterface *interface = object->interfaces->pdata[i]; + + if (strcmp (interface->name, name) == 0) + return interface; + } + + return NULL; +} + +static DbwMember * +find_member (DbwInterface *interface, const char *name) +{ + int i; + + for (i = 0; i < interface->members->len; ++i) + { + DbwMember *member = interface->members->pdata[i]; + + if (strcmp (member->name, name) == 0) + return member; + } + + return NULL; +} + void dbw_invoke (DbwService *service, const char *method_desc, @@ -980,20 +1165,92 @@ dbw_invoke (DbwService *service, gpointer data, ...) { - char *object, *interface, *method; - - decompose_method (method_desc, &object, &interface, &method); + char *object_str, *interface_str, *method_str; + DbwObject *object; + DbwInterface *interface; + DbwMember *method; + DBusMessage *message; + DBusMessageIter iter; + DBusConnection *connection; + va_list args; + InvokeInfo *info; + DBusPendingCall *pending; + int i; - g_print ("Path: %s\n", object); - g_print ("Interface: %s\n", interface); - g_print ("Method: %s\n", method); -} + g_return_if_fail (service != NULL); + + decode_method_desc (method_desc, &object_str, &interface_str, &method_str); + + object = find_object (service, object_str); + interface = find_interface (object, interface_str); + method = find_member (interface, method_str); + + g_return_if_fail (object != NULL); + g_return_if_fail (interface != NULL); + g_return_if_fail (method != NULL); + + message = dbus_message_new_method_call ( + service->name, object->name, interface->name, method->name); + + dbus_message_iter_init_append (message, &iter); + + va_start (args, data); + + for (i = 0; i < method->parameters->len; ++i) + { + DbwParameter *parameter = method->parameters->pdata[i]; + int32_t i32; + uint32_t u32; + const char *s; + + if (parameter->out) + continue; -#if 0 -void -dbw_proxy_invoke (DbwProxy *proxy) -{ + switch (parameter->type->type) + { + case INT32: + i32 = va_arg (args, int32_t); + + dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &i32); + break; + + case UINT32: + u32 = va_arg (args, uint32_t); + + dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT32, &u32); + break; + + case STRING: + s = va_arg (args, const char *); + + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &s); + break; + } + } + va_end (args); + + connection = get_connection (service->type, NULL); + + dbus_connection_send_with_reply (connection, message, &pending, -1); + if (!pending) + { + /* FIXME: generate an error and call the callback */ + + /* Or alternatively, we should deal with getting disconnected, + * though it's not clear what we should do with that + */ + } + else + { + info = g_new0 (InvokeInfo, 1); + + info->callback = callback; + info->data = data; + info->method = method; + + dbus_pending_call_set_notify (pending, on_reply, info, g_free); + } + + dbus_message_unref (message); } -#endif - @@ -11,9 +11,9 @@ main () }; Arg ret; - FunDef *def = fun_def_new ((Function)printf, TYPE_INT, 2, arg_types); + FunDef *def = fun_def_new (TYPE_INT, 2, arg_types); - ret = fun_def_invoke (def, args); + ret = fun_def_invoke (def, (Function)printf, args); printf ("returned: %d\n", ret.v_int); @@ -2,12 +2,11 @@ #include <assert.h> #include <string.h> #include <stdio.h> -#include "libnul.h" #include "ffi.h" +#include "libnul.h" struct FunDef { - Function fn; int n_args; ffi_type *ffi_ret_type; ffi_type **ffi_arg_types; @@ -51,8 +50,7 @@ ffi_type_from_type (Type type) } FunDef * -fun_def_new (Function f, - Type ret_type, +fun_def_new (Type ret_type, int n_args, Type *arg_types) { @@ -79,7 +77,6 @@ fun_def_new (Function f, def->ffi_ret_type = ffi_type_from_type (ret_type); - def->fn = f; def->n_args = n_args; ffi_prep_cif (&def->ffi_cif, FFI_DEFAULT_ABI, n_args, def->ffi_ret_type, def->ffi_arg_types); @@ -89,6 +86,7 @@ fun_def_new (Function f, Arg fun_def_invoke (FunDef *fun, + Function f, Arg *args) { void *stack_args[8]; @@ -104,7 +102,7 @@ fun_def_invoke (FunDef *fun, for (i = 0; i < fun->n_args; ++i) ffi_args[i] = &(args[i]); - ffi_call (&(fun->ffi_cif), fun->fn, &ret, ffi_args); + ffi_call (&(fun->ffi_cif), f, &ret, ffi_args); if (ffi_args != stack_args) free (ffi_args); @@ -16,8 +16,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef INVOKE_H -#define INVOKE_H +#ifndef __LIBNUL_H +#define __LIBNUL_H #include <stdint.h> #include <glib.h> @@ -75,14 +75,15 @@ typedef void (* Function)(); typedef struct FunDef FunDef; -FunDef *fun_def_new (Function f, - Type ret_type, +FunDef *fun_def_new (Type ret_type, int n_args, Type *arg_types); Arg fun_def_invoke (FunDef *fun, + Function f, Arg *args); void fun_def_free (FunDef *fun); + /* * Watching file descriptors */ @@ -156,10 +157,10 @@ DbwProxy *dbw_proxy_new_session_service (const char *bus_name, const char *object, const char *interface); -void -dbw_invoke (DbwService *service, - const char *method_desc, - DbwFunction callback, - gpointer data, - ...); +void dbw_invoke (DbwService *service, + const char *method_desc, + DbwFunction callback, + gpointer data, + ...); + #endif |