From 0d753f3a8fd1de89f9f43a6bdb69068fd420d905 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 2 Apr 2008 19:15:52 +0000 Subject: Add RequestMode sessions support. --- hcid/adapter.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++---------- hcid/adapter.h | 2 ++ 2 files changed, 83 insertions(+), 17 deletions(-) diff --git a/hcid/adapter.c b/hcid/adapter.c index 8d548ce5..1ca70276 100644 --- a/hcid/adapter.c +++ b/hcid/adapter.c @@ -81,7 +81,8 @@ struct mode_req { struct adapter *adapter; DBusConnection *conn; /* Connection reference */ DBusMessage *msg; /* Message reference */ - char *mode; /* Requested mode */ + uint8_t mode; /* Requested mode */ + guint id; /* Listener id */ }; static const char *service_cls[] = { @@ -556,17 +557,17 @@ static DBusHandlerResult adapter_get_mode(DBusConnection *conn, } static DBusHandlerResult set_mode(DBusConnection *conn, DBusMessage *msg, - const char *mode, void *data) + uint8_t new_mode, void *data) { struct adapter *adapter = data; DBusMessage *reply; uint8_t scan_enable; - uint8_t new_mode, current_scan = adapter->scan_enable; + uint8_t current_scan = adapter->scan_enable; bdaddr_t local; gboolean limited; int err, dd; + const char *mode; - new_mode = str2mode(adapter->address, mode); switch(new_mode) { case MODE_OFF: scan_enable = SCAN_DISABLED; @@ -664,7 +665,7 @@ static DBusHandlerResult set_mode(DBusConnection *conn, DBusMessage *msg, if (adapter->timeout_id) g_source_remove(adapter->timeout_id); - if (adapter->discov_timeout != 0) + if (!adapter->sessions && !adapter->discov_timeout) adapter->timeout_id = g_timeout_add(adapter->discov_timeout * 1000, discov_timeout_handler, adapter); } @@ -687,7 +688,9 @@ done: static DBusHandlerResult adapter_set_mode(DBusConnection *conn, DBusMessage *msg, void *data) { + struct adapter *adapter = data; const char *mode; + DBusMessage *reply; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &mode, @@ -697,7 +700,17 @@ static DBusHandlerResult adapter_set_mode(DBusConnection *conn, if (!mode) return error_invalid_arguments(conn, msg, NULL); - return set_mode(conn, msg, mode, data); + adapter->last_mode = str2mode(adapter->address, mode); + + if (adapter->sessions && adapter->last_mode > adapter->mode) { + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + return send_message_and_unref(conn, reply); + } + + return set_mode(conn, msg, str2mode(adapter->address, mode), data); } static DBusHandlerResult adapter_get_discoverable_to(DBusConnection *conn, @@ -3393,6 +3406,7 @@ static DBusHandlerResult get_properties(DBusConnection *conn, static DBusHandlerResult set_property(DBusConnection *conn, DBusMessage *msg, void *data) { + struct adapter *adapter = data; DBusMessageIter iter; DBusMessageIter sub; const char *property; @@ -3439,17 +3453,46 @@ static DBusHandlerResult set_property(DBusConnection *conn, return adapter_stop_periodic(conn, msg, data); } else if (g_str_equal("Mode", property)) { const char *mode; + DBusMessage *reply; if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) return error_invalid_arguments(conn, msg, NULL); dbus_message_iter_get_basic(&sub, &mode); - return set_mode(conn, msg, mode, data); + adapter->last_mode = str2mode(adapter->address, mode); + + if (adapter->sessions && adapter->last_mode > adapter->mode) { + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + return send_message_and_unref(conn, reply); + } + + return set_mode(conn, msg, str2mode(adapter->address, mode), + data); } return error_invalid_arguments(conn, msg, NULL); } +static void session_exit(const char *name, void *data) +{ + struct mode_req *req = data; + struct adapter *adapter = req->adapter; + + adapter->sessions = g_slist_remove(adapter->sessions, req); + + if (!adapter->sessions) + debug("Falling back to %d mode", mode2str(adapter->last_mode)); + /* FIXME: fallback to previous mode + set_mode(req->conn, req->msg, adapter->last_mode, adapter); + */ + dbus_connection_unref(req->conn); + dbus_message_unref(req->msg); + g_free(req); +} + static void request_mode_cb(struct agent *agent, DBusError *err, void *data) { struct mode_req *req = data; @@ -3463,13 +3506,23 @@ static void request_mode_cb(struct agent *agent, DBusError *err, void *data) set_mode(req->conn, req->msg, req->mode, req->adapter); + return; + cleanup: dbus_connection_unref(req->conn); dbus_message_unref(req->msg); - g_free(req->mode); + name_listener_id_remove(req->id); g_free(req); } +gint find_session(struct mode_req *req, DBusMessage *msg) +{ + const char *name = dbus_message_get_sender(req->msg); + const char *sender = dbus_message_get_sender(msg); + + return strcmp(name, sender); +} + static DBusHandlerResult request_mode(DBusConnection *conn, DBusMessage *msg, void *data) { @@ -3488,6 +3541,25 @@ static DBusHandlerResult request_mode(DBusConnection *conn, if (new_mode != MODE_CONNECTABLE && new_mode != MODE_DISCOVERABLE) return error_invalid_arguments(conn, msg, NULL); + if (!adapter->agent) + return error_failed(conn, msg, "No agent registered"); + + if (g_slist_find_custom(adapter->sessions, msg, + (GCompareFunc) find_session)) + return error_failed(conn, msg, "Mode already requested"); + + req = g_new0(struct mode_req, 1); + req->adapter = adapter; + req->conn = dbus_connection_ref(conn); + req->msg = dbus_message_ref(msg); + req->mode = new_mode; + req->id = name_listener_add(conn, dbus_message_get_sender(msg), + (name_cb_t) session_exit, req); + + if (!adapter->sessions) + adapter->last_mode = adapter->mode; + adapter->sessions = g_slist_append(adapter->sessions, req); + /* No need to change mode */ if (adapter->mode >= new_mode) { reply = dbus_message_new_method_return(msg); @@ -3497,20 +3569,12 @@ static DBusHandlerResult request_mode(DBusConnection *conn, return send_message_and_unref(conn, reply); } - if (!adapter->agent) - return error_failed(conn, msg, "No agent registered"); - - req = g_new0(struct mode_req, 1); - req->adapter = adapter; - req->conn = dbus_connection_ref(conn); - req->msg = dbus_message_ref(msg); - req->mode = g_strdup(mode); ret = agent_confirm_mode_change(adapter->agent, mode, request_mode_cb, req); if (ret < 0) { dbus_connection_unref(req->conn); dbus_message_unref(req->msg); - g_free(req->mode); + name_listener_id_remove(req->id); g_free(req); return error_invalid_arguments(conn, msg, NULL); } diff --git a/hcid/adapter.h b/hcid/adapter.h index 82e4f68c..f520f718 100644 --- a/hcid/adapter.h +++ b/hcid/adapter.h @@ -88,6 +88,7 @@ struct adapter { uint32_t discov_timeout; /* discoverable time(msec) */ uint8_t scan_enable; /* scan mode: SCAN_DISABLED, SCAN_PAGE, SCAN_INQUIRY */ uint8_t mode; /* off, connectable, discoverable, limited */ + uint8_t last_mode; /* last mode changed */ uint8_t class[3]; /* device class */ int discov_active; /* standard discovery active: includes name resolution step */ int pdiscov_active; /* periodic discovery active */ @@ -109,6 +110,7 @@ struct adapter { struct pending_dc_info *pending_dc; struct create_device_req *create; GSList *devices; /* Devices structure pointers */ + GSList *sessions; /* Request Mode sessions */ }; dbus_bool_t adapter_init(DBusConnection *conn, const char *path); -- cgit