Index: sys/compat/cloudabi/cloudabi_sock.c =================================================================== --- sys/compat/cloudabi/cloudabi_sock.c +++ sys/compat/cloudabi/cloudabi_sock.c @@ -27,14 +27,62 @@ __FBSDID("$FreeBSD$"); #include +#include +#include +#include +#include +#include #include +#include #include #include #include #include +#include + +#include + #include #include +#include + +/* Converts FreeBSD's struct sockaddr to CloudABI's cloudabi_sockaddr_t. */ +void +cloudabi_convert_sockaddr(const struct sockaddr *sa, socklen_t sal, + cloudabi_sockaddr_t *rsa) +{ + const struct sockaddr_in *sin; + const struct sockaddr_in6 *sin6; + + /* Zero-sized socket address. */ + if (sal < offsetof(struct sockaddr, sa_family) + sizeof(sa->sa_family)) + return; + + switch (sa->sa_family) { + case AF_INET: + if (sal < sizeof(struct sockaddr_in)) + return; + sin = (const struct sockaddr_in *)sa; + rsa->sa_family = CLOUDABI_AF_INET; + memcpy(&rsa->sa_inet.addr, &sin->sin_addr, + sizeof(rsa->sa_inet.addr)); + rsa->sa_inet.port = ntohs(sin->sin_port); + return; + case AF_INET6: + if (sal < sizeof(struct sockaddr_in6)) + return; + sin6 = (const struct sockaddr_in6 *)sa; + rsa->sa_family = CLOUDABI_AF_INET6; + memcpy(&rsa->sa_inet6.addr, &sin6->sin6_addr, + sizeof(rsa->sa_inet6.addr)); + rsa->sa_inet6.port = ntohs(sin6->sin6_port); + return; + case AF_UNIX: + rsa->sa_family = CLOUDABI_AF_UNIX; + return; + } +} /* Copies a pathname into a UNIX socket address structure. */ static int @@ -62,9 +110,27 @@ cloudabi_sys_sock_accept(struct thread *td, struct cloudabi_sys_sock_accept_args *uap) { + struct sockaddr *sa; + cloudabi_sockstat_t ss = {}; + socklen_t sal; + int error; - /* Not implemented. */ - return (ENOSYS); + if (uap->buf == NULL) { + /* Only return the new file descriptor number. */ + return (kern_accept(td, uap->s, NULL, NULL, NULL)); + } else { + /* Also return properties of the new socket descriptor. */ + sal = MAX(sizeof(struct sockaddr_in), + sizeof(struct sockaddr_in6)); + error = kern_accept(td, uap->s, (void *)&sa, &sal, NULL); + if (error != 0) + return (error); + + /* TODO(ed): Fill the other members of cloudabi_sockstat_t. */ + cloudabi_convert_sockaddr(sa, sal, &ss.ss_peername); + free(sa, M_SONAME); + return (copyout(&ss, uap->buf, sizeof(ss))); + } } int @@ -134,7 +200,51 @@ cloudabi_sys_sock_stat_get(struct thread *td, struct cloudabi_sys_sock_stat_get_args *uap) { + cloudabi_sockstat_t ss = {}; + cap_rights_t rights; + struct file *fp; + struct sockaddr *sa; + struct socket *so; + int error; + + error = getsock_cap(td, uap->fd, cap_rights_init(&rights, + CAP_GETSOCKOPT | CAP_GETPEERNAME | CAP_GETSOCKNAME), &fp, NULL); + if (error != 0) + return (error); + so = fp->f_data; + + CURVNET_SET(so->so_vnet); + + /* Set ss_sockname. */ + error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); + if (error == 0) { + cloudabi_convert_sockaddr(sa, sa->sa_len, &ss.ss_sockname); + free(sa, M_SONAME); + } + + /* Set ss_peername. */ + if ((so->so_state & (SS_ISCONNECTED | SS_ISCONFIRMING)) != 0) { + error = so->so_proto->pr_usrreqs->pru_peeraddr(so, &sa); + if (error == 0) { + cloudabi_convert_sockaddr(sa, sa->sa_len, + &ss.ss_peername); + free(sa, M_SONAME); + } + } + + CURVNET_RESTORE(); + + /* Set ss_error. */ + SOCK_LOCK(so); + ss.ss_error = so->so_error; + if ((uap->flags & CLOUDABI_SOCKSTAT_CLEAR_ERROR) != 0) + so->so_error = 0; + SOCK_UNLOCK(so); + + /* Set ss_state. */ + if ((so->so_options & SO_ACCEPTCONN) != 0) + ss.ss_state |= CLOUDABI_SOCKSTAT_ACCEPTCONN; - /* Not implemented. */ - return (ENOSYS); + fdrop(fp, td); + return (copyout(&ss, uap->buf, sizeof(ss))); } Index: sys/compat/cloudabi/cloudabi_util.h =================================================================== --- sys/compat/cloudabi/cloudabi_util.h +++ sys/compat/cloudabi/cloudabi_util.h @@ -28,6 +28,8 @@ #ifndef _CLOUDABI_UTIL_H_ #define _CLOUDABI_UTIL_H_ +#include + #include struct thread; @@ -40,6 +42,10 @@ /* Converts a FreeBSD errno to a CloudABI errno. */ cloudabi_errno_t cloudabi_convert_errno(int); +/* Converts FreeBSD's struct sockaddr to CloudABI's cloudabi_sockaddr_t. */ +void cloudabi_convert_sockaddr(const struct sockaddr *, socklen_t, + cloudabi_sockaddr_t *); + /* Converts a struct timespec to a CloudABI timestamp. */ int cloudabi_convert_timespec(const struct timespec *, cloudabi_timestamp_t *);