about summary refs log tree commit diff stats
path: root/src/io
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2023-12-18 15:51:48 +0100
committerbptato <nincsnevem662@gmail.com>2023-12-18 15:51:48 +0100
commita8022d1cbfe4c1a1a33ec7c8b1d2d5935d89e933 (patch)
treec3694b2610be607aa53cd93e3b5823876eef9b91 /src/io
parenta3b2d9189f3b25c7cf79985beac843cc46c37cfc (diff)
downloadchawan-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.c32
-rw-r--r--src/io/sendfd.c28
-rw-r--r--src/io/socketstream.nim65
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(