diff options
author | Luiz Augusto von Dentz <luiz.dentz@openbossa.org> | 2007-03-26 13:39:46 +0000 |
---|---|---|
committer | Luiz Augusto von Dentz <luiz.dentz@openbossa.org> | 2007-03-26 13:39:46 +0000 |
commit | 82cef341d2adb711fc637c6b04d10862ef4120ce (patch) | |
tree | 7e7d5064fdb1bf4eaf14348d7b9b51510425c414 /network/connection.c | |
parent | 9bea84c70ceca8efd7f1137c5aa3425e77c196cf (diff) |
Fixes to use non-bloking socket on connect.
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, |