📄 manager.c
字号:
dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { /* FIXME : to not try to be clever about hcid error but forward as is to the user */ if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed")) error_connection_attempt_failed(pr->conn, pr->msg, EIO); else error_not_supported(pr->conn, pr->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)) { error_not_supported(pr->conn, pr->msg); error("%s: %s", derr.name, derr.message); goto fail; } if (len == 0) { error_not_supported(pr->conn, pr->msg); error("HID record handle not found"); goto fail; } if (get_record(pr, *phandle, hid_record_reply) < 0) { error_not_supported(pr->conn, pr->msg); error("HID service attribute request failed"); goto fail; } else { /* Wait record reply */ goto done; }fail: dbus_error_free(&derr); pending_req_free(pr);done: dbus_message_unref(reply);}static void pnp_record_reply(DBusPendingCall *call, void *data){ DBusMessage *reply = dbus_pending_call_steal_reply(call); struct pending_req *pr = data; DBusError derr; uint8_t *rec_bin; int len, scanned; dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { /* FIXME : to not try to be clever about hcid error but forward as is to the user */ if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed")) error_connection_attempt_failed(pr->conn, pr->msg, EIO); else error_not_supported(pr->conn, pr->msg); error("GetRemoteServiceRecord: %s(%s)", derr.name, derr.message); goto fail; } if (!dbus_message_get_args(reply, &derr, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len, DBUS_TYPE_INVALID)) { error_not_supported(pr->conn, pr->msg); error("%s: %s", derr.name, derr.message); goto fail; } if (len == 0) { error_not_supported(pr->conn, pr->msg); error("Invalid PnP service record length"); goto fail; } pr->pnp_rec = sdp_extract_pdu(rec_bin, &scanned); if (get_handles(pr, hid_uuid, hid_handle_reply) < 0) { error_not_supported(pr->conn, pr->msg); error("HID service search request failed"); goto fail; } else { /* Wait handle reply */ goto done; }fail: dbus_error_free(&derr); pending_req_free(pr);done: dbus_message_unref(reply);}static void pnp_handle_reply(DBusPendingCall *call, void *data){ DBusMessage *reply = dbus_pending_call_steal_reply(call); struct pending_req *pr = data; DBusError derr; uint32_t *phandle; int len; dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { /* FIXME : to not try to be clever about hcid error but forward as is to the user */ if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed")) error_connection_attempt_failed(pr->conn, pr->msg, EIO); else error_not_supported(pr->conn, pr->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)) { error_not_supported(pr->conn, pr->msg); error("%s: %s", derr.name, derr.message); goto fail; } if (len == 0) { /* PnP is optional: Ignore it and request the HID handle */ if (get_handles(pr, hid_uuid, hid_handle_reply) < 0) { error_not_supported(pr->conn, pr->msg); error("HID service search request failed"); goto fail; } } else { /* Request PnP record */ if (get_record(pr, *phandle, pnp_record_reply) < 0) { error_not_supported(pr->conn, pr->msg); error("PnP service attribute request failed"); goto fail; } } /* Wait HID handle reply or PnP record reply */ goto done;fail: dbus_error_free(&derr); pending_req_free(pr);done: dbus_message_unref(reply);}static void headset_record_reply(DBusPendingCall *call, void *data){ DBusMessage *reply = dbus_pending_call_steal_reply(call); DBusMessage *pr_reply; DBusError derr; struct pending_req *pr = data; uint8_t *rec_bin; sdp_record_t *rec; sdp_list_t *protos; const char *path; int len, scanned; uint8_t ch; dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { /* FIXME : to not try to be clever about hcid error but forward as is to the user */ if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed")) error_connection_attempt_failed(pr->conn, pr->msg, EIO); else error_not_supported(pr->conn, pr->msg); error("GetRemoteServiceRecord: %s(%s)", derr.name, derr.message); goto fail; } if (!dbus_message_get_args(reply, &derr, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len, DBUS_TYPE_INVALID)) { error_not_supported(pr->conn, pr->msg); error("%s: %s", derr.name, derr.message); goto fail; } if (len == 0) { error_not_supported(pr->conn, pr->msg); error("Invalid headset service record length"); goto fail; } rec = sdp_extract_pdu(rec_bin, &scanned); if (!rec) { error_not_supported(pr->conn, pr->msg); goto fail; } if (sdp_get_access_protos(rec, &protos) < 0) { error_not_supported(pr->conn, pr->msg); goto fail; } ch = sdp_get_proto_port(protos, RFCOMM_UUID); sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL); sdp_list_free(protos, NULL); sdp_record_free(rec); if (ch <= 0) { error_not_supported(pr->conn, pr->msg); error("Invalid RFCOMM channel"); goto fail; } /* FIXME: Store the fake input data */ if (fake_input_register(pr->conn, &pr->src, &pr->dst, ch, &path) < 0) { error("D-Bus path registration failed:%s", path); error_failed(pr->conn, pr->msg, "Path registration failed"); goto fail; } dbus_connection_emit_signal(pr->conn, INPUT_PATH, INPUT_MANAGER_INTERFACE, "DeviceCreated", DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID); device_paths = g_slist_append(device_paths, g_strdup(path)); pr_reply = dbus_message_new_method_return(pr->msg); dbus_message_append_args(pr_reply, DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID); send_message_and_unref(pr->conn, pr_reply);fail: dbus_error_free(&derr); pending_req_free(pr); dbus_message_unref(reply);}static void headset_handle_reply(DBusPendingCall *call, void *data){ DBusMessage *reply = dbus_pending_call_steal_reply(call); struct pending_req *pr = data; DBusError derr; uint32_t *phandle; int len; dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { /* FIXME : to not try to be clever about hcid error but forward as is to the user */ if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed")) error_connection_attempt_failed(pr->conn, pr->msg, EIO); else error_not_supported(pr->conn, pr->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)) { error_not_supported(pr->conn, pr->msg); error("%s: %s", derr.name, derr.message); goto fail; } if (len == 0) { error_not_supported(pr->conn, pr->msg); error("Headset record handle not found"); goto fail; } if (get_record(pr, *phandle, headset_record_reply) < 0) { error_not_supported(pr->conn, pr->msg); error("Headset service attribute request failed"); goto fail; } else { /* Wait record reply */ goto done; }fail: dbus_error_free(&derr); pending_req_free(pr);done: dbus_message_unref(reply);}static DBusHandlerResult create_device(DBusConnection *conn, DBusMessage *msg, void *data){ struct pending_req *pr; DBusError derr; const char *addr; bdaddr_t src, dst; uint32_t cls = 0; int dev_id; dbus_error_init(&derr); if (!dbus_message_get_args(msg, &derr, DBUS_TYPE_STRING, &addr, DBUS_TYPE_INVALID)) { error_invalid_arguments(conn, msg, derr.message); dbus_error_free(&derr); return DBUS_HANDLER_RESULT_HANDLED; } /* Get the default adapter */ dev_id = hci_get_route(NULL); if (dev_id < 0) { error("Bluetooth adapter not available"); return error_failed(conn, msg, "Adapter not available"); } if (hci_devba(dev_id, &src) < 0) { error("Can't get local adapter device info"); return error_failed(conn, msg, "Adapter not available"); } str2ba(addr, &dst); if (input_device_is_registered(&src, &dst)) return error_already_exists(conn, msg, "Input Already exists"); if (read_device_class(&src, &dst, &cls) < 0) { error("Device class not available"); return error_not_supported(conn, msg); } pr = pending_req_new(conn, msg, &src, &dst); if (!pr) return DBUS_HANDLER_RESULT_NEED_MEMORY; switch (cls & 0x1f00) { case 0x0500: /* Peripheral */ case 0x0200: /* Phone */ if (get_handles(pr, pnp_uuid, pnp_handle_reply) < 0) { pending_req_free(pr); return error_not_supported(conn, msg); } break; case 0x0400: /* Fake input */ if (get_handles(pr, headset_uuid, headset_handle_reply) < 0) { pending_req_free(pr); return error_not_supported(conn, msg); } break; default: pending_req_free(pr); return error_not_supported(conn, msg); } return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult remove_device(DBusConnection *conn, DBusMessage *msg, void *data){ DBusMessage *reply; DBusError derr; GSList *l; const char *path; int err; dbus_error_init(&derr); if (!dbus_message_get_args(msg, &derr, DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID)) { error_invalid_arguments(conn, msg, derr.message); dbus_error_free(&derr); return DBUS_HANDLER_RESULT_HANDLED; } l = g_slist_find_custom(device_paths, path, (GCompareFunc) strcmp); if (!l) return error_does_not_exist(conn, msg, "Input doesn't exist"); reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; err = input_device_unregister(conn, path); if (err < 0) { dbus_message_unref(reply); return error_failed_errno(conn, msg, -err); } g_free(l->data); device_paths = g_slist_remove(device_paths, l->data); return send_message_and_unref(conn, reply);}static DBusHandlerResult list_devices(DBusConnection *conn, DBusMessage *msg, void *data){ DBusMessageIter iter, iter_array; DBusMessage *reply; GSList *paths; reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &iter_array); for (paths = device_paths; paths != NULL; paths = paths->next) { const char *ppath = paths->data; dbus_message_iter_append_basic(&iter_array, DBUS_TYPE_STRING, &ppath); } dbus_message_iter_close_container(&iter, &iter_array); return send_message_and_unref(conn, reply);}static void manager_unregister(DBusConnection *conn, void *data){ info("Unregistered manager path"); g_slist_foreach(device_paths, (GFunc) free, NULL); g_slist_free(device_paths);}/* * Stored inputs registration functions */static void stored_input(char *key, char *value, void *data){ const char *path; struct hidp_connadd_req hidp; bdaddr_t dst, *src = data; str2ba(key, &dst); memset(&hidp, 0, sizeof(hidp)); if (parse_stored_device_info(value, &hidp) < 0) return; /* * Repeated entries for the same remote device are * acceptable since the source is different. */ if (input_device_register(connection, src, &dst, &hidp, &path) < 0) goto cleanup; device_paths = g_slist_append(device_paths, g_strdup(path));cleanup: if (hidp.rd_data) g_free(hidp.rd_data);}/* hidd to input transition function */static void stored_hidd(char *key, char *value, void *data){ struct hidp_connadd_req hidp; char *str, filename[PATH_MAX + 1], addr[18]; bdaddr_t dst, *src = data; ba2str(src, addr); create_name(filename, PATH_MAX, STORAGEDIR, addr, "input"); str = textfile_get(filename, key); if (str) { /* Skip: entry found in input file */ free(str); return; } memset(&hidp, 0, sizeof(hidp)); if (parse_stored_hidd(value, &hidp) < 0) return; str2ba(key, &dst); store_device_info(src, &dst, &hidp); if (hidp.rd_data) g_free(hidp.rd_data);}static void register_stored_inputs(void){ char dirname[PATH_MAX + 1]; char filename[PATH_MAX + 1]; struct dirent *de; DIR *dir; bdaddr_t src; snprintf(dirname, PATH_MAX, "%s", STORAGEDIR); dir = opendir(dirname); if (!dir) return; while ((de = readdir(dir)) != NULL) { if (!isdigit(de->d_name[0])) continue; str2ba(de->d_name, &src); /* move the hidd entries to the input storage */ create_name(filename, PATH_MAX, STORAGEDIR, de->d_name, "hidd"); textfile_foreach(filename, stored_hidd, &src); /* load the input stored devices */ create_name(filename, PATH_MAX, STORAGEDIR, de->d_name, "input"); textfile_foreach(filename, stored_input, &src); } closedir(dir);}static DBusMethodVTable manager_methods[] = { { "ListDevices", list_devices, "", "as" }, { "CreateDevice", create_device, "s", "s" }, { "CreateSecureDevice", create_device, "s", "s" }, { "RemoveDevice", remove_device, "s", "" }, { NULL, NULL, NULL, NULL },};static DBusSignalVTable manager_signals[] = { { "DeviceCreated", "s" }, { "DeviceRemoved", "s" }, { NULL, NULL }};int input_init(DBusConnection *conn){ dbus_connection_set_exit_on_disconnect(conn, TRUE); if (!dbus_connection_create_object_path(conn, INPUT_PATH, NULL, manager_unregister)) { error("D-Bus failed to register %s path", INPUT_PATH); return -1; } if (!dbus_connection_register_interface(conn, INPUT_PATH, INPUT_MANAGER_INTERFACE, manager_methods, manager_signals, NULL)) { error("Failed to register %s interface to %s", INPUT_MANAGER_INTERFACE, INPUT_PATH); dbus_connection_destroy_object_path(connection, INPUT_PATH); return -1; } connection = dbus_connection_ref(conn); info("Registered input manager path:%s", INPUT_PATH); /* Register well known HID devices */ register_stored_inputs(); server_start(connection); return 0;}void input_exit(void){ dbus_connection_destroy_object_path(connection, INPUT_PATH); server_stop(); dbus_connection_unref(connection); connection = NULL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -