diff options
author | bptato <nincsnevem662@gmail.com> | 2023-12-18 15:51:48 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2023-12-18 15:51:48 +0100 |
commit | a8022d1cbfe4c1a1a33ec7c8b1d2d5935d89e933 (patch) | |
tree | c3694b2610be607aa53cd93e3b5823876eef9b91 /src/io | |
parent | a3b2d9189f3b25c7cf79985beac843cc46c37cfc (diff) | |
download | chawan-a8022d1cbfe4c1a1a33ec7c8b1d2d5935d89e933.tar.gz |
socketstream: get rid of emits
Use .compile, as that is supported by nlvm too.
Diffstat (limited to 'src/io')
-rw-r--r-- | src/io/recvfd.c | 32 | ||||
-rw-r--r-- | src/io/sendfd.c | 28 | ||||
-rw-r--r-- | src/io/socketstream.nim | 65 |
3 files changed, 75 insertions, 50 deletions
diff --git a/src/io/recvfd.c b/src/io/recvfd.c new file mode 100644 index 00000000..de376c39 --- /dev/null +++ b/src/io/recvfd.c @@ -0,0 +1,32 @@ +#include <sys/socket.h> +#include <string.h> + +/* See https://stackoverflow.com/a/4491203 + * Receive a file handle from socket `sock`. + * Sets `fd` to the result if recvmsg returns sizeof(int), otherwise to -1. + * Returns: the return value of recvmsg; this may be -1. */ +ssize_t recvfd(int sock, int *fd) +{ + ssize_t n; + struct iovec iov; + struct msghdr hdr; + int cmsgbuf[CMSG_SPACE(sizeof(int))]; + struct cmsghdr *cmsg; + char buf = '\0'; + + iov.iov_base = &buf; + iov.iov_len = 1; + memset(&hdr, 0, sizeof(hdr)); + hdr.msg_iov = &iov; + hdr.msg_iovlen = 1; + hdr.msg_control = &cmsgbuf[0]; + hdr.msg_controllen = CMSG_SPACE(sizeof(int)); + n = recvmsg(sock, &hdr, 0); + if (n <= 0) { + *fd = -1; + return n; + } + cmsg = CMSG_FIRSTHDR(&hdr); + *fd = *((int *)CMSG_DATA(cmsg)); + return n; +} diff --git a/src/io/sendfd.c b/src/io/sendfd.c new file mode 100644 index 00000000..578009c2 --- /dev/null +++ b/src/io/sendfd.c @@ -0,0 +1,28 @@ +#include <sys/socket.h> +#include <string.h> + +/* See https://stackoverflow.com/a/4491203 + * Send a file handle to socket `sock`. + * Returns: 1 on success, -1 on error. I *think* this never returns * 0. */ +ssize_t sendfd(int sock, int fd) +{ + struct msghdr hdr; + struct iovec iov; + int cmsgbuf[CMSG_SPACE(sizeof(int))]; + char buf = '\0'; + struct cmsghdr *cmsg; + + memset(&hdr, 0, sizeof(hdr)); + iov.iov_base = &buf; + iov.iov_len = 1; + hdr.msg_iov = &iov; + hdr.msg_iovlen = 1; + hdr.msg_control = &cmsgbuf[0]; + hdr.msg_controllen = CMSG_LEN(sizeof(fd)); + cmsg = CMSG_FIRSTHDR(&hdr); + cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + *((int *)CMSG_DATA(cmsg)) = fd; + return sendmsg(sock, &hdr, 0); +} diff --git a/src/io/socketstream.nim b/src/io/socketstream.nim index 28b15c11..7fe7e831 100644 --- a/src/io/socketstream.nim +++ b/src/io/socketstream.nim @@ -57,62 +57,27 @@ proc sockClose(s: Stream) = {.cast(tags: []).}: #...sigh let s = SocketStream(s) s.source.close() +{.compile: "sendfd.c".} +proc sendfd(sock: SocketHandle, fd: cint): int {.importc.} + # See https://stackoverflow.com/a/4491203 proc sendFileHandle*(s: SocketStream, fd: FileHandle) = assert not s.source.hasDataBuffered - var hdr: Tmsghdr - var iov: IOVec - var space: csize_t - {.emit: [ - space, """ = CMSG_SPACE(sizeof(int));""", - ].} - var cmsgbuf = alloc(cast[int](space)) - var buf = char(0) - iov.iov_base = addr buf - iov.iov_len = csize_t(1) - zeroMem(addr hdr, sizeof(hdr)) - hdr.msg_iov = addr iov - hdr.msg_iovlen = 1 - hdr.msg_control = cmsgbuf - # ...sigh - {.emit: [ - hdr.msg_controllen, """ = CMSG_LEN(sizeof(int));""", - ].} - let cmsg = CMSG_FIRSTHDR(addr hdr) - # FileHandle is cint, so sizeof(FileHandle) in c is sizeof(int). - when sizeof(FileHandle) != sizeof(cint): - error("Or not...") - {.emit: [ - cmsg.cmsg_len, """ = CMSG_LEN(sizeof(int));""" - ].} - cmsg.cmsg_level = SOL_SOCKET - cmsg.cmsg_type = SCM_RIGHTS - cast[ptr FileHandle](CMSG_DATA(cmsg))[] = fd - let n = sendmsg(s.source.getFd(), addr hdr, 0) - dealloc(cmsgbuf) - assert n == int(iov.iov_len) #TODO remove this + let n = sendfd(s.source.getFd(), cint(fd)) + if n < -1: + raisePosixIOError() + assert n == 1 # we send a single nul byte as buf + +{.compile: "recvfd.c".} +proc recvfd(sock: SocketHandle, fdout: ptr cint): int {.importc.} proc recvFileHandle*(s: SocketStream): FileHandle = assert not s.source.hasDataBuffered - var iov: IOVec - var hdr: Tmsghdr - var buf: char - var cmsgbuf = alloc(CMSG_SPACE(csize_t(sizeof(FileHandle)))) - iov.iov_base = addr buf - iov.iov_len = 1 - zeroMem(addr hdr, sizeof(hdr)) - hdr.msg_iov = addr iov - hdr.msg_iovlen = 1 - hdr.msg_control = cmsgbuf - {.emit: [ - hdr.msg_controllen, """ = CMSG_SPACE(sizeof(int));""" - ].} - let n = recvmsg(s.source.getFd(), addr hdr, 0) - assert n != 0, "Unexpected EOF" #TODO remove this - assert n > 0, "Failed to receive message " & $osLastError() #TODO remove this - var cmsg = CMSG_FIRSTHDR(addr hdr) - result = cast[ptr FileHandle](CMSG_DATA(cmsg))[] - dealloc(cmsgbuf) + var fd: cint + let n = recvfd(s.source.getFd(), addr fd) + if n < 0: + raisePosixIOError() + return FileHandle(fd) func newSocketStream*(): SocketStream = return SocketStream( |