Last active
May 3, 2025 22:36
-
-
Save mischief/93efd00debeb9af83795424497b7a2d2 to your computer and use it in GitHub Desktop.
luajit imsg
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| local ffi = require("ffi") | |
| local unix = require("unix") | |
| ffi.cdef [[ | |
| typedef uint32_t pid_t; | |
| struct msgbuf; | |
| struct imsgbuf { | |
| struct msgbuf *w; | |
| pid_t pid; | |
| uint32_t maxsize; | |
| int fd; | |
| int flags; | |
| }; | |
| struct imsg_hdr { | |
| uint32_t type; | |
| uint32_t len; | |
| uint32_t peerid; | |
| uint32_t pid; | |
| }; | |
| struct imsg { | |
| struct imsg_hdr hdr; | |
| void *data; | |
| struct ibuf *buf; | |
| }; | |
| int imsgbuf_init(struct imsgbuf*, int); | |
| int imsgbuf_read(struct imsgbuf*); | |
| int imsgbuf_write(struct imsgbuf*); | |
| int imsg_compose(struct imsgbuf*, uint32_t type, uint32_t id, pid_t pid, int fd, const void *data, size_t datalen); | |
| void imsg_free(struct imsg*); | |
| ssize_t imsg_get(struct imsgbuf*, struct imsg *img); | |
| int imsg_get_data(struct imsg*, void*, size_t); | |
| int imsg_get_type(struct imsg*); | |
| size_t imsg_get_len(struct imsg*); | |
| ]] | |
| local libutil = ffi.load("util") | |
| local sizettype = ffi.typeof("size_t"); | |
| local charptype = ffi.typeof("char*") | |
| local imsgbuftype = ffi.typeof("struct imsgbuf") | |
| local imsgtype = ffi.typeof("struct imsg") | |
| local t = {} | |
| local imsgbufmeta = {} | |
| imsgbufmeta.write = function(self) | |
| local rv = libutil.imsgbuf_write(self.buf) | |
| if rv ~= 0 then | |
| error(unix.strerror(ffi.errno())) | |
| end | |
| end | |
| imsgbufmeta.compose = function(self, type, id, pid, fd, data) | |
| local rv = libutil.imsg_compose(self.buf, type, id, pid, fd, data, #data) | |
| assert(rv == 1) | |
| end | |
| imsgbufmeta.compose_ct = function(self, typ, id, pid, fd, ct) | |
| assert(type(ct) == "cdata") | |
| local rv = libutil.imsg_compose(self.buf, typ, id, pid, fd, ct, ffi.sizeof(ct)) | |
| assert(rv == 1) | |
| end | |
| imsgbufmeta.read = function(self) | |
| local rv = libutil.imsgbuf_read(self.buf) | |
| return rv | |
| end | |
| local imsgmeta = {} | |
| imsgmeta.type = function(self) | |
| return libutil.imsg_get_type(self.imsg) | |
| end | |
| imsgmeta.len = function(self) | |
| return libutil.imsg_get_len(self.imsg) | |
| end | |
| imsgmeta.as_ct = function(self, ct) | |
| assert(type(ct) == "cdata") | |
| local neu = ct() | |
| local sz = ffi.sizeof(neu) | |
| local rv = libutil.imsg_get_data(self.imsg, neu, sz) | |
| if rv ~= 0 then | |
| error("imsg_get_data: " .. unix.strerror(ffi.errno())) | |
| end | |
| return neu | |
| end | |
| local imsgtostring = function(self) | |
| local sz = self:len() | |
| local cp = ffi.new("char[?]", sz) | |
| local rv = libutil.imsg_get_data(self.imsg, cp, sz) | |
| if rv ~= 0 then | |
| error("imsg_get_data: " .. unix.strerror(ffi.errno())) | |
| end | |
| return ffi.string(cp, sz) | |
| end | |
| imsgbufmeta.get = function(self) | |
| local imsg = imsgtype() | |
| local n = libutil.imsg_get(self.buf, imsg) | |
| if n == -1 then | |
| error("imsg_get error") | |
| end | |
| if n == 0 then | |
| return 0, nil | |
| end | |
| ffi.gc(imsg, libutil.imsg_free) | |
| return n, setmetatable({imsg=imsg}, {__index=imsgmeta, | |
| __tostring=imsgtostring, | |
| }) | |
| end | |
| t.init = function(fd) | |
| local buf = imsgbuftype() | |
| if libutil.imsgbuf_init(buf, fd) == -1 then | |
| error("imsgbuf_init failed") | |
| end | |
| return setmetatable({buf=buf}, {__index=imsgbufmeta}) | |
| end | |
| return t | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| local os = assert(require("os")) | |
| local ffi = assert(require("ffi")) | |
| local imsg = assert(require("imsg")) | |
| local unix = assert(require("unix")) | |
| local TYP_STRING = 42 | |
| local TYP_MSG = 41 | |
| local msgtype = ffi.typeof("struct { int answer; char data[32]; }") | |
| local child_main = function(imsg) | |
| while true do | |
| local rv = buf1:read() | |
| if rv == 0 then | |
| return 0 | |
| end | |
| while true do | |
| local n, msg = buf1:get() | |
| if n == -1 then | |
| error("read error?") | |
| end | |
| if n == 0 then | |
| break | |
| end | |
| local typ = msg:type() | |
| print("child", msg:type(), msg:len()) | |
| if typ == TYP_STRING then | |
| print("child", msg) | |
| elseif typ == TYP_MSG then | |
| local m = msg:as_ct(msgtype) | |
| print("child", m.answer, ffi.string(m.data)) | |
| end | |
| end | |
| end | |
| end | |
| local parent_main = function(imsg) | |
| imsg:compose(TYP_STRING, 0, 0, -1, "hello world") | |
| imsg:write() | |
| local m = msgtype() | |
| m.answer = 1234 | |
| ffi.copy(m.data, "fnord") | |
| imsg:compose_ct(TYP_MSG, 0, 0, -1, m) | |
| imsg:write() | |
| return 0 | |
| end | |
| p0, p1 = unix.socketpair() | |
| local rv = unix.fork() | |
| if rv == -1 then | |
| error("fork") | |
| end | |
| if rv == 0 then | |
| -- child | |
| unix.close(p0) | |
| buf1 = imsg.init(p1) | |
| os.exit(child_main(buf1)) | |
| end | |
| unix.close(p1) | |
| buf0 = imsg.init(p0) | |
| os.exit(parent_main(buf0)) | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| local ffi = require("ffi") | |
| local bit = require("bit") | |
| ffi.cdef[[ | |
| typedef uint32_t pid_t; | |
| int close(int); | |
| int socketpair(int domain, int type, int protocol, int sv[2]); | |
| pid_t fork(void); | |
| char *strerror(int); | |
| ]] | |
| local t = {} | |
| t.close = ffi.C.close | |
| t.fork = ffi.C.fork | |
| t.strerror = function(eno) | |
| return ffi.string(ffi.C.strerror(eno)) | |
| end | |
| t.SOCK_STREAM = 1 | |
| t.SOCK_CLOEXEC = 0x8000 | |
| t.SOCK_NONBLOCK = 0x4000 | |
| t.AF_UNSPEC = 0 | |
| t.AF_UNIX = 1 | |
| t.PF_UNSPEC = t.AF_UNSPEC | |
| t.socketpair = function() | |
| local fds = ffi.new("int[?]", 2) | |
| local r = ffi.C.socketpair(t.AF_UNIX, t.SOCK_STREAM, t.PF_UNSPEC, fds) | |
| if r == -1 then | |
| error(ffi.C.strerror(ffi.errno())) | |
| end | |
| return fds[0], fds[1] | |
| end | |
| return t | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment