From: DoHyun Pyun Date: Thu, 7 Sep 2017 07:28:33 +0000 (+0900) Subject: Add the missed hid-agent folder X-Git-Tag: accepted/tizen/unified/20170908.061951^0 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fconnectivity%2Fbluetooth-agent.git;a=commitdiff_plain;h=e2012b4f12aaf40db15d53858ee1677d2f2a99fd Add the missed hid-agent folder Change-Id: I9adbf5b6a24cb5df0d6fb98bc938b18f45e433ca Signed-off-by: DoHyun Pyun --- diff --git a/hid-agent/CMakeLists.txt b/hid-agent/CMakeLists.txt new file mode 100644 index 0000000..09f54dc --- /dev/null +++ b/hid-agent/CMakeLists.txt @@ -0,0 +1,25 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(bluetooth-hid-agent C) + +SET(SRCS bluetooth-hid-agent.c bluetooth-hid-manager.c) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + +INCLUDE(FindPkgConfig) +pkg_check_modules(pkgs_hf_agent + REQUIRED + dlog aul bluetooth-api capi-appfw-app-manager + glib-2.0 gio-2.0 gio-unix-2.0 capi-system-device vconf) + +FOREACH(flag ${pkgs_hf_agent_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall") + +ADD_EXECUTABLE(${PROJECT_NAME} ${SRCS}) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_hf_agent_LDFLAGS}) + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/org.bluez.hid_agent.service + DESTINATION share/dbus-1/system-services) diff --git a/hid-agent/bluetooth-hid-agent.c b/hid-agent/bluetooth-hid-agent.c new file mode 100644 index 0000000..323713e --- /dev/null +++ b/hid-agent/bluetooth-hid-agent.c @@ -0,0 +1,848 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "bluetooth-hid-agent.h" + +static GMainLoop *gmain_loop; +static char *g_obj_path; + +static GDBusConnection *gdbus_conn; +static GDBusProxy *profile_gproxy; +static guint owner_sig_id; +static guint bluez_device_sig_id; +static guint name_owner_sig_id; + +#define BT_HID_SIG_NUM 3 +#define HID_DEVICE_UUID "00001124-0000-1000-8000-00805f9b43bf" +#define DEFAULT_ADAPTER_OBJECT_PATH "/org/bluez/hci0" + +/*Below Inrospection data is exposed to application from agent*/ +static const gchar hid_agent_introspection_xml[] = +"" +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +""; + +static bt_hid_agent_info_t bt_hid_info = {0,}; +static gboolean is_hid_connected; +static gboolean is_hid_connectable; +static struct sigaction bt_hid_sigoldact[BT_HID_SIG_NUM]; +static int bt_hid_sig_to_handle[] = { SIGABRT, SIGSEGV, SIGTERM }; + +static void __bt_hid_agent_sigterm_handler(int signo); +static GError *__bt_hid_agent_set_error(bt_hid_agent_error_t error); + +static void __on_log_glib(const gchar *log_domain, GLogLevelFlags log_level, + const gchar *msg, gpointer user_data) +{ + ERR_C("%s", msg); +} + +static GQuark __bt_hid_agent_error_quark(void) +{ + FN_START; + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string("hid-agent"); + + return quark; +} + +static GError *__bt_hid_agent_set_error(bt_hid_agent_error_t error) +{ + ERR("error[%d]", error); + + switch (error) { + case BT_HID_AGENT_ERROR_NOT_AVAILABLE: + return g_error_new(BT_HID_AGENT_ERROR, error, + BT_ERROR_NOT_AVAILABLE); + case BT_HID_AGENT_ERROR_NOT_CONNECTED: + return g_error_new(BT_HID_AGENT_ERROR, error, + BT_ERROR_NOT_CONNECTED); + case BT_HID_AGENT_ERROR_CONNECTION_FAILED: + return g_error_new(BT_HID_AGENT_ERROR, error, + BT_ERROR_NOT_CONNECTION_FAILED); + case BT_HID_AGENT_ERROR_BUSY: + return g_error_new(BT_HID_AGENT_ERROR, error, + BT_ERROR_BUSY); + case BT_HID_AGENT_ERROR_INVALID_PARAM: + return g_error_new(BT_HID_AGENT_ERROR, error, + BT_ERROR_INVALID_PARAM); + case BT_HID_AGENT_ERROR_ALREADY_EXIST: + return g_error_new(BT_HID_AGENT_ERROR, error, + BT_ERROR_ALREADY_EXIST); + case BT_HID_AGENT_ERROR_ALREADY_CONNECTED: + return g_error_new(BT_HID_AGENT_ERROR, error, + BT_ERROR_ALREADY_CONNECTED); + case BT_HID_AGENT_ERROR_NO_MEMORY: + return g_error_new(BT_HID_AGENT_ERROR, error, + BT_ERROR_NO_MEMORY); + case BT_HID_AGENT_ERROR_NO_DATA: + return g_error_new(BT_HID_AGENT_ERROR, error, + BT_ERROR_NO_DATA); + case BT_HID_AGENT_ERROR_I_O_ERROR: + return g_error_new(BT_HID_AGENT_ERROR, error, + BT_ERROR_I_O_ERROR); + case BT_HID_AGENT_ERROR_APPLICATION: + return g_error_new(BT_HID_AGENT_ERROR, error, + BT_ERROR_OPERATION_NOT_AVAILABLE); + case BT_HID_AGENT_ERROR_NOT_ALLOWED: + return g_error_new(BT_HID_AGENT_ERROR, error, + BT_ERROR_OPERATION_NOT_ALLOWED); + case BT_HID_AGENT_ERROR_NOT_SUPPORTED: + return g_error_new(BT_HID_AGENT_ERROR, error, + BT_ERROR_OPERATION_NOT_SUPPORTED); + case BT_HID_AGENT_ERROR_INVALID_FILE_DESCRIPTOR: + return g_error_new(BT_HID_AGENT_ERROR, error, + BT_ERROR_INVALID_FILE_DESCRIPTOR); + case BT_HID_AGENT_ERROR_INTERNAL: + default: + return g_error_new(BT_HID_AGENT_ERROR, error, + BT_ERROR_INTERNAL); + } +} + +static void __bt_hid_name_owner_changed_cb(GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + char *name_owner = NULL; + char *old_owner = NULL; + char *new_owner = NULL; + int ret = 0; + + if (strcasecmp(signal_name, "NameOwnerChanged") == 0) { + g_variant_get(parameters, "(sss)", &name_owner, &old_owner, &new_owner); + + ret = _bt_hid_register_application(FALSE, name_owner); + if (ret == BT_HID_AGENT_ERROR_NONE) { + is_hid_connectable = FALSE; + if (name_owner_sig_id > 0) { + g_dbus_connection_signal_unsubscribe(gdbus_conn, + name_owner_sig_id); + name_owner_sig_id = 0; + } + } + } +} + +static void __hid_agent_method(GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *method_name, + GVariant *parameters, + GDBusMethodInvocation *context, + gpointer user_data) +{ + INFO("method %s", method_name); + int ret = 0; + GError *err; + + if (g_strcmp0(method_name, "RegisterApplication") == 0) { + DBG("Sender = %s\n", sender); + + ret = _bt_hid_register_application(TRUE, sender); + if (ret == BT_HID_AGENT_ERROR_NONE) { + is_hid_connectable = TRUE; + if (name_owner_sig_id == 0) { + name_owner_sig_id = g_dbus_connection_signal_subscribe(gdbus_conn, + NULL, NULL, "NameOwnerChanged", NULL, NULL, 0, + __bt_hid_name_owner_changed_cb, NULL, NULL); + } + } else { + goto fail; + } + + g_dbus_method_invocation_return_value(context, NULL); + } else if (g_strcmp0(method_name, "UnregisterApplication") == 0) { + DBG("Sender = %s\n", sender); + + ret = _bt_hid_register_application(FALSE, sender); + if (ret == BT_HID_AGENT_ERROR_NONE) { + is_hid_connectable = FALSE; + if (name_owner_sig_id > 0) { + g_dbus_connection_signal_unsubscribe(gdbus_conn, + name_owner_sig_id); + name_owner_sig_id = 0; + } + } else { + goto fail; + } + + g_dbus_method_invocation_return_value(context, NULL); + } else if (g_strcmp0(method_name, "IsHidConnected") == 0) { + DBG("Going to call IsHidConnected"); + INFO("is_hid_connected : %s", + is_hid_connected ? "Connected" : "Disconnected"); + + g_dbus_method_invocation_return_value(context, + g_variant_new("(b)", is_hid_connected)); + } else if (g_strcmp0(method_name, "IsHidConnectable") == 0) { + DBG("Going to call IsHidConnectable"); + INFO("is_hid_connectable : %s", + is_hid_connectable ? "Connectable" : "Non-Connectable"); + + g_dbus_method_invocation_return_value(context, + g_variant_new("(b)", is_hid_connectable)); + } + + return; + +fail: + err = __bt_hid_agent_set_error(ret); + g_dbus_method_invocation_return_gerror(context, err); + g_error_free(err); +} + +static const GDBusInterfaceVTable method_table = { + __hid_agent_method, + NULL, + NULL, +}; + +static GDBusNodeInfo *__bt_hid_create_method_node_info + (const gchar *introspection_data) +{ + if (introspection_data == NULL) + return NULL; + + return g_dbus_node_info_new_for_xml(introspection_data, NULL); +} + +static GDBusConnection *__bt_hid_get_gdbus_connection(void) +{ + GDBusConnection *local_system_gconn = NULL; + GError *err = NULL; + + if (gdbus_conn == NULL) { + gdbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err); + if (!gdbus_conn) { + if (err) { + ERR("Unable to connect to dbus: %s", err->message); + g_clear_error(&err); + } + gdbus_conn = NULL; + } + } else if (g_dbus_connection_is_closed(gdbus_conn)) { + local_system_gconn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err); + + if (!local_system_gconn) { + ERR("Unable to connect to dbus: %s", err->message); + g_clear_error(&err); + } + + gdbus_conn = local_system_gconn; + } + return gdbus_conn; +} + +static gboolean __bt_hid_register_methods(void) +{ + FN_START; + GError *error = NULL; + guint object_id; + guint owner_id; + GDBusNodeInfo *node_info; + GDBusConnection *conn; + + owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM, + BT_HID_SERVICE_NAME, + G_BUS_NAME_OWNER_FLAGS_NONE, + NULL, NULL, NULL, + NULL, NULL); + + DBG("owner_id is [%d]", owner_id); + + conn = __bt_hid_get_gdbus_connection(); + if (!conn) { + ERR("Unable to get connection"); + return FALSE; + } + + node_info = __bt_hid_create_method_node_info(hid_agent_introspection_xml); + if (node_info == NULL) + return FALSE; + + object_id = g_dbus_connection_register_object(conn, + BT_HID_AGENT_OBJECT_PATH, + node_info->interfaces[0], + &method_table, + NULL, NULL, &error); + g_dbus_node_info_unref(node_info); + if (object_id == 0) { + if (error != NULL) { + ERR("Failed to register: %s", error->message); + g_error_free(error); + } + return FALSE; + } + + FN_END; + return TRUE; +} + +static GDBusProxy *__bt_hid_gdbus_init_profile_proxy(void) +{ + FN_START; + + GDBusProxy *proxy; + GError *err = NULL; + GDBusConnection *conn; + + conn = __bt_hid_get_gdbus_connection(); + if (!conn) { + ERR("Unable to get connection"); + return NULL; + } + + proxy = g_dbus_proxy_new_sync(conn, + G_DBUS_PROXY_FLAGS_NONE, NULL, + BLUEZ_SERVICE_NAME, "/org/bluez", + BLUEZ_PROFILE_MGMT_INTERFACE, NULL, &err); + + if (!proxy) { + if (err) { + ERR("Unable to create proxy: %s", err->message); + g_clear_error(&err); + } + return NULL; + } + + profile_gproxy = proxy; + + FN_END; + return proxy; +} + +static GDBusProxy *__bt_hid_gdbus_get_profile_proxy(void) +{ + return (profile_gproxy) ? profile_gproxy : + __bt_hid_gdbus_init_profile_proxy(); +} + +static GDBusProxy *__bt_hid_gdbus_get_service_proxy(const gchar *service, + const gchar *path, const gchar *interface) +{ + FN_START; + + GDBusProxy *proxy; + GError *err = NULL; + GDBusConnection *conn; + + conn = __bt_hid_get_gdbus_connection(); + if (!conn) { + ERR("Unable to get connection"); + return NULL; + } + + proxy = g_dbus_proxy_new_sync(conn, + G_DBUS_PROXY_FLAGS_NONE, NULL, + service, path, + interface, NULL, &err); + + if (!proxy) { + if (err) { + ERR("Unable to create proxy: %s", err->message); + g_clear_error(&err); + } + return NULL; + } + + FN_END; + return proxy; +} + +static GDBusProxy *__bt_hid_gdbus_get_device_proxy(char *object_path) +{ + GDBusConnection *conn; + GError *err = NULL; + GDBusProxy *device_gproxy; + + conn = __bt_hid_get_gdbus_connection(); + + if (conn == NULL) + return NULL; + + device_gproxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE, + NULL, BLUEZ_SERVICE_NAME, + object_path, + BLUEZ_DEVICE_INTERFACE, + NULL, &err); + + if (device_gproxy == NULL && err) { + ERR("Unable to create proxy: %s", err->message); + g_clear_error(&err); + return NULL; + } + + return device_gproxy; +} + +static int __bt_hid_agent_gdbus_method_send(const char *service, + GVariant *path, const char *interface, + const char *method) +{ + FN_START; + + GVariant *ret; + GDBusProxy *proxy; + GError *error = NULL; + + proxy = __bt_hid_gdbus_get_service_proxy(service, g_obj_path, interface); + if (!proxy) + return BT_HID_AGENT_ERROR_INTERNAL; + + ret = g_dbus_proxy_call_sync(proxy, + method, path, + G_DBUS_CALL_FLAGS_NONE, -1, + NULL, &error); + if (ret == NULL) { + /* dBUS-RPC is failed */ + ERR("dBUS-RPC is failed"); + if (error != NULL) { + /* dBUS gives error cause */ + ERR("D-Bus API failure: errCode[%x], message[%s]", + error->code, error->message); + + g_clear_error(&error); + } + g_object_unref(proxy); + return BT_HID_AGENT_ERROR_INTERNAL; + } + + g_variant_unref(ret); + g_object_unref(proxy); + + return BT_HID_AGENT_ERROR_NONE; +} + +static void __bt_hid_agent_sigterm_handler(int signo) +{ + GDBusConnection *conn; + int i; + + ERR_C("***** Signal handler came with signal %d *****", signo); + + conn = __bt_hid_get_gdbus_connection(); + if (!conn) { + ERR("Unable to get G-DBus connection"); + goto done; + } + + g_dbus_connection_flush(conn, NULL, NULL, NULL); + INFO("Flush g_dbus_connection"); + +done: + if (gmain_loop) { + g_main_loop_quit(gmain_loop); + INFO("Exiting"); + gmain_loop = NULL; + } else { + INFO_C("Terminating HID agent"); + exit(0); + } + + if (signo == SIGTERM) + return; + + for (i = 0; i < BT_HID_SIG_NUM; i++) + sigaction(bt_hid_sig_to_handle[i], &(bt_hid_sigoldact[i]), NULL); + + raise(signo); +} + +static int __bt_hid_register_profile(const char *uuid, + const char *name, const char *object) +{ + FN_START; + GDBusProxy *proxy; + GVariant *ret; + GError *error = NULL; + GVariantBuilder *builder; + + proxy = __bt_hid_gdbus_get_profile_proxy(); + + if (proxy == NULL) + return BT_HID_AGENT_ERROR_INTERNAL; + + builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}")); + + g_variant_builder_add(builder, "{sv}", + "Name", g_variant_new("s", + name)); + + g_variant_builder_add(builder, "{sv}", + "PSM", g_variant_new("q", 17)); + + ret = g_dbus_proxy_call_sync(proxy, "RegisterProfile", + g_variant_new("(osa{sv})", BT_HID_BLUEZ_OBJECT_PATH, + HID_DEVICE_UUID, builder), + G_DBUS_CALL_FLAGS_NONE, -1, + NULL, &error); + + g_variant_builder_unref(builder); + + if (ret == NULL) { + /* dBUS-RPC is failed */ + ERR("dBUS-RPC is failed"); + if (error != NULL) { + /* dBUS gives error cause */ + ERR("D-Bus API failure: errCode[%x], message[%s]", + error->code, error->message); + g_clear_error(&error); + } + return BT_HID_AGENT_ERROR_INTERNAL; + } + g_variant_unref(ret); + + FN_END; + return BT_HID_AGENT_ERROR_NONE; +} + +static void __bt_hid_agent_register(void) +{ + FN_START; + int ret; + + ret = __bt_hid_register_profile(HID_DEVICE_UUID, + "HID device", BT_HID_BLUEZ_OBJECT_PATH); + if (ret) + ERR("Error in register"); + + FN_END; + return; +} + +static void __bt_hid_agent_unregister(void) +{ + FN_START; + + if (g_obj_path) { + __bt_hid_agent_gdbus_method_send(BLUEZ_SERVICE_NAME, + g_variant_new("(o)", BT_HID_BLUEZ_OBJECT_PATH), + BLUEZ_HID_INTERFACE_NAME, + "UnregisterAgent"); + g_free(g_obj_path); + g_obj_path = NULL; + } + + FN_END; + return; +} + +static void __bt_hid_agent_filter_cb(GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + FN_START; + char *path = NULL; + + GVariant *optional_param; + + if (strcasecmp(signal_name, "InterfacesAdded") == 0) { + + g_variant_get(parameters, "(&o@a{sa{sv}})", + &path, &optional_param); + if (!path) { + ERR("Invalid adapter path"); + return; + } + + if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) { + g_obj_path = g_strdup(path); + INFO("Adapter Path = [%s]", path); + __bt_hid_agent_register(); + } + } else if (strcasecmp(signal_name, "InterfacesRemoved") == 0) { + g_variant_get(parameters, "(&o@as)", &path, &optional_param); + if (!path) + __bt_hid_agent_unregister(); + } + FN_END; +} + +void _bt_convert_device_path_to_address(const char *device_path, + char *device_address) +{ + char address[BT_ADDRESS_STRING_SIZE] = { 0 }; + char *dev_addr; + + ret_if(device_path == NULL); + ret_if(device_address == NULL); + + dev_addr = strstr(device_path, "dev_"); + if (dev_addr != NULL) { + char *pos = NULL; + dev_addr += 4; + g_strlcpy(address, dev_addr, sizeof(address)); + + while ((pos = strchr(address, '_')) != NULL) { + *pos = ':'; + } + + g_strlcpy(device_address, address, BT_ADDRESS_STRING_SIZE); + } +} + +static void __bt_hid_device_filter_cb(GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + DBG("sender_name = %s, object_path = %s", sender_name, object_path); + + if (strcasecmp(signal_name, "ProfileStateChanged") == 0) { + char *profile_uuid = NULL; + bt_hid_state_t state = 0; + + g_variant_get(parameters, "(&si)", &profile_uuid, &state); + if (g_strcmp0(profile_uuid, HID_DEVICE_UUID) == 0) { + if (state == BT_HID_STATE_CONNECTED) { + g_free(bt_hid_info.object_path); + bt_hid_info.object_path = g_strdup(object_path); + DBG("device : [%s]", bt_hid_info.object_path); + } + _bt_hid_set_profile_state(state); + } + } +} + +static int __bt_hid_agent_get_adapter_path(GDBusConnection *conn, char *path) +{ + GError *err = NULL; + GDBusProxy *manager_proxy = NULL; + GVariant *result = NULL; + char *adapter_path = NULL; + + if (conn == NULL) + return BT_HID_AGENT_ERROR_INTERNAL; + + manager_proxy = g_dbus_proxy_new_sync(conn, + G_DBUS_PROXY_FLAGS_NONE, NULL, + BLUEZ_SERVICE_NAME, + "/", + BT_MANAGER_INTERFACE, + NULL, &err); + + if (!manager_proxy) { + ERR("Unable to create proxy: %s", err->message); + goto fail; + } + + result = g_dbus_proxy_call_sync(manager_proxy, "DefaultAdapter", NULL, + G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err); + if (!result) { + if (err != NULL) + ERR("Fail to get DefaultAdapter (Error: %s)", err->message); + else + ERR("Fail to get DefaultAdapter"); + + goto fail; + } + + if (g_strcmp0(g_variant_get_type_string(result), "(o)")) { + ERR("Incorrect result\n"); + goto fail; + } + + g_variant_get(result, "(&o)", &adapter_path); + + if (adapter_path == NULL || + strlen(adapter_path) >= BT_ADAPTER_OBJECT_PATH_MAX) { + ERR("Adapter path is inproper\n"); + goto fail; + } + + if (path) + g_strlcpy(path, adapter_path, BT_ADAPTER_OBJECT_PATH_MAX); + + if (g_obj_path == NULL) { + g_obj_path = g_strdup(adapter_path); + INFO("Update g_obj_path [%s]", adapter_path); + } + + g_variant_unref(result); + g_object_unref(manager_proxy); + + return 0; + +fail: + g_clear_error(&err); + + if (result) + g_variant_unref(result); + + if (manager_proxy) + g_object_unref(manager_proxy); + + return BT_HID_AGENT_ERROR_INTERNAL; + +} + +static void __bt_hid_agent_dbus_init(void) +{ + GDBusConnection *conn; + + FN_START; + + conn = __bt_hid_get_gdbus_connection(); + if (conn == NULL) { + ERR("Error in creating the gdbus connection"); + return; + } + if (!__bt_hid_register_methods()) { + ERR("Error in __bt_hid_register_methods"); + return; + } + + if (!__bt_hid_agent_get_adapter_path(conn, NULL)) { + __bt_hid_agent_register(); + } + + owner_sig_id = g_dbus_connection_signal_subscribe(conn, + NULL, BT_MANAGER_INTERFACE, NULL, NULL, NULL, 0, + __bt_hid_agent_filter_cb, NULL, NULL); + + bluez_device_sig_id = g_dbus_connection_signal_subscribe(conn, + NULL, BLUEZ_DEVICE_INTERFACE, NULL, NULL, + NULL, 0, __bt_hid_device_filter_cb, + NULL, NULL); + + _bt_hid_set_profile_state(BT_HID_STATE_DISCONNECTED); + + FN_END; +} + +static void __bt_hid_agent_dbus_deinit(void) +{ + if (profile_gproxy) { + g_object_unref(profile_gproxy); + profile_gproxy = NULL; + } + + if (gdbus_conn) { + if (owner_sig_id > 0) + g_dbus_connection_signal_unsubscribe(gdbus_conn, + owner_sig_id); + + if (bluez_device_sig_id > 0) + g_dbus_connection_signal_unsubscribe(gdbus_conn, + bluez_device_sig_id); + + if (name_owner_sig_id > 0) + g_dbus_connection_signal_unsubscribe(gdbus_conn, + name_owner_sig_id); + + owner_sig_id = 0; + bluez_device_sig_id = 0; + name_owner_sig_id = 0; + + g_object_unref(gdbus_conn); + gdbus_conn = NULL; + } +} + + + + +bt_hid_agent_error_t __bt_hid_disconnect_profile(void) +{ + FN_START; + GDBusProxy *proxy; + + proxy = __bt_hid_gdbus_get_device_proxy(bt_hid_info.object_path); + + if (proxy == NULL) { + ERR("Error while getting proxy"); + return BT_HID_AGENT_ERROR_INTERNAL; + } + + g_dbus_proxy_call(proxy, "DisconnectProfile", + g_variant_new("(s)", HID_DEVICE_UUID), + G_DBUS_CALL_FLAGS_NONE, 2000, + NULL, NULL, NULL); + + FN_END; + + return BT_HID_AGENT_ERROR_NONE; +} + +int main(void) +{ + int i; + struct sigaction sa; + + + INFO_C("### Starting Bluetooth HID agent"); + +#if GLIB_VERSION_MIN_REQUIRED < GLIB_VERSION_2_36 + g_type_init(); +#endif + + memset(&sa, 0, sizeof(sa)); + sa.sa_flags = SA_NOCLDSTOP; + sa.sa_handler = __bt_hid_agent_sigterm_handler; + + for (i = 0; i < BT_HID_SIG_NUM; i++) + sigaction(bt_hid_sig_to_handle[i], &sa, &(bt_hid_sigoldact[i])); + + g_log_set_default_handler(__on_log_glib, NULL); + + gmain_loop = g_main_loop_new(NULL, FALSE); + + __bt_hid_agent_dbus_init(); + + g_main_loop_run(gmain_loop); + + __bt_hid_agent_dbus_deinit(); + + if (gmain_loop) + g_main_loop_unref(gmain_loop); + + INFO_C("### Terminating Bluetooth HID agent"); + return 0; +} + diff --git a/hid-agent/bluetooth-hid-agent.h b/hid-agent/bluetooth-hid-agent.h new file mode 100644 index 0000000..8149ce6 --- /dev/null +++ b/hid-agent/bluetooth-hid-agent.h @@ -0,0 +1,163 @@ +/* + * Bluetooth-hid-agent + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef __DEF_BT_HID_AGENT_H_ +#define __DEF_BT_HID_AGENT_H_ +#define FUNCTION_TRACE + +#include +#include +#include +#include +#include +#include +#include + +#undef LOG_TAG +#define LOG_TAG "BLUETOOTH_HID_AGENT" + +#define LOG_COLOR_RESET "\033[0m" +#define LOG_COLOR_RED "\033[31m" +#define LOG_COLOR_YELLOW "\033[33m" +#define LOG_COLOR_GREEN "\033[32m" +#define LOG_COLOR_BLUE "\033[36m" +#define LOG_COLOR_PURPLE "\033[35m" + +#define DBG(fmt, args...) SLOGD(fmt, ##args) +#define INFO(fmt, args...) SLOGI(fmt, ##args) +#define ERR(fmt, args...) SLOGE(fmt, ##args) +#define DBG_SECURE(fmt, args...) SECURE_SLOGD(fmt, ##args) +#define INFO_SECURE(fmt, args...) SECURE_SLOGI(fmt, ##args) +#define ERR_SECURE(fmt, args...) SECURE_SLOGE(fmt, ##args) +#define DBG_SECURE(fmt, args...) SECURE_SLOGD(fmt, ##args) +#define INFO_C(fmt, arg...) \ + SLOGI_IF(TRUE, LOG_COLOR_BLUE" "fmt" "LOG_COLOR_RESET, ##arg) +#define ERR_C(fmt, arg...) \ + SLOGI_IF(TRUE, LOG_COLOR_RED" "fmt" "LOG_COLOR_RESET, ##arg) + +#ifdef FUNCTION_TRACE +#define FN_START DBG("[ENTER FUNC]") +#define FN_END DBG("[EXIT FUNC]") +#else +#define FN_START +#define FN_END +#endif + +#define BT_HID_SERVICE_NAME "org.bluez.hid_agent" +#define BT_HID_AGENT_OBJECT_PATH "/org/bluez/hid_agent" +#define BT_HID_SERVICE_INTERFACE "org.tizen.HidApp" +#define BT_HID_AGENT_ERROR (__bt_hid_agent_error_quark()) + +#define BT_HID_BLUEZ_OBJECT_PATH "/org/tizen/hid" +#define BT_HID_BLUEZ_INTERFACE "org.bluez.HidAgent" + +#define BLUEZ_SERVICE_NAME "org.bluez" +#define BLUEZ_HID_INTERFACE_NAME "org.bluez.hid_device" + +#define BLUEZ_PROFILE_MGMT_INTERFACE "org.bluez.ProfileManager1" +#define BT_MANAGER_INTERFACE "org.freedesktop.DBus.ObjectManager" +#define BT_ADAPTER_INTERFACE "org.bluez.Adapter1" + +#define BT_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties" +#define BLUEZ_MEDIA_TRANSPORT_INTERFACE "org.bluez.MediaTransport1" +#define BLUEZ_MEDIA_ENDPOINT_INTERFACE "org.bluez.MediaEndpoint1" +#define BLUEZ_DEVICE_INTERFACE "org.bluez.Device1" +#define A2DP_SOURCE_ENDPOINT "/MediaEndpoint/A2DPSource" + +#define BT_ADDRESS_STRING_SIZE 18 +#define BT_ADAPTER_OBJECT_PATH_MAX 50 +#define BT_HID_DATA_BUF_SIZE 1024 + +#define BT_ERROR_INTERNAL "InternalError" +#define BT_ERROR_NOT_AVAILABLE "NotAvailable" +#define BT_ERROR_NOT_CONNECTED "NotConnected" +#define BT_ERROR_NOT_CONNECTION_FAILED "ConnectionFailed" +#define BT_ERROR_BUSY "InProgress" +#define BT_ERROR_INVALID_PARAM "InvalidArguments" +#define BT_ERROR_ALREADY_EXIST "AlreadyExists" +#define BT_ERROR_ALREADY_CONNECTED "Already Connected" +#define BT_ERROR_NO_MEMORY "No memory" +#define BT_ERROR_NO_DATA "No data" +#define BT_ERROR_I_O_ERROR "I/O error" +#define BT_ERROR_OPERATION_NOT_AVAILABLE "Operation currently not available" +#define BT_ERROR_OPERATION_NOT_ALLOWED "Operation not allowed" +#define BT_ERROR_OPERATION_NOT_SUPPORTED "Operation not supported" +#define BT_ERROR_INVALID_FILE_DESCRIPTOR "Invalid File Descriptor" + +#define ret_if(expr) \ + do { \ + if (expr) { \ + ERR("(%s) return", #expr); \ + return; \ + } \ + } while (0) + +typedef enum { + BT_HID_AGENT_ERROR_NONE, + BT_HID_AGENT_ERROR_INTERNAL, + BT_HID_AGENT_ERROR_NOT_AVAILABLE, + BT_HID_AGENT_ERROR_NOT_CONNECTED, + BT_HID_AGENT_ERROR_CONNECTION_FAILED, + BT_HID_AGENT_ERROR_BUSY, + BT_HID_AGENT_ERROR_INVALID_PARAM, + BT_HID_AGENT_ERROR_ALREADY_EXIST, + BT_HID_AGENT_ERROR_ALREADY_CONNECTED, + BT_HID_AGENT_ERROR_NO_MEMORY, + BT_HID_AGENT_ERROR_NO_DATA, + BT_HID_AGENT_ERROR_I_O_ERROR, + BT_HID_AGENT_ERROR_APPLICATION, + BT_HID_AGENT_ERROR_NOT_ALLOWED, + BT_HID_AGENT_ERROR_NOT_SUPPORTED, + BT_HID_AGENT_ERROR_INVALID_FILE_DESCRIPTOR, +} bt_hid_agent_error_t; + +typedef enum { + BT_HID_STATE_UNAVAILABLE, + BT_HID_STATE_DISCONNECTED, + BT_HID_STATE_CONNECTING, + BT_HID_STATE_CONNECTED, + BT_HID_STATE_DISCONNECTING, +} bt_hid_state_t; + +typedef struct { + guint32 fd; + char remote_addr[BT_ADDRESS_STRING_SIZE]; + char *object_path; + GDBusMethodInvocation *context; + char *path; +} bt_hid_agent_info_t; + +typedef struct { + unsigned char b[6]; +} __attribute__((packed)) bdaddr_t; + +/* Remote socket address */ +struct sockaddr_remote { + sa_family_t family; + bdaddr_t remote_bdaddr; + uint8_t channel; +}; + +void _bt_hid_set_profile_state(bt_hid_state_t new_state); +bt_hid_agent_error_t _bt_hid_register_application(gboolean register_flag, + const char *sender_name); + +bt_hid_agent_error_t __bt_hid_disconnect_profile(void); + +#endif /* __DEF_BT_HID_AGENT_H_ */ diff --git a/hid-agent/bluetooth-hid-manager.c b/hid-agent/bluetooth-hid-manager.c new file mode 100644 index 0000000..f101b32 --- /dev/null +++ b/hid-agent/bluetooth-hid-manager.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "bluetooth-hid-agent.h" + +static char *sender; +static bt_hid_state_t hid_state; + +static const char *__bt_hid_state2str(bt_hid_state_t state) +{ + switch (state) { + case BT_HID_STATE_UNAVAILABLE: + return "UNAVAILABLE"; + case BT_HID_STATE_DISCONNECTED: + return "DISCONNECTED"; + case BT_HID_STATE_CONNECTING: + return "CONNECTING"; + case BT_HID_STATE_CONNECTED: + return "CONNECTED"; + case BT_HID_STATE_DISCONNECTING: + return "DISCONNECTING"; + } + + return NULL; +} + +#if 0 +static gboolean __bt_hid_check_for_callpath(const char *call_sender) +{ + GSList *s_list = app_list; + char *sender; + + DBG_SECURE("sender is = %s\n", call_sender); + + if (call_sender == NULL) { + + ERR("Invalid Parameters"); + return FALSE; + } + + /*check if the call is already registered*/ + DBG("Checking if the call is already registered"); + while (s_list != NULL) { + sender = s_list->data; + + if (sender == NULL) + break; + + if (g_strcmp0(sender, call_sender) == 0) { + DBG("sender path and call path match... so return true"); + return TRUE; + } + + s_list = s_list->next; + } + + ERR("Sender [%s] is not registered", call_sender); + return FALSE; +} + +bt_hid_agent_error_t _bt_hid_register_application(gboolean register_flag, + const char *sender) +{ + char *sender_name; + + if (sender == NULL) + return BT_HID_AGENT_ERROR_INVALID_PARAM; + + DBG(" Requesting [%s]", register_flag ? "Register" : "Unregister"); + DBG(" sender = %s", sender); + + if (register_flag) { + if (__bt_hid_check_for_callpath(sender)) + return BT_HID_AGENT_ERROR_ALREADY_EXIST; + + /* add call path to the senders list*/ + sender_name = g_strdup(sender); + app_list = g_slist_append(app_list, sender_name); + + return BT_HID_AGENT_ERROR_NONE; + } else { + /*remove the call from senders list */ + GSList *s_list = app_list; + + while (s_list != NULL) { + sender_name = s_list->data; + + if (sender_name == NULL) + return BT_HID_AGENT_ERROR_NOT_AVAILABLE; + + if (g_strcmp0(sender_name, sender) == 0) { + app_list = g_slist_remove(app_list, sender_name); + g_free(sender_name); + + if (app_list == NULL && hid_state == BT_HID_STATE_CONNECTED) + __bt_hid_disconnect_profile(); + + return BT_HID_AGENT_ERROR_NONE; + } + s_list = s_list->next; + } + + return BT_HID_AGENT_ERROR_NOT_AVAILABLE; + } +} + +#else +bt_hid_agent_error_t _bt_hid_register_application(gboolean register_flag, + const char *sender_name) +{ + if (sender_name == NULL) + return BT_HID_AGENT_ERROR_INVALID_PARAM; + + if (register_flag == TRUE) { + if (sender != NULL) { + ERR("Already registered [sender:%s]", sender_name); + return BT_HID_AGENT_ERROR_ALREADY_EXIST; + } + + /* set the call path to the sender */ + sender = g_strdup(sender_name); + INFO("Registered [sender:%s]", sender_name); + } else { + if (sender == NULL) + return BT_HID_AGENT_ERROR_NOT_AVAILABLE; + if (strcasecmp(sender, sender_name) != 0) + return BT_HID_AGENT_ERROR_NOT_AVAILABLE; + + /* unset the call path to the sender */ + g_free(sender); + sender = NULL; + if (hid_state == BT_HID_STATE_CONNECTED) + __bt_hid_disconnect_profile(); + INFO("Unregistered [sender:%s]", sender_name); + } + + return BT_HID_AGENT_ERROR_NONE; +} +#endif + +void _bt_hid_set_profile_state(bt_hid_state_t new_state) +{ + INFO_C("state changed [%s] =>[%s]", __bt_hid_state2str(hid_state), + __bt_hid_state2str(new_state)); + hid_state = new_state; + + switch (new_state) { + case BT_HID_STATE_UNAVAILABLE: + case BT_HID_STATE_DISCONNECTED: + break; + case BT_HID_STATE_CONNECTED: + break; + case BT_HID_STATE_CONNECTING: + case BT_HID_STATE_DISCONNECTING: + default: + break; + } +} + +bt_hid_state_t _bt_hid_get_profile_state(void) +{ + return hid_state; +} diff --git a/hid-agent/org.bluez.hid_agent.service b/hid-agent/org.bluez.hid_agent.service new file mode 100644 index 0000000..e678c59 --- /dev/null +++ b/hid-agent/org.bluez.hid_agent.service @@ -0,0 +1,5 @@ +[D-BUS Service] +Name=org.bluez.hid_agent +Exec=/usr/bin/bluetooth-hid-agent +User=network_fw +Group=network_fw