From 2f49216e15741e2f388ff641f3ea7d2cdb89d03c Mon Sep 17 00:00:00 2001 From: Christian Ulrich Date: Thu, 11 Jun 2020 16:18:56 +0200 Subject: [PATCH] implement asyncRecvMsg --- asyncutils.nim | 55 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/asyncutils.nim b/asyncutils.nim index d536261..5b9afc1 100644 --- a/asyncutils.nim +++ b/asyncutils.nim @@ -16,7 +16,8 @@ from posix import CMSG_FIRSTHDR, CMSG_LEN, CMSG_DATA, - sendmsg + sendmsg, + recvmsg ## asyncReadline as discussed at https://github.com/nim-lang/Nim/issues/11564 proc asyncReadline*(): Future[string] = @@ -90,3 +91,55 @@ proc asyncSendMsg*(fd: AsyncFD, addWrite(fd, cb) return retFuture + +proc asyncRecvMsg*(fd: AsyncFD, + size: int): Future[tuple[data: string, ancillaryFd: Option[AsyncFD]]] = + var retFuture = newFuture[ + tuple[data: string, ancillaryFd: Option[AsyncFD]] + ]("asyncRecvMsg") + + proc cb(sock: AsyncFD): bool = + result = true + + var dataBuffer = newString(size) + var iovec = IOVec(iov_base: dataBuffer.cstring, + iov_len: dataBuffer.len.csize_t) + let cmsgBufferLen = CMSG_SPACE(sizeof(AsyncFD).csize_t) + let cmsgBuffer = newString(cmsgBufferLen) + var msg = Tmsghdr(msg_iov: addr iovec, + msg_iovlen: 1, + msg_control: cmsgBuffer.cstring, + msg_controllen: cmsgBufferLen) + let cmsg: ptr Tcmsghdr = CMSG_FIRSTHDR(addr msg) + cmsg.cmsg_len = 0 + cmsg.cmsg_level = 0 + cmsg.cmsg_type = 0 + + let res = recvmsg(sock.SocketHandle, addr msg, 0) + if res < 0: + let lastError = osLastError() + if lastError.int32 != EINTR and + lastError.int32 != EWOULDBLOCK and + lastError.int32 != EAGAIN: + retFuture.fail(newOSError(lastError)) + else: + result = false + return + + var ancillaryData = none(AsyncFD) + if cmsg.cmsg_len > 0: + if cmsg.cmsg_len == CMSG_LEN(sizeof(AsyncFD).csize_t) and + cmsg.cmsg_level == SOL_SOCKET and + cmsg.cmsg_type == SCM_RIGHTS: + var ancillaryFd: AsyncFD + copyMem(addr ancillaryFd, CMSG_DATA(cmsg), sizeof(AsyncFD)) + ancillaryData = some(ancillaryFd) + else: + retFuture.fail(newException(ValueError, "unexpected ancillary data")) + return + + dataBuffer.setLen(msg.msg_iov.iov_len) + retFuture.complete((dataBuffer, ancillaryData)) + + addRead(fd, cb) + return retFuture