diff options
Diffstat (limited to 'sys/compat/cloudabi/cloudabi_sock.c')
-rw-r--r-- | sys/compat/cloudabi/cloudabi_sock.c | 133 |
1 files changed, 129 insertions, 4 deletions
diff --git a/sys/compat/cloudabi/cloudabi_sock.c b/sys/compat/cloudabi/cloudabi_sock.c index bbecc49..9d0e036 100644 --- a/sys/compat/cloudabi/cloudabi_sock.c +++ b/sys/compat/cloudabi/cloudabi_sock.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2015 Nuxi, https://nuxi.nl/ + * Copyright (c) 2015-2017 Nuxi, https://nuxi.nl/ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,7 +30,9 @@ __FBSDID("$FreeBSD$"); #include <sys/capsicum.h> #include <sys/lock.h> #include <sys/malloc.h> +#include <sys/mbuf.h> #include <sys/mutex.h> +#include <sys/proc.h> #include <sys/protosw.h> #include <sys/socket.h> #include <sys/socketvar.h> @@ -48,7 +50,7 @@ __FBSDID("$FreeBSD$"); #include <compat/cloudabi/cloudabi_util.h> /* Converts FreeBSD's struct sockaddr to CloudABI's cloudabi_sockaddr_t. */ -void +static void cloudabi_convert_sockaddr(const struct sockaddr *sa, socklen_t sal, cloudabi_sockaddr_t *rsa) { @@ -140,7 +142,7 @@ cloudabi_sys_sock_bind(struct thread *td, struct sockaddr_un sun; int error; - error = copyin_sockaddr_un(uap->path, uap->pathlen, &sun); + error = copyin_sockaddr_un(uap->path, uap->path_len, &sun); if (error != 0) return (error); return (kern_bindat(td, uap->fd, uap->sock, (struct sockaddr *)&sun)); @@ -153,7 +155,7 @@ cloudabi_sys_sock_connect(struct thread *td, struct sockaddr_un sun; int error; - error = copyin_sockaddr_un(uap->path, uap->pathlen, &sun); + error = copyin_sockaddr_un(uap->path, uap->path_len, &sun); if (error != 0) return (error); return (kern_connectat(td, uap->fd, uap->sock, @@ -243,3 +245,126 @@ cloudabi_sys_sock_stat_get(struct thread *td, fdrop(fp, td); return (copyout(&ss, uap->buf, sizeof(ss))); } + +int +cloudabi_sock_recv(struct thread *td, cloudabi_fd_t fd, struct iovec *data, + size_t datalen, cloudabi_fd_t *fds, size_t fdslen, + cloudabi_msgflags_t flags, size_t *rdatalen, size_t *rfdslen, + cloudabi_sockaddr_t *peername, cloudabi_msgflags_t *rflags) +{ + struct sockaddr_storage ss; + struct msghdr hdr = { + .msg_name = &ss, + .msg_namelen = sizeof(ss), + .msg_iov = data, + .msg_iovlen = datalen, + }; + struct mbuf *control; + int error; + + /* Convert flags. */ + if (flags & CLOUDABI_MSG_PEEK) + hdr.msg_flags |= MSG_PEEK; + if (flags & CLOUDABI_MSG_WAITALL) + hdr.msg_flags |= MSG_WAITALL; + + control = NULL; + error = kern_recvit(td, fd, &hdr, UIO_SYSSPACE, + fdslen > 0 ? &control : NULL); + if (error != 0) + return (error); + + /* Convert return values. */ + *rdatalen = td->td_retval[0]; + td->td_retval[0] = 0; + *rfdslen = 0; + cloudabi_convert_sockaddr((struct sockaddr *)&ss, + MIN(hdr.msg_namelen, sizeof(ss)), peername); + *rflags = 0; + if (hdr.msg_flags & MSG_EOR) + *rflags |= CLOUDABI_MSG_EOR; + if (hdr.msg_flags & MSG_TRUNC) + *rflags |= CLOUDABI_MSG_TRUNC; + + /* Extract file descriptors from SCM_RIGHTS messages. */ + if (control != NULL) { + struct cmsghdr *chdr; + + hdr.msg_control = mtod(control, void *); + hdr.msg_controllen = control->m_len; + for (chdr = CMSG_FIRSTHDR(&hdr); chdr != NULL; + chdr = CMSG_NXTHDR(&hdr, chdr)) { + if (chdr->cmsg_level == SOL_SOCKET && + chdr->cmsg_type == SCM_RIGHTS) { + size_t nfds; + + nfds = (chdr->cmsg_len - CMSG_LEN(0)) / + sizeof(int); + if (nfds > fdslen) { + /* Unable to store file descriptors. */ + nfds = fdslen; + *rflags |= CLOUDABI_MSG_CTRUNC; + } + error = copyout(CMSG_DATA(chdr), fds, + nfds * sizeof(int)); + if (error != 0) { + m_free(control); + return (error); + } + fds += nfds; + fdslen -= nfds; + *rfdslen += nfds; + } + } + m_free(control); + } + return (0); +} + +int +cloudabi_sock_send(struct thread *td, cloudabi_fd_t fd, struct iovec *data, + size_t datalen, const cloudabi_fd_t *fds, size_t fdslen, + cloudabi_msgflags_t flags, size_t *rdatalen) +{ + struct msghdr hdr = { + .msg_iov = data, + .msg_iovlen = datalen, + }; + struct mbuf *control; + int error, mflags; + + /* Convert flags. */ + mflags = MSG_NOSIGNAL; + if (flags & CLOUDABI_MSG_EOR) + mflags |= MSG_EOR; + + /* Convert file descriptor array to an SCM_RIGHTS message. */ + if (fdslen > MCLBYTES || CMSG_SPACE(fdslen * sizeof(int)) > MCLBYTES) { + return (EINVAL); + } else if (fdslen > 0) { + struct cmsghdr *chdr; + + control = m_get2(CMSG_SPACE(fdslen * sizeof(int)), + M_WAITOK, MT_CONTROL, 0); + control->m_len = CMSG_SPACE(fdslen * sizeof(int)); + + chdr = mtod(control, struct cmsghdr *); + chdr->cmsg_len = CMSG_LEN(fdslen * sizeof(int)); + chdr->cmsg_level = SOL_SOCKET; + chdr->cmsg_type = SCM_RIGHTS; + error = copyin(fds, CMSG_DATA(chdr), fdslen * sizeof(int)); + if (error != 0) { + m_free(control); + return (error); + } + } else { + control = NULL; + } + + error = kern_sendit(td, fd, &hdr, mflags, control, UIO_USERSPACE); + if (error != 0) + return (error); + *rdatalen = td->td_retval[0]; + td->td_retval[0] = 0; + return (0); +} |