(!1601) Xext: xres: ProcXResQueryClientIds() collect reply in one buffer

In order to allow simplifying the reply send path, collect the reply
fragments into one buffer, instead of arbitrary number of WriteToClient()
calls. This also makes it much easier for potentially new purely packet-based
transports which (eg. binder) that would need their own stream parsing logic.

This xres function is an exceptionally hard case, since payload is constructed
step by step, and it's size only known when finished. The current way of the
fragment handling still has lots of room for improvement (eg. using very small
number of allocations), but leaving this for later exercise.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
This commit is contained in:
Enrico Weigelt, metux IT consult 2024-07-24 16:39:49 +02:00
parent 4c42242339
commit ca62578352

View File

@ -112,21 +112,6 @@ AddFragment(struct xorg_list *frags, int bytes)
} }
} }
/** @brief Sends all fragments in the list to the client. Does not
free anything.
@param client The client to send the fragments to
@param frags The head of the list of fragments
*/
static void
WriteFragmentsToClient(ClientPtr client, struct xorg_list *frags)
{
FragmentList *it;
xorg_list_for_each_entry(it, frags, l) {
WriteToClient(client, it->bytes, (char*) it + sizeof(*it));
}
}
/** @brief Frees a list of fragments. Does not free() root node. /** @brief Frees a list of fragments. Does not free() root node.
@param frags The head of the list of fragments @param frags The head of the list of fragments
@ -564,7 +549,18 @@ ProcXResQueryClientIds (ClientPtr client)
rc = ConstructClientIds(client, stuff->numSpecs, specs, &ctx); rc = ConstructClientIds(client, stuff->numSpecs, specs, &ctx);
if (rc == Success) { if (rc == Success) {
assert((ctx.resultBytes & 3) == 0); char *buf = calloc(1, ctx.resultBytes);
if (!buf) {
rc = BadAlloc;
goto out;
}
char *walk = buf;
FragmentList *it;
xorg_list_for_each_entry(it, &ctx.response, l) {
memcpy(walk, FRAGMENT_DATA(it), it->bytes);
walk += it->bytes;
}
xXResQueryClientIdsReply rep = { xXResQueryClientIdsReply rep = {
.type = X_Reply, .type = X_Reply,
@ -580,9 +576,11 @@ ProcXResQueryClientIds (ClientPtr client)
} }
WriteToClient(client, sizeof(rep), &rep); WriteToClient(client, sizeof(rep), &rep);
WriteFragmentsToClient(client, &ctx.response); WriteToClient(client, ctx.resultBytes, buf);
free(buf);
} }
out:
DestroyConstructClientIdCtx(&ctx); DestroyConstructClientIdCtx(&ctx);
return rc; return rc;
@ -964,10 +962,24 @@ ProcXResQueryResourceBytes (ClientPtr client)
SwapXResQueryResourceBytes(&ctx.response); SwapXResQueryResourceBytes(&ctx.response);
} }
WriteToClient(client, sizeof(rep), &rep); char *buf = calloc(1, ctx.resultBytes);
WriteFragmentsToClient(client, &ctx.response); if (!buf) {
rc = BadAlloc;
goto out;
} }
char *walk = buf;
FragmentList *it;
xorg_list_for_each_entry(it, &ctx.response, l) {
memcpy(walk, FRAGMENT_DATA(it), it->bytes);
walk += it->bytes;
}
WriteToClient(client, sizeof(rep), &rep);
WriteToClient(client, ctx.resultBytes, buf);
free(buf);
}
out:
DestroyConstructResourceBytesCtx(&ctx); DestroyConstructResourceBytesCtx(&ctx);
return rc; return rc;