about summary refs log tree commit diff stats
path: root/src/io
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-10-20 16:54:40 +0200
committerbptato <nincsnevem662@gmail.com>2024-10-20 16:54:40 +0200
commitd29105fa71f315816ce03c1e5f89423b65b3b389 (patch)
tree7a46c8ce69328ce0ad2659d123e264a8e8cf6c93 /src/io
parentddb0ba9eb1454b15ba6db7c109ce23c448ddd66e (diff)
downloadchawan-d29105fa71f315816ce03c1e5f89423b65b3b389.tar.gz
dynstream: refactor
* consistently use cint instead of FileHandle
	- this was another remnant of winapi support; on posix, they are
	  the same.
* move "blocking" field to PosixStream
* recvFileHandle -> recvFd, sendFileHandle -> sendFd
* merge serversocket into dynstream
* merge auxiliary C functions into dynstream_aux
Diffstat (limited to 'src/io')
-rw-r--r--src/io/bind_unix.c31
-rw-r--r--src/io/bufreader.nim4
-rw-r--r--src/io/bufwriter.nim4
-rw-r--r--src/io/connect_unix.c31
-rw-r--r--src/io/dynstream.nim108
-rw-r--r--src/io/dynstream_aux.c110
-rw-r--r--src/io/recvfd.c32
-rw-r--r--src/io/sendfd.c28
-rw-r--r--src/io/serversocket.nim74
9 files changed, 198 insertions, 224 deletions
diff --git a/src/io/bind_unix.c b/src/io/bind_unix.c
deleted file mode 100644
index ea0140cf..00000000
--- a/src/io/bind_unix.c
+++ /dev/null
@@ -1,31 +0,0 @@
-#include <stddef.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <string.h>
-
-int bind_unix_from_c(int socket, const char *path, int pathlen)
-{
-	struct sockaddr_un sa = {
-		.sun_family = AF_UNIX
-	};
-	int len = offsetof(struct sockaddr_un, sun_path) + pathlen + 1;
-
-	memcpy(sa.sun_path, path, pathlen + 1);
-	return bind(socket, (struct sockaddr *)&sa, len);
-}
-
-#ifdef __FreeBSD__
-#include <fcntl.h>
-
-int bindat_unix_from_c(int fd, int socket, const char *path, int pathlen)
-{
-	struct sockaddr_un sa = {
-		.sun_family = AF_UNIX
-	};
-	int len = offsetof(struct sockaddr_un, sun_path) + pathlen + 1;
-
-	memcpy(sa.sun_path, path, pathlen + 1);
-	return bindat(fd, socket, (struct sockaddr *)&sa, len);
-}
-#endif
diff --git a/src/io/bufreader.nim b/src/io/bufreader.nim
index 7813bd93..c7ec04b1 100644
--- a/src/io/bufreader.nim
+++ b/src/io/bufreader.nim
@@ -8,7 +8,7 @@ import types/opt
 type BufferedReader* = object
   buffer: seq[uint8]
   bufIdx: int
-  recvAux*: seq[FileHandle] #TODO assert on unused ones
+  recvAux*: seq[cint] #TODO assert on unused ones
 
 proc sread*(reader: var BufferedReader; n: var SomeNumber)
 proc sread*[T](reader: var BufferedReader; s: var set[T])
@@ -34,7 +34,7 @@ proc initReader*(stream: DynStream; len, auxLen: int): BufferedReader =
   )
   stream.recvDataLoop(reader.buffer)
   for i in 0 ..< auxLen:
-    reader.recvAux.add(SocketStream(stream).recvFileHandle())
+    reader.recvAux.add(SocketStream(stream).recvFd())
   return reader
 
 proc initPacketReader*(stream: DynStream): BufferedReader =
diff --git a/src/io/bufwriter.nim b/src/io/bufwriter.nim
index 5b07e0d6..9c3d6c79 100644
--- a/src/io/bufwriter.nim
+++ b/src/io/bufwriter.nim
@@ -13,7 +13,7 @@ type BufferedWriter* = object
   buffer: ptr UncheckedArray[uint8]
   bufSize: int
   bufLen: int
-  sendAux*: seq[FileHandle]
+  sendAux*: seq[cint]
 
 proc `=destroy`(writer: var BufferedWriter) =
   if writer.buffer != nil:
@@ -53,7 +53,7 @@ proc flush*(writer: var BufferedWriter) =
   copyMem(writer.buffer, unsafeAddr len[0], sizeof(len))
   writer.stream.sendDataLoop(writer.buffer, writer.bufLen)
   for i in countdown(writer.sendAux.high, 0):
-    SocketStream(writer.stream).sendFileHandle(writer.sendAux[i])
+    SocketStream(writer.stream).sendFd(writer.sendAux[i])
   writer.bufLen = 0
   writer.stream.sflush()
 
diff --git a/src/io/connect_unix.c b/src/io/connect_unix.c
deleted file mode 100644
index f5bdbfa1..00000000
--- a/src/io/connect_unix.c
+++ /dev/null
@@ -1,31 +0,0 @@
-#include <stddef.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <string.h>
-
-int connect_unix_from_c(int socket, const char *path, int pathlen)
-{
-	struct sockaddr_un sa = {
-		.sun_family = AF_UNIX
-	};
-	int len = offsetof(struct sockaddr_un, sun_path) + pathlen + 1;
-
-	memcpy(sa.sun_path, path, pathlen + 1);
-	return connect(socket, (struct sockaddr *)&sa, len);
-}
-
-#ifdef __FreeBSD__
-#include <fcntl.h>
-
-int connectat_unix_from_c(int fd, int socket, const char *path, int pathlen)
-{
-	struct sockaddr_un sa = {
-		.sun_family = AF_UNIX
-	};
-	int len = offsetof(struct sockaddr_un, sun_path) + pathlen + 1;
-
-	memcpy(sa.sun_path, path, pathlen + 1);
-	return connectat(fd, socket, (struct sockaddr *)&sa, len);
-}
-#endif
diff --git a/src/io/dynstream.nim b/src/io/dynstream.nim
index 792f2ce8..5a106491 100644
--- a/src/io/dynstream.nim
+++ b/src/io/dynstream.nim
@@ -4,7 +4,6 @@ import std/posix
 type
   DynStream* = ref object of RootObj
     isend*: bool
-    blocking*: bool #TODO move to posixstream
     closed: bool
 
 # Semantics of this function are those of POSIX read(3): that is, it may return
@@ -95,6 +94,7 @@ proc recvAll*(s: DynStream): string =
 type
   PosixStream* = ref object of DynStream
     fd*: cint
+    blocking*: bool
 
   ErrorAgain* = object of IOError
   ErrorBadFD* = object of IOError
@@ -187,11 +187,11 @@ proc safeClose*(ps: PosixStream) =
   else:
     ps.sclose()
 
-proc newPosixStream*(fd: FileHandle): PosixStream =
-  return PosixStream(fd: cint(fd), blocking: true)
+proc newPosixStream*(fd: cint): PosixStream =
+  return PosixStream(fd: fd, blocking: true)
 
 proc newPosixStream*(fd: SocketHandle): PosixStream =
-  return PosixStream(fd: cint(fd), blocking: true)
+  return newPosixStream(cint(fd))
 
 proc newPosixStream*(path: string; flags, mode: cint): PosixStream =
   let fd = open(cstring(path), flags, mode)
@@ -299,37 +299,42 @@ proc drain*(ps: PosixStream) =
 
 type SocketStream* = ref object of PosixStream
 
-{.compile: "sendfd.c".}
+# Auxiliary functions in C, because writing them portably in Nim is
+# a pain.
+{.compile: "dynstream_aux.c".}
+
+proc bind_unix_from_c(fd: cint; path: cstring; pathlen: cint): cint {.importc.}
+proc connect_unix_from_c(fd: cint; path: cstring; pathlen: cint): cint
+  {.importc.}
+
+when defined(freebsd):
+  # capsicum stuff
+  proc unlinkat(dfd: cint; path: cstring; flag: cint): cint
+    {.importc, header: "<unistd.h>".}
+  proc bindat_unix_from_c(dfd, sock: cint; path: cstring; pathlen: cint): cint
+    {.importc.}
+  proc connectat_unix_from_c(baseFd, sockFd: cint; rel_path: cstring;
+    rel_pathlen: cint): cint {.importc.}
+
 proc sendfd(sock, fd: cint): int {.importc.}
+proc recvfd(sock: cint; fdout: var cint): int {.importc.}
 
-proc sendFileHandle*(s: SocketStream; fd: FileHandle) =
-  let n = sendfd(s.fd, cint(fd))
+proc sendFd*(s: SocketStream; fd: cint) =
+  let n = sendfd(s.fd, fd)
   if n < 0:
     raisePosixIOError()
   assert n == 1 # we send a single nul byte as buf
 
-{.compile: "recvfd.c".}
-proc recvfd(sock: cint; fdout: ptr cint): int {.importc.}
-
-proc recvFileHandle*(s: SocketStream): FileHandle =
+proc recvFd*(s: SocketStream): cint =
   var fd: cint
-  let n = recvfd(s.fd, addr fd)
+  let n = recvfd(s.fd, fd)
   if n < 0:
     raisePosixIOError()
-  return FileHandle(fd)
+  return fd
 
 method seek*(s: SocketStream; off: int) =
   doAssert false
 
-# see serversocket.nim for an explanation
-{.compile: "connect_unix.c".}
-proc connect_unix_from_c(fd: cint; path: cstring; pathlen: cint): cint
-  {.importc.}
-when defined(freebsd):
-  # for FreeBSD/capsicum
-  proc connectat_unix_from_c(baseFd, sockFd: cint; rel_path: cstring;
-    rel_pathlen: cint): cint {.importc.}
-
 const SocketPathPrefix = "cha_sock_"
 proc getSocketName*(pid: int): string =
   SocketPathPrefix & $pid
@@ -417,7 +422,7 @@ proc reallyFlush*(s: BufStream) =
     s.source.sendDataLoop(s.writeBuffer)
 
 proc newBufStream*(ps: PosixStream; registerFun: proc(fd: int)): BufStream =
-  return BufStream(source: ps, blocking: ps.blocking, registerFun: registerFun)
+  return BufStream(source: ps, registerFun: registerFun)
 
 type
   DynFileStream* = ref object of DynStream
@@ -446,10 +451,65 @@ method sflush*(s: DynFileStream) =
   s.file.flushFile()
 
 proc newDynFileStream*(file: File): DynFileStream =
-  return DynFileStream(file: file, blocking: true)
+  return DynFileStream(file: file)
 
 proc newDynFileStream*(path: string): DynFileStream =
   var file: File
   if file.open(path):
     return newDynFileStream(path)
   return nil
+
+type ServerSocket* = ref object
+  fd*: cint
+  path*: string
+  dfd: cint
+
+proc setBlocking*(ssock: ServerSocket; blocking: bool) =
+  let ofl = fcntl(ssock.fd, F_GETFL, 0)
+  if blocking:
+    discard fcntl(ssock.fd, F_SETFL, ofl and not O_NONBLOCK)
+  else:
+    discard fcntl(ssock.fd, F_SETFL, ofl and O_NONBLOCK)
+
+proc newServerSocket*(fd: cint; sockDir: string; sockDirFd: cint; pid: int):
+    ServerSocket =
+  let path = getSocketPath(sockDir, pid)
+  return ServerSocket(fd: cint(fd), path: path, dfd: sockDirFd)
+
+proc newServerSocket*(sockDir: string; sockDirFd: cint; pid: int): ServerSocket =
+  let fd = cint(socket(AF_UNIX, SOCK_STREAM, IPPROTO_IP))
+  let ssock = newServerSocket(fd, sockDir, sockDirFd, pid)
+  if sockDirFd == -1:
+    discard tryRemoveFile(ssock.path)
+    if bind_unix_from_c(fd, cstring(ssock.path), cint(ssock.path.len)) != 0:
+      raiseOSError(osLastError())
+  else:
+    when defined(freebsd):
+      let name = getSocketName(pid)
+      discard unlinkat(sockDirFd, cstring(name), 0)
+      if bindat_unix_from_c(sockDirFd, fd, cstring(name), cint(name.len)) != 0:
+        raiseOSError(osLastError())
+    else:
+      # shouldn't have sockDirFd on other architectures
+      doAssert false
+  if listen(SocketHandle(fd), 128) != 0:
+    raiseOSError(osLastError())
+  return ssock
+
+proc close*(ssock: ServerSocket; unlink = true) =
+  discard close(ssock.fd)
+  if unlink:
+    when defined(freebsd):
+      if ssock.dfd != -1:
+        discard unlinkat(ssock.dfd, cstring(ssock.path), 0)
+        return
+    discard tryRemoveFile(ssock.path)
+
+proc acceptSocketStream*(ssock: ServerSocket; blocking = true): SocketStream =
+  let fd = cint(accept(SocketHandle(ssock.fd), nil, nil))
+  if fd == -1:
+    return nil
+  let ss = SocketStream(fd: fd, blocking: false)
+  if not blocking:
+    ss.setBlocking(false)
+  return ss
diff --git a/src/io/dynstream_aux.c b/src/io/dynstream_aux.c
new file mode 100644
index 00000000..651157f8
--- /dev/null
+++ b/src/io/dynstream_aux.c
@@ -0,0 +1,110 @@
+#include <stddef.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <string.h>
+
+int bind_unix_from_c(int socket, const char *path, int pathlen)
+{
+	struct sockaddr_un sa = {
+		.sun_family = AF_UNIX
+	};
+	int len = offsetof(struct sockaddr_un, sun_path) + pathlen + 1;
+
+	memcpy(sa.sun_path, path, pathlen + 1);
+	return bind(socket, (struct sockaddr *)&sa, len);
+}
+
+int connect_unix_from_c(int socket, const char *path, int pathlen)
+{
+	struct sockaddr_un sa = {
+		.sun_family = AF_UNIX
+	};
+	int len = offsetof(struct sockaddr_un, sun_path) + pathlen + 1;
+
+	memcpy(sa.sun_path, path, pathlen + 1);
+	return connect(socket, (struct sockaddr *)&sa, len);
+}
+
+#ifdef __FreeBSD__
+#include <fcntl.h>
+
+int bindat_unix_from_c(int fd, int socket, const char *path, int pathlen)
+{
+	struct sockaddr_un sa = {
+		.sun_family = AF_UNIX
+	};
+	int len = offsetof(struct sockaddr_un, sun_path) + pathlen + 1;
+
+	memcpy(sa.sun_path, path, pathlen + 1);
+	return bindat(fd, socket, (struct sockaddr *)&sa, len);
+}
+
+int connectat_unix_from_c(int fd, int socket, const char *path, int pathlen)
+{
+	struct sockaddr_un sa = {
+		.sun_family = AF_UNIX
+	};
+	int len = offsetof(struct sockaddr_un, sun_path) + pathlen + 1;
+
+	memcpy(sa.sun_path, path, pathlen + 1);
+	return connectat(fd, socket, (struct sockaddr *)&sa, len);
+}
+#endif
+
+/*
+ * 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);
+}
+
+/*
+ * 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/recvfd.c b/src/io/recvfd.c
deleted file mode 100644
index de376c39..00000000
--- a/src/io/recvfd.c
+++ /dev/null
@@ -1,32 +0,0 @@
-#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
deleted file mode 100644
index 578009c2..00000000
--- a/src/io/sendfd.c
+++ /dev/null
@@ -1,28 +0,0 @@
-#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/serversocket.nim b/src/io/serversocket.nim
deleted file mode 100644
index a5b0fd67..00000000
--- a/src/io/serversocket.nim
+++ /dev/null
@@ -1,74 +0,0 @@
-import std/os
-import std/posix
-
-import io/dynstream
-
-type ServerSocket* = ref object
-  fd*: cint
-  path*: string
-  dfd: int #TODO should be cint
-
-# The way stdlib does bindUnix is utterly broken at least on FreeBSD.
-# It seems that just writing it in C is the easiest solution.
-{.compile: "bind_unix.c".}
-proc bind_unix_from_c(fd: cint; path: cstring; pathlen: cint): cint
-  {.importc.}
-
-when defined(freebsd):
-  # capsicum stuff
-  proc unlinkat(dfd: cint; path: cstring; flag: cint): cint
-    {.importc, header: "<unistd.h>".}
-  proc bindat_unix_from_c(dfd, sock: cint; path: cstring; pathlen: cint): cint
-    {.importc.}
-
-proc setBlocking*(ssock: ServerSocket; blocking: bool) =
-  let ofl = fcntl(ssock.fd, F_GETFL, 0)
-  if blocking:
-    discard fcntl(ssock.fd, F_SETFL, ofl and not O_NONBLOCK)
-  else:
-    discard fcntl(ssock.fd, F_SETFL, ofl and O_NONBLOCK)
-
-proc newServerSocket*(fd: cint; sockDir: string; pid, sockDirFd: int):
-    ServerSocket =
-  let path = getSocketPath(sockDir, pid)
-  return ServerSocket(fd: cint(fd), path: path, dfd: sockDirFd)
-
-proc newServerSocket*(sockDir: string; sockDirFd, pid: int): ServerSocket =
-  let fd = cint(socket(AF_UNIX, SOCK_STREAM, IPPROTO_IP))
-  let path = getSocketPath(sockDir, pid)
-  let ssock = ServerSocket(fd: fd, path: path, dfd: sockDirFd)
-  if sockDirFd == -1:
-    discard tryRemoveFile(path)
-    if bind_unix_from_c(fd, cstring(path), cint(path.len)) != 0:
-      raiseOSError(osLastError())
-  else:
-    when defined(freebsd):
-      let name = getSocketName(pid)
-      discard unlinkat(cint(sockDirFd), cstring(name), 0)
-      if bindat_unix_from_c(cint(sockDirFd), fd, cstring(name),
-          cint(name.len)) != 0:
-        raiseOSError(osLastError())
-    else:
-      # shouldn't have sockDirFd on other architectures
-      doAssert false
-  if listen(SocketHandle(fd), 128) != 0:
-    raiseOSError(osLastError())
-  return ssock
-
-proc close*(ssock: ServerSocket; unlink = true) =
-  discard close(ssock.fd)
-  if unlink:
-    when defined(freebsd):
-      if ssock.dfd != -1:
-        discard unlinkat(cint(ssock.dfd), cstring(ssock.path), 0)
-        return
-    discard tryRemoveFile(ssock.path)
-
-proc acceptSocketStream*(ssock: ServerSocket; blocking = true): SocketStream =
-  let fd = cint(accept(SocketHandle(ssock.fd), nil, nil))
-  if fd == -1:
-    return nil
-  let ss = SocketStream(fd: fd, blocking: false)
-  if not blocking:
-    ss.setBlocking(false)
-  return ss