ipc: strip machinery no peer uses; keep client state in one Keyreq

ipc.c: an AF_UNIX nonblocking connect completes at once or fails with
EAGAIN, so the EINPROGRESS/poll/SO_ERROR path and the fcntl juggling
were dead; the deadline plumbing checked a clock that cannot fail and
re-tested the deadline before every transfer although only waitfd
blocks; readfield's truncation and discard loop served the unit test,
since every caller owns char[Ipcfieldmax+1]; NULL-argument checks on
in-tree encoders are gone (peer validation stays). The primary key frame
is Ipckey, not 'legacy'; ipckeysym names the keysym mapping.

srv.c: the per-connection capability and caret already lived in the
persistent Keyreq; the mirror locals and 'negotiated' flag guarded a
protocol rule no client relied on. proccreate never fails in libthread.

gtk: focus-out no longer round-trips a reset before closing the socket
that releases the engine; the caret dedup compares the packed frame;
srvconnect's preedit no-ops and the insimple flag are gone.
This commit is contained in:
2026-08-16 15:53:08 +09:00
parent 43b469f70b
commit eb0f88f764
11 changed files with 205 additions and 394 deletions

View File

@@ -48,13 +48,13 @@ ipc_masks_modifiers(struct ct *t)
CT_CHECK(t, ipcreqreset(buf));
/* Frontends share one keysym and modifier mapping. */
CT_EQ_UINT(t, 'a', ipckey('a', 'a'));
CT_EQ_UINT(t, '1', ipckey(0xffb1, '1')); /* KP_1 */
CT_EQ_UINT(t, Kret, ipckey(0xff0d, '\r'));
CT_EQ_UINT(t, Kback, ipckey(0xff08, 8));
CT_EQ_UINT(t, Kspec + 0xff, ipckey(0xffff, 0x7f)); /* Delete */
CT_EQ_UINT(t, 0x1f642, ipckey(0x101f642, 0x1f642));
CT_EQ_UINT(t, 0, ipckey(0xfe03, 0)); /* ISO_Level3_Shift */
CT_EQ_UINT(t, 'a', ipckeysym('a', 'a'));
CT_EQ_UINT(t, '1', ipckeysym(0xffb1, '1')); /* KP_1 */
CT_EQ_UINT(t, Kret, ipckeysym(0xff0d, '\r'));
CT_EQ_UINT(t, Kback, ipckeysym(0xff08, 8));
CT_EQ_UINT(t, Kspec + 0xff, ipckeysym(0xffff, 0x7f)); /* Delete */
CT_EQ_UINT(t, 0x1f642, ipckeysym(0x101f642, 0x1f642));
CT_EQ_UINT(t, 0, ipckeysym(0xfe03, 0)); /* ISO_Level3_Shift */
CT_EQ_UINT(t, Mshift|Mctrl, ipcmod(Mshift|Mctrl|(1<<1)|(1<<4)));
CT_EQ_UINT(t, Msuper, ipcmod(1<<6));
CT_EQ_UINT(t, Msuper, ipcmod(1<<26));
@@ -96,7 +96,7 @@ ipc_control_and_caret_frames(struct ct *t)
CT_EQ_INT(t, 0, want);
CT_EQ_UINT(t, 0, key);
CT_EQ_INT(t, 0, ipcpackcaret(buf, 1, -2, 0x01020304, 0x506));
ipcpackcaret(buf, 1, -2, 0x01020304, 0x506);
CT_EQ_MEM(t, caret, buf, sizeof caret);
CT_EQ_INT(t, Ipccaret, ipcreqtype(buf));
if(CT_EQ_INT(t, 0, ipcunpackcaret(buf, &valid, &x, &y, &h))){
@@ -105,17 +105,16 @@ ipc_control_and_caret_frames(struct ct *t)
CT_EQ_INT(t, 0x01020304, y);
CT_EQ_INT(t, 0x506, h);
}
CT_EQ_INT(t, 0, ipcpackcaret(buf, 1, INT32_MIN, INT32_MAX, 0));
ipcpackcaret(buf, 1, INT32_MIN, INT32_MAX, 0);
if(CT_EQ_INT(t, 0, ipcunpackcaret(buf, &valid, &x, &y, &h))){
CT_EQ_INT(t, INT32_MIN, x);
CT_EQ_INT(t, INT32_MAX, y);
CT_EQ_INT(t, 0, h);
}
CT_EQ_INT(t, 0, ipcpackcaret(buf, 0, -2, 3, 4));
ipcpackcaret(buf, 0, -2, 3, 4);
CT_EQ_MEM(t, nocaret, buf, sizeof nocaret);
if(CT_EQ_INT(t, 0, ipcunpackcaret(buf, &valid, &x, &y, &h)))
CT_EQ_INT(t, 0, valid);
CT_EQ_INT(t, -1, ipcpackcaret(buf, 1, 0, 0, -1));
memcpy(bad, caret, sizeof bad);
bad[1]++;
@@ -139,9 +138,9 @@ ipc_control_and_caret_frames(struct ct *t)
CT_EQ_INT(t, Ipcunknown, ipcreqtype(bad));
ipcpackreq(buf, 1, 0, 'a');
CT_EQ_INT(t, Ipclegacy, ipcreqtype(buf));
CT_EQ_INT(t, Ipckey, ipcreqtype(buf));
ipcpackreset(buf, 1);
CT_EQ_INT(t, Ipclegacy, ipcreqtype(buf));
CT_EQ_INT(t, Ipckey, ipcreqtype(buf));
}
void
@@ -162,7 +161,6 @@ ipc_runtime_path(struct ct *t)
snprint(fallback, sizeof fallback, "/tmp/strans.%d", getuid());
CT_EQ_STR(t, fallback, buf);
CT_EQ_INT(t, -1, ipcpath(buf, 4));
CT_EQ_INT(t, -1, ipcpath(nil, sizeof buf));
if(saved != nil){
setenv("XDG_RUNTIME_DIR", saved, 1);
free(saved);
@@ -200,22 +198,18 @@ ipc_response_pack_boundaries(struct ct *t)
CT_EQ_INT(t, -1, ipcpackresp(out, Ipcmaxresp-1, 1,
(char*)field, sizeof field, (char*)field, sizeof field, 1));
CT_EQ_INT(t, -1, ipcpackresp(out, sizeof out, 0,
nil, 1, nil, 0, 0));
CT_EQ_INT(t, -1, ipcpackresp(out, sizeof out, 0,
nil, 0, nil, 1, 1));
CT_EQ_INT(t, -1, ipcpackresp(out, sizeof out, 0,
(char*)field, Ipcfieldmax+1, nil, 0, 0));
(char*)field, Ipcfieldmax+1, "", 0, 0));
}
void
ipc_response_empty_and_preedit(struct ct *t)
{
uchar first[Ipcmaxresp], second[Ipcmaxresp];
char commit[16], preedit[16];
char commit[Ipcfieldmax+1], preedit[Ipcfieldmax+1];
Ipcresp resp;
int fd[2], nfirst, nsecond;
nfirst = ipcpackresp(first, sizeof first, 0, nil, 0, nil, 0, 0);
nfirst = ipcpackresp(first, sizeof first, 0, "", 0, "", 0, 0);
nsecond = ipcpackresp(second, sizeof second, 1,
"go", 2, "kana", 4, 1);
if(!CT_CHECK(t, nfirst > 0 && nsecond > 0))
@@ -226,15 +220,13 @@ ipc_response_empty_and_preedit(struct ct *t)
}
if(CT_EQ_INT(t, 0, ipcsend(fd[0], first, nfirst)) &&
CT_EQ_INT(t, 0, ipcsend(fd[0], second, nsecond)) &&
CT_EQ_INT(t, 0, ipcreadresp(fd[1], 0, commit, sizeof commit,
nil, 0, &resp))){
CT_EQ_INT(t, 0, ipcreadresp(fd[1], 0, commit, preedit, &resp))){
CT_EQ_INT(t, 0, resp.eaten);
CT_EQ_SIZE(t, 0, resp.commitlen);
CT_EQ_SIZE(t, 0, resp.preeditlen);
CT_EQ_STR(t, "", commit);
}
if(CT_EQ_INT(t, 0, ipcreadresp(fd[1], 1, commit, sizeof commit,
preedit, sizeof preedit, &resp))){
if(CT_EQ_INT(t, 0, ipcreadresp(fd[1], 1, commit, preedit, &resp))){
CT_EQ_INT(t, 1, resp.eaten);
CT_EQ_SIZE(t, 2, resp.commitlen);
CT_EQ_SIZE(t, 4, resp.preeditlen);
@@ -249,14 +241,14 @@ void
ipc_response_max_and_drain(struct ct *t)
{
uchar first[Ipcmaxresp], second[Ipcmaxresp], field[Ipcfieldmax];
char commit[8], preedit[8];
char commit[Ipcfieldmax+1], preedit[Ipcfieldmax+1];
Ipcresp resp;
int fd[2], nfirst, nsecond;
memset(field, 'x', sizeof field);
nfirst = ipcpackresp(first, sizeof first, 1,
(char*)field, sizeof field, (char*)field, sizeof field, 1);
nsecond = ipcpackresp(second, sizeof second, 0, "ok", 2, nil, 0, 0);
nsecond = ipcpackresp(second, sizeof second, 0, "ok", 2, "", 0, 0);
if(!CT_CHECK(t, nfirst == Ipcmaxresp && nsecond > 0))
return;
if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0){
@@ -265,15 +257,15 @@ ipc_response_max_and_drain(struct ct *t)
}
if(CT_EQ_INT(t, 0, ipcsend(fd[0], first, nfirst)) &&
CT_EQ_INT(t, 0, ipcsend(fd[0], second, nsecond)) &&
CT_EQ_INT(t, 0, ipcreadresp(fd[1], 1, commit, sizeof commit,
preedit, sizeof preedit, &resp))){
CT_EQ_SIZE(t, sizeof commit - 1, resp.commitlen);
CT_EQ_SIZE(t, sizeof preedit - 1, resp.preeditlen);
CT_EQ_STR(t, "xxxxxxx", commit);
CT_EQ_STR(t, "xxxxxxx", preedit);
CT_EQ_INT(t, 0, ipcreadresp(fd[1], 1, commit, preedit, &resp))){
CT_EQ_SIZE(t, Ipcfieldmax, resp.commitlen);
CT_EQ_SIZE(t, Ipcfieldmax, resp.preeditlen);
CT_EQ_MEM(t, field, commit, Ipcfieldmax);
CT_EQ_MEM(t, field, preedit, Ipcfieldmax);
CT_EQ_INT(t, 0, commit[Ipcfieldmax]);
CT_EQ_INT(t, 0, preedit[Ipcfieldmax]);
}
if(CT_EQ_INT(t, 0, ipcreadresp(fd[1], 0, commit, sizeof commit,
nil, 0, &resp)))
if(CT_EQ_INT(t, 0, ipcreadresp(fd[1], 0, commit, preedit, &resp)))
CT_EQ_STR(t, "ok", commit);
close(fd[0]);
close(fd[1]);
@@ -283,7 +275,7 @@ void
ipc_response_fragmented_and_truncated(struct ct *t)
{
uchar frame[Ipcmaxresp];
char commit[8], preedit[8];
char commit[Ipcfieldmax+1], preedit[Ipcfieldmax+1];
Ipcresp resp;
int fd[2], i, n;
@@ -299,8 +291,8 @@ ipc_response_fragmented_and_truncated(struct ct *t)
CT_ERRORF(t, "fragment send failed");
break;
}
if(i == n && CT_EQ_INT(t, 0, ipcreadresp(fd[1], 1,
commit, sizeof commit, preedit, sizeof preedit, &resp))){
if(i == n && CT_EQ_INT(t, 0, ipcreadresp(fd[1], 1, commit, preedit,
&resp))){
CT_EQ_STR(t, "abc", commit);
CT_EQ_STR(t, "xy", preedit);
}
@@ -313,8 +305,7 @@ ipc_response_fragmented_and_truncated(struct ct *t)
}
CT_EQ_INT(t, 0, ipcsend(fd[0], frame, n-1));
shutdown(fd[0], SHUT_WR);
CT_EQ_INT(t, -1, ipcreadresp(fd[1], 1, commit, sizeof commit,
preedit, sizeof preedit, &resp));
CT_EQ_INT(t, -1, ipcreadresp(fd[1], 1, commit, preedit, &resp));
close(fd[0]);
close(fd[1]);
@@ -325,8 +316,7 @@ ipc_response_fragmented_and_truncated(struct ct *t)
frame[0] = 2;
CT_EQ_INT(t, 0, ipcsend(fd[0], frame, n));
errno = 0;
CT_EQ_INT(t, -1, ipcreadresp(fd[1], 1, commit, sizeof commit,
preedit, sizeof preedit, &resp));
CT_EQ_INT(t, -1, ipcreadresp(fd[1], 1, commit, preedit, &resp));
CT_EQ_INT(t, EPROTO, errno);
close(fd[0]);
close(fd[1]);
@@ -351,7 +341,7 @@ ipc_broken_peer_send(struct ct *t)
static void
ipcclientdeadlines(struct ct *t)
{
char fill[4096], commit[8];
char fill[4096], commit[Ipcfieldmax+1], preedit[Ipcfieldmax+1];
Ipcresp resp;
int fd[2];
int64_t start, elapsed;
@@ -363,8 +353,7 @@ ipcclientdeadlines(struct ct *t)
}
start = nowms();
errno = 0;
CT_EQ_INT(t, -1, ipcreadresp(fd[0], 0, commit, sizeof commit,
nil, 0, &resp));
CT_EQ_INT(t, -1, ipcreadresp(fd[0], 0, commit, preedit, &resp));
elapsed = nowms() - start;
CT_EQ_INT(t, ETIMEDOUT, errno);
CT_CHECK(t, elapsed >= 0 && elapsed < 4*Ipcwaitms);