[PATCH 1/3 v3] wayland-server: Add API to control globals visibility

Olivier Fourdan ofourdan at redhat.com
Mon Aug 8 08:10:50 UTC 2016


Add a new API to let compositor decide whether or not a wl_global
should be advertised to the clients via wl_registry_bind() or
display_get_registry()

By using its own filter, the compositor can decide which wl_global would
be listed to clients.

Compositors can use this mechanism to hide their own private interfaces
that regular clients should not use.

Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
---
 v2: Follow-up on Jonas' comments on v1:
     Add global's data as user data in callback filter function
     Pass wl_global instead of wl_interface in callback filter function
     Add wl_global_get_interface() to retrieve the wl_interface from the
     given wl_global
     Post an error if a client tries to bind a global which is filtered
     out.
 v3: Follow-up on Jonas' comments on v2:
     Separate from the other wl_global and test additions
     Add its own user data to the global filter
     Rephrase the API doc
     Other few small changes

 src/wayland-server-core.h | 10 ++++++++
 src/wayland-server.c      | 62 +++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 67 insertions(+), 5 deletions(-)

diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h
index ad1292f..b70d85f 100644
--- a/src/wayland-server-core.h
+++ b/src/wayland-server-core.h
@@ -28,6 +28,7 @@
 
 #include <sys/types.h>
 #include <stdint.h>
+#include <stdbool.h>
 #include "wayland-util.h"
 #include "wayland-version.h"
 
@@ -164,6 +165,15 @@ wl_global_create(struct wl_display *display,
 void
 wl_global_destroy(struct wl_global *global);
 
+typedef bool (*wl_display_filter_global_func_t)(const struct wl_client *client,
+						const struct wl_global *global,
+						void *data);
+
+void
+wl_display_set_filter_global(struct wl_display *display,
+			     wl_display_filter_global_func_t filter,
+			     void *data);
+
 struct wl_client *
 wl_client_create(struct wl_display *display, int fd);
 
diff --git a/src/wayland-server.c b/src/wayland-server.c
index 19aa2e8..480af23 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -98,6 +98,9 @@ struct wl_display {
 	struct wl_signal destroy_signal;
 
 	struct wl_array additional_shm_formats;
+
+	wl_display_filter_global_func_t global_filter;
+	void *global_filter_data;
 };
 
 struct wl_global {
@@ -714,6 +717,16 @@ wl_client_destroy(struct wl_client *client)
 	free(client);
 }
 
+static bool
+filter_global(const struct wl_client *client,
+	      const struct wl_global *global)
+{
+	struct wl_display *display = client->display;
+
+	return (display->global_filter == NULL ||
+		display->global_filter(client, global, display->global_filter_data));
+}
+
 static void
 registry_bind(struct wl_client *client,
 	      struct wl_resource *resource, uint32_t name,
@@ -740,6 +753,10 @@ registry_bind(struct wl_client *client,
 				       WL_DISPLAY_ERROR_INVALID_OBJECT,
 				       "invalid version for global %s (%d): have %d, wanted %d",
 				       interface, name, global->version, version);
+	else if (!filter_global(client, global))
+		wl_resource_post_error(resource,
+				       WL_DISPLAY_ERROR_INVALID_OBJECT,
+				       "invalid global %s (%d)", interface, name);
 	else
 		global->bind(client, global->data, version, id);
 }
@@ -795,11 +812,12 @@ display_get_registry(struct wl_client *client,
 		       &registry_resource->link);
 
 	wl_list_for_each(global, &display->global_list, link)
-		wl_resource_post_event(registry_resource,
-				       WL_REGISTRY_GLOBAL,
-				       global->name,
-				       global->interface->name,
-				       global->version);
+		if (filter_global(client, global))
+			wl_resource_post_event(registry_resource,
+					       WL_REGISTRY_GLOBAL,
+					       global->name,
+					       global->interface->name,
+					       global->version);
 }
 
 static const struct wl_display_interface display_interface = {
@@ -868,6 +886,9 @@ wl_display_create(void)
 	display->id = 1;
 	display->serial = 0;
 
+	display->global_filter = NULL;
+	display->global_filter_data = NULL;
+
 	wl_array_init(&display->additional_shm_formats);
 
 	return display;
@@ -940,6 +961,37 @@ wl_display_destroy(struct wl_display *display)
 	free(display);
 }
 
+/** Set a filter function for global objects
+ *
+ * \param display The Wayland display object.
+ * \param filter  The global filter funtion.
+ * \param data User data to be associated with the global filter.
+ * \return None.
+ *
+ * Set a filter for the wl_display to advertise or hide global objects
+ * to clients.
+ * The set filter will be used during wl_global advertisment to
+ * determine whether a global object should be advertised to a
+ * given client, and during wl_global binding to determine whether
+ * a given client should be allowed to bind to a global.
+ *
+ * Clients that try to bind to a global that was filtered out will
+ * have an error raised.
+ *
+ * Setting the filter NULL will result in all globals being
+ * advertised to all clients. The default is no filter.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT void
+wl_display_set_filter_global(struct wl_display *display,
+			     wl_display_filter_global_func_t filter,
+			     void *data)
+{
+	display->global_filter = filter;
+	display->global_filter_data = data;
+}
+
 WL_EXPORT struct wl_global *
 wl_global_create(struct wl_display *display,
 		 const struct wl_interface *interface, int version,
-- 
2.7.4



More information about the wayland-devel mailing list