summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClaudio Takahasi <claudio.takahasi@openbossa.org>2007-08-22 15:01:52 +0000
committerClaudio Takahasi <claudio.takahasi@openbossa.org>2007-08-22 15:01:52 +0000
commit26c787542c3949e2b64564ce84c3f52761b275d1 (patch)
tree3a9915553f2d1a6edd73f9a7fdd8082b73f82bf8
parent9a2408e2e45e5b47c3f7019246d9260d7f864f4f (diff)
serial: added proxy for unix sockets
-rw-r--r--serial/manager.c374
-rw-r--r--serial/serial-api.txt8
-rw-r--r--serial/storage.c4
3 files changed, 273 insertions, 113 deletions
diff --git a/serial/manager.c b/serial/manager.c
index 15e0fca8..ace402b5 100644
--- a/serial/manager.c
+++ b/serial/manager.c
@@ -39,6 +39,7 @@
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/un.h>
#include <glib.h>
@@ -103,18 +104,25 @@ static struct {
{ NULL }
};
+typedef enum {
+ TTY_PROXY,
+ UNIX_SOCKET_PROXY,
+ UNKNOWN_PROXY_TYPE = 0xFF
+} proxy_type_t;
+
struct proxy {
bdaddr_t src;
bdaddr_t dst;
char *uuid128; /* UUID 128 */
- char *tty; /* TTY name */
+ char *address; /* TTY or Unix socket name */
+ proxy_type_t type; /* TTY or Unix socket */
struct termios sys_ti; /* Default TTY setting */
struct termios proxy_ti; /* Proxy TTY settings */
uint8_t channel; /* RFCOMM channel */
uint32_t record_id; /* Service record id */
guint listen_watch; /* Server listen watch */
- guint rfcomm_watch; /* RFCOMM connection watch */
- guint tty_watch; /* Openned TTY watch */
+ guint rfcomm_watch; /* RFCOMM watch: Remote */
+ guint local_watch; /* Local watch: TTY or Unix socket */
};
static DBusConnection *connection = NULL;
@@ -122,13 +130,12 @@ static GSList *pending_connects = NULL;
static GSList *ports_paths = NULL;
static GSList *proxies_paths = NULL;
static int rfcomm_ctl = -1;
+static int sk_counter = 0;
static void proxy_free(struct proxy *prx)
{
- if (prx->tty)
- g_free(prx->tty);
- if (prx->uuid128)
- g_free(prx->uuid128);
+ g_free(prx->address);
+ g_free(prx->uuid128);
g_free(prx);
}
@@ -1190,14 +1197,76 @@ static int remove_proxy_record(DBusConnection *conn, uint32_t rec_id)
return 0;
}
+static inline int unix_socket_connect(const char *address)
+{
+ struct sockaddr_un addr;
+ int err, sk;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = PF_UNIX;
+
+ if (strncmp("x00", address, 3) == 0) {
+ /*
+ * Abstract namespace: first byte NULL, x00
+ * must be removed from the original address.
+ */
+ strcpy(addr.sun_path + 1, address + 3);
+ } else {
+ /* Filesystem address */
+ strcpy(addr.sun_path, address);
+ }
+
+ /* Unix socket */
+ sk = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sk < 0) {
+ err = errno;
+ error("Can't create socket %s: %s(%d)",
+ address, strerror(err), err);
+ return -err;
+ }
+
+ if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ err = errno;
+ error("Unable to connect %s(%d)", strerror(err), err);
+ close(sk);
+ errno = err;
+ return -err;
+ }
+
+ return sk;
+}
+
+static inline int tty_open(const char *tty, struct termios *ti)
+{
+ int err, sk;
+
+ sk = open(tty, O_RDWR | O_NOCTTY);
+ if (sk < 0) {
+ err = errno;
+ error("Can't open TTY %s: %s(%d)", tty, strerror(err), err);
+ return -err;
+ }
+
+ if (ti && tcsetattr(sk, TCSANOW, ti) < 0) {
+ err = errno;
+ error("Can't change serial settings: %s(%d)",
+ strerror(err), err);
+ close(sk);
+ errno = err;
+ return -err;
+ }
+
+ return sk;
+}
+
static gboolean connect_event(GIOChannel *chan,
GIOCondition cond, gpointer data)
{
struct proxy *prx = data;
struct sockaddr_rc raddr;
- GIOChannel *node_io, *tty_io;
+ GIOChannel *rio, *lio;
socklen_t alen;
- int sk, nsk, tty_sk;
+ int sk, rsk, lsk;
if (cond & G_IO_NVAL)
return FALSE;
@@ -1211,40 +1280,37 @@ static gboolean connect_event(GIOChannel *chan,
memset(&raddr, 0, sizeof(raddr));
alen = sizeof(raddr);
- nsk = accept(sk, (struct sockaddr *) &raddr, &alen);
- if (nsk < 0)
+ rsk = accept(sk, (struct sockaddr *) &raddr, &alen);
+ if (rsk < 0)
return TRUE;
bacpy(&prx->dst, &raddr.rc_bdaddr);
- /* TTY open */
- tty_sk = open(prx->tty, O_RDWR | O_NOCTTY);
- if (tty_sk < 0) {
- error("Unable to open %s: %s(%d)",
- prx->tty, strerror(errno), errno);
- close(nsk);
+ if (prx->type == UNIX_SOCKET_PROXY)
+ lsk = unix_socket_connect(prx->address);
+ else
+ lsk = tty_open(prx->address, &prx->proxy_ti);
+
+ if (lsk < 0) {
+ close(rsk);
return TRUE;
}
- if (tcsetattr(tty_sk, TCSANOW, &prx->proxy_ti) < 0)
- error("Can't change serial settings: %s(%d)",
- strerror(errno), errno);
+ rio = g_io_channel_unix_new(rsk);
+ g_io_channel_set_close_on_unref(rio, TRUE);
+ lio = g_io_channel_unix_new(lsk);
+ g_io_channel_set_close_on_unref(lio, TRUE);
- node_io = g_io_channel_unix_new(nsk);
- g_io_channel_set_close_on_unref(node_io, TRUE);
- tty_io = g_io_channel_unix_new(tty_sk);
- g_io_channel_set_close_on_unref(tty_io, TRUE);
-
- prx->rfcomm_watch = g_io_add_watch(node_io,
+ prx->rfcomm_watch = g_io_add_watch(rio,
G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
- forward_data, tty_io);
+ forward_data, lio);
- prx->tty_watch = g_io_add_watch(tty_io,
+ prx->local_watch = g_io_add_watch(lio,
G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
- forward_data, node_io);
+ forward_data, rio);
- g_io_channel_unref(node_io);
- g_io_channel_unref(tty_io);
+ g_io_channel_unref(rio);
+ g_io_channel_unref(lio);
return TRUE;
}
@@ -1260,9 +1326,9 @@ static void listen_watch_notify(gpointer data)
prx->rfcomm_watch = 0;
}
- if (prx->tty_watch) {
- g_source_remove(prx->tty_watch);
- prx->tty_watch = 0;
+ if (prx->local_watch) {
+ g_source_remove(prx->local_watch);
+ prx->local_watch = 0;
}
remove_proxy_record(connection, prx->record_id);
@@ -1348,8 +1414,8 @@ static DBusHandlerResult proxy_get_info(DBusConnection *conn,
dbus_message_iter_append_dict_entry(&dict, "uuid",
DBUS_TYPE_STRING, &prx->uuid128);
- dbus_message_iter_append_dict_entry(&dict, "tty",
- DBUS_TYPE_STRING, &prx->tty);
+ dbus_message_iter_append_dict_entry(&dict, "address",
+ DBUS_TYPE_STRING, &prx->address);
if (prx->channel)
dbus_message_iter_append_dict_entry(&dict, "channel",
@@ -1483,7 +1549,7 @@ static DBusHandlerResult proxy_set_serial_params(DBusConnection *conn,
speed_t speed = B0; /* In/Out speed */
/* Don't allow change TTY settings if it is open */
- if (prx->tty_watch)
+ if (prx->local_watch)
return err_failed(conn, msg, "Not allowed");
dbus_error_init(&derr);
@@ -1533,94 +1599,169 @@ static void proxy_handler_unregister(DBusConnection *conn, void *data)
struct proxy *prx = data;
int sk;
- info("Unregistered proxy: %s", prx->tty);
+ info("Unregistered proxy: %s", prx->address);
+
+ if (prx->type != TTY_PROXY)
+ goto done;
/* Restore the initial TTY configuration */
- sk = open(prx->tty, O_RDWR | O_NOCTTY);
+ sk = open(prx->address, O_RDWR | O_NOCTTY);
if (sk) {
tcsetattr(sk, TCSAFLUSH, &prx->sys_ti);
close(sk);
}
+done:
if (prx->listen_watch)
g_source_remove(prx->listen_watch);
proxy_free(prx);
}
-static int proxy_register(DBusConnection *conn, bdaddr_t *src, const char *path,
- const char *uuid128, const char *tty, struct termios *ti)
+static int register_proxy_object(struct proxy *prx, char *outpath, size_t size)
+{
+ char path[MAX_PATH_LENGTH + 1];
+ const char *ppath = path;
+
+ snprintf(path, MAX_PATH_LENGTH, "/org/bluez/serial/proxy%d",
+ sk_counter++);
+
+ if (!dbus_connection_create_object_path(connection, path, prx,
+ proxy_handler_unregister)) {
+ error("D-Bus failed to register %s path", path);
+ return -1;
+ }
+
+ dbus_connection_register_interface(connection, path,
+ SERIAL_PROXY_INTERFACE, proxy_methods, NULL, NULL);
+
+ dbus_connection_emit_signal(connection, SERIAL_MANAGER_PATH,
+ SERIAL_MANAGER_INTERFACE, "ProxyCreated",
+ DBUS_TYPE_STRING, &ppath,
+ DBUS_TYPE_INVALID);
+
+ proxies_paths = g_slist_append(proxies_paths, g_strdup(path));
+
+ if (outpath)
+ strncpy(outpath, path, size);
+
+ info("Registered proxy:%s", path);
+
+ return 0;
+}
+
+static int proxy_tty_register(bdaddr_t *src, const char *uuid128,
+ const char *address, struct termios *ti, char *outpath, size_t size)
{
struct termios sys_ti;
struct proxy *prx;
- int sk;
+ int sk, ret;
- sk = open(tty, O_RDWR | O_NOCTTY);
+ sk = open(address, O_RDONLY | O_NOCTTY);
if (sk < 0) {
error("Cant open TTY: %s(%d)", strerror(errno), errno);
return -EINVAL;
}
prx = g_new0(struct proxy, 1);
- prx->tty = g_strdup(tty);
+ prx->address = g_strdup(address);
prx->uuid128 = g_strdup(uuid128);
+ prx->type = TTY_PROXY;
bacpy(&prx->src, src);
- if (!dbus_connection_create_object_path(conn, path, prx,
- proxy_handler_unregister)) {
- proxy_free(prx);
- close(sk);
- return -1;
- }
-
/* Current TTY settings */
memset(&sys_ti, 0, sizeof(sys_ti));
tcgetattr(sk, &sys_ti);
memcpy(&prx->sys_ti, &sys_ti, sizeof(sys_ti));
close(sk);
- if (!ti)
+ if (!ti) {
/* Use current settings */
memcpy(&prx->proxy_ti, &sys_ti, sizeof(sys_ti));
- else
+ } else {
/* New TTY settings: user provided */
memcpy(&prx->proxy_ti, ti, sizeof(*ti));
+ }
- if (!dbus_connection_register_interface(conn, path,
- SERIAL_PROXY_INTERFACE,
- proxy_methods,
- NULL, NULL)) {
- dbus_connection_destroy_object_path(conn, path);
- return -1;
+ ret = register_proxy_object(prx, outpath, size);
+ if (ret < 0)
+ proxy_free(prx);
+
+ return ret;
+}
+
+static int proxy_socket_register(bdaddr_t *src, const char *uuid128,
+ const char *address, char *outpath, size_t size)
+{
+ struct proxy *prx;
+ int ret;
+
+ prx = g_new0(struct proxy, 1);
+ prx->address = g_strdup(address);
+ prx->uuid128 = g_strdup(uuid128);
+ prx->type = UNIX_SOCKET_PROXY;
+ bacpy(&prx->src, src);
+
+ ret = register_proxy_object(prx, outpath, size);
+ if (ret < 0)
+ proxy_free(prx);
+
+ return ret;
+}
+
+static proxy_type_t addr2type(const char *address)
+{
+ struct stat st;
+
+ if (stat(address, &st) < 0) {
+ /*
+ * Unix socket: if the sun_path starts with null byte
+ * it refers to abstract namespace. 'x00' will be used
+ * to represent the null byte.
+ */
+ if (strncmp("x00", address, 3) != 0)
+ return UNKNOWN_PROXY_TYPE;
+ else
+ return UNIX_SOCKET_PROXY;
+ } else {
+ /* Filesystem: char device or unix socket */
+ if (S_ISCHR(st.st_mode) && strncmp("/dev/", address, 4) == 0)
+ return TTY_PROXY;
+ else if (S_ISSOCK(st.st_mode))
+ return UNIX_SOCKET_PROXY;
+ else
+ return UNKNOWN_PROXY_TYPE;
}
+}
- dbus_connection_emit_signal(conn, SERIAL_MANAGER_PATH,
- SERIAL_MANAGER_INTERFACE, "ProxyCreated",
- DBUS_TYPE_STRING, &path,
- DBUS_TYPE_INVALID);
+static int proxycmp(const char *path, const char *address)
+{
+ struct proxy *prx = NULL;
- info("Registered proxy:%s path:%s", tty, path);
+ if (!dbus_connection_get_object_user_data(connection,
+ path, (void *) &prx) || !prx)
+ return -1;
- return 0;
+ return strcmp(prx->address, address);
}
static DBusHandlerResult create_proxy(DBusConnection *conn,
DBusMessage *msg, void *data)
{
- char path[MAX_PATH_LENGTH];
- const char *uuid128, *tty, *ppath = path;
+ char path[MAX_PATH_LENGTH + 1];
+ const char *uuid128, *address, *ppath = path;
DBusMessage *reply;
+ proxy_type_t type;
GSList *l;
DBusError derr;
- struct stat st;
bdaddr_t src;
uuid_t uuid;
- int dev_id, pos = 0;
+ int dev_id, ret;
dbus_error_init(&derr);
if (!dbus_message_get_args(msg, &derr,
DBUS_TYPE_STRING, &uuid128,
- DBUS_TYPE_STRING, &tty,
+ DBUS_TYPE_STRING, &address,
DBUS_TYPE_INVALID)) {
err_invalid_args(conn, msg, derr.message);
dbus_error_free(&derr);
@@ -1630,14 +1771,12 @@ static DBusHandlerResult create_proxy(DBusConnection *conn,
if (str2uuid(&uuid, uuid128) < 0)
return err_invalid_args(conn, msg, "Invalid UUID");
- sscanf(tty, "/dev/%n", &pos);
- if (!pos || stat(tty, &st) < 0)
- return err_invalid_args(conn, msg, "Invalid TTY");
-
- snprintf(path, MAX_PATH_LENGTH - 1,
- "/org/bluez/serial/proxy%s", tty + pos);
+ type = addr2type(address);
+ if (type == UNKNOWN_PROXY_TYPE)
+ return err_invalid_args(conn, msg, "Invalid address");
- l = g_slist_find_custom(proxies_paths, path, (GCompareFunc) strcmp);
+ /* Only one proxy per address(TTY or unix socket) is allowed */
+ l = g_slist_find_custom(proxies_paths, address, (GCompareFunc) proxycmp);
if (l)
return err_already_exists(conn, msg, "Proxy already exists");
@@ -1651,13 +1790,18 @@ static DBusHandlerResult create_proxy(DBusConnection *conn,
if (!reply)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
- if (proxy_register(conn, &src, path, uuid128, tty, NULL) < 0) {
+ if (type != TTY_PROXY)
+ ret = proxy_socket_register(&src, uuid128,
+ address, path, sizeof(path));
+ else
+ ret = proxy_tty_register(&src, uuid128,
+ address, NULL, path, sizeof(path));
+
+ if (ret < 0) {
dbus_message_unref(reply);
return err_failed(conn, msg, "Create object path failed");
}
- proxies_paths = g_slist_append(proxies_paths, g_strdup(path));
-
dbus_message_append_args(reply,
DBUS_TYPE_STRING, &ppath,
DBUS_TYPE_INVALID);
@@ -1703,7 +1847,7 @@ static DBusHandlerResult remove_proxy(DBusConnection *conn,
/* Remove from storage */
if (dbus_connection_get_object_user_data(conn,
path, (void *) &prx) && prx)
- proxy_delete(&prx->src, prx->tty);
+ proxy_delete(&prx->src, prx->address);
g_free(l->data);
proxies_paths = g_slist_remove(proxies_paths, l->data);
@@ -1892,9 +2036,13 @@ static void proxy_path_free(gpointer data, gpointer udata)
/* Store/Update the proxy entries before exit */
if (dbus_connection_get_object_user_data(conn,
- path, (void *) &prx) && prx)
- proxy_store(&prx->src, prx->uuid128, prx->tty, NULL,
- prx->channel, 0, &prx->proxy_ti);
+ path, (void *) &prx) && prx) {
+ struct termios *ti;
+
+ ti = (prx->type == TTY_PROXY ? &prx->proxy_ti : NULL);
+ proxy_store(&prx->src, prx->uuid128, prx->address, NULL,
+ prx->channel, 0, ti);
+ }
g_free(data);
}
@@ -1996,14 +2144,16 @@ static void parse_port(char *key, char *value, void *data)
static void parse_proxy(char *key, char *value, void *data)
{
- char path[MAX_PATH_LENGTH], uuid128[MAX_LEN_UUID_STR], tmp[3];
+ char uuid128[MAX_LEN_UUID_STR], tmp[3];
char *pvalue, *src_addr = data;
- struct termios ti;
- int ch, opts, pos = 0;
+ proxy_type_t type;
+ int ch, opts, pos;
bdaddr_t src;
+ struct termios ti;
uint8_t *pti;
memset(uuid128, 0, sizeof(uuid128));
+ ch = opts = pos = 0;
if (sscanf(value,"%s %d 0x%04X %n", uuid128, &ch, &opts, &pos) != 3)
return;
@@ -2016,33 +2166,33 @@ static void parse_proxy(char *key, char *value, void *data)
/* FIXME: currently name is not used */
*pvalue = '\0';
- /* Extracting termios */
- pvalue++;
- if (strlen(pvalue) != (2 * sizeof(ti)))
- return;
-
- memset(&ti, 0, sizeof(ti));
- memset(tmp, 0, sizeof(tmp));
-
- /* Converting to termios struct */
- pti = (uint8_t *) &ti;
- for (pos = 0; pos < sizeof(ti); pos++, pvalue += 2, pti++) {
- memcpy(tmp, pvalue, 2);
- *pti = (uint8_t) strtol(tmp, NULL, 16);
- }
-
- pos = 0;
- sscanf(key, "/dev/%n", &pos);
- if (!pos)
- return;
-
- snprintf(path, MAX_PATH_LENGTH - 1,
- "/org/bluez/serial/proxy%s", key + pos);
-
str2ba(src_addr, &src);
- proxy_register(connection, &src, path, uuid128, key, &ti);
+ type = addr2type(key);
+ switch (type) {
+ case TTY_PROXY:
+ /* Extracting termios */
+ pvalue++;
+ if (!pvalue || strlen(pvalue) != (2 * sizeof(ti)))
+ return;
+
+ memset(&ti, 0, sizeof(ti));
+ memset(tmp, 0, sizeof(tmp));
+
+ /* Converting to termios struct */
+ pti = (uint8_t *) &ti;
+ for (pos = 0; pos < sizeof(ti); pos++, pvalue += 2, pti++) {
+ memcpy(tmp, pvalue, 2);
+ *pti = (uint8_t) strtol(tmp, NULL, 16);
+ }
- proxies_paths = g_slist_append(proxies_paths, g_strdup(path));
+ proxy_tty_register(&src, uuid128, key, &ti, NULL, 0);
+ break;
+ case UNIX_SOCKET_PROXY:
+ proxy_socket_register(&src, uuid128, key, NULL, 0);
+ break;
+ default:
+ return;
+ }
}
static void register_stored(void)
diff --git a/serial/serial-api.txt b/serial/serial-api.txt
index 70e8983f..ab0a4a35 100644
--- a/serial/serial-api.txt
+++ b/serial/serial-api.txt
@@ -10,10 +10,16 @@ Manager hierarchy
Interface org.bluez.serial.Manager
Object path /org/bluez/serial
-Methods string CreateProxy(string uuid, string tty)
+Methods string CreateProxy(string uuid, string address)
Creates a serial port proxy object.
+ Service identifier must be provided in the uuid 128
+ format. Addresses can be TTY char devices or unix
+ socket address. Abstract namespace can be informed
+ replacing the null byte by 'x00'. eg: "/dev/ttyS0",
+ "/tmp/gps-data", "x00/org/bluez/echo".
+
Possible errors:org.bluez.serial.Error.InvalidArguments
org.bluez.serial.NotAvailable
org.bluez.serial.Failed
diff --git a/serial/storage.c b/serial/storage.c
index 641ca1e8..8b66354f 100644
--- a/serial/storage.c
+++ b/serial/storage.c
@@ -121,9 +121,13 @@ int proxy_store(bdaddr_t *src, const char *uuid, const char *tty,
/* tty uuid 00 0x0000 name:termios */
pos = snprintf(value, size, "%s %d 0x%04X %s:", uuid, ch, opts, name);
+ if (!ti)
+ goto done;
+
for (i = 0, pti = (uint8_t *) ti; i < sizeof(struct termios); i++, pti++)
sprintf(value + pos + (i * 2), "%2.2X", *pti);
+done:
err = textfile_put(filename, key, value);
g_free(value);