summaryrefslogtreecommitdiffstats
path: root/transfer
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2007-01-21 03:19:07 +0000
committerMarcel Holtmann <marcel@holtmann.org>2007-01-21 03:19:07 +0000
commit1c9948d54b407ce9f80a41f8fc3aa2fec2aa3400 (patch)
tree6b554473df16d45434fef9c2ebe3bdf7a61b8b6e /transfer
parent3240a5476f0c18bc0a30b0e0c5d995b55320ae7e (diff)
First attempts for session and process handling
Diffstat (limited to 'transfer')
-rw-r--r--transfer/Makefile.am5
-rw-r--r--transfer/main.c101
-rw-r--r--transfer/session.c214
-rw-r--r--transfer/session.h18
4 files changed, 329 insertions, 9 deletions
diff --git a/transfer/Makefile.am b/transfer/Makefile.am
index b8392b50..0dae6c09 100644
--- a/transfer/Makefile.am
+++ b/transfer/Makefile.am
@@ -4,8 +4,9 @@ servicedir = $(libdir)/bluetooth
noinst_PROGRAMS = bluetoothd-service-transfer
-bluetoothd_service_transfer_SOURCES = \
- main.c server.h server.c session.h session.c
+bluetoothd_service_transfer_SOURCES = main.c \
+ server.h server.c session.h session.c \
+ process.h process.c
LDADD = $(top_builddir)/common/libhelper.a \
@GLIB_LIBS@ @DBUS_LIBS@ @OPENOBEX_LIBS@ @BLUEZ_LIBS@
diff --git a/transfer/main.c b/transfer/main.c
index 416b871e..c8baec6f 100644
--- a/transfer/main.c
+++ b/transfer/main.c
@@ -26,21 +26,98 @@
#endif
#include <stdlib.h>
-#include <string.h>
+#include <stdint.h>
#include <signal.h>
-#include <sys/stat.h>
-
-#include <dbus/dbus.h>
#include <glib.h>
+#include <dbus/dbus.h>
+
#include "logging.h"
#include "dbus.h"
+#include "server.h"
+#include "session.h"
+
+#define SERVICE_PATH "/org/bluez/transfer"
+
static GMainLoop *main_loop;
static DBusConnection *system_bus;
+static DBusHandlerResult error_reply(DBusConnection *conn,
+ DBusMessage *msg, const char *str)
+{
+ return send_message_and_unref(conn,
+ dbus_message_new_error(msg, "org.bluez.transfer.Error", str));
+}
+
+static DBusHandlerResult push_message(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ const char *address, *pathname, *identifier;
+ struct session_data *session;
+
+ if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_STRING, &pathname, DBUS_TYPE_INVALID) == FALSE)
+ return error_reply(conn, msg, "Invalid arguments");
+
+ debug("Requesting push of %s to %s", pathname, address);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ session = session_create(conn, msg);
+ if (!session) {
+ dbus_message_unref(reply);
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ }
+
+ identifier = session_connect(session, address, pathname);
+ if (!identifier) {
+ session_destroy(session);
+ dbus_message_unref(reply);
+ return error_reply(conn, msg, "Unable to connect session");
+ }
+
+ debug("Created new session at %s", identifier);
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &identifier,
+ DBUS_TYPE_INVALID);
+
+ dbus_connection_send(conn, reply, NULL);
+
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult manager_handler(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ if (dbus_message_is_method_call(msg, "org.bluez.transfer.Manager", "Push"))
+ return push_message(conn, msg, data);
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusObjectPathVTable manager_table = {
+ .message_function = manager_handler,
+};
+
+static int setup_manager(void)
+{
+ if (dbus_connection_register_object_path(system_bus,
+ SERVICE_PATH, &manager_table, NULL) == FALSE) {
+ error("Service path registration failed");
+ return -1;
+ }
+
+ return 0;
+}
+
static void sig_term(int sig)
{
g_main_loop_quit(main_loop);
@@ -59,8 +136,6 @@ int main(int argc, char *argv[])
{
struct sigaction sa;
- umask(0077);
-
start_logging("transfer", "Bluetooth transfer service ver %s", VERSION);
memset(&sa, 0, sizeof(sa));
@@ -82,14 +157,26 @@ int main(int argc, char *argv[])
main_loop = g_main_loop_new(NULL, FALSE);
- system_bus = init_dbus("org.bluez.transfer", NULL, NULL);
+ system_bus = init_dbus(NULL, NULL, NULL);
if (!system_bus) {
g_main_loop_unref(main_loop);
exit(1);
}
+ if (setup_manager() < 0) {
+ dbus_connection_unref(system_bus);
+ g_main_loop_unref(main_loop);
+ exit(1);
+ }
+
+ start_server(9);
+
g_main_loop_run(main_loop);
+ stop_server();
+
+ dbus_connection_unregister_object_path(system_bus, SERVICE_PATH);
+
dbus_connection_unref(system_bus);
g_main_loop_unref(main_loop);
diff --git a/transfer/session.c b/transfer/session.c
index 9a30e98f..e63fc3bc 100644
--- a/transfer/session.c
+++ b/transfer/session.c
@@ -25,4 +25,218 @@
#include <config.h>
#endif
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+
+#include <glib.h>
+
+#include <dbus/dbus.h>
+
+#include "logging.h"
+
+#include "process.h"
#include "session.h"
+
+static DBusHandlerResult cancel_message(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ struct session_data *session = data;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ debug("Cancel of session at %s", session->identifier);
+
+ dbus_message_append_args(reply, DBUS_TYPE_INVALID);
+
+ dbus_connection_send(conn, reply, NULL);
+
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult session_handler(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ if (dbus_message_is_method_call(msg, "org.bluez.transfer.Session", "Cancel"))
+ return cancel_message(conn, msg, data);
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusObjectPathVTable session_table = {
+ .message_function = session_handler,
+};
+
+struct session_data *session_create(DBusConnection *conn, DBusMessage *msg)
+{
+ struct session_data *session;
+
+ session = malloc(sizeof(*session));
+ if (!session)
+ return NULL;
+
+ memset(session, 0, sizeof(*session));
+
+ session->conn = dbus_connection_ref(conn);
+
+ session->msg = dbus_message_ref(msg);
+
+ return session;
+}
+
+void session_destroy(struct session_data *session)
+{
+ if (!session)
+ return;
+
+ if (session->identifier) {
+ dbus_connection_unregister_object_path(session->conn,
+ session->identifier);
+ free(session->identifier);
+ }
+
+ dbus_message_unref(session->msg);
+
+ dbus_connection_unref(session->conn);
+
+ free(session);
+}
+
+static gboolean connect_callback(GIOChannel *chan,
+ GIOCondition cond, gpointer data)
+{
+ struct session_data *session = data;
+ int sk;
+
+ debug("Connection for session %s established", session->identifier);
+
+ sk = g_io_channel_unix_get_fd(session->rfcomm_io);
+
+ close(sk);
+
+ return FALSE;
+}
+
+static int rfcomm_connect(struct session_data *session)
+{
+ struct sockaddr_rc addr;
+ long arg;
+ int sk;
+
+ sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+ if (sk < 0)
+ return -1;
+
+ arg = fcntl(sk, F_GETFL);
+ if (arg < 0) {
+ close(sk);
+ return -1;
+ }
+
+ arg |= O_NONBLOCK;
+
+ if (fcntl(sk, F_SETFL, arg) < 0) {
+ close(sk);
+ return -1;
+ }
+
+ session->rfcomm_io = g_io_channel_unix_new(sk);
+ if (!session->rfcomm_io) {
+ close(sk);
+ return -1;
+ }
+
+ g_io_channel_set_close_on_unref(session->rfcomm_io, TRUE);
+
+ memset(&addr, 0, sizeof(addr));
+ addr.rc_family = AF_BLUETOOTH;
+ bacpy(&addr.rc_bdaddr, &session->bdaddr);
+ addr.rc_channel = session->channel;
+
+ if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ if (errno != EAGAIN && errno != EINPROGRESS) {
+ close(sk);
+ return -1;
+ }
+ }
+
+ g_io_add_watch(session->rfcomm_io, G_IO_OUT, connect_callback, session);
+
+ return 0;
+}
+
+static gboolean data_event(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+ unsigned char buf[64];
+ gsize len;
+ GIOError err;
+ int i;
+
+ debug("Data event");
+
+ if (cond & (G_IO_HUP | G_IO_ERR))
+ return FALSE;
+
+ memset(buf, 0, sizeof(buf));
+
+ err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf) - 1, &len);
+ if (err == G_IO_ERROR_AGAIN)
+ return TRUE;
+
+ for (i = 0; i < len; i++)
+ if (!isprint(buf[i]))
+ buf[i] = '.';
+
+ debug("%s", buf);
+
+ return TRUE;
+}
+
+const char *session_connect(struct session_data *session,
+ const char *address, const char *pathname)
+{
+ const char *sender;
+ char path[128];
+
+ sender = dbus_message_get_sender(session->msg);
+
+ session->uid = dbus_bus_get_unix_user(session->conn, sender, NULL);
+
+ debug("Request by user %d", session->uid);
+
+ create_reader(session->uid, pathname, data_event, NULL);
+
+ str2ba(address, &session->bdaddr);
+
+ session->channel = 1;
+
+ snprintf(path, sizeof(path), "/org/bluez/transfer/%d%d",
+ session->uid, rand());
+
+ session->identifier = strdup(path);
+ if (!session->identifier)
+ return NULL;
+
+ if (dbus_connection_register_object_path(session->conn, path,
+ &session_table, session) == FALSE) {
+ free(session->identifier);
+ session->identifier = NULL;
+ return NULL;
+ }
+
+ if (rfcomm_connect(session) < 0)
+ return NULL;
+
+ return session->identifier;
+}
diff --git a/transfer/session.h b/transfer/session.h
index bc4c495a..c5a946b4 100644
--- a/transfer/session.h
+++ b/transfer/session.h
@@ -20,3 +20,21 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
+
+#include <bluetooth/bluetooth.h>
+
+struct session_data {
+ DBusConnection *conn;
+ DBusMessage *msg;
+ uid_t uid;
+ bdaddr_t bdaddr;
+ uint8_t channel;
+ char *identifier;
+ GIOChannel *rfcomm_io;
+};
+
+struct session_data *session_create(DBusConnection *conn, DBusMessage *msg);
+void session_destroy(struct session_data *session);
+
+const char *session_connect(struct session_data *session,
+ const char *address, const char *pathname);