📄 manager.c
字号:
* Unix socket: if the sun_path starts with null byte * it refers to abstract namespace. 'x00' will be used * to represent the null byte. */ if (strncmp("localhost:", address, 10) == 0) return TCP_SOCKET_PROXY; if (strncmp("x00", address, 3) != 0) return UNKNOWN_PROXY_TYPE; else return UNIX_SOCKET_PROXY; } else { /* Filesystem: char device or unix socket */ if (S_ISCHR(st.st_mode) && strncmp("/dev/", address, 4) == 0) return TTY_PROXY; else if (S_ISSOCK(st.st_mode)) return UNIX_SOCKET_PROXY; else return UNKNOWN_PROXY_TYPE; }}static int proxycmp(const char *path, const char *address){ struct proxy *prx = NULL; if (!dbus_connection_get_object_user_data(connection, path, (void *) &prx) || !prx) return -1; return strcmp(prx->address, address);}static DBusHandlerResult create_proxy(DBusConnection *conn, DBusMessage *msg, void *data){ char path[MAX_PATH_LENGTH + 1]; const char *uuid128, *address, *ppath = path; DBusMessage *reply; proxy_type_t type; DBusError derr; bdaddr_t src; uuid_t uuid; int dev_id, ret; dbus_error_init(&derr); if (!dbus_message_get_args(msg, &derr, DBUS_TYPE_STRING, &uuid128, DBUS_TYPE_STRING, &address, DBUS_TYPE_INVALID)) { error_invalid_arguments(conn, msg, derr.message); dbus_error_free(&derr); return DBUS_HANDLER_RESULT_HANDLED; } if (str2uuid(&uuid, uuid128) < 0) return error_invalid_arguments(conn, msg, "Invalid UUID"); type = addr2type(address); if (type == UNKNOWN_PROXY_TYPE) return error_invalid_arguments(conn, msg, "Invalid address"); /* Only one proxy per address(TTY or unix socket) is allowed */ if (g_slist_find_custom(proxies_paths, address, (GCompareFunc) proxycmp)) return error_already_exists(conn, msg, "Proxy already exists"); dev_id = hci_get_route(NULL); if ((dev_id < 0) || (hci_devba(dev_id, &src) < 0)) { error("Adapter not available"); return error_failed(conn, msg, "Adapter not available"); } reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; switch (type) { case UNIX_SOCKET_PROXY: ret = proxy_socket_register(&src, uuid128, address, path, sizeof(path)); break; case TTY_PROXY: ret = proxy_tty_register(&src, uuid128, address, NULL, path, sizeof(path)); break; case TCP_SOCKET_PROXY: ret = proxy_tcp_register(&src, uuid128, address, path, sizeof(path)); break; default: ret = -1; } if (ret < 0) { dbus_message_unref(reply); return error_failed(conn, msg, "Create object path failed"); } dbus_connection_emit_signal(connection, SERIAL_MANAGER_PATH, SERIAL_MANAGER_INTERFACE, "ProxyCreated", DBUS_TYPE_STRING, &ppath, DBUS_TYPE_INVALID); dbus_message_append_args(reply, DBUS_TYPE_STRING, &ppath, DBUS_TYPE_INVALID); return send_message_and_unref(conn, reply);}static DBusHandlerResult list_proxies(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, proxies_paths); return send_message_and_unref(conn, reply);}static DBusHandlerResult remove_proxy(DBusConnection *conn, DBusMessage *msg, void *data){ struct proxy *prx = NULL; const char *path; GSList *l; DBusError derr; 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(proxies_paths, path, (GCompareFunc) strcmp); if (!l) return error_does_not_exist(conn, msg, "Invalid proxy path"); /* Remove from storage */ if (dbus_connection_get_object_user_data(conn, path, (void *) &prx) && prx) proxy_delete(&prx->src, prx->address); g_free(l->data); proxies_paths = g_slist_remove(proxies_paths, l->data); dbus_connection_destroy_object_path(conn, path); dbus_connection_emit_signal(conn, SERIAL_MANAGER_PATH, SERIAL_MANAGER_INTERFACE, "ProxyRemoved", DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID); return send_message_and_unref(conn, dbus_message_new_method_return(msg));}static DBusHandlerResult connect_service_from_devid(DBusConnection *conn, DBusMessage *msg, void *data, int dev_id, const char *bda, const char *pattern){ struct pending_connect *pending, *pc; bdaddr_t src; long val; int err; char uuid[MAX_LEN_UUID_STR]; pending = find_pending_connect_by_pattern(bda, pattern); if (pending) return error_in_progress(conn, msg, "Connection in progress"); 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); goto done; } /* 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); goto done; } /* RFCOMM Channel range: 1 - 30 */ if (val < 1 || val > 30) { pending_connect_free(pc); return error_invalid_arguments(conn, msg, "invalid RFCOMM channel"); } /* Add here since connect() in the first try can happen */ pending_connects = g_slist_append(pending_connects, pc); pc->channel = val; err = rfcomm_connect(pc); if (err < 0) { const char *strerr = strerror(-err); error("RFCOMM connect failed: %s(%d)", strerr, -err); pending_connects = g_slist_remove(pending_connects, pc); pending_connect_free(pc); return error_connection_attempt_failed(conn, msg, -err); }done: name_listener_add(conn, dbus_message_get_sender(msg), (name_cb_t) transaction_owner_exited, NULL); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult connect_service(DBusConnection *conn, DBusMessage *msg, void *data){ DBusError derr; const char *bda, *pattern; int devid; 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; } devid = hci_get_route(NULL); return connect_service_from_devid(conn, msg, data, devid, bda, pattern);}static DBusHandlerResult connect_service_from_adapter(DBusConnection *conn, DBusMessage *msg, void *data){ DBusError derr; const char *adapter, *bda, *pattern; int devid; dbus_error_init(&derr); if (!dbus_message_get_args(msg, &derr, DBUS_TYPE_STRING, &adapter, 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; } devid = hci_devid(adapter); return connect_service_from_devid(conn, msg, data, devid, bda, pattern);}static DBusHandlerResult disconnect_service(DBusConnection *conn, DBusMessage *msg, void *data){ DBusError derr; const char *name; int err, id; dbus_error_init(&derr); if (!dbus_message_get_args(msg, &derr, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) { error_invalid_arguments(conn, msg, derr.message); dbus_error_free(&derr); return DBUS_HANDLER_RESULT_HANDLED; } if (sscanf(name, "/dev/rfcomm%d", &id) != 1) return error_invalid_arguments(conn, msg, "invalid RFCOMM node"); err = port_remove_listener(dbus_message_get_sender(msg), name); if (err < 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, "ServiceDisconnected" , DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult cancel_connect_service(DBusConnection *conn, DBusMessage *msg, void *data){ struct pending_connect *pending; DBusMessage *reply; DBusError derr; const char *bda, *pattern; 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_does_not_exist(conn, msg, "No such connection request"); reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; pending->canceled = 1; return send_message_and_unref(conn, reply);}static void proxy_path_free(gpointer data, gpointer udata){ DBusConnection *conn = udata; const char *path = data; struct proxy *prx = NULL; /* Store/Update the proxy entries before exit */ if (dbus_connection_get_object_user_data(conn, path, (void *) &prx) && prx) { struct termios *ti; ti = (prx->type == TTY_PROXY ? &prx->proxy_ti : NULL); proxy_store(&prx->src, prx->uuid128, prx->address, NULL, prx->channel, 0, ti); } g_free(data);}static void manager_unregister(DBusConnection *conn, void *data){ char **dev; int i; if (pending_connects) { g_slist_foreach(pending_connects, (GFunc) pending_connect_free, NULL); g_slist_free(pending_connects); pending_connects = NULL; } if (proxies_paths) { g_slist_foreach(proxies_paths, proxy_path_free, conn); g_slist_free(proxies_paths); proxies_paths = NULL; } if (ports_paths) { g_slist_foreach(ports_paths, (GFunc) g_free, NULL); g_slist_free(ports_paths); ports_paths = NULL; } /* Unregister all paths in serial hierarchy */ if (!dbus_connection_list_registered(conn, SERIAL_MANAGER_PATH, &dev)) return; for (i = 0; dev[i]; i++) { char dev_path[MAX_PATH_LENGTH]; snprintf(dev_path, sizeof(dev_path), "%s/%s", SERIAL_MANAGER_PATH, dev[i]); dbus_connection_destroy_object_path(conn, dev_path); } dbus_free_string_array(dev);}static DBusMethodVTable manager_methods[] = { { "CreatePort", create_port, "ss", "s" }, { "ListPorts", list_ports, "", "as" }, { "RemovePort", remove_port, "s", "" }, { "CreateProxy", create_proxy, "ss", "s" }, { "ListProxies", list_proxies, "", "as" }, { "RemoveProxy", remove_proxy, "s", "" }, { "ConnectService", connect_service, "ss", "s" }, { "ConnectServiceFromAdapter", connect_service_from_adapter, "sss", "s" }, { "DisconnectService", disconnect_service, "s", "" }, { "CancelConnectService", cancel_connect_service, "ss", "" }, { NULL, NULL, NULL, NULL },};static DBusSignalVTable manager_signals[] = { { "PortCreated", "s" }, { "PortRemoved", "s" }, { "ProxyCreated", "s" }, { "ProxyRemoved", "s" }, { "ServiceConnected", "s" }, { "ServiceDisconnected", "s" }, { NULL, NULL }};static void parse_port(char *key, char *value, void *data){ char path[MAX_PATH_LENGTH], port_name[16], dst_addr[18], *svc; char *src_addr = data; bdaddr_t dst, src; int ch, id; memset(dst_addr, 0, sizeof(dst_addr)); if (sscanf(key,"%17s#%d", dst_addr, &id) != 2) return; if (sscanf(value,"%d:", &ch) != 1) return; svc = strchr(value, ':'); if (svc && *svc) svc++; str2ba(dst_addr, &dst); str2ba(src_addr, &src); if (rfcomm_bind(&src, &dst, id, ch) < 0) return; snprintf(port_name, sizeof(port_name), "/dev/rfcomm%d", id); if (port_register(connection, id, &src, &dst, port_name, path, svc) < 0) { rfcomm_release(id); return; } ports_paths = g_slist_append(ports_paths, g_strdup(path));}static void parse_proxy(char *key, char *value, void *data){ char uuid128[MAX_LEN_UUID_STR], tmp[3]; char *pvalue, *src_addr = data; proxy_type_t type; int ch, opts, pos; bdaddr_t src; struct termios ti; uint8_t *pti; memset(uuid128, 0, sizeof(uuid128)); ch = opts = pos = 0; if (sscanf(value,"%s %d 0x%04X %n", uuid128, &ch, &opts, &pos) != 3) return; /* Extracting name */ value += pos; pvalue = strchr(value, ':'); if (!pvalue) return; /* FIXME: currently name is not used */ *pvalue = '\0'; str2ba(src_addr, &src); type = addr2type(key); switch (type) { case TTY_PROXY: /* Extracting termios */ pvalue++; if (!pvalue || strlen(pvalue) != (2 * sizeof(ti))) return; memset(&ti, 0, sizeof(ti)); memset(tmp, 0, sizeof(tmp)); /* Converting to termios struct */ pti = (uint8_t *) &ti; for (pos = 0; pos < sizeof(ti); pos++, pvalue += 2, pti++) { memcpy(tmp, pvalue, 2); *pti = (uint8_t) strtol(tmp, NULL, 16); } proxy_tty_register(&src, uuid128, key, &ti, NULL, 0); break; case UNIX_SOCKET_PROXY: proxy_socket_register(&src, uuid128, key, NULL, 0); break; case TCP_SOCKET_PROXY: proxy_tcp_register(&src, uuid128, key, NULL, 0); break; default: return; }}static void register_stored(void){ char filename[PATH_MAX + 1]; struct dirent *de; DIR *dir; snprintf(filename, PATH_MAX, "%s", STORAGEDIR); dir = opendir(filename); if (!dir) return; while ((de = readdir(dir)) != NULL) { if (!isdigit(de->d_name[0])) continue; snprintf(filename, PATH_MAX, "%s/%s/serial", STORAGEDIR, de->d_name); textfile_foreach(filename, parse_port, de->d_name); snprintf(filename, PATH_MAX, "%s/%s/proxy", STORAGEDIR, de->d_name); textfile_foreach(filename, parse_proxy, de->d_name); } closedir(dir);}int serial_init(DBusConnection *conn){ if (rfcomm_ctl < 0) { rfcomm_ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_RFCOMM); if (rfcomm_ctl < 0) return -errno; } if (!dbus_connection_create_object_path(conn, SERIAL_MANAGER_PATH, NULL, manager_unregister)) { error("D-Bus failed to register %s path", SERIAL_MANAGER_PATH); return -1; } if (!dbus_connection_register_interface(conn, SERIAL_MANAGER_PATH, SERIAL_MANAGER_INTERFACE, manager_methods, manager_signals, NULL)) { error("Failed to register %s interface to %s", SERIAL_MANAGER_INTERFACE, SERIAL_MANAGER_PATH); dbus_connection_destroy_object_path(connection, SERIAL_MANAGER_PATH); return -1; } connection = dbus_connection_ref(conn); info("Registered manager path:%s", SERIAL_MANAGER_PATH); register_stored(); return 0;}void serial_exit(void){ dbus_connection_destroy_object_path(connection, SERIAL_MANAGER_PATH); dbus_connection_unref(connection); connection = NULL; if (rfcomm_ctl >= 0) close(rfcomm_ctl);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -