<div dir="ltr"><div class="gmail_extra"><br><div class="gmail_quote">On Thu, May 23, 2013 at 3:20 PM, <span dir="ltr"><<a href="mailto:alexl@redhat.com" target="_blank">alexl@redhat.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
From: Alexander Larsson <<a href="mailto:alexl@redhat.com">alexl@redhat.com</a>><br>
<br>
If an interface has any messages and its version is larger than 1<br>
then we emit a method counts array which lists the number of methods<br>
for each version of the interface. This can be used in addition<br>
to the normal method_count to reject requests that the<br>
server doesn't support. This allows the wayland server library<br>
to be upgraded and still safely run oler compositors that don't<br>
implement the new requests.<br>
<br>
Since there is no other space in the wm_interface we add the<br>
method count array at the end of the events array. We then<br>
add some warnings to the event sending code so that we never<br>
accidentally trigger these events.<br></blockquote><div><br></div><div>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.<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Then we add code in the server to reject messages that are not<br>
supported by the server version of the object they are sent to.<br>
---<br>
src/scanner.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++------<br>
src/wayland-server.c | 34 +++++++++++++++++++++++++++++++--<br>
2 files changed, 80 insertions(+), 8 deletions(-)<br>
<br>
diff --git a/src/scanner.c b/src/scanner.c<br>
index 9c14ad3..38e7909 100644<br>
--- a/src/scanner.c<br>
+++ b/src/scanner.c<br>
@@ -1019,12 +1019,13 @@ emit_types(struct protocol *protocol, struct wl_list *message_list)<br>
<br>
static void<br>
emit_messages(struct wl_list *message_list,<br>
- struct interface *interface, const char *suffix)<br>
+ struct interface *interface, const char *suffix,<br>
+ int emit_method_counts)<br>
{<br>
struct message *m;<br>
struct arg *a;<br>
<br>
- if (wl_list_empty(message_list))<br>
+ if (wl_list_empty(message_list) && !emit_method_counts)<br>
return;<br>
<br>
printf("static const struct wl_message "<br>
@@ -1070,13 +1071,52 @@ emit_messages(struct wl_list *message_list,<br>
printf("\", types + %d },\n", m->type_index);<br>
}<br>
<br>
+ if (emit_method_counts) {<br>
+ printf("\t{ NULL, \"\", (void *)%s_method_counts },\n", interface->name);<br>
+ }<br>
+<br>
+ printf("};\n\n");<br>
+}<br>
+<br>
+static int<br>
+emit_method_counts(struct wl_list *message_list,<br>
+ struct interface *interface)<br>
+{<br>
+ struct message *m;<br>
+ int version = 1;<br>
+ int count;<br>
+<br>
+ if (wl_list_empty(message_list) || interface->version == 1)<br>
+ return 0;<br>
+<br>
+ printf("static const uint32_t "<br>
+ "%s_method_counts[] = { ",<br>
+ interface->name);<br>
+<br>
+ count = 0;<br>
+ wl_list_for_each(m, message_list, link) {<br>
+ while (m->since != version) {<br>
+ printf("%d,", count);<br>
+ version++;<br>
+ }<br>
+ count++;<br>
+ }<br>
+<br>
+ while (version <= interface->version) {<br>
+ printf("%d, ", count);<br>
+ version++;<br>
+ }<br>
+<br>
printf("};\n\n");<br>
+<br>
+ return 1;<br>
}<br>
<br>
static void<br>
emit_code(struct protocol *protocol)<br>
{<br>
struct interface *i;<br>
+ int has_method_counts;<br>
<br>
if (protocol->copyright)<br>
format_copyright(protocol->copyright);<br>
@@ -1101,8 +1141,10 @@ emit_code(struct protocol *protocol)<br>
<br>
wl_list_for_each(i, &protocol->interface_list, link) {<br>
<br>
- emit_messages(&i->request_list, i, "requests");<br>
- emit_messages(&i->event_list, i, "events");<br>
+<br>
+ emit_messages(&i->request_list, i, "requests", 0);<br>
+ has_method_counts = emit_method_counts(&i->request_list, i);<br>
+ emit_messages(&i->event_list, i, "events", has_method_counts);<br>
<br>
printf("WL_EXPORT const struct wl_interface "<br>
"%s_interface = {\n"<br>
@@ -1115,9 +1157,9 @@ emit_code(struct protocol *protocol)<br>
else<br>
printf("\t0, NULL,\n");<br>
<br>
- if (!wl_list_empty(&i->event_list))<br>
+ if (!wl_list_empty(&i->event_list) || has_method_counts)<br>
printf("\t%d, %s_events,\n",<br>
- wl_list_length(&i->event_list), i->name);<br>
+ wl_list_length(&i->event_list) + has_method_counts, i->name);<br>
else<br>
printf("\t0, NULL,\n");<br>
<br>
diff --git a/src/wayland-server.c b/src/wayland-server.c<br>
index c808f6a..e94366b 100644<br>
--- a/src/wayland-server.c<br>
+++ b/src/wayland-server.c<br>
@@ -124,6 +124,12 @@ wl_resource_post_event(struct wl_resource *resource, uint32_t opcode, ...)<br>
struct wl_object *object = &resource->object;<br>
va_list ap;<br>
<br>
+ if (opcode >= (uint32_t)object->interface->event_count ||<br>
+ object->interface->events[opcode].name == NULL) {<br>
+ wl_log ("Trying to post unsupported event\n");<br>
+ return;<br>
+ }<br>
+<br>
va_start(ap, opcode);<br>
closure = wl_closure_vmarshal(object, opcode, ap,<br>
&object->interface->events[opcode]);<br>
@@ -150,6 +156,12 @@ wl_resource_queue_event(struct wl_resource *resource, uint32_t opcode, ...)<br>
struct wl_object *object = &resource->object;<br>
va_list ap;<br>
<br>
+ if (opcode >= (uint32_t)object->interface->event_count ||<br>
+ object->interface->events[opcode].name == NULL) {<br>
+ wl_log ("Trying to queue unsupported event\n");<br>
+ return;<br>
+ }<br>
+<br>
va_start(ap, opcode);<br>
closure = wl_closure_vmarshal(object, opcode, ap,<br>
&object->interface->events[opcode]);<br>
@@ -206,7 +218,8 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)<br>
struct wl_closure *closure;<br>
const struct wl_message *message;<br>
uint32_t p[2];<br>
- int opcode, size;<br>
+ uint32_t opcode;<br>
+ int size;<br>
int len;<br>
<br>
if (mask & (WL_EVENT_ERROR | WL_EVENT_HANGUP)) {<br>
@@ -250,7 +263,7 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)<br>
}<br>
<br>
object = &resource->object;<br>
- if (opcode >= object->interface->method_count) {<br>
+ if (opcode >= (uint32_t)object->interface->method_count) {<br>
wl_resource_post_error(client->display_resource,<br>
WL_DISPLAY_ERROR_INVALID_METHOD,<br>
"invalid method %d, object %s@%u",<br>
@@ -260,6 +273,23 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)<br>
break;<br>
}<br>
<br>
+ if (object->interface->event_count > 0 &&<br>
+ object->interface->events[object->interface->event_count-1].name == NULL) {<br>
+ uint32_t *method_counts = (uint32_t *)<br>
+ object->interface->events[object->interface->event_count-1].types;<br>
+<br>
+ if (opcode >= method_counts[wl_resource_get_version (resource)]) {<br>
+ wl_resource_post_error(client->display_resource,<br>
+ WL_DISPLAY_ERROR_INVALID_METHOD,<br>
+ "invalid method %d, object %s@%u",<br>
+ opcode,<br>
+ object->interface->name,<br>
+ object->id);<br>
+ break;<br>
+ }<br>
+ }<br>
+<br>
+<br>
message = &object->interface->methods[opcode];<br>
closure = wl_connection_demarshal(client->connection, size,<br>
&client->objects, message);<br>
<span class="HOEnZb"><font color="#888888">--<br>
1.8.1.4<br>
<br>
_______________________________________________<br>
wayland-devel mailing list<br>
<a href="mailto:wayland-devel@lists.freedesktop.org">wayland-devel@lists.freedesktop.org</a><br>
<a href="http://lists.freedesktop.org/mailman/listinfo/wayland-devel" target="_blank">http://lists.freedesktop.org/mailman/listinfo/wayland-devel</a><br>
</font></span></blockquote></div><br></div><div class="gmail_extra">Thanks,<br></div><div class="gmail_extra">--Jason Ekstrand<br></div></div>