import asyncdispatch from net import BufferSize from os import osLastError, newOsError from posix import EINTR, EWOULDBLOCK, EAGAIN, IOVec, Tmsghdr, Tcmsghdr, SocketHandle, CMSG_FIRSTHDR, CMSG_NXTHDR, CMSG_DATA, SOL_SOCKET, SCM_RIGHTS, recvmsg type ControlMessage* = object level*: int msgType*: int data*: string proc getFd*(cmsg: ControlMessage): AsyncFD = echo "cmsg.data.len: ", cmsg.data.len if cmsg.level != SOL_SOCKET or cmsg.msgType != SCM_RIGHTS or cmsg.data.len != sizeof(AsyncFD): raise(newException(ValueError, "unexpected ancillary data")) result = cast[ptr AsyncFD](cmsg.data.cstring)[] proc asyncRecvMsg*(fd: AsyncFD, size: int = BufferSize, cmsgSize: int = BufferSize): Future[tuple[data: string, cmsgs: seq[ControlMessage]]] = var retFuture = newFuture[tuple[data: string, cmsgs: seq[ControlMessage]]]("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) var cmsgBuffer = newString(cmsgSize) zeroMem(cmsgBuffer.cstring, cmsgBuffer.len) var msg = Tmsghdr(msg_iov: addr iovec, msg_iovlen: 1, msg_control: addr cmsgBuffer[0], msg_controllen: cmsgSize.csize_t) 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 cmsgs = newSeq[ControlMessage]() var cmsgHeader = CMSG_FIRSTHDR(addr msg) while cmsgHeader != nil: let dataLen = cmsgHeader.cmsg_len - sizeof(Tcmsghdr).csize_t var cmsg = ControlMessage(level: cmsgHeader.cmsg_level, msgType: cmsgHeader.cmsg_type, data: newString(dataLen)) copyMem(cmsg.data.cstring, CMSG_DATA(cmsgHeader), cmsgHeader.cmsg_len) cmsgs.add(cmsg) cmsgHeader = CMSG_NXTHDR(addr msg, cmsgHeader) dataBuffer.setLen(res) retFuture.complete((dataBuffer, cmsgs)) addRead(fd, cb) return retFuture