diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2004-02-17 18:04:03 +0000 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2004-02-17 18:04:03 +0000 |
commit | f17bb94f47090f3397b60b5e264aa9f18dbf203d (patch) | |
tree | cd475c5e55def20433d0ac0e83a0410e0606da91 /hcid/dbus.c | |
parent | 5903cfe8fdfa5df4a0ce737219385d16da85e279 (diff) |
Add D-Bus support for PIN request
Diffstat (limited to 'hcid/dbus.c')
-rw-r--r-- | hcid/dbus.c | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/hcid/dbus.c b/hcid/dbus.c new file mode 100644 index 00000000..4c2bb18d --- /dev/null +++ b/hcid/dbus.c @@ -0,0 +1,206 @@ +#include <stdio.h> +#include <sys/socket.h> +#include <sys/syslog.h> + +#include <bluetooth/bluetooth.h> +#include <bluetooth/hci.h> +#include <bluetooth/hci_lib.h> + +#define DBUS_API_SUBJECT_TO_CHANGE +#include <dbus/dbus.h> + +#include "hcid.h" +#include "glib-ectomy.h" + +static DBusConnection *connection; + +#define TIMEOUT (30 * 1000) // 30 seconds + +#define SERVICE_NAME "org.handhelds.gpe.bluez" +#define INTERFACE_NAME SERVICE_NAME ".PinAgent" +#define REQUEST_NAME "PinRequest" +#define PATH_NAME "/org/handhelds/gpe/bluez/PinAgent" + +#define WRONG_ARGS_ERROR "org.handhelds.gpe.bluez.Error.WrongArgs" + +struct pin_request +{ + int dev; + bdaddr_t bda; +}; + +static void reply_handler_function(DBusPendingCall *call, void *user_data) +{ + struct pin_request *req = (struct pin_request *) user_data; + pin_code_reply_cp pr; + DBusMessage *message; + DBusMessageIter iter; + int type; + size_t len; + char *pin; + + message = dbus_pending_call_get_reply(call); + + if (dbus_message_is_error(message, WRONG_ARGS_ERROR)) + goto error; + + dbus_message_iter_init(message, &iter); + + type = dbus_message_iter_get_arg_type(&iter); + if (type != DBUS_TYPE_STRING) + goto error; + + pin = dbus_message_iter_get_string(&iter); + len = strlen(pin); + + memset(&pr, 0, sizeof(pr)); + bacpy(&pr.bdaddr, &req->bda); + memcpy(pr.pin_code, pin, len); + pr.pin_len = len; + hci_send_cmd(req->dev, OGF_LINK_CTL, OCF_PIN_CODE_REPLY, + PIN_CODE_REPLY_CP_SIZE, &pr); + + return; + +error: + hci_send_cmd(req->dev, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, + 6, &req->bda); +} + + +static void free_pin_req(void *req) +{ + free(req); +} + +void hcid_dbus_request_pin(int dev, struct hci_conn_info *ci) +{ + DBusMessage *message; + DBusMessageIter iter; + DBusPendingCall *pending = NULL; + struct pin_request *req; + + message = dbus_message_new_method_call(SERVICE_NAME, PATH_NAME, + INTERFACE_NAME, REQUEST_NAME); + if (message == NULL) { + syslog(LOG_ERR, "Couldn't allocate D-BUS message"); + goto failed; + } + + req = malloc(sizeof(*req)); + req->dev = dev; + bacpy(&req->bda, &ci->bdaddr); + + dbus_message_append_iter_init(message, &iter); + + dbus_message_iter_append_boolean(&iter, ci->out); + dbus_message_iter_append_byte_array(&iter, + (unsigned char *) &ci->bdaddr, sizeof(ci->bdaddr)); + + if (dbus_connection_send_with_reply(connection, message, + &pending, TIMEOUT) == FALSE) { + syslog(LOG_ERR, "D-BUS send failed"); + goto failed; + } + + dbus_pending_call_set_notify(pending, reply_handler_function, + req, free_pin_req); + + dbus_connection_flush (connection); + + dbus_message_unref (message); + + return; + +failed: + dbus_message_unref (message); + hci_send_cmd(dev, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, + 6, &ci->bdaddr); +} + +gboolean watch_func(GIOChannel *chan, GIOCondition cond, gpointer data) +{ + DBusWatch *watch = (DBusWatch *) data; + int flags = 0; + + if (cond & G_IO_IN) flags |= DBUS_WATCH_READABLE; + if (cond & G_IO_OUT) flags |= DBUS_WATCH_WRITABLE; + if (cond & G_IO_HUP) flags |= DBUS_WATCH_HANGUP; + if (cond & G_IO_ERR) flags |= DBUS_WATCH_ERROR; + + dbus_watch_handle(watch, flags); + + dbus_connection_ref(connection); + + /* Dispatch messages */ + while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS); + + dbus_connection_unref(connection); + + return TRUE; +} + +dbus_bool_t add_watch(DBusWatch *watch, void *data) +{ + GIOCondition cond = G_IO_HUP | G_IO_ERR; + GIOChannel *io; + guint id; + int fd, flags; + + if (!dbus_watch_get_enabled(watch)) + return TRUE; + + fd = dbus_watch_get_fd(watch); + io = g_io_channel_unix_new(fd); + flags = dbus_watch_get_flags(watch); + + if (flags & DBUS_WATCH_READABLE) cond |= G_IO_IN; + if (flags & DBUS_WATCH_WRITABLE) cond |= G_IO_OUT; + + id = g_io_add_watch(io, cond, watch_func, watch); + + dbus_watch_set_data(watch, (void *) id, NULL); + + return TRUE; +} + +static void remove_watch(DBusWatch *watch, void *data) +{ + guint id = (guint) dbus_watch_get_data(watch); + + dbus_watch_set_data(watch, NULL, NULL); + + if (id) + g_io_remove_watch(id); +} + +static void watch_toggled(DBusWatch *watch, void *data) +{ + /* Because we just exit on OOM, enable/disable is + * no different from add/remove + */ + if (dbus_watch_get_enabled(watch)) + add_watch(watch, data); + else + remove_watch(watch, data); +} + +gboolean hcid_dbus_init(void) +{ + DBusError error; + + dbus_error_init(&error); + + connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error); + if (connection == NULL) { + fprintf(stderr, "Failed to open connection to system message bus: %s\n", + error.message); + dbus_error_free(&error); + return FALSE; + } + + dbus_connection_set_watch_functions(connection, + add_watch, remove_watch, watch_toggled, NULL, NULL); + + return TRUE; +} |