fix(ipc): preserve legacy preedit and bound client waits
This commit is contained in:
141
tests/ipc_test.c
141
tests/ipc_test.c
@@ -1,10 +1,31 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include "test.h"
|
||||
|
||||
#undef accept
|
||||
#undef listen
|
||||
#undef send
|
||||
|
||||
static int64_t
|
||||
nowms(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
if(clock_gettime(CLOCK_MONOTONIC, &ts) < 0)
|
||||
return 0;
|
||||
return (int64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
|
||||
}
|
||||
|
||||
static void ipcclientdeadlines(struct ct*);
|
||||
static void ipcconnectcloexec(struct ct*);
|
||||
|
||||
void
|
||||
ipc_masks_modifiers(struct ct *t)
|
||||
{
|
||||
@@ -196,15 +217,15 @@ ipc_response_empty_and_preedit(struct ct *t)
|
||||
CT_EQ_INT(t, 0, ipcreadresp(fd[1], 0, commit, sizeof commit,
|
||||
nil, 0, &resp))){
|
||||
CT_EQ_INT(t, 0, resp.eaten);
|
||||
CT_EQ_SIZE(t, 0, resp.ncommit);
|
||||
CT_EQ_SIZE(t, 0, resp.npreedit);
|
||||
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))){
|
||||
CT_EQ_INT(t, 1, resp.eaten);
|
||||
CT_EQ_SIZE(t, 2, resp.ncommit);
|
||||
CT_EQ_SIZE(t, 4, resp.npreedit);
|
||||
CT_EQ_SIZE(t, 2, resp.commitlen);
|
||||
CT_EQ_SIZE(t, 4, resp.preeditlen);
|
||||
CT_EQ_STR(t, "go", commit);
|
||||
CT_EQ_STR(t, "kana", preedit);
|
||||
}
|
||||
@@ -234,8 +255,8 @@ ipc_response_max_and_drain(struct ct *t)
|
||||
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, Ipcfieldmax, resp.ncommit);
|
||||
CT_EQ_SIZE(t, Ipcfieldmax, resp.npreedit);
|
||||
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);
|
||||
}
|
||||
@@ -284,6 +305,19 @@ ipc_response_fragmented_and_truncated(struct ct *t)
|
||||
preedit, sizeof preedit, &resp));
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
|
||||
if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0){
|
||||
CT_ERRORF(t, "socketpair failed");
|
||||
return;
|
||||
}
|
||||
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, EPROTO, errno);
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -298,4 +332,99 @@ ipc_broken_peer_send(struct ct *t)
|
||||
close(fd[1]);
|
||||
CT_EQ_INT(t, -1, ipcsend(fd[0], "x", 1));
|
||||
close(fd[0]);
|
||||
ipcclientdeadlines(t);
|
||||
ipcconnectcloexec(t);
|
||||
}
|
||||
|
||||
static void
|
||||
ipcclientdeadlines(struct ct *t)
|
||||
{
|
||||
char fill[4096], commit[8];
|
||||
Ipcresp resp;
|
||||
int fd[2];
|
||||
int64_t start, elapsed;
|
||||
ssize_t n;
|
||||
|
||||
if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0){
|
||||
CT_ERRORF(t, "socketpair failed");
|
||||
return;
|
||||
}
|
||||
start = nowms();
|
||||
errno = 0;
|
||||
CT_EQ_INT(t, -1, ipcreadresp(fd[0], 0, commit, sizeof commit,
|
||||
nil, 0, &resp));
|
||||
elapsed = nowms() - start;
|
||||
CT_EQ_INT(t, ETIMEDOUT, errno);
|
||||
CT_CHECK(t, elapsed >= 0 && elapsed < 4*Ipcwaitms);
|
||||
|
||||
memset(fill, 'x', sizeof fill);
|
||||
for(;;){
|
||||
n = send(fd[0], fill, sizeof fill, MSG_DONTWAIT|MSG_NOSIGNAL);
|
||||
if(n < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))
|
||||
break;
|
||||
if(n <= 0){
|
||||
CT_ERRORF(t, "fill send failed: %s", strerror(errno));
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
start = nowms();
|
||||
errno = 0;
|
||||
CT_EQ_INT(t, -1, ipcsend(fd[0], "x", 1));
|
||||
elapsed = nowms() - start;
|
||||
CT_EQ_INT(t, ETIMEDOUT, errno);
|
||||
CT_CHECK(t, elapsed >= 0 && elapsed < 4*Ipcwaitms);
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
}
|
||||
|
||||
static void
|
||||
ipcconnectcloexec(struct ct *t)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
char root[] = "/tmp/strans-ipc.XXXXXX";
|
||||
char *old, *saved;
|
||||
int accepted, client, flags, listener;
|
||||
|
||||
accepted = client = listener = -1;
|
||||
old = getenv("XDG_RUNTIME_DIR");
|
||||
saved = old == nil ? nil : strdup(old);
|
||||
if(mkdtemp(root) == nil){
|
||||
CT_ERRORF(t, "mkdtemp failed: %s", strerror(errno));
|
||||
free(saved);
|
||||
return;
|
||||
}
|
||||
setenv("XDG_RUNTIME_DIR", root, 1);
|
||||
memset(&addr, 0, sizeof addr);
|
||||
addr.sun_family = AF_UNIX;
|
||||
if(ipcpath(addr.sun_path, sizeof addr.sun_path) < 0 ||
|
||||
(listener = socket(AF_UNIX, SOCK_STREAM, 0)) < 0 ||
|
||||
bind(listener, (struct sockaddr*)&addr, sizeof addr) < 0 ||
|
||||
listen(listener, 1) < 0){
|
||||
CT_ERRORF(t, "listen failed: %s", strerror(errno));
|
||||
goto Out;
|
||||
}
|
||||
client = ipcconnect();
|
||||
if(!CT_CHECK(t, client >= 0))
|
||||
goto Out;
|
||||
accepted = accept(listener, nil, nil);
|
||||
if(!CT_CHECK(t, accepted >= 0))
|
||||
goto Out;
|
||||
flags = fcntl(client, F_GETFD);
|
||||
CT_CHECK(t, flags >= 0 && (flags & FD_CLOEXEC) != 0);
|
||||
Out:
|
||||
if(accepted >= 0)
|
||||
close(accepted);
|
||||
if(client >= 0)
|
||||
close(client);
|
||||
if(listener >= 0)
|
||||
close(listener);
|
||||
unlink(addr.sun_path);
|
||||
rmdir(root);
|
||||
if(saved != nil){
|
||||
setenv("XDG_RUNTIME_DIR", saved, 1);
|
||||
free(saved);
|
||||
}else
|
||||
unsetenv("XDG_RUNTIME_DIR");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user