Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH] Convert CreateDevice on test-device script to an asynchronous call
From: Claudio Takahasi @ 2010-12-09 19:42 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1291923166-30880-1-git-send-email-claudio.takahasi@openbossa.org>

Change required to test the scenario when the sender of a CreateDevice
request disconnects from the system bus. Current implementation is
blocking and it doesn't allow the user to cancel a request.
---
 test/test-device |   22 +++++++++++++++++++---
 1 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/test/test-device b/test/test-device
index a04ff35..828349c 100755
--- a/test/test-device
+++ b/test/test-device
@@ -1,11 +1,16 @@
 #!/usr/bin/python
 
+import gobject
+
 import sys
 import dbus
+import dbus.mainloop.glib
 import re
 from optparse import OptionParser, make_option
 
+dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
 bus = dbus.SystemBus()
+mainloop = gobject.MainLoop()
 
 manager = dbus.Interface(bus.get_object("org.bluez", "/"), "org.bluez.Manager")
 
@@ -48,13 +53,24 @@ if (args[0] == "list"):
 
 	sys.exit(0)
 
+def create_device_reply(device):
+	print "New device (%s)" % device
+	mainloop.quit()
+	sys.exit(0)
+
+def create_device_error(error):
+	print "Creating device failed: %s" % error
+	mainloop.quit()
+	sys.exit(1)
+
 if (args[0] == "create"):
 	if (len(args) < 2):
 		print "Need address parameter"
 	else:
-		device = adapter.CreateDevice(args[1])
-		print device
-	sys.exit(0)
+		adapter.CreateDevice(args[1],
+				reply_handler=create_device_reply,
+				error_handler=create_device_error)
+	mainloop.run()
 
 if (args[0] == "remove"):
 	if (len(args) < 2):
-- 
1.7.3.3


^ permalink raw reply related

* [PATCH] Convert CreateDevice on test-device script to an asynchronous call
From: Claudio Takahasi @ 2010-12-09 19:32 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi

Change required to test the scenario when the sender of a CreateDevice
or CreatePairedDevice request disconnects from the system bus.
---
 test/test-device |   22 +++++++++++++++++++---
 1 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/test/test-device b/test/test-device
index a04ff35..828349c 100755
--- a/test/test-device
+++ b/test/test-device
@@ -1,11 +1,16 @@
 #!/usr/bin/python
 
+import gobject
+
 import sys
 import dbus
+import dbus.mainloop.glib
 import re
 from optparse import OptionParser, make_option
 
+dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
 bus = dbus.SystemBus()
+mainloop = gobject.MainLoop()
 
 manager = dbus.Interface(bus.get_object("org.bluez", "/"), "org.bluez.Manager")
 
@@ -48,13 +53,24 @@ if (args[0] == "list"):
 
 	sys.exit(0)
 
+def create_device_reply(device):
+	print "New device (%s)" % device
+	mainloop.quit()
+	sys.exit(0)
+
+def create_device_error(error):
+	print "Creating device failed: %s" % error
+	mainloop.quit()
+	sys.exit(1)
+
 if (args[0] == "create"):
 	if (len(args) < 2):
 		print "Need address parameter"
 	else:
-		device = adapter.CreateDevice(args[1])
-		print device
-	sys.exit(0)
+		adapter.CreateDevice(args[1],
+				reply_handler=create_device_reply,
+				error_handler=create_device_error)
+	mainloop.run()
 
 if (args[0] == "remove"):
 	if (len(args) < 2):
-- 
1.7.3.3


^ permalink raw reply related

* Re: [PATCH] btusb: Fix log spamming due to autosuspend
From: Stefan Seyfried @ 2010-12-09 19:16 UTC (permalink / raw)
  To: Gustavo F. Padovan
  Cc: linux-bluetooth, Marcel Holtmann, gregkh, Stefan Seyfried,
	Oliver Neukum
In-Reply-To: <20101201174910.GA16125@vigoh>

Hi all,

On Wed, 1 Dec 2010 15:49:10 -0200
"Gustavo F. Padovan" <padovan@profusion.mobi> wrote:

> Hi Stefan,
> 
> * Stefan Seyfried <stefan.seyfried@googlemail.com> [2010-12-01 15:47:14 +0100]:

> > > > If a device is autosuspended an inability to resubmit URBs is
> > > > to be expected. Check the error code and only log real errors.
> > > > (Now that autosuspend is default enabled for btusb, those log
> > > > messages were happening all the time e.g. with a BT mouse)
> > > > 
> > > > Signed-off-by: Stefan Seyfried <seife+kernel@b1-systems.com>
> > > > Signed-off-by: Oliver Neukum <oneukum@suse.de>
> > > 
> > > we had a similar one some time ago, but I am fine with this one as well.
> > > Actually this one might be a bit better since it still keeps some
> > > errors.
> > > 
> > > Acked-by: Marcel Holtmann <marcel@holtmann.org>
> > 
> > Could you (or Gustavo) send it to Linus? It's pretty trivial, but the
> > messages are annoying and users will complain if they are still in 2.6.37
> > final.
> 
> I'll send it, applied to bluetooth-2.6 tree. Thanks.

unfortunately, it does not seem to make it into 2.6.37?
-- 
Stefan Seyfried

"Any ideas, John?"
"Well, surrounding them's out."

^ permalink raw reply

* Re: RFC: Allow Bluez to select flushable or non-flushable ACL packets with L2CAP_LM_RELIABLE
From: Nick Pelly @ 2010-12-09 16:55 UTC (permalink / raw)
  To: Andrei Emeltchenko
  Cc: Luiz Augusto von Dentz, Marcel Holtmann, linux-bluetooth
In-Reply-To: <AANLkTimPNHrnY4Xn-oqsOQac45Z_rSr1SZtV90cna+ey@mail.gmail.com>

On Thu, Dec 9, 2010 at 2:37 AM, Andrei Emeltchenko
<andrei.emeltchenko.news@gmail.com> wrote:
>
> Hi All,
>
> On Wed, Jun 16, 2010 at 5:15 PM, Nick Pelly <npelly@google.com> wrote:
> > On Wed, Jun 16, 2010 at 4:40 AM, Luiz Augusto von Dentz
> > <luiz.dentz@gmail.com> wrote:
> >> Hi,
> >>
> >> On Tue, Mar 9, 2010 at 11:45 PM, Marcel Holtmann <marcel@holtmann.org>=
 wrote:
> >>> Hi Nick,
> >>>
> >>>> >>> >> Right now Bluez always requests flushable ACL packets (but do=
es not
> >>>> >>> >> set a flush timeout, so effectively they are non-flushable):
> >>>> >>> >>
> >>>> >>> >> However it is desirable to use an ACL flush timeout on A2DP p=
ackets so
> >>>> >>> >> that if the ACL packets block for some reason then the LM can=
 flush
> >>>> >>> >> them to make room for newer packets.
> >>>> >>> >>
> >>>> >>> >> Is it reasonable for Bluez to use the 0x00 ACL packet boundar=
y flag by
> >>>> >>> >> default (non-flushable packet), and let userspace request flu=
shable
> >>>> >>> >> packets on A2DP L2CAP sockets with the socket option
> >>>> >>> >> L2CAP_LM_RELIABLE.
> >>>> >>> >
> >>>> >>> > the reliable option has a different meaning. It comes back fro=
m the old
> >>>> >>> > Bluetooth 1.1 qualification days where we had to tests on L2CA=
P that had
> >>>> >>> > to confirm that we can detect malformed packets and report the=
m. These
> >>>> >>> > days it is just fine to drop them.
> >>>> >>>
> >>>> >>> Got it, how about introducing
> >>>> >>>
> >>>> >>> #define L2CAP_LM_FLUSHABLE 0x0040
> >>>> >>
> >>>> >> that l2cap_sock_setsockopt_old() sets this didn't give you a hint=
 that
> >>>> >> we might wanna deprecate this socket options ;)
> >>>> >>
> >>>> >> I need to read up on the flushable stuff, but in the end it deser=
ves its
> >>>> >> own socket option. Also an ioctl() to actually trigger Enhanced f=
lush
> >>>> >> might be needed.
> >>>> >>
> >>>> >>> struct l2cap_pinfo {
> >>>> >>> =A0 =A0...
> >>>> >>> =A0 =A0__u8 flushable;
> >>>> >>> }
> >>>> >>
> >>>> >> Sure. In the long run we need to turn this into a bitmask. We are=
 just
> >>>> >> wasting memory here.
> >>>> >
> >>>> > Attached is an updated patch, that checks the LMP features bitmask
> >>>> > before using the new non-flushable packet type.
> >>>> >
> >>>> > I am still using L2CAP_LM_FLUSHABLE socket option in
> >>>> > l2cap_sock_setsockopt_old(), which I don't think you are happy wit=
h.
> >>>> > So how about a new option:
> >>>> >
> >>>> > SOL_L2CAP, L2CAP_ACL_FLUSH
> >>>> > which has a default value of 0, and can be set to 1 to make the AC=
L
> >>>> > data sent by this L2CAP socket flushable.
> >>>> >
> >>>> > In a later commit we would then add
> >>>> > SOL_ACL, ACL_FLUSH_TIMEOUT
> >>>> > That is used to set an automatic flush timeout for the ACL link on=
 a
> >>>> > L2CAP socket. Note that SOL_ACL is new.
> >>>> >
> >>>> > But maybe this is not what you had in mind, so I'm looking for you=
r
> >>>> > advice before I implement this.
> >>>>
> >>>> Attached an updated patch for 2.6.32 kernel. We've been using this
> >>>> patch successfully on production devices.
> >>>
> >>> can see anything wrong with that patch. However we need to use
> >>> SOL_BLUETOOTH for it of course. So we need to come up with something =
to
> >>> make this simple.
>
> Nick are you going to take Marcel comments? Otherwise I could take
> care about the patch as it seems that it might help in some
> situations.

I'm not actively working on this patch.

> >>> An additional change I like to see is to use flags for booleans like
> >>> flushable in the structures. Can you work on changing that.
> >>>
> >>> Also do we have decoding support for this in hcidump. It might be nic=
e
> >>> to include some really simple examples in the commit message.
>
> At least wireshark which I use understands those packets.
>
> >> I would like to play a little bit with this, so is there any missing u=
pdates?
> >
> > Nope, that is our most recent version.
>
> Nick, do you know headset which could help to hear the real
> difference? I was trying to use Sony DR-BT22 headset which has some
> issues with A2DP but the solution did not help much.

It becomes essential in non-ideal radio bandwidth conditions such as
single antenna wifi co-existence. We also had some headsets that
exacerbated the problem (presumably they had less logic to 'catch-up'
through late packets) but I can't remember off hand.

Nick

^ permalink raw reply

* Re: A2DP reconfigure with BMW Carkit (supporting multi streams) timeouts.
From: Johan Hedberg @ 2010-12-09 14:41 UTC (permalink / raw)
  To: roystonr; +Cc: linux-bluetooth, skrovvid, rshaffer
In-Reply-To: <3b53a90114d801b0adba526895deed74.squirrel@www.codeaurora.org>

[-- Attachment #1: Type: text/plain, Size: 1208 bytes --]

Hi Royston,

On Thu, Dec 09, 2010, roystonr@codeaurora.org wrote:
> Change expected:
> avdtp_get_seps should be able to provide the SEP of the one used in the
> AVDTP_CLOSE previously. But there weren't any previously closed streams
> then provide the SEP which is not in use (as done currently).
> 
> Kindly let us know whether our understanding is right and can this be a
> suspected cause of the issue seen. Correct if mistaken.

Sounds like that might be the cause. Have you experimented with patching
the bluez code to reuse the same SEP as was used for the Close? If not
I'd advice you to do that so we can be sure that a change to the ACP SEP
selection logic makes sense.

Right now the reconfiguration happens in audio/a2dp.c where there's a
setup->reconfigure flag to track if a new stream should be configured
after receiving close_ind. The a2dp_reconfigure function in a2dp.c is
responsible for selecting the remote SEP. Could you try the attached
(completely untested) patch to see if it helps? It stores the old remote
SEP in the setup structure when starting the Close procedure in which
case a2dp_reconfigure() shouldn't try to reselect a new remote SEP but
use the stored one instead.

Johan

[-- Attachment #2: acp_sep_selection.patch --]
[-- Type: text/x-diff, Size: 1602 bytes --]

diff --git a/audio/a2dp.c b/audio/a2dp.c
index b1e94d9..7ed84e9 100644
--- a/audio/a2dp.c
+++ b/audio/a2dp.c
@@ -2032,6 +2032,7 @@ unsigned int a2dp_config(struct avdtp *session, struct a2dp_sep *sep,
 				error("avdtp_close failed");
 				goto failed;
 			}
+			setup->rsep = avdtp_stream_get_remote_sep(tmp->stream);
 			break;
 		}
 
@@ -2061,6 +2062,7 @@ unsigned int a2dp_config(struct avdtp *session, struct a2dp_sep *sep,
 				error("avdtp_close failed");
 				goto failed;
 			}
+			setup->rsep = avdtp_stream_get_remote_sep(sep->stream);
 		}
 		break;
 	default:
diff --git a/audio/avdtp.c b/audio/avdtp.c
index 1683e7c..33178c3 100644
--- a/audio/avdtp.c
+++ b/audio/avdtp.c
@@ -3133,6 +3133,12 @@ gboolean avdtp_stream_has_capabilities(struct avdtp_stream *stream,
 	return TRUE;
 }
 
+struct avdtp_remote_sep *avdtp_stream_get_remote_sep(
+						struct avdtp_stream *stream)
+{
+	return avdtp_get_remote_sep(stream->session, stream->rseid);
+}
+
 gboolean avdtp_stream_get_transport(struct avdtp_stream *stream, int *sock,
 					uint16_t *imtu, uint16_t *omtu,
 					GSList **caps)
diff --git a/audio/avdtp.h b/audio/avdtp.h
index 9406fa7..5f37dc3 100644
--- a/audio/avdtp.h
+++ b/audio/avdtp.h
@@ -257,6 +257,8 @@ gboolean avdtp_stream_has_capability(struct avdtp_stream *stream,
 				struct avdtp_service_capability *cap);
 gboolean avdtp_stream_has_capabilities(struct avdtp_stream *stream,
 					GSList *caps);
+struct avdtp_remote_sep *avdtp_stream_get_remote_sep(
+						struct avdtp_stream *stream);
 
 unsigned int avdtp_add_state_cb(avdtp_session_state_cb cb, void *user_data);
 

^ permalink raw reply related

* Re: [PATCH v2] Fix compiler flags when CFLAGS is set in the environment
From: Johan Hedberg @ 2010-12-09 14:01 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <1291902098-20765-1-git-send-email-luiz.dentz@gmail.com>

Hi Luiz,

On Thu, Dec 09, 2010, Luiz Augusto von Dentz wrote:
> D_FILE_OFFSET_BITS need to be set even if CFLAGS is not empty
> ---
>  Makefile.am  |    2 +-
>  acinclude.m4 |    2 +-
>  2 files changed, 2 insertions(+), 2 deletions(-)

Pushed upstream. Thanks.

Johan

^ permalink raw reply

* Re: [PATCH] Check the security level on a per request base
From: Johan Hedberg @ 2010-12-09 14:00 UTC (permalink / raw)
  To: Bruna Moreira; +Cc: linux-bluetooth
In-Reply-To: <1291900153-8541-1-git-send-email-bruna.moreira@openbossa.org>

Hi Bruna,

On Thu, Dec 09, 2010, Bruna Moreira wrote:
> Check security level on attribute server on each request, and update the
> "encrypted" flag.
> ---
>  attrib/gattrib.c    |   13 +++++++++++++
>  attrib/gattrib.h    |    2 ++
>  src/attrib-server.c |    7 ++-----
>  3 files changed, 17 insertions(+), 5 deletions(-)

Pushed upstream. Thanks.

Johan

^ permalink raw reply

* A2DP reconfigure with BMW Carkit (supporting multi streams) timeouts.
From: roystonr @ 2010-12-09 13:54 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: skrovvid, rshaffer

Hi All,

During the interop tests with BMW Carkit using DUT (Device under Test)
running Bluez stack, we observe that A2DP reconfiguration timeouts.

Scenario:
1)	Connect A2DP from DUT
2)	Start streaming
3)	Power down the BMW carkit
4)	Power on the BMW carkit
5)	A2DP streaming not resuming.

>From the sniffer logs, firstly we observe that the BMW carkit supports
multiple stream endpoints whereas the DUT supports only one. We observe
that after powering on, the BMW carkit(CK) was initiating an inbound A2DP
connection there by configuring the stream (INT and ACP SEID were 1 for
set configuration). Later on we observe that the DUT tries to reconfigure
the stream by sending a AVDTP_CLOSE as the stream had capabilities
differing from the remote device (CK in this case). The BMW CK rightly
acknowledges the AVDTP_CLOSE (here ACP SEID = 1). Following this the DUT
sends a stream configuration with INT SEID as 1 and ACP SEID as 2. To this
the remote CK doesn't respond.

We suspect this behaviour because the set configuration lastly send from
the DUT after an AVDTP_CLOSE should have been with ACP SEID as 1 and not
2. As per our understanding of the code, 2 is used as the ACP SEID because
avdtp_get_seps returns the 1st not in use SEP from the list that was
contructed based on the device capabalities retreived by the DUT from the
remote CK. It is observed that the DISCOVER response from the remote CK
provided SEID 2 info before 1.

Change expected:
avdtp_get_seps should be able to provide the SEP of the one used in the
AVDTP_CLOSE previously. But there weren't any previously closed streams
then provide the SEP which is not in use (as done currently).

Kindly let us know whether our understanding is right and can this be a
suspected cause of the issue seen. Correct if mistaken.

Regards,
Royston Rodrigues





^ permalink raw reply

* [PATCH v2] Fix compiler flags when CFLAGS is set in the environment
From: Luiz Augusto von Dentz @ 2010-12-09 13:41 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.dentz-von@nokia.com>

D_FILE_OFFSET_BITS need to be set even if CFLAGS is not empty
---
 Makefile.am  |    2 +-
 acinclude.m4 |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 175747c..a317556 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -123,7 +123,7 @@ service_DATA = $(service_in_files:.service.in=.service)
 
 AM_CFLAGS = @OPENOBEX_CFLAGS@ @BLUEZ_CFLAGS@ @EBOOK_CFLAGS@ \
 			@GTHREAD_CFLAGS@ @GLIB_CFLAGS@ @DBUS_CFLAGS@ \
-			@LIBICAL_CFLAGS@ \
+			@LIBICAL_CFLAGS@ -D_FILE_OFFSET_BITS=64 \
 			-DOBEX_PLUGIN_BUILTIN -DPLUGINDIR=\""$(plugindir)"\"
 
 INCLUDES = -I$(builddir)/src -I$(srcdir)/src -I$(srcdir)/plugins \
diff --git a/acinclude.m4 b/acinclude.m4
index 3d1f511..4594073 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -12,7 +12,7 @@ AC_DEFUN([AC_PROG_CC_PIE], [
 
 AC_DEFUN([COMPILER_FLAGS], [
 	if (test "${CFLAGS}" = ""); then
-		CFLAGS="-Wall -O2 -D_FORTIFY_SOURCE=2 -D_FILE_OFFSET_BITS=64"
+		CFLAGS="-Wall -O2 -D_FORTIFY_SOURCE=2"
 	fi
 	if (test "$USE_MAINTAINER_MODE" = "yes"); then
 		CFLAGS+=" -Werror -Wextra"
-- 
1.7.1


^ permalink raw reply related

* [PATCH] Fix compiler flags when CFLAGS is set in the environment
From: Luiz Augusto von Dentz @ 2010-12-09 13:38 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.dentz-von@nokia.com>

D_FILE_OFFSET_BITS need to be set even if CFLAGS is not empty
---
 Makefile.am  |    4 ++--
 acinclude.m4 |    2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 175747c..fad4eb5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -123,8 +123,8 @@ service_DATA = $(service_in_files:.service.in=.service)
 
 AM_CFLAGS = @OPENOBEX_CFLAGS@ @BLUEZ_CFLAGS@ @EBOOK_CFLAGS@ \
 			@GTHREAD_CFLAGS@ @GLIB_CFLAGS@ @DBUS_CFLAGS@ \
-			@LIBICAL_CFLAGS@ \
-			-DOBEX_PLUGIN_BUILTIN -DPLUGINDIR=\""$(plugindir)"\"
+			@LIBICAL_CFLAGS@ -D_FILE_OFFSET_BITS=64 \
+			-DOBEX_PLUGIN_BUILTIN -DPLUGINDIR=\""$(plugindir)"\" \
 
 INCLUDES = -I$(builddir)/src -I$(srcdir)/src -I$(srcdir)/plugins \
 				-I$(srcdir)/gdbus -I$(srcdir)/gwobex \
diff --git a/acinclude.m4 b/acinclude.m4
index 3d1f511..4594073 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -12,7 +12,7 @@ AC_DEFUN([AC_PROG_CC_PIE], [
 
 AC_DEFUN([COMPILER_FLAGS], [
 	if (test "${CFLAGS}" = ""); then
-		CFLAGS="-Wall -O2 -D_FORTIFY_SOURCE=2 -D_FILE_OFFSET_BITS=64"
+		CFLAGS="-Wall -O2 -D_FORTIFY_SOURCE=2"
 	fi
 	if (test "$USE_MAINTAINER_MODE" = "yes"); then
 		CFLAGS+=" -Werror -Wextra"
-- 
1.7.1


^ permalink raw reply related

* [PATCH] Check the security level on a per request base
From: Bruna Moreira @ 2010-12-09 13:09 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bruna Moreira

Check security level on attribute server on each request, and update the
"encrypted" flag.
---
 attrib/gattrib.c    |   13 +++++++++++++
 attrib/gattrib.h    |    2 ++
 src/attrib-server.c |    7 ++-----
 3 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/attrib/gattrib.c b/attrib/gattrib.c
index 1083519..4ed29d9 100644
--- a/attrib/gattrib.c
+++ b/attrib/gattrib.c
@@ -32,6 +32,7 @@
 #include <bluetooth/sdp.h>
 
 #include "att.h"
+#include "btio.h"
 #include "gattrib.h"
 
 struct _GAttrib {
@@ -489,6 +490,18 @@ static gint event_cmp_by_id(gconstpointer a, gconstpointer b)
 	return evt->id - id;
 }
 
+gboolean g_attrib_is_encrypted(GAttrib *attrib)
+{
+	BtIOSecLevel sec_level;
+
+	if (!bt_io_get(attrib->io, BT_IO_L2CAP, NULL,
+			BT_IO_OPT_SEC_LEVEL, &sec_level,
+			BT_IO_OPT_INVALID))
+		return FALSE;
+
+	return sec_level > BT_IO_SEC_LOW;
+}
+
 gboolean g_attrib_unregister(GAttrib *attrib, guint id)
 {
 	struct event *evt;
diff --git a/attrib/gattrib.h b/attrib/gattrib.h
index 4306ca4..0940289 100644
--- a/attrib/gattrib.h
+++ b/attrib/gattrib.h
@@ -63,6 +63,8 @@ guint g_attrib_register(GAttrib *attrib, guint8 opcode,
 		GAttribNotifyFunc func, gpointer user_data,
 					GDestroyNotify notify);
 
+gboolean g_attrib_is_encrypted(GAttrib *attrib);
+
 gboolean g_attrib_unregister(GAttrib *attrib, guint id);
 gboolean g_attrib_unregister_all(GAttrib *attrib);
 
diff --git a/src/attrib-server.c b/src/attrib-server.c
index f2df853..18759e7 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -145,6 +145,8 @@ static uint8_t att_check_reqs(struct gatt_channel *channel, uint8_t opcode,
 	/* FIXME: currently, it is assumed an encrypted link is enough for
 	 * authentication. This will allow to enable the SMP negotiation once
 	 * it is on upstream kernel. */
+	if (!channel->encrypted)
+		channel->encrypted = g_attrib_is_encrypted(channel->attrib);
 	if (reqs == ATT_AUTHENTICATION && !channel->encrypted)
 		return ATT_ECODE_INSUFF_ENC;
 
@@ -700,7 +702,6 @@ static void connect_event(GIOChannel *io, GError *err, void *user_data)
 {
 	struct gatt_channel *channel;
 	GError *gerr = NULL;
-	int sec_level;
 
 	if (err) {
 		error("%s", err->message);
@@ -712,7 +713,6 @@ static void connect_event(GIOChannel *io, GError *err, void *user_data)
 	bt_io_get(io, BT_IO_L2CAP, &gerr,
 			BT_IO_OPT_SOURCE_BDADDR, &channel->src,
 			BT_IO_OPT_DEST_BDADDR, &channel->dst,
-			BT_IO_OPT_SEC_LEVEL, &sec_level,
 			BT_IO_OPT_INVALID);
 	if (gerr) {
 		error("bt_io_get: %s", gerr->message);
@@ -725,9 +725,6 @@ static void connect_event(GIOChannel *io, GError *err, void *user_data)
 	channel->attrib = g_attrib_new(io);
 	channel->mtu = ATT_DEFAULT_MTU;
 
-	/* FIXME: the security level needs to checked on every request. */
-	channel->encrypted = sec_level > BT_IO_SEC_LOW;
-
 	channel->id = g_attrib_register(channel->attrib, GATTRIB_ALL_EVENTS,
 				channel_handler, channel, NULL);
 
-- 
1.7.0.4


^ permalink raw reply related

* Re: [PATCH] ath3k-fw: Fix EEPROM radio table issue.
From: Bala Shanmugam @ 2010-12-09 12:01 UTC (permalink / raw)
  To: Shanmugamkamatchi Balashanmugam
  Cc: dwmw2@infradead.org, linux-bluetooth@vger.kernel.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <1291367907-3650-1-git-send-email-sbalashanmugam@atheros.com>

On 12/3/2010 2:48 PM, Shanmugamkamatchi Balashanmugam wrote:
> Updated PID value to 3005 for devices with
> sflash firmware.
>
> Signed-off-by: Bala Shanmugam<sbalashanmugam@atheros.com>
> ---
>   WHENCE     |    2 ++
>   ath3k-1.fw |  Bin 246804 ->  246804 bytes
>   2 files changed, 2 insertions(+), 0 deletions(-)
>
> diff --git a/WHENCE b/WHENCE
> index 907fe68..0e3468f 100644
> --- a/WHENCE
> +++ b/WHENCE
> @@ -1101,6 +1101,8 @@ Driver: ath3k - DFU Driver for Atheros bluetooth chipset AR3011
>   File: ath3k-1.fw
>   Info: v1.0
>
> +Fix EEPROM radio table issue and change PID to 3005
> +
>   Licence: Redistributable. See LICENCE.atheros_firmware for details
>
>   --------------------------------------------------------------------------
> diff --git a/ath3k-1.fw b/ath3k-1.fw
> index 4a5ffb8de898fab1595662742f287493689e2b3b..63aa9b9ad87d3d918e441d921ada9cad08687ae5 100644
> GIT binary patch
> delta 129491
>
David,

We have upstreamed the transport driver changes.
We need this firmware upstreamed soon for our chip to work.

Do you have any comments on this patch?

Regards,
Bala.

^ permalink raw reply

* Re: RFC: Allow Bluez to select flushable or non-flushable ACL packets with L2CAP_LM_RELIABLE
From: Andrei Emeltchenko @ 2010-12-09 10:37 UTC (permalink / raw)
  To: Nick Pelly; +Cc: Luiz Augusto von Dentz, Marcel Holtmann, linux-bluetooth
In-Reply-To: <AANLkTim9qOTdeWhU1H-ove2rPR4MlEyUmQZ3zUeS75K_@mail.gmail.com>

Hi All,

On Wed, Jun 16, 2010 at 5:15 PM, Nick Pelly <npelly@google.com> wrote:
> On Wed, Jun 16, 2010 at 4:40 AM, Luiz Augusto von Dentz
> <luiz.dentz@gmail.com> wrote:
>> Hi,
>>
>> On Tue, Mar 9, 2010 at 11:45 PM, Marcel Holtmann <marcel@holtmann.org> w=
rote:
>>> Hi Nick,
>>>
>>>> >>> >> Right now Bluez always requests flushable ACL packets (but does=
 not
>>>> >>> >> set a flush timeout, so effectively they are non-flushable):
>>>> >>> >>
>>>> >>> >> However it is desirable to use an ACL flush timeout on A2DP pac=
kets so
>>>> >>> >> that if the ACL packets block for some reason then the LM can f=
lush
>>>> >>> >> them to make room for newer packets.
>>>> >>> >>
>>>> >>> >> Is it reasonable for Bluez to use the 0x00 ACL packet boundary =
flag by
>>>> >>> >> default (non-flushable packet), and let userspace request flush=
able
>>>> >>> >> packets on A2DP L2CAP sockets with the socket option
>>>> >>> >> L2CAP_LM_RELIABLE.
>>>> >>> >
>>>> >>> > the reliable option has a different meaning. It comes back from =
the old
>>>> >>> > Bluetooth 1.1 qualification days where we had to tests on L2CAP =
that had
>>>> >>> > to confirm that we can detect malformed packets and report them.=
 These
>>>> >>> > days it is just fine to drop them.
>>>> >>>
>>>> >>> Got it, how about introducing
>>>> >>>
>>>> >>> #define L2CAP_LM_FLUSHABLE 0x0040
>>>> >>
>>>> >> that l2cap_sock_setsockopt_old() sets this didn't give you a hint t=
hat
>>>> >> we might wanna deprecate this socket options ;)
>>>> >>
>>>> >> I need to read up on the flushable stuff, but in the end it deserve=
s its
>>>> >> own socket option. Also an ioctl() to actually trigger Enhanced flu=
sh
>>>> >> might be needed.
>>>> >>
>>>> >>> struct l2cap_pinfo {
>>>> >>> =A0 =A0...
>>>> >>> =A0 =A0__u8 flushable;
>>>> >>> }
>>>> >>
>>>> >> Sure. In the long run we need to turn this into a bitmask. We are j=
ust
>>>> >> wasting memory here.
>>>> >
>>>> > Attached is an updated patch, that checks the LMP features bitmask
>>>> > before using the new non-flushable packet type.
>>>> >
>>>> > I am still using L2CAP_LM_FLUSHABLE socket option in
>>>> > l2cap_sock_setsockopt_old(), which I don't think you are happy with.
>>>> > So how about a new option:
>>>> >
>>>> > SOL_L2CAP, L2CAP_ACL_FLUSH
>>>> > which has a default value of 0, and can be set to 1 to make the ACL
>>>> > data sent by this L2CAP socket flushable.
>>>> >
>>>> > In a later commit we would then add
>>>> > SOL_ACL, ACL_FLUSH_TIMEOUT
>>>> > That is used to set an automatic flush timeout for the ACL link on a
>>>> > L2CAP socket. Note that SOL_ACL is new.
>>>> >
>>>> > But maybe this is not what you had in mind, so I'm looking for your
>>>> > advice before I implement this.
>>>>
>>>> Attached an updated patch for 2.6.32 kernel. We've been using this
>>>> patch successfully on production devices.
>>>
>>> can see anything wrong with that patch. However we need to use
>>> SOL_BLUETOOTH for it of course. So we need to come up with something to
>>> make this simple.

Nick are you going to take Marcel comments? Otherwise I could take
care about the patch as it seems that it might help in some
situations.

>>> An additional change I like to see is to use flags for booleans like
>>> flushable in the structures. Can you work on changing that.
>>>
>>> Also do we have decoding support for this in hcidump. It might be nice
>>> to include some really simple examples in the commit message.

At least wireshark which I use understands those packets.

>> I would like to play a little bit with this, so is there any missing upd=
ates?
>
> Nope, that is our most recent version.

Nick, do you know headset which could help to hear the real
difference? I was trying to use Sony DR-BT22 headset which has some
issues with A2DP but the solution did not help much.

Regards,
Andrei

^ permalink raw reply

* Re: [PATCH 0/3 v4] Cancel pending phonebook request
From: Johan Hedberg @ 2010-12-09 10:19 UTC (permalink / raw)
  To: Dmitriy Paliy; +Cc: linux-bluetooth
In-Reply-To: <1291889119-23915-1-git-send-email-dmitriy.paliy@nokia.com>

Hi Dmitriy,

On Thu, Dec 09, 2010, Dmitriy Paliy wrote:
> Structure context_query changed to query_context in phonebook-ebook.c
> comparing to previous submission, and phonebook_req_cancel changed to
> phonebook_req_finalize.
> 
> More comments added to phonebook.h.

Thanks for the update. All three patches have been pushed upstream.

Johan

^ permalink raw reply

* [PATCH 3/3 v4] Code clean-up: long, empty lines, indentation
From: Dmitriy Paliy @ 2010-12-09 10:05 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Dmitriy Paliy
In-Reply-To: <1291889119-23915-1-git-send-email-dmitriy.paliy@nokia.com>

Lines longer 80 symbols and empty lines removed. Indentation in
generate_response function corrected.
---
 plugins/pbap.c |   17 ++++++++---------
 1 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/plugins/pbap.c b/plugins/pbap.c
index 820e35c..3ebfbe8 100644
--- a/plugins/pbap.c
+++ b/plugins/pbap.c
@@ -273,8 +273,8 @@ static void query_result(const char *buffer, size_t bufsize, int vcards,
 	if (!pbap->obj->buffer)
 		pbap->obj->buffer = g_string_new_len(buffer, bufsize);
 	else
-		pbap->obj->buffer = g_string_append_len(pbap->obj->buffer, buffer,
-								bufsize);
+		pbap->obj->buffer = g_string_append_len(pbap->obj->buffer,
+							buffer,	bufsize);
 
 	obex_object_set_io_flags(pbap->obj, G_IO_IN, 0);
 }
@@ -418,9 +418,8 @@ static int generate_response(void *user_data)
 	 * only the reference for the "real" cache entry.
 	 */
 	sorted = sort_entries(pbap->cache.entries, pbap->params->order,
-			pbap->params->searchattrib,
-			(const char *) pbap->params->searchval);
-
+				pbap->params->searchattrib,
+				(const char *) pbap->params->searchval);
 	if (sorted == NULL)
 		return -ENOENT;
 
@@ -431,12 +430,12 @@ static int generate_response(void *user_data)
 	for (; l && max; l = l->next, max--) {
 		const struct cache_entry *entry = l->data;
 
-		g_string_append_printf(pbap->obj->buffer, VCARD_LISTING_ELEMENT,
-						entry->handle, entry->name);
+		g_string_append_printf(pbap->obj->buffer,
+			VCARD_LISTING_ELEMENT, entry->handle, entry->name);
 	}
 
-	pbap->obj->buffer = g_string_append(pbap->obj->buffer, VCARD_LISTING_END);
-
+	pbap->obj->buffer = g_string_append(pbap->obj->buffer,
+							VCARD_LISTING_END);
 	g_slist_free(sorted);
 
 	return 0;
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 2/3 v4] Add handing of backend pending request
From: Dmitriy Paliy @ 2010-12-09 10:05 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Dmitriy Paliy
In-Reply-To: <1291889119-23915-1-git-send-email-dmitriy.paliy@nokia.com>

Add phonebook_req_finalize function prototype in phonebook.h that
deallocates resources associated to asynchronous request, and
cancels the request if it is not completed. It unrefs pointer to
pending request if such is applicable.

It does the following, depending on phonebook backend:
- for phonebook-tracker.c backend driver, it cancels pending DBus call,
- for phonebook-dummy.c, it removes GSource with a given id,
- for phonebook-ebook.c, it cancels last, still running, asynchronous
operation.

The following modifcations are donein the code. Phonebook request
pointer is added in PBAP object and IRMC session data to provide
reference for pending call. Phonebook callbacks are updated in PBAP
and IRMC to unref request upon completion and clear pointers, if such
is applicable.

PBAP and IRMC are updated to cancel pending request, if any, when OBEX
object is closed.

Phonebook_pull, phonebook_get_entry, phonebook_create_cache functions
are updated to return void pointer to backend specific request and error
code. All backend drivers updated accordingly to the modified API, which
are phonebook-tracker.c, phonebook-dummy.c, and phonebook-ebook.c, to be
specific.

In phonebook-tracker.c, query_tracker is updated to return pending DBus
call request. Allocated pending_reply and phonebook_data are destroyed
after call is unrefed. For this purpose new query_free_data function is
created.

Call is unrefed either if request succeeded or in
phonebook_req_finalize if terminated.

Such fix prevents obexd crash on unexpected OBEX session close. E.g.,
OBEX session is closed before reply comes from phonebook backend. In
that case, both session and object are destroyed, and dereferencing of
object in associated callback function causes crash.
---
 plugins/irmc.c              |   27 ++++++++---
 plugins/pbap.c              |   65 +++++++++++++++++++------
 plugins/phonebook-dummy.c   |   70 +++++++++++++++++++--------
 plugins/phonebook-ebook.c   |   96 +++++++++++++++++++++++++++++-------
 plugins/phonebook-tracker.c |  113 ++++++++++++++++++++++++++++++++----------
 plugins/phonebook.h         |   35 +++++++++++---
 6 files changed, 310 insertions(+), 96 deletions(-)

diff --git a/plugins/irmc.c b/plugins/irmc.c
index f7ad33b..a281341 100644
--- a/plugins/irmc.c
+++ b/plugins/irmc.c
@@ -110,6 +110,7 @@ struct irmc_session {
 	char did[DID_LEN];
 	char manu[DID_LEN];
 	char model[DID_LEN];
+	void *request;
 };
 
 #define IRMC_TARGET_SIZE 9
@@ -139,6 +140,11 @@ static void phonebook_size_result(const char *buffer, size_t bufsize,
 	DBG("vcards %d", vcards);
 
 	irmc->params->maxlistcount = vcards;
+
+	if (irmc->request) {
+		phonebook_req_finalize(irmc->request);
+		irmc->request = NULL;
+	}
 }
 
 static void query_result(const char *buffer, size_t bufsize, int vcards,
@@ -149,6 +155,11 @@ static void query_result(const char *buffer, size_t bufsize, int vcards,
 
 	DBG("bufsize %zu vcards %d missed %d", bufsize, vcards, missed);
 
+	if (irmc->request) {
+		phonebook_req_finalize(irmc->request);
+		irmc->request = NULL;
+	}
+
 	/* first add a 'owner' vcard */
 	if (!irmc->buffer)
 		irmc->buffer = g_string_new(owner_vcard);
@@ -210,11 +221,8 @@ static void *irmc_connect(struct obex_session *os, int *err)
 	param->maxlistcount = 0; /* to count the number of vcards... */
 	param->filter = 0x200085; /* UID TEL N VERSION */
 	irmc->params = param;
-	phonebook_pull("telecom/pb.vcf", irmc->params, phonebook_size_result,
-									irmc);
-
-	if (err)
-		*err = 0;
+	irmc->request = phonebook_pull("telecom/pb.vcf", irmc->params,
+					phonebook_size_result, irmc, err);
 
 	return irmc;
 }
@@ -298,8 +306,8 @@ static void *irmc_open_pb(const char *name, struct irmc_session *irmc,
 
 	if (!g_strcmp0(name, ".vcf")) {
 		/* how can we tell if the vcard count call already finished? */
-		ret = phonebook_pull("telecom/pb.vcf", irmc->params,
-							query_result, irmc);
+		irmc->request = phonebook_pull("telecom/pb.vcf", irmc->params,
+						query_result, irmc, &ret);
 		if (ret < 0) {
 			DBG("phonebook_pull failed...");
 			goto fail;
@@ -435,6 +443,11 @@ static int irmc_close(void *object)
 		irmc->buffer = NULL;
 	}
 
+	if (irmc->request) {
+		phonebook_req_finalize(irmc->request);
+		irmc->request = NULL;
+	}
+
 	return 0;
 }
 
diff --git a/plugins/pbap.c b/plugins/pbap.c
index 4086227..820e35c 100644
--- a/plugins/pbap.c
+++ b/plugins/pbap.c
@@ -147,6 +147,7 @@ struct pbap_session {
 struct pbap_object {
 	GString *buffer;
 	struct pbap_session *session;
+	void *request;
 };
 
 static const uint8_t PBAP_TARGET[TARGET_SIZE] = {
@@ -231,6 +232,11 @@ static void phonebook_size_result(const char *buffer, size_t bufsize,
 	struct aparam_header *hdr = (struct aparam_header *) aparam;
 	uint16_t phonebooksize;
 
+	if (pbap->obj->request) {
+		phonebook_req_finalize(pbap->obj->request);
+		pbap->obj->request = NULL;
+	}
+
 	if (vcards < 0)
 		vcards = 0;
 
@@ -254,6 +260,11 @@ static void query_result(const char *buffer, size_t bufsize, int vcards,
 
 	DBG("");
 
+	if (pbap->obj->request) {
+		phonebook_req_finalize(pbap->obj->request);
+		pbap->obj->request = NULL;
+	}
+
 	if (vcards <= 0) {
 		obex_object_set_io_flags(pbap->obj, G_IO_ERR, -ENOENT);
 		return;
@@ -466,8 +477,11 @@ static void cache_entry_done(void *user_data)
 		return;
 	}
 
-	ret = phonebook_get_entry(pbap->folder, id, pbap->params,
-						query_result, pbap);
+	/* Unref previous request, associated data will be freed. */
+	phonebook_req_finalize(pbap->obj->request);
+	/* Get new pointer to pending call. */
+	pbap->obj->request = phonebook_get_entry(pbap->folder, id,
+				pbap->params, query_result, pbap, &ret);
 	if (ret < 0)
 		obex_object_set_io_flags(pbap->obj, G_IO_ERR, ret);
 }
@@ -709,13 +723,15 @@ static struct obex_service_driver pbap = {
 	.chkput = pbap_chkput
 };
 
-static struct pbap_object *vobject_create(struct pbap_session *pbap)
+static struct pbap_object *vobject_create(struct pbap_session *pbap,
+								void *request)
 {
 	struct pbap_object *obj;
 
 	obj = g_new0(struct pbap_object, 1);
 	obj->session = pbap;
 	pbap->obj = obj;
+	obj->request = request;
 
 	return obj;
 }
@@ -726,6 +742,7 @@ static void *vobject_pull_open(const char *name, int oflag, mode_t mode,
 	struct pbap_session *pbap = context;
 	phonebook_cb cb;
 	int ret;
+	void *request;
 
 	DBG("name %s context %p maxlistcount %d", name, context,
 						pbap->params->maxlistcount);
@@ -745,11 +762,15 @@ static void *vobject_pull_open(const char *name, int oflag, mode_t mode,
 	else
 		cb = query_result;
 
-	ret = phonebook_pull(name, pbap->params, cb, pbap);
+	request = phonebook_pull(name, pbap->params, cb, pbap, &ret);
+
 	if (ret < 0)
 		goto fail;
 
-	return vobject_create(pbap);
+	if (err)
+		*err = 0;
+
+	return vobject_create(pbap, request);
 
 fail:
 	if (err)
@@ -770,6 +791,11 @@ static int vobject_close(void *object)
 	if (obj->buffer)
 		g_string_free(obj->buffer, TRUE);
 
+	if (obj->request) {
+		phonebook_req_finalize(obj->request);
+		obj->request = NULL;
+	}
+
 	g_free(obj);
 
 	return 0;
@@ -781,6 +807,7 @@ static void *vobject_list_open(const char *name, int oflag, mode_t mode,
 	struct pbap_session *pbap = context;
 	struct pbap_object *obj = NULL;
 	int ret;
+	void *request;
 
 	DBG("name %s context %p valid %d", name, context, pbap->cache.valid);
 
@@ -796,13 +823,15 @@ static void *vobject_list_open(const char *name, int oflag, mode_t mode,
 
 	/* PullvCardListing always get the contacts from the cache */
 
-	obj = vobject_create(pbap);
-
-	if (pbap->cache.valid)
+	if (pbap->cache.valid) {
+		obj = vobject_create(pbap, NULL);
 		ret = generate_response(pbap);
-	else
-		ret = phonebook_create_cache(name, cache_entry_notify,
-						cache_ready_notify, pbap);
+	} else {
+		request = phonebook_create_cache(name, cache_entry_notify,
+					cache_ready_notify, pbap, &ret);
+		if (ret == 0)
+			obj = vobject_create(pbap, request);
+	}
 	if (ret < 0)
 		goto fail;
 
@@ -828,6 +857,7 @@ static void *vobject_vcard_open(const char *name, int oflag, mode_t mode,
 	const char *id;
 	uint32_t handle;
 	int ret;
+	void *request;
 
 	DBG("name %s context %p valid %d", name, context, pbap->cache.valid);
 
@@ -843,8 +873,8 @@ static void *vobject_vcard_open(const char *name, int oflag, mode_t mode,
 
 	if (pbap->cache.valid == FALSE) {
 		pbap->find_handle = handle;
-		ret = phonebook_create_cache(pbap->folder, cache_entry_notify,
-						cache_entry_done, pbap);
+		request = phonebook_create_cache(pbap->folder,
+			cache_entry_notify, cache_entry_done, pbap, &ret);
 		goto done;
 	}
 
@@ -854,14 +884,17 @@ static void *vobject_vcard_open(const char *name, int oflag, mode_t mode,
 		goto fail;
 	}
 
-	ret = phonebook_get_entry(pbap->folder, id, pbap->params, query_result,
-									pbap);
+	request = phonebook_get_entry(pbap->folder, id, pbap->params,
+						query_result, pbap, &ret);
 
 done:
 	if (ret < 0)
 		goto fail;
 
-	return vobject_create(pbap);
+	if (err)
+		*err = 0;
+
+	return vobject_create(pbap, request);
 
 fail:
 	if (err)
diff --git a/plugins/phonebook-dummy.c b/plugins/phonebook-dummy.c
index 7c549fa..60b7640 100644
--- a/plugins/phonebook-dummy.c
+++ b/plugins/phonebook-dummy.c
@@ -447,11 +447,19 @@ done:
 	return relative;
 }
 
-int phonebook_pull(const char *name, const struct apparam_field *params,
-					phonebook_cb cb, void *user_data)
+void phonebook_req_finalize(void *request)
+{
+	guint id = GPOINTER_TO_INT(request);
+
+	g_source_remove(id);
+}
+
+void *phonebook_pull(const char *name, const struct apparam_field *params,
+				phonebook_cb cb, void *user_data, int *err)
 {
 	struct dummy_data *dummy;
 	char *filename, *folder;
+	guint ret;
 
 	/*
 	 * Main phonebook objects will be created dinamically based on the
@@ -463,14 +471,18 @@ int phonebook_pull(const char *name, const struct apparam_field *params,
 
 	if (!g_str_has_suffix(filename, ".vcf")) {
 		g_free(filename);
-		return -EBADR;
+		if (err)
+			*err = -EBADR;
+		return NULL;
 	}
 
 	folder = g_strndup(filename, strlen(filename) - 4);
 	g_free(filename);
 	if (!is_dir(folder)) {
 		g_free(folder);
-		return -ENOENT;
+		if (err)
+			*err = -ENOENT;
+		return NULL;
 	}
 
 	dummy = g_new0(struct dummy_data, 1);
@@ -480,26 +492,32 @@ int phonebook_pull(const char *name, const struct apparam_field *params,
 	dummy->folder = folder;
 	dummy->fd = -1;
 
-	g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, read_dir, dummy, dummy_free);
+	ret = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, read_dir, dummy,
+								dummy_free);
 
-	return 0;
+	if (err)
+		*err = 0;
+
+	return GINT_TO_POINTER(ret);
 }
 
-int phonebook_get_entry(const char *folder, const char *id,
-					const struct apparam_field *params,
-					phonebook_cb cb, void *user_data)
+void *phonebook_get_entry(const char *folder, const char *id,
+			const struct apparam_field *params, phonebook_cb cb,
+			void *user_data, int *err)
 {
 	struct dummy_data *dummy;
 	char *filename;
 	int fd;
+	guint ret;
 
 	filename = g_build_filename(root_folder, folder, id, NULL);
 
 	fd = open(filename, O_RDONLY);
 	if (fd < 0) {
-		int err = errno;
-		DBG("open(): %s(%d)", strerror(err), err);
-		return -ENOENT;
+		DBG("open(): %s(%d)", strerror(errno), errno);
+		if (err)
+			*err = -ENOENT;
+		return NULL;
 	}
 
 	dummy = g_new0(struct dummy_data, 1);
@@ -508,26 +526,32 @@ int phonebook_get_entry(const char *folder, const char *id,
 	dummy->apparams = params;
 	dummy->fd = fd;
 
-	g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, read_entry, dummy, dummy_free);
+	ret = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, read_entry, dummy,
+								dummy_free);
 
-	return 0;
+	if (err)
+		*err = 0;
+
+	return GINT_TO_POINTER(ret);
 }
 
-int phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
-		phonebook_cache_ready_cb ready_cb, void *user_data)
+void *phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
+		phonebook_cache_ready_cb ready_cb, void *user_data, int *err)
 {
 	struct cache_query *query;
 	char *foldername;
 	DIR *dp;
+	guint ret;
 
 	foldername = g_build_filename(root_folder, name, NULL);
 	dp = opendir(foldername);
 	g_free(foldername);
 
 	if (dp == NULL) {
-		int err = errno;
-		DBG("opendir(): %s(%d)", strerror(err), err);
-		return -ENOENT;
+		DBG("opendir(): %s(%d)", strerror(errno), errno);
+		if (err)
+			*err = -ENOENT;
+		return NULL;
 	}
 
 	query = g_new0(struct cache_query, 1);
@@ -536,7 +560,11 @@ int phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
 	query->user_data = user_data;
 	query->dp = dp;
 
-	g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, create_cache, query,
+	ret = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, create_cache, query,
 								query_free);
-	return 0;
+
+	if (err)
+		*err = 0;
+
+	return GINT_TO_POINTER(ret);
 }
diff --git a/plugins/phonebook-ebook.c b/plugins/phonebook-ebook.c
index 80398ef..70b9c02 100644
--- a/plugins/phonebook-ebook.c
+++ b/plugins/phonebook-ebook.c
@@ -45,7 +45,9 @@
 #define QUERY_NAME "(contains \"given_name\" \"%s\")"
 #define QUERY_PHONE "(contains \"phone\" \"%s\")"
 
+
 struct query_context {
+	gboolean completed;
 	const struct apparam_field *params;
 	phonebook_cb contacts_cb;
 	phonebook_entry_cb entry_cb;
@@ -142,6 +144,11 @@ static void ebookpull_cb(EBook *book, EBookStatus estatus, GList *contacts,
 	unsigned int count = 0, maxcount;
 	GList *l;
 
+	if (estatus == E_BOOK_ERROR_CANCELLED) {
+		error("E-Book operation was cancelled: status %d", estatus);
+		goto fail;
+	}
+
 	if (estatus != E_BOOK_ERROR_OK) {
 		error("E-Book query failed: status %d", estatus);
 		goto done;
@@ -178,10 +185,14 @@ static void ebookpull_cb(EBook *book, EBookStatus estatus, GList *contacts,
 
 
 done:
+	data->completed = TRUE;
 	data->contacts_cb(string->str, string->len, count, 0, data->user_data);
 
+fail:
 	g_string_free(string, TRUE);
-	g_free(data);
+
+	if (data->completed)
+		g_free(data);
 }
 
 static void ebook_entry_cb(EBook *book, EBookStatus estatus,
@@ -192,11 +203,17 @@ static void ebook_entry_cb(EBook *book, EBookStatus estatus,
 	char *vcard;
 	size_t len;
 
+	if (estatus == E_BOOK_ERROR_CANCELLED) {
+		error("E-Book operation was cancelled: status %d", estatus);
+		goto fail;
+	}
+
+	data->completed = TRUE;
+
 	if (estatus != E_BOOK_ERROR_OK) {
 		error("E-Book query failed: status %d", estatus);
 		data->contacts_cb(NULL, 0, 1, 0, data->user_data);
-		g_free(data);
-		return;
+		goto fail;
 	}
 
 	evcard = E_VCARD(contact);
@@ -209,7 +226,10 @@ static void ebook_entry_cb(EBook *book, EBookStatus estatus,
 	data->contacts_cb(vcard, len, 1, 0, data->user_data);
 
 	g_free(vcard);
-	g_free(data);
+
+fail:
+	if (data->completed)
+		g_free(data);
 }
 
 static char *evcard_name_attribute_to_string(EVCard *evcard)
@@ -248,6 +268,13 @@ static void cache_cb(EBook *book, EBookStatus estatus, GList *contacts,
 	struct query_context *data = user_data;
 	GList *l;
 
+	if (estatus == E_BOOK_ERROR_CANCELLED) {
+		error("E-Book operation was cancelled: status %d", estatus);
+		goto fail;
+	}
+
+	data->completed = TRUE;
+
 	if (estatus != E_BOOK_ERROR_OK) {
 		error("E-Book query failed: status %d", estatus);
 		goto done;
@@ -285,6 +312,10 @@ static void cache_cb(EBook *book, EBookStatus estatus, GList *contacts,
 	}
 done:
 	data->ready_cb(data->user_data);
+
+fail:
+	if (data->completed)
+		g_free(data);
 }
 
 int phonebook_init(void)
@@ -404,8 +435,21 @@ done:
 	return fullname;
 }
 
-int phonebook_pull(const char *name, const struct apparam_field *params,
-					phonebook_cb cb, void *user_data)
+void phonebook_req_finalize(void *request)
+{
+	struct query_context *data = request;
+
+	if (!data)
+		return;
+
+	if (!data->completed) {
+		data->completed = TRUE;
+		e_book_cancel_async_op(ebook, NULL);
+	}
+}
+
+void *phonebook_pull(const char *name, const struct apparam_field *params,
+				phonebook_cb cb, void *user_data, int *err)
 {
 	struct query_context *data;
 	EBookQuery *query;
@@ -421,12 +465,15 @@ int phonebook_pull(const char *name, const struct apparam_field *params,
 
 	e_book_query_unref(query);
 
-	return 0;
+	if (err)
+		*err = 0;
+
+	return data;
 }
 
-int phonebook_get_entry(const char *folder, const char *id,
-					const struct apparam_field *params,
-					phonebook_cb cb, void *user_data)
+void *phonebook_get_entry(const char *folder, const char *id,
+				const struct apparam_field *params,
+				phonebook_cb cb, void *user_data, int *err)
 {
 	struct query_context *data;
 
@@ -437,21 +484,29 @@ int phonebook_get_entry(const char *folder, const char *id,
 
 	if (e_book_async_get_contact(ebook, id, ebook_entry_cb, data)) {
 		g_free(data);
-		return -ENOENT;
+		if (err)
+			*err = -ENOENT;
+		return NULL;
 	}
 
-	return 0;
+	if (err)
+		*err = 0;
+
+	return data;
 }
 
-int phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
-			phonebook_cache_ready_cb ready_cb, void *user_data)
+void *phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
+		phonebook_cache_ready_cb ready_cb, void *user_data, int *err)
 {
 	struct query_context *data;
 	EBookQuery *query;
 	gboolean ret;
 
-	if (g_strcmp0("/telecom/pb", name) != 0)
-		return -ENOENT;
+	if (g_strcmp0("/telecom/pb", name) != 0) {
+		if (err)
+			*err = -ENOENT;
+		return NULL;
+	}
 
 	query = e_book_query_any_field_contains("");
 
@@ -464,8 +519,13 @@ int phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
 	e_book_query_unref(query);
 	if (ret != FALSE) {
 		g_free(data);
-		return -EFAULT;
+		if (err)
+			*err = -EFAULT;
+		return NULL;
 	}
 
-	return 0;
+	if (err)
+		*err = 0;
+
+	return data;
 }
diff --git a/plugins/phonebook-tracker.c b/plugins/phonebook-tracker.c
index cdc1008..0a023aa 100644
--- a/plugins/phonebook-tracker.c
+++ b/plugins/phonebook-tracker.c
@@ -807,6 +807,7 @@ struct pending_reply {
 	reply_list_foreach_t callback;
 	void *user_data;
 	int num_fields;
+	GDestroyNotify destroy;
 };
 
 struct contact_data {
@@ -996,11 +997,30 @@ done:
 	pending->callback(NULL, err, pending->user_data);
 
 	dbus_message_unref(reply);
+
+	/*
+	 * pending data is freed in query_free_data after call is unreffed.
+	 * Same holds for pending->user_data which is not freed in callback
+	 * but in query_free_data.
+	 */
+}
+
+static void query_free_data(void *user_data)
+{
+	struct pending_reply *pending = user_data;
+
+	if (!pending)
+		return;
+
+	if (pending->destroy)
+		pending->destroy(pending->user_data);
+
 	g_free(pending);
 }
 
-static int query_tracker(const char *query, int num_fields,
-				reply_list_foreach_t callback, void *user_data)
+static DBusPendingCall *query_tracker(const char *query, int num_fields,
+				reply_list_foreach_t callback, void *user_data,
+				GDestroyNotify destroy, int *err)
 {
 	struct pending_reply *pending;
 	DBusPendingCall *call;
@@ -1020,19 +1040,27 @@ static int query_tracker(const char *query, int num_fields,
 							-1) == FALSE) {
 		error("Could not send dbus message");
 		dbus_message_unref(msg);
-		return -EPERM;
+		if (err)
+			*err = -EPERM;
+		/* user_data is freed otherwise only if call was sent */
+		g_free(user_data);
+		return NULL;
 	}
 
 	pending = g_new0(struct pending_reply, 1);
 	pending->callback = callback;
 	pending->user_data = user_data;
 	pending->num_fields = num_fields;
+	pending->destroy = destroy;
 
-	dbus_pending_call_set_notify(call, query_reply, pending, NULL);
-	dbus_pending_call_unref(call);
+	dbus_pending_call_set_notify(call, query_reply, pending,
+							query_free_data);
 	dbus_message_unref(msg);
 
-	return 0;
+	if (err)
+		*err = 0;
+
+	return call;
 }
 
 static char *iso8601_utc_to_localtime(const char *datetime)
@@ -1245,7 +1273,7 @@ static void pull_contacts_size(char **reply, int num_fields, void *user_data)
 
 	if (num_fields < 0) {
 		data->cb(NULL, 0, num_fields, 0, data->user_data);
-		goto fail;
+		return;
 	}
 
 	if (reply != NULL) {
@@ -1255,8 +1283,11 @@ static void pull_contacts_size(char **reply, int num_fields, void *user_data)
 
 	data->cb(NULL, 0, data->index, 0, data->user_data);
 
-fail:
-	g_free(data);
+	/*
+	 * phonebook_data is freed in query_free_data after call is unreffed.
+	 * It is accessible by pointer from data (pending) associated to call.
+	 * Useful in cases when call was terminated.
+	 */
 }
 
 static void add_affiliation(char **field, const char *value)
@@ -1482,9 +1513,14 @@ done:
 	g_string_free(vcards, TRUE);
 fail:
 	g_slist_free(data->contacts);
-	g_free(data);
 	g_free(temp_id);
 	temp_id = NULL;
+
+	/*
+	 * phonebook_data is freed in query_free_data after call is unreffed.
+	 * It is accessible by pointer from data (pending) associated to call.
+	 * Useful in cases when call was terminated.
+	 */
 }
 
 static void add_to_cache(char **reply, int num_fields, void *user_data)
@@ -1529,7 +1565,11 @@ done:
 	if (num_fields <= 0)
 		cache->ready_cb(cache->user_data);
 
-	g_free(cache);
+	/*
+	 * cache is freed in query_free_data after call is unreffed.
+	 * It is accessible by pointer from data (pending) associated to call.
+	 * Useful in cases when call was terminated.
+	 */
 }
 
 int phonebook_init(void)
@@ -1617,8 +1657,20 @@ done:
 	return path;
 }
 
-int phonebook_pull(const char *name, const struct apparam_field *params,
-					phonebook_cb cb, void *user_data)
+void phonebook_req_finalize(void *request)
+{
+	struct DBusPendingCall *call = request;
+
+	DBG("");
+
+	if (!dbus_pending_call_get_completed(call))
+		dbus_pending_call_cancel(call);
+
+	dbus_pending_call_unref(call);
+}
+
+void *phonebook_pull(const char *name, const struct apparam_field *params,
+				phonebook_cb cb, void *user_data, int *err)
 {
 	struct phonebook_data *data;
 	const char *query;
@@ -1637,24 +1689,27 @@ int phonebook_pull(const char *name, const struct apparam_field *params,
 		pull_cb = pull_contacts;
 	}
 
-	if (query == NULL)
-		return -ENOENT;
+	if (query == NULL) {
+		if (err)
+			*err = -ENOENT;
+		return NULL;
+	}
 
 	data = g_new0(struct phonebook_data, 1);
 	data->params = params;
 	data->user_data = user_data;
 	data->cb = cb;
 
-	return query_tracker(query, col_amount, pull_cb, data);
+	return query_tracker(query, col_amount, pull_cb, data, g_free, err);
 }
 
-int phonebook_get_entry(const char *folder, const char *id,
-					const struct apparam_field *params,
-					phonebook_cb cb, void *user_data)
+void *phonebook_get_entry(const char *folder, const char *id,
+				const struct apparam_field *params,
+				phonebook_cb cb, void *user_data, int *err)
 {
 	struct phonebook_data *data;
 	char *query;
-	int ret;
+	DBusPendingCall *call;
 
 	DBG("folder %s id %s", folder, id);
 
@@ -1672,15 +1727,16 @@ int phonebook_get_entry(const char *folder, const char *id,
 		query = g_strdup_printf(CONTACTS_OTHER_QUERY_FROM_URI,
 								id, id, id);
 
-	ret = query_tracker(query, PULL_QUERY_COL_AMOUNT, pull_contacts, data);
+	call = query_tracker(query, PULL_QUERY_COL_AMOUNT, pull_contacts,
+							data, g_free, err);
 
 	g_free(query);
 
-	return ret;
+	return call;
 }
 
-int phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
-			phonebook_cache_ready_cb ready_cb, void *user_data)
+void *phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
+		phonebook_cache_ready_cb ready_cb, void *user_data, int *err)
 {
 	struct cache_data *cache;
 	const char *query;
@@ -1688,13 +1744,16 @@ int phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
 	DBG("name %s", name);
 
 	query = folder2query(name);
-	if (query == NULL)
-		return -ENOENT;
+	if (query == NULL) {
+		if (err)
+			*err = -ENOENT;
+		return NULL;
+	}
 
 	cache = g_new0(struct cache_data, 1);
 	cache->entry_cb = entry_cb;
 	cache->ready_cb = ready_cb;
 	cache->user_data = user_data;
 
-	return query_tracker(query, 7, add_to_cache, cache);
+	return query_tracker(query, 7, add_to_cache, cache, g_free, err);
 }
diff --git a/plugins/phonebook.h b/plugins/phonebook.h
index d7cfa46..bfbae0f 100644
--- a/plugins/phonebook.h
+++ b/plugins/phonebook.h
@@ -85,25 +85,46 @@ char *phonebook_set_folder(const char *current_folder,
  * PullPhoneBook never use cached entries. PCE use this function to get all
  * entries of a given folder. The back-end MUST return only the content based
  * on the application parameters requested by the client.
+ *
+ * Return value is a pointer to asynchronous request to phonebook back-end.
+ * phonebook_req_finalize MUST always be used to free associated resources.
  */
-int phonebook_pull(const char *name, const struct apparam_field *params,
-					phonebook_cb cb, void *user_data);
+void *phonebook_pull(const char *name, const struct apparam_field *params,
+				phonebook_cb cb, void *user_data, int *err);
 
 /*
  * Function used to retrieve a contact from the backend. Only contacts
  * found in the cache are requested to the back-ends. The back-end MUST
  * return only the content based on the application parameters requested
  * by the client.
+ *
+ * Return value is a pointer to asynchronous request to phonebook back-end.
+ * phonebook_req_finalize MUST always be used to free associated resources.
  */
-int phonebook_get_entry(const char *folder, const char *id,
+void *phonebook_get_entry(const char *folder, const char *id,
 				const struct apparam_field *params,
-				phonebook_cb cb, void *user_data);
+				phonebook_cb cb, void *user_data, int *err);
 
 /*
  * PBAP core will keep the contacts cache per folder. SetPhoneBook or
  * PullvCardListing can invalidate the cache if the current folder changes.
  * Cache will store only the necessary information required to reply to
- * PullvCardListing request and verify if a given contact belongs to the source.
+ * PullvCardListing request and verify if a given contact belongs to the
+ * source.
+ *
+ * Return value is a pointer to asynchronous request to phonebook back-end.
+ * phonebook_req_finalize MUST always be used to free associated resources.
+ */
+void *phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
+		phonebook_cache_ready_cb ready_cb, void *user_data, int *err);
+
+/*
+ * Finalizes request to phonebook back-end and deallocates associated
+ * resources. Operation is canceled if not completed. This function MUST
+ * always be used after any of phonebook_pull, phonebook_get_entry, and
+ * phonebook_create_cache invoked.
+ *
+ * request is a pointer to asynchronous operation returned by phonebook_pull,
+ * phonebook_get_entry, and phonebook_create_cache.
  */
-int phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
-			phonebook_cache_ready_cb ready_cb, void *user_data);
+void phonebook_req_finalize(void *request);
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 1/3 v4] Unified ebook data structures
From: Dmitriy Paliy @ 2010-12-09 10:05 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Dmitriy Paliy
In-Reply-To: <1291889119-23915-1-git-send-email-dmitriy.paliy@nokia.com>

Query data structures are unified in phonebook-ebook.c to have a
unique identifier for ebook async operation. Purpose of this
modification is next commit where pending async operation can be
cancelled.
---
 plugins/phonebook-ebook.c |   36 ++++++++++++++++--------------------
 1 files changed, 16 insertions(+), 20 deletions(-)

diff --git a/plugins/phonebook-ebook.c b/plugins/phonebook-ebook.c
index 073ff33..80398ef 100644
--- a/plugins/phonebook-ebook.c
+++ b/plugins/phonebook-ebook.c
@@ -45,13 +45,9 @@
 #define QUERY_NAME "(contains \"given_name\" \"%s\")"
 #define QUERY_PHONE "(contains \"phone\" \"%s\")"
 
-struct contacts_query {
+struct query_context {
 	const struct apparam_field *params;
-	phonebook_cb cb;
-	void *user_data;
-};
-
-struct cache_query {
+	phonebook_cb contacts_cb;
 	phonebook_entry_cb entry_cb;
 	phonebook_cache_ready_cb ready_cb;
 	void *user_data;
@@ -141,7 +137,7 @@ static char *evcard_to_string(EVCard *evcard, unsigned int format,
 static void ebookpull_cb(EBook *book, EBookStatus estatus, GList *contacts,
 							void *user_data)
 {
-	struct contacts_query *data = user_data;
+	struct query_context *data = user_data;
 	GString *string = g_string_new("");
 	unsigned int count = 0, maxcount;
 	GList *l;
@@ -182,7 +178,7 @@ static void ebookpull_cb(EBook *book, EBookStatus estatus, GList *contacts,
 
 
 done:
-	data->cb(string->str, string->len, count, 0, data->user_data);
+	data->contacts_cb(string->str, string->len, count, 0, data->user_data);
 
 	g_string_free(string, TRUE);
 	g_free(data);
@@ -191,14 +187,14 @@ done:
 static void ebook_entry_cb(EBook *book, EBookStatus estatus,
 			EContact *contact, void *user_data)
 {
-	struct contacts_query *data = user_data;
+	struct query_context *data = user_data;
 	EVCard *evcard;
 	char *vcard;
 	size_t len;
 
 	if (estatus != E_BOOK_ERROR_OK) {
 		error("E-Book query failed: status %d", estatus);
-		data->cb(NULL, 0, 1, 0, data->user_data);
+		data->contacts_cb(NULL, 0, 1, 0, data->user_data);
 		g_free(data);
 		return;
 	}
@@ -210,7 +206,7 @@ static void ebook_entry_cb(EBook *book, EBookStatus estatus,
 
 	len = vcard ? strlen(vcard) : 0;
 
-	data->cb(vcard, len, 1, 0, data->user_data);
+	data->contacts_cb(vcard, len, 1, 0, data->user_data);
 
 	g_free(vcard);
 	g_free(data);
@@ -249,7 +245,7 @@ static char *evcard_name_attribute_to_string(EVCard *evcard)
 static void cache_cb(EBook *book, EBookStatus estatus, GList *contacts,
 							void *user_data)
 {
-	struct cache_query *data = user_data;
+	struct query_context *data = user_data;
 	GList *l;
 
 	if (estatus != E_BOOK_ERROR_OK) {
@@ -411,13 +407,13 @@ done:
 int phonebook_pull(const char *name, const struct apparam_field *params,
 					phonebook_cb cb, void *user_data)
 {
-	struct contacts_query *data;
+	struct query_context *data;
 	EBookQuery *query;
 
 	query = e_book_query_any_field_contains("");
 
-	data = g_new0(struct contacts_query, 1);
-	data->cb = cb;
+	data = g_new0(struct query_context, 1);
+	data->contacts_cb = cb;
 	data->params = params;
 	data->user_data = user_data;
 
@@ -432,10 +428,10 @@ int phonebook_get_entry(const char *folder, const char *id,
 					const struct apparam_field *params,
 					phonebook_cb cb, void *user_data)
 {
-	struct contacts_query *data;
+	struct query_context *data;
 
-	data = g_new0(struct contacts_query, 1);
-	data->cb = cb;
+	data = g_new0(struct query_context, 1);
+	data->contacts_cb = cb;
 	data->params = params;
 	data->user_data = user_data;
 
@@ -450,7 +446,7 @@ int phonebook_get_entry(const char *folder, const char *id,
 int phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
 			phonebook_cache_ready_cb ready_cb, void *user_data)
 {
-	struct cache_query *data;
+	struct query_context *data;
 	EBookQuery *query;
 	gboolean ret;
 
@@ -459,7 +455,7 @@ int phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
 
 	query = e_book_query_any_field_contains("");
 
-	data = g_new0(struct cache_query, 1);
+	data = g_new0(struct query_context, 1);
 	data->entry_cb = entry_cb;
 	data->ready_cb = ready_cb;
 	data->user_data = user_data;
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 0/3 v4] Cancel pending phonebook request
From: Dmitriy Paliy @ 2010-12-09 10:05 UTC (permalink / raw)
  To: linux-bluetooth

Hi,

Structure context_query changed to query_context in phonebook-ebook.c
comparing to previous submission, and phonebook_req_cancel changed to
phonebook_req_finalize.

More comments added to phonebook.h.

Br,
Dmitriy


^ permalink raw reply

* Re: [PATCH v2] Change obex_service_driver put() signature
From: Johan Hedberg @ 2010-12-09  8:47 UTC (permalink / raw)
  To: Slawomir Bochenski; +Cc: linux-bluetooth
In-Reply-To: <1291878480-14865-1-git-send-email-lkslawek@gmail.com>

Hi Slawek,

On Thu, Dec 09, 2010, Slawomir Bochenski wrote:
> This API change is needed for implementing Message Access Profile, as
> MAP uses application parameters in puts also (for example
> SetMessageStatus function, see MAP specification, chapter 5.7) and in
> order to access application parameters headers, access to obex object
> is required.
> ---
>  plugins/ftp.c           |    3 ++-
>  plugins/opp.c           |    3 ++-
>  plugins/syncevolution.c |    3 ++-
>  src/obex.c              |    2 +-
>  src/service.h           |    3 ++-
>  5 files changed, 9 insertions(+), 5 deletions(-)

Pushed upstream. Thanks.

Johan

^ permalink raw reply

* Re: [PATCH v7] Bluetooth: btwilink driver
From: Pavan Savoy @ 2010-12-09  7:47 UTC (permalink / raw)
  To: Vitaly Wool, Gustavo F. Padovan; +Cc: marcel, linux-bluetooth, linux-kernel
In-Reply-To: <AANLkTimJiHhkwb-0PQqc6n3wJwx2WPterQqMCXqzce8z@mail.gmail.com>

Gustavo,

On Tue, Dec 7, 2010 at 3:05 AM, Vitaly Wool <vitalywool@gmail.com> wrote:
> Hi Gustavo,
>
> On Mon, Dec 6, 2010 at 10:23 PM, Gustavo F. Padovan
> <padovan@profusion.mobi> wrote:
>
>> Can't you differentiate Bluetooth data in a generic way, withou looking =
if it
>> is ACL, SCO or HCI EVENT? That done, you can just accumulate in a buffer=
 all
>> the Bluetooth data you received in that stream then send it to Bluetooth
>> driver after finish that stream processing.
>
> I'm afraid he can't do this because he needs to route events to the
> appropriate entity (BT/FM/GPS). I'm not sure how it can be done
> without analyzing the incoming packet.

Think of TI-ST driver as a extension to the HCI-H4 driver or HCI-LL
with FM and GPS being the additional protocols, and more protocols
coming in future...
So some driver has to have a knowledge of the protocols which are on chip.
the basic arch can be found @ http://omappedia.org/wiki/Wilink_ST

As Vitaly rightly pointed out, the TI-ST driver needs to peek into all
the protocol's data be it BT, FM or GPS to assemble fragmented data
(say ACL data coming out of TTY in 2 fragments) or fragment multiple
protocol data (say HCI-Event + FM Channel 8 event data)....
Note: we include even the FM and GPS headers to understand protocol
frames, but they lack a standard unlike Bluetooth...

Since there lacks a generic way to differentiate BT, FM or GPS data at
TI-ST driver layer,  please suggest what can be done ...


> Thanks,
> =C2=A0 Vitaly
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth=
" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at =C2=A0http://vger.kernel.org/majordomo-info.html
>

^ permalink raw reply

* [PATCH v2] Change obex_service_driver put() signature
From: Slawomir Bochenski @ 2010-12-09  7:08 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Slawomir Bochenski

This API change is needed for implementing Message Access Profile, as
MAP uses application parameters in puts also (for example
SetMessageStatus function, see MAP specification, chapter 5.7) and in
order to access application parameters headers, access to obex object
is required.
---
 plugins/ftp.c           |    3 ++-
 plugins/opp.c           |    3 ++-
 plugins/syncevolution.c |    3 ++-
 src/obex.c              |    2 +-
 src/service.h           |    3 ++-
 5 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/plugins/ftp.c b/plugins/ftp.c
index 91c77a3..a952f64 100644
--- a/plugins/ftp.c
+++ b/plugins/ftp.c
@@ -258,7 +258,8 @@ static int ftp_chkput(struct obex_session *os, void *user_data)
 	return ret;
 }
 
-static int ftp_put(struct obex_session *os, void *user_data)
+static int ftp_put(struct obex_session *os, obex_object_t *obj,
+						void *user_data)
 {
 	struct ftp_session *ftp = user_data;
 	const char *name = obex_get_name(os);
diff --git a/plugins/opp.c b/plugins/opp.c
index 05f944f..17c4356 100644
--- a/plugins/opp.c
+++ b/plugins/opp.c
@@ -155,7 +155,8 @@ skip_auth:
 	return ret;
 }
 
-static int opp_put(struct obex_session *os, void *user_data)
+static int opp_put(struct obex_session *os, obex_object_t *obj,
+						void *user_data)
 {
 	const char *name = obex_get_name(os);
 	const char *folder = obex_get_root_folder(os);
diff --git a/plugins/syncevolution.c b/plugins/syncevolution.c
index bf436a9..8041df6 100644
--- a/plugins/syncevolution.c
+++ b/plugins/syncevolution.c
@@ -243,7 +243,8 @@ failed:
 	return NULL;
 }
 
-static int synce_put(struct obex_session *os, void *user_data)
+static int synce_put(struct obex_session *os, obex_object_t *obj,
+					void *user_data)
 {
 	return 0;
 }
diff --git a/src/obex.c b/src/obex.c
index 6d4430d..1649cd0 100644
--- a/src/obex.c
+++ b/src/obex.c
@@ -1089,7 +1089,7 @@ static void cmd_put(struct obex_session *os, obex_t *obex, obex_object_t *obj)
 		return;
 	}
 
-	err = os->service->put(os, os->service_data);
+	err = os->service->put(os, obj, os->service_data);
 	if (err < 0)
 		os_set_response(obj, err);
 }
diff --git a/src/service.h b/src/service.h
index 1726c43..a844885 100644
--- a/src/service.h
+++ b/src/service.h
@@ -34,7 +34,8 @@ struct obex_service_driver {
 	void (*progress) (struct obex_session *os, void *user_data);
 	int (*get) (struct obex_session *os, obex_object_t *obj,
 			gboolean *stream, void *user_data);
-	int (*put) (struct obex_session *os, void *user_data);
+	int (*put) (struct obex_session *os, obex_object_t *obj,
+			void *user_data);
 	int (*chkput) (struct obex_session *os, void *user_data);
 	int (*setpath) (struct obex_session *os, obex_object_t *obj,
 							void *user_data);
-- 
1.7.1


^ permalink raw reply related

* compat-wireless-2.6.37-rc5 released
From: Luis R. Rodriguez @ 2010-12-09  0:15 UTC (permalink / raw)
  To: linux-wireless; +Cc: linux-kernel, linux-bluetooth

We're closing in on the 2.6.37 release, now at rc5, so I'll start
making two releases, a vanilla release and one which has more stuff.
For now I'll just suck in all pending stable patches (all patches
marked with Cc: stable@kernel.org on linux-next.git, not only
Atheros', everyone's). This is:

pending-stable/0001-cfg80211-pass-the-reg-hint-initiator-to-helpers.patch
pending-stable/0002-cfg80211-fix-allowing-country-IEs-for-WIPHY_FLAG_STR.patch
pending-stable/0003-cfg80211-fix-disabling-channels-based-on-hints.patch
pending-stable/0004-ath9k_hw-fix-potential-spurious-tx-error-bit-interpr.patch
pending-stable/0005-ath9k-simplify-hw-reset-locking.patch
pending-stable/0006-ath9k-move-the-PCU-lock-to-the-sc-structure.patch
pending-stable/0007-ath9k-content-DMA-start-stop-through-the-PCU-lock.patch
pending-stable/0008-ath9k_hw-Fix-XPABIAS-level-configuration-for-AR9003.patch
pending-stable/0009-ath9k-Fix-bug-in-delimiter-padding-computation.patch
pending-stable/0010-ath9k-Disable-SWBA-interrupt-on-remove_interface.patch
pending-stable/0011-mac80211-Fix-STA-disconnect-due-to-MIC-failure.patch
pending-stable/0012-ath9k-Fix-STA-disconnect-issue-due-to-received-MIC-f.patch
pending-stable/0013-ath9k-Fix-bug-in-reading-input-gpio-state-for-ar9003.patch
pending-stable/0014-ath9k_hw-fix-endian-issues-with-CTLs-on-AR9003.patch

You can find the vanilla [1] and extra pending-stable [2] releass on
the stable download page [3] along with the respective ChangeLog of
all:

  * The kernel components
  * compat-wireless
  * compat

In later releases we will have to consider if we want to cherry pick
anything extra or leave them as is. These few patches seem tempting to
suck in:

01-ath9k-OTP.patch
03-ath9k-no-aggr-VO.patch
04-mac80211-no-aggr-VO.patch
05-ath9k-Reintroduce-modparam-to-enable-btcoex.patch
06-ath9k_hw-fix-A-MPDU-key-search-issues-on-AR9003.patch

Particularly it is now known AR9003 devices will only ship with OTP
so.. it seems to make sense to actually disable AR9003 on 36 and even
37 and only have it available with the OTP patch and above EEPROM
fixes. I'm inclined to just disregard all these and just let us get
AR9003 from 2.6.38.... but we already have users of AR9003 coming up
so this can't wait in practice now. This now goes compile-tested and
fixed for 2.6.31.

[1] http://www.orbit-lab.org/kernel/compat-wireless-2.6-stable/v2.6.37/compat-wireless-2.6.37-rc5-2.tar.bz2
[2] http://www.orbit-lab.org/kernel/compat-wireless-2.6-stable/v2.6.37/compat-wireless-2.6.37-rc5-2-s.tar.bz2
[3] http://wireless.kernel.org/en/users/Download/stable
[4] http://www.orbit-lab.org/kernel/compat-wireless-2.6-stable/v2.6.37/ChangeLog-2.6.37-wireless

  Luis

^ permalink raw reply

* [PATCH 3/3 v3] Code clean-up: long, empty lines, indentation
From: Dmitriy Paliy @ 2010-12-08 21:15 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Dmitriy Paliy
In-Reply-To: <1291842956-8610-1-git-send-email-dmitriy.paliy@nokia.com>

Lines longer 80 symbols and empty lines removed. Indentation in
generate_response function corrected.
---
 plugins/pbap.c |   17 ++++++++---------
 1 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/plugins/pbap.c b/plugins/pbap.c
index a8e1ec6..5121685 100644
--- a/plugins/pbap.c
+++ b/plugins/pbap.c
@@ -273,8 +273,8 @@ static void query_result(const char *buffer, size_t bufsize, int vcards,
 	if (!pbap->obj->buffer)
 		pbap->obj->buffer = g_string_new_len(buffer, bufsize);
 	else
-		pbap->obj->buffer = g_string_append_len(pbap->obj->buffer, buffer,
-								bufsize);
+		pbap->obj->buffer = g_string_append_len(pbap->obj->buffer,
+							buffer,	bufsize);
 
 	obex_object_set_io_flags(pbap->obj, G_IO_IN, 0);
 }
@@ -418,9 +418,8 @@ static int generate_response(void *user_data)
 	 * only the reference for the "real" cache entry.
 	 */
 	sorted = sort_entries(pbap->cache.entries, pbap->params->order,
-			pbap->params->searchattrib,
-			(const char *) pbap->params->searchval);
-
+				pbap->params->searchattrib,
+				(const char *) pbap->params->searchval);
 	if (sorted == NULL)
 		return -ENOENT;
 
@@ -431,12 +430,12 @@ static int generate_response(void *user_data)
 	for (; l && max; l = l->next, max--) {
 		const struct cache_entry *entry = l->data;
 
-		g_string_append_printf(pbap->obj->buffer, VCARD_LISTING_ELEMENT,
-						entry->handle, entry->name);
+		g_string_append_printf(pbap->obj->buffer,
+			VCARD_LISTING_ELEMENT, entry->handle, entry->name);
 	}
 
-	pbap->obj->buffer = g_string_append(pbap->obj->buffer, VCARD_LISTING_END);
-
+	pbap->obj->buffer = g_string_append(pbap->obj->buffer,
+							VCARD_LISTING_END);
 	g_slist_free(sorted);
 
 	return 0;
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 2/3 v3] Add handing of backend pending request
From: Dmitriy Paliy @ 2010-12-08 21:15 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Dmitriy Paliy
In-Reply-To: <1291842956-8610-1-git-send-email-dmitriy.paliy@nokia.com>

Add phonebook_req_cancel function prototype in phonebook.h to cancel
pending request if it is not completed, and to unref pointer to pending
request if such is applicable.

It does the following, depending on phonebook backend:
- for phonebook-tracker.c backend driver, it cancels pending DBus call,
- for phonebook-dummy.c, it removes GSource with a given id,
- for phonebook-ebook.c, it cancels last, still running, asynchronous
operation.

The following modifcations are donein the code. Phonebook request
pointer is added in PBAP object and IRMC session data to provide
reference for pending call. Phonebook callbacks are updated in PBAP
and IRMC to unref request upon completion and clear pointers, if such
is applicable.

PBAP and IRMC are updated to cancel pending request, if any, when OBEX
object is closed.

Phonebook_pull, phonebook_get_entry, phonebook_create_cache functions
are updated to return void pointer to backend specific request and error
code. All backend drivers updated accordingly to the modified API, which
are phonebook-tracker.c, phonebook-dummy.c, and phonebook-ebook.c, to be
specific.

In phonebook-tracker.c, query_tracker is updated to return pending DBus
call request. Allocated pending_reply and phonebook_data are destroyed
after call is unrefed. For this purpose new query_free_data function is
created.

Call is unrefed either if request succeeded or in phonebook_req_cancel
if terminated.

Such fix prevents obexd crash on unexpected OBEX session close. E.g.,
OBEX session is closed before reply comes from phonebook backend. In
that case, both session and object are destroyed, and dereferencing of
object in associated callback function causes crash.
---
 plugins/irmc.c              |   27 ++++++++---
 plugins/pbap.c              |   69 ++++++++++++++++++++------
 plugins/phonebook-dummy.c   |   70 +++++++++++++++++++--------
 plugins/phonebook-ebook.c   |   95 +++++++++++++++++++++++++++++-------
 plugins/phonebook-tracker.c |  113 ++++++++++++++++++++++++++++++++----------
 plugins/phonebook.h         |   17 ++++--
 6 files changed, 296 insertions(+), 95 deletions(-)

diff --git a/plugins/irmc.c b/plugins/irmc.c
index f7ad33b..ede5554 100644
--- a/plugins/irmc.c
+++ b/plugins/irmc.c
@@ -110,6 +110,7 @@ struct irmc_session {
 	char did[DID_LEN];
 	char manu[DID_LEN];
 	char model[DID_LEN];
+	void *request;
 };
 
 #define IRMC_TARGET_SIZE 9
@@ -139,6 +140,11 @@ static void phonebook_size_result(const char *buffer, size_t bufsize,
 	DBG("vcards %d", vcards);
 
 	irmc->params->maxlistcount = vcards;
+
+	if (irmc->request) {
+		phonebook_req_cancel(irmc->request);
+		irmc->request = NULL;
+	}
 }
 
 static void query_result(const char *buffer, size_t bufsize, int vcards,
@@ -149,6 +155,11 @@ static void query_result(const char *buffer, size_t bufsize, int vcards,
 
 	DBG("bufsize %zu vcards %d missed %d", bufsize, vcards, missed);
 
+	if (irmc->request) {
+		phonebook_req_cancel(irmc->request);
+		irmc->request = NULL;
+	}
+
 	/* first add a 'owner' vcard */
 	if (!irmc->buffer)
 		irmc->buffer = g_string_new(owner_vcard);
@@ -210,11 +221,8 @@ static void *irmc_connect(struct obex_session *os, int *err)
 	param->maxlistcount = 0; /* to count the number of vcards... */
 	param->filter = 0x200085; /* UID TEL N VERSION */
 	irmc->params = param;
-	phonebook_pull("telecom/pb.vcf", irmc->params, phonebook_size_result,
-									irmc);
-
-	if (err)
-		*err = 0;
+	irmc->request = phonebook_pull("telecom/pb.vcf", irmc->params,
+					phonebook_size_result, irmc, err);
 
 	return irmc;
 }
@@ -298,8 +306,8 @@ static void *irmc_open_pb(const char *name, struct irmc_session *irmc,
 
 	if (!g_strcmp0(name, ".vcf")) {
 		/* how can we tell if the vcard count call already finished? */
-		ret = phonebook_pull("telecom/pb.vcf", irmc->params,
-							query_result, irmc);
+		irmc->request = phonebook_pull("telecom/pb.vcf", irmc->params,
+						query_result, irmc, &ret);
 		if (ret < 0) {
 			DBG("phonebook_pull failed...");
 			goto fail;
@@ -435,6 +443,11 @@ static int irmc_close(void *object)
 		irmc->buffer = NULL;
 	}
 
+	if (irmc->request) {
+		phonebook_req_cancel(irmc->request);
+		irmc->request = NULL;
+	}
+
 	return 0;
 }
 
diff --git a/plugins/pbap.c b/plugins/pbap.c
index 4086227..a8e1ec6 100644
--- a/plugins/pbap.c
+++ b/plugins/pbap.c
@@ -147,6 +147,7 @@ struct pbap_session {
 struct pbap_object {
 	GString *buffer;
 	struct pbap_session *session;
+	void *request;
 };
 
 static const uint8_t PBAP_TARGET[TARGET_SIZE] = {
@@ -231,6 +232,11 @@ static void phonebook_size_result(const char *buffer, size_t bufsize,
 	struct aparam_header *hdr = (struct aparam_header *) aparam;
 	uint16_t phonebooksize;
 
+	if (pbap->obj->request) {
+		phonebook_req_cancel(pbap->obj->request);
+		pbap->obj->request = NULL;
+	}
+
 	if (vcards < 0)
 		vcards = 0;
 
@@ -254,6 +260,11 @@ static void query_result(const char *buffer, size_t bufsize, int vcards,
 
 	DBG("");
 
+	if (pbap->obj->request) {
+		phonebook_req_cancel(pbap->obj->request);
+		pbap->obj->request = NULL;
+	}
+
 	if (vcards <= 0) {
 		obex_object_set_io_flags(pbap->obj, G_IO_ERR, -ENOENT);
 		return;
@@ -466,8 +477,11 @@ static void cache_entry_done(void *user_data)
 		return;
 	}
 
-	ret = phonebook_get_entry(pbap->folder, id, pbap->params,
-						query_result, pbap);
+	/* Unref previous request, associated data will be freed. */
+	phonebook_req_cancel(pbap->obj->request);
+	/* Get new pointer to pending call. */
+	pbap->obj->request = phonebook_get_entry(pbap->folder, id,
+				pbap->params, query_result, pbap, &ret);
 	if (ret < 0)
 		obex_object_set_io_flags(pbap->obj, G_IO_ERR, ret);
 }
@@ -709,13 +723,15 @@ static struct obex_service_driver pbap = {
 	.chkput = pbap_chkput
 };
 
-static struct pbap_object *vobject_create(struct pbap_session *pbap)
+static struct pbap_object *vobject_create(struct pbap_session *pbap,
+								void *request)
 {
 	struct pbap_object *obj;
 
 	obj = g_new0(struct pbap_object, 1);
 	obj->session = pbap;
 	pbap->obj = obj;
+	obj->request = request;
 
 	return obj;
 }
@@ -726,6 +742,7 @@ static void *vobject_pull_open(const char *name, int oflag, mode_t mode,
 	struct pbap_session *pbap = context;
 	phonebook_cb cb;
 	int ret;
+	void *request;
 
 	DBG("name %s context %p maxlistcount %d", name, context,
 						pbap->params->maxlistcount);
@@ -745,11 +762,15 @@ static void *vobject_pull_open(const char *name, int oflag, mode_t mode,
 	else
 		cb = query_result;
 
-	ret = phonebook_pull(name, pbap->params, cb, pbap);
+	request = phonebook_pull(name, pbap->params, cb, pbap, &ret);
+
 	if (ret < 0)
 		goto fail;
 
-	return vobject_create(pbap);
+	if (err)
+		*err = 0;
+
+	return vobject_create(pbap, request);
 
 fail:
 	if (err)
@@ -770,6 +791,11 @@ static int vobject_close(void *object)
 	if (obj->buffer)
 		g_string_free(obj->buffer, TRUE);
 
+	if (obj->request) {
+		phonebook_req_cancel(obj->request);
+		obj->request = NULL;
+	}
+
 	g_free(obj);
 
 	return 0;
@@ -781,6 +807,7 @@ static void *vobject_list_open(const char *name, int oflag, mode_t mode,
 	struct pbap_session *pbap = context;
 	struct pbap_object *obj = NULL;
 	int ret;
+	void *request;
 
 	DBG("name %s context %p valid %d", name, context, pbap->cache.valid);
 
@@ -796,13 +823,19 @@ static void *vobject_list_open(const char *name, int oflag, mode_t mode,
 
 	/* PullvCardListing always get the contacts from the cache */
 
-	obj = vobject_create(pbap);
-
-	if (pbap->cache.valid)
+	if (pbap->cache.valid) {
+		obj = vobject_create(pbap, NULL);
 		ret = generate_response(pbap);
-	else
-		ret = phonebook_create_cache(name, cache_entry_notify,
-						cache_ready_notify, pbap);
+	} else {
+		request = phonebook_create_cache(name, cache_entry_notify,
+					cache_ready_notify, pbap, &ret);
+		/*
+		 * This is not to do memory allocation since if request
+		 * fails, then memory is freed when object is closed below.
+		 */
+		if (ret == 0)
+			obj = vobject_create(pbap, request);
+	}
 	if (ret < 0)
 		goto fail;
 
@@ -828,6 +861,7 @@ static void *vobject_vcard_open(const char *name, int oflag, mode_t mode,
 	const char *id;
 	uint32_t handle;
 	int ret;
+	void *request;
 
 	DBG("name %s context %p valid %d", name, context, pbap->cache.valid);
 
@@ -843,8 +877,8 @@ static void *vobject_vcard_open(const char *name, int oflag, mode_t mode,
 
 	if (pbap->cache.valid == FALSE) {
 		pbap->find_handle = handle;
-		ret = phonebook_create_cache(pbap->folder, cache_entry_notify,
-						cache_entry_done, pbap);
+		request = phonebook_create_cache(pbap->folder,
+			cache_entry_notify, cache_entry_done, pbap, &ret);
 		goto done;
 	}
 
@@ -854,14 +888,17 @@ static void *vobject_vcard_open(const char *name, int oflag, mode_t mode,
 		goto fail;
 	}
 
-	ret = phonebook_get_entry(pbap->folder, id, pbap->params, query_result,
-									pbap);
+	request = phonebook_get_entry(pbap->folder, id, pbap->params,
+						query_result, pbap, &ret);
 
 done:
 	if (ret < 0)
 		goto fail;
 
-	return vobject_create(pbap);
+	if (err)
+		*err = 0;
+
+	return vobject_create(pbap, request);
 
 fail:
 	if (err)
diff --git a/plugins/phonebook-dummy.c b/plugins/phonebook-dummy.c
index 7c549fa..efb1430 100644
--- a/plugins/phonebook-dummy.c
+++ b/plugins/phonebook-dummy.c
@@ -447,11 +447,19 @@ done:
 	return relative;
 }
 
-int phonebook_pull(const char *name, const struct apparam_field *params,
-					phonebook_cb cb, void *user_data)
+void phonebook_req_cancel(void *request)
+{
+	guint id = GPOINTER_TO_INT(request);
+
+	g_source_remove(id);
+}
+
+void *phonebook_pull(const char *name, const struct apparam_field *params,
+				phonebook_cb cb, void *user_data, int *err)
 {
 	struct dummy_data *dummy;
 	char *filename, *folder;
+	guint ret;
 
 	/*
 	 * Main phonebook objects will be created dinamically based on the
@@ -463,14 +471,18 @@ int phonebook_pull(const char *name, const struct apparam_field *params,
 
 	if (!g_str_has_suffix(filename, ".vcf")) {
 		g_free(filename);
-		return -EBADR;
+		if (err)
+			*err = -EBADR;
+		return NULL;
 	}
 
 	folder = g_strndup(filename, strlen(filename) - 4);
 	g_free(filename);
 	if (!is_dir(folder)) {
 		g_free(folder);
-		return -ENOENT;
+		if (err)
+			*err = -ENOENT;
+		return NULL;
 	}
 
 	dummy = g_new0(struct dummy_data, 1);
@@ -480,26 +492,32 @@ int phonebook_pull(const char *name, const struct apparam_field *params,
 	dummy->folder = folder;
 	dummy->fd = -1;
 
-	g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, read_dir, dummy, dummy_free);
+	ret = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, read_dir, dummy,
+								dummy_free);
 
-	return 0;
+	if (err)
+		*err = 0;
+
+	return GINT_TO_POINTER(ret);
 }
 
-int phonebook_get_entry(const char *folder, const char *id,
-					const struct apparam_field *params,
-					phonebook_cb cb, void *user_data)
+void *phonebook_get_entry(const char *folder, const char *id,
+			const struct apparam_field *params, phonebook_cb cb,
+			void *user_data, int *err)
 {
 	struct dummy_data *dummy;
 	char *filename;
 	int fd;
+	guint ret;
 
 	filename = g_build_filename(root_folder, folder, id, NULL);
 
 	fd = open(filename, O_RDONLY);
 	if (fd < 0) {
-		int err = errno;
-		DBG("open(): %s(%d)", strerror(err), err);
-		return -ENOENT;
+		DBG("open(): %s(%d)", strerror(errno), errno);
+		if (err)
+			*err = -ENOENT;
+		return NULL;
 	}
 
 	dummy = g_new0(struct dummy_data, 1);
@@ -508,26 +526,32 @@ int phonebook_get_entry(const char *folder, const char *id,
 	dummy->apparams = params;
 	dummy->fd = fd;
 
-	g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, read_entry, dummy, dummy_free);
+	ret = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, read_entry, dummy,
+								dummy_free);
 
-	return 0;
+	if (err)
+		*err = 0;
+
+	return GINT_TO_POINTER(ret);
 }
 
-int phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
-		phonebook_cache_ready_cb ready_cb, void *user_data)
+void *phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
+		phonebook_cache_ready_cb ready_cb, void *user_data, int *err)
 {
 	struct cache_query *query;
 	char *foldername;
 	DIR *dp;
+	guint ret;
 
 	foldername = g_build_filename(root_folder, name, NULL);
 	dp = opendir(foldername);
 	g_free(foldername);
 
 	if (dp == NULL) {
-		int err = errno;
-		DBG("opendir(): %s(%d)", strerror(err), err);
-		return -ENOENT;
+		DBG("opendir(): %s(%d)", strerror(errno), errno);
+		if (err)
+			*err = -ENOENT;
+		return NULL;
 	}
 
 	query = g_new0(struct cache_query, 1);
@@ -536,7 +560,11 @@ int phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
 	query->user_data = user_data;
 	query->dp = dp;
 
-	g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, create_cache, query,
+	ret = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, create_cache, query,
 								query_free);
-	return 0;
+
+	if (err)
+		*err = 0;
+
+	return GINT_TO_POINTER(ret);
 }
diff --git a/plugins/phonebook-ebook.c b/plugins/phonebook-ebook.c
index b9d297a..c079de7 100644
--- a/plugins/phonebook-ebook.c
+++ b/plugins/phonebook-ebook.c
@@ -46,6 +46,7 @@
 #define QUERY_PHONE "(contains \"phone\" \"%s\")"
 
 struct context_query {
+	gboolean completed;
 	const struct apparam_field *params;
 	phonebook_cb contacts_cb;
 	phonebook_entry_cb entry_cb;
@@ -142,6 +143,11 @@ static void ebookpull_cb(EBook *book, EBookStatus estatus, GList *contacts,
 	unsigned int count = 0, maxcount;
 	GList *l;
 
+	if (estatus == E_BOOK_ERROR_CANCELLED) {
+		error("E-Book operation was cancelled: status %d", estatus);
+		goto fail;
+	}
+
 	if (estatus != E_BOOK_ERROR_OK) {
 		error("E-Book query failed: status %d", estatus);
 		goto done;
@@ -178,10 +184,14 @@ static void ebookpull_cb(EBook *book, EBookStatus estatus, GList *contacts,
 
 
 done:
+	data->completed = TRUE;
 	data->contacts_cb(string->str, string->len, count, 0, data->user_data);
 
+fail:
 	g_string_free(string, TRUE);
-	g_free(data);
+
+	if (data->completed)
+		g_free(data);
 }
 
 static void ebook_entry_cb(EBook *book, EBookStatus estatus,
@@ -192,11 +202,17 @@ static void ebook_entry_cb(EBook *book, EBookStatus estatus,
 	char *vcard;
 	size_t len;
 
+	if (estatus == E_BOOK_ERROR_CANCELLED) {
+		error("E-Book operation was cancelled: status %d", estatus);
+		goto fail;
+	}
+
+	data->completed = TRUE;
+
 	if (estatus != E_BOOK_ERROR_OK) {
 		error("E-Book query failed: status %d", estatus);
 		data->contacts_cb(NULL, 0, 1, 0, data->user_data);
-		g_free(data);
-		return;
+		goto fail;
 	}
 
 	evcard = E_VCARD(contact);
@@ -209,7 +225,10 @@ static void ebook_entry_cb(EBook *book, EBookStatus estatus,
 	data->contacts_cb(vcard, len, 1, 0, data->user_data);
 
 	g_free(vcard);
-	g_free(data);
+
+fail:
+	if (data->completed)
+		g_free(data);
 }
 
 static char *evcard_name_attribute_to_string(EVCard *evcard)
@@ -248,6 +267,13 @@ static void cache_cb(EBook *book, EBookStatus estatus, GList *contacts,
 	struct context_query *data = user_data;
 	GList *l;
 
+	if (estatus == E_BOOK_ERROR_CANCELLED) {
+		error("E-Book operation was cancelled: status %d", estatus);
+		goto fail;
+	}
+
+	data->completed = TRUE;
+
 	if (estatus != E_BOOK_ERROR_OK) {
 		error("E-Book query failed: status %d", estatus);
 		goto done;
@@ -285,6 +311,10 @@ static void cache_cb(EBook *book, EBookStatus estatus, GList *contacts,
 	}
 done:
 	data->ready_cb(data->user_data);
+
+fail:
+	if (data->completed)
+		g_free(data);
 }
 
 int phonebook_init(void)
@@ -404,8 +434,21 @@ done:
 	return fullname;
 }
 
-int phonebook_pull(const char *name, const struct apparam_field *params,
-					phonebook_cb cb, void *user_data)
+void phonebook_req_cancel(void *request)
+{
+	struct context_query *data = request;
+
+	if (!data)
+		return;
+
+	if (!data->completed) {
+		data->completed = TRUE;
+		e_book_cancel_async_op(ebook, NULL);
+	}
+}
+
+void *phonebook_pull(const char *name, const struct apparam_field *params,
+				phonebook_cb cb, void *user_data, int *err)
 {
 	struct context_query *data;
 	EBookQuery *query;
@@ -421,12 +464,15 @@ int phonebook_pull(const char *name, const struct apparam_field *params,
 
 	e_book_query_unref(query);
 
-	return 0;
+	if (err)
+		*err = 0;
+
+	return data;
 }
 
-int phonebook_get_entry(const char *folder, const char *id,
-					const struct apparam_field *params,
-					phonebook_cb cb, void *user_data)
+void *phonebook_get_entry(const char *folder, const char *id,
+				const struct apparam_field *params,
+				phonebook_cb cb, void *user_data, int *err)
 {
 	struct context_query *data;
 
@@ -437,21 +483,29 @@ int phonebook_get_entry(const char *folder, const char *id,
 
 	if (e_book_async_get_contact(ebook, id, ebook_entry_cb, data)) {
 		g_free(data);
-		return -ENOENT;
+		if (err)
+			*err = -ENOENT;
+		return NULL;
 	}
 
-	return 0;
+	if (err)
+		*err = 0;
+
+	return data;
 }
 
-int phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
-			phonebook_cache_ready_cb ready_cb, void *user_data)
+void *phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
+		phonebook_cache_ready_cb ready_cb, void *user_data, int *err)
 {
 	struct context_query *data;
 	EBookQuery *query;
 	gboolean ret;
 
-	if (g_strcmp0("/telecom/pb", name) != 0)
-		return -ENOENT;
+	if (g_strcmp0("/telecom/pb", name) != 0) {
+		if (err)
+			*err = -ENOENT;
+		return NULL;
+	}
 
 	query = e_book_query_any_field_contains("");
 
@@ -464,8 +518,13 @@ int phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
 	e_book_query_unref(query);
 	if (ret != FALSE) {
 		g_free(data);
-		return -EFAULT;
+		if (err)
+			*err = -EFAULT;
+		return NULL;
 	}
 
-	return 0;
+	if (err)
+		*err = 0;
+
+	return data;
 }
diff --git a/plugins/phonebook-tracker.c b/plugins/phonebook-tracker.c
index cdc1008..92299a0 100644
--- a/plugins/phonebook-tracker.c
+++ b/plugins/phonebook-tracker.c
@@ -807,6 +807,7 @@ struct pending_reply {
 	reply_list_foreach_t callback;
 	void *user_data;
 	int num_fields;
+	GDestroyNotify destroy;
 };
 
 struct contact_data {
@@ -996,11 +997,30 @@ done:
 	pending->callback(NULL, err, pending->user_data);
 
 	dbus_message_unref(reply);
+
+	/*
+	 * pending data is freed in query_free_data after call is unreffed.
+	 * Same holds for pending->user_data which is not freed in callback
+	 * but in query_free_data.
+	 */
+}
+
+static void query_free_data(void *user_data)
+{
+	struct pending_reply *pending = user_data;
+
+	if (!pending)
+		return;
+
+	if (pending->destroy)
+		pending->destroy(pending->user_data);
+
 	g_free(pending);
 }
 
-static int query_tracker(const char *query, int num_fields,
-				reply_list_foreach_t callback, void *user_data)
+static DBusPendingCall *query_tracker(const char *query, int num_fields,
+				reply_list_foreach_t callback, void *user_data,
+				GDestroyNotify destroy, int *err)
 {
 	struct pending_reply *pending;
 	DBusPendingCall *call;
@@ -1020,19 +1040,27 @@ static int query_tracker(const char *query, int num_fields,
 							-1) == FALSE) {
 		error("Could not send dbus message");
 		dbus_message_unref(msg);
-		return -EPERM;
+		if (err)
+			*err = -EPERM;
+		/* user_data is freed otherwise only if call was sent */
+		g_free(user_data);
+		return NULL;
 	}
 
 	pending = g_new0(struct pending_reply, 1);
 	pending->callback = callback;
 	pending->user_data = user_data;
 	pending->num_fields = num_fields;
+	pending->destroy = destroy;
 
-	dbus_pending_call_set_notify(call, query_reply, pending, NULL);
-	dbus_pending_call_unref(call);
+	dbus_pending_call_set_notify(call, query_reply, pending,
+							query_free_data);
 	dbus_message_unref(msg);
 
-	return 0;
+	if (err)
+		*err = 0;
+
+	return call;
 }
 
 static char *iso8601_utc_to_localtime(const char *datetime)
@@ -1245,7 +1273,7 @@ static void pull_contacts_size(char **reply, int num_fields, void *user_data)
 
 	if (num_fields < 0) {
 		data->cb(NULL, 0, num_fields, 0, data->user_data);
-		goto fail;
+		return;
 	}
 
 	if (reply != NULL) {
@@ -1255,8 +1283,11 @@ static void pull_contacts_size(char **reply, int num_fields, void *user_data)
 
 	data->cb(NULL, 0, data->index, 0, data->user_data);
 
-fail:
-	g_free(data);
+	/*
+	 * phonebook_data is freed in query_free_data after call is unreffed.
+	 * It is accessible by pointer from data (pending) associated to call.
+	 * Useful in cases when call was terminated.
+	 */
 }
 
 static void add_affiliation(char **field, const char *value)
@@ -1482,9 +1513,14 @@ done:
 	g_string_free(vcards, TRUE);
 fail:
 	g_slist_free(data->contacts);
-	g_free(data);
 	g_free(temp_id);
 	temp_id = NULL;
+
+	/*
+	 * phonebook_data is freed in query_free_data after call is unreffed.
+	 * It is accessible by pointer from data (pending) associated to call.
+	 * Useful in cases when call was terminated.
+	 */
 }
 
 static void add_to_cache(char **reply, int num_fields, void *user_data)
@@ -1529,7 +1565,11 @@ done:
 	if (num_fields <= 0)
 		cache->ready_cb(cache->user_data);
 
-	g_free(cache);
+	/*
+	 * cache is freed in query_free_data after call is unreffed.
+	 * It is accessible by pointer from data (pending) associated to call.
+	 * Useful in cases when call was terminated.
+	 */
 }
 
 int phonebook_init(void)
@@ -1617,8 +1657,20 @@ done:
 	return path;
 }
 
-int phonebook_pull(const char *name, const struct apparam_field *params,
-					phonebook_cb cb, void *user_data)
+void phonebook_req_cancel(void *request)
+{
+	struct DBusPendingCall *call = request;
+
+	DBG("");
+
+	if (!dbus_pending_call_get_completed(call))
+		dbus_pending_call_cancel(call);
+
+	dbus_pending_call_unref(call);
+}
+
+void *phonebook_pull(const char *name, const struct apparam_field *params,
+				phonebook_cb cb, void *user_data, int *err)
 {
 	struct phonebook_data *data;
 	const char *query;
@@ -1637,24 +1689,27 @@ int phonebook_pull(const char *name, const struct apparam_field *params,
 		pull_cb = pull_contacts;
 	}
 
-	if (query == NULL)
-		return -ENOENT;
+	if (query == NULL) {
+		if (err)
+			*err = -ENOENT;
+		return NULL;
+	}
 
 	data = g_new0(struct phonebook_data, 1);
 	data->params = params;
 	data->user_data = user_data;
 	data->cb = cb;
 
-	return query_tracker(query, col_amount, pull_cb, data);
+	return query_tracker(query, col_amount, pull_cb, data, g_free, err);
 }
 
-int phonebook_get_entry(const char *folder, const char *id,
-					const struct apparam_field *params,
-					phonebook_cb cb, void *user_data)
+void *phonebook_get_entry(const char *folder, const char *id,
+				const struct apparam_field *params,
+				phonebook_cb cb, void *user_data, int *err)
 {
 	struct phonebook_data *data;
 	char *query;
-	int ret;
+	DBusPendingCall *call;
 
 	DBG("folder %s id %s", folder, id);
 
@@ -1672,15 +1727,16 @@ int phonebook_get_entry(const char *folder, const char *id,
 		query = g_strdup_printf(CONTACTS_OTHER_QUERY_FROM_URI,
 								id, id, id);
 
-	ret = query_tracker(query, PULL_QUERY_COL_AMOUNT, pull_contacts, data);
+	call = query_tracker(query, PULL_QUERY_COL_AMOUNT, pull_contacts,
+							data, g_free, err);
 
 	g_free(query);
 
-	return ret;
+	return call;
 }
 
-int phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
-			phonebook_cache_ready_cb ready_cb, void *user_data)
+void *phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
+		phonebook_cache_ready_cb ready_cb, void *user_data, int *err)
 {
 	struct cache_data *cache;
 	const char *query;
@@ -1688,13 +1744,16 @@ int phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
 	DBG("name %s", name);
 
 	query = folder2query(name);
-	if (query == NULL)
-		return -ENOENT;
+	if (query == NULL) {
+		if (err)
+			*err = -ENOENT;
+		return NULL;
+	}
 
 	cache = g_new0(struct cache_data, 1);
 	cache->entry_cb = entry_cb;
 	cache->ready_cb = ready_cb;
 	cache->user_data = user_data;
 
-	return query_tracker(query, 7, add_to_cache, cache);
+	return query_tracker(query, 7, add_to_cache, cache, g_free, err);
 }
diff --git a/plugins/phonebook.h b/plugins/phonebook.h
index d7cfa46..687feb8 100644
--- a/plugins/phonebook.h
+++ b/plugins/phonebook.h
@@ -86,8 +86,8 @@ char *phonebook_set_folder(const char *current_folder,
  * entries of a given folder. The back-end MUST return only the content based
  * on the application parameters requested by the client.
  */
-int phonebook_pull(const char *name, const struct apparam_field *params,
-					phonebook_cb cb, void *user_data);
+void *phonebook_pull(const char *name, const struct apparam_field *params,
+				phonebook_cb cb, void *user_data, int *err);
 
 /*
  * Function used to retrieve a contact from the backend. Only contacts
@@ -95,9 +95,9 @@ int phonebook_pull(const char *name, const struct apparam_field *params,
  * return only the content based on the application parameters requested
  * by the client.
  */
-int phonebook_get_entry(const char *folder, const char *id,
+void *phonebook_get_entry(const char *folder, const char *id,
 				const struct apparam_field *params,
-				phonebook_cb cb, void *user_data);
+				phonebook_cb cb, void *user_data, int *err);
 
 /*
  * PBAP core will keep the contacts cache per folder. SetPhoneBook or
@@ -105,5 +105,10 @@ int phonebook_get_entry(const char *folder, const char *id,
  * Cache will store only the necessary information required to reply to
  * PullvCardListing request and verify if a given contact belongs to the source.
  */
-int phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
-			phonebook_cache_ready_cb ready_cb, void *user_data);
+void *phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
+		phonebook_cache_ready_cb ready_cb, void *user_data, int *err);
+
+/*
+ * Cancels pending call to phonebook backend.
+ */
+void phonebook_req_cancel(void *request);
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 1/3 v3] Unified ebook data structures
From: Dmitriy Paliy @ 2010-12-08 21:15 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Dmitriy Paliy
In-Reply-To: <1291842956-8610-1-git-send-email-dmitriy.paliy@nokia.com>

Query data structures are unified in phonebook-ebook.c to have a
unique identifier for ebook async operation. Purpose of this
modification is next commit where pending async operation can be
cancelled.
---
 plugins/phonebook-ebook.c |   36 ++++++++++++++++--------------------
 1 files changed, 16 insertions(+), 20 deletions(-)

diff --git a/plugins/phonebook-ebook.c b/plugins/phonebook-ebook.c
index 073ff33..b9d297a 100644
--- a/plugins/phonebook-ebook.c
+++ b/plugins/phonebook-ebook.c
@@ -45,13 +45,9 @@
 #define QUERY_NAME "(contains \"given_name\" \"%s\")"
 #define QUERY_PHONE "(contains \"phone\" \"%s\")"
 
-struct contacts_query {
+struct context_query {
 	const struct apparam_field *params;
-	phonebook_cb cb;
-	void *user_data;
-};
-
-struct cache_query {
+	phonebook_cb contacts_cb;
 	phonebook_entry_cb entry_cb;
 	phonebook_cache_ready_cb ready_cb;
 	void *user_data;
@@ -141,7 +137,7 @@ static char *evcard_to_string(EVCard *evcard, unsigned int format,
 static void ebookpull_cb(EBook *book, EBookStatus estatus, GList *contacts,
 							void *user_data)
 {
-	struct contacts_query *data = user_data;
+	struct context_query *data = user_data;
 	GString *string = g_string_new("");
 	unsigned int count = 0, maxcount;
 	GList *l;
@@ -182,7 +178,7 @@ static void ebookpull_cb(EBook *book, EBookStatus estatus, GList *contacts,
 
 
 done:
-	data->cb(string->str, string->len, count, 0, data->user_data);
+	data->contacts_cb(string->str, string->len, count, 0, data->user_data);
 
 	g_string_free(string, TRUE);
 	g_free(data);
@@ -191,14 +187,14 @@ done:
 static void ebook_entry_cb(EBook *book, EBookStatus estatus,
 			EContact *contact, void *user_data)
 {
-	struct contacts_query *data = user_data;
+	struct context_query *data = user_data;
 	EVCard *evcard;
 	char *vcard;
 	size_t len;
 
 	if (estatus != E_BOOK_ERROR_OK) {
 		error("E-Book query failed: status %d", estatus);
-		data->cb(NULL, 0, 1, 0, data->user_data);
+		data->contacts_cb(NULL, 0, 1, 0, data->user_data);
 		g_free(data);
 		return;
 	}
@@ -210,7 +206,7 @@ static void ebook_entry_cb(EBook *book, EBookStatus estatus,
 
 	len = vcard ? strlen(vcard) : 0;
 
-	data->cb(vcard, len, 1, 0, data->user_data);
+	data->contacts_cb(vcard, len, 1, 0, data->user_data);
 
 	g_free(vcard);
 	g_free(data);
@@ -249,7 +245,7 @@ static char *evcard_name_attribute_to_string(EVCard *evcard)
 static void cache_cb(EBook *book, EBookStatus estatus, GList *contacts,
 							void *user_data)
 {
-	struct cache_query *data = user_data;
+	struct context_query *data = user_data;
 	GList *l;
 
 	if (estatus != E_BOOK_ERROR_OK) {
@@ -411,13 +407,13 @@ done:
 int phonebook_pull(const char *name, const struct apparam_field *params,
 					phonebook_cb cb, void *user_data)
 {
-	struct contacts_query *data;
+	struct context_query *data;
 	EBookQuery *query;
 
 	query = e_book_query_any_field_contains("");
 
-	data = g_new0(struct contacts_query, 1);
-	data->cb = cb;
+	data = g_new0(struct context_query, 1);
+	data->contacts_cb = cb;
 	data->params = params;
 	data->user_data = user_data;
 
@@ -432,10 +428,10 @@ int phonebook_get_entry(const char *folder, const char *id,
 					const struct apparam_field *params,
 					phonebook_cb cb, void *user_data)
 {
-	struct contacts_query *data;
+	struct context_query *data;
 
-	data = g_new0(struct contacts_query, 1);
-	data->cb = cb;
+	data = g_new0(struct context_query, 1);
+	data->contacts_cb = cb;
 	data->params = params;
 	data->user_data = user_data;
 
@@ -450,7 +446,7 @@ int phonebook_get_entry(const char *folder, const char *id,
 int phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
 			phonebook_cache_ready_cb ready_cb, void *user_data)
 {
-	struct cache_query *data;
+	struct context_query *data;
 	EBookQuery *query;
 	gboolean ret;
 
@@ -459,7 +455,7 @@ int phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
 
 	query = e_book_query_any_field_contains("");
 
-	data = g_new0(struct cache_query, 1);
+	data = g_new0(struct context_query, 1);
 	data->entry_cb = entry_cb;
 	data->ready_cb = ready_cb;
 	data->user_data = user_data;
-- 
1.7.0.4


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox