⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 manager.c

📁 Linux的蓝牙操作工具。配合bluez-lib使用
💻 C
📖 第 1 页 / 共 4 页
字号:
		 * 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 + -