📄 manager.c
字号:
DBusMessage *msg; DBusPendingCall *call; msg = dbus_message_new_method_call("org.bluez", pc->adapter_path, "org.bluez.Adapter", "GetRemoteServiceRecord"); if (!msg) return -1; dbus_message_append_args(msg, DBUS_TYPE_STRING, &pc->bda, DBUS_TYPE_UINT32, &handle, DBUS_TYPE_INVALID); if (!dbus_connection_send_with_reply(pc->conn, msg, &call, -1)) { error("Can't send D-Bus message."); dbus_message_unref(msg); return -1; } dbus_pending_call_set_notify(call, cb, pc, NULL); dbus_pending_call_unref(call); dbus_message_unref(msg); return 0;}static void handles_reply(DBusPendingCall *call, void *data){ struct pending_connect *pc; DBusMessage *reply = dbus_pending_call_steal_reply(call); DBusError derr; uint32_t *phandle; int len; /* Owner exited? */ if (!g_slist_find(pending_connects, data)) { dbus_message_unref(reply); return; } pc = data; if (pc->canceled) { error_canceled(pc->conn, pc->msg, "Connection canceled"); goto fail; } dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { /* FIXME : forward error as is */ if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed")) error_connection_attempt_failed(pc->conn, pc->msg, EIO); else error_not_supported(pc->conn, pc->msg); error("GetRemoteServiceHandles: %s(%s)", derr.name, derr.message); dbus_error_free(&derr); goto fail; } if (!dbus_message_get_args(reply, &derr, DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len, DBUS_TYPE_INVALID)) { error_not_supported(pc->conn, pc->msg); error("%s: %s", derr.name, derr.message); dbus_error_free(&derr); goto fail; } if (len == 0) { error_not_supported(pc->conn, pc->msg); goto fail; } if (get_record(pc, *phandle, record_reply) < 0) { error_not_supported(pc->conn, pc->msg); goto fail; } dbus_message_unref(reply); return;fail: dbus_message_unref(reply); pending_connect_remove(pc);}static int get_handles(struct pending_connect *pc, const char *uuid, DBusPendingCallNotifyFunction cb){ DBusMessage *msg; DBusPendingCall *call; 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->bda, DBUS_TYPE_STRING, &uuid, DBUS_TYPE_INVALID); if (!dbus_connection_send_with_reply(pc->conn, msg, &call, -1)) { error("Can't send D-Bus message."); dbus_message_unref(msg); return -1; } dbus_pending_call_set_notify(call, cb, pc, NULL); dbus_pending_call_unref(call); dbus_message_unref(msg); return 0;}static int pattern2uuid128(const char *pattern, char *uuid, size_t size){ uint16_t cls; /* Friendly name */ cls = str2class(pattern); if (cls) { uuid_t uuid16, uuid128; sdp_uuid16_create(&uuid16, cls); sdp_uuid16_to_uuid128(&uuid128, &uuid16); sdp_uuid2strn(&uuid128, uuid, size); return 0; } /* UUID 128*/ if ((strlen(pattern) == 36) && (strncasecmp(BASE_UUID, pattern, 3) == 0) && (strncasecmp(BASE_UUID + 8, pattern + 8, 28) == 0)) { strncpy(uuid, pattern, size); return 0; } return -EINVAL;}static int pattern2long(const char *pattern, long *pval){ char *endptr; long val; errno = 0; val = strtol(pattern, &endptr, 0); if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || (errno != 0 && val == 0) || (pattern == endptr)) { return -EINVAL; } *pval = val; return 0;}static DBusHandlerResult create_port(DBusConnection *conn, DBusMessage *msg, void *data){ char path[MAX_PATH_LENGTH], port_name[16], uuid[MAX_LEN_UUID_STR]; const char *bda, *pattern, *ppath = path; struct pending_connect *pending, *pc; DBusMessage *reply; DBusError derr; bdaddr_t src, dst; long val; int dev_id, err; dbus_error_init(&derr); if (!dbus_message_get_args(msg, &derr, DBUS_TYPE_STRING, &bda, DBUS_TYPE_STRING, &pattern, DBUS_TYPE_INVALID)) { error_invalid_arguments(conn, msg, derr.message); dbus_error_free(&derr); return DBUS_HANDLER_RESULT_HANDLED; } pending = find_pending_connect_by_pattern(bda, pattern); if (pending) return error_in_progress(conn, msg, "Connection in progress"); dev_id = hci_get_route(NULL); if ((dev_id < 0) || (hci_devba(dev_id, &src) < 0)) return error_failed(conn, msg, "Adapter not available"); pc = g_new0(struct pending_connect, 1); bacpy(&pc->src, &src); pc->conn = dbus_connection_ref(conn); pc->msg = dbus_message_ref(msg); pc->bda = g_strdup(bda); pc->id = -1; pc->pattern = g_strdup(pattern); pc->adapter_path = g_malloc0(16); snprintf(pc->adapter_path, 16, "/org/bluez/hci%d", dev_id); memset(uuid, 0, sizeof(uuid)); /* Friendly name or uuid128 */ if (pattern2uuid128(pattern, uuid, sizeof(uuid)) == 0) { if (get_handles(pc, uuid, handles_reply) < 0) { pending_connect_free(pc); return error_not_supported(conn, msg); } pending_connects = g_slist_append(pending_connects, pc); name_listener_add(conn, dbus_message_get_sender(msg), (name_cb_t) transaction_owner_exited, NULL); return DBUS_HANDLER_RESULT_HANDLED; } /* Record handle or channel */ err = pattern2long(pattern, &val); if (err < 0) { pending_connect_free(pc); return error_invalid_arguments(conn, msg, "invalid pattern"); } /* Record handle: starts at 0x10000 */ if (strncasecmp("0x", pattern, 2) == 0) { if (val < 0x10000) { pending_connect_free(pc); return error_invalid_arguments(conn, msg, "invalid record handle"); } if (get_record(pc, val, record_reply) < 0) { pending_connect_free(pc); return error_not_supported(conn, msg); } pending_connects = g_slist_append(pending_connects, pc); name_listener_add(conn, dbus_message_get_sender(msg), (name_cb_t) transaction_owner_exited, NULL); return DBUS_HANDLER_RESULT_HANDLED; } pending_connect_free(pc); /* RFCOMM Channel range: 1 - 30 */ if (val < 1 || val > 30) return error_invalid_arguments(conn, msg, "invalid RFCOMM channel"); str2ba(bda, &dst); err = rfcomm_bind(&src, &dst, -1, val); if (err < 0) return error_failed_errno(conn, msg, -err); snprintf(port_name, sizeof(port_name), "/dev/rfcomm%d", err); port_store(&src, &dst, err, val, NULL); port_register(conn, err, &src, &dst, port_name, path, NULL); ports_paths = g_slist_append(ports_paths, g_strdup(path)); reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; dbus_message_append_args(reply, DBUS_TYPE_STRING, &ppath, DBUS_TYPE_INVALID); send_message_and_unref(conn, reply); dbus_connection_emit_signal(conn, SERIAL_MANAGER_PATH, SERIAL_MANAGER_INTERFACE, "PortCreated" , DBUS_TYPE_STRING, &ppath, DBUS_TYPE_INVALID); return DBUS_HANDLER_RESULT_HANDLED;}static void message_append_paths(DBusMessage *msg, const GSList *list){ const GSList *l; const char *path; DBusMessageIter iter, iter_array; dbus_message_iter_init_append(msg, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &iter_array); for (l = list; l; l = l->next) { path = l->data; dbus_message_iter_append_basic(&iter_array, DBUS_TYPE_STRING, &path); } dbus_message_iter_close_container(&iter, &iter_array);}static DBusHandlerResult list_ports(DBusConnection *conn, DBusMessage *msg, void *data){ DBusMessage *reply; reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; message_append_paths(reply, ports_paths); return send_message_and_unref(conn, reply);}static DBusHandlerResult remove_port(DBusConnection *conn, DBusMessage *msg, void *data){ struct rfcomm_dev_info di; DBusError derr; const char *path; GSList *l; int16_t id; 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; } if (sscanf(path, SERIAL_MANAGER_PATH"/rfcomm%hd", &id) != 1) return error_does_not_exist(conn, msg, "Invalid RFCOMM node"); di.id = id; if (ioctl(rfcomm_ctl, RFCOMMGETDEVINFO, &di) < 0) return error_does_not_exist(conn, msg, "Invalid RFCOMM node"); port_delete(&di.src, &di.dst, id); if (port_unregister(path) < 0) return error_does_not_exist(conn, msg, "Invalid RFCOMM node"); send_message_and_unref(conn, dbus_message_new_method_return(msg)); dbus_connection_emit_signal(conn, SERIAL_MANAGER_PATH, SERIAL_MANAGER_INTERFACE, "PortRemoved" , DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID); l = g_slist_find_custom(ports_paths, path, (GCompareFunc) strcmp); if (l) { g_free(l->data); ports_paths = g_slist_remove(ports_paths, l->data); } return DBUS_HANDLER_RESULT_HANDLED;}static int rfcomm_listen(bdaddr_t *src, uint8_t *channel, int opts){ struct sockaddr_rc laddr; socklen_t alen; int err, sk; sk = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); if (sk < 0) return -errno; if (setsockopt(sk, SOL_RFCOMM, RFCOMM_LM, &opts, sizeof(opts)) < 0) goto fail; memset(&laddr, 0, sizeof(laddr)); laddr.rc_family = AF_BLUETOOTH; bacpy(&laddr.rc_bdaddr, src); laddr.rc_channel = (channel ? *channel : 0); alen = sizeof(laddr); if (bind(sk, (struct sockaddr *) &laddr, alen) < 0) goto fail; if (listen(sk, 1) < 0) goto fail; if (!channel) return sk; memset(&laddr, 0, sizeof(laddr)); if (getsockname(sk, (struct sockaddr *)&laddr, &alen) < 0) goto fail; *channel = laddr.rc_channel; return sk;fail: err = errno; close(sk); errno = err; return -err;}static void add_lang_attr(sdp_record_t *r){ sdp_lang_attr_t base_lang; sdp_list_t *langs = 0; /* UTF-8 MIBenum (http://www.iana.org/assignments/character-sets) */ base_lang.code_ISO639 = (0x65 << 8) | 0x6e; base_lang.encoding = 106; base_lang.base_offset = SDP_PRIMARY_LANG_BASE; langs = sdp_list_append(0, &base_lang); sdp_set_lang_attr(r, langs); sdp_list_free(langs, 0);}static int str2uuid(uuid_t *uuid, const char *string){ uint16_t data1, data2, data3, data5; uint32_t data0, data4; if (strlen(string) == 36 && string[8] == '-' && string[13] == '-' && string[18] == '-' && string[23] == '-' && sscanf(string, "%08x-%04hx-%04hx-%04hx-%08x%04hx", &data0, &data1, &data2, &data3, &data4, &data5) == 6) { uint8_t val[16]; data0 = htonl(data0); data1 = htons(data1); data2 = htons(data2); data3 = htons(data3); data4 = htonl(data4); data5 = htons(data5); memcpy(&val[0], &data0, 4); memcpy(&val[4], &data1, 2); memcpy(&val[6], &data2, 2); memcpy(&val[8], &data3, 2); memcpy(&val[10], &data4, 4); memcpy(&val[14], &data5, 2); sdp_uuid128_create(uuid, val); return 0; } return -1;}static int create_proxy_record(sdp_buf_t *buf, const char *uuid128, uint8_t channel){ sdp_list_t *apseq, *aproto, *profiles, *proto[2], *root, *svclass_id; uuid_t uuid, root_uuid, l2cap, rfcomm; sdp_profile_desc_t profile; sdp_record_t record; sdp_data_t *ch; int ret; memset(&record, 0, sizeof(sdp_record_t)); record.handle = 0xffffffff; sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root = sdp_list_append(NULL, &root_uuid); sdp_set_browse_groups(&record, root); sdp_list_free(root, NULL); str2uuid(&uuid, uuid128); svclass_id = sdp_list_append(NULL, &uuid); sdp_set_service_classes(&record, svclass_id); sdp_list_free(svclass_id, NULL); sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID); profile.version = 0x0100; profiles = sdp_list_append(NULL, &profile); sdp_set_profile_descs(&record, profiles); sdp_list_free(profiles, NULL); sdp_uuid16_create(&l2cap, L2CAP_UUID); proto[0] = sdp_list_append(NULL, &l2cap); apseq = sdp_list_append(NULL, proto[0]); sdp_uuid16_create(&rfcomm, RFCOMM_UUID); proto[1] = sdp_list_append(NULL, &rfcomm); ch = sdp_data_alloc(SDP_UINT8, &channel); proto[1] = sdp_list_append(proto[1], ch); apseq = sdp_list_append(apseq, proto[1]); aproto = sdp_list_append(NULL, apseq); sdp_set_access_protos(&record, aproto); add_lang_attr(&record); sdp_set_info_attr(&record, "Port Proxy Entity", NULL, "Port Proxy Entity"); ret = sdp_gen_record_pdu(&record, buf); sdp_data_free(ch); sdp_list_free(proto[0], NULL); sdp_list_free(proto[1], NULL); sdp_list_free(apseq, NULL); sdp_list_free(aproto, NULL); sdp_list_free(record.attrlist, (sdp_free_func_t) sdp_data_free); sdp_list_free(record.pattern, free); return ret;}static GIOError channel_write(GIOChannel *chan, char *buf, size_t size){ GIOError err = G_IO_ERROR_NONE; gsize wbytes, written; wbytes = written = 0; while (wbytes < size) { err = g_io_channel_write(chan, buf + wbytes, size - wbytes, &written); if (err != G_IO_ERROR_NONE) return err; wbytes += written; } return err;}static gboolean forward_data(GIOChannel *chan, GIOCondition cond, gpointer data){ char buf[BUF_SIZE]; GIOChannel *dest = data; GIOError err; size_t rbytes; if (cond & G_IO_NVAL) return FALSE; if (cond & (G_IO_HUP | G_IO_ERR)) { /* Try forward remaining data */ do { rbytes = 0; err = g_io_channel_read(chan, buf, sizeof(buf), &rbytes); if (err != G_IO_ERROR_NONE || rbytes == 0) break; err = channel_write(dest, buf, rbytes); } while (err == G_IO_ERROR_NONE); g_io_channel_close(dest); return FALSE; } rbytes = 0; err = g_io_channel_read(chan, buf, sizeof(buf), &rbytes); if (err != G_IO_ERROR_NONE) return FALSE; err = channel_write(dest, buf, rbytes); if (err != G_IO_ERROR_NONE) return FALSE; return TRUE;}static uint32_t add_proxy_record(DBusConnection *conn, sdp_buf_t *buf){ DBusMessage *msg, *reply; DBusError derr; dbus_uint32_t rec_id; msg = dbus_message_new_method_call("org.bluez", "/org/bluez", "org.bluez.Database", "AddServiceRecord"); if (!msg) { error("Can't allocate new method call"); return 0; } dbus_message_append_args(msg, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &buf->data, buf->data_size, DBUS_TYPE_INVALID); dbus_error_init(&derr); reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &derr); free(buf->data); dbus_message_unref(msg); if (dbus_error_is_set(&derr) || dbus_set_error_from_message(&derr, reply)) { error("Adding service record failed: %s", derr.message); dbus_error_free(&derr); return 0; } dbus_message_get_args(reply, &derr, DBUS_TYPE_UINT32, &rec_id, DBUS_TYPE_INVALID); if (dbus_error_is_set(&derr)) { error("Invalid arguments to AddServiceRecord reply: %s", derr.message); dbus_message_unref(reply); dbus_error_free(&derr); return 0; } dbus_message_unref(reply); return rec_id;}static int remove_proxy_record(DBusConnection *conn, uint32_t rec_id){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -