diff options
-rw-r--r-- | common/dbus.c | 385 | ||||
-rw-r--r-- | common/dbus.h | 11 | ||||
-rw-r--r-- | cups/Makefile.am | 4 | ||||
-rw-r--r-- | cups/main.c | 5 | ||||
-rw-r--r-- | daemon/Makefile.am | 16 | ||||
-rw-r--r-- | daemon/echo.c | 448 | ||||
-rw-r--r-- | daemon/echo.service | 4 | ||||
-rw-r--r-- | daemon/main.c | 5 | ||||
-rw-r--r-- | gdbus/gdbus.h | 21 | ||||
-rw-r--r-- | gdbus/mainloop.c | 280 | ||||
-rw-r--r-- | hcid/dbus-common.c | 5 |
11 files changed, 316 insertions, 868 deletions
diff --git a/common/dbus.c b/common/dbus.c index beb97a07..4ea56c9f 100644 --- a/common/dbus.c +++ b/common/dbus.c @@ -48,35 +48,9 @@ #include "dbus.h" #include "logging.h" -#define DISPATCH_TIMEOUT 0 - static guint listener_id = 0; static GSList *name_listeners = NULL; -#ifndef HAVE_DBUS_GLIB -typedef struct { - uint32_t id; - DBusTimeout *timeout; -} timeout_handler_t; - -struct watch_info { - guint watch_id; - GIOChannel *io; - DBusConnection *conn; -}; - -struct server_info { - guint watch_id; - GIOChannel *io; - DBusServer *server; -}; -#endif - -struct disconnect_data { - void (*disconnect_cb)(void *); - void *user_data; -}; - struct name_callback { name_cb_t func; void *user_data; @@ -415,362 +389,3 @@ int name_listener_indicate_disconnect(DBusConnection *connection) return 0; } - -static DBusHandlerResult disconnect_filter(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct disconnect_data *dc_data = data; - - if (dbus_message_is_signal(msg, - DBUS_INTERFACE_LOCAL, "Disconnected") == TRUE) { - error("Got disconnected from the system message bus"); - dbus_connection_unref(conn); - dc_data->disconnect_cb(dc_data->user_data); - } - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - -#ifndef HAVE_DBUS_GLIB -static dbus_int32_t server_slot = -1; - -static gboolean server_func(GIOChannel *chan, GIOCondition cond, gpointer data) -{ - DBusWatch *watch = 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); - - return TRUE; -} - -static dbus_bool_t add_server(DBusWatch *watch, void *data) -{ - GIOCondition cond = G_IO_HUP | G_IO_ERR; - DBusServer *server = data; - struct server_info *info; - int fd, flags; - - if (!dbus_watch_get_enabled(watch)) - return TRUE; - - info = g_new(struct server_info, 1); - - fd = dbus_watch_get_unix_fd(watch); - info->io = g_io_channel_unix_new(fd); - info->server = dbus_server_ref(server); - - dbus_watch_set_data(watch, info, NULL); - - flags = dbus_watch_get_flags(watch); - - if (flags & DBUS_WATCH_READABLE) cond |= G_IO_IN; - if (flags & DBUS_WATCH_WRITABLE) cond |= G_IO_OUT; - - info->watch_id = g_io_add_watch(info->io, cond, server_func, watch); - - return TRUE; -} - -static void remove_server(DBusWatch *watch, void *data) -{ - struct server_info *info = dbus_watch_get_data(watch); - - dbus_watch_set_data(watch, NULL, NULL); - - if (info) { - g_source_remove(info->watch_id); - g_io_channel_unref(info->io); - dbus_server_unref(info->server); - g_free(info); - } -} - -static void server_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_server(watch, data); - else - remove_server(watch, data); -} - -static gboolean message_dispatch_cb(void *data) -{ - DBusConnection *connection = data; - - dbus_connection_ref(connection); - - /* Dispatch messages */ - while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS); - - dbus_connection_unref(connection); - - return FALSE; -} - -static gboolean watch_func(GIOChannel *chan, GIOCondition cond, gpointer data) -{ - DBusWatch *watch = data; - struct watch_info *info = dbus_watch_get_data(watch); - 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); - - if (dbus_connection_get_dispatch_status(info->conn) == DBUS_DISPATCH_DATA_REMAINS) - g_timeout_add(DISPATCH_TIMEOUT, message_dispatch_cb, info->conn); - - return TRUE; -} - -static dbus_bool_t add_watch(DBusWatch *watch, void *data) -{ - GIOCondition cond = G_IO_HUP | G_IO_ERR; - DBusConnection *conn = data; - struct watch_info *info; - int fd, flags; - - if (!dbus_watch_get_enabled(watch)) - return TRUE; - - info = g_new(struct watch_info, 1); - - fd = dbus_watch_get_unix_fd(watch); - info->io = g_io_channel_unix_new(fd); - info->conn = dbus_connection_ref(conn); - - dbus_watch_set_data(watch, info, NULL); - - flags = dbus_watch_get_flags(watch); - - if (flags & DBUS_WATCH_READABLE) cond |= G_IO_IN; - if (flags & DBUS_WATCH_WRITABLE) cond |= G_IO_OUT; - - info->watch_id = g_io_add_watch(info->io, cond, watch_func, watch); - - return TRUE; -} - -static void remove_watch(DBusWatch *watch, void *data) -{ - struct watch_info *info = dbus_watch_get_data(watch); - - dbus_watch_set_data(watch, NULL, NULL); - - if (info) { - g_source_remove(info->watch_id); - g_io_channel_unref(info->io); - dbus_connection_unref(info->conn); - g_free(info); - } -} - -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); -} - -static gboolean timeout_handler_dispatch(gpointer data) -{ - timeout_handler_t *handler = data; - - /* if not enabled should not be polled by the main loop */ - if (dbus_timeout_get_enabled(handler->timeout) != TRUE) - return FALSE; - - dbus_timeout_handle(handler->timeout); - - return FALSE; -} - -static void timeout_handler_free(void *data) -{ - timeout_handler_t *handler = data; - if (!handler) - return; - - g_source_remove(handler->id); - g_free(handler); -} - -static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) -{ - timeout_handler_t *handler; - - if (!dbus_timeout_get_enabled(timeout)) - return TRUE; - - handler = g_new0(timeout_handler_t, 1); - - handler->timeout = timeout; - handler->id = g_timeout_add(dbus_timeout_get_interval(timeout), - timeout_handler_dispatch, handler); - - dbus_timeout_set_data(timeout, handler, timeout_handler_free); - - return TRUE; -} - -static void remove_timeout(DBusTimeout *timeout, void *data) -{ -} - -static void timeout_toggled(DBusTimeout *timeout, void *data) -{ - if (dbus_timeout_get_enabled(timeout)) - add_timeout(timeout, data); - else - remove_timeout(timeout, data); -} - -static void dispatch_status_cb(DBusConnection *conn, - DBusDispatchStatus new_status, void *data) -{ - if (!dbus_connection_get_is_connected(conn)) - return; - - if (new_status == DBUS_DISPATCH_DATA_REMAINS) - g_timeout_add(DISPATCH_TIMEOUT, message_dispatch_cb, data); -} -#endif - -void setup_dbus_server_with_main_loop(DBusServer *server) -{ -#ifdef HAVE_DBUS_GLIB - debug("Using D-Bus GLib server setup"); - - dbus_server_setup_with_g_main(server, NULL); -#else - dbus_server_allocate_data_slot(&server_slot); - if (server_slot < 0) - return; - - dbus_server_set_data(server, server_slot, server, NULL); - - dbus_server_set_watch_functions(server, add_server, remove_server, - server_toggled, server, NULL); - - dbus_server_set_timeout_functions(server, add_timeout, remove_timeout, - timeout_toggled, server, NULL); -#endif -} - -void setup_dbus_with_main_loop(DBusConnection *conn) -{ -#ifdef HAVE_DBUS_GLIB - debug("Using D-Bus GLib connection setup"); - - dbus_connection_setup_with_g_main(conn, NULL); -#else - dbus_connection_set_watch_functions(conn, add_watch, remove_watch, - watch_toggled, conn, NULL); - - dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout, - timeout_toggled, conn, NULL); - - dbus_connection_set_dispatch_status_function(conn, dispatch_status_cb, - conn, NULL); -#endif -} - -DBusConnection *init_dbus(const char *name, - void (*disconnect_cb)(void *), void *user_data) -{ - struct disconnect_data *dc_data; - DBusConnection *conn; - DBusError err; - - dbus_error_init(&err); - - conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err); - - if (dbus_error_is_set(&err)) { - error("Can't connect to system message bus: %s", err.message); - dbus_error_free(&err); - return NULL; - } - - setup_dbus_with_main_loop(conn); - - if (name) { - dbus_error_init(&err); - - if (dbus_bus_request_name(conn, name, 0, &err) != - DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER ) { - error("Could not become the primary owner of %s", name); - dbus_connection_unref(conn); - return NULL; - } - - if (dbus_error_is_set(&err)) { - error("Can't get bus name %s: %s", name, err.message); - dbus_error_free(&err); - dbus_connection_unref(conn); - return NULL; - } - } - - if (!disconnect_cb) - return conn; - - dc_data = g_new(struct disconnect_data, 1); - - dc_data->disconnect_cb = disconnect_cb; - dc_data->user_data = user_data; - - dbus_connection_set_exit_on_disconnect(conn, FALSE); - - if (!dbus_connection_add_filter(conn, disconnect_filter, - dc_data, g_free)) { - error("Can't add D-Bus disconnect filter"); - g_free(dc_data); - dbus_connection_unref(conn); - return NULL; - } - - return conn; -} - -DBusConnection *init_dbus_direct(const char *address) -{ - DBusConnection *conn; - DBusError err; - - dbus_error_init(&err); - - conn = dbus_connection_open(address, &err); - - if (dbus_error_is_set(&err)) { - error("Can't connect to message server: %s", err.message); - dbus_error_free(&err); - return NULL; - } - - setup_dbus_with_main_loop(conn); - - dbus_connection_set_exit_on_disconnect(conn, FALSE); - - return conn; -} - -DBusConnection *dbus_bus_system_setup_with_main_loop(const char *name, - void (*disconnect_cb)(void *), void *user_data) -{ - return init_dbus(name, disconnect_cb, user_data); -} diff --git a/common/dbus.h b/common/dbus.h index 94244eb6..5976a479 100644 --- a/common/dbus.h +++ b/common/dbus.h @@ -27,17 +27,6 @@ #include <dbus/dbus.h> #include <glib.h> -void setup_dbus_server_with_main_loop(DBusServer *server); -void setup_dbus_with_main_loop(DBusConnection *conn); - -DBusConnection *init_dbus(const char *name, - void (*disconnect_cb)(void *), void *user_data); - -DBusConnection *init_dbus_direct(const char *address); - -DBusConnection *dbus_bus_system_setup_with_main_loop(const char *name, - void (*disconnect_cb)(void *), void *user_data); - typedef void (*name_cb_t)(const char *name, void *user_data); guint name_listener_add(DBusConnection *connection, const char *name, diff --git a/cups/Makefile.am b/cups/Makefile.am index 853c436d..f01665ee 100644 --- a/cups/Makefile.am +++ b/cups/Makefile.am @@ -7,10 +7,10 @@ cups_PROGRAMS = bluetooth bluetooth_SOURCES = main.c cups.h sdp.c spp.c hcrp.c bluetooth_LDADD = $(top_builddir)/common/libhelper.a \ - @DBUS_LIBS@ @GLIB_LIBS@ @BLUEZ_LIBS@ + @GDBUS_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@ endif -AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ +AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@ INCLUDES = -I$(top_srcdir)/common diff --git a/cups/main.c b/cups/main.c index ac77e85d..b36b2074 100644 --- a/cups/main.c +++ b/cups/main.c @@ -38,10 +38,9 @@ #include <bluetooth/sdp.h> #include <bluetooth/sdp_lib.h> -#include <glib.h> +#include <gdbus.h> #include "cups.h" -#include "dbus.h" #include "sdp-xml.h" extern int sdp_search_spp(sdp_session_t *sdp, uint8_t *channel); @@ -456,7 +455,7 @@ static gboolean list_printers(void) char *adapter, *match; guint len; - conn = init_dbus(NULL, NULL, NULL); + conn = dbus_bus_system_setup_with_main_loop("org.bluez", NULL, NULL); if (conn == NULL) return FALSE; diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 8b2bba31..e2a16be2 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -1,12 +1,5 @@ -noinst_PROGRAMS = bluetoothd passkey-agent auth-agent \ - bluetoothd-service-echo - -bluetoothd_service_echo_SOURCES = echo.c - -bluetoothd_service_echo_LDADD = \ - $(top_builddir)/common/libhelper.a \ - @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@ +noinst_PROGRAMS = bluetoothd passkey-agent auth-agent if CONFIGFILES dbusdir = $(sysconfdir)/dbus-1/system.d @@ -21,7 +14,7 @@ bluetoothd_SOURCES = main.c system.h \ bluetoothd_LDADD = \ $(top_builddir)/common/libhelper.a \ $(top_builddir)/sdpd/libsdpserver.a \ - @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@ + @GDBUS_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@ passkey_agent_SOURCES = passkey-agent.c @@ -31,11 +24,10 @@ auth_agent_SOURCES = auth-agent.c auth_agent_LDADD = @DBUS_LIBS@ -AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ +AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@ INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/sdpd -EXTRA_DIST = bluetooth.conf echo.service \ - test-manager test-database +EXTRA_DIST = bluetooth.conf test-manager test-database MAINTAINERCLEANFILES = Makefile.in diff --git a/daemon/echo.c b/daemon/echo.c deleted file mode 100644 index 09ceef31..00000000 --- a/daemon/echo.c +++ /dev/null @@ -1,448 +0,0 @@ -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <unistd.h> -#include <stdlib.h> -#include <string.h> -#include <signal.h> -#include <sys/socket.h> - -#include <bluetooth/bluetooth.h> -#include <bluetooth/rfcomm.h> -#include <bluetooth/sdp.h> -#include <bluetooth/sdp_lib.h> - -#include <glib.h> - -#include <dbus/dbus.h> - -#include "dbus.h" -#include "logging.h" - -struct auth_data { - DBusConnection *conn; - GIOChannel *io; - char *address; -}; - -static gboolean session_event(GIOChannel *chan, - GIOCondition cond, gpointer data) -{ - unsigned char buf[672]; - gsize len, written; - GIOError err; - - if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) - return FALSE; - - err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf), &len); - if (err == G_IO_ERROR_AGAIN) - return TRUE; - - g_io_channel_write(chan, (const gchar *) buf, len, &written); - - return TRUE; -} - -static void cancel_authorization(DBusConnection *conn, const char *address) -{ - DBusMessage *msg; - const char *string = ""; - - info("Canceling authorization for %s", address); - - msg = dbus_message_new_method_call("org.bluez", "/org/bluez", - "org.bluez.Database", "CancelAuthorizationRequest"); - if (!msg) { - error("Allocation of method message failed"); - return; - } - - dbus_message_append_args(msg, DBUS_TYPE_STRING, &address, - DBUS_TYPE_STRING, &string, DBUS_TYPE_INVALID); - - dbus_connection_send(conn, msg, NULL); - - dbus_message_unref(msg); -} - -static void authorization_callback(DBusPendingCall *call, void *data) -{ - DBusMessage *reply = dbus_pending_call_steal_reply(call); - struct auth_data *auth = data; - DBusError err; - - dbus_error_init(&err); - - if (dbus_set_error_from_message(&err, reply)) { - error("Access denied: %s", err.message); - if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) - cancel_authorization(auth->conn, auth->address); - dbus_error_free(&err); - } else { - info("Accepting incoming connection"); - g_io_add_watch(auth->io, - G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, - session_event, NULL); - } - - g_io_channel_unref(auth->io); - - dbus_message_unref(reply); -} - -static void authorization_free(void *data) -{ - struct auth_data *auth = data; - - g_free(auth->address); - g_free(auth); -} - -static int request_authorization(DBusConnection *conn, - GIOChannel *io, const char *address) -{ - DBusMessage *msg; - DBusPendingCall *pending; - struct auth_data *auth; - const char *string = ""; - - info("Requesting authorization for %s", address); - - auth = g_try_malloc0(sizeof(*auth)); - if (!auth) { - error("Allocation of auth object failed"); - return -1; - } - - msg = dbus_message_new_method_call("org.bluez", "/org/bluez", - "org.bluez.Database", "RequestAuthorization"); - if (!msg) { - error("Allocation of method message failed"); - g_free(auth); - return -1; - } - - dbus_message_append_args(msg, DBUS_TYPE_STRING, &address, - DBUS_TYPE_STRING, &string, DBUS_TYPE_INVALID); - - if (dbus_connection_send_with_reply(conn, msg, &pending, -1) == FALSE) { - error("Sending of authorization request failed"); - dbus_message_unref(msg); - g_free(auth); - return -1; - } - - auth->conn = conn; - auth->io = io; - auth->address = g_strdup(address); - - dbus_pending_call_set_notify(pending, authorization_callback, - auth, authorization_free); - - dbus_pending_call_unref(pending); - - dbus_message_unref(msg); - - return 0; -} - -static gboolean connect_event(GIOChannel *chan, - GIOCondition cond, gpointer data) -{ - DBusConnection *conn = data; - GIOChannel *io; - struct sockaddr_rc addr; - socklen_t optlen; - char address[18]; - int sk, nsk; - - sk = g_io_channel_unix_get_fd(chan); - - memset(&addr, 0, sizeof(addr)); - optlen = sizeof(addr); - - nsk = accept(sk, (struct sockaddr *) &addr, &optlen); - if (nsk < 0) - return TRUE; - - io = g_io_channel_unix_new(nsk); - g_io_channel_set_close_on_unref(io, TRUE); - - ba2str(&addr.rc_bdaddr, address); - - if (request_authorization(conn, io, address) < 0) { - close(nsk); - return TRUE; - } - - return TRUE; -} - -static GIOChannel *setup_rfcomm(DBusConnection *conn, uint8_t channel) -{ - GIOChannel *io; - struct sockaddr_rc addr; - int sk; - - sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); - if (sk < 0) - return NULL; - - memset(&addr, 0, sizeof(addr)); - addr.rc_family = AF_BLUETOOTH; - bacpy(&addr.rc_bdaddr, BDADDR_ANY); - addr.rc_channel = channel; - - if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - close(sk); - return NULL; - } - - if (listen(sk, 10) < 0) { - close(sk); - return NULL; - } - - io = g_io_channel_unix_new(sk); - g_io_channel_set_close_on_unref(io, TRUE); - - g_io_add_watch(io, G_IO_IN, connect_event, conn); - - return io; -} - -static int setup_sdp(DBusConnection *conn, uint8_t channel) -{ - DBusMessage *msg, *reply; - DBusError err; - sdp_record_t *record; - sdp_buf_t buf; - sdp_list_t *svclass, *pfseq, *apseq, *root, *aproto; - uuid_t root_uuid, l2cap, rfcomm, spp; - sdp_profile_desc_t profile[1]; - sdp_list_t *proto[2]; - sdp_data_t *chan; - - record = sdp_record_alloc(); - if (!record) { - error("Allocation of service record failed"); - return -1; - } - - sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); - root = sdp_list_append(NULL, &root_uuid); - sdp_set_browse_groups(record, root); - - sdp_uuid16_create(&l2cap, L2CAP_UUID); - proto[0] = sdp_list_append(NULL, &l2cap); - apseq = sdp_list_append(NULL, proto[0]); - - chan = sdp_data_alloc(SDP_UINT8, &channel); - sdp_uuid16_create(&rfcomm, RFCOMM_UUID); - proto[1] = sdp_list_append(NULL, &rfcomm); - proto[1] = sdp_list_append(proto[1], chan); - apseq = sdp_list_append(apseq, proto[1]); - - aproto = sdp_list_append(NULL, apseq); - sdp_set_access_protos(record, aproto); - - sdp_uuid16_create(&spp, SERIAL_PORT_SVCLASS_ID); - svclass = sdp_list_append(NULL, &spp); - sdp_set_service_classes(record, svclass); - - sdp_uuid16_create(&profile[0].uuid, SERIAL_PORT_PROFILE_ID); - profile[0].version = 0x0100; - pfseq = sdp_list_append(NULL, &profile[0]); - sdp_set_profile_descs(record, pfseq); - - sdp_set_info_attr(record, "Echo service", NULL, NULL); - - if (sdp_gen_record_pdu(record, &buf) < 0) { - error("Generation of service record failed"); - sdp_record_free(record); - return -1; - } - - sdp_data_free(chan); - sdp_list_free(root, NULL); - sdp_list_free(apseq, NULL); - sdp_list_free(pfseq, NULL); - sdp_list_free(aproto, NULL); - sdp_list_free(svclass, NULL); - sdp_list_free(proto[0], NULL); - sdp_list_free(proto[1], NULL); - - sdp_record_free(record); - - msg = dbus_message_new_method_call("org.bluez", "/org/bluez", - "org.bluez.Database", "AddServiceRecord"); - if (!msg) { - error("Allocation of method message failed"); - return -1; - } - - dbus_message_append_args(msg, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &buf.data, buf.data_size, DBUS_TYPE_INVALID); - - dbus_error_init(&err); - - reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err); - - dbus_message_unref(msg); - - free(buf.data); - - if (!reply) { - error("Registration of service record failed"); - error("%s", err.message); - dbus_error_free(&err); - return -1; - } - - dbus_message_unref(reply); - - dbus_connection_flush(conn); - - return 0; -} - -static int register_standalone(DBusConnection *conn) -{ - DBusMessage *msg, *reply; - DBusError err; - const char *ident = "echo", *name = "Echo service", *desc = ""; - - info("Registering service"); - - msg = dbus_message_new_method_call("org.bluez", "/org/bluez", - "org.bluez.Database", "RegisterService"); - if (!msg) { - error("Allocation of method message failed"); - return -1; - } - - dbus_message_append_args(msg, DBUS_TYPE_STRING, &ident, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_STRING, &desc, DBUS_TYPE_INVALID); - - dbus_error_init(&err); - - reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err); - - dbus_message_unref(msg); - - if (!reply) { - error("Registration of service failed"); - error("%s", err.message); - dbus_error_free(&err); - return -1; - } - - dbus_message_unref(reply); - - dbus_connection_flush(conn); - - return 0; -} - -static GMainLoop *main_loop = NULL; - -static void sig_term(int sig) -{ - g_main_loop_quit(main_loop); -} - -int main(int argc, char *argv[]) -{ - DBusConnection *conn; - GIOChannel *io; - struct sigaction sa; - char *addr; - - start_logging("echo", "Bluetooth echo service ver %s", VERSION); - - memset(&sa, 0, sizeof(sa)); - sa.sa_flags = SA_NOCLDSTOP; - sa.sa_handler = sig_term; - sigaction(SIGTERM, &sa, NULL); - sigaction(SIGINT, &sa, NULL); - - sa.sa_handler = SIG_IGN; - sigaction(SIGCHLD, &sa, NULL); - sigaction(SIGPIPE, &sa, NULL); - - enable_debug(); - - addr = getenv("BLUETOOTHD_ADDRESS"); - if (!addr) { - error("No D-Bus server address available"); - exit(1); - } - - debug("Bluetooth daemon at %s", addr); - - main_loop = g_main_loop_new(NULL, FALSE); - - if (argc > 1 && !strcmp(argv[1], "-s")) - conn = init_dbus_direct(addr); - else - conn = init_dbus(NULL, NULL, NULL); - - if (!conn) { - error("Connection to bus failed"); - g_main_loop_unref(main_loop); - exit(1); - } - - io = setup_rfcomm(conn, 23); - if (!io) { - error("Creation of server channel failed"); - dbus_connection_unref(conn); - g_main_loop_unref(main_loop); - exit(1); - } - - setup_sdp(conn, 23); - - if (argc > 1 && !strcmp(argv[1], "-s")) - register_standalone(conn); - - g_main_loop_run(main_loop); - - g_io_channel_unref(io); - - dbus_connection_unref(conn); - - g_main_loop_unref(main_loop); - - info("Exit"); - - stop_logging(); - - return 0; -} diff --git a/daemon/echo.service b/daemon/echo.service deleted file mode 100644 index bd13d649..00000000 --- a/daemon/echo.service +++ /dev/null @@ -1,4 +0,0 @@ -[Bluetooth Service] -Identifier=echo -Name=Echo service -Description=Bluetooth RFCOMM based Echo service diff --git a/daemon/main.c b/daemon/main.c index 94eba19a..be731b14 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -37,6 +37,8 @@ #include <dbus/dbus.h> +#include <gdbus.h> + #include "dbus-helper.h" #include "dbus.h" @@ -56,7 +58,8 @@ static DBusConnection *system_bus = NULL; static int setup_dbus(void) { - system_bus = init_dbus("org.bluez", NULL, NULL); + system_bus = dbus_bus_system_setup_with_main_loop("org.bluez", + NULL, NULL); if (!system_bus) return -1; diff --git a/gdbus/gdbus.h b/gdbus/gdbus.h index 71377516..d749d5e2 100644 --- a/gdbus/gdbus.h +++ b/gdbus/gdbus.h @@ -20,3 +20,24 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ + +#ifndef __GDBUS_H +#define __GDBUS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <dbus/dbus.h> +#include <glib.h> + +void setup_dbus_with_main_loop(DBusConnection *conn); + +DBusConnection *dbus_bus_system_setup_with_main_loop(const char *name, + void (*disconnect_cb)(void *), void *user_data); + +#ifdef __cplusplus +} +#endif + +#endif /* __GDBUS_H */ diff --git a/gdbus/mainloop.c b/gdbus/mainloop.c index f08299f0..e8e7e0af 100644 --- a/gdbus/mainloop.c +++ b/gdbus/mainloop.c @@ -25,8 +25,9 @@ #include <config.h> #endif -#include <glib.h> +#include <stdint.h> +#include <glib.h> #include <dbus/dbus.h> #ifdef NEED_DBUS_WATCH_GET_UNIX_FD @@ -38,3 +39,280 @@ #endif #include "gdbus.h" + +#define DISPATCH_TIMEOUT 0 + +#define info(fmt...) +#define error(fmt...) +#define debug(fmt...) + +#ifndef HAVE_DBUS_GLIB +typedef struct { + uint32_t id; + DBusTimeout *timeout; +} timeout_handler_t; + +struct watch_info { + guint watch_id; + GIOChannel *io; + DBusConnection *conn; +}; + +struct server_info { + guint watch_id; + GIOChannel *io; + DBusServer *server; +}; +#endif + +struct disconnect_data { + void (*disconnect_cb)(void *); + void *user_data; +}; + +static DBusHandlerResult disconnect_filter(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct disconnect_data *dc_data = data; + + if (dbus_message_is_signal(msg, + DBUS_INTERFACE_LOCAL, "Disconnected") == TRUE) { + error("Got disconnected from the system message bus"); + dbus_connection_unref(conn); + dc_data->disconnect_cb(dc_data->user_data); + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +#ifndef HAVE_DBUS_GLIB +static gboolean message_dispatch_cb(void *data) +{ + DBusConnection *connection = data; + + dbus_connection_ref(connection); + + /* Dispatch messages */ + while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS); + + dbus_connection_unref(connection); + + return FALSE; +} + +static gboolean watch_func(GIOChannel *chan, GIOCondition cond, gpointer data) +{ + DBusWatch *watch = data; + struct watch_info *info = dbus_watch_get_data(watch); + 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); + + if (dbus_connection_get_dispatch_status(info->conn) == DBUS_DISPATCH_DATA_REMAINS) + g_timeout_add(DISPATCH_TIMEOUT, message_dispatch_cb, info->conn); + + return TRUE; +} + +static dbus_bool_t add_watch(DBusWatch *watch, void *data) +{ + GIOCondition cond = G_IO_HUP | G_IO_ERR; + DBusConnection *conn = data; + struct watch_info *info; + int fd, flags; + + if (!dbus_watch_get_enabled(watch)) + return TRUE; + + info = g_new(struct watch_info, 1); + + fd = dbus_watch_get_unix_fd(watch); + info->io = g_io_channel_unix_new(fd); + info->conn = dbus_connection_ref(conn); + + dbus_watch_set_data(watch, info, NULL); + + flags = dbus_watch_get_flags(watch); + + if (flags & DBUS_WATCH_READABLE) cond |= G_IO_IN; + if (flags & DBUS_WATCH_WRITABLE) cond |= G_IO_OUT; + + info->watch_id = g_io_add_watch(info->io, cond, watch_func, watch); + + return TRUE; +} + +static void remove_watch(DBusWatch *watch, void *data) +{ + struct watch_info *info = dbus_watch_get_data(watch); + + dbus_watch_set_data(watch, NULL, NULL); + + if (info) { + g_source_remove(info->watch_id); + g_io_channel_unref(info->io); + dbus_connection_unref(info->conn); + g_free(info); + } +} + +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); +} + +static gboolean timeout_handler_dispatch(gpointer data) +{ + timeout_handler_t *handler = data; + + /* if not enabled should not be polled by the main loop */ + if (dbus_timeout_get_enabled(handler->timeout) != TRUE) + return FALSE; + + dbus_timeout_handle(handler->timeout); + + return FALSE; +} + +static void timeout_handler_free(void *data) +{ + timeout_handler_t *handler = data; + if (!handler) + return; + + g_source_remove(handler->id); + g_free(handler); +} + +static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) +{ + timeout_handler_t *handler; + + if (!dbus_timeout_get_enabled(timeout)) + return TRUE; + + handler = g_new0(timeout_handler_t, 1); + + handler->timeout = timeout; + handler->id = g_timeout_add(dbus_timeout_get_interval(timeout), + timeout_handler_dispatch, handler); + + dbus_timeout_set_data(timeout, handler, timeout_handler_free); + + return TRUE; +} + +static void remove_timeout(DBusTimeout *timeout, void *data) +{ +} + +static void timeout_toggled(DBusTimeout *timeout, void *data) +{ + if (dbus_timeout_get_enabled(timeout)) + add_timeout(timeout, data); + else + remove_timeout(timeout, data); +} + +static void dispatch_status_cb(DBusConnection *conn, + DBusDispatchStatus new_status, void *data) +{ + if (!dbus_connection_get_is_connected(conn)) + return; + + if (new_status == DBUS_DISPATCH_DATA_REMAINS) + g_timeout_add(DISPATCH_TIMEOUT, message_dispatch_cb, data); +} +#endif + +void setup_dbus_with_main_loop(DBusConnection *conn) +{ +#ifdef HAVE_DBUS_GLIB + debug("Using D-Bus GLib connection setup"); + + dbus_connection_setup_with_g_main(conn, NULL); +#else + dbus_connection_set_watch_functions(conn, add_watch, remove_watch, + watch_toggled, conn, NULL); + + dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout, + timeout_toggled, conn, NULL); + + dbus_connection_set_dispatch_status_function(conn, dispatch_status_cb, + conn, NULL); +#endif +} + +static DBusConnection *init_dbus(const char *name, + void (*disconnect_cb)(void *), void *user_data) +{ + struct disconnect_data *dc_data; + DBusConnection *conn; + DBusError err; + + dbus_error_init(&err); + + conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err); + + if (dbus_error_is_set(&err)) { + error("Can't connect to system message bus: %s", err.message); + dbus_error_free(&err); + return NULL; + } + + setup_dbus_with_main_loop(conn); + + if (name) { + dbus_error_init(&err); + + if (dbus_bus_request_name(conn, name, 0, &err) != + DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER ) { + error("Could not become the primary owner of %s", name); + dbus_connection_unref(conn); + return NULL; + } + + if (dbus_error_is_set(&err)) { + error("Can't get bus name %s: %s", name, err.message); + dbus_error_free(&err); + dbus_connection_unref(conn); + return NULL; + } + } + + if (!disconnect_cb) + return conn; + + dc_data = g_new(struct disconnect_data, 1); + + dc_data->disconnect_cb = disconnect_cb; + dc_data->user_data = user_data; + + dbus_connection_set_exit_on_disconnect(conn, FALSE); + + if (!dbus_connection_add_filter(conn, disconnect_filter, + dc_data, g_free)) { + error("Can't add D-Bus disconnect filter"); + g_free(dc_data); + dbus_connection_unref(conn); + return NULL; + } + + return conn; +} + +DBusConnection *dbus_bus_system_setup_with_main_loop(const char *name, + void (*disconnect_cb)(void *), void *user_data) +{ + return init_dbus(name, disconnect_cb, user_data); +} diff --git a/hcid/dbus-common.c b/hcid/dbus-common.c index 20453c82..8a8a721a 100644 --- a/hcid/dbus-common.c +++ b/hcid/dbus-common.c @@ -49,6 +49,8 @@ #include <dbus/dbus.h> +#include <gdbus.h> + #include "hcid.h" #include "dbus.h" #include "dbus-helper.h" @@ -336,7 +338,8 @@ int hcid_dbus_init(void) { DBusConnection *conn; - conn = init_dbus(BLUEZ_NAME, disconnect_callback, NULL); + conn = dbus_bus_system_setup_with_main_loop(BLUEZ_NAME, + disconnect_callback, NULL); if (!conn) return -1; |