[PATCH] bluetooth: Add bluetooth server support (based on Zhenhua code)

2011-01-18 Thread Frédéric Danis
It watches Bluetooth adapter property changes and adds SDP record to
listen client connection request (refactored to support both DUN and
HFP GW servers).
Add bluetooth_ref()/bluetooth_unref() to support reference count in
bluetooth utils.
---
 Makefile.am |2 +-
 plugins/bluetooth.c |  396 --
 plugins/bluetooth.h |   11 ++
 3 files changed, 392 insertions(+), 17 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index da59be7..fb3f750 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -312,7 +312,7 @@ builtin_sources += plugins/nokiacdma.c
 
 if BLUETOOTH
 builtin_modules += bluetooth
-builtin_sources += plugins/bluetooth.c plugins/bluetooth.h
+builtin_sources += $(btio_sources) plugins/bluetooth.c plugins/bluetooth.h
 
 builtin_modules += hfp
 builtin_sources += plugins/hfp.c plugins/bluetooth.h
diff --git a/plugins/bluetooth.c b/plugins/bluetooth.c
index 602c6da..fd6f541 100644
--- a/plugins/bluetooth.c
+++ b/plugins/bluetooth.c
@@ -35,11 +35,34 @@
 
 #include ofono/dbus.h
 
+#include btio.h
 #include bluetooth.h
 
 static DBusConnection *connection;
 static GHashTable *uuid_hash = NULL;
 static GHashTable *adapter_address_hash = NULL;
+static GSList *server_list = NULL;
+static gint ref_count;
+
+#define TIMEOUT (60*1000) /* Timeout for user response (miliseconds) */
+
+struct client {
+   GIOChannel  *io;
+   guint   watch;
+};
+
+struct server {
+   gchar   *name;
+   guint8  channel;
+   gchar   *sdp_record;
+   GIOChannel  *io;
+   gchar   *adapter;
+   guint   handle;
+   ConnectFunc connect_cb;
+   gpointeruser_data;
+
+   struct client   client;
+};
 
 void bluetooth_create_path(const char *dev_addr, const char *adapter_addr,
char *buf, int size)
@@ -370,6 +393,246 @@ 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;
+   }
+
+   

Re: [PATCH] bluetooth: Add bluetooth server support (based on Zhenhua code)

2011-01-18 Thread Marcel Holtmann
Hi Fred,

 Add bluetooth_ref()/bluetooth_unref() to support reference count in
 bluetooth utils.

didn't you had this as separate patch already? I think we should keep
that as a separate patch.

 ---
  Makefile.am |2 +-
  plugins/bluetooth.c |  396 --
  plugins/bluetooth.h |   11 ++
  3 files changed, 392 insertions(+), 17 deletions(-)
 
 diff --git a/Makefile.am b/Makefile.am
 index da59be7..fb3f750 100644
 --- a/Makefile.am
 +++ b/Makefile.am
 @@ -312,7 +312,7 @@ builtin_sources += plugins/nokiacdma.c
  
  if BLUETOOTH
  builtin_modules += bluetooth
 -builtin_sources += plugins/bluetooth.c plugins/bluetooth.h
 +builtin_sources += $(btio_sources) plugins/bluetooth.c plugins/bluetooth.h
  
  builtin_modules += hfp
  builtin_sources += plugins/hfp.c plugins/bluetooth.h

Please do it like this:

builtin_sources += $(btio_sources)
builtin_cflags += @BLUEZ_CFLAGS@
builtin_libadd += @BLUEZ_LIBS@

 +struct client {
 + GIOChannel  *io;
 + guint   watch;
 +};

Why do you need both. Normally only the watch is enough?

 +struct server {
 + gchar   *name;

Don't bother with gchar. Just use char.

 + guint8  channel;
 + gchar   *sdp_record;
 + GIOChannel  *io;
 + gchar   *adapter;
 + guint   handle;
 + ConnectFunc connect_cb;
 + gpointeruser_data;
 +
 + struct client   client;

Is it not simpler to just fold client_watch directly into it?

 +};
  
  void bluetooth_create_path(const char *dev_addr, const char *adapter_addr,
   char *buf, int size)
 @@ -370,6 +393,246 @@ 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;

Don't bother with return for functions returning void.

 +}
 +
 +static void server_stop(gpointer data, gpointer user_data)
 +{
 + struct server *server = data;
 +
 + disconnect(server);
 +
 + if (server-handle) {

We do prefer service-handle  0 for these cases.

 + 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) {

And here please do server-io != NULL.

 + 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);

Check that msg allocation succeeded before calling send.

 +
 + 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 =