diff options
| -rw-r--r-- | network/manager.c | 322 | 
1 files changed, 251 insertions, 71 deletions
| diff --git a/network/manager.c b/network/manager.c index a8b9974f..58c335bb 100644 --- a/network/manager.c +++ b/network/manager.c @@ -51,40 +51,28 @@ struct manager {  	GSList *connections;	/* Network registered connections paths */  }; +struct pending_reply { +	DBusConnection *conn; +	DBusMessage *msg; +	struct manager *mgr; +	uint16_t id; +	char *addr; +	char *path; +	char *adapter_path; +}; +  static DBusConnection *connection = NULL; -static DBusHandlerResult list_paths(DBusConnection *conn, DBusMessage *msg, -					GSList *list) +static void pending_reply_free(struct pending_reply *pr)  { -	DBusMessage *reply; -	DBusMessageIter iter; -	DBusMessageIter array_iter; - -	reply = dbus_message_new_method_return(msg); -	if (!reply) -		return DBUS_HANDLER_RESULT_NEED_MEMORY; +	if (pr->addr) +		g_free(pr->addr); -	dbus_message_iter_init_append(reply, &iter); -	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, -				DBUS_TYPE_STRING_AS_STRING, &array_iter); +	if (pr->path) +		g_free(pr->path); -	for (; list; list = list->next) { -		dbus_message_iter_append_basic(&array_iter, -						DBUS_TYPE_STRING, -						&list->data); -	} - -	dbus_message_iter_close_container(&iter, &array_iter); - -	return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult list_servers(DBusConnection *conn, DBusMessage *msg, -					void *data) -{ -	struct manager *mgr = data; - -	return list_paths(conn, msg, mgr->servers); +	if (pr->adapter_path) +		g_free(pr->adapter_path);  }  static DBusHandlerResult create_path(DBusConnection *conn, @@ -116,44 +104,29 @@ static DBusHandlerResult create_path(DBusConnection *conn,  	return send_message_and_unref(conn, reply);  } -static DBusHandlerResult create_server(DBusConnection *conn, -					DBusMessage *msg, void *data) +static DBusHandlerResult list_paths(DBusConnection *conn, DBusMessage *msg, +					GSList *list)  { -	struct manager *mgr = data; -	DBusError derr; -	const char *str; -	char *path; -	uint16_t id; - -	dbus_error_init(&derr); -	if (!dbus_message_get_args(msg, &derr, -				DBUS_TYPE_STRING, &str, -				DBUS_TYPE_INVALID)) { -		err_invalid_args(conn, msg, derr.message); -		dbus_error_free(&derr); -		return DBUS_HANDLER_RESULT_HANDLED; -	} - -	id = bnep_service_id(str); -	if ((id != BNEP_SVC_GN) && (id != BNEP_SVC_NAP)) -		return err_invalid_args(conn, msg, "Not supported"); +	DBusMessage *reply; +	DBusMessageIter iter; +	DBusMessageIter array_iter; -	path = g_new0(char, 32); -	snprintf(path, 32, NETWORK_PATH "/server/%s", bnep_name(id)); +	reply = dbus_message_new_method_return(msg); +	if (!reply) +		return DBUS_HANDLER_RESULT_NEED_MEMORY; -	/* Path already registered */ -	if (g_slist_find_custom(mgr->servers, path, (GCompareFunc) strcmp)) -		return create_path(conn, msg, path, NULL); /* Return already exist error */ +	dbus_message_iter_init_append(reply, &iter); +	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, +				DBUS_TYPE_STRING_AS_STRING, &array_iter); -	if (server_register(conn, path, id) < 0) { -		err_failed(conn, msg, "D-Bus path registration failed"); -		g_free(path); -		return DBUS_HANDLER_RESULT_HANDLED; +	for (; list; list = list->next) { +		dbus_message_iter_append_basic(&array_iter, +						DBUS_TYPE_STRING, +						&list->data);  	} +	dbus_message_iter_close_container(&iter, &array_iter); -	mgr->servers = g_slist_append(mgr->servers, g_strdup(path)); - -	return create_path(conn, msg, path, "ServerCreated"); +	return send_message_and_unref(conn, reply);  }  static DBusHandlerResult remove_path(DBusConnection *conn, @@ -200,6 +173,206 @@ static DBusHandlerResult remove_path(DBusConnection *conn,  	return send_message_and_unref(conn, reply);  } +static void pan_record_reply(DBusPendingCall *call, void *data) +{ +	struct pending_reply *pr = data; +	DBusMessage *reply = dbus_pending_call_steal_reply(call); +	DBusError derr; +	int len; +	uint8_t *rec_bin; + +	dbus_error_init(&derr); +	if (dbus_set_error_from_message(&derr, reply)) { +		if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed")) +			err_connection_failed(pr->conn, pr->msg, derr.message); +		else +			err_not_supported(pr->conn, pr->msg); + +		error("GetRemoteServiceRecord failed: %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)) { +		err_not_supported(pr->conn, pr->msg); +		error("%s: %s", derr.name, derr.message); +		goto fail; +	} + +	if (len == 0) { +		err_not_supported(pr->conn, pr->msg); +		error("Invalid PAN service record length"); +		goto fail; +	} + + +	if (connection_register(pr->conn, pr->path, pr->addr, pr->id) == -1) { +		err_failed(pr->conn, pr->msg, "D-Bus path registration failed"); +		goto fail; +	} + +	pr->mgr->connections = g_slist_append(pr->mgr->connections, +						g_strdup(pr->path)); + +	create_path(pr->conn, pr->msg, g_strdup (pr->path), "ConnectionCreated"); +fail: +	dbus_error_free(&derr); +	pending_reply_free(pr); +	dbus_message_unref(reply); +	dbus_pending_call_unref(call); +} + +static int get_record(struct pending_reply *pr, uint32_t handle, +					DBusPendingCallNotifyFunction cb) +{ +	DBusMessage *msg; +	DBusPendingCall *pending; + +	msg = dbus_message_new_method_call("org.bluez", pr->adapter_path, +			"org.bluez.Adapter", "GetRemoteServiceRecord"); +	if (!msg) +		return -1; + +	dbus_message_append_args(msg, +			DBUS_TYPE_STRING, &pr->addr, +			DBUS_TYPE_UINT32, &handle, +			DBUS_TYPE_INVALID); + +	if (dbus_connection_send_with_reply(pr->conn, msg, &pending, -1) == FALSE) { +		error("Can't send D-Bus message."); +		return -1; +	} + +	dbus_pending_call_set_notify(pending, cb, pr, NULL); +	dbus_message_unref(msg); + +	return 0; +} + +static void pan_handle_reply(DBusPendingCall *call, void *data) +{ +	struct pending_reply *pr = data; +	DBusMessage *reply = dbus_pending_call_steal_reply(call); +	DBusError derr; +	uint32_t *phandle; +	int len; + +	dbus_error_init(&derr); +	if (dbus_set_error_from_message(&derr, reply)) { +		if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed")) +			err_connection_failed(pr->conn, pr->msg, derr.message); +		else +			err_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)) { +		err_not_supported(pr->conn, pr->msg); +		error("%s: %s", derr.name, derr.message); +		goto fail; +	} + +	if (!len) { +		err_not_supported(pr->conn, pr->msg); +		goto fail; +	} + +	if (get_record(pr, *phandle, pan_record_reply) < 0) { +		err_not_supported(pr->conn, pr->msg); +		goto fail; +	} + +	dbus_message_unref(reply); +	dbus_pending_call_unref(call); +	return; +fail: +	dbus_error_free(&derr); +	pending_reply_free(pr); +} + +static int get_handles(struct pending_reply *pr, DBusPendingCallNotifyFunction cb) +{ +	DBusMessage *msg; +	DBusPendingCall *pending; +	const char *uuid; + +	msg = dbus_message_new_method_call("org.bluez", pr->adapter_path, +			"org.bluez.Adapter", "GetRemoteServiceHandles"); +	if (!msg) +		return -1; + +	uuid = bnep_uuid(pr->id); +	dbus_message_append_args(msg, +			DBUS_TYPE_STRING, &pr->addr, +			DBUS_TYPE_STRING, &uuid, +			DBUS_TYPE_INVALID); + +	if (dbus_connection_send_with_reply(pr->conn, msg, &pending, -1) == FALSE) { +		error("Can't send D-Bus message."); +		return -1; +	} + +	dbus_pending_call_set_notify(pending, cb, pr, NULL); +	dbus_message_unref(msg); + +	return 0; +} + +static DBusHandlerResult list_servers(DBusConnection *conn, DBusMessage *msg, +					void *data) +{ +	struct manager *mgr = data; + +	return list_paths(conn, msg, mgr->servers); +} + +static DBusHandlerResult create_server(DBusConnection *conn, +					DBusMessage *msg, void *data) +{ +	struct manager *mgr = data; +	DBusError derr; +	const char *str; +	char *path; +	int id; + +	dbus_error_init(&derr); +	if (!dbus_message_get_args(msg, &derr, +				DBUS_TYPE_STRING, &str, +				DBUS_TYPE_INVALID)) { +		err_invalid_args(conn, msg, derr.message); +		dbus_error_free(&derr); +		return DBUS_HANDLER_RESULT_HANDLED; +	} + +	id = bnep_service_id(str); +	if ((id != BNEP_SVC_GN) && (id != BNEP_SVC_NAP)) +		return err_invalid_args(conn, msg, "Not supported"); + +	path = g_new0(char, 32); +	snprintf(path, 32, NETWORK_PATH "/server/%X", id); + +	/* Path already registered */ +	if (g_slist_find_custom(mgr->servers, path, (GCompareFunc) strcmp)) +		return create_path(conn, msg, path, NULL); /* Return already exist error */ + +	/* FIXME: define which type should be used -- string/uuid str/uui128 */ +	if (server_register(conn, path, id) == -1) { +		err_failed(conn, msg, "D-Bus path registration failed"); +		g_free(path); +		return DBUS_HANDLER_RESULT_HANDLED; +	} + +	mgr->servers = g_slist_append(mgr->servers, g_strdup(path)); + +	return create_path(conn, msg, path, "ServerCreated"); +} +  static DBusHandlerResult remove_server(DBusConnection *conn,  					DBusMessage *msg, void *data)  { @@ -220,11 +393,12 @@ static DBusHandlerResult create_connection(DBusConnection *conn,  						DBusMessage *msg, void *data)  {  	struct manager *mgr = data; +	struct pending_reply *pr;  	static int uid = 0;  	DBusError derr; +	char src_addr[18];  	const char *addr;  	const char *str; -	char *path;  	uint16_t id;  	dbus_error_init(&derr); @@ -241,18 +415,24 @@ static DBusHandlerResult create_connection(DBusConnection *conn,  	if ((id != BNEP_SVC_GN) && (id != BNEP_SVC_NAP))  		return err_invalid_args(conn, msg, "Not supported"); -	path = g_new0(char, 32); -	snprintf(path, 32, NETWORK_PATH "/connection%d", uid++); - -	if (connection_register(conn, path, addr, id) == -1) { +	pr = g_new(struct pending_reply, 1); +	pr->conn = conn; +	pr->msg = dbus_message_ref(msg); +	pr->mgr = mgr; +	pr->addr = g_strdup(addr); +	pr->id = id; +	pr->path = g_new0(char, 48); +	snprintf(pr->path, 48, NETWORK_PATH "/connection%d", uid++); +	ba2str(&mgr->src, src_addr); +	pr->adapter_path = g_new0(char, 32); +	snprintf(pr->adapter_path , 32, "/org/bluez/hci%d", hci_devid(src_addr)); + +	if (get_handles(pr, pan_handle_reply) < 0) {  		err_failed(conn, msg, "D-Bus path registration failed"); -		g_free(path); -		return DBUS_HANDLER_RESULT_HANDLED; +		pending_reply_free(pr);  	} -	mgr->connections = g_slist_append(mgr->connections, g_strdup(path)); - -	return create_path(conn, msg, path, "ConnectionCreated"); +	return DBUS_HANDLER_RESULT_HANDLED;  }  static DBusHandlerResult remove_connection(DBusConnection *conn, | 
