2012-10-19 15:39:17

by Mikel Astiz

[permalink] [raw]
Subject: [RFC v0 00/15] WIP: btd_profile connect and disconnect

From: Mikel Astiz <[email protected]>

This RFC is work-in-progress: the patches are not intended to be applied, but instead submitted as a base for discussion.

The patchset proposes three inter-related changes:

(1) Splitting of individual btd_profile instantes per role. Some profiles do already have such separation (see HFP-Gateway) but some others have all roles merged into one (see A2DP or PAN).

(2) Exposure of internal APIs to connect/disconnect devices, as proposed by the btd_profile approach (.connect and .disconnect). The goal would be not only to support Device.Connect, but also to be able to implement connection-handling plugins such as the IVI case.

(3) The exposure of a D-Bus API to connect/disconnect profiles, and report the current state (disconnected, connecting, or connected). The goal here would be to be able to implement Bluetooth-centric UIs, which typically show which profiles have been connected per device. Additionally, this would allow implementing connection-handling policies externally, instead of in a plugin.

Each of this point requires some discussion. For example, in point (2), there are different possible way to expose an internal API to connect/disconnect profiles. The patchset, in fact, proposes different approaches for HID (patch 08/15), where it's btd_profile-aware, or networking (patch 03/15), where the internal API has nothing to do with the btd_profile infrastructure.

The D-Bus API could have several variants as well, one of them being the currently existing one in BlueZ 4.x. This first RFC proposes a completely different one, based on a new D-Bus interface (org.bluez.Profile, see patch 15/15), which is admittedly ugly.

I hope some of this ideas can make sense for BlueZ 5.

Any feedback will be welcome,

Mikel

Mikel Astiz (15):
network: Specify id while registering server
network: Trivial function rename
network: Expose internal connection API
network: Split Network into three btd_profile
network: Add network .connect and .disconnect
audio: Split A2DP into three btd_profile
audio: Trivial function rename
source: Expose internal connection API
source: Add profile .connect and .disconnect
input: Trivial function rename
input: Expose internal disconnection API
input: Add profile .disconnect
profile: Rename org.bluez.Profile->ProfileAgent
profile: Add object to represent device-profile
profile: Add new org.bluez.Profile

Makefile.am | 1 +
audio/a2dp.c | 88 ++++++-------
audio/a2dp.h | 4 +-
audio/device.h | 3 +
audio/manager.c | 185 ++++++++++++++++++++++++---
audio/sink.c | 12 +-
audio/source.c | 158 +++++++++++++----------
audio/source.h | 2 +
doc/device-api.txt | 23 ----
doc/manager-api.txt | 3 +-
doc/profile-api.txt | 59 ++++-----
doc/profileagent-api.txt | 53 ++++++++
profiles/input/device.c | 39 ++++--
profiles/input/device.h | 6 +-
profiles/input/manager.c | 1 +
profiles/network/connection.c | 160 +++++++++++++++--------
profiles/network/connection.h | 8 ++
profiles/network/manager.c | 205 +++++++++++++++++++++++++++---
profiles/network/server.c | 9 +-
profiles/network/server.h | 4 +-
src/bluetooth.conf | 2 +-
src/device-profile.c | 288 ++++++++++++++++++++++++++++++++++++++++++
src/device-profile.h | 43 +++++++
src/device.c | 110 +++++++++++-----
src/manager.c | 2 +-
src/profile.c | 56 ++++----
src/profile.h | 11 +-
test/test-profile | 8 +-
28 files changed, 1191 insertions(+), 352 deletions(-)
create mode 100644 doc/profileagent-api.txt
create mode 100644 src/device-profile.c
create mode 100644 src/device-profile.h

--
1.7.11.7



2012-10-25 17:38:01

by Johan Hedberg

[permalink] [raw]
Subject: Re: [RFC v0 05/15] network: Add network .connect and .disconnect

Hi Mikel,

On Thu, Oct 25, 2012, Mikel Astiz wrote:
> >> > + req = g_new0(struct connect_req, 1);
> >> > + req->device = dev;
> >>
> >> Isn't btd_device_ref() required here?
> >
> > Looks like you're right and I missed this in my initial review. I went
> > ahead and pushed an extra patch to fix this.
>
> I don't think this patch was needed. Actually, the device pointer in
> struct connect_req can be completely removed, since the callback
> already receives such pointer, and the network_peer takes care of the
> device refcounting. Mea culpa for adding this unnecessary field.

Good point. Feel free to send a patch to remove it.

Johan

2012-10-25 15:53:13

by Mikel Astiz

[permalink] [raw]
Subject: Re: [RFC v0 05/15] network: Add network .connect and .disconnect

Hi,

On Thu, Oct 25, 2012 at 12:42 PM, Johan Hedberg <[email protected]> wrote:
> Hi Lizardo,
>
> On Wed, Oct 24, 2012, Anderson Lizardo wrote:
>> Hi Mikel,
>>
>> On Fri, Oct 19, 2012 at 11:39 AM, Mikel Astiz <[email protected]> wrote:
>> > +static void connect_profile_cb(struct btd_device *device, int err,
>> > + const char *pdev, void *data)
>> > +{
>> > + struct connect_req *req = data;
>> > +
>> > + req->cb(req->profile, req->device, err);
>> > +
>> > + g_free(req);
>> > +}
>> > +
>> > +static int connect_profile(struct btd_device *dev, struct btd_profile *profile,
>> > + uint16_t id, btd_profile_cb cb)
>> > +{
>> > + struct connect_req *req;
>> > + int err;
>> > +
>> > + DBG("path %s id %u", device_get_path(dev), id);
>> > +
>> > + req = g_new0(struct connect_req, 1);
>> > + req->device = dev;
>>
>> Isn't btd_device_ref() required here?
>
> Looks like you're right and I missed this in my initial review. I went
> ahead and pushed an extra patch to fix this.

I don't think this patch was needed. Actually, the device pointer in
struct connect_req can be completely removed, since the callback
already receives such pointer, and the network_peer takes care of the
device refcounting. Mea culpa for adding this unnecessary field.

Cheers,
Mikel

2012-10-25 15:49:47

by Mikel Astiz

[permalink] [raw]
Subject: Re: [RFC v0 12/15] input: Add profile .disconnect

Hi Johan,

On Thu, Oct 25, 2012 at 12:39 PM, Johan Hedberg <[email protected]> wrote:
> Hi Mikel,
>
> On Fri, Oct 19, 2012, Mikel Astiz wrote:
>> From: Mikel Astiz <[email protected]>
>>
>> Add the disconnect hook to the btd_profile.
>> ---
>> profiles/input/manager.c | 1 +
>> 1 file changed, 1 insertion(+)
>
> I've applied the patches up until this one with the exception of the
> audio ones which I'll let Luiz to look at and sync up with the work he's
> doing for audio right now. The last three will still need some
> discussion as I'm not convinced that it's a good idea to have these
> generic profile objects instead or Adapter.Connect/DisconnectProfile.

The problem with Adapter.Connect/DisconnectProfile is that you are not
able to expose the state of the profile. That was the reason to
propose such APIs, since UIs and applications could be interested in
this information.

Cheers,
Mikel

2012-10-25 10:42:19

by Johan Hedberg

[permalink] [raw]
Subject: Re: [RFC v0 05/15] network: Add network .connect and .disconnect

Hi Lizardo,

On Wed, Oct 24, 2012, Anderson Lizardo wrote:
> Hi Mikel,
>
> On Fri, Oct 19, 2012 at 11:39 AM, Mikel Astiz <[email protected]> wrote:
> > +static void connect_profile_cb(struct btd_device *device, int err,
> > + const char *pdev, void *data)
> > +{
> > + struct connect_req *req = data;
> > +
> > + req->cb(req->profile, req->device, err);
> > +
> > + g_free(req);
> > +}
> > +
> > +static int connect_profile(struct btd_device *dev, struct btd_profile *profile,
> > + uint16_t id, btd_profile_cb cb)
> > +{
> > + struct connect_req *req;
> > + int err;
> > +
> > + DBG("path %s id %u", device_get_path(dev), id);
> > +
> > + req = g_new0(struct connect_req, 1);
> > + req->device = dev;
>
> Isn't btd_device_ref() required here?

Looks like you're right and I missed this in my initial review. I went
ahead and pushed an extra patch to fix this.

Johan

2012-10-25 10:39:22

by Johan Hedberg

[permalink] [raw]
Subject: Re: [RFC v0 12/15] input: Add profile .disconnect

Hi Mikel,

On Fri, Oct 19, 2012, Mikel Astiz wrote:
> From: Mikel Astiz <[email protected]>
>
> Add the disconnect hook to the btd_profile.
> ---
> profiles/input/manager.c | 1 +
> 1 file changed, 1 insertion(+)

I've applied the patches up until this one with the exception of the
audio ones which I'll let Luiz to look at and sync up with the work he's
doing for audio right now. The last three will still need some
discussion as I'm not convinced that it's a good idea to have these
generic profile objects instead or Adapter.Connect/DisconnectProfile.

Johan

2012-10-24 12:28:23

by Anderson Lizardo

[permalink] [raw]
Subject: Re: [RFC v0 05/15] network: Add network .connect and .disconnect

Hi Mikel,

On Fri, Oct 19, 2012 at 11:39 AM, Mikel Astiz <[email protected]> wrote:
> +static void connect_profile_cb(struct btd_device *device, int err,
> + const char *pdev, void *data)
> +{
> + struct connect_req *req = data;
> +
> + req->cb(req->profile, req->device, err);
> +
> + g_free(req);
> +}
> +
> +static int connect_profile(struct btd_device *dev, struct btd_profile *profile,
> + uint16_t id, btd_profile_cb cb)
> +{
> + struct connect_req *req;
> + int err;
> +
> + DBG("path %s id %u", device_get_path(dev), id);
> +
> + req = g_new0(struct connect_req, 1);
> + req->device = dev;

Isn't btd_device_ref() required here?

> + req->profile = profile;
> + req->cb = cb;
> +
> + err = connection_connect(dev, BNEP_SVC_PANU, NULL, connect_profile_cb,
> + req);
> + if (err < 0) {
> + g_free(req);
> + return err;
> + }
> +
> + return 0;
> +}

Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil

2012-10-19 16:10:25

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [RFC v0 13/15] profile: Rename org.bluez.Profile->ProfileAgent

Hi Mikel,

> The interface represents an external component supporting a specific
> profile by implementing an agent. Therefore ProfileAgent is a more
> accurate name for the D-Bus interface.

actually I think Johan and I discussed this. And the reason for keeping
the name Profile is that the external component implements the profile.
It is not just an agent, it is the profile.

Regards

Marcel



2012-10-19 15:39:26

by Mikel Astiz

[permalink] [raw]
Subject: [RFC v0 09/15] source: Add profile .connect and .disconnect

From: Mikel Astiz <[email protected]>

Add the connection and disconnection hooks to the a2dp_source
btd_profile.
---
audio/manager.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 82 insertions(+)

diff --git a/audio/manager.c b/audio/manager.c
index c5d295e..77e3540 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -83,6 +83,12 @@ struct audio_adapter {
gint ref;
};

+struct profile_req {
+ struct btd_device *device;
+ struct btd_profile *profile;
+ btd_profile_cb cb;
+};
+
static gboolean auto_connect = TRUE;
static int max_connected_headsets = 1;
static GKeyFile *config = NULL;
@@ -776,6 +782,79 @@ static int avrcp_probe(struct btd_profile *p, struct btd_device *device,
return 0;
}

+static struct profile_req *new_profile_request(struct btd_device *dev,
+ struct btd_profile *profile,
+ btd_profile_cb cb)
+{
+ struct profile_req *req;
+
+ req = g_new0(struct profile_req, 1);
+ req->device = dev;
+ req->profile = profile;
+ req->cb = cb;
+
+ return req;
+}
+
+static void profile_cb(struct audio_device *dev, int err, void *data)
+{
+ struct profile_req *req = data;
+
+ req->cb(req->profile, req->device, err);
+
+ g_free(req);
+}
+
+static int a2dp_source_connect(struct btd_device *dev,
+ struct btd_profile *profile,
+ btd_profile_cb cb)
+{
+ struct audio_device *audio_dev;
+ struct profile_req *req;
+ int err;
+
+ audio_dev = get_audio_dev(dev);
+ if (!audio_dev) {
+ DBG("unable to get a device object");
+ return -1;
+ }
+
+ req = new_profile_request(dev, profile, cb);
+
+ err = source_connect(audio_dev, profile_cb, req);
+ if (err < 0) {
+ g_free(req);
+ return err;
+ }
+
+ return 0;
+}
+
+static int a2dp_source_disconnect(struct btd_device *dev,
+ struct btd_profile *profile,
+ btd_profile_cb cb)
+{
+ struct audio_device *audio_dev;
+ struct profile_req *req;
+ int err;
+
+ audio_dev = get_audio_dev(dev);
+ if (!audio_dev) {
+ DBG("unable to get a device object");
+ return -1;
+ }
+
+ req = new_profile_request(dev, profile, cb);
+
+ err = source_disconnect(audio_dev, profile_cb, req);
+ if (err < 0) {
+ g_free(req);
+ return err;
+ }
+
+ return 0;
+}
+
static struct audio_adapter *audio_adapter_ref(struct audio_adapter *adp)
{
adp->ref++;
@@ -1150,6 +1229,9 @@ static struct btd_profile a2dp_source_profile = {
.device_probe = a2dp_source_probe,
.device_remove = audio_remove,

+ .connect = a2dp_source_connect,
+ .disconnect = a2dp_source_disconnect,
+
.adapter_probe = a2dp_source_server_probe,
};

--
1.7.11.7


2012-10-19 15:39:27

by Mikel Astiz

[permalink] [raw]
Subject: [RFC v0 10/15] input: Trivial function rename

From: Mikel Astiz <[email protected]>

Use the local_ name prefix for functions implementing the D-Bus API.
---
profiles/input/device.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/profiles/input/device.c b/profiles/input/device.c
index 9dd8002..7df92e2 100644
--- a/profiles/input/device.c
+++ b/profiles/input/device.c
@@ -700,7 +700,7 @@ static DBusMessage *local_connect(DBusConnection *conn, DBusMessage *msg,
return NULL;
}

-static DBusMessage *input_device_disconnect(DBusConnection *conn,
+static DBusMessage *local_disconnect(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct input_device *idev = data;
@@ -742,7 +742,7 @@ static const GDBusMethodTable device_methods[] = {
{ GDBUS_ASYNC_METHOD("Connect",
NULL, NULL, local_connect) },
{ GDBUS_METHOD("Disconnect",
- NULL, NULL, input_device_disconnect) },
+ NULL, NULL, local_disconnect) },
{ }
};

--
1.7.11.7


2012-10-19 15:39:31

by Mikel Astiz

[permalink] [raw]
Subject: [RFC v0 14/15] profile: Add object to represent device-profile

From: Mikel Astiz <[email protected]>

An instance of bdm_device_profile represents a profile that has been
probed for a given device, including the state of the connection.
---
Makefile.am | 1 +
audio/manager.c | 32 ++++++------
profiles/input/device.c | 21 ++++----
profiles/input/device.h | 8 +--
profiles/network/manager.c | 57 ++++++++++-----------
src/device-profile.c | 124 +++++++++++++++++++++++++++++++++++++++++++++
src/device-profile.h | 42 +++++++++++++++
src/device.c | 107 +++++++++++++++++++++++++++-----------
src/profile.c | 45 +++++++++-------
src/profile.h | 11 ++--
10 files changed, 334 insertions(+), 114 deletions(-)
create mode 100644 src/device-profile.c
create mode 100644 src/device-profile.h

diff --git a/Makefile.am b/Makefile.am
index 35b1520..4fa341e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -311,6 +311,7 @@ src_bluetoothd_SOURCES = $(gdbus_sources) $(builtin_sources) \
src/manager.h src/manager.c \
src/adapter.h src/adapter.c \
src/profile.h src/profile.c \
+ src/device-profile.h src/device-profile.c \
src/device.h src/device.c src/attio.h \
src/dbus-common.c src/dbus-common.h \
src/event.h src/event.c src/eir.h src/eir.c \
diff --git a/audio/manager.c b/audio/manager.c
index 77e3540..042d131 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -54,6 +54,7 @@
#include "../src/manager.h"
#include "../src/device.h"
#include "../src/profile.h"
+#include "../src/device-profile.h"

#include "log.h"
#include "device.h"
@@ -84,9 +85,8 @@ struct audio_adapter {
};

struct profile_req {
- struct btd_device *device;
- struct btd_profile *profile;
- btd_profile_cb cb;
+ struct btd_device_profile *dp;
+ btd_device_profile_cb cb;
};

static gboolean auto_connect = TRUE;
@@ -782,15 +782,13 @@ static int avrcp_probe(struct btd_profile *p, struct btd_device *device,
return 0;
}

-static struct profile_req *new_profile_request(struct btd_device *dev,
- struct btd_profile *profile,
- btd_profile_cb cb)
+static struct profile_req *new_profile_request(struct btd_device_profile *dp,
+ btd_device_profile_cb cb)
{
struct profile_req *req;

req = g_new0(struct profile_req, 1);
- req->device = dev;
- req->profile = profile;
+ req->dp = dp;
req->cb = cb;

return req;
@@ -800,15 +798,15 @@ static void profile_cb(struct audio_device *dev, int err, void *data)
{
struct profile_req *req = data;

- req->cb(req->profile, req->device, err);
+ req->cb(req->dp, err);

g_free(req);
}

-static int a2dp_source_connect(struct btd_device *dev,
- struct btd_profile *profile,
- btd_profile_cb cb)
+static int a2dp_source_connect(struct btd_device_profile *dp,
+ btd_device_profile_cb cb)
{
+ struct btd_device *dev = device_profile_get_device(dp);
struct audio_device *audio_dev;
struct profile_req *req;
int err;
@@ -819,7 +817,7 @@ static int a2dp_source_connect(struct btd_device *dev,
return -1;
}

- req = new_profile_request(dev, profile, cb);
+ req = new_profile_request(dp, cb);

err = source_connect(audio_dev, profile_cb, req);
if (err < 0) {
@@ -830,10 +828,10 @@ static int a2dp_source_connect(struct btd_device *dev,
return 0;
}

-static int a2dp_source_disconnect(struct btd_device *dev,
- struct btd_profile *profile,
- btd_profile_cb cb)
+static int a2dp_source_disconnect(struct btd_device_profile *dp,
+ btd_device_profile_cb cb)
{
+ struct btd_device *dev = device_profile_get_device(dp);
struct audio_device *audio_dev;
struct profile_req *req;
int err;
@@ -844,7 +842,7 @@ static int a2dp_source_disconnect(struct btd_device *dev,
return -1;
}

- req = new_profile_request(dev, profile, cb);
+ req = new_profile_request(dp, cb);

err = source_disconnect(audio_dev, profile_cb, req);
if (err < 0) {
diff --git a/profiles/input/device.c b/profiles/input/device.c
index fbc3d6f..4867e34 100644
--- a/profiles/input/device.c
+++ b/profiles/input/device.c
@@ -45,6 +45,7 @@
#include "../src/adapter.h"
#include "../src/device.h"
#include "../src/profile.h"
+#include "../src/device-profile.h"
#include "../src/storage.h"
#include "../src/manager.h"
#include "../src/dbus-common.h"
@@ -67,8 +68,8 @@ struct pending_connect {
bool local;
union {
struct {
- struct btd_profile *profile;
- btd_profile_cb cb;
+ struct btd_device_profile *dp;
+ btd_device_profile_cb cb;
} p;
DBusMessage *msg;
};
@@ -528,7 +529,7 @@ static void connect_reply(struct input_device *idev, int err,
error("%s", err_msg);

if (!pending->local) {
- pending->p.cb(pending->p.profile, idev->device, err);
+ pending->p.cb(pending->p.dp, err);
g_free(pending);
return;
}
@@ -657,9 +658,10 @@ static int dev_connect(struct input_device *idev)
return -EIO;
}

-int input_device_connect(struct btd_device *dev, struct btd_profile *profile,
- btd_profile_cb cb)
+int input_device_connect(struct btd_device_profile *dp,
+ btd_device_profile_cb cb)
{
+ struct btd_device *dev = device_profile_get_device(dp);
struct input_device *idev;

idev = find_device_by_path(devices, device_get_path(dev));
@@ -674,7 +676,7 @@ int input_device_connect(struct btd_device *dev, struct btd_profile *profile,

idev->pending = g_new0(struct pending_connect, 1);
idev->pending->local = false;
- idev->pending->p.profile = profile;
+ idev->pending->p.dp = dp;
idev->pending->p.cb = cb;

return dev_connect(idev);
@@ -700,9 +702,10 @@ static DBusMessage *local_connect(DBusConnection *conn, DBusMessage *msg,
return NULL;
}

-int input_device_disconnect(struct btd_device *dev, struct btd_profile *profile,
- btd_profile_cb cb)
+int input_device_disconnect(struct btd_device_profile *dp,
+ btd_device_profile_cb cb)
{
+ struct btd_device *dev = device_profile_get_device(dp);
struct input_device *idev;
int err;

@@ -715,7 +718,7 @@ int input_device_disconnect(struct btd_device *dev, struct btd_profile *profile,
return err;

if (cb)
- cb(profile, dev, 0);
+ cb(dp, 0);

return 0;
}
diff --git a/profiles/input/device.h b/profiles/input/device.h
index d68798c..18924a0 100644
--- a/profiles/input/device.h
+++ b/profiles/input/device.h
@@ -36,7 +36,7 @@ int input_device_set_channel(const bdaddr_t *src, const bdaddr_t *dst, int psm,
GIOChannel *io);
int input_device_close_channels(const bdaddr_t *src, const bdaddr_t *dst);

-int input_device_connect(struct btd_device *dev, struct btd_profile *profile,
- btd_profile_cb cb);
-int input_device_disconnect(struct btd_device *dev, struct btd_profile *profile,
- btd_profile_cb cb);
+int input_device_connect(struct btd_device_profile *dp,
+ btd_device_profile_cb cb);
+int input_device_disconnect(struct btd_device_profile *dp,
+ btd_device_profile_cb cb);
diff --git a/profiles/network/manager.c b/profiles/network/manager.c
index 87d263a..6917b5b 100644
--- a/profiles/network/manager.c
+++ b/profiles/network/manager.c
@@ -40,6 +40,7 @@
#include "adapter.h"
#include "device.h"
#include "profile.h"
+#include "device-profile.h"
#include "manager.h"
#include "common.h"
#include "connection.h"
@@ -48,9 +49,8 @@
static gboolean conf_security = TRUE;

struct connect_req {
- struct btd_device *device;
- struct btd_profile *profile;
- btd_profile_cb cb;
+ struct btd_device_profile *dp;
+ btd_device_profile_cb cb;
};

static void read_config(const char *file)
@@ -84,22 +84,22 @@ static void connect_profile_cb(struct btd_device *device, int err,
{
struct connect_req *req = data;

- req->cb(req->profile, req->device, err);
+ req->cb(req->dp, err);

g_free(req);
}

-static int connect_profile(struct btd_device *dev, struct btd_profile *profile,
- uint16_t id, btd_profile_cb cb)
+static int connect_profile(struct btd_device_profile *dp, uint16_t id,
+ btd_device_profile_cb cb)
{
+ struct btd_device *dev = device_profile_get_device(dp);
struct connect_req *req;
int err;

DBG("path %s id %u", device_get_path(dev), id);

req = g_new0(struct connect_req, 1);
- req->device = dev;
- req->profile = profile;
+ req->dp = dp;
req->cb = cb;

err = connection_connect(dev, BNEP_SVC_PANU, NULL, connect_profile_cb,
@@ -112,10 +112,10 @@ static int connect_profile(struct btd_device *dev, struct btd_profile *profile,
return 0;
}

-static int disconnect_profile(struct btd_device *dev,
- struct btd_profile *profile,
- uint16_t id, btd_profile_cb cb)
+static int disconnect_profile(struct btd_device_profile *dp, uint16_t id,
+ btd_device_profile_cb cb)
{
+ struct btd_device *dev = device_profile_get_device(dp);
int err;

DBG("path %s id %u", device_get_path(dev), id);
@@ -125,7 +125,7 @@ static int disconnect_profile(struct btd_device *dev,
return err;

if (cb)
- cb(profile, dev, 0);
+ cb(dp, 0);

return 0;
}
@@ -145,16 +145,15 @@ static void network_remove(struct btd_profile *p, struct btd_device *device)
connection_unregister(device);
}

-static int panu_connect(struct btd_device *dev, struct btd_profile *profile,
- btd_profile_cb cb)
+static int panu_connect(struct btd_device_profile *dp, btd_device_profile_cb cb)
{
- return connect_profile(dev, profile, BNEP_SVC_PANU, cb);
+ return connect_profile(dp, BNEP_SVC_PANU, cb);
}

-static int panu_disconnect(struct btd_device *dev, struct btd_profile *profile,
- btd_profile_cb cb)
+static int panu_disconnect(struct btd_device_profile *dp,
+ btd_device_profile_cb cb)
{
- return disconnect_profile(dev, profile, BNEP_SVC_PANU, cb);
+ return disconnect_profile(dp, BNEP_SVC_PANU, cb);
}

static int panu_server_probe(struct btd_profile *p, struct btd_adapter *adapter)
@@ -184,16 +183,15 @@ static int gn_probe(struct btd_profile *p, struct btd_device *device,
return connection_register(device, BNEP_SVC_GN);
}

-static int gn_connect(struct btd_device *dev, struct btd_profile *profile,
- btd_profile_cb cb)
+static int gn_connect(struct btd_device_profile *dp, btd_device_profile_cb cb)
{
- return connect_profile(dev, profile, BNEP_SVC_GN, cb);
+ return connect_profile(dp, BNEP_SVC_GN, cb);
}

-static int gn_disconnect(struct btd_device *dev, struct btd_profile *profile,
- btd_profile_cb cb)
+static int gn_disconnect(struct btd_device_profile *dp,
+ btd_device_profile_cb cb)
{
- return disconnect_profile(dev, profile, BNEP_SVC_GN, cb);
+ return disconnect_profile(dp, BNEP_SVC_GN, cb);
}

static int gn_server_probe(struct btd_profile *p, struct btd_adapter *adapter)
@@ -223,16 +221,15 @@ static int nap_probe(struct btd_profile *p, struct btd_device *device,
return connection_register(device, BNEP_SVC_NAP);
}

-static int nap_connect(struct btd_device *dev, struct btd_profile *profile,
- btd_profile_cb cb)
+static int nap_connect(struct btd_device_profile *dp, btd_device_profile_cb cb)
{
- return connect_profile(dev, profile, BNEP_SVC_NAP, cb);
+ return connect_profile(dp, BNEP_SVC_NAP, cb);
}

-static int nap_disconnect(struct btd_device *dev, struct btd_profile *profile,
- btd_profile_cb cb)
+static int nap_disconnect(struct btd_device_profile *dp,
+ btd_device_profile_cb cb)
{
- return disconnect_profile(dev, profile, BNEP_SVC_NAP, cb);
+ return disconnect_profile(dp, BNEP_SVC_NAP, cb);
}

static int nap_server_probe(struct btd_profile *p, struct btd_adapter *adapter)
diff --git a/src/device-profile.c b/src/device-profile.c
new file mode 100644
index 0000000..ea796ac
--- /dev/null
+++ b/src/device-profile.c
@@ -0,0 +1,124 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 BMW Car IT GmbH
+ *
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/uuid.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+#include <bluetooth/mgmt.h>
+
+#include <glib.h>
+
+#include "log.h"
+
+#include "adapter.h"
+#include "device.h"
+#include "profile.h"
+#include "device-profile.h"
+
+struct btd_device_profile {
+ gint ref;
+ struct btd_device *device;
+ struct btd_profile *profile;
+ profile_state_t state;
+};
+
+static char *str_state[] = {
+ "PROFILE_STATE_DISCONNECTED",
+ "PROFILE_STATE_CONNECTING",
+ "PROFILE_STATE_CONNECTED",
+};
+
+struct btd_device *device_profile_get_device(struct btd_device_profile *dp)
+{
+ return dp->device;
+}
+
+struct btd_profile *device_profile_get_profile(struct btd_device_profile *dp)
+{
+ return dp->profile;
+}
+
+void device_profile_set_state(struct btd_device_profile *dp,
+ profile_state_t state)
+{
+ DBG("State changed %p: %s -> %s", dp, str_state[dp->state],
+ str_state[state]);
+
+ dp->state = state;
+}
+
+struct btd_device_profile *device_profile_create(struct btd_device *device,
+ struct btd_profile *profile)
+{
+ struct btd_device_profile *dp;
+
+ dp = g_try_new0(struct btd_device_profile, 1);
+ if (!dp) {
+ error("device_profile_create: failed to alloc memory");
+ return NULL;
+ }
+
+ dp->ref = 1;
+ dp->device = btd_device_ref(device);
+ dp->profile = profile;
+ dp->state = PROFILE_STATE_DISCONNECTED;
+
+ return dp;
+}
+
+struct btd_device_profile *device_profile_ref(struct btd_device_profile *dp)
+{
+ dp->ref++;
+
+ DBG("%p: ref=%d", dp, dp->ref);
+
+ return dp;
+}
+
+void device_profile_unref(struct btd_device_profile *dp)
+{
+ dp->ref--;
+
+ DBG("%p: ref=%d", dp, dp->ref);
+
+ if (dp->ref > 0)
+ return;
+
+ btd_device_unref(dp->device);
+
+ g_free(dp);
+}
diff --git a/src/device-profile.h b/src/device-profile.h
new file mode 100644
index 0000000..ef75d79
--- /dev/null
+++ b/src/device-profile.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 BMW Car IT GmbH
+ *
+ *
+ * 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
+ *
+ */
+
+typedef enum {
+ PROFILE_STATE_DISCONNECTED,
+ PROFILE_STATE_CONNECTING,
+ PROFILE_STATE_CONNECTED,
+} profile_state_t;
+
+struct btd_device_profile;
+
+struct btd_device_profile *device_profile_create(struct btd_device *device,
+ struct btd_profile *profile);
+
+struct btd_device_profile *device_profile_ref(struct btd_device_profile *dp);
+void device_profile_unref(struct btd_device_profile *dp);
+
+struct btd_device *device_profile_get_device(struct btd_device_profile *dp);
+struct btd_profile *device_profile_get_profile(struct btd_device_profile *dp);
+
+void device_profile_set_state(struct btd_device_profile *dp,
+ profile_state_t state);
diff --git a/src/device.c b/src/device.c
index bc7f8dd..37eddef 100644
--- a/src/device.c
+++ b/src/device.c
@@ -54,6 +54,7 @@
#include "attio.h"
#include "device.h"
#include "profile.h"
+#include "device-profile.h"
#include "dbus-common.h"
#include "error.h"
#include "glib-helper.h"
@@ -852,10 +853,14 @@ static gboolean dev_property_get_adapter(const GDBusPropertyTable *property,
return TRUE;
}

-static void profile_remove(struct btd_profile *profile,
- struct btd_device *device)
+static void profile_remove(gpointer p)
{
+ struct btd_device_profile *dp = p;
+ struct btd_device *device = device_profile_get_device(dp);
+ struct btd_profile *profile = device_profile_get_profile(dp);
+
profile->device_remove(profile, device);
+ device_profile_unref(dp);
}

static gboolean do_disconnect(gpointer user_data)
@@ -880,8 +885,7 @@ int device_block(struct btd_device *device, gboolean update_only)
if (device->connected)
do_disconnect(device);

- g_slist_foreach(device->profiles, (GFunc) profile_remove, device);
- g_slist_free(device->profiles);
+ g_slist_free_full(device->profiles, profile_remove);
device->profiles = NULL;

if (!update_only)
@@ -1100,13 +1104,15 @@ static void bonding_request_cancel(struct bonding_req *bonding)

static void dev_disconn_profile(gpointer a, gpointer b)
{
- struct btd_profile *profile = a;
- struct btd_device *dev = b;
+ struct btd_device_profile *dp = a;
+ struct btd_profile *profile = device_profile_get_profile(dp);

if (!profile->disconnect)
return;

- profile->disconnect(dev, profile, NULL);
+ profile->disconnect(dp, NULL);
+
+ device_profile_set_state(dp, PROFILE_STATE_DISCONNECTED);
}

void device_request_disconnect(struct btd_device *device, DBusMessage *msg)
@@ -1127,7 +1133,7 @@ void device_request_disconnect(struct btd_device *device, DBusMessage *msg)
return;

if (device->profiles_connected)
- g_slist_foreach(device->profiles, dev_disconn_profile, device);
+ g_slist_foreach(device->profiles, dev_disconn_profile, NULL);

g_slist_free(device->pending);
device->pending = NULL;
@@ -1170,32 +1176,42 @@ static DBusMessage *disconnect(DBusConnection *conn, DBusMessage *msg,
return NULL;
}

-static int connect_next(struct btd_device *dev, btd_profile_cb cb)
+static int connect_next(struct btd_device *dev, btd_device_profile_cb cb)
{
- struct btd_profile *profile;
int err = -ENOENT;

while (dev->pending) {
+ struct btd_device_profile *dp;
+ struct btd_profile *profile;
int err;

- profile = dev->pending->data;
+ dp = dev->pending->data;
+ profile = device_profile_get_profile(dp);

- err = profile->connect(dev, profile, cb);
- if (err == 0)
+ err = profile->connect(dp, cb);
+ if (err == 0) {
+ device_profile_set_state(dp, PROFILE_STATE_CONNECTING);
return 0;
+ }

error("Failed to connect %s: %s", profile->name,
strerror(-err));
- dev->pending = g_slist_remove(dev->pending, profile);
+ dev->pending = g_slist_remove_link(dev->pending, dev->pending);
}

return err;
}

-static void dev_profile_connected(struct btd_profile *profile,
- struct btd_device *dev, int err)
+static void dev_profile_connected(struct btd_device_profile *dp, int err)
{
- dev->pending = g_slist_remove(dev->pending, profile);
+ struct btd_device *dev = device_profile_get_device(dp);
+
+ dev->pending = g_slist_remove(dev->pending, dp);
+
+ if (err == 0)
+ device_profile_set_state(dp, PROFILE_STATE_CONNECTED);
+ else
+ device_profile_set_state(dp, PROFILE_STATE_DISCONNECTED);

if (connect_next(dev, dev_profile_connected) == 0)
return;
@@ -1245,7 +1261,7 @@ static DBusMessage *dev_connect(DBusConnection *conn, DBusMessage *msg,
void *user_data)
{
struct btd_device *dev = user_data;
- struct btd_profile *p;
+ struct btd_device_profile *dp;
GSList *l;
int err;

@@ -1265,7 +1281,10 @@ static DBusMessage *dev_connect(DBusConnection *conn, DBusMessage *msg,
}

for (l = dev->profiles; l != NULL; l = g_slist_next(l)) {
- p = l->data;
+ struct btd_profile *p;
+
+ dp = l->data;
+ p = device_profile_get_profile(dp);

if (p->auto_connect)
dev->pending = g_slist_append(dev->pending, p);
@@ -1731,7 +1750,7 @@ void device_remove(struct btd_device *device, gboolean remove_stored)
}

if (device->profiles_connected)
- g_slist_foreach(device->profiles, dev_disconn_profile, device);
+ g_slist_foreach(device->profiles, dev_disconn_profile, NULL);

g_slist_free(device->pending);
device->pending = NULL;
@@ -1742,8 +1761,7 @@ void device_remove(struct btd_device *device, gboolean remove_stored)
if (remove_stored)
device_remove_stored(device);

- g_slist_foreach(device->profiles, (GFunc) profile_remove, device);
- g_slist_free(device->profiles);
+ g_slist_free_full(device->profiles, profile_remove);
device->profiles = NULL;

attrib_client_unregister(device->services);
@@ -1820,6 +1838,7 @@ struct probe_data {
static void dev_probe(struct btd_profile *p, void *user_data)
{
struct probe_data *d = user_data;
+ struct btd_device_profile *dp;
GSList *probe_uuids;
int err;

@@ -1837,7 +1856,9 @@ static void dev_probe(struct btd_profile *p, void *user_data)
return;
}

- d->dev->profiles = g_slist_append(d->dev->profiles, p);
+ dp = device_profile_create(d->dev, p);
+
+ d->dev->profiles = g_slist_append(d->dev->profiles, dp);
g_slist_free(probe_uuids);
}

@@ -1845,6 +1866,7 @@ void device_probe_profile(gpointer a, gpointer b)
{
struct btd_device *device = a;
struct btd_profile *profile = b;
+ struct btd_device_profile *dp;
GSList *probe_uuids;
char addr[18];
int err;
@@ -1859,23 +1881,45 @@ void device_probe_profile(gpointer a, gpointer b)
ba2str(&device->bdaddr, addr);

err = profile->device_probe(profile, device, probe_uuids);
- if (err < 0)
+ if (err < 0) {
error("%s profile probe failed for %s", profile->name, addr);
- else
- device->profiles = g_slist_append(device->profiles, profile);
+ g_slist_free(probe_uuids);
+ return;
+ }
+
+ dp = device_profile_create(device, profile);

+ device->profiles = g_slist_append(device->profiles, dp);
g_slist_free(probe_uuids);
}

+static gint device_profile_cmp(gconstpointer a, gconstpointer b)
+{
+ struct btd_device_profile *dp = (gpointer) a;
+ const struct btd_profile *profile = b;
+
+ if (device_profile_get_profile(dp) == profile)
+ return 0;
+
+ return 1;
+}
+
void device_remove_profile(gpointer a, gpointer b)
{
struct btd_device *device = a;
struct btd_profile *profile = b;
+ struct btd_device_profile *dp;
+ GSList *l;

- if (!g_slist_find(device->profiles, profile))
+ l = g_slist_find_custom(device->profiles, profile, device_profile_cmp);
+ if (l == NULL)
return;

- device->profiles = g_slist_remove(device->profiles, profile);
+ dp = l->data;
+
+ device->profiles = g_slist_remove_link(device->profiles, l);
+
+ device_profile_unref(dp);

profile->device_remove(profile, device);
}
@@ -1948,7 +1992,8 @@ static void device_remove_profiles(struct btd_device *device, GSList *uuids)
sdp_list_free(records, (sdp_free_func_t) sdp_record_free);

for (l = device->profiles; l != NULL; l = next) {
- struct btd_profile *profile = l->data;
+ struct btd_device_profile *dp = l->data;
+ struct btd_profile *profile = device_profile_get_profile(dp);
GSList *probe_uuids;

next = l->next;
@@ -1960,7 +2005,9 @@ static void device_remove_profiles(struct btd_device *device, GSList *uuids)
}

profile->device_remove(profile, device);
- device->profiles = g_slist_remove(device->profiles, profile);
+ device->profiles = g_slist_remove_link(device->profiles, l);
+
+ device_profile_unref(dp);
}
}

diff --git a/src/profile.c b/src/profile.c
index 7e7c945..cc78612 100644
--- a/src/profile.c
+++ b/src/profile.c
@@ -50,6 +50,7 @@
#include "manager.h"
#include "device.h"
#include "profile.h"
+#include "device-profile.h"

#define SPP_DEFAULT_CHANNEL 3

@@ -88,10 +89,10 @@ struct ext_io {
GIOChannel *io;
guint io_id;
struct btd_adapter *adapter;
- struct btd_device *device;
+ struct btd_device_profile *dp;

bool resolving;
- btd_profile_cb cb;
+ btd_device_profile_cb cb;
uint16_t rec_handle;

guint auth_id;
@@ -185,9 +186,13 @@ static void ext_io_destroy(gpointer p)
ext_cancel(ext);
}

- if (ext_io->resolving)
+ if (ext_io->resolving) {
+ struct btd_device *device;
+
+ device = device_profile_get_device(ext_io->dp);
bt_cancel_discovery(adapter_get_address(ext_io->adapter),
- device_get_address(ext_io->device));
+ device_get_address(device));
+ }

if (ext_io->rec_handle)
remove_record_from_server(ext_io->rec_handle);
@@ -195,8 +200,8 @@ static void ext_io_destroy(gpointer p)
if (ext_io->adapter)
btd_adapter_unref(ext_io->adapter);

- if (ext_io->device)
- btd_device_unref(ext_io->device);
+ if (ext_io->dp)
+ device_profile_unref(ext_io->dp);

g_free(ext_io);
}
@@ -244,7 +249,7 @@ static void new_conn_reply(DBusPendingCall *call, void *user_data)

if (!dbus_error_is_set(&err)) {
if (conn->cb) {
- conn->cb(&ext->p, conn->device, 0);
+ conn->cb(conn->dp, 0);
conn->cb = NULL;
}
return;
@@ -254,7 +259,7 @@ static void new_conn_reply(DBusPendingCall *call, void *user_data)
err.name, err.message);

if (conn->cb) {
- conn->cb(&ext->p, conn->device, -ECONNREFUSED);
+ conn->cb(conn->dp, -ECONNREFUSED);
conn->cb = NULL;
}

@@ -638,7 +643,7 @@ static void remove_connect(struct ext_profile *ext, struct btd_device *dev)
if (!conn->cb)
continue;

- if (conn->device != dev)
+ if (device_profile_get_device(conn->dp) != dev)
continue;

ext->conns = g_slist_remove(ext->conns, conn);
@@ -716,6 +721,7 @@ static uint16_t get_goep_l2cap_psm(sdp_record_t *rec)
static void record_cb(sdp_list_t *recs, int err, gpointer user_data)
{
struct ext_io *conn = user_data;
+ struct btd_device *device = device_profile_get_device(conn->dp);
struct ext_profile *ext = conn->ext;
sdp_list_t *r;

@@ -769,7 +775,7 @@ static void record_cb(sdp_list_t *recs, int err, gpointer user_data)
}

err = connect_io(conn, adapter_get_address(conn->adapter),
- device_get_address(conn->device));
+ device_get_address(device));
if (err < 0) {
error("Connecting %s failed: %s", ext->name, strerror(-err));
goto failed;
@@ -778,7 +784,7 @@ static void record_cb(sdp_list_t *recs, int err, gpointer user_data)
return;

failed:
- conn->cb(&ext->p, conn->device, err);
+ conn->cb(conn->dp, err);
ext->conns = g_slist_remove(ext->conns, conn);
ext_io_destroy(conn);
}
@@ -799,10 +805,12 @@ static int resolve_service(struct ext_io *conn, const bdaddr_t *src,
return err;
}

-static int ext_connect_dev(struct btd_device *dev, struct btd_profile *profile,
- btd_profile_cb cb)
+static int ext_connect_dev(struct btd_device_profile *dp,
+ btd_device_profile_cb cb)
{
struct btd_adapter *adapter;
+ struct btd_device *dev = device_profile_get_device(dp);
+ struct btd_profile *profile = device_profile_get_profile(dp);
struct ext_io *conn;
struct ext_profile *ext;
int err;
@@ -827,7 +835,7 @@ static int ext_connect_dev(struct btd_device *dev, struct btd_profile *profile,
goto failed;

conn->adapter = btd_adapter_ref(adapter);
- conn->device = btd_device_ref(dev);
+ conn->dp = device_profile_ref(dp);
conn->cb = cb;

ext->conns = g_slist_append(ext->conns, conn);
@@ -839,17 +847,16 @@ failed:
return err;
}

-static int ext_disconnect_dev(struct btd_device *dev,
- struct btd_profile *profile,
- btd_profile_cb cb)
+static int ext_disconnect_dev(struct btd_device_profile *dp,
+ btd_device_profile_cb cb)
{
struct ext_profile *ext;

- ext = find_ext(profile);
+ ext = find_ext(device_profile_get_profile(dp));
if (!ext)
return -ENOENT;

- remove_connect(ext, dev);
+ remove_connect(ext, device_profile_get_device(dp));

return 0;
}
diff --git a/src/profile.h b/src/profile.h
index e20b383..2ee90a7 100644
--- a/src/profile.h
+++ b/src/profile.h
@@ -24,9 +24,11 @@
#define BTD_UUIDS(args...) ((const char *[]) { args, NULL } )

struct btd_profile;
+struct btd_device_profile;

typedef void (*btd_profile_cb)(struct btd_profile *profile,
struct btd_device *device, int err);
+typedef void (*btd_device_profile_cb)(struct btd_device_profile *dp, int err);

struct btd_profile {
const char *name;
@@ -41,11 +43,10 @@ struct btd_profile {
void (*device_remove) (struct btd_profile *p,
struct btd_device *device);

- int (*connect) (struct btd_device *device, struct btd_profile *profile,
- btd_profile_cb cb);
- int (*disconnect) (struct btd_device *device,
- struct btd_profile *profile,
- btd_profile_cb cb);
+ int (*connect) (struct btd_device_profile *dp,
+ btd_device_profile_cb cb);
+ int (*disconnect) (struct btd_device_profile *dp,
+ btd_device_profile_cb cb);

int (*adapter_probe) (struct btd_profile *p,
struct btd_adapter *adapter);
--
1.7.11.7


2012-10-19 15:39:28

by Mikel Astiz

[permalink] [raw]
Subject: [RFC v0 11/15] input: Expose internal disconnection API

From: Mikel Astiz <[email protected]>

Expose the same API exposed in D-Bus to disconnect devices.
---
profiles/input/device.c | 20 ++++++++++++++++++++
profiles/input/device.h | 2 ++
2 files changed, 22 insertions(+)

diff --git a/profiles/input/device.c b/profiles/input/device.c
index 7df92e2..fbc3d6f 100644
--- a/profiles/input/device.c
+++ b/profiles/input/device.c
@@ -700,6 +700,26 @@ static DBusMessage *local_connect(DBusConnection *conn, DBusMessage *msg,
return NULL;
}

+int input_device_disconnect(struct btd_device *dev, struct btd_profile *profile,
+ btd_profile_cb cb)
+{
+ struct input_device *idev;
+ int err;
+
+ idev = find_device_by_path(devices, device_get_path(dev));
+ if (!idev)
+ return -ENOENT;
+
+ err = connection_disconnect(idev, 0);
+ if (err < 0)
+ return err;
+
+ if (cb)
+ cb(profile, dev, 0);
+
+ return 0;
+}
+
static DBusMessage *local_disconnect(DBusConnection *conn,
DBusMessage *msg, void *data)
{
diff --git a/profiles/input/device.h b/profiles/input/device.h
index be1f830..d68798c 100644
--- a/profiles/input/device.h
+++ b/profiles/input/device.h
@@ -38,3 +38,5 @@ int input_device_close_channels(const bdaddr_t *src, const bdaddr_t *dst);

int input_device_connect(struct btd_device *dev, struct btd_profile *profile,
btd_profile_cb cb);
+int input_device_disconnect(struct btd_device *dev, struct btd_profile *profile,
+ btd_profile_cb cb);
--
1.7.11.7


2012-10-19 15:39:32

by Mikel Astiz

[permalink] [raw]
Subject: [RFC v0 15/15] profile: Add new org.bluez.Profile

From: Mikel Astiz <[email protected]>

Add a D-Bus interface to represent a profile that is supported by a
device, moving the profile-specific API in org.bluez.Device and
additionally exposing state information.
---
doc/device-api.txt | 23 -------
doc/profile-api.txt | 48 +++++++++++++++
src/device-profile.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++-
src/device-profile.h | 1 +
src/device.c | 3 +
5 files changed, 217 insertions(+), 24 deletions(-)
create mode 100644 doc/profile-api.txt

diff --git a/doc/device-api.txt b/doc/device-api.txt
index c1f2361..b0145e0 100644
--- a/doc/device-api.txt
+++ b/doc/device-api.txt
@@ -70,29 +70,6 @@ Methods dict DiscoverServices(string pattern)

Possible errors: org.bluez.Error.NotConnected

- void ConnectProfile(string uuid)
-
- This method connects a specific profile of this
- device. The profile needs to be registered client
- profile.
-
- Possible errors: org.bluez.Error.DoesNotExist
- org.bluez.Error.AlreadyConnected
- org.bluez.Error.ConnectFailed
-
- void DisconnectProfile(string uuid)
-
- This method disconnects a specific profile of
- this device. The profile needs to be registered
- client profile.
-
- There is no connection tracking for a profile, so
- as long as the profile is registered this will always
- succeed.
-
- Possible errors: org.bluez.Error.DoesNotExist
- org.bluez.Error.NotConnected
-
void Pair(object agent, string capability)

This method will connect to the remote device,
diff --git a/doc/profile-api.txt b/doc/profile-api.txt
new file mode 100644
index 0000000..9540b7a
--- /dev/null
+++ b/doc/profile-api.txt
@@ -0,0 +1,48 @@
+BlueZ D-Bus Profile API description
+***********************************
+
+Copyright (C) 2012 BMW Car IT GmbH. All rights reserved.
+
+
+Profile hierarchy
+=================
+
+Service unique name
+Interface org.bluez.Profile
+Object path freely definable
+
+Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/
+ profileZZZ
+
+Methods void Connect()
+
+ This method connects a specific profile of this
+ device. The profile needs to be registered client
+ profile.
+
+ Possible errors: org.bluez.Error.AlreadyConnected
+ org.bluez.Error.ConnectFailed
+ org.bluez.Error.Canceled
+ org.bluez.Error.AgentNotAvailable
+
+ void Disconnect()
+
+ This method disconnects a specific profile of
+ this device. The profile needs to be registered
+ client profile.
+
+ There is no connection tracking for a profile, so
+ as long as the profile is registered this will always
+ succeed.
+
+ Possible errors: org.bluez.Error.NotConnected
+
+Properties string State [readonly]
+
+ Indicates the state of the connection. Possible
+ values are:
+ "disconnected": profile disconnected
+ "connecting": outgoing or incoming connection
+ attempt going on, including
+ local agent authorization
+ "connected": profile connected
diff --git a/src/device-profile.c b/src/device-profile.c
index ea796ac..d4b72d1 100644
--- a/src/device-profile.c
+++ b/src/device-profile.c
@@ -41,19 +41,27 @@
#include <bluetooth/mgmt.h>

#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus.h>

#include "log.h"

+#include "dbus-common.h"
+#include "error.h"
#include "adapter.h"
#include "device.h"
#include "profile.h"
#include "device-profile.h"

+#define DEVICE_PROFILE_INTERFACE "org.bluez.Profile"
+
struct btd_device_profile {
gint ref;
struct btd_device *device;
struct btd_profile *profile;
+ gchar *path;
profile_state_t state;
+ DBusMessage *msg;
};

static char *str_state[] = {
@@ -62,6 +70,20 @@ static char *str_state[] = {
"PROFILE_STATE_CONNECTED",
};

+static const char *state2str(profile_state_t state)
+{
+ switch (state) {
+ case PROFILE_STATE_DISCONNECTED:
+ return "disconnected";
+ case PROFILE_STATE_CONNECTING:
+ return "connecting";
+ case PROFILE_STATE_CONNECTED:
+ return "connected";
+ }
+
+ return NULL;
+}
+
struct btd_device *device_profile_get_device(struct btd_device_profile *dp)
{
return dp->device;
@@ -75,12 +97,131 @@ struct btd_profile *device_profile_get_profile(struct btd_device_profile *dp)
void device_profile_set_state(struct btd_device_profile *dp,
profile_state_t state)
{
- DBG("State changed %p: %s -> %s", dp, str_state[dp->state],
+ DBG("State changed %s: %s -> %s", dp->path, str_state[dp->state],
str_state[state]);

dp->state = state;
+
+ g_dbus_emit_property_changed(btd_get_dbus_connection(),
+ dp->path, DEVICE_PROFILE_INTERFACE,
+ "State");
+}
+
+static void connect_cb(struct btd_device_profile *dp, int err)
+{
+ DBusMessage *msg = dp->msg;
+ DBusMessage *reply;
+
+ if (err == 0) {
+ reply = dbus_message_new_method_return(msg);
+ device_profile_set_state(dp, PROFILE_STATE_CONNECTED);
+ } else {
+ reply = btd_error_failed(msg, strerror(-err));
+ device_profile_set_state(dp, PROFILE_STATE_DISCONNECTED);
+ }
+
+ g_dbus_send_message(btd_get_dbus_connection(), reply);
+
+ dbus_message_unref(msg);
+ dp->msg = NULL;
+}
+
+static DBusMessage *dp_connect(DBusConnection *conn, DBusMessage *msg,
+ void *user_data)
+{
+ struct btd_device_profile *dp = user_data;
+ int err;
+
+ if (dp->state != PROFILE_STATE_DISCONNECTED)
+ return btd_error_already_connected(msg);
+
+ if (dp->msg != NULL)
+ return btd_error_busy(msg);
+
+ err = dp->profile->connect(dp, connect_cb);
+ if (err < 0)
+ return btd_error_failed(msg, strerror(-err));
+
+ dp->msg = dbus_message_ref(msg);
+ device_profile_set_state(dp, PROFILE_STATE_CONNECTING);
+
+ return NULL;
+}
+
+static gboolean disconnect_cb_continue(gpointer user_data)
+{
+ struct btd_device_profile *dp = user_data;
+
+ g_dbus_send_message(btd_get_dbus_connection(), dp->msg);
+ dbus_message_unref(dp->msg);
+ dp->msg = NULL;
+
+ return FALSE;
+}
+
+static void disconnect_cb(struct btd_device_profile *dp, int err)
+{
+ DBusMessage *msg = dp->msg;
+ DBusMessage *reply;
+
+ if (err == 0) {
+ reply = dbus_message_new_method_return(msg);
+ device_profile_set_state(dp, PROFILE_STATE_DISCONNECTED);
+ } else
+ reply = btd_error_failed(msg, strerror(-err));
+
+ dbus_message_unref(msg);
+ dp->msg = reply;
+
+ g_idle_add(disconnect_cb_continue, dp);
}

+static DBusMessage *dp_disconnect(DBusConnection *conn, DBusMessage *msg,
+ void *user_data)
+{
+ struct btd_device_profile *dp = user_data;
+ int err;
+
+ if (dp->state == PROFILE_STATE_DISCONNECTED)
+ return btd_error_not_connected(msg);
+
+ if (dp->msg != NULL)
+ return btd_error_busy(msg);
+
+ dp->msg = dbus_message_ref(msg);
+
+ err = dp->profile->disconnect(dp, disconnect_cb);
+ if (err < 0) {
+ dbus_message_unref(dp->msg);
+ dp->msg = NULL;
+ return btd_error_failed(msg, strerror(-err));
+ }
+
+ return NULL;
+}
+
+static gboolean dp_property_get_state(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct btd_device_profile *dp = data;
+ const char *state = state2str(dp->state);
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &state);
+
+ return TRUE;
+}
+
+static const GDBusMethodTable device_profile_methods[] = {
+ { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, dp_connect) },
+ { GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL, dp_disconnect) },
+ { }
+};
+
+static const GDBusPropertyTable device_profile_properties[] = {
+ { "State", "s", dp_property_get_state },
+ { }
+};
+
struct btd_device_profile *device_profile_create(struct btd_device *device,
struct btd_profile *profile)
{
@@ -96,10 +237,29 @@ struct btd_device_profile *device_profile_create(struct btd_device *device,
dp->device = btd_device_ref(device);
dp->profile = profile;
dp->state = PROFILE_STATE_DISCONNECTED;
+ dp->path = g_strdup_printf("%s/%s", device_get_path(device),
+ profile->name);
+ g_strdelimit(dp->path, "-", '_');
+
+ if (!g_dbus_register_interface(btd_get_dbus_connection(),
+ dp->path, DEVICE_PROFILE_INTERFACE,
+ device_profile_methods, NULL,
+ device_profile_properties, dp,
+ NULL)) {
+ error("Device profile init failed on path %s", dp->path);
+ device_profile_unref(dp);
+ return NULL;
+ }

return dp;
}

+void device_profile_unregister(struct btd_device_profile *dp)
+{
+ g_dbus_unregister_interface(btd_get_dbus_connection(),
+ dp->path, DEVICE_PROFILE_INTERFACE);
+}
+
struct btd_device_profile *device_profile_ref(struct btd_device_profile *dp)
{
dp->ref++;
@@ -120,5 +280,9 @@ void device_profile_unref(struct btd_device_profile *dp)

btd_device_unref(dp->device);

+ if (dp->msg)
+ dbus_message_unref(dp->msg);
+
+ g_free(dp->path);
g_free(dp);
}
diff --git a/src/device-profile.h b/src/device-profile.h
index ef75d79..db03d79 100644
--- a/src/device-profile.h
+++ b/src/device-profile.h
@@ -31,6 +31,7 @@ struct btd_device_profile;

struct btd_device_profile *device_profile_create(struct btd_device *device,
struct btd_profile *profile);
+void device_profile_unregister(struct btd_device_profile *dp);

struct btd_device_profile *device_profile_ref(struct btd_device_profile *dp);
void device_profile_unref(struct btd_device_profile *dp);
diff --git a/src/device.c b/src/device.c
index 37eddef..2a73f2f 100644
--- a/src/device.c
+++ b/src/device.c
@@ -860,6 +860,7 @@ static void profile_remove(gpointer p)
struct btd_profile *profile = device_profile_get_profile(dp);

profile->device_remove(profile, device);
+ device_profile_unregister(dp);
device_profile_unref(dp);
}

@@ -1919,6 +1920,7 @@ void device_remove_profile(gpointer a, gpointer b)

device->profiles = g_slist_remove_link(device->profiles, l);

+ device_profile_unregister(dp);
device_profile_unref(dp);

profile->device_remove(profile, device);
@@ -2007,6 +2009,7 @@ static void device_remove_profiles(struct btd_device *device, GSList *uuids)
profile->device_remove(profile, device);
device->profiles = g_slist_remove_link(device->profiles, l);

+ device_profile_unregister(dp);
device_profile_unref(dp);
}
}
--
1.7.11.7


2012-10-19 15:39:29

by Mikel Astiz

[permalink] [raw]
Subject: [RFC v0 12/15] input: Add profile .disconnect

From: Mikel Astiz <[email protected]>

Add the disconnect hook to the btd_profile.
---
profiles/input/manager.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/profiles/input/manager.c b/profiles/input/manager.c
index a2690b5..71fd48f 100644
--- a/profiles/input/manager.c
+++ b/profiles/input/manager.c
@@ -90,6 +90,7 @@ static struct btd_profile input_profile = {

.auto_connect = true,
.connect = input_device_connect,
+ .disconnect = input_device_disconnect,

.device_probe = hid_device_probe,
.device_remove = hid_device_remove,
--
1.7.11.7


2012-10-19 15:39:30

by Mikel Astiz

[permalink] [raw]
Subject: [RFC v0 13/15] profile: Rename org.bluez.Profile->ProfileAgent

From: Mikel Astiz <[email protected]>

The interface represents an external component supporting a specific
profile by implementing an agent. Therefore ProfileAgent is a more
accurate name for the D-Bus interface.
---
doc/manager-api.txt | 3 ++-
doc/profile-api.txt | 53 ------------------------------------------------
doc/profileagent-api.txt | 53 ++++++++++++++++++++++++++++++++++++++++++++++++
src/bluetooth.conf | 2 +-
src/manager.c | 2 +-
src/profile.c | 11 +++++-----
test/test-profile | 8 ++++----
7 files changed, 67 insertions(+), 65 deletions(-)
delete mode 100644 doc/profile-api.txt
create mode 100644 doc/profileagent-api.txt

diff --git a/doc/manager-api.txt b/doc/manager-api.txt
index fe50556..16fe4ee 100644
--- a/doc/manager-api.txt
+++ b/doc/manager-api.txt
@@ -29,7 +29,8 @@ Object path /
Possible errors: org.bluez.Error.InvalidArguments
org.bluez.Error.NoSuchAdapter

- void RegisterProfile(object profile, string uuid, dict options)
+ void RegisterProfileAgent(object profile, string uuid,
+ dict options)

This registers a profile implementation.

diff --git a/doc/profile-api.txt b/doc/profile-api.txt
deleted file mode 100644
index 639202f..0000000
--- a/doc/profile-api.txt
+++ /dev/null
@@ -1,53 +0,0 @@
-BlueZ D-Bus Profile API description
-***********************************
-
-Copyright (C) 2012 Intel Corporation. All rights reserved.
-
-
-Profile hierarchy
-=================
-
-Service unique name
-Interface org.bluez.Profile
-Object path freely definable
-
-Methods void Release()
-
- This method gets called when the service daemon
- unregisters the profile. A profile can use it to do
- cleanup tasks. There is no need to unregister the
- profile, because when this method gets called it has
- already been unregistered.
-
- void NewConnection(object device, fd)
-
- This method gets called when a new service level
- connection has been made and authorized.
-
- Possible errors: org.bluez.Error.Rejected
- org.bluez.Error.Canceled
-
- void RequestDisconnection(object device)
-
- This method gets called when a profile gets
- disconnected.
-
- The file descriptor is no longer owned by the service
- daemon and the profile implementation needs to take
- care of cleaning up all connections.
-
- If multiple file descriptors are indicated via
- NewConnection, it is expected that all of them
- are disconnected before returning from this
- method call.
-
- Possible errors: org.bluez.Error.Rejected
- org.bluez.Error.Canceled
-
- void Cancel()
-
- This method gets called to indicate that the profile
- request failed before a reply was returned.
-
- All request are queued and there will be only one
- pending pequest at a time per profile.
diff --git a/doc/profileagent-api.txt b/doc/profileagent-api.txt
new file mode 100644
index 0000000..8a27a01
--- /dev/null
+++ b/doc/profileagent-api.txt
@@ -0,0 +1,53 @@
+BlueZ D-Bus Profile API description
+***********************************
+
+Copyright (C) 2012 Intel Corporation. All rights reserved.
+
+
+Profile hierarchy
+=================
+
+Service unique name
+Interface org.bluez.ProfileAgent
+Object path freely definable
+
+Methods void Release()
+
+ This method gets called when the service daemon
+ unregisters the profile. A profile can use it to do
+ cleanup tasks. There is no need to unregister the
+ profile, because when this method gets called it has
+ already been unregistered.
+
+ void NewConnection(object device, fd)
+
+ This method gets called when a new service level
+ connection has been made and authorized.
+
+ Possible errors: org.bluez.Error.Rejected
+ org.bluez.Error.Canceled
+
+ void RequestDisconnection(object device)
+
+ This method gets called when a profile gets
+ disconnected.
+
+ The file descriptor is no longer owned by the service
+ daemon and the profile implementation needs to take
+ care of cleaning up all connections.
+
+ If multiple file descriptors are indicated via
+ NewConnection, it is expected that all of them
+ are disconnected before returning from this
+ method call.
+
+ Possible errors: org.bluez.Error.Rejected
+ org.bluez.Error.Canceled
+
+ void Cancel()
+
+ This method gets called to indicate that the profile
+ request failed before a reply was returned.
+
+ All request are queued and there will be only one
+ pending pequest at a time per profile.
diff --git a/src/bluetooth.conf b/src/bluetooth.conf
index 2db43d9..49dafc8 100644
--- a/src/bluetooth.conf
+++ b/src/bluetooth.conf
@@ -17,7 +17,7 @@
<allow send_interface="org.bluez.Watcher"/>
<allow send_interface="org.bluez.ThermometerWatcher"/>
<allow send_interface="org.bluez.AlertAgent"/>
- <allow send_interface="org.bluez.Profile"/>
+ <allow send_interface="org.bluez.ProfileAgent"/>
<allow send_interface="org.bluez.HeartRateWatcher"/>
</policy>

diff --git a/src/manager.c b/src/manager.c
index a96115b..1dc1c54 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -163,7 +163,7 @@ static const GDBusMethodTable manager_methods[] = {
GDBUS_ARGS({ "pattern", "s" }),
GDBUS_ARGS({ "adapter", "o" }),
find_adapter) },
- { GDBUS_METHOD("RegisterProfile",
+ { GDBUS_METHOD("RegisterProfileAgent",
GDBUS_ARGS({ "profile", "o"}, { "UUID", "s" },
{ "options", "a{sv}" }),
NULL, btd_profile_reg_ext) },
diff --git a/src/profile.c b/src/profile.c
index eb63e1e..7e7c945 100644
--- a/src/profile.c
+++ b/src/profile.c
@@ -157,7 +157,8 @@ static void ext_cancel(struct ext_profile *ext)
DBusMessage *msg;

msg = dbus_message_new_method_call(ext->owner, ext->path,
- "org.bluez.Profile", "Cancel");
+ "org.bluez.ProfileAgent",
+ "Cancel");
if (msg)
g_dbus_send_message(btd_get_dbus_connection(), msg);
}
@@ -274,8 +275,8 @@ static bool send_new_connection(struct ext_profile *ext, struct ext_io *conn,
int fd;

msg = dbus_message_new_method_call(ext->owner, ext->path,
- "org.bluez.Profile",
- "NewConnection");
+ "org.bluez.ProfileAgent",
+ "NewConnection");
if (!msg) {
error("Unable to create NewConnection call for %s", ext->name);
return false;
@@ -1108,8 +1109,8 @@ void btd_profile_cleanup(void)
ext->conns = NULL;

msg = dbus_message_new_method_call(ext->owner, ext->path,
- "org.bluez.Profile",
- "Release");
+ "org.bluez.ProfileAgent",
+ "Release");
if (msg)
g_dbus_send_message(conn, msg);

diff --git a/test/test-profile b/test/test-profile
index 2d66444..cfc9331 100755
--- a/test/test-profile
+++ b/test/test-profile
@@ -12,18 +12,18 @@ import dbus.mainloop.glib
from optparse import OptionParser, make_option

class Profile(dbus.service.Object):
- @dbus.service.method("org.bluez.Profile",
+ @dbus.service.method("org.bluez.ProfileAgent",
in_signature="", out_signature="")
def Release(self):
print("Release")
mainloop.quit()

- @dbus.service.method("org.bluez.Profile",
+ @dbus.service.method("org.bluez.ProfileAgent",
in_signature="", out_signature="")
def Cancel(self):
print("Cancel")

- @dbus.service.method("org.bluez.Profile",
+ @dbus.service.method("org.bluez.ProfileAgent",
in_signature="oh", out_signature="")
def NewConnection(self, path, fd):
fd = fd.take()
@@ -84,6 +84,6 @@ if __name__ == '__main__':
if (options.channel):
opts["Channel"] = dbus.UInt16(options.channel)

- manager.RegisterProfile(options.path, options.uuid, opts)
+ manager.RegisterProfileAgent(options.path, options.uuid, opts)

mainloop.run()
--
1.7.11.7


2012-10-19 15:39:25

by Mikel Astiz

[permalink] [raw]
Subject: [RFC v0 08/15] source: Expose internal connection API

From: Mikel Astiz <[email protected]>

Separate the D-Bus code from the internal connection handling code,
exposing an internal API in case some internal codepath/plugin is
interested in using it.
---
audio/device.h | 3 ++
audio/source.c | 146 ++++++++++++++++++++++++++++++++-------------------------
audio/source.h | 2 +
3 files changed, 88 insertions(+), 63 deletions(-)

diff --git a/audio/device.h b/audio/device.h
index 1e2cac1..41e5635 100644
--- a/audio/device.h
+++ b/audio/device.h
@@ -22,6 +22,7 @@
*
*/

+struct audio_device;
struct source;
struct control;
struct target;
@@ -30,6 +31,8 @@ struct headset;
struct gateway;
struct dev_priv;

+typedef void (*audio_device_cb) (struct audio_device *dev, int err, void *data);
+
struct audio_device {
struct btd_device *btd_dev;

diff --git a/audio/source.c b/audio/source.c
index 04971d9..e48e308 100644
--- a/audio/source.c
+++ b/audio/source.c
@@ -53,7 +53,8 @@
#define STREAM_SETUP_RETRY_TIMER 2

struct pending_request {
- DBusMessage *msg;
+ audio_device_cb cb;
+ void *cb_data;
unsigned int id;
};

@@ -152,10 +153,12 @@ static void avdtp_state_callback(struct audio_device *dev,
}

static void pending_request_free(struct audio_device *dev,
- struct pending_request *pending)
+ struct pending_request *pending,
+ int err)
{
- if (pending->msg)
- dbus_message_unref(pending->msg);
+ if (pending->cb)
+ pending->cb(dev, err, pending->cb_data);
+
if (pending->id)
a2dp_cancel(dev, pending->id);

@@ -177,15 +180,12 @@ static void stream_state_changed(struct avdtp_stream *stream,
switch (new_state) {
case AVDTP_STATE_IDLE:
if (source->disconnect) {
- DBusMessage *reply;
struct pending_request *p;

p = source->disconnect;
source->disconnect = NULL;

- reply = dbus_message_new_method_return(p->msg);
- g_dbus_send_message(btd_get_dbus_connection(), reply);
- pending_request_free(dev, p);
+ pending_request_free(dev, p, 0);
}

if (source->session) {
@@ -211,35 +211,24 @@ static void stream_state_changed(struct avdtp_stream *stream,
source->stream_state = new_state;
}

-static void error_failed(DBusMessage *msg,
- const char *desc)
-{
- DBusMessage *reply = btd_error_failed(msg, desc);
- g_dbus_send_message(btd_get_dbus_connection(), reply);
-}
-
static gboolean stream_setup_retry(gpointer user_data)
{
struct source *source = user_data;
struct pending_request *pending = source->connect;
+ int err;

source->retry_id = 0;

if (source->stream_state >= AVDTP_STATE_OPEN) {
DBG("Stream successfully created, after XCASE connect:connect");
- if (pending->msg) {
- DBusMessage *reply;
- reply = dbus_message_new_method_return(pending->msg);
- g_dbus_send_message(btd_get_dbus_connection(), reply);
- }
+ err = 0;
} else {
DBG("Stream setup failed, after XCASE connect:connect");
- if (pending->msg)
- error_failed(pending->msg, "Stream setup failed");
+ err = -EIO;
}

source->connect = NULL;
- pending_request_free(source->dev, pending);
+ pending_request_free(source->dev, pending, err);

return FALSE;
}
@@ -258,14 +247,8 @@ static void stream_setup_complete(struct avdtp *session, struct a2dp_sep *sep,
if (stream) {
DBG("Stream successfully created");

- if (pending->msg) {
- DBusMessage *reply;
- reply = dbus_message_new_method_return(pending->msg);
- g_dbus_send_message(btd_get_dbus_connection(), reply);
- }
-
source->connect = NULL;
- pending_request_free(source->dev, pending);
+ pending_request_free(source->dev, pending, 0);

return;
}
@@ -279,10 +262,8 @@ static void stream_setup_complete(struct avdtp *session, struct a2dp_sep *sep,
stream_setup_retry,
source);
} else {
- if (pending->msg)
- error_failed(pending->msg, "Stream setup failed");
source->connect = NULL;
- pending_request_free(source->dev, pending);
+ pending_request_free(source->dev, pending, -EIO);
DBG("Stream setup failed : %s", avdtp_strerror(err));
}
}
@@ -309,9 +290,7 @@ static void select_complete(struct avdtp *session, struct a2dp_sep *sep,
return;

failed:
- if (pending->msg)
- error_failed(pending->msg, "Stream setup failed");
- pending_request_free(source->dev, pending);
+ pending_request_free(source->dev, pending, -EIO);
source->connect = NULL;
avdtp_unref(source->session);
source->session = NULL;
@@ -352,9 +331,7 @@ static void discovery_complete(struct avdtp *session, GSList *seps, struct avdtp
return;

failed:
- if (pending->msg)
- error_failed(pending->msg, "Stream setup failed");
- pending_request_free(source->dev, pending);
+ pending_request_free(source->dev, pending, -EIO);
source->connect = NULL;
avdtp_unref(source->session);
source->session = NULL;
@@ -379,71 +356,114 @@ gboolean source_setup_stream(struct source *source, struct avdtp *session)
return TRUE;
}

+static void generic_cb(struct audio_device *dev, int err, void *data)
+{
+ DBusMessage *msg = data;
+ DBusMessage *reply;
+
+ if (err < 0) {
+ reply = btd_error_failed(msg, strerror(-err));
+ g_dbus_send_message(btd_get_dbus_connection(), reply);
+ dbus_message_unref(msg);
+ return;
+ }
+
+ g_dbus_send_reply(btd_get_dbus_connection(), msg, DBUS_TYPE_INVALID);
+
+ dbus_message_unref(msg);
+}
+
static DBusMessage *local_connect(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct audio_device *dev = data;
+ int err;
+
+ err = source_connect(dev, generic_cb, msg);
+ if (err < 0)
+ return btd_error_failed(msg, strerror(-err));
+
+ dbus_message_ref(msg);
+
+ return NULL;
+}
+
+int source_connect(struct audio_device *dev, audio_device_cb cb, void *data)
+{
struct source *source = dev->source;
struct pending_request *pending;

if (!source->session)
source->session = avdtp_get(&dev->src, &dev->dst);

- if (!source->session)
- return btd_error_failed(msg, "Unable to get a session");
+ if (!source->session) {
+ DBG("Unable to get a session");
+ return -EIO;
+ }

if (source->connect || source->disconnect)
- return btd_error_busy(msg);
+ return -EBUSY;

if (source->stream_state >= AVDTP_STATE_OPEN)
- return btd_error_already_connected(msg);
+ return -EALREADY;

- if (!source_setup_stream(source, NULL))
- return btd_error_failed(msg, "Failed to create a stream");
+ if (!source_setup_stream(source, NULL)) {
+ DBG("Failed to create a stream");
+ return -EIO;
+ }

dev->auto_connect = FALSE;

pending = source->connect;
-
- pending->msg = dbus_message_ref(msg);
+ pending->cb = cb;
+ pending->cb_data = data;

DBG("stream creation in progress");

- return NULL;
+ return 0;
}

static DBusMessage *local_disconnect(DBusConnection *conn,
DBusMessage *msg, void *data)
{
+ struct audio_device *dev = data;
+ int err;
+
+ err = source_disconnect(dev, generic_cb, msg);
+ if (err < 0)
+ return btd_error_failed(msg, strerror(-err));
+
+ dbus_message_ref(msg);
+
+ return NULL;
+}
+
+int source_disconnect(struct audio_device *dev, audio_device_cb cb, void *data)
+{
struct audio_device *device = data;
struct source *source = device->source;
struct pending_request *pending;
int err;

if (!source->session)
- return btd_error_not_connected(msg);
+ return -ENOTCONN;

if (source->connect || source->disconnect)
- return btd_error_busy(msg);
+ return -EBUSY;

- if (source->stream_state < AVDTP_STATE_OPEN) {
- DBusMessage *reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
- avdtp_unref(source->session);
- source->session = NULL;
- return reply;
- }
+ if (source->stream_state < AVDTP_STATE_OPEN)
+ return -ENOTCONN;

err = avdtp_close(source->session, source->stream, FALSE);
if (err < 0)
- return btd_error_failed(msg, strerror(-err));
+ return err;

pending = g_new0(struct pending_request, 1);
- pending->msg = dbus_message_ref(msg);
+ pending->cb = cb;
+ pending->cb_data = data;
source->disconnect = pending;

- return NULL;
+ return 0;
}

static DBusMessage *local_get_properties(DBusConnection *conn,
@@ -504,10 +524,10 @@ static void source_free(struct audio_device *dev)
avdtp_unref(source->session);

if (source->connect)
- pending_request_free(dev, source->connect);
+ pending_request_free(dev, source->connect, -ECANCELED);

if (source->disconnect)
- pending_request_free(dev, source->disconnect);
+ pending_request_free(dev, source->disconnect, -ECANCELED);

if (source->retry_id)
g_source_remove(source->retry_id);
diff --git a/audio/source.h b/audio/source.h
index 695bded..dadb392 100644
--- a/audio/source.h
+++ b/audio/source.h
@@ -44,6 +44,8 @@ struct source *source_init(struct audio_device *dev);
void source_unregister(struct audio_device *dev);
gboolean source_is_active(struct audio_device *dev);
source_state_t source_get_state(struct audio_device *dev);
+int source_connect(struct audio_device *dev, audio_device_cb cb, void *data);
+int source_disconnect(struct audio_device *dev, audio_device_cb cb, void *data);
gboolean source_new_stream(struct audio_device *dev, struct avdtp *session,
struct avdtp_stream *stream);
gboolean source_setup_stream(struct source *source, struct avdtp *session);
--
1.7.11.7


2012-10-19 15:39:24

by Mikel Astiz

[permalink] [raw]
Subject: [RFC v0 07/15] audio: Trivial function rename

From: Mikel Astiz <[email protected]>

Use the local_ name prefix for local functions implementing the D-Bus
API.
---
audio/sink.c | 12 ++++++------
audio/source.c | 12 ++++++------
2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/audio/sink.c b/audio/sink.c
index 2e63579..b9e4fe0 100644
--- a/audio/sink.c
+++ b/audio/sink.c
@@ -390,7 +390,7 @@ gboolean sink_setup_stream(struct sink *sink, struct avdtp *session)
return TRUE;
}

-static DBusMessage *sink_connect(DBusConnection *conn,
+static DBusMessage *local_connect(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct audio_device *dev = data;
@@ -423,7 +423,7 @@ static DBusMessage *sink_connect(DBusConnection *conn,
return NULL;
}

-static DBusMessage *sink_disconnect(DBusConnection *conn,
+static DBusMessage *local_disconnect(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct audio_device *device = data;
@@ -457,7 +457,7 @@ static DBusMessage *sink_disconnect(DBusConnection *conn,
return NULL;
}

-static DBusMessage *sink_get_properties(DBusConnection *conn,
+static DBusMessage *local_get_properties(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct audio_device *device = data;
@@ -489,11 +489,11 @@ static DBusMessage *sink_get_properties(DBusConnection *conn,
}

static const GDBusMethodTable sink_methods[] = {
- { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, sink_connect) },
- { GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL, sink_disconnect) },
+ { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, local_connect) },
+ { GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL, local_disconnect) },
{ GDBUS_METHOD("GetProperties",
NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
- sink_get_properties) },
+ local_get_properties) },
{ }
};

diff --git a/audio/source.c b/audio/source.c
index 1d0c74a..04971d9 100644
--- a/audio/source.c
+++ b/audio/source.c
@@ -379,7 +379,7 @@ gboolean source_setup_stream(struct source *source, struct avdtp *session)
return TRUE;
}

-static DBusMessage *source_connect(DBusConnection *conn,
+static DBusMessage *local_connect(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct audio_device *dev = data;
@@ -412,7 +412,7 @@ static DBusMessage *source_connect(DBusConnection *conn,
return NULL;
}

-static DBusMessage *source_disconnect(DBusConnection *conn,
+static DBusMessage *local_disconnect(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct audio_device *device = data;
@@ -446,7 +446,7 @@ static DBusMessage *source_disconnect(DBusConnection *conn,
return NULL;
}

-static DBusMessage *source_get_properties(DBusConnection *conn,
+static DBusMessage *local_get_properties(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct audio_device *device = data;
@@ -478,11 +478,11 @@ static DBusMessage *source_get_properties(DBusConnection *conn,
}

static const GDBusMethodTable source_methods[] = {
- { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, source_connect) },
- { GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL, source_disconnect) },
+ { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, local_connect) },
+ { GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL, local_disconnect) },
{ GDBUS_METHOD("GetProperties",
NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
- source_get_properties) },
+ local_get_properties) },
{ }
};

--
1.7.11.7


2012-10-19 15:39:23

by Mikel Astiz

[permalink] [raw]
Subject: [RFC v0 06/15] audio: Split A2DP into three btd_profile

From: Mikel Astiz <[email protected]>

Merging the three audio profiles (AVDTP, A2DP sink and A2DP source)
into one was convenient in the past was doesn't fit very well the new
btd_profile approach. The split is also more consistent with the
approach of the HFP/HSP profile.
---
audio/a2dp.c | 88 ++++++++++++++++++++++-------------------------
audio/a2dp.h | 4 ++-
audio/manager.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++---------
3 files changed, 133 insertions(+), 64 deletions(-)

diff --git a/audio/a2dp.c b/audio/a2dp.c
index 7799420..6bfc8c2 100644
--- a/audio/a2dp.c
+++ b/audio/a2dp.c
@@ -1167,73 +1167,67 @@ static struct a2dp_server *find_server(GSList *list, const bdaddr_t *src)
return NULL;
}

-int a2dp_register(const bdaddr_t *src, GKeyFile *config)
+int a2dp_server_register(const bdaddr_t *src, GKeyFile *config)
{
- gboolean source = TRUE, sink = FALSE;
gboolean delay_reporting = FALSE;
- char *str;
- GError *err = NULL;
struct a2dp_server *server;
+ int av_err;

- if (!config)
- goto proceed;
+ server = find_server(servers, src);
+ if (server)
+ return 0;

- str = g_key_file_get_string(config, "General", "Enable", &err);
+ server = g_new0(struct a2dp_server, 1);

- if (err) {
- DBG("audio.conf: %s", err->message);
- g_clear_error(&err);
- } else {
- if (strstr(str, "Sink"))
- source = TRUE;
- if (strstr(str, "Source"))
- sink = TRUE;
- g_free(str);
+ av_err = avdtp_init(src, config, &server->version);
+ if (av_err < 0) {
+ g_free(server);
+ return av_err;
}

- str = g_key_file_get_string(config, "General", "Disable", &err);
+ bacpy(&server->src, src);
+ servers = g_slist_append(servers, server);

- if (err) {
- DBG("audio.conf: %s", err->message);
- g_clear_error(&err);
- } else {
- if (strstr(str, "Sink"))
- source = FALSE;
- if (strstr(str, "Source"))
- sink = FALSE;
- g_free(str);
- }
+ if (config)
+ delay_reporting = g_key_file_get_boolean(config, "A2DP",
+ "DelayReporting", NULL);

-proceed:
+ if (delay_reporting)
+ server->version = 0x0103;
+ else
+ server->version = 0x0102;
+
+ return 0;
+}
+
+int a2dp_source_register(const bdaddr_t *src, GKeyFile *config)
+{
+ struct a2dp_server *server;

server = find_server(servers, src);
if (!server) {
- int av_err;
+ DBG("AVDTP not registered");
+ return -EPROTONOSUPPORT;

- server = g_new0(struct a2dp_server, 1);
+ }

- av_err = avdtp_init(src, config, &server->version);
- if (av_err < 0) {
- g_free(server);
- return av_err;
- }
+ server->source_enabled = TRUE;

- bacpy(&server->src, src);
- servers = g_slist_append(servers, server);
- }
+ return 0;
+}

- if (config)
- delay_reporting = g_key_file_get_boolean(config, "A2DP",
- "DelayReporting", NULL);
+int a2dp_sink_register(const bdaddr_t *src, GKeyFile *config)
+{
+ struct a2dp_server *server;

- if (delay_reporting)
- server->version = 0x0103;
- else
- server->version = 0x0102;
+ server = find_server(servers, src);
+ if (!server) {
+ DBG("AVDTP not registered");
+ return -EPROTONOSUPPORT;

- server->source_enabled = source;
+ }

- server->sink_enabled = sink;
+ server->sink_enabled = TRUE;

return 0;
}
diff --git a/audio/a2dp.h b/audio/a2dp.h
index 736bc66..c471499 100644
--- a/audio/a2dp.h
+++ b/audio/a2dp.h
@@ -64,7 +64,9 @@ typedef void (*a2dp_stream_cb_t) (struct avdtp *session,
struct avdtp_error *err,
void *user_data);

-int a2dp_register(const bdaddr_t *src, GKeyFile *config);
+int a2dp_server_register(const bdaddr_t *src, GKeyFile *config);
+int a2dp_source_register(const bdaddr_t *src, GKeyFile *config);
+int a2dp_sink_register(const bdaddr_t *src, GKeyFile *config);
void a2dp_unregister(const bdaddr_t *src);

struct a2dp_sep *a2dp_add_sep(const bdaddr_t *src, uint8_t type,
diff --git a/audio/manager.c b/audio/manager.c
index 4ea61bf..c5d295e 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -722,7 +722,7 @@ static int ag_probe(struct btd_profile *p, struct btd_device *device,
return 0;
}

-static int a2dp_probe(struct btd_profile *p, struct btd_device *device,
+static int a2dp_source_probe(struct btd_profile *p, struct btd_device *device,
GSList *uuids)
{
struct audio_device *audio_dev;
@@ -733,13 +733,23 @@ static int a2dp_probe(struct btd_profile *p, struct btd_device *device,
return -1;
}

- if (g_slist_find_custom(uuids, A2DP_SINK_UUID, bt_uuid_strcmp) &&
- audio_dev->sink == NULL)
- audio_dev->sink = sink_init(audio_dev);
+ audio_dev->source = source_init(audio_dev);

- if (g_slist_find_custom(uuids, A2DP_SOURCE_UUID, bt_uuid_strcmp) &&
- audio_dev->source == NULL)
- audio_dev->source = source_init(audio_dev);
+ return 0;
+}
+
+static int a2dp_sink_probe(struct btd_profile *p, struct btd_device *device,
+ GSList *uuids)
+{
+ struct audio_device *audio_dev;
+
+ audio_dev = get_audio_dev(device);
+ if (!audio_dev) {
+ DBG("unable to get a device object");
+ return -1;
+ }
+
+ audio_dev->sink = sink_init(audio_dev);

return 0;
}
@@ -975,7 +985,7 @@ static int a2dp_server_probe(struct btd_profile *p,
if (!adp)
return -EINVAL;

- err = a2dp_register(adapter_get_address(adapter), config);
+ err = a2dp_server_register(adapter_get_address(adapter), config);
if (err < 0)
audio_adapter_unref(adp);

@@ -998,6 +1008,40 @@ static void a2dp_server_remove(struct btd_profile *p,
audio_adapter_unref(adp);
}

+static int a2dp_source_server_probe(struct btd_profile *p,
+ struct btd_adapter *adapter)
+{
+ struct audio_adapter *adp;
+ const gchar *path = adapter_get_path(adapter);
+
+ DBG("path %s", path);
+
+ adp = audio_adapter_get(adapter);
+ if (!adp)
+ return -EINVAL;
+
+ audio_adapter_unref(adp); /* Referenced by a2dp server */
+
+ return a2dp_source_register(adapter_get_address(adapter), config);
+}
+
+static int a2dp_sink_server_probe(struct btd_profile *p,
+ struct btd_adapter *adapter)
+{
+ struct audio_adapter *adp;
+ const gchar *path = adapter_get_path(adapter);
+
+ DBG("path %s", path);
+
+ adp = audio_adapter_get(adapter);
+ if (!adp)
+ return -EINVAL;
+
+ audio_adapter_unref(adp); /* Referenced by a2dp server */
+
+ return a2dp_sink_register(adapter_get_address(adapter), config);
+}
+
static int avrcp_server_probe(struct btd_profile *p,
struct btd_adapter *adapter)
{
@@ -1090,18 +1134,35 @@ static struct btd_profile gateway_profile = {
.adapter_remove = gateway_server_remove,
};

-static struct btd_profile a2dp_profile = {
- .name = "audio-a2dp",
+static struct btd_profile avdtp_profile = {
+ .name = "audio-avdtp",

- .remote_uuids = BTD_UUIDS(A2DP_SOURCE_UUID, A2DP_SINK_UUID,
- ADVANCED_AUDIO_UUID),
- .device_probe = a2dp_probe,
- .device_remove = audio_remove,
+ .remote_uuids = BTD_UUIDS(ADVANCED_AUDIO_UUID),

.adapter_probe = a2dp_server_probe,
.adapter_remove = a2dp_server_remove,
};

+static struct btd_profile a2dp_source_profile = {
+ .name = "audio-source",
+
+ .remote_uuids = BTD_UUIDS(A2DP_SOURCE_UUID),
+ .device_probe = a2dp_source_probe,
+ .device_remove = audio_remove,
+
+ .adapter_probe = a2dp_source_server_probe,
+};
+
+static struct btd_profile a2dp_sink_profile = {
+ .name = "audio-sink",
+
+ .remote_uuids = BTD_UUIDS(A2DP_SINK_UUID),
+ .device_probe = a2dp_sink_probe,
+ .device_remove = audio_remove,
+
+ .adapter_probe = a2dp_sink_server_probe,
+};
+
static struct btd_profile avrcp_profile = {
.name = "audio-avrcp",

@@ -1194,7 +1255,13 @@ proceed:
btd_profile_register(&gateway_profile);

if (enabled.source || enabled.sink)
- btd_profile_register(&a2dp_profile);
+ btd_profile_register(&avdtp_profile);
+
+ if (enabled.source)
+ btd_profile_register(&a2dp_source_profile);
+
+ if (enabled.sink)
+ btd_profile_register(&a2dp_sink_profile);

if (enabled.control)
btd_profile_register(&avrcp_profile);
@@ -1219,8 +1286,14 @@ void audio_manager_exit(void)
if (enabled.gateway)
btd_profile_unregister(&gateway_profile);

+ if (enabled.source)
+ btd_profile_unregister(&a2dp_source_profile);
+
+ if (enabled.sink)
+ btd_profile_unregister(&a2dp_sink_profile);
+
if (enabled.source || enabled.sink)
- btd_profile_unregister(&a2dp_profile);
+ btd_profile_unregister(&avdtp_profile);

if (enabled.control)
btd_profile_unregister(&avrcp_profile);
--
1.7.11.7


2012-10-19 15:39:22

by Mikel Astiz

[permalink] [raw]
Subject: [RFC v0 05/15] network: Add network .connect and .disconnect

From: Mikel Astiz <[email protected]>

Add the btd_profile hooks to connect and disconnect all three network
roles.
---
profiles/network/manager.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 99 insertions(+)

diff --git a/profiles/network/manager.c b/profiles/network/manager.c
index eda0bbe..87d263a 100644
--- a/profiles/network/manager.c
+++ b/profiles/network/manager.c
@@ -47,6 +47,12 @@

static gboolean conf_security = TRUE;

+struct connect_req {
+ struct btd_device *device;
+ struct btd_profile *profile;
+ btd_profile_cb cb;
+};
+
static void read_config(const char *file)
{
GKeyFile *keyfile;
@@ -73,6 +79,57 @@ done:
conf_security ? "true" : "false");
}

+static void connect_profile_cb(struct btd_device *device, int err,
+ const char *pdev, void *data)
+{
+ struct connect_req *req = data;
+
+ req->cb(req->profile, req->device, err);
+
+ g_free(req);
+}
+
+static int connect_profile(struct btd_device *dev, struct btd_profile *profile,
+ uint16_t id, btd_profile_cb cb)
+{
+ struct connect_req *req;
+ int err;
+
+ DBG("path %s id %u", device_get_path(dev), id);
+
+ req = g_new0(struct connect_req, 1);
+ req->device = dev;
+ req->profile = profile;
+ req->cb = cb;
+
+ err = connection_connect(dev, BNEP_SVC_PANU, NULL, connect_profile_cb,
+ req);
+ if (err < 0) {
+ g_free(req);
+ return err;
+ }
+
+ return 0;
+}
+
+static int disconnect_profile(struct btd_device *dev,
+ struct btd_profile *profile,
+ uint16_t id, btd_profile_cb cb)
+{
+ int err;
+
+ DBG("path %s id %u", device_get_path(dev), id);
+
+ err = connection_disconnect(dev, id, NULL);
+ if (err < 0)
+ return err;
+
+ if (cb)
+ cb(profile, dev, 0);
+
+ return 0;
+}
+
static int panu_probe(struct btd_profile *p, struct btd_device *device,
GSList *uuids)
{
@@ -88,6 +145,18 @@ static void network_remove(struct btd_profile *p, struct btd_device *device)
connection_unregister(device);
}

+static int panu_connect(struct btd_device *dev, struct btd_profile *profile,
+ btd_profile_cb cb)
+{
+ return connect_profile(dev, profile, BNEP_SVC_PANU, cb);
+}
+
+static int panu_disconnect(struct btd_device *dev, struct btd_profile *profile,
+ btd_profile_cb cb)
+{
+ return disconnect_profile(dev, profile, BNEP_SVC_PANU, cb);
+}
+
static int panu_server_probe(struct btd_profile *p, struct btd_adapter *adapter)
{
const gchar *path = adapter_get_path(adapter);
@@ -115,6 +184,18 @@ static int gn_probe(struct btd_profile *p, struct btd_device *device,
return connection_register(device, BNEP_SVC_GN);
}

+static int gn_connect(struct btd_device *dev, struct btd_profile *profile,
+ btd_profile_cb cb)
+{
+ return connect_profile(dev, profile, BNEP_SVC_GN, cb);
+}
+
+static int gn_disconnect(struct btd_device *dev, struct btd_profile *profile,
+ btd_profile_cb cb)
+{
+ return disconnect_profile(dev, profile, BNEP_SVC_GN, cb);
+}
+
static int gn_server_probe(struct btd_profile *p, struct btd_adapter *adapter)
{
const gchar *path = adapter_get_path(adapter);
@@ -142,6 +223,18 @@ static int nap_probe(struct btd_profile *p, struct btd_device *device,
return connection_register(device, BNEP_SVC_NAP);
}

+static int nap_connect(struct btd_device *dev, struct btd_profile *profile,
+ btd_profile_cb cb)
+{
+ return connect_profile(dev, profile, BNEP_SVC_NAP, cb);
+}
+
+static int nap_disconnect(struct btd_device *dev, struct btd_profile *profile,
+ btd_profile_cb cb)
+{
+ return disconnect_profile(dev, profile, BNEP_SVC_NAP, cb);
+}
+
static int nap_server_probe(struct btd_profile *p, struct btd_adapter *adapter)
{
const gchar *path = adapter_get_path(adapter);
@@ -166,6 +259,8 @@ static struct btd_profile panu_profile = {
.remote_uuids = BTD_UUIDS(PANU_UUID),
.device_probe = panu_probe,
.device_remove = network_remove,
+ .connect = panu_connect,
+ .disconnect = panu_disconnect,
.adapter_probe = panu_server_probe,
.adapter_remove = panu_server_remove,
};
@@ -175,6 +270,8 @@ static struct btd_profile gn_profile = {
.remote_uuids = BTD_UUIDS(GN_UUID),
.device_probe = gn_probe,
.device_remove = network_remove,
+ .connect = gn_connect,
+ .disconnect = gn_disconnect,
.adapter_probe = gn_server_probe,
.adapter_remove = gn_server_remove,
};
@@ -184,6 +281,8 @@ static struct btd_profile nap_profile = {
.remote_uuids = BTD_UUIDS(NAP_UUID),
.device_probe = nap_probe,
.device_remove = network_remove,
+ .connect = nap_connect,
+ .disconnect = nap_disconnect,
.adapter_probe = nap_server_probe,
.adapter_remove = nap_server_remove,
};
--
1.7.11.7


2012-10-19 15:39:21

by Mikel Astiz

[permalink] [raw]
Subject: [RFC v0 04/15] network: Split Network into three btd_profile

From: Mikel Astiz <[email protected]>

Split the possible roles into three different btd_profile instances, one
role each, in accordance with the rest of the existing profiles.
---
profiles/network/manager.c | 105 +++++++++++++++++++++++++++++++++++++--------
1 file changed, 86 insertions(+), 19 deletions(-)

diff --git a/profiles/network/manager.c b/profiles/network/manager.c
index fe3324b..eda0bbe 100644
--- a/profiles/network/manager.c
+++ b/profiles/network/manager.c
@@ -73,19 +73,12 @@ done:
conf_security ? "true" : "false");
}

-static int network_probe(struct btd_profile *p, struct btd_device *device,
+static int panu_probe(struct btd_profile *p, struct btd_device *device,
GSList *uuids)
{
DBG("path %s", device_get_path(device));

- if (g_slist_find_custom(uuids, PANU_UUID, bt_uuid_strcmp))
- connection_register(device, BNEP_SVC_PANU);
- if (g_slist_find_custom(uuids, GN_UUID, bt_uuid_strcmp))
- connection_register(device, BNEP_SVC_GN);
- if (g_slist_find_custom(uuids, NAP_UUID, bt_uuid_strcmp))
- connection_register(device, BNEP_SVC_NAP);
-
- return 0;
+ return connection_register(device, BNEP_SVC_PANU);
}

static void network_remove(struct btd_profile *p, struct btd_device *device)
@@ -95,17 +88,70 @@ static void network_remove(struct btd_profile *p, struct btd_device *device)
connection_unregister(device);
}

-static int network_server_probe(struct btd_profile *p,
+static int panu_server_probe(struct btd_profile *p, struct btd_adapter *adapter)
+{
+ const gchar *path = adapter_get_path(adapter);
+
+ DBG("path %s", path);
+
+ return server_register(adapter, BNEP_SVC_PANU);
+}
+
+static void panu_server_remove(struct btd_profile *p,
+ struct btd_adapter *adapter)
+{
+ const gchar *path = adapter_get_path(adapter);
+
+ DBG("path %s", path);
+
+ server_unregister(adapter, BNEP_SVC_PANU);
+}
+
+static int gn_probe(struct btd_profile *p, struct btd_device *device,
+ GSList *uuids)
+{
+ DBG("path %s", device_get_path(device));
+
+ return connection_register(device, BNEP_SVC_GN);
+}
+
+static int gn_server_probe(struct btd_profile *p, struct btd_adapter *adapter)
+{
+ const gchar *path = adapter_get_path(adapter);
+
+ DBG("path %s", path);
+
+ return server_register(adapter, BNEP_SVC_GN);
+}
+
+static void gn_server_remove(struct btd_profile *p,
struct btd_adapter *adapter)
{
const gchar *path = adapter_get_path(adapter);

DBG("path %s", path);

+ server_unregister(adapter, BNEP_SVC_GN);
+}
+
+static int nap_probe(struct btd_profile *p, struct btd_device *device,
+ GSList *uuids)
+{
+ DBG("path %s", device_get_path(device));
+
+ return connection_register(device, BNEP_SVC_NAP);
+}
+
+static int nap_server_probe(struct btd_profile *p, struct btd_adapter *adapter)
+{
+ const gchar *path = adapter_get_path(adapter);
+
+ DBG("path %s", path);
+
return server_register(adapter, BNEP_SVC_NAP);
}

-static void network_server_remove(struct btd_profile *p,
+static void nap_server_remove(struct btd_profile *p,
struct btd_adapter *adapter)
{
const gchar *path = adapter_get_path(adapter);
@@ -115,14 +161,31 @@ static void network_server_remove(struct btd_profile *p,
server_unregister(adapter, BNEP_SVC_NAP);
}

-static struct btd_profile network_profile = {
- .name = "network",
- .remote_uuids = BTD_UUIDS(PANU_UUID, GN_UUID, NAP_UUID),
- .device_probe = network_probe,
+static struct btd_profile panu_profile = {
+ .name = "network-panu",
+ .remote_uuids = BTD_UUIDS(PANU_UUID),
+ .device_probe = panu_probe,
+ .device_remove = network_remove,
+ .adapter_probe = panu_server_probe,
+ .adapter_remove = panu_server_remove,
+};
+
+static struct btd_profile gn_profile = {
+ .name = "network-gn",
+ .remote_uuids = BTD_UUIDS(GN_UUID),
+ .device_probe = gn_probe,
.device_remove = network_remove,
+ .adapter_probe = gn_server_probe,
+ .adapter_remove = gn_server_remove,
+};

- .adapter_probe = network_server_probe,
- .adapter_remove = network_server_remove,
+static struct btd_profile nap_profile = {
+ .name = "network-nap",
+ .remote_uuids = BTD_UUIDS(NAP_UUID),
+ .device_probe = nap_probe,
+ .device_remove = network_remove,
+ .adapter_probe = nap_server_probe,
+ .adapter_remove = nap_server_remove,
};

int network_manager_init(void)
@@ -144,7 +207,9 @@ int network_manager_init(void)
if (server_init(conf_security) < 0)
return -1;

- btd_profile_register(&network_profile);
+ btd_profile_register(&panu_profile);
+ btd_profile_register(&gn_profile);
+ btd_profile_register(&nap_profile);

return 0;
}
@@ -153,7 +218,9 @@ void network_manager_exit(void)
{
server_exit();

- btd_profile_unregister(&network_profile);
+ btd_profile_unregister(&panu_profile);
+ btd_profile_unregister(&gn_profile);
+ btd_profile_unregister(&nap_profile);

bnep_cleanup();
}
--
1.7.11.7


2012-10-19 15:39:20

by Mikel Astiz

[permalink] [raw]
Subject: [RFC v0 03/15] network: Expose internal connection API

From: Mikel Astiz <[email protected]>

Separate the D-Bus code from the internal connection handling code,
exposing an internal API in case some internal codepath/plugin is
interested in using it.
---
profiles/network/connection.c | 148 ++++++++++++++++++++++++++++--------------
profiles/network/connection.h | 8 +++
2 files changed, 108 insertions(+), 48 deletions(-)

diff --git a/profiles/network/connection.c b/profiles/network/connection.c
index afa8a6b..abcbee8 100644
--- a/profiles/network/connection.c
+++ b/profiles/network/connection.c
@@ -64,11 +64,13 @@ struct network_peer {
};

struct network_conn {
- DBusMessage *msg;
+ btd_connection_cb cb;
+ void *cb_data;
char dev[16]; /* Interface name */
uint16_t id; /* Role: Service Class Identifier */
conn_state state;
GIOChannel *io;
+ char *owner; /* Connection initiator D-Bus client */
guint watch; /* Disconnect watch */
guint dc_id;
struct network_peer *peer;
@@ -141,10 +143,9 @@ static gboolean bnep_watchdog_cb(GIOChannel *chan, GIOCondition cond,
return FALSE;
}

-static void cancel_connection(struct network_conn *nc, const char *err_msg)
+static void cancel_connection(struct network_conn *nc, int err)
{
DBusConnection *conn = btd_get_dbus_connection();
- DBusMessage *reply;

if (nc->timeout_source > 0) {
g_source_remove(nc->timeout_source);
@@ -156,14 +157,8 @@ static void cancel_connection(struct network_conn *nc, const char *err_msg)
nc->watch = 0;
}

- if (nc->msg) {
- if (err_msg) {
- reply = btd_error_failed(nc->msg, err_msg);
- g_dbus_send_message(conn, reply);
- }
- dbus_message_unref(nc->msg);
- nc->msg = NULL;
- }
+ if (nc->cb)
+ nc->cb(nc->peer->device, err, NULL, nc->cb_data);

g_io_channel_shutdown(nc->io, TRUE, NULL);
g_io_channel_unref(nc->io);
@@ -180,7 +175,12 @@ static void connection_destroy(DBusConnection *conn, void *user_data)
bnep_if_down(nc->dev);
bnep_kill_connection(device_get_address(nc->peer->device));
} else if (nc->io)
- cancel_connection(nc, NULL);
+ cancel_connection(nc, -EIO);
+
+ if (nc->owner) {
+ g_free(nc->owner);
+ nc->owner = NULL;
+ }
}

static void disconnect_cb(struct btd_device *device, gboolean removal,
@@ -270,11 +270,8 @@ static gboolean bnep_setup_cb(GIOChannel *chan, GIOCondition cond,
pdev = nc->dev;
uuid = bnep_uuid(nc->id);

- g_dbus_send_reply(btd_get_dbus_connection(), nc->msg,
- DBUS_TYPE_STRING, &pdev,
- DBUS_TYPE_INVALID);
- dbus_message_unref(nc->msg);
- nc->msg = NULL;
+ if (nc->cb)
+ nc->cb(nc->peer->device, 0, pdev, nc->cb_data);

path = device_get_path(nc->peer->device);

@@ -303,7 +300,7 @@ static gboolean bnep_setup_cb(GIOChannel *chan, GIOCondition cond,
return FALSE;

failed:
- cancel_connection(nc, "bnep setup failed");
+ cancel_connection(nc, -EIO);

return FALSE;
}
@@ -349,7 +346,7 @@ static gboolean bnep_conn_req_to(gpointer user_data)
return TRUE;
}

- cancel_connection(nc, "bnep setup failed");
+ cancel_connection(nc, -ETIMEDOUT);

return FALSE;
}
@@ -393,32 +390,74 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer data)
return;

failed:
- cancel_connection(nc, err_msg);
+ cancel_connection(nc, -EIO);
+}
+
+static void local_connect_cb(struct btd_device *device, int err,
+ const char *pdev, void *data)
+{
+ DBusMessage *msg = data;
+ DBusMessage *reply;
+
+ if (err < 0) {
+ reply = btd_error_failed(msg, strerror(-err));
+ g_dbus_send_message(btd_get_dbus_connection(), reply);
+ dbus_message_unref(msg);
+ return;
+ }
+
+ g_dbus_send_reply(btd_get_dbus_connection(), msg,
+ DBUS_TYPE_STRING, &pdev,
+ DBUS_TYPE_INVALID);
+
+ dbus_message_unref(msg);
}

-/* Connect and initiate BNEP session */
static DBusMessage *local_connect(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct network_peer *peer = data;
- struct network_conn *nc;
const char *svc;
uint16_t id;
- GError *err = NULL;
- const bdaddr_t *src;
- const bdaddr_t *dst;
+ int err;

if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &svc,
DBUS_TYPE_INVALID) == FALSE)
return btd_error_invalid_args(msg);

id = bnep_service_id(svc);
+
+ err = connection_connect(peer->device, id, dbus_message_get_sender(msg),
+ local_connect_cb, msg);
+ if (err < 0)
+ return btd_error_failed(msg, strerror(-err));
+
+ dbus_message_ref(msg);
+
+ return NULL;
+}
+
+/* Connect and initiate BNEP session */
+int connection_connect(struct btd_device *device, uint16_t id,
+ const char *owner,
+ btd_connection_cb cb, void *data)
+{
+ struct network_peer *peer;
+ struct network_conn *nc;
+ GError *err = NULL;
+ const bdaddr_t *src;
+ const bdaddr_t *dst;
+
+ peer = find_peer(peers, device);
+ if (!peer)
+ return -ENOENT;
+
nc = find_connection(peer->connections, id);
if (!nc)
- return btd_error_not_supported(msg);
+ return -ENOTSUP;

if (nc->state != DISCONNECTED)
- return btd_error_already_connected(msg);
+ return -EALREADY;

src = adapter_get_address(device_get_adapter(peer->device));
dst = device_get_address(peer->device);
@@ -432,52 +471,65 @@ static DBusMessage *local_connect(DBusConnection *conn,
BT_IO_OPT_OMTU, BNEP_MTU,
BT_IO_OPT_IMTU, BNEP_MTU,
BT_IO_OPT_INVALID);
- if (!nc->io) {
- DBusMessage *reply;
- error("%s", err->message);
- reply = btd_error_failed(msg, err->message);
- g_error_free(err);
- return reply;
- }
+ if (!nc->io)
+ return -EIO;

nc->state = CONNECTING;
- nc->msg = dbus_message_ref(msg);
- nc->watch = g_dbus_add_disconnect_watch(conn,
- dbus_message_get_sender(msg),
- connection_destroy,
+ nc->owner = g_strdup(owner);
+
+ if (owner)
+ nc->watch = g_dbus_add_disconnect_watch(
+ btd_get_dbus_connection(),
+ owner, connection_destroy,
nc, NULL);

- return NULL;
+ return 0;
}

-static DBusMessage *connection_cancel(DBusConnection *conn,
- DBusMessage *msg, void *data)
+int connection_disconnect(struct btd_device *device, uint16_t id,
+ const char *caller)
{
- struct network_conn *nc = data;
- const char *owner = dbus_message_get_sender(nc->msg);
- const char *caller = dbus_message_get_sender(msg);
+ struct network_peer *peer;
+ struct network_conn *nc;
+
+ peer = find_peer(peers, device);
+ if (!peer)
+ return -ENOENT;
+
+ nc = find_connection(peer->connections, id);
+ if (!nc)
+ return -ENOTSUP;
+
+ if (nc->state == DISCONNECTED)
+ return 0;

- if (!g_str_equal(owner, caller))
- return btd_error_not_authorized(msg);
+ if (!g_str_equal(nc->owner, caller))
+ return -EPERM;

connection_destroy(NULL, nc);

- return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+ return 0;
}

static DBusMessage *local_disconnect(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct network_peer *peer = data;
+ const char *caller = dbus_message_get_sender(msg);
GSList *l;

for (l = peer->connections; l; l = l->next) {
struct network_conn *nc = l->data;
+ int err;

if (nc->state == DISCONNECTED)
continue;

- return connection_cancel(conn, msg, nc);
+ err = connection_disconnect(peer->device, nc->id, caller);
+ if (err < 0)
+ return btd_error_failed(msg, strerror(-err));
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}

return btd_error_not_connected(msg);
diff --git a/profiles/network/connection.h b/profiles/network/connection.h
index 50c0774..e67b0ec 100644
--- a/profiles/network/connection.h
+++ b/profiles/network/connection.h
@@ -21,5 +21,13 @@
*
*/

+typedef void (*btd_connection_cb)(struct btd_device *device, int err,
+ const char *pdev, void *data);
+
int connection_register(struct btd_device *device, uint16_t id);
void connection_unregister(struct btd_device *device);
+int connection_connect(struct btd_device *device, uint16_t id,
+ const char *owner,
+ btd_connection_cb cb, void *data);
+int connection_disconnect(struct btd_device *device, uint16_t id,
+ const char *caller);
--
1.7.11.7


2012-10-19 15:39:19

by Mikel Astiz

[permalink] [raw]
Subject: [RFC v0 02/15] network: Trivial function rename

From: Mikel Astiz <[email protected]>

Avoid the connection_ prefix for local functions implementing the D-Bus
API.
---
profiles/network/connection.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/profiles/network/connection.c b/profiles/network/connection.c
index 8564bca..afa8a6b 100644
--- a/profiles/network/connection.c
+++ b/profiles/network/connection.c
@@ -397,7 +397,7 @@ failed:
}

/* Connect and initiate BNEP session */
-static DBusMessage *connection_connect(DBusConnection *conn,
+static DBusMessage *local_connect(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct network_peer *peer = data;
@@ -465,7 +465,7 @@ static DBusMessage *connection_cancel(DBusConnection *conn,
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}

-static DBusMessage *connection_disconnect(DBusConnection *conn,
+static DBusMessage *local_disconnect(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct network_peer *peer = data;
@@ -483,7 +483,7 @@ static DBusMessage *connection_disconnect(DBusConnection *conn,
return btd_error_not_connected(msg);
}

-static DBusMessage *connection_get_properties(DBusConnection *conn,
+static DBusMessage *local_get_properties(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct network_peer *peer = data;
@@ -568,12 +568,12 @@ static const GDBusMethodTable connection_methods[] = {
{ GDBUS_ASYNC_METHOD("Connect",
GDBUS_ARGS({"uuid", "s"}),
GDBUS_ARGS({"interface", "s"}),
- connection_connect) },
+ local_connect) },
{ GDBUS_METHOD("Disconnect",
- NULL, NULL, connection_disconnect) },
+ NULL, NULL, local_disconnect) },
{ GDBUS_METHOD("GetProperties",
NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
- connection_get_properties) },
+ local_get_properties) },
{ }
};

--
1.7.11.7


2012-10-19 15:39:18

by Mikel Astiz

[permalink] [raw]
Subject: [RFC v0 01/15] network: Specify id while registering server

From: Mikel Astiz <[email protected]>

Only one type of server is being installed (BNEP_SVC_NAP), but the
server API actually supports having several of them. Therefore, it is
more accurate to specify BNEP_SVC_NAP in the manager's side.
---
profiles/network/manager.c | 4 ++--
profiles/network/server.c | 9 ++++-----
profiles/network/server.h | 4 ++--
3 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/profiles/network/manager.c b/profiles/network/manager.c
index aa564bd..fe3324b 100644
--- a/profiles/network/manager.c
+++ b/profiles/network/manager.c
@@ -102,7 +102,7 @@ static int network_server_probe(struct btd_profile *p,

DBG("path %s", path);

- return server_register(adapter);
+ return server_register(adapter, BNEP_SVC_NAP);
}

static void network_server_remove(struct btd_profile *p,
@@ -112,7 +112,7 @@ static void network_server_remove(struct btd_profile *p,

DBG("path %s", path);

- server_unregister(adapter);
+ server_unregister(adapter, BNEP_SVC_NAP);
}

static struct btd_profile network_profile = {
diff --git a/profiles/network/server.c b/profiles/network/server.c
index ccf6e69..7b4460d 100644
--- a/profiles/network/server.c
+++ b/profiles/network/server.c
@@ -766,7 +766,7 @@ static struct network_adapter *create_adapter(struct btd_adapter *adapter)
return na;
}

-int server_register(struct btd_adapter *adapter)
+int server_register(struct btd_adapter *adapter, uint16_t id)
{
struct network_adapter *na;
struct network_server *ns;
@@ -780,7 +780,7 @@ int server_register(struct btd_adapter *adapter)
adapters = g_slist_append(adapters, na);
}

- ns = find_server(na->servers, BNEP_SVC_NAP);
+ ns = find_server(na->servers, id);
if (ns)
return 0;

@@ -802,7 +802,7 @@ int server_register(struct btd_adapter *adapter)
}

bacpy(&ns->src, adapter_get_address(adapter));
- ns->id = BNEP_SVC_NAP;
+ ns->id = id;
ns->na = na;
ns->record_id = 0;
na->servers = g_slist_append(na->servers, ns);
@@ -812,11 +812,10 @@ int server_register(struct btd_adapter *adapter)
return 0;
}

-int server_unregister(struct btd_adapter *adapter)
+int server_unregister(struct btd_adapter *adapter, uint16_t id)
{
struct network_adapter *na;
struct network_server *ns;
- uint16_t id = BNEP_SVC_NAP;

na = find_adapter(adapters, adapter);
if (!na)
diff --git a/profiles/network/server.h b/profiles/network/server.h
index 4c3ab85..2edd342 100644
--- a/profiles/network/server.h
+++ b/profiles/network/server.h
@@ -23,5 +23,5 @@

int server_init(gboolean secure);
void server_exit(void);
-int server_register(struct btd_adapter *adapter);
-int server_unregister(struct btd_adapter *adapter);
+int server_register(struct btd_adapter *adapter, uint16_t id);
+int server_unregister(struct btd_adapter *adapter, uint16_t id);
--
1.7.11.7