summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClaudio Takahasi <claudio.takahasi@openbossa.org>2007-05-07 19:06:44 +0000
committerClaudio Takahasi <claudio.takahasi@openbossa.org>2007-05-07 19:06:44 +0000
commit4a653936cf357c3266777e176da15508e08d7271 (patch)
treec791738e366bdc32fd8b3a59c82e388a10c18911
parent7026c4f01e50040d2539a6ca7f80cb533210e8dd (diff)
serial: added get_handles and pending_connection struct
-rw-r--r--serial/manager.c142
1 files changed, 135 insertions, 7 deletions
diff --git a/serial/manager.c b/serial/manager.c
index 36711c1a..6e46bc51 100644
--- a/serial/manager.c
+++ b/serial/manager.c
@@ -48,14 +48,34 @@
#define PATH_LENGTH 32
#define BASE_UUID "00000000-0000-1000-8000-00805F9B34FB"
+struct pending_connection {
+ DBusConnection *conn;
+ DBusMessage *msg;
+ bdaddr_t src; /* Source address */
+ char *addr; /* Destination address */
+ char *adapter_path; /* Adapter D-Bus path */
+};
+
static DBusConnection *connection = NULL;
-static DBusHandlerResult err_invalid_args(DBusConnection *conn,
+static void pending_connection_free(struct pending_connection *pc)
+{
+ if (pc->conn)
+ dbus_connection_unref(pc->conn);
+ if (pc->msg)
+ dbus_message_unref(pc->msg);
+ if (pc->addr)
+ g_free(pc->addr);
+ if (pc->adapter_path)
+ g_free(pc->adapter_path);
+}
+
+static DBusHandlerResult err_connection_failed(DBusConnection *conn,
DBusMessage *msg, const char *str)
{
return send_message_and_unref(conn,
dbus_message_new_error(msg,
- SERIAL_ERROR_INTERFACE ".InvalidArguments", str));
+ SERIAL_ERROR_INTERFACE".ConnectionAttemptFailed", str));
}
static DBusHandlerResult err_failed(DBusConnection *conn,
@@ -66,11 +86,100 @@ static DBusHandlerResult err_failed(DBusConnection *conn,
SERIAL_ERROR_INTERFACE ".Failed", str));
}
+static DBusHandlerResult err_invalid_args(DBusConnection *conn,
+ DBusMessage *msg, const char *str)
+{
+ return send_message_and_unref(conn,
+ dbus_message_new_error(msg,
+ SERIAL_ERROR_INTERFACE ".InvalidArguments", str));
+}
+
+static DBusHandlerResult err_not_supported(DBusConnection *conn,
+ DBusMessage *msg)
+{
+ return send_message_and_unref(conn,
+ dbus_message_new_error(msg,
+ SERIAL_ERROR_INTERFACE ".NotSupported",
+ "The service is not supported by the remote device"));
+}
+
+static void handles_reply(DBusPendingCall *call, void *data)
+{
+ struct pending_connection *pc = data;
+ DBusMessage *reply = dbus_pending_call_steal_reply(call);
+ DBusError derr;
+ uint32_t *phandle;
+ int len;
+
+ dbus_error_init(&derr);
+ if (dbus_set_error_from_message(&derr, reply)) {
+ if (dbus_error_has_name(&derr,
+ "org.bluez.Error.ConnectionAttemptFailed"))
+ err_connection_failed(pc->conn, pc->msg, derr.message);
+ else
+ err_not_supported(pc->conn, pc->msg);
+
+ error("GetRemoteServiceHandles: %s(%s)",
+ derr.name, derr.message);
+ goto fail;
+ }
+
+ if (!dbus_message_get_args(reply, &derr,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle,
+ &len, DBUS_TYPE_INVALID)) {
+ err_not_supported(pc->conn, pc->msg);
+ error("%s: %s", derr.name, derr.message);
+ goto fail;
+ }
+
+ if (len == 0) {
+ err_not_supported(pc->conn, pc->msg);
+ goto fail;
+ }
+
+ /* FIXME: Get the record */
+ dbus_message_unref(reply);
+ return;
+fail:
+ dbus_message_unref(reply);
+ dbus_error_free(&derr);
+ pending_connection_free(pc);
+}
+
+static int get_handles(struct pending_connection *pc, const char *uuid,
+ DBusPendingCallNotifyFunction cb)
+{
+ DBusMessage *msg;
+ DBusPendingCall *pending;
+
+ msg = dbus_message_new_method_call("org.bluez", pc->adapter_path,
+ "org.bluez.Adapter", "GetRemoteServiceHandles");
+ if (!msg)
+ return -1;
+
+ dbus_message_append_args(msg,
+ DBUS_TYPE_STRING, &pc->addr,
+ DBUS_TYPE_STRING, &uuid,
+ DBUS_TYPE_INVALID);
+
+ if (dbus_connection_send_with_reply(pc->conn, msg, &pending, -1) == FALSE) {
+ error("Can't send D-Bus message.");
+ return -1;
+ }
+
+ dbus_pending_call_set_notify(pending, cb, pc, NULL);
+ dbus_message_unref(msg);
+ dbus_pending_call_unref(pending);
+
+ return 0;
+}
+
static DBusHandlerResult connect_service(DBusConnection *conn,
DBusMessage *msg, void *data)
{
DBusError derr;
bdaddr_t src;
+ struct pending_connection *pc;
const char *addr, *pattern;
char *endptr;
long val;
@@ -92,6 +201,14 @@ static DBusHandlerResult connect_service(DBusConnection *conn,
if ((dev_id < 0) || (hci_devba(dev_id, &src) < 0))
return err_failed(conn, msg, "Adapter not available");
+ pc = g_new0(struct pending_connection, 1);
+ pc->conn = dbus_connection_ref(conn);
+ pc->msg = dbus_message_ref(msg);
+ bacpy(&pc->src, &src);
+ pc->addr = g_strdup(addr);
+ pc->adapter_path = g_malloc0(16);
+ snprintf(pc->adapter_path, 16, "/org/bluez/hci%d", dev_id);
+
/* UUID 128*/
if (strlen(pattern) == 36) {
char tmp[37];
@@ -102,10 +219,15 @@ static DBusHandlerResult connect_service(DBusConnection *conn,
tmp[6] = '0';
tmp[7] = '0';
- if (strcasecmp(BASE_UUID, tmp) != 0)
+ if (strcasecmp(BASE_UUID, tmp) != 0) {
+ pending_connection_free(pc);
return err_invalid_args(conn, msg, "invalid UUID");
+ }
- /* FIXME: Retrieve the handle/record */
+ if (get_handles(pc, pattern, handles_reply) < 0) {
+ pending_connection_free(pc);
+ return err_not_supported(conn, msg);
+ }
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -113,22 +235,28 @@ static DBusHandlerResult connect_service(DBusConnection *conn,
errno = 0;
val = strtol(pattern, &endptr, 0);
if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) ||
- (errno != 0 && val == 0) || (pattern == endptr))
+ (errno != 0 && val == 0) || (pattern == endptr)) {
+ pending_connection_free(pc);
return err_invalid_args(conn, msg, "Invalid pattern");
+ }
/* Record handle: starts at 0x10000 */
if (strncasecmp("0x", pattern, 2) == 0) {
- if (val < 0x10000)
+ if (val < 0x10000) {
+ pending_connection_free(pc);
return err_invalid_args(conn, msg,
"invalid record handle");
+ }
/* FIXME: retrieve the record */
return DBUS_HANDLER_RESULT_HANDLED;
}
/* RFCOMM Channel range: 1 - 30 */
- if (val < 1 || val > 30)
+ if (val < 1 || val > 30) {
+ pending_connection_free(pc);
return err_invalid_args(conn, msg,
"invalid RFCOMM channel");
+ }
/* FIXME: Connect */
info("Connecting to channel: %d", val);