summaryrefslogtreecommitdiffstats
path: root/network/connection.c
diff options
context:
space:
mode:
authorLuiz Augusto von Dentz <luiz.dentz@openbossa.org>2007-03-26 13:39:46 +0000
committerLuiz Augusto von Dentz <luiz.dentz@openbossa.org>2007-03-26 13:39:46 +0000
commit82cef341d2adb711fc637c6b04d10862ef4120ce (patch)
tree7e7d5064fdb1bf4eaf14348d7b9b51510425c414 /network/connection.c
parent9bea84c70ceca8efd7f1137c5aa3425e77c196cf (diff)
Fixes to use non-bloking socket on connect.
Diffstat (limited to 'network/connection.c')
-rw-r--r--network/connection.c162
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,