diff options
| -rw-r--r-- | serial/manager.c | 103 | 
1 files changed, 69 insertions, 34 deletions
| diff --git a/serial/manager.c b/serial/manager.c index 8eb1b906..8d7af3f9 100644 --- a/serial/manager.c +++ b/serial/manager.c @@ -64,11 +64,13 @@  struct pending_connect {  	DBusConnection	*conn;  	DBusMessage	*msg; +	DBusPendingCall *pcall;		/* Pending get handles/records */  	char		*bda;		/* Destination address  */  	char		*adapter_path;	/* Adapter D-Bus path   */  	char		*pattern;	/* Connection request pattern */  	bdaddr_t	src;  	uint8_t		channel; +	guint		io_id;		/* GIOChannel watch id */  	int		id;		/* RFCOMM device id */  	int		ntries;		/* Open attempts */  	int 		canceled;	/* Operation canceled */ @@ -119,15 +121,11 @@ static void pending_connect_free(struct pending_connect *pc)  		g_free(pc->pattern);  	if (pc->adapter_path)  		g_free(pc->adapter_path); +	if (pc->pcall) +		dbus_pending_call_unref(pc->pcall);  	g_free(pc);  } -static void pending_connect_remove(struct pending_connect *pc) -{ -	pending_connects = g_slist_remove(pending_connects, pc); -	pending_connect_free(pc); -} -  static struct pending_connect *find_pending_connect_by_pattern(const char *bda,  							const char *pattern)  { @@ -258,7 +256,7 @@ static int rfcomm_bind(bdaddr_t *src, bdaddr_t *dst, int16_t dev_id, uint8_t ch)  static void open_notify(int fd, int err, void *data)  {  	char port_name[16]; -	const char *owner, *pname = port_name; +	const char *pname = port_name;  	struct pending_connect *pc = data;  	DBusMessage *reply;  	bdaddr_t dst; @@ -275,14 +273,6 @@ static void open_notify(int fd, int err, void *data)  		return;  	} -	/* FIXME: it must be a per request listener */ -	owner = dbus_message_get_sender(pc->msg); -	if (!dbus_bus_name_has_owner(pc->conn, owner, NULL)) { -		error("Connect requestor %s exited", owner); -		rfcomm_release(pc->id); -		return; -	} -  	snprintf(port_name, sizeof(port_name), "/dev/rfcomm%d", pc->id);  	/* Reply to the requestor */ @@ -299,7 +289,49 @@ static void open_notify(int fd, int err, void *data)  			DBUS_TYPE_INVALID);  	str2ba(pc->bda, &dst); -	port_add_listener(pc->conn, pc->id, &dst, fd, port_name, owner); + +	/* Add the RFCOMM connection listener */ +	port_add_listener(pc->conn, pc->id, &dst, fd, +			port_name, dbus_message_get_sender(pc->msg)); +} + +static void transaction_owner_exited(const char *name, void *data) +{ +	GSList *l, *tmp = NULL; +	debug("transaction owner %s exited", name); + +	/* Clean all pending calls that belongs to this owner */ +	for (l = pending_connects; l != NULL; l = l->next) { +		struct pending_connect *pc = l->data; +		if (strcmp(name, dbus_message_get_sender(pc->msg)) != 0) { +			tmp = g_slist_append(tmp, pc); +			continue; +		} + +		if (pc->pcall) +			dbus_pending_call_cancel(pc->pcall); + +		if (pc->io_id > 0) +			g_source_remove(pc->io_id); + +		if (pc->id >= 0) +			rfcomm_release(pc->id); + +		pending_connect_free(pc); +	} + +	g_slist_free(pending_connects); +	pending_connects = tmp; +} + +static void pending_connect_remove(struct pending_connect *pc) +{ +	/* Remove the connection request owner */ +	name_listener_remove(pc->conn, dbus_message_get_sender(pc->msg), +				(name_cb_t) transaction_owner_exited, NULL); + +	pending_connects = g_slist_remove(pending_connects, pc); +	pending_connect_free(pc);  }  static gboolean rfcomm_connect_cb(GIOChannel *chan, @@ -377,8 +409,7 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan,  	open_notify(fd, 0, pc);  fail: -	pending_connects = g_slist_remove(pending_connects, pc); -	pending_connect_free(pc); +	pending_connect_remove(pc);  	if (close_chan)  		g_io_channel_close(chan); @@ -421,8 +452,8 @@ static int rfcomm_connect(struct pending_connect *pc)  		}  		debug("Connect in progress"); -		g_io_add_watch(io, G_IO_OUT | G_IO_ERR | G_IO_NVAL | G_IO_HUP, -						(GIOFunc) rfcomm_connect_cb, pc); +		pc->io_id = g_io_add_watch(io, G_IO_OUT | G_IO_ERR | G_IO_NVAL | G_IO_HUP, +							(GIOFunc) rfcomm_connect_cb, pc);  	} else {  		debug("Connect succeeded with first try");  		(void) rfcomm_connect_cb(io, G_IO_OUT, pc); @@ -551,8 +582,7 @@ static void record_reply(DBusPendingCall *call, void *data)  	}  fail: -	pending_connects = g_slist_remove(pending_connects, pc); -	pending_connect_free(pc); +	pending_connect_remove(pc);  done:  	if (rec)  		sdp_record_free(rec); @@ -563,7 +593,6 @@ static int get_record(struct pending_connect *pc, uint32_t handle,  					DBusPendingCallNotifyFunction cb)  {  	DBusMessage *msg; -	DBusPendingCall *pending;  	msg = dbus_message_new_method_call("org.bluez", pc->adapter_path,  			"org.bluez.Adapter", "GetRemoteServiceRecord"); @@ -575,14 +604,13 @@ static int get_record(struct pending_connect *pc, uint32_t handle,  			DBUS_TYPE_UINT32, &handle,  			DBUS_TYPE_INVALID); -	if (dbus_connection_send_with_reply(pc->conn, msg, &pending, -1) == FALSE) { +	if (dbus_connection_send_with_reply(pc->conn, msg, &pc->pcall, -1) == FALSE) {  		error("Can't send D-Bus message.");  		return -1;  	} -	dbus_pending_call_set_notify(pending, cb, pc, NULL); +	dbus_pending_call_set_notify(pc->pcall, cb, pc, NULL);  	dbus_message_unref(msg); -	dbus_pending_call_unref(pending);  	return 0;  } @@ -637,15 +665,13 @@ static void handles_reply(DBusPendingCall *call, void *data)  	return;  fail:  	dbus_message_unref(reply); -	pending_connects = g_slist_remove(pending_connects, pc); -	pending_connect_free(pc); +	pending_connect_remove(pc);  }  static int get_handles(struct pending_connect *pc, const char *uuid,  					DBusPendingCallNotifyFunction cb)  {  	DBusMessage *msg; -	DBusPendingCall *pending;  	msg = dbus_message_new_method_call("org.bluez", pc->adapter_path,  				"org.bluez.Adapter", "GetRemoteServiceHandles"); @@ -657,14 +683,13 @@ static int get_handles(struct pending_connect *pc, const char *uuid,  			DBUS_TYPE_STRING, &uuid,  			DBUS_TYPE_INVALID); -	if (dbus_connection_send_with_reply(pc->conn, msg, &pending, -1) == FALSE) { +	if (dbus_connection_send_with_reply(pc->conn, msg, &pc->pcall, -1) == FALSE) {  		error("Can't send D-Bus message.");  		return -1;  	} -	dbus_pending_call_set_notify(pending, cb, pc, NULL); +	dbus_pending_call_set_notify(pc->pcall, cb, pc, NULL);  	dbus_message_unref(msg); -	dbus_pending_call_unref(pending);  	return 0;  } @@ -748,6 +773,7 @@ static DBusHandlerResult create_port(DBusConnection *conn,  	pc->conn = dbus_connection_ref(conn);  	pc->msg = dbus_message_ref(msg);  	pc->bda = g_strdup(bda); +	pc->id = -1;  	pc->pattern = g_strdup(pattern);  	pc->adapter_path = g_malloc0(16);  	snprintf(pc->adapter_path, 16, "/org/bluez/hci%d", dev_id); @@ -761,6 +787,8 @@ static DBusHandlerResult create_port(DBusConnection *conn,  			return err_not_supported(conn, msg);  		}  		pending_connects = g_slist_append(pending_connects, pc); +		name_listener_add(conn, dbus_message_get_sender(msg), +				(name_cb_t) transaction_owner_exited, NULL);  		return DBUS_HANDLER_RESULT_HANDLED;  	} @@ -784,6 +812,8 @@ static DBusHandlerResult create_port(DBusConnection *conn,  			return err_not_supported(conn, msg);  		}  		pending_connects = g_slist_append(pending_connects, pc); +		name_listener_add(conn, dbus_message_get_sender(msg), +				(name_cb_t) transaction_owner_exited, NULL);  		return DBUS_HANDLER_RESULT_HANDLED;  	} @@ -926,6 +956,7 @@ static DBusHandlerResult connect_service(DBusConnection *conn,  	pc->conn = dbus_connection_ref(conn);  	pc->msg = dbus_message_ref(msg);  	pc->bda = g_strdup(bda); +	pc->id = -1;  	pc->pattern = g_strdup(pattern);  	pc->adapter_path = g_malloc0(16);  	snprintf(pc->adapter_path, 16, "/org/bluez/hci%d", dev_id); @@ -939,7 +970,7 @@ static DBusHandlerResult connect_service(DBusConnection *conn,  			return err_not_supported(conn, msg);  		}  		pending_connects = g_slist_append(pending_connects, pc); -		return DBUS_HANDLER_RESULT_HANDLED; +		goto done;  	}  	/* Record handle or channel */ @@ -962,7 +993,7 @@ static DBusHandlerResult connect_service(DBusConnection *conn,  			return err_not_supported(conn, msg);  		}  		pending_connects = g_slist_append(pending_connects, pc); -		return DBUS_HANDLER_RESULT_HANDLED; +		goto done;  	}  	/* RFCOMM Channel range: 1 - 30 */ @@ -984,6 +1015,10 @@ static DBusHandlerResult connect_service(DBusConnection *conn,  		pending_connect_free(pc);  		return err_connection_failed(conn, msg, strerr);  	} +done: +	name_listener_add(conn, dbus_message_get_sender(msg), +			(name_cb_t) transaction_owner_exited, NULL); +  	return DBUS_HANDLER_RESULT_HANDLED;  } | 
