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

85
srv.c
View File

@@ -11,98 +11,78 @@ static int
srvreadreq(int fd, Keyreq *kr, int *want)
{
uchar req[Ipccaretsz];
int type, valid;
int valid;
int32_t x, y, h;
u32int ks, mod;
if(ipcreadn(fd, req, Ipcreqsz) < 0)
return -1;
type = ipcreqtype(req);
switch(type){
case Ipclegacy:
ipcunpackreq(req, want, &mod, &ks);
*want = 0;
kr->ks = 0;
kr->mod = 0;
switch(ipcreqtype(req)){
case Ipckey:
ipcunpackreq(req, want, &kr->mod, &kr->ks);
kr->op = ipcreqreset(req) ? Keyreset : Keypress;
kr->ks = ks;
kr->mod = mod;
break;
return 0;
case Ipccap:
*want = (req[0] & Ipcreqwant) != 0;
kr->op = Keycap;
kr->ks = 0;
kr->mod = 0;
break;
return 0;
case Ipccaret:
if(ipcreadn(fd, req + Ipcreqsz, Ipccaretsz - Ipcreqsz) < 0 ||
ipcunpackcaret(req, &valid, &x, &y, &h) < 0)
return -1;
*want = 0;
kr->op = Keycaret;
kr->ks = 0;
kr->mod = 0;
kr->caret.valid = valid;
kr->caret.x = x;
kr->caret.y = y;
kr->caret.h = h;
break;
default:
return -1;
return 0;
}
return type;
return -1;
}
/*
* One Keyreq persists for the connection: the negotiated capability and
* the last caret ride along with every request, and the socket closing
* releases the engine.
*/
static void
clientthread(void *arg)
{
Channel *reply;
int fd;
Keyreq kr;
Keyres res;
Caret caret;
uchar out[Ipcmaxresp];
uchar out[Ipcmaxresp], token;
char commit[Maxutf], preedit[Maxutf];
int cap, n, ncommit, negotiated, npreedit, type, want;
uchar token;
int fd, n, ncommit, npreedit, want;
fd = (int)(uintptr)arg;
threadsetname("client %d", fd);
reply = chancreate(sizeof(Keyres), 0);
kr.reply = reply;
memset(&kr, 0, sizeof kr);
kr.reply = chancreate(sizeof(Keyres), 0);
kr.owner = &fd;
cap = Cclientpreedit;
negotiated = 0;
memset(&caret, 0, sizeof caret);
kr.cap = cap;
kr.caret = caret;
while((type = srvreadreq(fd, &kr, &want)) >= 0){
if(type == Ipccap){
cap = want ? Cclientpreedit : 0;
negotiated = 1;
}else if(type == Ipclegacy && !negotiated)
cap = want ? Cclientpreedit : 0;
else if(type == Ipccaret)
caret = kr.caret;
kr.cap = cap;
kr.caret = caret;
kr.cap = Cclientpreedit;
while(srvreadreq(fd, &kr, &want) >= 0){
if(kr.op != Keycaret)
kr.cap = want ? Cclientpreedit : 0;
chansend(keyc, &kr);
chanrecv(reply, &res);
if(type == Ipccaret)
chanrecv(kr.reply, &res);
if(kr.op == Keycaret)
continue;
ncommit = stoutf(&res.commit, commit, sizeof commit);
npreedit = stoutf(&res.preedit, preedit, sizeof preedit);
n = ipcpackresp(out, sizeof out,
type == Ipccap ? 1 : res.eaten,
/* A capability reply is always eaten: it marks the extension. */
n = ipcpackresp(out, sizeof out, kr.op == Keycap || res.eaten,
commit, ncommit, preedit, npreedit, want);
if(n < 0 || ipcsend(fd, out, n) < 0)
break;
}
kr.op = Keyrelease;
kr.cap = cap;
kr.caret = caret;
kr.ks = 0;
kr.mod = 0;
chansend(keyc, &kr);
chanrecv(reply, &res);
chanfree(reply);
chanrecv(kr.reply, &res);
chanfree(kr.reply);
close(fd);
chanrecv(clientc, &token);
}
@@ -142,9 +122,6 @@ srvthread(void*)
close(fd);
continue;
}
if(proccreate(clientthread, (void*)(uintptr)fd, 8192) < 0){
chanrecv(clientc, &token);
close(fd);
}
proccreate(clientthread, (void*)(uintptr)fd, 8192);
}
}