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

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 2c23ef83b0

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Jeremy Huddleston <jeremyhu@apple.com>
This commit is contained in:
Peter Hutterer 2012-04-23 10:35:53 +10:00
parent 93d6ba5b71
commit ea51e9b287
2 changed files with 133 additions and 19 deletions

View File

@ -70,27 +70,28 @@ 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;
}
if (version_compare(XIVersion.major_version, XIVersion.minor_version,
stuff->major_version, stuff->minor_version) > 0) {
major = stuff->major_version;
minor = stuff->minor_version;
pXIClient->major_version = major;
pXIClient->minor_version = minor;
}
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;

View File

@ -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;
}