| @@ -1,950 +1,965 @@ | | | @@ -1,950 +1,965 @@ |
1 | /* $NetBSD: rumpuser_sp.c,v 1.1 2010/10/27 20:44:50 pooka Exp $ */ | | 1 | /* $NetBSD: rumpuser_sp.c,v 1.2 2010/10/28 14:37:29 pooka Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2010 Antti Kantee. All Rights Reserved. | | 4 | * Copyright (c) 2010 Antti Kantee. All Rights Reserved. |
5 | * | | 5 | * |
6 | * Redistribution and use in source and binary forms, with or without | | 6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions | | 7 | * modification, are permitted provided that the following conditions |
8 | * are met: | | 8 | * are met: |
9 | * 1. Redistributions of source code must retain the above copyright | | 9 | * 1. Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. | | 10 | * notice, this list of conditions and the following disclaimer. |
11 | * 2. Redistributions in binary form must reproduce the above copyright | | 11 | * 2. Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the | | 12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. | | 13 | * documentation and/or other materials provided with the distribution. |
14 | * | | 14 | * |
15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS | | 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS |
16 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | | 16 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | | 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
18 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | | 18 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | | 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
23 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 23 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
24 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 24 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
25 | * SUCH DAMAGE. | | 25 | * SUCH DAMAGE. |
26 | */ | | 26 | */ |
27 | | | 27 | |
28 | /* | | 28 | /* |
29 | * Sysproxy routines. This provides system RPC support over host sockets. | | 29 | * Sysproxy routines. This provides system RPC support over host sockets. |
30 | * The most notable limitation is that the client and server must share | | 30 | * The most notable limitation is that the client and server must share |
31 | * the same ABI. This does not mean that they have to be the same | | 31 | * the same ABI. This does not mean that they have to be the same |
32 | * machine or that they need to run the same version of the host OS, | | 32 | * machine or that they need to run the same version of the host OS, |
33 | * just that they must agree on the data structures. This even *might* | | 33 | * just that they must agree on the data structures. This even *might* |
34 | * work correctly from one hardware architecture to another. | | 34 | * work correctly from one hardware architecture to another. |
35 | * | | 35 | * |
36 | * Not finished yet, i.e. don't use in production. Lacks locking plus | | 36 | * Not finished yet, i.e. don't use in production. Lacks locking plus |
37 | * handling of multiple clients and unexpected connection closes. | | 37 | * handling of multiple clients and unexpected connection closes. |
38 | */ | | 38 | */ |
39 | | | 39 | |
40 | #include <sys/cdefs.h> | | 40 | #include <sys/cdefs.h> |
41 | __RCSID("$NetBSD: rumpuser_sp.c,v 1.1 2010/10/27 20:44:50 pooka Exp $"); | | 41 | __RCSID("$NetBSD: rumpuser_sp.c,v 1.2 2010/10/28 14:37:29 pooka Exp $"); |
42 | | | 42 | |
43 | #include <sys/types.h> | | 43 | #include <sys/types.h> |
44 | #include <sys/mman.h> | | 44 | #include <sys/mman.h> |
45 | #include <sys/socket.h> | | 45 | #include <sys/socket.h> |
46 | | | 46 | |
47 | #include <arpa/inet.h> | | 47 | #include <arpa/inet.h> |
48 | #include <netinet/in.h> | | 48 | #include <netinet/in.h> |
49 | #include <netinet/tcp.h> | | 49 | #include <netinet/tcp.h> |
50 | | | 50 | |
51 | #include <assert.h> | | 51 | #include <assert.h> |
52 | #include <errno.h> | | 52 | #include <errno.h> |
53 | #include <fcntl.h> | | 53 | #include <fcntl.h> |
54 | #include <poll.h> | | 54 | #include <poll.h> |
55 | #include <pthread.h> | | 55 | #include <pthread.h> |
56 | #include <stdarg.h> | | 56 | #include <stdarg.h> |
57 | #include <stdio.h> | | 57 | #include <stdio.h> |
58 | #include <stdlib.h> | | 58 | #include <stdlib.h> |
59 | #include <string.h> | | 59 | #include <string.h> |
60 | #include <unistd.h> | | 60 | #include <unistd.h> |
61 | | | 61 | |
62 | #include <rump/rump.h> | | 62 | #include <rump/rump.h> |
63 | #include <rump/rumpuser.h> | | 63 | #include <rump/rumpuser.h> |
64 | | | 64 | |
65 | //#define DEBUG | | 65 | //#define DEBUG |
66 | #ifdef DEBUG | | 66 | #ifdef DEBUG |
67 | #define DPRINTF(x) mydprintf x | | 67 | #define DPRINTF(x) mydprintf x |
68 | static void | | 68 | static void |
69 | mydprintf(const char *fmt, ...) | | 69 | mydprintf(const char *fmt, ...) |
70 | { | | 70 | { |
71 | va_list ap; | | 71 | va_list ap; |
72 | | | 72 | |
73 | va_start(ap, fmt); | | 73 | va_start(ap, fmt); |
74 | vfprintf(stderr, fmt, ap); | | 74 | vfprintf(stderr, fmt, ap); |
75 | va_end(ap); | | 75 | va_end(ap); |
76 | } | | 76 | } |
77 | #else | | 77 | #else |
78 | #define DPRINTF(x) | | 78 | #define DPRINTF(x) |
79 | #endif | | 79 | #endif |
80 | | | 80 | |
81 | /* | | 81 | /* |
82 | * Bah, I hate writing on-off-wire conversions in C | | 82 | * Bah, I hate writing on-off-wire conversions in C |
83 | */ | | 83 | */ |
84 | | | 84 | |
85 | enum { | | 85 | enum { |
86 | RUMPSP_SYSCALL_REQ, RUMPSP_SYSCALL_RESP, | | 86 | RUMPSP_SYSCALL_REQ, RUMPSP_SYSCALL_RESP, |
87 | RUMPSP_COPYIN_REQ, RUMPSP_COPYIN_RESP, | | 87 | RUMPSP_COPYIN_REQ, RUMPSP_COPYIN_RESP, |
88 | RUMPSP_COPYOUT_REQ, /* no copyout resp */ | | 88 | RUMPSP_COPYOUT_REQ, /* no copyout resp */ |
89 | RUMPSP_ANONMMAP_REQ, RUMPSP_ANONMMAP_RESP | | 89 | RUMPSP_ANONMMAP_REQ, RUMPSP_ANONMMAP_RESP |
90 | }; | | 90 | }; |
91 | | | 91 | |
92 | struct rsp_hdr { | | 92 | struct rsp_hdr { |
93 | uint64_t rsp_len; | | 93 | uint64_t rsp_len; |
94 | uint64_t rsp_reqno; | | 94 | uint64_t rsp_reqno; |
95 | uint32_t rsp_type; | | 95 | uint32_t rsp_type; |
96 | /* | | 96 | /* |
97 | * We want this structure 64bit-aligned for typecast fun, | | 97 | * We want this structure 64bit-aligned for typecast fun, |
98 | * so might as well use the following for something. | | 98 | * so might as well use the following for something. |
99 | */ | | 99 | */ |
100 | uint32_t rsp_sysnum; | | 100 | uint32_t rsp_sysnum; |
101 | }; | | 101 | }; |
102 | #define HDRSZ sizeof(struct rsp_hdr) | | 102 | #define HDRSZ sizeof(struct rsp_hdr) |
103 | | | 103 | |
104 | /* | | 104 | /* |
105 | * Data follows the header. We have two types of structured data. | | 105 | * Data follows the header. We have two types of structured data. |
106 | */ | | 106 | */ |
107 | | | 107 | |
108 | /* copyin/copyout */ | | 108 | /* copyin/copyout */ |
109 | struct rsp_copydata { | | 109 | struct rsp_copydata { |
110 | size_t rcp_len; | | 110 | size_t rcp_len; |
111 | void *rcp_addr; | | 111 | void *rcp_addr; |
112 | uint8_t rcp_data[0]; | | 112 | uint8_t rcp_data[0]; |
113 | }; | | 113 | }; |
114 | | | 114 | |
115 | /* syscall response */ | | 115 | /* syscall response */ |
116 | struct rsp_sysresp { | | 116 | struct rsp_sysresp { |
117 | int rsys_error; | | 117 | int rsys_error; |
118 | register_t rsys_retval[2]; | | 118 | register_t rsys_retval[2]; |
119 | }; | | 119 | }; |
120 | | | 120 | |
121 | | | 121 | |
122 | struct spclient { | | 122 | struct spclient { |
123 | int spc_fd; | | 123 | int spc_fd; |
| | | 124 | struct lwp *spc_lwp; |
124 | | | 125 | |
125 | /* incoming */ | | 126 | /* incoming */ |
126 | struct rsp_hdr spc_hdr; | | 127 | struct rsp_hdr spc_hdr; |
127 | uint8_t *spc_buf; | | 128 | uint8_t *spc_buf; |
128 | size_t spc_off; | | 129 | size_t spc_off; |
129 | | | 130 | |
130 | #if 0 | | 131 | #if 0 |
131 | /* outgoing */ | | 132 | /* outgoing */ |
132 | int spc_obusy; | | 133 | int spc_obusy; |
133 | pthread_mutex_t spc_omtx; | | 134 | pthread_mutex_t spc_omtx; |
134 | pthread_cond_t spc_cv; | | 135 | pthread_cond_t spc_cv; |
135 | #endif | | 136 | #endif |
136 | }; | | 137 | }; |
137 | | | 138 | |
138 | typedef int (*addrparse_fn)(const char *, int, struct sockaddr **); | | 139 | typedef int (*addrparse_fn)(const char *, int, struct sockaddr **); |
139 | typedef int (*connecthook_fn)(int); | | 140 | typedef int (*connecthook_fn)(int); |
140 | | | 141 | |
141 | #define MAXCLI 4 | | 142 | #define MAXCLI 4 |
142 | | | 143 | |
143 | static struct pollfd pfdlist[MAXCLI]; | | 144 | static struct pollfd pfdlist[MAXCLI]; |
144 | static struct spclient spclist[MAXCLI]; | | 145 | static struct spclient spclist[MAXCLI]; |
145 | static unsigned int nfds, maxidx; | | 146 | static unsigned int nfds, maxidx; |
146 | static uint64_t nextreq; | | 147 | static uint64_t nextreq; |
147 | static pthread_key_t spclient_tls; | | 148 | static pthread_key_t spclient_tls; |
148 | | | 149 | |
149 | static struct spclient clispc; | | 150 | static struct spclient clispc; |
150 | | | 151 | |
151 | | | 152 | |
152 | static int | | 153 | static int |
153 | dosend(struct spclient *spc, const void *data, size_t dlen) | | 154 | dosend(struct spclient *spc, const void *data, size_t dlen) |
154 | { | | 155 | { |
155 | struct pollfd pfd; | | 156 | struct pollfd pfd; |
156 | const uint8_t *sdata = data; | | 157 | const uint8_t *sdata = data; |
157 | ssize_t n; | | 158 | ssize_t n; |
158 | size_t sent; | | 159 | size_t sent; |
159 | int fd = spc->spc_fd; | | 160 | int fd = spc->spc_fd; |
160 | | | 161 | |
161 | pfd.fd = fd; | | 162 | pfd.fd = fd; |
162 | pfd.events = POLLOUT; | | 163 | pfd.events = POLLOUT; |
163 | | | 164 | |
164 | for (sent = 0, n = 0; sent < dlen; ) { | | 165 | for (sent = 0, n = 0; sent < dlen; ) { |
165 | if (n) { | | 166 | if (n) { |
166 | if (poll(&pfd, 1, INFTIM) == -1) { | | 167 | if (poll(&pfd, 1, INFTIM) == -1) { |
167 | if (errno == EINTR) | | 168 | if (errno == EINTR) |
168 | continue; | | 169 | continue; |
169 | return errno; | | 170 | return errno; |
170 | } | | 171 | } |
171 | } | | 172 | } |
172 | | | 173 | |
173 | n = write(fd, sdata + sent, dlen - sent); | | 174 | n = write(fd, sdata + sent, dlen - sent); |
174 | if (n == 0) { | | 175 | if (n == 0) { |
175 | return EFAULT; | | 176 | return EFAULT; |
176 | } | | 177 | } |
177 | if (n == -1 && errno != EAGAIN) { | | 178 | if (n == -1 && errno != EAGAIN) { |
178 | return EFAULT; | | 179 | return EFAULT; |
179 | } | | 180 | } |
180 | sent += n; | | 181 | sent += n; |
181 | } | | 182 | } |
182 | | | 183 | |
183 | return 0; | | 184 | return 0; |
184 | } | | 185 | } |
185 | | | 186 | |
186 | static int | | 187 | static int |
187 | send_syscall_req(struct spclient *spc, int sysnum, | | 188 | send_syscall_req(struct spclient *spc, int sysnum, |
188 | const void *data, size_t dlen) | | 189 | const void *data, size_t dlen) |
189 | { | | 190 | { |
190 | struct rsp_hdr rhdr; | | 191 | struct rsp_hdr rhdr; |
191 | | | 192 | |
192 | rhdr.rsp_len = sizeof(rhdr) + dlen; | | 193 | rhdr.rsp_len = sizeof(rhdr) + dlen; |
193 | rhdr.rsp_reqno = nextreq++; | | 194 | rhdr.rsp_reqno = nextreq++; |
194 | rhdr.rsp_type = RUMPSP_SYSCALL_REQ; | | 195 | rhdr.rsp_type = RUMPSP_SYSCALL_REQ; |
195 | rhdr.rsp_sysnum = sysnum; | | 196 | rhdr.rsp_sysnum = sysnum; |
196 | | | 197 | |
197 | dosend(spc, &rhdr, sizeof(rhdr)); | | 198 | dosend(spc, &rhdr, sizeof(rhdr)); |
198 | dosend(spc, data, dlen); | | 199 | dosend(spc, data, dlen); |
199 | | | 200 | |
200 | return 0; | | 201 | return 0; |
201 | } | | 202 | } |
202 | | | 203 | |
203 | static int | | 204 | static int |
204 | send_syscall_resp(struct spclient *spc, uint64_t reqno, int error, | | 205 | send_syscall_resp(struct spclient *spc, uint64_t reqno, int error, |
205 | register_t retval[2]) | | 206 | register_t retval[2]) |
206 | { | | 207 | { |
207 | struct rsp_hdr rhdr; | | 208 | struct rsp_hdr rhdr; |
208 | struct rsp_sysresp sysresp; | | 209 | struct rsp_sysresp sysresp; |
209 | | | 210 | |
210 | rhdr.rsp_len = sizeof(rhdr) + sizeof(sysresp); | | 211 | rhdr.rsp_len = sizeof(rhdr) + sizeof(sysresp); |
211 | rhdr.rsp_reqno = reqno; | | 212 | rhdr.rsp_reqno = reqno; |
212 | rhdr.rsp_type = RUMPSP_SYSCALL_RESP; | | 213 | rhdr.rsp_type = RUMPSP_SYSCALL_RESP; |
213 | rhdr.rsp_sysnum = 0; | | 214 | rhdr.rsp_sysnum = 0; |
214 | | | 215 | |
215 | sysresp.rsys_error = error; | | 216 | sysresp.rsys_error = error; |
216 | memcpy(sysresp.rsys_retval, retval, sizeof(retval)); | | 217 | memcpy(sysresp.rsys_retval, retval, sizeof(retval)); |
217 | | | 218 | |
218 | dosend(spc, &rhdr, sizeof(rhdr)); | | 219 | dosend(spc, &rhdr, sizeof(rhdr)); |
219 | dosend(spc, &sysresp, sizeof(sysresp)); | | 220 | dosend(spc, &sysresp, sizeof(sysresp)); |
220 | | | 221 | |
221 | return 0; | | 222 | return 0; |
222 | } | | 223 | } |
223 | | | 224 | |
224 | static int | | 225 | static int |
225 | send_copyin_req(struct spclient *spc, const void *remaddr, size_t dlen) | | 226 | send_copyin_req(struct spclient *spc, const void *remaddr, size_t dlen) |
226 | { | | 227 | { |
227 | struct rsp_hdr rhdr; | | 228 | struct rsp_hdr rhdr; |
228 | struct rsp_copydata copydata; | | 229 | struct rsp_copydata copydata; |
229 | | | 230 | |
230 | rhdr.rsp_len = sizeof(rhdr) + sizeof(copydata); | | 231 | rhdr.rsp_len = sizeof(rhdr) + sizeof(copydata); |
231 | rhdr.rsp_reqno = nextreq++; | | 232 | rhdr.rsp_reqno = nextreq++; |
232 | rhdr.rsp_type = RUMPSP_COPYIN_REQ; | | 233 | rhdr.rsp_type = RUMPSP_COPYIN_REQ; |
233 | rhdr.rsp_sysnum = 0; | | 234 | rhdr.rsp_sysnum = 0; |
234 | | | 235 | |
235 | copydata.rcp_addr = __UNCONST(remaddr); | | 236 | copydata.rcp_addr = __UNCONST(remaddr); |
236 | copydata.rcp_len = dlen; | | 237 | copydata.rcp_len = dlen; |
237 | | | 238 | |
238 | dosend(spc, &rhdr, sizeof(rhdr)); | | 239 | dosend(spc, &rhdr, sizeof(rhdr)); |
239 | dosend(spc, ©data, sizeof(copydata)); | | 240 | dosend(spc, ©data, sizeof(copydata)); |
240 | | | 241 | |
241 | return 0; | | 242 | return 0; |
242 | } | | 243 | } |
243 | | | 244 | |
244 | static int | | 245 | static int |
245 | send_copyin_resp(struct spclient *spc, uint64_t reqno, void *data, size_t dlen) | | 246 | send_copyin_resp(struct spclient *spc, uint64_t reqno, void *data, size_t dlen) |
246 | { | | 247 | { |
247 | struct rsp_hdr rhdr; | | 248 | struct rsp_hdr rhdr; |
248 | | | 249 | |
249 | rhdr.rsp_len = sizeof(rhdr) + dlen; | | 250 | rhdr.rsp_len = sizeof(rhdr) + dlen; |
250 | rhdr.rsp_reqno = reqno; | | 251 | rhdr.rsp_reqno = reqno; |
251 | rhdr.rsp_type = RUMPSP_COPYIN_RESP; | | 252 | rhdr.rsp_type = RUMPSP_COPYIN_RESP; |
252 | rhdr.rsp_sysnum = 0; | | 253 | rhdr.rsp_sysnum = 0; |
253 | | | 254 | |
254 | dosend(spc, &rhdr, sizeof(rhdr)); | | 255 | dosend(spc, &rhdr, sizeof(rhdr)); |
255 | dosend(spc, data, dlen); | | 256 | dosend(spc, data, dlen); |
256 | | | 257 | |
257 | return 0; | | 258 | return 0; |
258 | } | | 259 | } |
259 | | | 260 | |
260 | static int | | 261 | static int |
261 | send_copyout_req(struct spclient *spc, const void *remaddr, | | 262 | send_copyout_req(struct spclient *spc, const void *remaddr, |
262 | const void *data, size_t dlen) | | 263 | const void *data, size_t dlen) |
263 | { | | 264 | { |
264 | struct rsp_hdr rhdr; | | 265 | struct rsp_hdr rhdr; |
265 | struct rsp_copydata copydata; | | 266 | struct rsp_copydata copydata; |
266 | | | 267 | |
267 | rhdr.rsp_len = sizeof(rhdr) + sizeof(copydata) + dlen; | | 268 | rhdr.rsp_len = sizeof(rhdr) + sizeof(copydata) + dlen; |
268 | rhdr.rsp_reqno = nextreq++; | | 269 | rhdr.rsp_reqno = nextreq++; |
269 | rhdr.rsp_type = RUMPSP_COPYOUT_REQ; | | 270 | rhdr.rsp_type = RUMPSP_COPYOUT_REQ; |
270 | rhdr.rsp_sysnum = 0; | | 271 | rhdr.rsp_sysnum = 0; |
271 | | | 272 | |
272 | copydata.rcp_addr = __UNCONST(remaddr); | | 273 | copydata.rcp_addr = __UNCONST(remaddr); |
273 | copydata.rcp_len = dlen; | | 274 | copydata.rcp_len = dlen; |
274 | | | 275 | |
275 | dosend(spc, &rhdr, sizeof(rhdr)); | | 276 | dosend(spc, &rhdr, sizeof(rhdr)); |
276 | dosend(spc, ©data, sizeof(copydata)); | | 277 | dosend(spc, ©data, sizeof(copydata)); |
277 | dosend(spc, data, dlen); | | 278 | dosend(spc, data, dlen); |
278 | | | 279 | |
279 | return 0; | | 280 | return 0; |
280 | } | | 281 | } |
281 | | | 282 | |
282 | static int | | 283 | static int |
283 | send_anonmmap_req(struct spclient *spc, size_t howmuch) | | 284 | send_anonmmap_req(struct spclient *spc, size_t howmuch) |
284 | { | | 285 | { |
285 | struct rsp_hdr rhdr; | | 286 | struct rsp_hdr rhdr; |
286 | | | 287 | |
287 | rhdr.rsp_len = sizeof(rhdr) + sizeof(howmuch); | | 288 | rhdr.rsp_len = sizeof(rhdr) + sizeof(howmuch); |
288 | rhdr.rsp_reqno = nextreq++; | | 289 | rhdr.rsp_reqno = nextreq++; |
289 | rhdr.rsp_type = RUMPSP_ANONMMAP_REQ; | | 290 | rhdr.rsp_type = RUMPSP_ANONMMAP_REQ; |
290 | rhdr.rsp_sysnum = 0; | | 291 | rhdr.rsp_sysnum = 0; |
291 | | | 292 | |
292 | dosend(spc, &rhdr, sizeof(rhdr)); | | 293 | dosend(spc, &rhdr, sizeof(rhdr)); |
293 | dosend(spc, &howmuch, sizeof(howmuch)); | | 294 | dosend(spc, &howmuch, sizeof(howmuch)); |
294 | | | 295 | |
295 | return 0; | | 296 | return 0; |
296 | } | | 297 | } |
297 | | | 298 | |
298 | static int | | 299 | static int |
299 | send_anonmmap_resp(struct spclient *spc, uint64_t reqno, void *addr) | | 300 | send_anonmmap_resp(struct spclient *spc, uint64_t reqno, void *addr) |
300 | { | | 301 | { |
301 | struct rsp_hdr rhdr; | | 302 | struct rsp_hdr rhdr; |
302 | | | 303 | |
303 | rhdr.rsp_len = sizeof(rhdr) + sizeof(addr); | | 304 | rhdr.rsp_len = sizeof(rhdr) + sizeof(addr); |
304 | rhdr.rsp_reqno = reqno; | | 305 | rhdr.rsp_reqno = reqno; |
305 | rhdr.rsp_type = RUMPSP_ANONMMAP_RESP; | | 306 | rhdr.rsp_type = RUMPSP_ANONMMAP_RESP; |
306 | rhdr.rsp_sysnum = 0; | | 307 | rhdr.rsp_sysnum = 0; |
307 | | | 308 | |
308 | dosend(spc, &rhdr, sizeof(rhdr)); | | 309 | dosend(spc, &rhdr, sizeof(rhdr)); |
309 | dosend(spc, &addr, sizeof(addr)); | | 310 | dosend(spc, &addr, sizeof(addr)); |
310 | | | 311 | |
311 | return 0; | | 312 | return 0; |
312 | } | | 313 | } |
313 | | | 314 | |
314 | static void | | 315 | static void |
315 | serv_handle_disco(unsigned int idx) | | 316 | serv_handledisco(unsigned int idx) |
316 | { | | 317 | { |
317 | struct spclient *spc = &spclist[idx]; | | 318 | struct spclient *spc = &spclist[idx]; |
318 | int fd = spc->spc_fd; | | 319 | int fd = spc->spc_fd; |
319 | | | 320 | |
320 | DPRINTF(("rump_sp: disconnecting [%u]\n", idx)); | | 321 | DPRINTF(("rump_sp: disconnecting [%u]\n", idx)); |
321 | | | 322 | |
| | | 323 | rump_pub_lwproc_switch(spc->spc_lwp); |
| | | 324 | rump_pub_lwproc_releaselwp(); |
| | | 325 | |
322 | free(spc->spc_buf); | | 326 | free(spc->spc_buf); |
323 | memset(spc, 0, sizeof(*spc)); | | 327 | memset(spc, 0, sizeof(*spc)); |
324 | close(fd); | | 328 | close(fd); |
325 | pfdlist[idx].fd = -1; | | 329 | pfdlist[idx].fd = -1; |
326 | nfds--; | | 330 | nfds--; |
327 | | | 331 | |
328 | if (idx == maxidx) { | | 332 | if (idx == maxidx) { |
329 | while (idx--) { | | 333 | while (idx--) { |
330 | if (pfdlist[idx].fd != -1) { | | 334 | if (pfdlist[idx].fd != -1) { |
331 | maxidx = idx; | | 335 | maxidx = idx; |
332 | break; | | 336 | break; |
333 | } | | 337 | } |
334 | assert(idx != 0); | | 338 | assert(idx != 0); |
335 | } | | 339 | } |
336 | DPRINTF(("rump_sp: set maxidx to [%u]\n", maxidx)); | | 340 | DPRINTF(("rump_sp: set maxidx to [%u]\n", maxidx)); |
337 | } | | 341 | } |
338 | } | | 342 | } |
339 | | | 343 | |
340 | static int | | 344 | static int |
341 | serv_handleconn(int fd, connecthook_fn connhook) | | 345 | serv_handleconn(int fd, connecthook_fn connhook) |
342 | { | | 346 | { |
343 | struct sockaddr_storage ss; | | 347 | struct sockaddr_storage ss; |
344 | socklen_t sl = sizeof(ss); | | 348 | socklen_t sl = sizeof(ss); |
345 | int newfd, flags, error; | | 349 | int newfd, flags, error; |
346 | unsigned i; | | 350 | unsigned i; |
347 | | | 351 | |
348 | /*LINTED: cast ok */ | | 352 | /*LINTED: cast ok */ |
349 | newfd = accept(fd, (struct sockaddr *)&ss, &sl); | | 353 | newfd = accept(fd, (struct sockaddr *)&ss, &sl); |
350 | if (newfd == -1) | | 354 | if (newfd == -1) |
351 | return errno; | | 355 | return errno; |
352 | | | 356 | |
353 | /* XXX: should do some sort of handshake too */ | | 357 | /* XXX: should do some sort of handshake too */ |
354 | | | 358 | |
355 | if (nfds == MAXCLI) { | | 359 | if (nfds == MAXCLI) { |
356 | close(newfd); /* EBUSY */ | | 360 | close(newfd); /* EBUSY */ |
357 | return EBUSY; | | 361 | return EBUSY; |
358 | } | | 362 | } |
359 | | | 363 | |
360 | flags = fcntl(newfd, F_GETFL, 0); | | 364 | flags = fcntl(newfd, F_GETFL, 0); |
361 | if (fcntl(newfd, F_SETFL, flags | O_NONBLOCK) == -1) { | | 365 | if (fcntl(newfd, F_SETFL, flags | O_NONBLOCK) == -1) { |
362 | close(newfd); | | 366 | close(newfd); |
363 | return errno; | | 367 | return errno; |
364 | } | | 368 | } |
365 | flags = 1; | | 369 | flags = 1; |
366 | | | 370 | |
367 | if ((error = connhook(newfd)) != 0) { | | 371 | if ((error = connhook(newfd)) != 0) { |
368 | close(newfd); | | 372 | close(newfd); |
369 | return error; | | 373 | return error; |
370 | } | | 374 | } |
371 | | | 375 | |
| | | 376 | if ((error = rump_pub_lwproc_newproc()) != 0) { |
| | | 377 | close(newfd); |
| | | 378 | return error; |
| | | 379 | } |
| | | 380 | |
372 | /* find empty slot the simple way */ | | 381 | /* find empty slot the simple way */ |
373 | for (i = 0; i < MAXCLI; i++) { | | 382 | for (i = 0; i < MAXCLI; i++) { |
374 | if (pfdlist[i].fd == -1) | | 383 | if (pfdlist[i].fd == -1) |
375 | break; | | 384 | break; |
376 | } | | 385 | } |
377 | | | 386 | |
378 | assert(i < MAXCLI); | | 387 | assert(i < MAXCLI); |
379 | nfds++; | | 388 | nfds++; |
380 | | | 389 | |
381 | pfdlist[i].fd = newfd; | | 390 | pfdlist[i].fd = newfd; |
382 | spclist[i].spc_fd = newfd; | | 391 | spclist[i].spc_fd = newfd; |
| | | 392 | spclist[i].spc_lwp = rump_pub_lwproc_curlwp(); |
383 | if (maxidx < i) | | 393 | if (maxidx < i) |
384 | maxidx = i; | | 394 | maxidx = i; |
385 | | | 395 | |
386 | DPRINTF(("rump_sp: added new connection at idx %u\n", i)); | | 396 | DPRINTF(("rump_sp: added new connection at idx %u, pid %d\n", |
| | | 397 | i, rump_sys_getpid())); |
| | | 398 | |
| | | 399 | rump_pub_lwproc_switch(NULL); |
387 | | | 400 | |
388 | return 0; | | 401 | return 0; |
389 | } | | 402 | } |
390 | | | 403 | |
391 | static void | | 404 | static void |
392 | serv_handlesyscall(struct spclient *spc, struct rsp_hdr *rhdr, uint8_t *data) | | 405 | serv_handlesyscall(struct spclient *spc, struct rsp_hdr *rhdr, uint8_t *data) |
393 | { | | 406 | { |
394 | register_t retval[2]; | | 407 | register_t retval[2]; |
395 | int rv, sysnum; | | 408 | int rv, sysnum; |
396 | | | 409 | |
397 | sysnum = (int)rhdr->rsp_sysnum; | | 410 | sysnum = (int)rhdr->rsp_sysnum; |
398 | DPRINTF(("rump_sp: handling syscall %d from client %d\n", | | 411 | DPRINTF(("rump_sp: handling syscall %d from client %d\n", |
399 | sysnum, 0)); | | 412 | sysnum, 0)); |
400 | | | 413 | |
401 | pthread_setspecific(spclient_tls, spc); | | 414 | pthread_setspecific(spclient_tls, spc); |
| | | 415 | rump_pub_lwproc_switch(spc->spc_lwp); |
402 | rv = rump_pub_syscall(sysnum, data, retval); | | 416 | rv = rump_pub_syscall(sysnum, data, retval); |
| | | 417 | rump_pub_lwproc_switch(NULL); |
403 | pthread_setspecific(spclient_tls, NULL); | | 418 | pthread_setspecific(spclient_tls, NULL); |
404 | | | 419 | |
405 | send_syscall_resp(spc, rhdr->rsp_reqno, rv, retval); | | 420 | send_syscall_resp(spc, rhdr->rsp_reqno, rv, retval); |
406 | } | | 421 | } |
407 | | | 422 | |
408 | static int | | 423 | static int |
409 | readframe(struct spclient *spc) | | 424 | readframe(struct spclient *spc) |
410 | { | | 425 | { |
411 | int fd = spc->spc_fd; | | 426 | int fd = spc->spc_fd; |
412 | size_t left; | | 427 | size_t left; |
413 | size_t framelen; | | 428 | size_t framelen; |
414 | ssize_t n; | | 429 | ssize_t n; |
415 | | | 430 | |
416 | /* still reading header? */ | | 431 | /* still reading header? */ |
417 | if (spc->spc_off < HDRSZ) { | | 432 | if (spc->spc_off < HDRSZ) { |
418 | DPRINTF(("rump_sp: readframe getting header at offset %zu\n", | | 433 | DPRINTF(("rump_sp: readframe getting header at offset %zu\n", |
419 | spc->spc_off)); | | 434 | spc->spc_off)); |
420 | | | 435 | |
421 | left = HDRSZ - spc->spc_off; | | 436 | left = HDRSZ - spc->spc_off; |
422 | /*LINTED: cast ok */ | | 437 | /*LINTED: cast ok */ |
423 | n = read(fd, (uint8_t *)&spc->spc_hdr + spc->spc_off, left); | | 438 | n = read(fd, (uint8_t *)&spc->spc_hdr + spc->spc_off, left); |
424 | if (n == 0) { | | 439 | if (n == 0) { |
425 | return -1; | | 440 | return -1; |
426 | } | | 441 | } |
427 | if (n == -1) { | | 442 | if (n == -1) { |
428 | if (errno == EAGAIN) | | 443 | if (errno == EAGAIN) |
429 | return 0; | | 444 | return 0; |
430 | return -1; | | 445 | return -1; |
431 | } | | 446 | } |
432 | | | 447 | |
433 | spc->spc_off += n; | | 448 | spc->spc_off += n; |
434 | if (spc->spc_off < HDRSZ) | | 449 | if (spc->spc_off < HDRSZ) |
435 | return -1; | | 450 | return -1; |
436 | | | 451 | |
437 | /*LINTED*/ | | 452 | /*LINTED*/ |
438 | framelen = spc->spc_hdr.rsp_len; | | 453 | framelen = spc->spc_hdr.rsp_len; |
439 | | | 454 | |
440 | if (framelen < HDRSZ) { | | 455 | if (framelen < HDRSZ) { |
441 | return -1; | | 456 | return -1; |
442 | } else if (framelen == HDRSZ) { | | 457 | } else if (framelen == HDRSZ) { |
443 | return 1; | | 458 | return 1; |
444 | } | | 459 | } |
445 | | | 460 | |
446 | spc->spc_buf = malloc(framelen - HDRSZ); | | 461 | spc->spc_buf = malloc(framelen - HDRSZ); |
447 | if (spc->spc_buf == NULL) { | | 462 | if (spc->spc_buf == NULL) { |
448 | return -1; | | 463 | return -1; |
449 | } | | 464 | } |
450 | memset(spc->spc_buf, 0, framelen - HDRSZ); | | 465 | memset(spc->spc_buf, 0, framelen - HDRSZ); |
451 | | | 466 | |
452 | /* "fallthrough" */ | | 467 | /* "fallthrough" */ |
453 | } else { | | 468 | } else { |
454 | /*LINTED*/ | | 469 | /*LINTED*/ |
455 | framelen = spc->spc_hdr.rsp_len; | | 470 | framelen = spc->spc_hdr.rsp_len; |
456 | } | | 471 | } |
457 | | | 472 | |
458 | left = framelen - spc->spc_off; | | 473 | left = framelen - spc->spc_off; |
459 | | | 474 | |
460 | DPRINTF(("rump_sp: readframe getting body at offset %zu, left %zu\n", | | 475 | DPRINTF(("rump_sp: readframe getting body at offset %zu, left %zu\n", |
461 | spc->spc_off, left)); | | 476 | spc->spc_off, left)); |
462 | | | 477 | |
463 | if (left == 0) | | 478 | if (left == 0) |
464 | return 1; | | 479 | return 1; |
465 | n = read(fd, spc->spc_buf + (spc->spc_off - HDRSZ), left); | | 480 | n = read(fd, spc->spc_buf + (spc->spc_off - HDRSZ), left); |
466 | if (n == 0) { | | 481 | if (n == 0) { |
467 | return -1; | | 482 | return -1; |
468 | } | | 483 | } |
469 | if (n == -1) { | | 484 | if (n == -1) { |
470 | if (errno == EAGAIN) | | 485 | if (errno == EAGAIN) |
471 | return 0; | | 486 | return 0; |
472 | return -1; | | 487 | return -1; |
473 | } | | 488 | } |
474 | spc->spc_off += n; | | 489 | spc->spc_off += n; |
475 | left -= n; | | 490 | left -= n; |
476 | | | 491 | |
477 | /* got everything? */ | | 492 | /* got everything? */ |
478 | if (left == 0) | | 493 | if (left == 0) |
479 | return 1; | | 494 | return 1; |
480 | else | | 495 | else |
481 | return 0; | | 496 | return 0; |
482 | } | | 497 | } |
483 | | | 498 | |
484 | int | | 499 | int |
485 | rumpuser_sp_copyin(const void *uaddr, void *kaddr, size_t len) | | 500 | rumpuser_sp_copyin(const void *uaddr, void *kaddr, size_t len) |
486 | { | | 501 | { |
487 | struct spclient *spc; | | 502 | struct spclient *spc; |
488 | struct pollfd pfd; | | 503 | struct pollfd pfd; |
489 | | | 504 | |
490 | spc = pthread_getspecific(spclient_tls); | | 505 | spc = pthread_getspecific(spclient_tls); |
491 | if (!spc) | | 506 | if (!spc) |
492 | return EFAULT; | | 507 | return EFAULT; |
493 | | | 508 | |
494 | send_copyin_req(spc, uaddr, len); | | 509 | send_copyin_req(spc, uaddr, len); |
495 | | | 510 | |
496 | pfd.fd = spc->spc_fd; | | 511 | pfd.fd = spc->spc_fd; |
497 | pfd.events = POLLIN; | | 512 | pfd.events = POLLIN; |
498 | do { | | 513 | do { |
499 | poll(&pfd, 1, INFTIM); | | 514 | poll(&pfd, 1, INFTIM); |
500 | } while (readframe(spc) < 1); | | 515 | } while (readframe(spc) < 1); |
501 | | | 516 | |
502 | if (spc->spc_hdr.rsp_type != RUMPSP_COPYIN_RESP) { | | 517 | if (spc->spc_hdr.rsp_type != RUMPSP_COPYIN_RESP) { |
503 | abort(); | | 518 | abort(); |
504 | } | | 519 | } |
505 | | | 520 | |
506 | memcpy(kaddr, spc->spc_buf, len); | | 521 | memcpy(kaddr, spc->spc_buf, len); |
507 | free(spc->spc_buf); | | 522 | free(spc->spc_buf); |
508 | spc->spc_off = 0; | | 523 | spc->spc_off = 0; |
509 | | | 524 | |
510 | return 0; | | 525 | return 0; |
511 | } | | 526 | } |
512 | | | 527 | |
513 | int | | 528 | int |
514 | rumpuser_sp_copyout(const void *kaddr, void *uaddr, size_t dlen) | | 529 | rumpuser_sp_copyout(const void *kaddr, void *uaddr, size_t dlen) |
515 | { | | 530 | { |
516 | struct spclient *spc; | | 531 | struct spclient *spc; |
517 | | | 532 | |
518 | spc = pthread_getspecific(spclient_tls); | | 533 | spc = pthread_getspecific(spclient_tls); |
519 | if (!spc) { | | 534 | if (!spc) { |
520 | DPRINTF(("rump_sp: copyout curlwp not found\n")); | | 535 | DPRINTF(("rump_sp: copyout curlwp not found\n")); |
521 | return EFAULT; | | 536 | return EFAULT; |
522 | } | | 537 | } |
523 | | | 538 | |
524 | send_copyout_req(spc, uaddr, kaddr, dlen); | | 539 | send_copyout_req(spc, uaddr, kaddr, dlen); |
525 | | | 540 | |
526 | return 0; | | 541 | return 0; |
527 | } | | 542 | } |
528 | | | 543 | |
529 | int | | 544 | int |
530 | rumpuser_sp_anonmmap(size_t howmuch, void **addr) | | 545 | rumpuser_sp_anonmmap(size_t howmuch, void **addr) |
531 | { | | 546 | { |
532 | struct spclient *spc; | | 547 | struct spclient *spc; |
533 | struct pollfd pfd; | | 548 | struct pollfd pfd; |
534 | void *resp; | | 549 | void *resp; |
535 | | | 550 | |
536 | spc = pthread_getspecific(spclient_tls); | | 551 | spc = pthread_getspecific(spclient_tls); |
537 | if (!spc) | | 552 | if (!spc) |
538 | return EFAULT; | | 553 | return EFAULT; |
539 | | | 554 | |
540 | send_anonmmap_req(spc, howmuch); | | 555 | send_anonmmap_req(spc, howmuch); |
541 | | | 556 | |
542 | pfd.fd = spc->spc_fd; | | 557 | pfd.fd = spc->spc_fd; |
543 | pfd.events = POLLIN; | | 558 | pfd.events = POLLIN; |
544 | do { | | 559 | do { |
545 | poll(&pfd, 1, INFTIM); | | 560 | poll(&pfd, 1, INFTIM); |
546 | } while (readframe(spc) < 1); | | 561 | } while (readframe(spc) < 1); |
547 | | | 562 | |
548 | if (spc->spc_hdr.rsp_type != RUMPSP_ANONMMAP_RESP) { | | 563 | if (spc->spc_hdr.rsp_type != RUMPSP_ANONMMAP_RESP) { |
549 | abort(); | | 564 | abort(); |
550 | } | | 565 | } |
551 | | | 566 | |
552 | /*LINTED*/ | | 567 | /*LINTED*/ |
553 | resp = *(void **)spc->spc_buf; | | 568 | resp = *(void **)spc->spc_buf; |
554 | spc->spc_off = 0; | | 569 | spc->spc_off = 0; |
555 | | | 570 | |
556 | if (resp == NULL) | | 571 | if (resp == NULL) |
557 | return ENOMEM; | | 572 | return ENOMEM; |
558 | | | 573 | |
559 | *addr = resp; | | 574 | *addr = resp; |
560 | return 0; | | 575 | return 0; |
561 | } | | 576 | } |
562 | | | 577 | |
563 | int | | 578 | int |
564 | rumpuser_sp_syscall(int sysnum, const void *data, size_t dlen, | | 579 | rumpuser_sp_syscall(int sysnum, const void *data, size_t dlen, |
565 | register_t *retval) | | 580 | register_t *retval) |
566 | { | | 581 | { |
567 | struct rsp_sysresp *resp; | | 582 | struct rsp_sysresp *resp; |
568 | struct rsp_copydata *copydata; | | 583 | struct rsp_copydata *copydata; |
569 | struct pollfd pfd; | | 584 | struct pollfd pfd; |
570 | size_t maplen; | | 585 | size_t maplen; |
571 | void *mapaddr; | | 586 | void *mapaddr; |
572 | int gotresp; | | 587 | int gotresp; |
573 | | | 588 | |
574 | DPRINTF(("rump_sp_syscall: executing syscall %d\n", sysnum)); | | 589 | DPRINTF(("rump_sp_syscall: executing syscall %d\n", sysnum)); |
575 | | | 590 | |
576 | send_syscall_req(&clispc, sysnum, data, dlen); | | 591 | send_syscall_req(&clispc, sysnum, data, dlen); |
577 | | | 592 | |
578 | DPRINTF(("rump_sp_syscall: syscall %d request sent. " | | 593 | DPRINTF(("rump_sp_syscall: syscall %d request sent. " |
579 | "waiting for response\n", sysnum)); | | 594 | "waiting for response\n", sysnum)); |
580 | | | 595 | |
581 | pfd.fd = clispc.spc_fd; | | 596 | pfd.fd = clispc.spc_fd; |
582 | pfd.events = POLLIN; | | 597 | pfd.events = POLLIN; |
583 | | | 598 | |
584 | gotresp = 0; | | 599 | gotresp = 0; |
585 | while (!gotresp) { | | 600 | while (!gotresp) { |
586 | while (readframe(&clispc) < 1) | | 601 | while (readframe(&clispc) < 1) |
587 | poll(&pfd, 1, INFTIM); | | 602 | poll(&pfd, 1, INFTIM); |
588 | | | 603 | |
589 | switch (clispc.spc_hdr.rsp_type) { | | 604 | switch (clispc.spc_hdr.rsp_type) { |
590 | case RUMPSP_COPYIN_REQ: | | 605 | case RUMPSP_COPYIN_REQ: |
591 | /*LINTED*/ | | 606 | /*LINTED*/ |
592 | copydata = (struct rsp_copydata *)clispc.spc_buf; | | 607 | copydata = (struct rsp_copydata *)clispc.spc_buf; |
593 | DPRINTF(("rump_sp_syscall: copyin request: %p/%zu\n", | | 608 | DPRINTF(("rump_sp_syscall: copyin request: %p/%zu\n", |
594 | copydata->rcp_addr, copydata->rcp_len)); | | 609 | copydata->rcp_addr, copydata->rcp_len)); |
595 | send_copyin_resp(&clispc, clispc.spc_hdr.rsp_reqno, | | 610 | send_copyin_resp(&clispc, clispc.spc_hdr.rsp_reqno, |
596 | copydata->rcp_addr, copydata->rcp_len); | | 611 | copydata->rcp_addr, copydata->rcp_len); |
597 | clispc.spc_off = 0; | | 612 | clispc.spc_off = 0; |
598 | break; | | 613 | break; |
599 | case RUMPSP_COPYOUT_REQ: | | 614 | case RUMPSP_COPYOUT_REQ: |
600 | /*LINTED*/ | | 615 | /*LINTED*/ |
601 | copydata = (struct rsp_copydata *)clispc.spc_buf; | | 616 | copydata = (struct rsp_copydata *)clispc.spc_buf; |
602 | DPRINTF(("rump_sp_syscall: copyout request: %p/%zu\n", | | 617 | DPRINTF(("rump_sp_syscall: copyout request: %p/%zu\n", |
603 | copydata->rcp_addr, copydata->rcp_len)); | | 618 | copydata->rcp_addr, copydata->rcp_len)); |
604 | /*LINTED*/ | | 619 | /*LINTED*/ |
605 | memcpy(copydata->rcp_addr, copydata->rcp_data, | | 620 | memcpy(copydata->rcp_addr, copydata->rcp_data, |
606 | copydata->rcp_len); | | 621 | copydata->rcp_len); |
607 | clispc.spc_off = 0; | | 622 | clispc.spc_off = 0; |
608 | break; | | 623 | break; |
609 | case RUMPSP_ANONMMAP_REQ: | | 624 | case RUMPSP_ANONMMAP_REQ: |
610 | /*LINTED*/ | | 625 | /*LINTED*/ |
611 | maplen = *(size_t *)clispc.spc_buf; | | 626 | maplen = *(size_t *)clispc.spc_buf; |
612 | mapaddr = mmap(NULL, maplen, PROT_READ|PROT_WRITE, | | 627 | mapaddr = mmap(NULL, maplen, PROT_READ|PROT_WRITE, |
613 | MAP_ANON, -1, 0); | | 628 | MAP_ANON, -1, 0); |
614 | if (mapaddr == MAP_FAILED) | | 629 | if (mapaddr == MAP_FAILED) |
615 | mapaddr = NULL; | | 630 | mapaddr = NULL; |
616 | send_anonmmap_resp(&clispc, | | 631 | send_anonmmap_resp(&clispc, |
617 | clispc.spc_hdr.rsp_reqno, mapaddr); | | 632 | clispc.spc_hdr.rsp_reqno, mapaddr); |
618 | clispc.spc_off = 0; | | 633 | clispc.spc_off = 0; |
619 | break; | | 634 | break; |
620 | case RUMPSP_SYSCALL_RESP: | | 635 | case RUMPSP_SYSCALL_RESP: |
621 | DPRINTF(("rump_sp_syscall: got response \n")); | | 636 | DPRINTF(("rump_sp_syscall: got response \n")); |
622 | gotresp = 1; | | 637 | gotresp = 1; |
623 | break; | | 638 | break; |
624 | } | | 639 | } |
625 | } | | 640 | } |
626 | | | 641 | |
627 | /*LINTED*/ | | 642 | /*LINTED*/ |
628 | resp = (struct rsp_sysresp *)clispc.spc_buf; | | 643 | resp = (struct rsp_sysresp *)clispc.spc_buf; |
629 | memcpy(retval, &resp->rsys_retval, sizeof(resp->rsys_retval)); | | 644 | memcpy(retval, &resp->rsys_retval, sizeof(resp->rsys_retval)); |
630 | clispc.spc_off = 0; | | 645 | clispc.spc_off = 0; |
631 | | | 646 | |
632 | return resp->rsys_error; | | 647 | return resp->rsys_error; |
633 | } | | 648 | } |
634 | | | 649 | |
635 | /* | | 650 | /* |
636 | * | | 651 | * |
637 | * Startup routines and mainloop for server. | | 652 | * Startup routines and mainloop for server. |
638 | * | | 653 | * |
639 | */ | | 654 | */ |
640 | | | 655 | |
641 | static int | | 656 | static int |
642 | tcp_parse(const char *addr, int type, struct sockaddr **sa) | | 657 | tcp_parse(const char *addr, int type, struct sockaddr **sa) |
643 | { | | 658 | { |
644 | struct sockaddr_in sin; | | 659 | struct sockaddr_in sin; |
645 | char buf[64]; | | 660 | char buf[64]; |
646 | const char *p; | | 661 | const char *p; |
647 | size_t l; | | 662 | size_t l; |
648 | int port; | | 663 | int port; |
649 | | | 664 | |
650 | memset(&sin, 0, sizeof(sin)); | | 665 | memset(&sin, 0, sizeof(sin)); |
651 | sin.sin_len = sizeof(sin); | | 666 | sin.sin_len = sizeof(sin); |
652 | sin.sin_family = AF_INET; | | 667 | sin.sin_family = AF_INET; |
653 | | | 668 | |
654 | p = strchr(addr, ':'); | | 669 | p = strchr(addr, ':'); |
655 | if (!p) { | | 670 | if (!p) { |
656 | fprintf(stderr, "rump_sp_tcp: missing port specifier\n"); | | 671 | fprintf(stderr, "rump_sp_tcp: missing port specifier\n"); |
657 | return EINVAL; | | 672 | return EINVAL; |
658 | } | | 673 | } |
659 | | | 674 | |
660 | l = p - addr; | | 675 | l = p - addr; |
661 | if (l > sizeof(buf)-1) { | | 676 | if (l > sizeof(buf)-1) { |
662 | fprintf(stderr, "rump_sp_tcp: address too long\n"); | | 677 | fprintf(stderr, "rump_sp_tcp: address too long\n"); |
663 | return EINVAL; | | 678 | return EINVAL; |
664 | } | | 679 | } |
665 | strncpy(buf, addr, l); | | 680 | strncpy(buf, addr, l); |
666 | buf[l] = '\0'; | | 681 | buf[l] = '\0'; |
667 | | | 682 | |
668 | /* special INADDR_ANY treatment */ | | 683 | /* special INADDR_ANY treatment */ |
669 | if (strcmp(buf, "*") == 0 || strcmp(buf, "0") == 0) { | | 684 | if (strcmp(buf, "*") == 0 || strcmp(buf, "0") == 0) { |
670 | sin.sin_addr.s_addr = INADDR_ANY; | | 685 | sin.sin_addr.s_addr = INADDR_ANY; |
671 | } else { | | 686 | } else { |
672 | switch (inet_pton(AF_INET, buf, &sin.sin_addr)) { | | 687 | switch (inet_pton(AF_INET, buf, &sin.sin_addr)) { |
673 | case 1: | | 688 | case 1: |
674 | break; | | 689 | break; |
675 | case 0: | | 690 | case 0: |
676 | fprintf(stderr, "rump_sp_tcp: cannot parse %s\n", buf); | | 691 | fprintf(stderr, "rump_sp_tcp: cannot parse %s\n", buf); |
677 | return EINVAL; | | 692 | return EINVAL; |
678 | case -1: | | 693 | case -1: |
679 | fprintf(stderr, "rump_sp_tcp: inet_pton failed\n"); | | 694 | fprintf(stderr, "rump_sp_tcp: inet_pton failed\n"); |
680 | return errno; | | 695 | return errno; |
681 | default: | | 696 | default: |
682 | assert(/*CONSTCOND*/0); | | 697 | assert(/*CONSTCOND*/0); |
683 | return EINVAL; | | 698 | return EINVAL; |
684 | } | | 699 | } |
685 | } | | 700 | } |
686 | | | 701 | |
687 | if (type == RUMP_SP_CLIENT && sin.sin_addr.s_addr == INADDR_ANY) { | | 702 | if (type == RUMP_SP_CLIENT && sin.sin_addr.s_addr == INADDR_ANY) { |
688 | fprintf(stderr, "rump_sp_tcp: client needs !INADDR_ANY\n"); | | 703 | fprintf(stderr, "rump_sp_tcp: client needs !INADDR_ANY\n"); |
689 | return EINVAL; | | 704 | return EINVAL; |
690 | } | | 705 | } |
691 | | | 706 | |
692 | /* advance to port number & parse */ | | 707 | /* advance to port number & parse */ |
693 | p++; | | 708 | p++; |
694 | l = strspn(p, "0123456789"); | | 709 | l = strspn(p, "0123456789"); |
695 | if (l == 0) { | | 710 | if (l == 0) { |
696 | fprintf(stderr, "rump_sp_tcp: port now found: %s\n", p); | | 711 | fprintf(stderr, "rump_sp_tcp: port now found: %s\n", p); |
697 | return EINVAL; | | 712 | return EINVAL; |
698 | } | | 713 | } |
699 | strncpy(buf, p, l); | | 714 | strncpy(buf, p, l); |
700 | buf[l] = '\0'; | | 715 | buf[l] = '\0'; |
701 | | | 716 | |
702 | if (*(p+l) != '/' && *(p+l) != '\0') { | | 717 | if (*(p+l) != '/' && *(p+l) != '\0') { |
703 | fprintf(stderr, "rump_sp_tcp: junk at end of port: %s\n", addr); | | 718 | fprintf(stderr, "rump_sp_tcp: junk at end of port: %s\n", addr); |
704 | return EINVAL; | | 719 | return EINVAL; |
705 | } | | 720 | } |
706 | | | 721 | |
707 | port = atoi(buf); | | 722 | port = atoi(buf); |
708 | if (port < 0 || port >= (1<<(8*sizeof(in_port_t)))) { | | 723 | if (port < 0 || port >= (1<<(8*sizeof(in_port_t)))) { |
709 | fprintf(stderr, "rump_sp_tcp: port %d out of range\n", port); | | 724 | fprintf(stderr, "rump_sp_tcp: port %d out of range\n", port); |
710 | return ERANGE; | | 725 | return ERANGE; |
711 | } | | 726 | } |
712 | sin.sin_port = htons(port); | | 727 | sin.sin_port = htons(port); |
713 | | | 728 | |
714 | *sa = malloc(sizeof(sin)); | | 729 | *sa = malloc(sizeof(sin)); |
715 | if (*sa == NULL) | | 730 | if (*sa == NULL) |
716 | return errno; | | 731 | return errno; |
717 | memcpy(*sa, &sin, sizeof(sin)); | | 732 | memcpy(*sa, &sin, sizeof(sin)); |
718 | return 0; | | 733 | return 0; |
719 | } | | 734 | } |
720 | | | 735 | |
721 | static int | | 736 | static int |
722 | tcp_connecthook(int s) | | 737 | tcp_connecthook(int s) |
723 | { | | 738 | { |
724 | int x; | | 739 | int x; |
725 | | | 740 | |
726 | x = 1; | | 741 | x = 1; |
727 | setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &x, sizeof(x)); | | 742 | setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &x, sizeof(x)); |
728 | | | 743 | |
729 | return 0; | | 744 | return 0; |
730 | } | | 745 | } |
731 | | | 746 | |
732 | /*ARGSUSED*/ | | 747 | /*ARGSUSED*/ |
733 | static int | | 748 | static int |
734 | notsupp(void) | | 749 | notsupp(void) |
735 | { | | 750 | { |
736 | | | 751 | |
737 | fprintf(stderr, "rump_sp: support not yet implemented\n"); | | 752 | fprintf(stderr, "rump_sp: support not yet implemented\n"); |
738 | return EOPNOTSUPP; | | 753 | return EOPNOTSUPP; |
739 | } | | 754 | } |
740 | | | 755 | |
741 | static int | | 756 | static int |
742 | success(void) | | 757 | success(void) |
743 | { | | 758 | { |
744 | | | 759 | |
745 | return 0; | | 760 | return 0; |
746 | } | | 761 | } |
747 | | | 762 | |
748 | struct { | | 763 | struct { |
749 | const char *id; | | 764 | const char *id; |
750 | int domain; | | 765 | int domain; |
751 | addrparse_fn ap; | | 766 | addrparse_fn ap; |
752 | connecthook_fn connhook; | | 767 | connecthook_fn connhook; |
753 | } parsetab[] = { | | 768 | } parsetab[] = { |
754 | { "tcp", PF_INET, tcp_parse, tcp_connecthook }, | | 769 | { "tcp", PF_INET, tcp_parse, tcp_connecthook }, |
755 | { "unix", PF_LOCAL, (addrparse_fn)notsupp, (connecthook_fn)success }, | | 770 | { "unix", PF_LOCAL, (addrparse_fn)notsupp, (connecthook_fn)success }, |
756 | { "tcp6", PF_INET6, (addrparse_fn)notsupp, (connecthook_fn)success }, | | 771 | { "tcp6", PF_INET6, (addrparse_fn)notsupp, (connecthook_fn)success }, |
757 | }; | | 772 | }; |
758 | #define NPARSE (sizeof(parsetab)/sizeof(parsetab[0])) | | 773 | #define NPARSE (sizeof(parsetab)/sizeof(parsetab[0])) |
759 | | | 774 | |
760 | struct spservarg { | | 775 | struct spservarg { |
761 | int sps_sock; | | 776 | int sps_sock; |
762 | connecthook_fn sps_connhook; | | 777 | connecthook_fn sps_connhook; |
763 | }; | | 778 | }; |
764 | | | 779 | |
765 | static void * | | 780 | static void * |
766 | spserver(void *arg) | | 781 | spserver(void *arg) |
767 | { | | 782 | { |
768 | struct spservarg *sarg = arg; | | 783 | struct spservarg *sarg = arg; |
769 | unsigned idx; | | 784 | unsigned idx; |
770 | int seen; | | 785 | int seen; |
771 | int rv; | | 786 | int rv; |
772 | | | 787 | |
773 | for (idx = 1; idx < MAXCLI; idx++) { | | 788 | for (idx = 1; idx < MAXCLI; idx++) { |
774 | pfdlist[idx].fd = -1; | | 789 | pfdlist[idx].fd = -1; |
775 | pfdlist[idx].events = POLLIN; | | 790 | pfdlist[idx].events = POLLIN; |
776 | } | | 791 | } |
777 | pfdlist[0].fd = sarg->sps_sock; | | 792 | pfdlist[0].fd = sarg->sps_sock; |
778 | pfdlist[0].events = POLLIN; | | 793 | pfdlist[0].events = POLLIN; |
779 | nfds = 1; | | 794 | nfds = 1; |
780 | maxidx = 0; | | 795 | maxidx = 0; |
781 | | | 796 | |
782 | DPRINTF(("rump_sp: server mainloop\n")); | | 797 | DPRINTF(("rump_sp: server mainloop\n")); |
783 | | | 798 | |
784 | for (;;) { | | 799 | for (;;) { |
785 | DPRINTF(("rump_sp: loop nfd %d\n", maxidx+1)); | | 800 | DPRINTF(("rump_sp: loop nfd %d\n", maxidx+1)); |
786 | seen = 0; | | 801 | seen = 0; |
787 | rv = poll(pfdlist, maxidx+1, INFTIM); | | 802 | rv = poll(pfdlist, maxidx+1, INFTIM); |
788 | assert(maxidx+1 <= MAXCLI); | | 803 | assert(maxidx+1 <= MAXCLI); |
789 | assert(rv != 0); | | 804 | assert(rv != 0); |
790 | if (rv == -1) { | | 805 | if (rv == -1) { |
791 | if (errno == EINTR) | | 806 | if (errno == EINTR) |
792 | continue; | | 807 | continue; |
793 | fprintf(stderr, "rump_spserver: poll returned %d\n", | | 808 | fprintf(stderr, "rump_spserver: poll returned %d\n", |
794 | errno); | | 809 | errno); |
795 | break; | | 810 | break; |
796 | } | | 811 | } |
797 | | | 812 | |
798 | for (idx = 0; seen < rv; idx++) { | | 813 | for (idx = 0; seen < rv; idx++) { |
799 | assert(idx < MAXCLI); | | 814 | assert(idx < MAXCLI); |
800 | | | 815 | |
801 | if ((pfdlist[idx].revents & POLLIN) == 0) | | 816 | if ((pfdlist[idx].revents & POLLIN) == 0) |
802 | continue; | | 817 | continue; |
803 | | | 818 | |
804 | seen++; | | 819 | seen++; |
805 | DPRINTF(("rump_sp: activity at [%u] %d/%d\n", | | 820 | DPRINTF(("rump_sp: activity at [%u] %d/%d\n", |
806 | idx, seen, rv)); | | 821 | idx, seen, rv)); |
807 | if (idx > 0) { | | 822 | if (idx > 0) { |
808 | struct spclient *spc = &spclist[idx]; | | 823 | struct spclient *spc = &spclist[idx]; |
809 | | | 824 | |
810 | DPRINTF(("rump_sp: mainloop read [%u]\n", idx)); | | 825 | DPRINTF(("rump_sp: mainloop read [%u]\n", idx)); |
811 | switch (readframe(spc)) { | | 826 | switch (readframe(spc)) { |
812 | case 0: | | 827 | case 0: |
813 | break; | | 828 | break; |
814 | case -1: | | 829 | case -1: |
815 | serv_handle_disco(idx); | | 830 | serv_handledisco(idx); |
816 | break; | | 831 | break; |
817 | default: | | 832 | default: |
818 | spc->spc_off = 0; | | 833 | spc->spc_off = 0; |
819 | serv_handlesyscall(spc, | | 834 | serv_handlesyscall(spc, |
820 | &spc->spc_hdr, spc->spc_buf); | | 835 | &spc->spc_hdr, spc->spc_buf); |
821 | spc->spc_buf = NULL; | | 836 | spc->spc_buf = NULL; |
822 | break; | | 837 | break; |
823 | } | | 838 | } |
824 | } else { | | 839 | } else { |
825 | DPRINTF(("rump_sp: mainloop new connection\n")); | | 840 | DPRINTF(("rump_sp: mainloop new connection\n")); |
826 | serv_handleconn(pfdlist[0].fd, | | 841 | serv_handleconn(pfdlist[0].fd, |
827 | sarg->sps_connhook); | | 842 | sarg->sps_connhook); |
828 | } | | 843 | } |
829 | } | | 844 | } |
830 | } | | 845 | } |
831 | | | 846 | |
832 | return NULL; | | 847 | return NULL; |
833 | } | | 848 | } |
834 | | | 849 | |
835 | int | | 850 | int |
836 | rumpuser_sp_init(int *typep) | | 851 | rumpuser_sp_init(int *typep) |
837 | { | | 852 | { |
838 | struct spservarg *sarg; | | 853 | struct spservarg *sarg; |
839 | struct sockaddr *sap; | | 854 | struct sockaddr *sap; |
840 | char id[16]; | | 855 | char id[16]; |
841 | char *p, *p2; | | 856 | char *p, *p2; |
842 | size_t l; | | 857 | size_t l; |
843 | unsigned i; | | 858 | unsigned i; |
844 | int error, type, s; | | 859 | int error, type, s; |
845 | | | 860 | |
846 | p = NULL; | | 861 | p = NULL; |
847 | error = 0; | | 862 | error = 0; |
848 | | | 863 | |
849 | type = RUMP_SP_NONE; | | 864 | type = RUMP_SP_NONE; |
850 | if ((p = getenv("RUMP_SP_SERVER")) != NULL) { | | 865 | if ((p = getenv("RUMP_SP_SERVER")) != NULL) { |
851 | type = RUMP_SP_SERVER; | | 866 | type = RUMP_SP_SERVER; |
852 | } | | 867 | } |
853 | if ((p2 = getenv("RUMP_SP_CLIENT")) != NULL) { | | 868 | if ((p2 = getenv("RUMP_SP_CLIENT")) != NULL) { |
854 | if (type != RUMP_SP_NONE) | | 869 | if (type != RUMP_SP_NONE) |
855 | return EEXIST; | | 870 | return EEXIST; |
856 | type = RUMP_SP_CLIENT; | | 871 | type = RUMP_SP_CLIENT; |
857 | p = p2; | | 872 | p = p2; |
858 | } | | 873 | } |
859 | | | 874 | |
860 | /* | | 875 | /* |
861 | * Parse the url | | 876 | * Parse the url |
862 | */ | | 877 | */ |
863 | | | 878 | |
864 | if (type == RUMP_SP_NONE) | | 879 | if (type == RUMP_SP_NONE) |
865 | return RUMP_SP_NONE; | | 880 | return RUMP_SP_NONE; |
866 | | | 881 | |
867 | p2 = strstr(p, "://"); | | 882 | p2 = strstr(p, "://"); |
868 | if (!p2) { | | 883 | if (!p2) { |
869 | fprintf(stderr, "rump_sp: invalid locator ``%s''\n", p); | | 884 | fprintf(stderr, "rump_sp: invalid locator ``%s''\n", p); |
870 | return EINVAL; | | 885 | return EINVAL; |
871 | } | | 886 | } |
872 | l = p2-p; | | 887 | l = p2-p; |
873 | if (l > sizeof(id)-1) { | | 888 | if (l > sizeof(id)-1) { |
874 | fprintf(stderr, "rump_sp: identifier too long in ``%s''\n", p); | | 889 | fprintf(stderr, "rump_sp: identifier too long in ``%s''\n", p); |
875 | return EINVAL; | | 890 | return EINVAL; |
876 | } | | 891 | } |
877 | | | 892 | |
878 | strncpy(id, p, l); | | 893 | strncpy(id, p, l); |
879 | id[l] = '\0'; | | 894 | id[l] = '\0'; |
880 | p2 += 3; /* beginning of address */ | | 895 | p2 += 3; /* beginning of address */ |
881 | | | 896 | |
882 | for (i = 0; i < NPARSE; i++) { | | 897 | for (i = 0; i < NPARSE; i++) { |
883 | if (strcmp(id, parsetab[i].id) == 0) { | | 898 | if (strcmp(id, parsetab[i].id) == 0) { |
884 | error = parsetab[i].ap(p2, type, &sap); | | 899 | error = parsetab[i].ap(p2, type, &sap); |
885 | if (error) | | 900 | if (error) |
886 | return error; | | 901 | return error; |
887 | break; | | 902 | break; |
888 | } | | 903 | } |
889 | } | | 904 | } |
890 | if (i == NPARSE) { | | 905 | if (i == NPARSE) { |
891 | fprintf(stderr, "rump_sp: invalid identifier ``%s''\n", p); | | 906 | fprintf(stderr, "rump_sp: invalid identifier ``%s''\n", p); |
892 | return EINVAL; | | 907 | return EINVAL; |
893 | } | | 908 | } |
894 | | | 909 | |
895 | s = socket(parsetab[i].domain, SOCK_STREAM, 0); | | 910 | s = socket(parsetab[i].domain, SOCK_STREAM, 0); |
896 | if (s == -1) | | 911 | if (s == -1) |
897 | return errno; | | 912 | return errno; |
898 | | | 913 | |
899 | if (type == RUMP_SP_CLIENT) { | | 914 | if (type == RUMP_SP_CLIENT) { |
900 | /*LINTED*/ | | 915 | /*LINTED*/ |
901 | if (connect(s, sap, sap->sa_len) == -1) { | | 916 | if (connect(s, sap, sap->sa_len) == -1) { |
902 | fprintf(stderr, "rump_sp: client connect failed\n"); | | 917 | fprintf(stderr, "rump_sp: client connect failed\n"); |
903 | return errno; | | 918 | return errno; |
904 | } | | 919 | } |
905 | if ((error = parsetab[i].connhook(s)) != 0) { | | 920 | if ((error = parsetab[i].connhook(s)) != 0) { |
906 | fprintf(stderr, "rump_sp: connect hook failed\n"); | | 921 | fprintf(stderr, "rump_sp: connect hook failed\n"); |
907 | return error; | | 922 | return error; |
908 | } | | 923 | } |
909 | | | 924 | |
910 | clispc.spc_fd = s; | | 925 | clispc.spc_fd = s; |
911 | } else { | | 926 | } else { |
912 | pthread_t pt; | | 927 | pthread_t pt; |
913 | | | 928 | |
914 | sarg = malloc(sizeof(*sarg)); | | 929 | sarg = malloc(sizeof(*sarg)); |
915 | if (sarg == NULL) { | | 930 | if (sarg == NULL) { |
916 | close(s); | | 931 | close(s); |
917 | return ENOMEM; | | 932 | return ENOMEM; |
918 | } | | 933 | } |
919 | | | 934 | |
920 | sarg->sps_sock = s; | | 935 | sarg->sps_sock = s; |
921 | sarg->sps_connhook = parsetab[i].connhook; | | 936 | sarg->sps_connhook = parsetab[i].connhook; |
922 | | | 937 | |
923 | /* sloppy error recovery */ | | 938 | /* sloppy error recovery */ |
924 | | | 939 | |
925 | error = pthread_key_create(&spclient_tls, NULL); | | 940 | error = pthread_key_create(&spclient_tls, NULL); |
926 | if (error) { | | 941 | if (error) { |
927 | fprintf(stderr, "rump_sp: tls create failed\n"); | | 942 | fprintf(stderr, "rump_sp: tls create failed\n"); |
928 | return error; | | 943 | return error; |
929 | } | | 944 | } |
930 | | | 945 | |
931 | /*LINTED*/ | | 946 | /*LINTED*/ |
932 | if (bind(s, sap, sap->sa_len) == -1) { | | 947 | if (bind(s, sap, sap->sa_len) == -1) { |
933 | fprintf(stderr, "rump_sp: server bind failed\n"); | | 948 | fprintf(stderr, "rump_sp: server bind failed\n"); |
934 | return errno; | | 949 | return errno; |
935 | } | | 950 | } |
936 | if (listen(s, 20) == -1) { | | 951 | if (listen(s, 20) == -1) { |
937 | fprintf(stderr, "rump_sp: server listen failed\n"); | | 952 | fprintf(stderr, "rump_sp: server listen failed\n"); |
938 | return errno; | | 953 | return errno; |
939 | } | | 954 | } |
940 | | | 955 | |
941 | if ((error = pthread_create(&pt, NULL, spserver, sarg)) != 0) { | | 956 | if ((error = pthread_create(&pt, NULL, spserver, sarg)) != 0) { |
942 | fprintf(stderr, "rump_sp: cannot create wrkr thread\n"); | | 957 | fprintf(stderr, "rump_sp: cannot create wrkr thread\n"); |
943 | return errno; | | 958 | return errno; |
944 | } | | 959 | } |
945 | pthread_detach(pt); | | 960 | pthread_detach(pt); |
946 | } | | 961 | } |
947 | | | 962 | |
948 | *typep = type; | | 963 | *typep = type; |
949 | return 0; | | 964 | return 0; |
950 | } | | 965 | } |