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;
> +     gpointer        user_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 = g_io_add_watch(client->io,
> +                                     G_IO_HUP | G_IO_ERR | G_IO_NVAL,
> +                                     client_event, server);
> +
> +     dbus_message_unref(reply);

You could move dbus_message_unref higher up here since we are not
referencing anything in that message anymore.

Only if you access parameters or error values, you need to keep it
around.

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

Check with io != NULL.

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

You know that add_watch takes a GIOChannel reference count already. Why
take another one?

> +
> +     return;

No return for void functions.

> +}
> +
> +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;
> +
> +     if (server->io != NULL)
> +             return;
> +
> +     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 == NULL) {
> +             ofono_error("Bluetooth %s register failed: %s",
> +                                     server->name, err->message);
> +             g_error_free(err);
> +             goto failed;
> +     }
> +
> +     server->adapter = g_strdup(path);
> +
> +     if (server->sdp_record != NULL)
> +             bluetooth_send_with_reply(path, BLUEZ_SERVICE_INTERFACE,
> +                                     "AddRecord", add_record_cb,
> +                                     server, NULL, -1,
> +                                     DBUS_TYPE_STRING, &server->sdp_record,
> +                                     DBUS_TYPE_INVALID);
> +
> +     return;
> +
> +failed:
> +     server_stop(server, NULL);

Since this is only used in one error branch. You could call it directly
and avoid this label.

> +}
> +
>  static void adapter_properties_cb(DBusPendingCall *call, gpointer user_data)
>  {
>       const char *path = user_data;
> @@ -394,6 +657,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 +694,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;
>  }
>  
> @@ -504,12 +785,14 @@ 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_ref()

Empty parameter list need to be declared as (void).

>  {
>       int err;
>  
> -     if (uuid_hash)
> -             goto done;
> +     g_atomic_int_inc(&ref_count);
> +
> +     if (ref_count > 1)
> +             return 0;
>  
>       connection = ofono_dbus_get_connection();
>  
> @@ -543,13 +826,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:
> @@ -557,14 +833,18 @@ 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 void bluetooth_unref()

Use (void) here as well.

>  {
> -     g_hash_table_remove(uuid_hash, uuid);
> +     gboolean is_zero;
> +     GSList *l;
> +
> +     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);
> @@ -572,9 +852,93 @@ 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);
> +             uuid_hash = NULL;
> +     }
> +
> +     if (adapter_address_hash) {
> +             g_hash_table_destroy(adapter_address_hash);
> +             adapter_address_hash = NULL;
> +     }
> +
> +     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)
> +{
> +     int err = bluetooth_ref();;

Double semicolon?

And err with ref. This doesn't sound right. Please send the ref/unref
patch first for initial review.

> +
> +     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();
> +}
> +
> +struct server *bluetooth_register_rfcomm_server(char *name, guint8 channel,
> +                                     const char *sdp_record, 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->name = g_strdup(name);
> +     server->channel = channel;
> +     if (sdp_record != NULL)
> +             server->sdp_record = g_strdup(sdp_record);
> +     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_rfcomm_server(struct server *server)
> +{
> +     server_list = g_slist_remove(server_list, server);
> +     server_stop(server, NULL);
> +     g_free(server->name);
> +     g_free(server->sdp_record);
> +     g_free(server);
> +
> +     bluetooth_unref();
>  }
>  
>  OFONO_PLUGIN_DEFINE(bluetooth, "Bluetooth Utils Plugins", VERSION,
> diff --git a/plugins/bluetooth.h b/plugins/bluetooth.h
> index 42b0d13..c0df13f 100644
> --- a/plugins/bluetooth.h
> +++ b/plugins/bluetooth.h
> @@ -3,6 +3,7 @@
>   *  oFono - Open Source Telephony
>   *
>   *  Copyright (C) 2010 Gustavo F. Padovan <gust...@padovan.org>
> + *  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
> @@ -23,6 +24,7 @@
>  #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 DBUS_TIMEOUT 15
>  
> @@ -39,10 +41,19 @@ struct bluetooth_profile {
>       void (*set_alias)(const char *device, const char *);
>  };
>  
> +struct server;
> +
> +typedef void (*ConnectFunc)(GIOChannel *io, GError *err, gpointer user_data);
> +
>  int bluetooth_register_uuid(const char *uuid,
>                               struct bluetooth_profile *profile);
>  void bluetooth_unregister_uuid(const char *uuid);
>  
> +struct server *bluetooth_register_rfcomm_server(char *name, guint8 channel,
> +                                     const char *sdp_record, ConnectFunc cb,
> +                                     gpointer user_data);
> +void bluetooth_unregister_rfcomm_server(struct server *server);
> +
>  void bluetooth_create_path(const char *dev_addr, const char *adapter_addr,
>                                                       char *buf, int size);
>  

This was just an initial review, we really need to split this one in
more digestible pieces.

Regards

Marcel


_______________________________________________
ofono mailing list
ofono@ofono.org
http://lists.ofono.org/listinfo/ofono

Reply via email to