?? connection.c
字號:
/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org> * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <stdio.h>#include <errno.h>#include <unistd.h>#include <sys/stat.h>#include <netinet/in.h>#include <bluetooth/bluetooth.h>#include <bluetooth/hci.h>#include <bluetooth/hci_lib.h>#include <bluetooth/l2cap.h>#include <bluetooth/bnep.h>#include <glib.h>#include "logging.h"#include "dbus.h"#include "dbus-helper.h"#include "textfile.h"#include "error.h"#include "common.h"#include "connection.h"#define NETWORK_CONNECTION_INTERFACE "org.bluez.network.Connection"typedef enum { CONNECTED, CONNECTING, DISCONNECTED} conn_state;struct network_conn { DBusMessage *msg; bdaddr_t store; bdaddr_t src; bdaddr_t dst; char *path; /* D-Bus path */ char dev[16]; /* Interface name */ char *name; /* Service Name */ char *desc; /* Service Description*/ uint16_t id; /* Role: Service Class Identifier */ conn_state state; int sk;};struct __service_16 { uint16_t dst; uint16_t src;} __attribute__ ((packed));static DBusConnection *connection = NULL;static const char *prefix = NULL;static gboolean bnep_watchdog_cb(GIOChannel *chan, GIOCondition cond, gpointer data){ struct network_conn *nc = data; if (connection != NULL) { dbus_connection_emit_signal(connection, nc->path, NETWORK_CONNECTION_INTERFACE, "Disconnected", DBUS_TYPE_INVALID); } info("%s disconnected", nc->dev); nc->state = DISCONNECTED; memset(nc->dev, 0, 16); strncpy(nc->dev, prefix, strlen(prefix)); g_io_channel_close(chan); return FALSE;}static gboolean bnep_connect_cb(GIOChannel *chan, GIOCondition cond, gpointer data){ struct network_conn *nc = data; struct bnep_control_rsp *rsp; char pkt[BNEP_MTU]; gsize r; int sk; DBusMessage *reply; const char *pdev; if (cond & G_IO_NVAL) return FALSE; if (cond & (G_IO_HUP | G_IO_ERR)) { error("Hangup or error on l2cap server socket"); goto failed; } memset(pkt, 0, BNEP_MTU); if (g_io_channel_read(chan, pkt, sizeof(pkt) - 1, &r) != G_IO_ERROR_NONE) { error("IO Channel read error"); goto failed; } if (r <= 0) { error("No packet received on l2cap socket"); goto failed; } errno = EPROTO; if (r < sizeof(*rsp)) { error("Packet received is not bnep type"); goto failed; } rsp = (void *) pkt; if (rsp->type != BNEP_CONTROL) { error("Packet received is not bnep type"); goto failed; } if (rsp->ctrl != BNEP_SETUP_CONN_RSP) return TRUE; r = ntohs(rsp->resp); if (r != BNEP_SUCCESS) { error("bnep failed"); goto failed; } sk = g_io_channel_unix_get_fd(chan); if (bnep_connadd(sk, BNEP_SVC_PANU, nc->dev)) { error("%s could not be added", nc->dev); goto failed; } bnep_if_up(nc->dev, nc->id); dbus_connection_emit_signal(connection, nc->path, NETWORK_CONNECTION_INTERFACE, "Connected", DBUS_TYPE_INVALID); reply = dbus_message_new_method_return(nc->msg); pdev = nc->dev; dbus_message_append_args(reply, DBUS_TYPE_STRING, &pdev, DBUS_TYPE_INVALID); send_message_and_unref(connection, reply); nc->state = CONNECTED; info("%s connected", nc->dev); /* Start watchdog */ g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) bnep_watchdog_cb, nc); return FALSE;failed: if (nc->state != DISCONNECTED) { nc->state = DISCONNECTED; error_connection_attempt_failed(connection, nc->msg, EIO); g_io_channel_close(chan); } return FALSE;}static int bnep_connect(struct network_conn *nc){ struct bnep_setup_conn_req *req; struct __service_16 *s; unsigned char pkt[BNEP_MTU]; GIOChannel *io; int err = 0; /* Send request */ req = (void *) pkt; req->type = BNEP_CONTROL; req->ctrl = BNEP_SETUP_CONN_REQ; req->uuid_size = 2; /* 16bit UUID */ s = (void *) req->service; s->dst = htons(nc->id); s->src = htons(BNEP_SVC_PANU); io = g_io_channel_unix_new(nc->sk); g_io_channel_set_close_on_unref(io, FALSE); if (send(nc->sk, pkt, sizeof(*req) + sizeof(*s), 0) < 0) { err = -errno; goto out; } g_io_add_watch(io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) bnep_connect_cb, nc);out: g_io_channel_unref(io); return err;}static gboolean l2cap_connect_cb(GIOChannel *chan, GIOCondition cond, gpointer data){ struct network_conn *nc = data; socklen_t len; int sk, ret; if (cond & G_IO_NVAL) return FALSE; if (cond & (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(nc)) { error("connect(): %s (%d)", strerror(errno), errno); goto failed; } return FALSE;failed: nc->state = DISCONNECTED; error_connection_attempt_failed(connection, nc->msg, errno); g_io_channel_close(chan); return FALSE;}static int l2cap_connect(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(nc->sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &olen); l2o.imtu = l2o.omtu = BNEP_MTU; setsockopt(nc->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(nc->sk, (struct sockaddr *) &l2a, sizeof(l2a)) < 0) { error("Bind failed. %s(%d)", strerror(errno), errno); return -errno; } 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(nc->sk) < 0) { error("Set non blocking: %s (%d)", strerror(errno), errno); return -errno; } io = g_io_channel_unix_new(nc->sk); g_io_channel_set_close_on_unref(io, FALSE); if (connect(nc->sk, (struct sockaddr *) &l2a, sizeof(l2a))) { if (!(errno == EAGAIN || errno == EINPROGRESS)) { error("Connect failed. %s(%d)", strerror(errno), errno); g_io_channel_close(io); g_io_channel_unref(io); return -errno; } 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_adapter(DBusConnection *conn, DBusMessage *msg, void *data){ struct network_conn *nc = data; DBusMessage *reply; char addr[18]; const char *paddr = addr; ba2str(&nc->src, addr); reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; dbus_message_append_args(reply, DBUS_TYPE_STRING, &paddr, DBUS_TYPE_INVALID); return send_message_and_unref(conn, reply);}static DBusHandlerResult get_address(DBusConnection *conn, DBusMessage *msg, void *data){ struct network_conn *nc = data; DBusMessage *reply; char addr[18]; const char *paddr = addr; ba2str(&nc->dst, addr); reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; dbus_message_append_args(reply, DBUS_TYPE_STRING, &paddr, DBUS_TYPE_INVALID); return send_message_and_unref(conn, reply);}static DBusHandlerResult get_uuid(DBusConnection *conn, DBusMessage *msg, void *data){ struct network_conn *nc = data; const char *uuid; DBusMessage *reply; uuid = bnep_uuid(nc->id); reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; dbus_message_append_args(reply, DBUS_TYPE_STRING, &uuid, DBUS_TYPE_INVALID); return send_message_and_unref(conn, reply);}static DBusHandlerResult get_name(DBusConnection *conn, DBusMessage *msg, void *data){ struct network_conn *nc = data; DBusMessage *reply; if (!nc->name) { error_failed(conn, msg, "Cannot find service name"); return DBUS_HANDLER_RESULT_HANDLED; } reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; dbus_message_append_args(reply, DBUS_TYPE_STRING, &nc->name, DBUS_TYPE_INVALID); return send_message_and_unref(conn, reply);}static DBusHandlerResult get_description(DBusConnection *conn, DBusMessage *msg, void *data){ struct network_conn *nc = data; DBusMessage *reply; if (!nc->desc) { error_failed(conn, msg, "Cannot find service description"); return DBUS_HANDLER_RESULT_HANDLED;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -