diff options
Diffstat (limited to 'network/connection.c')
| -rw-r--r-- | network/connection.c | 162 | 
1 files changed, 113 insertions, 49 deletions
| diff --git a/network/connection.c b/network/connection.c index ea2c269c..e83dfe81 100644 --- a/network/connection.c +++ b/network/connection.c @@ -63,7 +63,7 @@ struct __service_16 {  	uint16_t src;  } __attribute__ ((packed)); -static gboolean l2cap_io_cb(GIOChannel *chan, GIOCondition cond, +static gboolean bnep_connect_cb(GIOChannel *chan, GIOCondition cond,  				gpointer data)  {  	struct network_conn *nc = data; @@ -119,7 +119,7 @@ static gboolean l2cap_io_cb(GIOChannel *chan, GIOCondition cond,  	sk = g_io_channel_unix_get_fd(chan);  	if (bnep_connadd(sk, BNEP_SVC_PANU, nc->dev)) { -		error("bnep0 could not be added"); +		error("%s could not be added", nc->dev);  		goto failed;  	} @@ -129,21 +129,22 @@ static gboolean l2cap_io_cb(GIOChannel *chan, GIOCondition cond,  			NETWORK_CONNECTION_INTERFACE, "Connected");  	send_message_and_unref(nc->conn, signal); - +	info("%s connected", nc->dev);  failed: +	signal = dbus_message_new_signal(nc->path, +			NETWORK_CONNECTION_INTERFACE, "Disconnected"); + +	send_message_and_unref(nc->conn, signal);  	g_io_channel_unref(chan);  	return FALSE;  } -int bnep_create_connection(int sk, struct network_conn *nc) +int bnep_connect(GIOChannel *io, struct network_conn *nc)  {  	struct bnep_setup_conn_req *req;  	struct __service_16 *s;  	unsigned char pkt[BNEP_MTU]; -	GIOChannel *io; - -	io = g_io_channel_unix_new(sk); -	g_io_channel_set_close_on_unref(io, TRUE); +	int sk;  	/* Send request */  	req = (void *) pkt; @@ -154,9 +155,10 @@ int bnep_create_connection(int sk, struct network_conn *nc)  	s->dst = htons(nc->id);  	s->src = htons(BNEP_SVC_PANU); +	sk = g_io_channel_unix_get_fd(io);  	if (send(sk, pkt, sizeof(*req) + sizeof(*s), 0) != -1) {  		g_io_add_watch(io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, -				(GIOFunc) l2cap_io_cb, nc); +				(GIOFunc) bnep_connect_cb, nc);  		return 0;  	} @@ -164,6 +166,102 @@ int bnep_create_connection(int sk, struct network_conn *nc)  	return -1;  } +static gboolean l2cap_connect_cb(GIOChannel *chan, +			GIOCondition cond, gpointer data) +{ +	struct network_conn *nc = data; +	DBusMessage *signal; +	socklen_t len; +	int sk, ret; + +	if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) +		goto failed; + +	sk = g_io_channel_unix_get_fd(chan); + +	len = sizeof(ret); +	if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { +		error("getsockopt(SO_ERROR): %s (%d)", strerror(errno), errno); +		goto failed; +	} + +	if (ret != 0) { +		error("connect(): %s (%d)", strerror(errno), errno); +		goto failed; +	} + +	if (bnep_connect(chan, nc)) { +		error("connect(): %s (%d)", strerror(errno), errno); +		signal = dbus_message_new_signal(nc->path, +				NETWORK_CONNECTION_INTERFACE, "Disconnected"); +		send_message_and_unref(nc->conn, signal); +		goto failed; +	} + +	return FALSE; +failed: +	g_io_channel_unref(chan); +	return FALSE; +} + +static int l2cap_connect(int sk, struct network_conn *nc) +{ +	struct l2cap_options l2o; +	struct sockaddr_l2 l2a; +	socklen_t olen; +	char addr[18]; +	GIOChannel *io; + +	ba2str(&nc->dst, addr); +	info("Connecting to %s", addr); + +	/* Setup L2CAP options according to BNEP spec */ +	memset(&l2o, 0, sizeof(l2o)); +	olen = sizeof(l2o); +	getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &olen); +	l2o.imtu = l2o.omtu = BNEP_MTU; +	setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, sizeof(l2o)); + +	memset(&l2a, 0, sizeof(l2a)); +	l2a.l2_family = AF_BLUETOOTH; +	bacpy(&l2a.l2_bdaddr, &nc->src); + +	if (bind(sk, (struct sockaddr *) &l2a, sizeof(l2a))) { +		error("Bind failed. %s(%d)", strerror(errno), errno); +		return -1; +	} + +	memset(&l2a, 0, sizeof(l2a)); +	l2a.l2_family = AF_BLUETOOTH; +	bacpy(&l2a.l2_bdaddr, &nc->dst); +	l2a.l2_psm = htobs(BNEP_PSM); + +	if (set_nonblocking(sk) < 0) { +		error("Set non blocking: %s (%d)", strerror(errno), errno); +		return -1; +	} + +	io = g_io_channel_unix_new(sk); +	g_io_channel_set_close_on_unref(io, FALSE); + +	if (connect(sk, (struct sockaddr *) &l2a, sizeof(l2a))) { +		if (!(errno == EAGAIN || errno == EINPROGRESS)) { +			error("Connect failed. %s(%d)", strerror(errno), +					errno); +			g_io_channel_unref(io); +			return -1; +		} +		g_io_add_watch(io, G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL, +				(GIOFunc) l2cap_connect_cb, nc); + +	} else { +		l2cap_connect_cb(io, G_IO_OUT, nc); +		g_io_channel_unref(io); +	} + +	return 0; +} +  static DBusHandlerResult get_address(DBusConnection *conn, DBusMessage *msg,  					void *data)  { @@ -233,13 +331,9 @@ static DBusHandlerResult connection_connect(DBusConnection *conn,  						DBusMessage *msg, void *data)  {  	struct network_conn *nc = data; -	struct l2cap_options l2o; -	struct sockaddr_l2 l2a; -	socklen_t olen;  	int sk;  	DBusError derr; -	DBusMessage *reply; -	char addr[18]; +	DBusMessage *reply, *signal;  	dbus_error_init(&derr);  	if (!dbus_message_get_args(msg, &derr, @@ -249,9 +343,6 @@ static DBusHandlerResult connection_connect(DBusConnection *conn,  		return DBUS_HANDLER_RESULT_HANDLED;  	} -	ba2str(&nc->dst, addr); -	info("Connecting to %s", addr); -  	sk = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);  	if (sk < 0) {  		error("Cannot create L2CAP socket. %s(%d)", strerror(errno), @@ -259,41 +350,12 @@ static DBusHandlerResult connection_connect(DBusConnection *conn,  		goto fail;  	} -	/* Setup L2CAP options according to BNEP spec */ -	memset(&l2o, 0, sizeof(l2o)); -	olen = sizeof(l2o); -	getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &olen); -	l2o.imtu = l2o.omtu = BNEP_MTU; -	setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, sizeof(l2o)); - -	memset(&l2a, 0, sizeof(l2a)); -	l2a.l2_family = AF_BLUETOOTH; -	bacpy(&l2a.l2_bdaddr, &nc->src); - -	if (bind(sk, (struct sockaddr *) &l2a, sizeof(l2a))) { -		error("Bind failed. %s(%d)", strerror(errno), errno); -		goto fail; -	} - -	memset(&l2a, 0, sizeof(l2a)); -	l2a.l2_family = AF_BLUETOOTH; -	bacpy(&l2a.l2_bdaddr, &nc->dst); -	l2a.l2_psm = htobs(BNEP_PSM); - -	/* FIXME: connection must be non-blocking */ -	if (connect(sk, (struct sockaddr *) &l2a, sizeof(l2a))) { +	if(l2cap_connect(sk, nc)) {  		error("Connect failed. %s(%d)", strerror(errno), errno);  		goto fail;  	} -	if (bnep_create_connection(sk, nc)) { -		error("Connection to %s failed. %s(%d)", addr, -				strerror(errno), errno); -		goto fail; -	} - -	info("%s connected", nc->dev); - +	/* FIXME: Do not replay until connection be connected */  	reply = dbus_message_new_method_return(msg);  	if (!reply)  		return DBUS_HANDLER_RESULT_NEED_MEMORY; @@ -301,8 +363,10 @@ static DBusHandlerResult connection_connect(DBusConnection *conn,  	return send_message_and_unref(conn, reply);  fail:  	err_connection_failed(conn, msg, strerror(errno)); +	signal = dbus_message_new_signal(nc->path, +			NETWORK_CONNECTION_INTERFACE, "Disconnected"); +	send_message_and_unref(nc->conn, signal);  	return DBUS_HANDLER_RESULT_HANDLED; -  }  static DBusHandlerResult connection_disconnect(DBusConnection *conn, | 
