summaryrefslogtreecommitdiffstats
path: root/sys/compat/cloudabi/cloudabi_sock.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/compat/cloudabi/cloudabi_sock.c')
-rw-r--r--sys/compat/cloudabi/cloudabi_sock.c133
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);
+}
OpenPOWER on IntegriCloud