[PATCH] Xi: return BadValue on XIQueryVersion if the version is less than first call

Peter Hutterer peter.hutterer at who-t.net
Sun Apr 22 20:29:59 PDT 2012


Clients that use plugin systems may require multiple calls to
XIQueryVersion from different plugins. The current error handling requires
client-side synchronisation of version numbers.

The first call to XIQueryVersion defines the server behaviour. Once cached,
always return that version number to any clients. Unless a client requests a
version lower than the first defined one, then a BadValue must be returned
to be protocol-compatible.

Introduced in 2c23ef83b0e03e163aeeb06133538606886f4e9c

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 Xi/xiqueryversion.c                |   41 ++++++-------
 test/xi2/protocol-xiqueryversion.c |  113 ++++++++++++++++++++++++++++++++++++
 2 files changed, 134 insertions(+), 20 deletions(-)

diff --git a/Xi/xiqueryversion.c b/Xi/xiqueryversion.c
index fc0ca75..6081c41 100644
--- a/Xi/xiqueryversion.c
+++ b/Xi/xiqueryversion.c
@@ -70,28 +70,29 @@ ProcXIQueryVersion(ClientPtr client)
 
     pXIClient = dixLookupPrivate(&client->devPrivates, XIClientPrivateKey);
 
-    if (pXIClient->major_version &&
-           (stuff->major_version != pXIClient->major_version ||
-            stuff->minor_version != pXIClient->minor_version))
-    {
-        client->errorValue = stuff->major_version;
-        return BadValue;
+    if (pXIClient->major_version) {
+        if (version_compare(stuff->major_version, stuff->minor_version,
+                            pXIClient->major_version, pXIClient->minor_version) < 0) {
+            client->errorValue = stuff->major_version;
+            return BadValue;
+        }
+        major = pXIClient->major_version;
+        minor = pXIClient->minor_version;
+    } else {
+        if (version_compare(XIVersion.major_version, XIVersion.minor_version,
+                    stuff->major_version, stuff->minor_version) > 0) {
+            major = stuff->major_version;
+            minor = stuff->minor_version;
+        }
+        else {
+            major = XIVersion.major_version;
+            minor = XIVersion.minor_version;
+        }
+
+        pXIClient->major_version = major;
+        pXIClient->minor_version = minor;
     }
 
-
-    if (version_compare(XIVersion.major_version, XIVersion.minor_version,
-                        stuff->major_version, stuff->minor_version) > 0) {
-        major = stuff->major_version;
-        minor = stuff->minor_version;
-    }
-    else {
-        major = XIVersion.major_version;
-        minor = XIVersion.minor_version;
-    }
-
-    pXIClient->major_version = major;
-    pXIClient->minor_version = minor;
-
     memset(&rep, 0, sizeof(xXIQueryVersionReply));
     rep.repType = X_Reply;
     rep.RepType = X_XIQueryVersion;
diff --git a/test/xi2/protocol-xiqueryversion.c b/test/xi2/protocol-xiqueryversion.c
index 2552307..1347e86 100644
--- a/test/xi2/protocol-xiqueryversion.c
+++ b/test/xi2/protocol-xiqueryversion.c
@@ -54,6 +54,8 @@ struct test_data {
     int minor_client;
     int major_server;
     int minor_server;
+    int major_cached;
+    int minor_cached;
 };
 
 static void
@@ -82,6 +84,24 @@ reply_XIQueryVersion(ClientPtr client, int len, char *data, void *userdata)
     assert((sver > cver) ? ver == cver : ver == sver);
 }
 
+static void
+reply_XIQueryVersion_multiple(ClientPtr client, int len, char *data, void *userdata)
+{
+    xXIQueryVersionReply *rep = (xXIQueryVersionReply *) data;
+    struct test_data *versions = (struct test_data *) userdata;
+
+    reply_check_defaults(rep, len, XIQueryVersion);
+    assert(rep->length == 0);
+
+    if (versions->major_cached == -1) {
+        versions->major_cached = rep->major_version;
+        versions->minor_cached = rep->minor_version;
+    }
+
+    assert(versions->major_cached == rep->major_version);
+    assert(versions->minor_cached == rep->minor_version);
+}
+
 /**
  * Run a single test with server version smaj.smin and client
  * version cmaj.cmin. Verify that return code is equal to 'error'.
@@ -173,12 +193,105 @@ test_XIQueryVersion(void)
     reply_handler = NULL;
 }
 
+
+static void
+test_XIQueryVersion_multiple(void)
+{
+    xXIQueryVersionReq request;
+    ClientRec client;
+    struct test_data versions;
+    int rc;
+
+    request_init(&request, XIQueryVersion);
+    client = init_client(request.length, &request);
+
+    /* Change the server to support 2.2 */
+    XIVersion.major_version = 2;
+    XIVersion.minor_version = 2;
+
+    reply_handler = reply_XIQueryVersion_multiple;
+    userdata = (void *) &versions;
+
+    /* run 1 */
+    versions.major_cached = -1;
+    versions.minor_cached = -1;
+
+    /* client is lower than server, noncached */
+    request.major_version = 2;
+    request.minor_version = 1;
+    rc = ProcXIQueryVersion(&client);
+    assert(rc == Success);
+
+    /* client is higher than server, cached */
+    request.major_version = 2;
+    request.minor_version = 3;
+    rc = ProcXIQueryVersion(&client);
+    assert(rc == Success);
+
+    /* client is equal, cached */
+    request.major_version = 2;
+    request.minor_version = 2;
+    rc = ProcXIQueryVersion(&client);
+    assert(rc == Success);
+
+    /* client is low than cached */
+    request.major_version = 2;
+    request.minor_version = 0;
+    rc = ProcXIQueryVersion(&client);
+    assert(rc == BadValue);
+
+    /* run 2 */
+    client = init_client(request.length, &request);
+    XIVersion.major_version = 2;
+    XIVersion.minor_version = 2;
+    versions.major_cached = -1;
+    versions.minor_cached = -1;
+
+    request.major_version = 2;
+    request.minor_version = 2;
+    rc = ProcXIQueryVersion(&client);
+    assert(rc == Success);
+
+    request.major_version = 2;
+    request.minor_version = 3;
+    rc = ProcXIQueryVersion(&client);
+    assert(rc == Success);
+
+    request.major_version = 2;
+    request.minor_version = 1;
+    rc = ProcXIQueryVersion(&client);
+    assert(rc == BadValue);
+
+    /* run 3 */
+    client = init_client(request.length, &request);
+    XIVersion.major_version = 2;
+    XIVersion.minor_version = 2;
+    versions.major_cached = -1;
+    versions.minor_cached = -1;
+
+    request.major_version = 2;
+    request.minor_version = 3;
+    rc = ProcXIQueryVersion(&client);
+    assert(rc == Success);
+
+    request.major_version = 2;
+    request.minor_version = 2;
+    rc = ProcXIQueryVersion(&client);
+    assert(rc == Success);
+
+    request.major_version = 2;
+    request.minor_version = 1;
+    rc = ProcXIQueryVersion(&client);
+    assert(rc == BadValue);
+}
+
 int
 main(int argc, char **argv)
 {
     init_simple();
 
     test_XIQueryVersion();
+    test_XIQueryVersion_multiple();
 
     return 0;
 }
-- 
1.7.10



More information about the xorg-devel mailing list