Re: [PATCH][RFC] Fix SDP resolving segfault

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Manuel,

On Fri, Jul 23, 2010 at 11:37 PM, Luiz Augusto von Dentz
<luiz.dentz@xxxxxxxxx> wrote:
> Hi,
>
> On Wed, Jul 21, 2010 at 6:11 PM, Manuel Naranjo <manuel@xxxxxxxxxxxx> wrote:
>> I think this is the one that really fix the problem. I see connect_watch
>> getting called and then getting into the crash. I have a nice log with the
>> tracing feature I sent the other day, here's the end of it (the hole thing
>> is almost 40 megs if someone wants just ask for it).
>
> I just figure out that our connect_watch in glib_helper.c is not quite
> right, it should be something similar as we have btio.c, specially
> this one is particular important:
>
>        /* If the user aborted this connect attempt */
>        if ((cond & G_IO_NVAL) || check_nval(io))
>                return FALSE;
>
> It is probably because of not having this check that the cb is still
> called after bt_cancel_discovery. Of course this doesn't invalidate
> your fix to bt_cancel_discovery itself, but I guess this should also
> be included to safe that the callback is not called after cancelling
> the discovery.

Can you try the patch attached to this email?


-- 
Luiz Augusto von Dentz
Computer Engineer
From 28953f5b419693d8281f057055a34d9bc3e4442e Mon Sep 17 00:00:00 2001
From: Luiz Augusto von Dentz <luiz.dentz-von@xxxxxxxxx>
Date: Wed, 28 Jul 2010 16:41:12 +0300
Subject: [PATCH] core: fix not handling sdp connection errors properly

---
 src/glib-helper.c |  145 +++++++++++++++++++++++++++++++++++++----------------
 1 files changed, 101 insertions(+), 44 deletions(-)

diff --git a/src/glib-helper.c b/src/glib-helper.c
index 41f5e3c..afd664e 100644
--- a/src/glib-helper.c
+++ b/src/glib-helper.c
@@ -44,6 +44,8 @@
 #include <glib.h>
 
 #include "glib-helper.h"
+#include "btio.h"
+#include "log.h"
 
 /* Number of seconds to keep a sdp_session_t in the cache */
 #define CACHE_TIMEOUT 2
@@ -98,7 +100,7 @@ static sdp_session_t *get_sdp_session(const bdaddr_t *src, const bdaddr_t *dst)
 		return session;
 	}
 
-	return sdp_connect(src, dst, SDP_NON_BLOCKING);
+	return NULL;
 }
 
 static void cache_sdp_session(bdaddr_t *src, bdaddr_t *dst,
@@ -143,6 +145,7 @@ struct search_context {
 	bdaddr_t		src;
 	bdaddr_t		dst;
 	sdp_session_t		*session;
+	GIOChannel		*io;
 	bt_callback_t		cb;
 	bt_destroy_t		destroy;
 	gpointer		user_data;
@@ -245,56 +248,99 @@ failed:
 	return FALSE;
 }
 
-static gboolean connect_watch(GIOChannel *chan, GIOCondition cond, gpointer user_data)
+static int sdp_search(struct search_context *ctxt)
 {
-	struct search_context *ctxt = user_data;
+	GIOChannel *chan;
 	sdp_list_t *search, *attrids;
 	uint32_t range = 0x0000ffff;
-	socklen_t len;
-	int sk, err = 0;
-
-	sk = g_io_channel_unix_get_fd(chan);
-	ctxt->io_id = 0;
+	int err, sk;
 
-	len = sizeof(err);
-	if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
-		err = errno;
-		goto failed;
-	}
-
-	if (err != 0)
-		goto failed;
-
-	if (sdp_set_notify(ctxt->session, search_completed_cb, ctxt) < 0) {
-		err = EIO;
-		goto failed;
-	}
+	err = sdp_set_notify(ctxt->session, search_completed_cb, ctxt);
+	if (err < 0)
+		return err;
 
 	search = sdp_list_append(NULL, &ctxt->uuid);
 	attrids = sdp_list_append(NULL, &range);
-	if (sdp_service_search_attr_async(ctxt->session,
-				search, SDP_ATTR_REQ_RANGE, attrids) < 0) {
-		sdp_list_free(attrids, NULL);
-		sdp_list_free(search, NULL);
-		err = EIO;
-		goto failed;
-	}
 
+	err = sdp_service_search_attr_async(ctxt->session, search,
+						SDP_ATTR_REQ_RANGE, attrids);
 	sdp_list_free(attrids, NULL);
 	sdp_list_free(search, NULL);
+	if (err < 0)
+		return err;
+
+	sk = sdp_get_socket(ctxt->session);
+	chan = g_io_channel_unix_new(sk);
 
 	/* Set callback responsible for update the internal SDP transaction */
 	ctxt->io_id = g_io_add_watch(chan,
 				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
 				search_process_cb, ctxt);
-	return FALSE;
+
+	return 0;
+}
+
+static void connect_watch(GIOChannel *chan, GError *gerr, gpointer user_data)
+{
+	struct search_context *ctxt = user_data;
+	int sk, err = 0;
+
+	if (gerr) {
+		err = -EHOSTDOWN;
+		goto failed;
+	}
+
+	g_io_channel_set_close_on_unref(ctxt->io, FALSE);
+	g_io_channel_unref(ctxt->io);
+	ctxt->io = NULL;
+
+	sk = g_io_channel_unix_get_fd(chan);
+	ctxt->session = sdp_create(sk, SDP_NON_BLOCKING);
+	if (ctxt->session == NULL) {
+		err = -ENOMEM;
+		goto failed;
+	}
+
+	err = sdp_search(ctxt);
+	if (err < 0)
+		goto failed;
+
+	return;
 
 failed:
+	if (ctxt->session) {
+		sdp_close(ctxt->session);
+		ctxt->session = NULL;
+	}
+
+	if (ctxt->io) {
+		g_io_channel_shutdown(ctxt->io, TRUE, NULL);
+		g_io_channel_unref(ctxt->io);
+		ctxt->io = NULL;
+	}
+
+	if (ctxt->cb)
+		ctxt->cb(NULL, err, ctxt->user_data);
+
+	search_context_cleanup(ctxt);
+}
+
+static gboolean sdp_resume(gpointer data)
+{
+	struct search_context *ctxt = data;
+	int err;
+
+	ctxt->io_id = 0;
+
+	err = sdp_search(ctxt);
+	if (err == 0)
+		return FALSE;
+
 	sdp_close(ctxt->session);
 	ctxt->session = NULL;
 
 	if (ctxt->cb)
-		ctxt->cb(NULL, -err, ctxt->user_data);
+		ctxt->cb(NULL, err, ctxt->user_data);
 
 	search_context_cleanup(ctxt);
 
@@ -306,15 +352,11 @@ static int create_search_context(struct search_context **ctxt,
 				uuid_t *uuid)
 {
 	sdp_session_t *s;
-	GIOChannel *chan;
+	GError *err = NULL;
 
 	if (!ctxt)
 		return -EINVAL;
 
-	s = get_sdp_session(src, dst);
-	if (!s)
-		return -errno;
-
 	*ctxt = g_try_malloc0(sizeof(struct search_context));
 	if (!*ctxt) {
 		sdp_close(s);
@@ -323,14 +365,27 @@ static int create_search_context(struct search_context **ctxt,
 
 	bacpy(&(*ctxt)->src, src);
 	bacpy(&(*ctxt)->dst, dst);
-	(*ctxt)->session = s;
 	(*ctxt)->uuid = *uuid;
 
-	chan = g_io_channel_unix_new(sdp_get_socket(s));
-	(*ctxt)->io_id = g_io_add_watch(chan,
-				G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-				connect_watch, *ctxt);
-	g_io_channel_unref(chan);
+	s = get_sdp_session(src, dst);
+	if (s != NULL) {
+		(*ctxt)->session = s;
+		(*ctxt)->io_id = g_idle_add(sdp_resume, *ctxt);
+		return 0;
+	}
+
+	(*ctxt)->io = bt_io_connect(BT_IO_L2CAP, connect_watch, *ctxt,
+					NULL, &err,
+					BT_IO_OPT_SOURCE_BDADDR, src,
+					BT_IO_OPT_DEST_BDADDR, dst,
+					BT_IO_OPT_PSM, SDP_PSM,
+					BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_SDP,
+					BT_IO_OPT_INVALID);
+	if ((*ctxt)->io == NULL) {
+		g_error_free(err);
+		search_context_cleanup(*ctxt);
+		return -EINVAL;
+	}
 
 	return 0;
 }
@@ -391,15 +446,17 @@ int bt_cancel_discovery(const bdaddr_t *src, const bdaddr_t *dst)
 		return -ENODATA;
 
 	ctxt = match->data;
-	if (!ctxt->session)
-		return -ENOTCONN;
-
 	if (ctxt->io_id)
 		g_source_remove(ctxt->io_id);
 
 	if (ctxt->session)
 		sdp_close(ctxt->session);
 
+	if (ctxt->io) {
+		g_io_channel_shutdown(ctxt->io, TRUE, NULL);
+		g_io_channel_unref(ctxt->io);
+	}
+
 	search_context_cleanup(ctxt);
 	return 0;
 }
-- 
1.7.0.4


[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux