[PATCH] wayland-server: Version check requests
Jason Ekstrand
jason at jlekstrand.net
Thu May 23 13:58:08 PDT 2013
On Thu, May 23, 2013 at 3:20 PM, <alexl at redhat.com> wrote:
> From: Alexander Larsson <alexl at redhat.com>
>
> If an interface has any messages and its version is larger than 1
> then we emit a method counts array which lists the number of methods
> for each version of the interface. This can be used in addition
> to the normal method_count to reject requests that the
> server doesn't support. This allows the wayland server library
> to be upgraded and still safely run oler compositors that don't
> implement the new requests.
>
> Since there is no other space in the wm_interface we add the
> method count array at the end of the events array. We then
> add some warnings to the event sending code so that we never
> accidentally trigger these events.
>
Would it possibly be better to use the upper bits of method_count (or
method_count < 0) to signal that a method_counts array is appended to
methods? This keeps methods with methods and also allows us to optionally
do the same thing with events client-side to protect clients from broken
newer-version compositors.
>
> Then we add code in the server to reject messages that are not
> supported by the server version of the object they are sent to.
> ---
> src/scanner.c | 54
> ++++++++++++++++++++++++++++++++++++++++++++++------
> src/wayland-server.c | 34 +++++++++++++++++++++++++++++++--
> 2 files changed, 80 insertions(+), 8 deletions(-)
>
> diff --git a/src/scanner.c b/src/scanner.c
> index 9c14ad3..38e7909 100644
> --- a/src/scanner.c
> +++ b/src/scanner.c
> @@ -1019,12 +1019,13 @@ emit_types(struct protocol *protocol, struct
> wl_list *message_list)
>
> static void
> emit_messages(struct wl_list *message_list,
> - struct interface *interface, const char *suffix)
> + struct interface *interface, const char *suffix,
> + int emit_method_counts)
> {
> struct message *m;
> struct arg *a;
>
> - if (wl_list_empty(message_list))
> + if (wl_list_empty(message_list) && !emit_method_counts)
> return;
>
> printf("static const struct wl_message "
> @@ -1070,13 +1071,52 @@ emit_messages(struct wl_list *message_list,
> printf("\", types + %d },\n", m->type_index);
> }
>
> + if (emit_method_counts) {
> + printf("\t{ NULL, \"\", (void *)%s_method_counts },\n",
> interface->name);
> + }
> +
> + printf("};\n\n");
> +}
> +
> +static int
> +emit_method_counts(struct wl_list *message_list,
> + struct interface *interface)
> +{
> + struct message *m;
> + int version = 1;
> + int count;
> +
> + if (wl_list_empty(message_list) || interface->version == 1)
> + return 0;
> +
> + printf("static const uint32_t "
> + "%s_method_counts[] = { ",
> + interface->name);
> +
> + count = 0;
> + wl_list_for_each(m, message_list, link) {
> + while (m->since != version) {
> + printf("%d,", count);
> + version++;
> + }
> + count++;
> + }
> +
> + while (version <= interface->version) {
> + printf("%d, ", count);
> + version++;
> + }
> +
> printf("};\n\n");
> +
> + return 1;
> }
>
> static void
> emit_code(struct protocol *protocol)
> {
> struct interface *i;
> + int has_method_counts;
>
> if (protocol->copyright)
> format_copyright(protocol->copyright);
> @@ -1101,8 +1141,10 @@ emit_code(struct protocol *protocol)
>
> wl_list_for_each(i, &protocol->interface_list, link) {
>
> - emit_messages(&i->request_list, i, "requests");
> - emit_messages(&i->event_list, i, "events");
> +
> + emit_messages(&i->request_list, i, "requests", 0);
> + has_method_counts = emit_method_counts(&i->request_list,
> i);
> + emit_messages(&i->event_list, i, "events",
> has_method_counts);
>
> printf("WL_EXPORT const struct wl_interface "
> "%s_interface = {\n"
> @@ -1115,9 +1157,9 @@ emit_code(struct protocol *protocol)
> else
> printf("\t0, NULL,\n");
>
> - if (!wl_list_empty(&i->event_list))
> + if (!wl_list_empty(&i->event_list) || has_method_counts)
> printf("\t%d, %s_events,\n",
> - wl_list_length(&i->event_list), i->name);
> + wl_list_length(&i->event_list) +
> has_method_counts, i->name);
> else
> printf("\t0, NULL,\n");
>
> diff --git a/src/wayland-server.c b/src/wayland-server.c
> index c808f6a..e94366b 100644
> --- a/src/wayland-server.c
> +++ b/src/wayland-server.c
> @@ -124,6 +124,12 @@ wl_resource_post_event(struct wl_resource *resource,
> uint32_t opcode, ...)
> struct wl_object *object = &resource->object;
> va_list ap;
>
> + if (opcode >= (uint32_t)object->interface->event_count ||
> + object->interface->events[opcode].name == NULL) {
> + wl_log ("Trying to post unsupported event\n");
> + return;
> + }
> +
> va_start(ap, opcode);
> closure = wl_closure_vmarshal(object, opcode, ap,
> &object->interface->events[opcode]);
> @@ -150,6 +156,12 @@ wl_resource_queue_event(struct wl_resource *resource,
> uint32_t opcode, ...)
> struct wl_object *object = &resource->object;
> va_list ap;
>
> + if (opcode >= (uint32_t)object->interface->event_count ||
> + object->interface->events[opcode].name == NULL) {
> + wl_log ("Trying to queue unsupported event\n");
> + return;
> + }
> +
> va_start(ap, opcode);
> closure = wl_closure_vmarshal(object, opcode, ap,
> &object->interface->events[opcode]);
> @@ -206,7 +218,8 @@ wl_client_connection_data(int fd, uint32_t mask, void
> *data)
> struct wl_closure *closure;
> const struct wl_message *message;
> uint32_t p[2];
> - int opcode, size;
> + uint32_t opcode;
> + int size;
> int len;
>
> if (mask & (WL_EVENT_ERROR | WL_EVENT_HANGUP)) {
> @@ -250,7 +263,7 @@ wl_client_connection_data(int fd, uint32_t mask, void
> *data)
> }
>
> object = &resource->object;
> - if (opcode >= object->interface->method_count) {
> + if (opcode >= (uint32_t)object->interface->method_count) {
> wl_resource_post_error(client->display_resource,
>
> WL_DISPLAY_ERROR_INVALID_METHOD,
> "invalid method %d, object
> %s@%u",
> @@ -260,6 +273,23 @@ wl_client_connection_data(int fd, uint32_t mask, void
> *data)
> break;
> }
>
> + if (object->interface->event_count > 0 &&
> +
> object->interface->events[object->interface->event_count-1].name == NULL) {
> + uint32_t *method_counts = (uint32_t *)
> +
> object->interface->events[object->interface->event_count-1].types;
> +
> + if (opcode >=
> method_counts[wl_resource_get_version (resource)]) {
> +
> wl_resource_post_error(client->display_resource,
> +
> WL_DISPLAY_ERROR_INVALID_METHOD,
> + "invalid method %d,
> object %s@%u",
> + opcode,
> +
> object->interface->name,
> + object->id);
> + break;
> + }
> + }
> +
> +
> message = &object->interface->methods[opcode];
> closure = wl_connection_demarshal(client->connection, size,
> &client->objects,
> message);
> --
> 1.8.1.4
>
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
>
Thanks,
--Jason Ekstrand
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/wayland-devel/attachments/20130523/fa0319cd/attachment-0001.html>
More information about the wayland-devel
mailing list