2010-07-29 07:18:15

by Zhenhua Zhang

[permalink] [raw]
Subject: [PATCH 0/6] oFono patches for BT DUN server

Hi Johan and Luiz,

This series of patches are for BT DUN server support in oFono. Could
you please to review them especially the btio.[ch] changes in patch
2/6.

oFono git: git://git.kernel.org/pub/scm/network/ofono/ofono.git

Thanks.
Zhenhua



2010-07-31 23:25:06

by Gustavo Padovan

[permalink] [raw]
Subject: Re: [PATCH 1/6] bluetooth: Add reference count for bluetooth utils

Hi Zhenhua,

* Zhenhua Zhang <[email protected]> [2010-07-29 15:18:16 +0800]:

> Add bluetooth_ref()/bluetooth_unref() to support reference count in
> bluetooth utils.
> ---
> plugins/bluetooth.c | 62 +++++++++++++++++++++++++++++++++++++--------------
> 1 files changed, 45 insertions(+), 17 deletions(-)
>
> diff --git a/plugins/bluetooth.c b/plugins/bluetooth.c
> index 5a85eaa..10cc49d 100644
> --- a/plugins/bluetooth.c
> +++ b/plugins/bluetooth.c
> @@ -39,6 +39,7 @@
> static DBusConnection *connection;
> static GHashTable *uuid_hash = NULL;
> static GHashTable *adapter_address_hash = NULL;
> +static gint ref_count;
>
> void bluetooth_create_path(const char *dev_addr, const char *adapter_addr,
> char *buf, int size)
> @@ -503,13 +504,10 @@ static guint adapter_added_watch;
> static guint adapter_removed_watch;
> static guint property_watch;
>
> -int bluetooth_register_uuid(const char *uuid, struct bluetooth_profile *profile)
> +static int bluetooth_init()
> {
> int err;
>
> - if (uuid_hash)
> - goto done;
> -
> connection = ofono_dbus_get_connection();
>
> bluetooth_watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE,
> @@ -542,13 +540,6 @@ int bluetooth_register_uuid(const char *uuid, struct bluetooth_profile *profile)
> adapter_address_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
> g_free, g_free);
>
> -done:
> - g_hash_table_insert(uuid_hash, g_strdup(uuid), profile);
> -
> - bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "GetProperties",
> - manager_properties_cb, NULL, NULL, -1,
> - DBUS_TYPE_INVALID);
> -
> return 0;
>
> remove:
> @@ -556,14 +547,27 @@ remove:
> g_dbus_remove_watch(connection, adapter_added_watch);
> g_dbus_remove_watch(connection, adapter_removed_watch);
> g_dbus_remove_watch(connection, property_watch);
> +
> return err;
> }
>
> -void bluetooth_unregister_uuid(const char *uuid)
> +static int bluetooth_ref()
> {
> - g_hash_table_remove(uuid_hash, uuid);
> + g_atomic_int_inc(&ref_count);
> +
> + if (ref_count > 1)
> + return 0;
> +
> + return bluetooth_init();
> +}
> +
> +static void bluetooth_unref()
> +{
> + gboolean is_zero;
> +
> + is_zero = g_atomic_int_dec_and_test(&ref_count);
>
> - if (g_hash_table_size(uuid_hash))
> + if (is_zero == FALSE)
> return;

We can remove the is_zero variable, and test g_atomic_int_dec_and_test()
directly. What do you think?

>
> g_dbus_remove_watch(connection, bluetooth_watch);
> @@ -571,9 +575,33 @@ void bluetooth_unregister_uuid(const char *uuid)
> g_dbus_remove_watch(connection, adapter_removed_watch);
> g_dbus_remove_watch(connection, property_watch);
>
> - g_hash_table_destroy(uuid_hash);
> - g_hash_table_destroy(adapter_address_hash);
> - uuid_hash = NULL;
> + if (uuid_hash)
> + g_hash_table_destroy(uuid_hash);
> +
> + if (adapter_address_hash)
> + g_hash_table_destroy(adapter_address_hash);
> +}
> +
> +int bluetooth_register_uuid(const char *uuid, struct bluetooth_profile *profile)
> +{
> + int err = bluetooth_ref();
> +
> + if (err != 0)
> + return err;
> +
> + g_hash_table_insert(uuid_hash, g_strdup(uuid), profile);
> +
> + bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "GetProperties",
> + manager_properties_cb, NULL, NULL, -1,
> + DBUS_TYPE_INVALID);
> + return 0;
> +}
> +
> +void bluetooth_unregister_uuid(const char *uuid)
> +{
> + g_hash_table_remove(uuid_hash, uuid);
> +
> + bluetooth_unref();
> }
>
> OFONO_PLUGIN_DEFINE(bluetooth, "Bluetooth Utils Plugins", VERSION,
> --
> 1.7.0.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html

--
Gustavo F. Padovan
http://padovan.org

2010-07-29 07:18:20

by Zhenhua Zhang

[permalink] [raw]
Subject: [PATCH 5/6] dun_gw: Add DUN server plugin for oFono

DUN server plug-in watches ofono modem status. When the modem comes to
ONLINE state, it registers itself on Bluetooth adapter and want for
incoming DUN connection.
---
Makefile.am | 4 ++
plugins/dun_gw.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 147 insertions(+), 0 deletions(-)
create mode 100644 plugins/dun_gw.c

diff --git a/Makefile.am b/Makefile.am
index e256841..2e08ff2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -242,6 +242,10 @@ builtin_sources += plugins/bluetooth.c plugins/bluetooth.h
builtin_modules += hfp
builtin_sources += plugins/hfp.c plugins/bluetooth.h

+builtin_modules += dun_gw
+builtin_sources += plugins/dun_gw.c plugins/bluetooth.h plugins/btio.c \
+ plugins/btio.h
+
builtin_modules += palmpre
builtin_sources += plugins/palmpre.c

diff --git a/plugins/dun_gw.c b/plugins/dun_gw.c
new file mode 100644
index 0000000..56bd03d
--- /dev/null
+++ b/plugins/dun_gw.c
@@ -0,0 +1,143 @@
+/*
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2010 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include <ofono.h>
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include <ofono/plugin.h>
+#include <ofono/log.h>
+#include <ofono/modem.h>
+
+#include <ofono/dbus.h>
+
+#include "gdbus.h"
+#include "bluetooth.h"
+
+#ifndef DBUS_TYPE_UNIX_FD
+#define DBUS_TYPE_UNIX_FD -1
+#endif
+
+#define DUN_GW_CHANNEL 1
+
+static struct server *server;
+static int modem_watch;
+
+static void dun_gw_connect_cb(GIOChannel *io, GError *err, gpointer user_data)
+{
+ DBG("");
+
+ if (err) {
+ DBG("%s", err->message);
+ goto failed;
+ }
+
+ return;
+
+failed:
+ g_io_channel_shutdown(io, TRUE, NULL);
+ bluetooth_unregister_server(server);
+ server = NULL;
+}
+
+static gboolean property_changed(DBusConnection *connection, DBusMessage *msg,
+ void *user_data)
+{
+ const char *property;
+ DBusMessageIter iter, var;
+
+ dbus_message_iter_init(msg, &iter);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return FALSE;
+
+ dbus_message_iter_get_basic(&iter, &property);
+
+ if (g_str_equal(property, "Online") == TRUE) {
+ const char *path = dbus_message_get_path(msg);
+ struct ofono_modem *modem;
+ struct ofono_atom *gprs;
+ gboolean online;
+
+ if (!dbus_message_iter_next(&iter))
+ return FALSE;
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+ return FALSE;
+
+ dbus_message_iter_recurse(&iter, &var);
+
+ dbus_message_iter_get_basic(&var, &online);
+
+ if (online == FALSE) {
+ bluetooth_unregister_server(server);
+ server = NULL;
+ goto done;
+ }
+
+ /* Create DUN server */
+ modem = ofono_modem_get_modem_by_path(path);
+ gprs = __ofono_modem_find_atom(modem,
+ OFONO_ATOM_TYPE_GPRS);
+ /* Make sure the modem has GPRS atom */
+ if (!gprs)
+ goto done;
+
+ server = bluetooth_register_server(DUN_GW,
+ "Dial-Up Networking", DUN_GW_CHANNEL,
+ dun_gw_connect_cb, modem);
+ }
+
+done:
+ return TRUE;
+}
+
+static int dun_gw_init()
+{
+ DBusConnection *connection = ofono_dbus_get_connection();
+
+ if (DBUS_TYPE_UNIX_FD < 0)
+ return -EBADF;
+
+ modem_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+ OFONO_MODEM_INTERFACE,
+ "PropertyChanged",
+ property_changed, NULL, NULL);
+
+ return 0;
+}
+
+static void dun_gw_exit()
+{
+ if (server)
+ bluetooth_unregister_server(server);
+
+ if (modem_watch)
+ g_source_remove(modem_watch);
+}
+
+OFONO_PLUGIN_DEFINE(dun_gw, "Dial-up Networking Profile Plugins", VERSION,
+ OFONO_PLUGIN_PRIORITY_DEFAULT, dun_gw_init, dun_gw_exit)
--
1.7.0.4


2010-07-29 07:18:21

by Zhenhua Zhang

[permalink] [raw]
Subject: [PATCH 6/6] emulator: Add emulator atom in oFono

DUN server could create emulator and use GAtServer to talk AT commands
to DUN client side.
---
Makefile.am | 4 +-
include/emulator.h | 41 ++++++++++++++++++
plugins/dun_gw.c | 8 +++
src/emulator.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/ofono.h | 3 +
5 files changed, 175 insertions(+), 2 deletions(-)
create mode 100644 include/emulator.h
create mode 100644 src/emulator.c

diff --git a/Makefile.am b/Makefile.am
index 2e08ff2..1ec04f3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -13,7 +13,7 @@ include_HEADERS = include/log.h include/plugin.h include/history.h \
include/cbs.h include/call-volume.h \
include/gprs.h include/gprs-context.h \
include/radio-settings.h include/stk.h \
- include/nettime.h
+ include/nettime.h include/emulator.h

nodist_include_HEADERS = include/version.h

@@ -274,7 +274,7 @@ src_ofonod_SOURCES = $(gdbus_sources) $(builtin_sources) \
src/storage.c src/cbs.c src/watch.c src/call-volume.c \
src/gprs.c src/idmap.h src/idmap.c \
src/radio-settings.c src/stkutil.h src/stkutil.c \
- src/nettime.c
+ src/nettime.c src/emulator.c

src_ofonod_LDADD = $(builtin_libadd) @GLIB_LIBS@ @DBUS_LIBS@ @CAPNG_LIBS@ -ldl

diff --git a/include/emulator.h b/include/emulator.h
new file mode 100644
index 0000000..1033e59
--- /dev/null
+++ b/include/emulator.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2010 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ * 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
+ *
+ */
+
+#ifndef __OFONO_EMULATOR_H
+#define __OFONO_EMULATOR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <ofono/types.h>
+
+struct ofono_emulator;
+
+struct ofono_emulator *ofono_emulator_create(struct ofono_modem *modem,
+ enum ofono_atom_type type,
+ GIOChannel *io);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __OFONO_EMULATOR_H */
diff --git a/plugins/dun_gw.c b/plugins/dun_gw.c
index 56bd03d..840d22d 100644
--- a/plugins/dun_gw.c
+++ b/plugins/dun_gw.c
@@ -48,6 +48,9 @@ static int modem_watch;

static void dun_gw_connect_cb(GIOChannel *io, GError *err, gpointer user_data)
{
+ struct ofono_modem *modem = user_data;
+ struct ofono_emulator *emulator;
+
DBG("");

if (err) {
@@ -55,6 +58,11 @@ static void dun_gw_connect_cb(GIOChannel *io, GError *err, gpointer user_data)
goto failed;
}

+ emulator = ofono_emulator_create(modem, OFONO_ATOM_TYPE_EMULATOR_DUN,
+ io);
+ if (!emulator)
+ goto failed;
+
return;

failed:
diff --git a/src/emulator.c b/src/emulator.c
new file mode 100644
index 0000000..6219bb1
--- /dev/null
+++ b/src/emulator.c
@@ -0,0 +1,121 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2010 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include <gdbus.h>
+
+#include "ofono.h"
+#include "common.h"
+#include "gatserver.h"
+
+struct ofono_emulator {
+ struct ofono_modem *modem;
+ struct ofono_atom *atom;
+ enum ofono_atom_type type;
+ unsigned int id;
+ GAtServer *server;
+};
+
+static unsigned int ofono_emulator_ids;
+
+static void ofono_emulator_debug(const char *str, void *data)
+{
+ g_print("%s: %s\n", (char *)data, str);
+}
+
+static unsigned int ofono_emulator_next_id()
+{
+ unsigned int i;
+
+ for (i = 1; i < sizeof(ofono_emulator_ids) * 8; i++) {
+ if (ofono_emulator_ids & (0x1 << i))
+ continue;
+
+ ofono_emulator_ids |= (0x1 << i);
+
+ return i;
+ }
+
+ return 0;
+}
+
+static void ofono_emulator_release_id(int id)
+{
+ ofono_emulator_ids &= ~(0x1 << id);
+}
+
+static void emulator_remove(struct ofono_atom *atom)
+{
+ struct ofono_emulator *e = __ofono_atom_get_data(atom);
+
+ DBG("");
+
+ g_at_server_shutdown(e->server);
+ g_at_server_unref(e->server);
+ e->server = NULL;
+
+ ofono_emulator_release_id(e->id);
+ g_free(e);
+ e = NULL;
+}
+
+static void emulator_disconnect(gpointer user_data)
+{
+ struct ofono_emulator *e = user_data;
+
+ __ofono_atom_free(e->atom);
+}
+
+struct ofono_emulator *ofono_emulator_create(struct ofono_modem *modem,
+ enum ofono_atom_type type,
+ GIOChannel *channel)
+{
+ struct ofono_emulator *e;
+
+ DBG("");
+
+ e = g_try_new0(struct ofono_emulator, 1);
+ if (!e)
+ return NULL;
+
+ e->server = g_at_server_new(channel);
+ if (!e->server) {
+ g_free(e);
+ return NULL;
+ }
+
+ g_at_server_set_debug(e->server, ofono_emulator_debug, "Server");
+ g_at_server_set_disconnect_function(e->server, emulator_disconnect, e);
+
+ e->modem = modem;
+ e->type = type;
+ e->id = ofono_emulator_next_id();
+ e->atom = __ofono_modem_add_atom(modem, type, emulator_remove, e);
+
+ return e;
+}
diff --git a/src/ofono.h b/src/ofono.h
index aaa01d9..8982a95 100644
--- a/src/ofono.h
+++ b/src/ofono.h
@@ -117,6 +117,7 @@ enum ofono_atom_type {
OFONO_ATOM_TYPE_RADIO_SETTINGS = 18,
OFONO_ATOM_TYPE_STK = 19,
OFONO_ATOM_TYPE_NETTIME = 20,
+ OFONO_ATOM_TYPE_EMULATOR_DUN = 21,
};

enum ofono_atom_watch_condition {
@@ -289,3 +290,5 @@ void __ofono_nettime_probe_drivers(struct ofono_modem *modem);

void __ofono_nettime_info_received(struct ofono_modem *modem,
struct ofono_network_time *info);
+
+#include <ofono/emulator.h>
--
1.7.0.4


2010-07-29 07:18:19

by Zhenhua Zhang

[permalink] [raw]
Subject: [PATCH 4/6] modem: Add method to get modem by path

Return modem instance by searching modem path.
---
include/modem.h | 1 +
src/modem.c | 15 +++++++++++++++
2 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/include/modem.h b/include/modem.h
index e1cd049..34c3fbf 100644
--- a/include/modem.h
+++ b/include/modem.h
@@ -36,6 +36,7 @@ void ofono_modem_remove_interface(struct ofono_modem *modem,
const char *interface);

const char *ofono_modem_get_path(struct ofono_modem *modem);
+struct ofono_modem *ofono_modem_get_modem_by_path(const char *path);

void ofono_modem_set_data(struct ofono_modem *modem, void *data);
void *ofono_modem_get_data(struct ofono_modem *modem);
diff --git a/src/modem.c b/src/modem.c
index f89d609..6907a5e 100644
--- a/src/modem.c
+++ b/src/modem.c
@@ -157,6 +157,21 @@ const char *ofono_modem_get_path(struct ofono_modem *modem)
return NULL;
}

+struct ofono_modem *ofono_modem_get_modem_by_path(const char *path)
+{
+ GSList *l;
+ struct ofono_modem *modem = NULL;
+
+ for (l = g_modem_list; l; l = l->next) {
+ modem = l->data;
+
+ if (g_str_equal(modem->path, path))
+ break;
+ }
+
+ return modem;
+}
+
struct ofono_atom *__ofono_modem_add_atom(struct ofono_modem *modem,
enum ofono_atom_type type,
void (*destruct)(struct ofono_atom *),
--
1.7.0.4


2010-07-29 07:18:17

by Zhenhua Zhang

[permalink] [raw]
Subject: [PATCH 2/6] bluetooth: Add Btio library for DUN

Btio library is the low level socket API for BT RFCOMM connection.
---
plugins/btio.c | 479 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
plugins/btio.h | 118 ++++++++++++++
2 files changed, 597 insertions(+), 0 deletions(-)
create mode 100644 plugins/btio.c
create mode 100644 plugins/btio.h

diff --git a/plugins/btio.c b/plugins/btio.c
new file mode 100644
index 0000000..6156027
--- /dev/null
+++ b/plugins/btio.c
@@ -0,0 +1,479 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2009 Marcel Holtmann <[email protected]>
+ * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2010 Intel Corporation. All rights reserved.
+ *
+ *
+ * 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
+ *
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <poll.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <glib.h>
+
+#include "btio.h"
+
+#define ERROR_FAILED(gerr, str, err) \
+ g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_FAILED, \
+ str ": %s (%d)", strerror(err), err)
+
+#define DEFAULT_DEFER_TIMEOUT 30
+
+struct set_opts {
+ bdaddr_t src;
+ int defer;
+ int sec_level;
+ uint8_t channel;
+ int master;
+};
+
+struct connect {
+ BtIOConnect connect;
+ gpointer user_data;
+ GDestroyNotify destroy;
+};
+
+struct accept {
+ BtIOConnect connect;
+ gpointer user_data;
+ GDestroyNotify destroy;
+};
+
+struct server {
+ BtIOConnect connect;
+ BtIOConfirm confirm;
+ gpointer user_data;
+ GDestroyNotify destroy;
+};
+
+static inline void bacpy(bdaddr_t *dst, const bdaddr_t *src)
+{
+ memcpy(dst, src, sizeof(bdaddr_t));
+}
+
+static void baswap(bdaddr_t *dst, const bdaddr_t *src)
+{
+ register unsigned char *d = (unsigned char *) dst;
+ register const unsigned char *s = (const unsigned char *) src;
+ register int i;
+
+ for (i = 0; i < 6; i++)
+ d[i] = s[5-i];
+}
+
+static int ba2str(const bdaddr_t *ba, char *str)
+{
+ uint8_t b[6];
+
+ baswap((bdaddr_t *) b, ba);
+ return sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+ b[0], b[1], b[2], b[3], b[4], b[5]);
+}
+
+static void server_remove(struct server *server)
+{
+ if (server->destroy)
+ server->destroy(server->user_data);
+ g_free(server);
+}
+
+static void accept_remove(struct accept *accept)
+{
+ if (accept->destroy)
+ accept->destroy(accept->user_data);
+ g_free(accept);
+}
+
+static gboolean accept_cb(GIOChannel *io, GIOCondition cond,
+ gpointer user_data)
+{
+ struct accept *accept = user_data;
+ GError *err = NULL;
+
+ /* If the user aborted this accept attempt */
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ if (cond & (G_IO_HUP | G_IO_ERR))
+ g_set_error(&err, BT_IO_ERROR, BT_IO_ERROR_DISCONNECTED,
+ "HUP or ERR on socket");
+
+ accept->connect(io, err, accept->user_data);
+
+ g_clear_error(&err);
+
+ return FALSE;
+}
+
+static gboolean server_cb(GIOChannel *io, GIOCondition cond,
+ gpointer user_data)
+{
+ struct server *server = user_data;
+ int srv_sock, cli_sock;
+ GIOChannel *cli_io;
+
+ /* If the user closed the server */
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ srv_sock = g_io_channel_unix_get_fd(io);
+
+ cli_sock = accept(srv_sock, NULL, NULL);
+ if (cli_sock < 0)
+ return TRUE;
+
+ cli_io = g_io_channel_unix_new(cli_sock);
+
+ g_io_channel_set_close_on_unref(cli_io, TRUE);
+ g_io_channel_set_flags(cli_io, G_IO_FLAG_NONBLOCK, NULL);
+
+ if (server->confirm)
+ server->confirm(cli_io, server->user_data);
+ else
+ server->connect(cli_io, NULL, server->user_data);
+
+ g_io_channel_unref(cli_io);
+
+ return TRUE;
+}
+
+static void server_add(GIOChannel *io, BtIOConnect connect,
+ BtIOConfirm confirm, gpointer user_data,
+ GDestroyNotify destroy)
+{
+ struct server *server;
+ GIOCondition cond;
+
+ server = g_new0(struct server, 1);
+ server->connect = connect;
+ server->confirm = confirm;
+ server->user_data = user_data;
+ server->destroy = destroy;
+
+ cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+ g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, server_cb, server,
+ (GDestroyNotify) server_remove);
+}
+
+static void accept_add(GIOChannel *io, BtIOConnect connect, gpointer user_data,
+ GDestroyNotify destroy)
+{
+ struct accept *accept;
+ GIOCondition cond;
+
+ accept = g_new0(struct accept, 1);
+ accept->connect = connect;
+ accept->user_data = user_data;
+ accept->destroy = destroy;
+
+ cond = G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+ g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, accept_cb, accept,
+ (GDestroyNotify) accept_remove);
+}
+
+static int rfcomm_set_lm(int sock, int level)
+{
+ int lm_map[] = {
+ 0,
+ RFCOMM_LM_AUTH,
+ RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT,
+ RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE,
+ }, opt = lm_map[level];
+
+ if (setsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &opt, sizeof(opt)) < 0)
+ return -errno;
+
+ return 0;
+}
+
+static gboolean set_sec_level(int sock, BtIOType type, int level, GError **err)
+{
+ struct bt_security sec;
+ int ret;
+
+ if (level < BT_SECURITY_LOW || level > BT_SECURITY_HIGH) {
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Valid security level range is %d-%d",
+ BT_SECURITY_LOW, BT_SECURITY_HIGH);
+ return FALSE;
+ }
+
+ memset(&sec, 0, sizeof(sec));
+ sec.level = level;
+
+ if (setsockopt(sock, SOL_BLUETOOTH, BT_SECURITY, &sec,
+ sizeof(sec)) == 0)
+ return TRUE;
+
+ if (errno != ENOPROTOOPT) {
+ ERROR_FAILED(err, "setsockopt(BT_SECURITY)", errno);
+ return FALSE;
+ }
+
+ ret = rfcomm_set_lm(sock, level);
+ if (ret < 0) {
+ ERROR_FAILED(err, "setsockopt(LM)", -ret);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int rfcomm_bind(int sock, const bdaddr_t *src, uint8_t channel)
+{
+ struct sockaddr_rc addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.rc_family = AF_BLUETOOTH;
+ bacpy(&addr.rc_bdaddr, src);
+ addr.rc_channel = channel;
+
+ return bind(sock, (struct sockaddr *) &addr, sizeof(addr));
+}
+
+static gboolean rfcomm_set(int sock, int sec_level, int master, GError **err)
+{
+ if (sec_level && !set_sec_level(sock, BT_IO_RFCOMM, sec_level, err))
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean parse_set_opts(struct set_opts *opts, GError **err,
+ BtIOOption opt1, va_list args)
+{
+ BtIOOption opt = opt1;
+
+ memset(opts, 0, sizeof(*opts));
+
+ /* Set defaults */
+ opts->defer = DEFAULT_DEFER_TIMEOUT;
+ opts->master = -1;
+
+ while (opt != BT_IO_OPT_INVALID) {
+ switch (opt) {
+ case BT_IO_OPT_CHANNEL:
+ opts->channel = va_arg(args, int);
+ break;
+ case BT_IO_OPT_SEC_LEVEL:
+ opts->sec_level = va_arg(args, int);
+ break;
+ default:
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown option %d", opt);
+ return FALSE;
+ }
+
+ opt = va_arg(args, int);
+ }
+
+ return TRUE;
+}
+
+static gboolean get_peers(int sock, struct sockaddr *src, struct sockaddr *dst,
+ socklen_t len, GError **err)
+{
+ socklen_t olen;
+
+ memset(src, 0, len);
+ olen = len;
+ if (getsockname(sock, src, &olen) < 0) {
+ ERROR_FAILED(err, "getsockname", errno);
+ return FALSE;
+ }
+
+ memset(dst, 0, len);
+ olen = len;
+ if (getpeername(sock, dst, &olen) < 0) {
+ ERROR_FAILED(err, "getpeername", errno);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean rfcomm_get(int sock, GError **err, BtIOOption opt1,
+ va_list args)
+{
+ BtIOOption opt = opt1;
+ struct sockaddr_rc src, dst;
+
+ if (!get_peers(sock, (struct sockaddr *) &src,
+ (struct sockaddr *) &dst, sizeof(src), err))
+ return FALSE;
+
+ while (opt != BT_IO_OPT_INVALID) {
+ switch (opt) {
+ case BT_IO_OPT_SOURCE:
+ ba2str(&src.rc_bdaddr, va_arg(args, char *));
+ break;
+ case BT_IO_OPT_DEST:
+ ba2str(&dst.rc_bdaddr, va_arg(args, char *));
+ break;
+ case BT_IO_OPT_CHANNEL:
+ *(va_arg(args, uint8_t *)) = src.rc_channel ?
+ src.rc_channel : dst.rc_channel;
+ break;
+ default:
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown option %d", opt);
+ return FALSE;
+ }
+
+ opt = va_arg(args, int);
+ }
+
+ return TRUE;
+}
+
+static gboolean get_valist(GIOChannel *io, BtIOType type, GError **err,
+ BtIOOption opt1, va_list args)
+{
+ int sock = g_io_channel_unix_get_fd(io);
+
+ if (type != BT_IO_RFCOMM) {
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown BtIO type %d", type);
+ return FALSE;
+ }
+
+ return rfcomm_get(sock, err, opt1, args);
+}
+
+gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data,
+ GDestroyNotify destroy, GError **err)
+{
+ int sock;
+ char c;
+ struct pollfd pfd;
+
+ sock = g_io_channel_unix_get_fd(io);
+
+ memset(&pfd, 0, sizeof(pfd));
+ pfd.fd = sock;
+ pfd.events = POLLOUT;
+
+ if (poll(&pfd, 1, 0) < 0) {
+ ERROR_FAILED(err, "poll", errno);
+ return FALSE;
+ }
+
+ if (!(pfd.revents & POLLOUT)) {
+ int ret;
+ ret = read(sock, &c, 1);
+ }
+
+ accept_add(io, connect, user_data, destroy);
+
+ return TRUE;
+}
+
+gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
+ BtIOOption opt1, ...)
+{
+ va_list args;
+ gboolean ret;
+
+ va_start(args, opt1);
+ ret = get_valist(io, type, err, opt1, args);
+ va_end(args);
+
+ return ret;
+}
+
+static GIOChannel *create_io(BtIOType type, gboolean server,
+ struct set_opts *opts, GError **err)
+{
+ int sock;
+ GIOChannel *io;
+
+ if (type != BT_IO_RFCOMM)
+ return NULL;
+
+ sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+ if (sock < 0) {
+ ERROR_FAILED(err, "socket(STREAM, RFCOMM)", errno);
+ return NULL;
+ }
+
+ if (rfcomm_bind(sock, &opts->src,
+ server ? opts->channel : 0) < 0) {
+ ERROR_FAILED(err, "rfcomm_bind", errno);
+ return NULL;
+ }
+
+ if (!rfcomm_set(sock, opts->sec_level, opts->master, err))
+ return NULL;
+
+ io = g_io_channel_unix_new(sock);
+
+ g_io_channel_set_close_on_unref(io, TRUE);
+ g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL);
+
+ return io;
+}
+
+GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
+ BtIOConfirm confirm, gpointer user_data,
+ GDestroyNotify destroy, GError **err,
+ BtIOOption opt1, ...)
+{
+ GIOChannel *io;
+ va_list args;
+ struct set_opts opts;
+ int sock;
+ gboolean ret;
+
+ va_start(args, opt1);
+ ret = parse_set_opts(&opts, err, opt1, args);
+ va_end(args);
+
+ if (ret == FALSE)
+ return NULL;
+
+ io = create_io(type, TRUE, &opts, err);
+ if (io == NULL)
+ return NULL;
+
+ sock = g_io_channel_unix_get_fd(io);
+
+ if (confirm)
+ setsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP, &opts.defer,
+ sizeof(opts.defer));
+
+ if (listen(sock, 5) < 0) {
+ ERROR_FAILED(err, "listen", errno);
+ g_io_channel_unref(io);
+ return NULL;
+ }
+
+ server_add(io, connect, confirm, user_data, destroy);
+
+ return io;
+}
+
+GQuark bt_io_error_quark(void)
+{
+ return g_quark_from_static_string("bt-io-error-quark");
+}
diff --git a/plugins/btio.h b/plugins/btio.h
new file mode 100644
index 0000000..78d5961
--- /dev/null
+++ b/plugins/btio.h
@@ -0,0 +1,118 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2009 Marcel Holtmann <[email protected]>
+ * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2010 Intel Corporation. All rights reserved.
+ *
+ *
+ * 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
+ *
+ */
+
+#include <glib.h>
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <endian.h>
+#include <byteswap.h>
+
+#ifndef AF_BLUETOOTH
+#define AF_BLUETOOTH 31
+#define PF_BLUETOOTH AF_BLUETOOTH
+#endif
+
+#define BTPROTO_RFCOMM 3
+#define SOL_RFCOMM 18
+#define SOL_BLUETOOTH 274
+
+struct bt_security {
+ uint8_t level;
+};
+#define BT_SECURITY_SDP 0
+#define BT_SECURITY_LOW 1
+#define BT_SECURITY_MEDIUM 2
+#define BT_SECURITY_HIGH 3
+#define BT_SECURITY 4
+
+#define BT_DEFER_SETUP 7
+
+/* BD Address */
+typedef struct {
+ uint8_t b[6];
+} __attribute__((packed)) bdaddr_t;
+
+#define RFCOMM_LM 0x03
+#define RFCOMM_LM_AUTH 0x0002
+#define RFCOMM_LM_ENCRYPT 0x0004
+#define RFCOMM_LM_TRUSTED 0x0008
+#define RFCOMM_LM_RELIABLE 0x0010
+#define RFCOMM_LM_SECURE 0x0020
+
+#include <sys/socket.h>
+
+/* RFCOMM socket address */
+struct sockaddr_rc {
+ sa_family_t rc_family;
+ bdaddr_t rc_bdaddr;
+ uint8_t rc_channel;
+};
+
+typedef enum {
+ BT_IO_ERROR_DISCONNECTED,
+ BT_IO_ERROR_CONNECT_FAILED,
+ BT_IO_ERROR_FAILED,
+ BT_IO_ERROR_INVALID_ARGS,
+} BtIOError;
+
+#define BT_IO_ERROR bt_io_error_quark()
+
+GQuark bt_io_error_quark(void);
+
+typedef enum {
+ BT_IO_RFCOMM,
+} BtIOType;
+
+typedef enum {
+ BT_IO_OPT_INVALID = 0,
+ BT_IO_OPT_SOURCE,
+ BT_IO_OPT_DEST,
+ BT_IO_OPT_SEC_LEVEL,
+ BT_IO_OPT_CHANNEL,
+} BtIOOption;
+
+typedef enum {
+ BT_IO_SEC_SDP = 0,
+ BT_IO_SEC_LOW,
+ BT_IO_SEC_MEDIUM,
+ BT_IO_SEC_HIGH,
+} BtIOSecLevel;
+
+typedef void (*BtIOConfirm)(GIOChannel *io, gpointer user_data);
+
+typedef void (*BtIOConnect)(GIOChannel *io, GError *err, gpointer user_data);
+
+gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data,
+ GDestroyNotify destroy, GError **err);
+
+gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
+ BtIOOption opt1, ...);
+
+GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
+ BtIOConfirm confirm, gpointer user_data,
+ GDestroyNotify destroy, GError **err,
+ BtIOOption opt1, ...);
--
1.7.0.4


2010-07-29 07:18:18

by Zhenhua Zhang

[permalink] [raw]
Subject: [PATCH 3/6] bluetooth: Add bluetooth server support for DUN

It watches Bluetooth adapter property changes and addes DUN record to
listen DUN client connection request.
---
plugins/bluetooth.c | 379 +++++++++++++++++++++++++++++++++++++++++++++++++++
plugins/bluetooth.h | 14 ++
2 files changed, 393 insertions(+), 0 deletions(-)

diff --git a/plugins/bluetooth.c b/plugins/bluetooth.c
index 10cc49d..5890161 100644
--- a/plugins/bluetooth.c
+++ b/plugins/bluetooth.c
@@ -35,12 +35,71 @@
#include <ofono/dbus.h>

#include "bluetooth.h"
+#include "btio.h"

static DBusConnection *connection;
static GHashTable *uuid_hash = NULL;
static GHashTable *adapter_address_hash = NULL;
+static GSList *server_list = NULL;
static gint ref_count;

+static const gchar *dun_record = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?> \
+<record> \
+ <attribute id=\"0x0001\"> \
+ <sequence> \
+ <uuid value=\"0x1103\"/> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id=\"0x0004\"> \
+ <sequence> \
+ <sequence> \
+ <uuid value=\"0x0100\"/> \
+ </sequence> \
+ <sequence> \
+ <uuid value=\"0x0003\"/> \
+ <uint8 value=\"%u\" name=\"channel\"/> \
+ </sequence> \
+ <sequence> \
+ <uuid value=\"0x0008\"/> \
+ </sequence> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id=\"0x0009\"> \
+ <sequence> \
+ <sequence> \
+ <uuid value=\"0x1103\"/> \
+ <uint16 value=\"0x0100\" name=\"version\"/> \
+ </sequence> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id=\"0x0100\"> \
+ <text value=\"%s\" name=\"name\"/> \
+ </attribute> \
+</record>";
+
+#define TIMEOUT (60*1000) /* Timeout for user response (miliseconds) */
+
+struct client {
+ GIOChannel *io;
+ guint watch;
+};
+
+struct server {
+ guint16 service;
+ gchar *name;
+ guint8 channel;
+ GIOChannel *io;
+ gchar *adapter;
+ guint handle;
+ ConnectFunc connect_cb;
+ gpointer user_data;
+
+ struct client client;
+};
+
void bluetooth_create_path(const char *dev_addr, const char *adapter_addr,
char *buf, int size)
{
@@ -370,6 +429,253 @@ static gboolean property_changed(DBusConnection *connection, DBusMessage *msg,
return TRUE;
}

+static void disconnect(struct server *server)
+{
+ struct client *client = &server->client;
+
+ if (!client->io)
+ return;
+
+ g_io_channel_unref(client->io);
+ client->io = NULL;
+
+ if (client->watch > 0) {
+ g_source_remove(client->watch);
+ client->watch = 0;
+ }
+
+ return;
+}
+
+static void server_stop(gpointer data, gpointer user_data)
+{
+ struct server *server = data;
+
+ disconnect(server);
+
+ if (server->handle) {
+ DBusMessage *msg;
+
+ msg = dbus_message_new_method_call(BLUEZ_SERVICE,
+ server->adapter,
+ BLUEZ_SERVICE_INTERFACE,
+ "RemoveRecord");
+ dbus_message_append_args(msg, DBUS_TYPE_UINT32, &server->handle,
+ DBUS_TYPE_INVALID);
+ g_dbus_send_message(connection, msg);
+
+ server->handle = 0;
+ }
+
+ if (server->io) {
+ g_io_channel_shutdown(server->io, TRUE, NULL);
+ g_io_channel_unref(server->io);
+ server->io = NULL;
+ }
+
+ g_free(server->adapter);
+ server->adapter = NULL;
+}
+
+static gboolean client_event(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+ struct server *server = data;
+
+ disconnect(server);
+
+ return FALSE;
+}
+
+static void cancel_authorization(struct server *server)
+{
+ DBusMessage *msg;
+
+ if (!server->adapter)
+ return;
+
+ msg = dbus_message_new_method_call(BLUEZ_SERVICE, server->adapter,
+ BLUEZ_SERVICE_INTERFACE,
+ "CancelAuthorization");
+
+ g_dbus_send_message(connection, msg);
+}
+
+static void auth_cb(DBusPendingCall *call, gpointer user_data)
+{
+ struct server *server = user_data;
+ struct client *client = &server->client;
+ GIOChannel *io = client->io;
+ DBusMessage *reply = dbus_pending_call_steal_reply(call);
+ DBusError derr;
+ GError *err = NULL;
+
+ dbus_error_init(&derr);
+
+ if (dbus_set_error_from_message(&derr, reply)) {
+ ofono_error("RequestAuthorization error: %s, %s",
+ derr.name, derr.message);
+
+ if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY))
+ cancel_authorization(server);
+
+ dbus_error_free(&derr);
+ goto failed;
+ }
+
+ ofono_info("RequestAuthorization succeeded");
+
+ if (!bt_io_accept(io, server->connect_cb, server->user_data,
+ NULL, &err)) {
+ ofono_error("%s", err->message);
+ g_error_free(err);
+ goto failed;
+ }
+
+ g_source_remove(client->watch);
+
+ client->watch = g_io_add_watch(client->io,
+ G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ client_event, server);
+
+ dbus_message_unref(reply);
+
+ return;
+
+failed:
+ dbus_message_unref(reply);
+ disconnect(server);
+}
+
+static gboolean auth_watch(GIOChannel *io, GIOCondition cond,
+ gpointer user_data)
+{
+ struct server *server = user_data;
+
+ cancel_authorization(server);
+ disconnect(server);
+
+ return FALSE;
+}
+
+static void confirm_event(GIOChannel *io, gpointer user_data)
+{
+ struct server *server = user_data;
+ struct client *client = &server->client;
+ GError *err = NULL;
+ char address[18];
+ const char *addr;
+ guint8 channel;
+ int ret;
+
+ if (client->io) {
+ ofono_error("Rejecting connection since one client already \
+ connected");
+ return;
+ }
+
+ bt_io_get(io, BT_IO_RFCOMM, &err, BT_IO_OPT_DEST, address,
+ BT_IO_OPT_CHANNEL, &channel,
+ BT_IO_OPT_INVALID);
+ if (err) {
+ ofono_error("%s", err->message);
+ g_error_free(err);
+ return;
+ }
+
+ ofono_info("New connection from: %s, channel %u", address, channel);
+
+ addr = address;
+ ret = bluetooth_send_with_reply(server->adapter,
+ BLUEZ_SERVICE_INTERFACE,
+ "RequestAuthorization",
+ auth_cb, server, NULL, TIMEOUT,
+ DBUS_TYPE_STRING, &addr,
+ DBUS_TYPE_UINT32, &server->handle,
+ DBUS_TYPE_INVALID);
+ if (ret < 0) {
+ ofono_error("Request Bluetooth authorization failed");
+ return;
+ }
+
+ ofono_info("RequestAuthorization(%s, 0x%x)", address, server->handle);
+
+ client->io = g_io_channel_ref(io);
+ client->watch = g_io_add_watch(io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ auth_watch, server);
+
+ return;
+}
+
+static void add_record_cb(DBusPendingCall *call, gpointer user_data)
+{
+ struct server *server = user_data;
+ DBusMessage *reply = dbus_pending_call_steal_reply(call);
+ DBusError derr;
+ guint32 handle;
+
+ dbus_error_init(&derr);
+
+ if (dbus_set_error_from_message(&derr, reply)) {
+ ofono_error("Replied with an error: %s, %s",
+ derr.name, derr.message);
+ dbus_error_free(&derr);
+ server_stop(server, NULL);
+ goto done;
+ }
+
+ dbus_message_get_args(reply, NULL, DBUS_TYPE_UINT32, &handle,
+ DBUS_TYPE_INVALID);
+ server->handle = handle;
+
+ ofono_info("Registered: %s, handle: 0x%x", server->name, handle);
+
+done:
+ dbus_message_unref(reply);
+}
+
+static void server_start(gpointer data, gpointer user_data)
+{
+ struct server *server = data;
+ gchar *path = user_data;
+ GError *err = NULL;
+ gchar *xml;
+
+ if (server->handle != 0)
+ return;
+
+ if (server->service != DUN_GW)
+ goto failed;
+
+ server->io = bt_io_listen(BT_IO_RFCOMM, NULL, confirm_event,
+ server, NULL, &err,
+ BT_IO_OPT_CHANNEL, server->channel,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+ BT_IO_OPT_INVALID);
+ if (!server->io) {
+ ofono_error("Bluetooth %s register failed: %s",
+ server->name, err->message);
+ g_error_free(err);
+ goto failed;
+ }
+
+ server->adapter = g_strdup(path);
+
+ xml = g_markup_printf_escaped(dun_record, server->channel,
+ server->name);
+
+ bluetooth_send_with_reply(path, BLUEZ_SERVICE_INTERFACE, "AddRecord",
+ add_record_cb, server, NULL, -1,
+ DBUS_TYPE_STRING, &xml,
+ DBUS_TYPE_INVALID);
+
+ g_free(xml);
+
+ return;
+
+failed:
+ server_stop(server, NULL);
+}
+
static void adapter_properties_cb(DBusPendingCall *call, gpointer user_data)
{
const char *path = user_data;
@@ -394,6 +700,9 @@ static void adapter_properties_cb(DBusPendingCall *call, gpointer user_data)
g_hash_table_insert(adapter_address_hash,
g_strdup(path), g_strdup(addr));

+ if (server_list)
+ g_slist_foreach(server_list, server_start, (gpointer)path);
+
for (l = device_list; l; l = l->next) {
const char *device = l->data;

@@ -428,11 +737,26 @@ static gboolean adapter_removed(DBusConnection *connection,
DBusMessage *message, void *user_data)
{
const char *path;
+ GSList *l;

if (dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID) == TRUE)
g_hash_table_remove(adapter_address_hash, path);

+ for (l = server_list; l; l = l->next) {
+ struct server *server = l->data;
+
+ if (!server->adapter)
+ continue;
+
+ if (!g_str_equal(path, server->adapter))
+ continue;
+
+ /* Don't remove handle if the adapter has been removed */
+ server->handle = 0;
+ server_stop(server, NULL);
+ }
+
return TRUE;
}

@@ -564,6 +888,7 @@ static int bluetooth_ref()
static void bluetooth_unref()
{
gboolean is_zero;
+ GSList *l;

is_zero = g_atomic_int_dec_and_test(&ref_count);

@@ -580,6 +905,20 @@ static void bluetooth_unref()

if (adapter_address_hash)
g_hash_table_destroy(adapter_address_hash);
+
+ if (server_list == NULL)
+ return;
+
+ for (l = server_list; l; l = l->next) {
+ struct server *server = l->data;
+
+ server_stop(server, NULL);
+ g_free(server->name);
+ g_free(server);
+ }
+
+ g_slist_free(server_list);
+ server_list = NULL;
}

int bluetooth_register_uuid(const char *uuid, struct bluetooth_profile *profile)
@@ -604,5 +943,45 @@ void bluetooth_unregister_uuid(const char *uuid)
bluetooth_unref();
}

+struct server *bluetooth_register_server(guint16 service, char *name,
+ guint8 channel, ConnectFunc cb,
+ gpointer user_data)
+{
+ struct server *server;
+ int err = bluetooth_ref();
+
+ if (err != 0)
+ return NULL;
+
+ server = g_try_new0(struct server, 1);
+ if (!server)
+ return NULL;
+
+ server->service = service;
+ server->name = g_strdup(name);
+ server->channel = channel;
+ server->connect_cb = cb;
+ server->user_data = user_data;
+
+ server_list = g_slist_prepend(server_list, server);
+
+ bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "GetProperties",
+ manager_properties_cb, NULL, NULL, -1,
+ DBUS_TYPE_INVALID);
+
+ return server;
+}
+
+void bluetooth_unregister_server(struct server *server)
+{
+ server_list = g_slist_remove(server_list, server);
+
+ server_stop(server, NULL);
+ g_free(server->name);
+ g_free(server);
+
+ bluetooth_unref();
+}
+
OFONO_PLUGIN_DEFINE(bluetooth, "Bluetooth Utils Plugins", VERSION,
OFONO_PLUGIN_PRIORITY_DEFAULT, NULL, NULL)
diff --git a/plugins/bluetooth.h b/plugins/bluetooth.h
index fb0d841..ab42c99 100644
--- a/plugins/bluetooth.h
+++ b/plugins/bluetooth.h
@@ -2,6 +2,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2010 Gustavo F. Padovan <[email protected]>
+ * Copyright (C) 2010 Intel Corporation. All rights reserved.
*
* 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
@@ -22,12 +23,16 @@
#define BLUEZ_MANAGER_INTERFACE BLUEZ_SERVICE ".Manager"
#define BLUEZ_ADAPTER_INTERFACE BLUEZ_SERVICE ".Adapter"
#define BLUEZ_DEVICE_INTERFACE BLUEZ_SERVICE ".Device"
+#define BLUEZ_SERVICE_INTERFACE BLUEZ_SERVICE ".Service"

#define HFP_AG_UUID "0000111F-0000-1000-8000-00805F9B34FB"

/* Profiles bitfield */
#define HFP_AG 0x01

+/* Service bitfield */
+#define DUN_GW 0x01
+
struct bluetooth_profile {
const char *name;
int (*create)(const char *device, const char *dev_addr,
@@ -36,10 +41,19 @@ struct bluetooth_profile {
void (*set_alias)(const char *device, const char *);
};

+typedef void (*ConnectFunc)(GIOChannel *io, GError *err, gpointer user_data);
+
+struct server;
+
int bluetooth_register_uuid(const char *uuid,
struct bluetooth_profile *profile);
void bluetooth_unregister_uuid(const char *uuid);

+struct server *bluetooth_register_server(guint16 service, char *name,
+ guint8 channel, ConnectFunc cb,
+ gpointer user_data);
+void bluetooth_unregister_server(struct server *server);
+
void bluetooth_create_path(const char *dev_addr, const char *adapter_addr,
char *buf, int size);

--
1.7.0.4


2010-07-29 07:18:16

by Zhenhua Zhang

[permalink] [raw]
Subject: [PATCH 1/6] bluetooth: Add reference count for bluetooth utils

Add bluetooth_ref()/bluetooth_unref() to support reference count in
bluetooth utils.
---
plugins/bluetooth.c | 62 +++++++++++++++++++++++++++++++++++++--------------
1 files changed, 45 insertions(+), 17 deletions(-)

diff --git a/plugins/bluetooth.c b/plugins/bluetooth.c
index 5a85eaa..10cc49d 100644
--- a/plugins/bluetooth.c
+++ b/plugins/bluetooth.c
@@ -39,6 +39,7 @@
static DBusConnection *connection;
static GHashTable *uuid_hash = NULL;
static GHashTable *adapter_address_hash = NULL;
+static gint ref_count;

void bluetooth_create_path(const char *dev_addr, const char *adapter_addr,
char *buf, int size)
@@ -503,13 +504,10 @@ static guint adapter_added_watch;
static guint adapter_removed_watch;
static guint property_watch;

-int bluetooth_register_uuid(const char *uuid, struct bluetooth_profile *profile)
+static int bluetooth_init()
{
int err;

- if (uuid_hash)
- goto done;
-
connection = ofono_dbus_get_connection();

bluetooth_watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE,
@@ -542,13 +540,6 @@ int bluetooth_register_uuid(const char *uuid, struct bluetooth_profile *profile)
adapter_address_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, g_free);

-done:
- g_hash_table_insert(uuid_hash, g_strdup(uuid), profile);
-
- bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "GetProperties",
- manager_properties_cb, NULL, NULL, -1,
- DBUS_TYPE_INVALID);
-
return 0;

remove:
@@ -556,14 +547,27 @@ remove:
g_dbus_remove_watch(connection, adapter_added_watch);
g_dbus_remove_watch(connection, adapter_removed_watch);
g_dbus_remove_watch(connection, property_watch);
+
return err;
}

-void bluetooth_unregister_uuid(const char *uuid)
+static int bluetooth_ref()
{
- g_hash_table_remove(uuid_hash, uuid);
+ g_atomic_int_inc(&ref_count);
+
+ if (ref_count > 1)
+ return 0;
+
+ return bluetooth_init();
+}
+
+static void bluetooth_unref()
+{
+ gboolean is_zero;
+
+ is_zero = g_atomic_int_dec_and_test(&ref_count);

- if (g_hash_table_size(uuid_hash))
+ if (is_zero == FALSE)
return;

g_dbus_remove_watch(connection, bluetooth_watch);
@@ -571,9 +575,33 @@ void bluetooth_unregister_uuid(const char *uuid)
g_dbus_remove_watch(connection, adapter_removed_watch);
g_dbus_remove_watch(connection, property_watch);

- g_hash_table_destroy(uuid_hash);
- g_hash_table_destroy(adapter_address_hash);
- uuid_hash = NULL;
+ if (uuid_hash)
+ g_hash_table_destroy(uuid_hash);
+
+ if (adapter_address_hash)
+ g_hash_table_destroy(adapter_address_hash);
+}
+
+int bluetooth_register_uuid(const char *uuid, struct bluetooth_profile *profile)
+{
+ int err = bluetooth_ref();
+
+ if (err != 0)
+ return err;
+
+ g_hash_table_insert(uuid_hash, g_strdup(uuid), profile);
+
+ bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "GetProperties",
+ manager_properties_cb, NULL, NULL, -1,
+ DBUS_TYPE_INVALID);
+ return 0;
+}
+
+void bluetooth_unregister_uuid(const char *uuid)
+{
+ g_hash_table_remove(uuid_hash, uuid);
+
+ bluetooth_unref();
}

OFONO_PLUGIN_DEFINE(bluetooth, "Bluetooth Utils Plugins", VERSION,
--
1.7.0.4


2010-08-02 00:20:56

by Zhenhua Zhang

[permalink] [raw]
Subject: RE: [PATCH 1/6] bluetooth: Add reference count for bluetooth utils

Hi Padovan,

Gustavo F. Padovan wrote:
> Hi Zhenhua,
>
> * Zhenhua Zhang <[email protected]> [2010-07-29 15:18:16 +0800]:
>
>> Add bluetooth_ref()/bluetooth_unref() to support reference count in
>> bluetooth utils.
>> ---
>> plugins/bluetooth.c | 62
>> +++++++++++++++++++++++++++++++++++++-------------- 1 files
>> changed, 45 insertions(+), 17 deletions(-)
>>
>> diff --git a/plugins/bluetooth.c b/plugins/bluetooth.c
>> index 5a85eaa..10cc49d 100644
>> --- a/plugins/bluetooth.c
>> +++ b/plugins/bluetooth.c
>> @@ -39,6 +39,7 @@
>> static DBusConnection *connection;
>> static GHashTable *uuid_hash = NULL;
>> static GHashTable *adapter_address_hash = NULL;
>> +static gint ref_count;
>>
>> void bluetooth_create_path(const char *dev_addr, const char
>> *adapter_addr, char *buf, int size) @@ -503,13 +504,10 @@
>> static guint adapter_added_watch; static guint
>> adapter_removed_watch; static guint property_watch;
>>
>> -int bluetooth_register_uuid(const char *uuid, struct
>> bluetooth_profile *profile) +static int bluetooth_init() {
>> int err;
>>
>> - if (uuid_hash)
>> - goto done;
>> -
>> connection = ofono_dbus_get_connection();
>>
>> bluetooth_watch = g_dbus_add_service_watch(connection,
>> BLUEZ_SERVICE, @@ -542,13 +540,6 @@ int
>> bluetooth_register_uuid(const char *uuid, struct bluetooth_profile
>> *profile) adapter_address_hash = g_hash_table_new_full(g_str_hash,
>> g_str_equal, g_free, g_free);
>>
>> -done:
>> - g_hash_table_insert(uuid_hash, g_strdup(uuid), profile); -
>> - bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE,
>> "GetProperties",
>> - manager_properties_cb, NULL, NULL, -1,
>> - DBUS_TYPE_INVALID);
>> -
>> return 0;
>>
>> remove:
>> @@ -556,14 +547,27 @@ remove:
>> g_dbus_remove_watch(connection, adapter_added_watch);
>> g_dbus_remove_watch(connection, adapter_removed_watch);
>> g_dbus_remove_watch(connection, property_watch);
>> +
>> return err;
>> }
>>
>> -void bluetooth_unregister_uuid(const char *uuid)
>> +static int bluetooth_ref()
>> {
>> - g_hash_table_remove(uuid_hash, uuid);
>> + g_atomic_int_inc(&ref_count);
>> +
>> + if (ref_count > 1)
>> + return 0;
>> +
>> + return bluetooth_init();
>> +}
>> +
>> +static void bluetooth_unref()
>> +{
>> + gboolean is_zero;
>> +
>> + is_zero = g_atomic_int_dec_and_test(&ref_count);
>>
>> - if (g_hash_table_size(uuid_hash))
>> + if (is_zero == FALSE)
>> return;
>
> We can remove the is_zero variable, and test
> g_atomic_int_dec_and_test() directly. What do you think?

Actually I think it's ok to keep this variable. We also have it in gatchat and gatppp.

Thanks,
Zhenhua

>>
>> g_dbus_remove_watch(connection, bluetooth_watch);
>> @@ -571,9 +575,33 @@ void bluetooth_unregister_uuid(const char *uuid)
>> g_dbus_remove_watch(connection, adapter_removed_watch);
>> g_dbus_remove_watch(connection, property_watch);
>>
>> - g_hash_table_destroy(uuid_hash);
>> - g_hash_table_destroy(adapter_address_hash);
>> - uuid_hash = NULL;
>> + if (uuid_hash)
>> + g_hash_table_destroy(uuid_hash);
>> +
>> + if (adapter_address_hash)
>> + g_hash_table_destroy(adapter_address_hash);
>> +}
>> +
>> +int bluetooth_register_uuid(const char *uuid, struct
>> bluetooth_profile *profile) +{ + int err = bluetooth_ref();
>> +
>> + if (err != 0)
>> + return err;
>> +
>> + g_hash_table_insert(uuid_hash, g_strdup(uuid), profile); +
>> + bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE,
>> "GetProperties", + manager_properties_cb, NULL, NULL, -1,
>> + DBUS_TYPE_INVALID);
>> + return 0;
>> +}
>> +
>> +void bluetooth_unregister_uuid(const char *uuid)
>> +{
>> + g_hash_table_remove(uuid_hash, uuid);
>> +
>> + bluetooth_unref();
>> }
>>
>> OFONO_PLUGIN_DEFINE(bluetooth, "Bluetooth Utils Plugins", VERSION,
>> --
>> 1.7.0.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe
>> linux-bluetooth" in
>> the body of a message to [email protected]
>> More majordomo info at http://vger.kernel.org/majordomo-info.html



Regards,
Zhenhua