diff --git a/sys-utils/libcmt/Makefile b/sys-utils/libcmt/Makefile index efe6b4f..beade10 100644 --- a/sys-utils/libcmt/Makefile +++ b/sys-utils/libcmt/Makefile @@ -25,8 +25,7 @@ TARGET_CFLAGS := $(COMMON_CFLAGS) -ftrivial-auto-var-init=zero -Wstrict-aliasing CFLAGS := $(COMMON_CFLAGS) CC := gcc -all: libcmt host -host: mock tools +all: libcmt host mock tools #------------------------------------------------------------------------------- examples_SRC := \ doc/examples/abi_encode_000.c \ @@ -167,6 +166,47 @@ install-mock: $(mock_LIB) $(mock_SO) build/ffi.h mkdir -p $(DESTDIR)$(PREFIX)/lib/pkgconfig sed -e 's|@ARG_PREFIX@|$(PREFIX)|g' src/libcmt_mock.pc > $(DESTDIR)$(PREFIX)/lib/pkgconfig/libcmt.pc +#------------------------------------------------------------------------------- +host_SRC := \ + src/abi.c \ + src/buf.c \ + src/keccak.c \ + src/merkle.c \ + src/rollup.c \ + src/util.c \ + src/sock.c \ + src/io-host.c + +host_OBJDIR := build/host +host_OBJ := $(patsubst %.c,$(host_OBJDIR)/%.o,$(host_SRC)) +host_LIB := $(host_OBJDIR)/libcmt.a +host_SO := $(host_OBJDIR)/libcmt.so + +$(host_OBJ): $(host_OBJDIR)/%.o: %.c + @mkdir -p $(@D) + $(CC) $(CFLAGS) -MT $@ -MMD -MP -MF $(@:.o=.d) -c -o $@ $< + +$(host_LIB): $(host_OBJ) + $(AR) rcs $@ $^ + +$(host_SO): $(host_OBJ) + $(CC) -shared -o $@ $^ + +host: $(host_LIB) $(host_SO) $(host_OBJDIR)/libcmt-host-sample + +install-host: $(host_LIB) $(host_SO) build/ffi.h + mkdir -p $(DESTDIR)$(PREFIX)/lib + cp -f $(host_LIB) $(host_SO) $(DESTDIR)$(PREFIX)/lib + mkdir -p $(DESTDIR)$(PREFIX)/include/libcmt/ + cp -f include/libcmt/*.h $(DESTDIR)$(PREFIX)/include/libcmt/ + cp -f build/ffi.h $(DESTDIR)$(PREFIX)/include/libcmt/ + mkdir -p $(DESTDIR)$(PREFIX)/lib/pkgconfig + sed -e 's|@ARG_PREFIX@|$(PREFIX)|g' src/libcmt_host.pc > $(DESTDIR)$(PREFIX)/lib/pkgconfig/libcmt.pc + +$(host_OBJDIR)/libcmt-host-sample: src/libcmt-host-sample.c $(host_LIB) + $(CC) $(CFLAGS) -o $@ $^ + + #------------------------------------------------------------------------------- unittests_BINS := \ $(mock_OBJDIR)/abi-multi \ diff --git a/sys-utils/libcmt/include/libcmt/io.h b/sys-utils/libcmt/include/libcmt/io.h index 8772335..85e6d3f 100644 --- a/sys-utils/libcmt/include/libcmt/io.h +++ b/sys-utils/libcmt/include/libcmt/io.h @@ -54,6 +54,7 @@ #ifndef CMT_IO_H #define CMT_IO_H #include "buf.h" +#include "sock.h" #include /** Device */ @@ -109,10 +110,18 @@ typedef struct { int gio_seq; } cmt_io_driver_mock_t; +typedef struct { + cmt_buf_t tx[1]; + cmt_buf_t rx[1]; + cmt_conn_t sock; + int fds[2]; // to close files when we are done +} cmt_io_driver_host_t; + /** Implementation specific cmio state. */ typedef union cmt_io_driver { cmt_io_driver_ioctl_t ioctl; cmt_io_driver_mock_t mock; + cmt_io_driver_host_t host; } cmt_io_driver_t; /** yield struct cmt_io_yield */ diff --git a/sys-utils/libcmt/include/libcmt/sock.h b/sys-utils/libcmt/include/libcmt/sock.h new file mode 100644 index 0000000..d03f922 --- /dev/null +++ b/sys-utils/libcmt/include/libcmt/sock.h @@ -0,0 +1,31 @@ +#ifndef CMT_SOCK_H +#define CMT_SOCK_H +#include +#include + +typedef union { + struct sockaddr_storage ss; + struct sockaddr_un un; +} cmt_sock_addr_t; + +typedef struct { + cmt_sock_addr_t addr, other; + int fd; +} cmt_conn_t; + +const char *cmt_sock_client_get_path(void); +const char *cmt_sock_server_get_path(void); + +int cmt_sock_addr_init(struct sockaddr_un *me, size_t length, const char path[]); + +int cmt_sock_init(cmt_conn_t *me, const char *self, const char *other); +void cmt_sock_fini(cmt_conn_t *me); + +int cmt_sock_send(cmt_conn_t *me, size_t length, const void *data); +int cmt_sock_recv(cmt_conn_t *me, size_t length, void *data); + +int cmt_sock_send_fds(cmt_conn_t *me, size_t length, int fds[]); +int cmt_sock_recv_fds(cmt_conn_t *me, size_t length, int fds[]); + + +#endif /* CMT_SOCK_H */ diff --git a/sys-utils/libcmt/src/io-host.c b/sys-utils/libcmt/src/io-host.c new file mode 100644 index 0000000..7bd6e1a --- /dev/null +++ b/sys-utils/libcmt/src/io-host.c @@ -0,0 +1,163 @@ +#include +#include +#include +#include +#include + +#include "libcmt/io.h" +#include "libcmt/util.h" +#include "libcmt/sock.h" + +static int mmapfd(int fd, int prot, uint8_t **begin, uint8_t **end) +{ + struct stat stat; + if (fstat(fd, &stat)) { + return -errno; + } + size_t size = stat.st_size; + + *begin = mmap(NULL, size, prot, MAP_SHARED, fd, 0); + *end = *begin + size; + if (*begin == MAP_FAILED) { + return -errno; + } + return 0; +} + +int cmt_io_init(cmt_io_driver_t *_me) { + int rc = 0; + + if (!_me) { + return -EINVAL; + } + cmt_io_driver_host_t *me = &_me->host; + + rc = cmt_sock_init(&me->sock, cmt_sock_client_get_path(), cmt_sock_server_get_path()); + if (rc) { + return rc; + } + + // signal the server we want the fds + rc = cmt_sock_send(&me->sock, 0, NULL); + if (rc) { + cmt_sock_fini(&me->sock); + return rc; + } + + rc = cmt_sock_recv_fds(&me->sock, sizeof(me->fds) / sizeof(int), me->fds); + if (rc) { + cmt_sock_fini(&me->sock); + return rc; + } + + rc = mmapfd(me->fds[0], PROT_READ | PROT_WRITE, &me->tx->begin, &me->tx->end); + if (rc) { + cmt_sock_fini(&me->sock); + return rc; + } + rc = mmapfd(me->fds[1], PROT_READ, &me->rx->begin, &me->rx->end); + if (rc) { + munmap(me->tx->begin, cmt_buf_length(me->tx)); + cmt_sock_fini(&me->sock); + return rc; + } + + return 0; +} + +void cmt_io_fini(cmt_io_driver_t *_me) { + if (!_me) { + return; + } + cmt_io_driver_host_t *me = &_me->host; + + munmap(me->tx->begin, cmt_buf_length(me->tx)); + munmap(me->rx->begin, cmt_buf_length(me->rx)); + + close(me->fds[0]); + close(me->fds[1]); + + cmt_sock_fini(&me->sock); +} + +cmt_buf_t cmt_io_get_tx(cmt_io_driver_t *me) { + const cmt_buf_t empty = {NULL, NULL}; + if (!me) { + return empty; + } + return *me->host.tx; +} + +cmt_buf_t cmt_io_get_rx(cmt_io_driver_t *me) { + const cmt_buf_t empty = {NULL, NULL}; + if (!me) { + return empty; + } + return *me->host.rx; +} + +static uint64_t pack(struct cmt_io_yield *rr) { + // clang-format off + return ((uint64_t) rr->dev << 56) + | ((uint64_t) rr->cmd << 56 >> 8) + | ((uint64_t) rr->reason << 48 >> 16) + | ((uint64_t) rr->data << 32 >> 32); + // clang-format on +} + +static struct cmt_io_yield unpack(uint64_t x) { + // clang-format off + struct cmt_io_yield out = { + x >> 56, + x << 8 >> 56, + x << 16 >> 48, + x << 32 >> 32, + }; + // clang-format on + return out; +} + +int cmt_io_yield(cmt_io_driver_t *_me, cmt_io_yield_t *rr) +{ + int rc = 0; + if (!_me) { + return -EINVAL; + } + if (!rr) { + return -EINVAL; + } + cmt_io_driver_host_t *me = &_me->host; + + bool debug = cmt_util_debug_enabled(); + if (debug) { + (void) fprintf(stderr, + "tohost {\n" + "\t.dev = %d,\n" + "\t.cmd = %d,\n" + "\t.reason = %d,\n" + "\t.data = %d,\n" + "};\n", + rr->dev, rr->cmd, rr->reason, rr->data); + } + + uint64_t req = pack(rr); + rc = cmt_sock_send(&me->sock, sizeof(req), &req); + if (rc < 0) return rc; + + uint64_t rep; + rc = cmt_sock_recv(&me->sock, sizeof(rep), &rep); + if (rc < 0) return rc; + *rr = unpack(rep); + + if (debug) { + (void) fprintf(stderr, + "fromhost {\n" + "\t.dev = %d,\n" + "\t.cmd = %d,\n" + "\t.reason = %d,\n" + "\t.data = %d,\n" + "};\n", + rr->dev, rr->cmd, rr->reason, rr->data); + } + return 0; +} diff --git a/sys-utils/libcmt/src/libcmt-host-sample.c b/sys-utils/libcmt/src/libcmt-host-sample.c new file mode 100644 index 0000000..9ca52ec --- /dev/null +++ b/sys-utils/libcmt/src/libcmt-host-sample.c @@ -0,0 +1,161 @@ +#if 0 +${CC:-cc} -Wall -pedantic -ggdb -O2 -Iinclude -Lbuild/host -o ${0%%.c} $0 -l:libcmt.a +exit $? +#endif +#include +#include +#include +#include +#include +#include + +#include "../tests/data.h" +#include "libcmt/sock.h" +#include "libcmt/util.h" +#include "libcmt/buf.h" +#include "libcmt/io.h" + +#define DBG(X) debug(X, #X, __FILE__, __LINE__) +static int debug(int rc, const char *expr, const char *file, int line) { + if (rc >= 0) { + return 0; + } + + if (cmt_util_debug_enabled()) { + (void) fprintf(stdout, "%s:%d Error %s on `%s'\n", file, line, expr, strerror(-rc)); + } + return rc; +} + +typedef struct { + cmt_buf_t buf[1]; + char path[64]; + int fd; +} cmt_file_t; + +// should we handle multiple connections? +typedef struct cmt_io_host { + cmt_conn_t sock[1]; + cmt_file_t tx[1], rx[1]; +} cmt_io_host_t; + +int cmt_file_init(cmt_file_t *me, size_t size, int prot) +{ + strncpy(me->path, "/tmp/tmp.XXXXXX", sizeof(me->path)); + me->fd = mkstemp(me->path); + if (ftruncate(me->fd, size) < 0) + return -errno; + me->buf->begin = mmap(NULL, size, prot, MAP_SHARED, me->fd, 0); + me->buf->end = me->buf->begin + size; + return 0; +} + +void cmt_file_fini(cmt_file_t *me) +{ + munmap(me->buf->begin, cmt_buf_length(me->buf)); + close(me->fd); + unlink(me->path); +} + +int cmt_io_host_init(cmt_io_host_t *me) +{ + size_t size = 2U << 20; // 2MB + DBG(cmt_file_init(me->tx, size, PROT_READ | PROT_WRITE)); + DBG(cmt_file_init(me->rx, size, PROT_READ | PROT_WRITE)); + DBG(cmt_sock_init(me->sock, cmt_sock_server_get_path(), cmt_sock_client_get_path())); + return 0; +} + +void cmt_io_host_fini(cmt_io_host_t *me) +{ + unlink(me->tx->path); + unlink(me->rx->path); + cmt_sock_fini(me->sock); +} + +static uint64_t pack(struct cmt_io_yield *rr) { + // clang-format off + return ((uint64_t) rr->dev << 56) + | ((uint64_t) rr->cmd << 56 >> 8) + | ((uint64_t) rr->reason << 48 >> 16) + | ((uint64_t) rr->data << 32 >> 32); + // clang-format on +} + +static struct cmt_io_yield unpack(uint64_t x) { + // clang-format off + struct cmt_io_yield out = { + x >> 56, + x << 8 >> 56, + x << 16 >> 48, + x << 32 >> 32, + }; + // clang-format on + return out; +} + +// wait for the client to signal it want the fds +int cmt_io_host_setup_client(cmt_io_host_t *me) +{ + int rc = 0; + + uint64_t req; + rc = DBG(cmt_sock_recv(me->sock, sizeof(req), &req)); + if (rc < 0) { + cmt_sock_fini(me->sock); + return rc; + } + + int fds[] = {me->rx->fd, me->tx->fd}; + rc = DBG(cmt_sock_send_fds(me->sock, 2, fds)); + if (rc < 0) { + cmt_sock_fini(me->sock); + return rc; + } + return 0; +} + +void cmt_io_yield_print(cmt_io_yield_t *me) +{ + (void) fprintf(stdout, + "tohost {\n" + "\t.dev = %d,\n" + "\t.cmd = %d,\n" + "\t.reason = %d,\n" + "\t.data = %u,\n" + "};\n", + me->dev, me->cmd, me->reason, me->data); +} + +int main(int argc, char *const argv[]) { + (void)argc; + cmt_io_host_t io_host[1]; + fprintf(stderr, "%s: start ...\n", argv[0]); + cmt_io_host_init(io_host); + fprintf(stderr, "ready ...\n"); + cmt_io_host_setup_client(io_host); + fprintf(stderr, "connected\n"); + + while (true) { + uint64_t req = 0xa0a0a0a0a0a0a0a0ULL; + + DBG(cmt_sock_recv(io_host->sock, sizeof(req), &req)); + cmt_io_yield_t y = unpack(req); + cmt_io_yield_print(&y); + + // do things here + memcpy(io_host->tx->buf->begin, valid_advance_0, sizeof(valid_advance_0)); + y.reason = 0; // advance + y.data = sizeof(valid_advance_0); + + uint64_t rep = pack(&y); + cmt_io_yield_print(&y); + + DBG(cmt_sock_send(io_host->sock, sizeof(rep), &rep)); + + break; // we are testing, send only once + } + + cmt_io_host_fini(io_host); + return 0; +} diff --git a/sys-utils/libcmt/src/sock.c b/sys-utils/libcmt/src/sock.c new file mode 100644 index 0000000..d319cb1 --- /dev/null +++ b/sys-utils/libcmt/src/sock.c @@ -0,0 +1,127 @@ +#include "libcmt/sock.h" +#include +#include +#include +#include +#include + +#include +#include +#include + +// send up to 64 file descriptors at once +#define CMT_CMSG_MAX (64 * sizeof(int)) + +int cmt_sock_addr_init(struct sockaddr_un *me, size_t length, const char path[]) { + if (length > sizeof(me->sun_path)-1U) { + return -ENOBUFS; + } + me->sun_family = AF_UNIX; + memset(me->sun_path, 0, sizeof(me->sun_path)); + memcpy(me->sun_path, path, length+1); // include '\0' + return 0; +} +static int send_fds(int fd, struct sockaddr_un *addr, size_t length, int fds[]) { + char cmsg[CMSG_SPACE(length * sizeof(int))]; // TODO: remove VLA + struct msghdr msg[1] = {{ + .msg_name = addr, + .msg_namelen = sizeof(*addr), + .msg_iov = NULL, + .msg_iovlen = 0, + .msg_control = cmsg, + .msg_controllen = sizeof(cmsg), + }}; + + struct cmsghdr *c = CMSG_FIRSTHDR(msg); + c->cmsg_level = SOL_SOCKET; + c->cmsg_type = SCM_RIGHTS; + c->cmsg_len = CMSG_LEN(length * sizeof(int)); + memcpy(CMSG_DATA(c), fds, length * sizeof(int)); + ssize_t rc = sendmsg(fd, msg, 0); + if (rc == -1) { return -errno; } + return 0; +} +static int recv_fds(int fd, struct sockaddr_un *addr, size_t length, int fds[]) { + char cmsg[CMSG_SPACE(length * sizeof(int))]; // TODO: remove VLA + struct msghdr msg[1] = {{ + .msg_name = (struct sockaddr *)addr, + .msg_namelen = sizeof(*addr), + .msg_iov = NULL, + .msg_iovlen = 0, + .msg_control = cmsg, + .msg_controllen = sizeof(cmsg), + }}; + ssize_t rc = recvmsg(fd, msg, 0); + if (rc == -1) { return -errno; } + + struct cmsghdr *c = CMSG_FIRSTHDR(msg); + memcpy(fds, CMSG_DATA(c), length * sizeof(int)); + return 0; +} +const char *cmt_sock_client_get_path(void) +{ + const char *env = getenv("CMT_SOCK"); + return env? env : "/tmp/cmt.client.sock"; +} +const char *cmt_sock_server_get_path(void) +{ + const char *env = getenv("CMT_SOCK"); + return env? env : "/tmp/cmt.server.sock"; +} + +int cmt_sock_init(cmt_conn_t *me, const char *addr, const char *other) +{ + int rc = 0; + + rc = cmt_sock_addr_init(&me->addr.un, strlen(addr), addr); + if (rc) { + return rc; + } + rc = cmt_sock_addr_init(&me->other.un, strlen(other), other); + if (rc) { + return rc; + } + + me->fd = socket(AF_UNIX, SOCK_DGRAM, 0); + if (me->fd < 0) { + return -errno; + } + + rc = bind(me->fd, (struct sockaddr *)&me->addr.un, sizeof(me->addr.un)); + if (rc < 0) { + close(me->fd); + return -errno; + } + return 0; +} + +void cmt_sock_fini(cmt_conn_t *me) +{ + unlink(me->addr.un.sun_path); + close(me->fd); + me->fd = -1; +} + +int cmt_sock_send(cmt_conn_t *me, size_t length, const void *data) +{ + ssize_t rc = sendto(me->fd, data, length, 0, (struct sockaddr *)&me->other.un, sizeof(me->other.un)); + if (rc < 0) { return -errno; } + return rc; +} + +int cmt_sock_recv(cmt_conn_t *me, size_t length, void *data) +{ + ssize_t rc = recv(me->fd, data, length, 0); + if (rc < 0) { return -errno; } + return rc; +} + +int cmt_sock_send_fds(cmt_conn_t *me, size_t length, int fds[]) +{ + return send_fds(me->fd, &me->other.un, length, fds); +} + +int cmt_sock_recv_fds(cmt_conn_t *me, size_t length, int fds[]) +{ + return recv_fds(me->fd, &me->addr.un, length, fds); +}