]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/compat/cloudabi/cloudabi_sock.c
Sync CloudABI compatibility against the latest upstream version (v0.13).
[FreeBSD/FreeBSD.git] / sys / compat / cloudabi / cloudabi_sock.c
1 /*-
2  * Copyright (c) 2015-2017 Nuxi, https://nuxi.nl/
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include <sys/param.h>
30 #include <sys/capsicum.h>
31 #include <sys/lock.h>
32 #include <sys/malloc.h>
33 #include <sys/mbuf.h>
34 #include <sys/mutex.h>
35 #include <sys/proc.h>
36 #include <sys/protosw.h>
37 #include <sys/socket.h>
38 #include <sys/socketvar.h>
39 #include <sys/syscallsubr.h>
40 #include <sys/systm.h>
41
42 #include <net/vnet.h>
43
44 #include <netinet/in.h>
45
46 #include <contrib/cloudabi/cloudabi_types_common.h>
47
48 #include <compat/cloudabi/cloudabi_proto.h>
49 #include <compat/cloudabi/cloudabi_util.h>
50
51 int
52 cloudabi_sys_sock_accept(struct thread *td,
53     struct cloudabi_sys_sock_accept_args *uap)
54 {
55
56         return (kern_accept(td, uap->sock, NULL, NULL, NULL));
57 }
58
59 int
60 cloudabi_sys_sock_shutdown(struct thread *td,
61     struct cloudabi_sys_sock_shutdown_args *uap)
62 {
63         int how;
64
65         switch (uap->how) {
66         case CLOUDABI_SHUT_RD:
67                 how = SHUT_RD;
68                 break;
69         case CLOUDABI_SHUT_WR:
70                 how = SHUT_WR;
71                 break;
72         case CLOUDABI_SHUT_RD | CLOUDABI_SHUT_WR:
73                 how = SHUT_RDWR;
74                 break;
75         default:
76                 return (EINVAL);
77         }
78
79         return (kern_shutdown(td, uap->sock, how));
80 }
81
82 int
83 cloudabi_sys_sock_stat_get(struct thread *td,
84     struct cloudabi_sys_sock_stat_get_args *uap)
85 {
86         cloudabi_sockstat_t ss = {};
87         cap_rights_t rights;
88         struct file *fp;
89         struct socket *so;
90         int error;
91
92         error = getsock_cap(td, uap->sock, cap_rights_init(&rights,
93             CAP_GETSOCKOPT, CAP_GETPEERNAME, CAP_GETSOCKNAME), &fp, NULL, NULL);
94         if (error != 0)
95                 return (error);
96         so = fp->f_data;
97
98         /* Set ss_error. */
99         SOCK_LOCK(so);
100         ss.ss_error = cloudabi_convert_errno(so->so_error);
101         if ((uap->flags & CLOUDABI_SOCKSTAT_CLEAR_ERROR) != 0)
102                 so->so_error = 0;
103         SOCK_UNLOCK(so);
104
105         /* Set ss_state. */
106         if ((so->so_options & SO_ACCEPTCONN) != 0)
107                 ss.ss_state |= CLOUDABI_SOCKSTATE_ACCEPTCONN;
108
109         fdrop(fp, td);
110         return (copyout(&ss, uap->buf, sizeof(ss)));
111 }
112
113 int
114 cloudabi_sock_recv(struct thread *td, cloudabi_fd_t fd, struct iovec *data,
115     size_t datalen, cloudabi_fd_t *fds, size_t fdslen,
116     cloudabi_riflags_t flags, size_t *rdatalen, size_t *rfdslen,
117     cloudabi_roflags_t *rflags)
118 {
119         struct msghdr hdr = {
120                 .msg_iov = data,
121                 .msg_iovlen = datalen,
122         };
123         struct mbuf *control;
124         int error;
125
126         /* Convert flags. */
127         if (flags & CLOUDABI_SOCK_RECV_PEEK)
128                 hdr.msg_flags |= MSG_PEEK;
129         if (flags & CLOUDABI_SOCK_RECV_WAITALL)
130                 hdr.msg_flags |= MSG_WAITALL;
131
132         control = NULL;
133         error = kern_recvit(td, fd, &hdr, UIO_SYSSPACE,
134             fdslen > 0 ? &control : NULL);
135         if (error != 0)
136                 return (error);
137
138         /* Convert return values. */
139         *rdatalen = td->td_retval[0];
140         td->td_retval[0] = 0;
141         *rfdslen = 0;
142         *rflags = 0;
143         if (hdr.msg_flags & MSG_TRUNC)
144                 *rflags |= CLOUDABI_SOCK_RECV_DATA_TRUNCATED;
145
146         /* Extract file descriptors from SCM_RIGHTS messages. */
147         if (control != NULL) {
148                 struct cmsghdr *chdr;
149
150                 hdr.msg_control = mtod(control, void *);
151                 hdr.msg_controllen = control->m_len;
152                 for (chdr = CMSG_FIRSTHDR(&hdr); chdr != NULL;
153                     chdr = CMSG_NXTHDR(&hdr, chdr)) {
154                         if (chdr->cmsg_level == SOL_SOCKET &&
155                             chdr->cmsg_type == SCM_RIGHTS) {
156                                 size_t nfds;
157
158                                 nfds = (chdr->cmsg_len - CMSG_LEN(0)) /
159                                     sizeof(int);
160                                 if (nfds > fdslen) {
161                                         /* Unable to store file descriptors. */
162                                         nfds = fdslen;
163                                         *rflags |=
164                                             CLOUDABI_SOCK_RECV_FDS_TRUNCATED;
165                                 }
166                                 error = copyout(CMSG_DATA(chdr), fds,
167                                     nfds * sizeof(int));
168                                 if (error != 0) {
169                                         m_free(control);
170                                         return (error);
171                                 }
172                                 fds += nfds;
173                                 fdslen -= nfds;
174                                 *rfdslen += nfds;
175                         }
176                 }
177                 m_free(control);
178         }
179         return (0);
180 }
181
182 int
183 cloudabi_sock_send(struct thread *td, cloudabi_fd_t fd, struct iovec *data,
184     size_t datalen, const cloudabi_fd_t *fds, size_t fdslen, size_t *rdatalen)
185 {
186         struct msghdr hdr = {
187                 .msg_iov = data,
188                 .msg_iovlen = datalen,
189         };
190         struct mbuf *control;
191         int error;
192
193         /* Convert file descriptor array to an SCM_RIGHTS message. */
194         if (fdslen > MCLBYTES || CMSG_SPACE(fdslen * sizeof(int)) > MCLBYTES) {
195                 return (EINVAL);
196         } else if (fdslen > 0) {
197                 struct cmsghdr *chdr;
198
199                 control = m_get2(CMSG_SPACE(fdslen * sizeof(int)),
200                     M_WAITOK, MT_CONTROL, 0);
201                 control->m_len = CMSG_SPACE(fdslen * sizeof(int));
202
203                 chdr = mtod(control, struct cmsghdr *);
204                 chdr->cmsg_len = CMSG_LEN(fdslen * sizeof(int));
205                 chdr->cmsg_level = SOL_SOCKET;
206                 chdr->cmsg_type = SCM_RIGHTS;
207                 error = copyin(fds, CMSG_DATA(chdr), fdslen * sizeof(int));
208                 if (error != 0) {
209                         m_free(control);
210                         return (error);
211                 }
212         } else {
213                 control = NULL;
214         }
215
216         error = kern_sendit(td, fd, &hdr, MSG_NOSIGNAL, control, UIO_USERSPACE);
217         if (error != 0)
218                 return (error);
219         *rdatalen = td->td_retval[0];
220         td->td_retval[0] = 0;
221         return (0);
222 }