diff options
| author | Ulisses Furquim <ulissesf@gmail.com> | 2006-09-06 22:33:16 +0000 | 
|---|---|---|
| committer | Ulisses Furquim <ulissesf@gmail.com> | 2006-09-06 22:33:16 +0000 | 
| commit | 4c47e772dbded0a7fe9d77346291bf24e2e07100 (patch) | |
| tree | 4c9ebd6ae9a6fca36834b378c1c294dae8c6c468 | |
| parent | b20069a85e89cf05849a4c4ed3b418c570535b01 (diff) | |
Use a timer when waiting for udev to create the rfcomm device node
| -rw-r--r-- | hcid/dbus-rfcomm.c | 160 | 
1 files changed, 100 insertions, 60 deletions
| diff --git a/hcid/dbus-rfcomm.c b/hcid/dbus-rfcomm.c index 90027a81..8142b227 100644 --- a/hcid/dbus-rfcomm.c +++ b/hcid/dbus-rfcomm.c @@ -50,8 +50,8 @@  #include "dbus.h"  /* Waiting for udev to create the device node */ -#define MAX_OPEN_TRIES 6 -#define OPEN_WAIT (1000 * 300) +#define MAX_OPEN_TRIES	5 +#define OPEN_WAIT	300  /* ms */  static int rfcomm_ctl = -1; @@ -73,6 +73,10 @@ struct pending_connect {  	int			canceled;  	struct sockaddr_rc	laddr;  	struct sockaddr_rc	raddr; + +	/* Used only when we wait for udev to create the device node */ +	struct rfcomm_node	*node; +	int			ntries;  };  static struct slist *pending_connects = NULL; @@ -199,15 +203,94 @@ static gboolean rfcomm_disconnect_cb(GIOChannel *io, GIOCondition cond,  	return FALSE;  } -static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, -					struct pending_connect *c) +static void rfcomm_connect_cb_devnode_opened(int fd, +					     struct pending_connect *c, +					     struct rfcomm_node *node)  { -	int sk, ret, err, fd = -1, i; -	socklen_t len; +	DBusMessage *reply = NULL;  	char *ptr; -	struct rfcomm_dev_req req; + +	reply = dbus_message_new_method_return(c->msg); +	if (!reply) { +		error_failed(c->conn, c->msg, ENOMEM); +		goto failed; +	} + +	ptr = node->name; +	if (!dbus_message_append_args(reply, +				      DBUS_TYPE_STRING, &ptr, +				      DBUS_TYPE_INVALID)) { +		error_failed(c->conn, c->msg, ENOMEM); +		goto failed; +	} + +	node->owner = strdup(dbus_message_get_sender(c->msg)); +	if (!node->owner) { +		error_failed(c->conn, c->msg, ENOMEM); +		goto failed; +	} + +	node->io = g_io_channel_unix_new(fd); +	g_io_channel_set_close_on_unref(node->io, TRUE); +	node->io_id = g_io_add_watch(node->io, G_IO_ERR | G_IO_HUP, +				     (GIOFunc) rfcomm_disconnect_cb, node); + +	send_reply_and_unref(c->conn, reply); + +	connected_nodes = slist_append(connected_nodes, node); + +	goto done; + +failed: +	close(fd); +	rfcomm_release(node, NULL); +	rfcomm_node_free(node); +	if (reply) +		dbus_message_unref(reply); +done: +	pending_connects = slist_remove(pending_connects, c); +	pending_connect_free(c); +} + +static gboolean rfcomm_connect_cb_continue(void *data) +{ +	struct pending_connect *c = data; +	struct rfcomm_node *node = c->node; +	int fd; + +	fd = open(node->name, O_RDONLY | O_NOCTTY); +	if (fd < 0) { +		if (++c->ntries >= MAX_OPEN_TRIES) { +			int err = errno; +			error("Could not open %s: %s (%d)", +			      node->name, strerror(err), err); +			error_connection_attempt_failed(c->conn, c->msg, err); +			goto failed; +		} +		return TRUE; +	} + +	rfcomm_connect_cb_devnode_opened(fd, c, node); + +	return FALSE; + +failed: +	rfcomm_release(node, NULL); +	rfcomm_node_free(node); + +	pending_connects = slist_remove(pending_connects, c); +	pending_connect_free(c); + +	return FALSE; +} + +static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, +				  struct pending_connect *c) +{  	struct rfcomm_node *node = NULL; -	DBusMessage *reply = NULL; +	struct rfcomm_dev_req req; +	int sk, ret, err, fd = -1; +	socklen_t len;  	if (c->canceled) {  		error_connect_canceled(c->conn, c->msg); @@ -267,65 +350,22 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond,  	rfcomm_node_name_from_id(node->id, node->name, sizeof(node->name)); -	/* FIXME: instead of looping here we should create a timer and -	 * return to the mainloop */ -	for (i = 0; i < MAX_OPEN_TRIES; i++) { -		fd = open(node->name, O_RDONLY | O_NOCTTY); -		if (fd >= 0) -			break; -		usleep(OPEN_WAIT); -	} - +	fd = open(node->name, O_RDONLY | O_NOCTTY);  	if (fd < 0) { -		err = errno; -		error("Could not open %s: %s (%d)", node->name, -				strerror(err), err); -		error_connection_attempt_failed(c->conn, c->msg, err); -		goto failed; +		c->node = node; +		c->ntries = 0; +		g_timeout_add(OPEN_WAIT, rfcomm_connect_cb_continue, c); +		return FALSE;  	} -	reply = dbus_message_new_method_return(c->msg); -	if (!reply) { -		error_failed(c->conn, c->msg, ENOMEM); -		goto failed; -	} +	rfcomm_connect_cb_devnode_opened(fd, c, node); -	ptr = node->name; -	if (!dbus_message_append_args(reply, -				DBUS_TYPE_STRING, &ptr, -				DBUS_TYPE_INVALID)) { -		error_failed(c->conn, c->msg, ENOMEM); -		goto failed; -	} - -	node->owner = strdup(dbus_message_get_sender(c->msg)); -	if (!node->owner) { -		error_failed(c->conn, c->msg, ENOMEM); -		goto failed; -	} - -        node->io = g_io_channel_unix_new(fd); -	g_io_channel_set_close_on_unref(node->io, TRUE); -	node->io_id = g_io_add_watch(node->io, G_IO_ERR | G_IO_HUP, -					(GIOFunc) rfcomm_disconnect_cb, node); - -	send_reply_and_unref(c->conn, reply); - -	connected_nodes = slist_append(connected_nodes, node); - -	goto done; +	return FALSE;  failed: -	if (fd >= 0) -		close(fd); -	if (node) { -		if (node->id >= 0) -			rfcomm_release(node, NULL); +	if (node)  		rfcomm_node_free(node); -	} -	if (reply) -		dbus_message_unref(reply); -done: +  	pending_connects = slist_remove(pending_connects, c);  	pending_connect_free(c); | 
