rumpclient.c revision 1.16.2.3 1 1.16.2.3 bouyer /* $NetBSD: rumpclient.c,v 1.16.2.3 2011/03/05 15:09:23 bouyer Exp $ */
2 1.1 pooka
3 1.1 pooka /*
4 1.11 pooka * Copyright (c) 2010, 2011 Antti Kantee. All Rights Reserved.
5 1.1 pooka *
6 1.1 pooka * Redistribution and use in source and binary forms, with or without
7 1.1 pooka * modification, are permitted provided that the following conditions
8 1.1 pooka * are met:
9 1.1 pooka * 1. Redistributions of source code must retain the above copyright
10 1.1 pooka * notice, this list of conditions and the following disclaimer.
11 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright
12 1.1 pooka * notice, this list of conditions and the following disclaimer in the
13 1.1 pooka * documentation and/or other materials provided with the distribution.
14 1.1 pooka *
15 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 1.1 pooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 1.1 pooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 1.1 pooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 1.1 pooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 1.1 pooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 1.1 pooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 1.1 pooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 1.1 pooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 1.1 pooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 1.1 pooka * SUCH DAMAGE.
26 1.1 pooka */
27 1.1 pooka
28 1.1 pooka /*
29 1.1 pooka * Client side routines for rump syscall proxy.
30 1.1 pooka */
31 1.1 pooka
32 1.1 pooka #include <sys/cdefs.h>
33 1.16.2.3 bouyer __RCSID("$NetBSD: rumpclient.c,v 1.16.2.3 2011/03/05 15:09:23 bouyer Exp $");
34 1.1 pooka
35 1.5 pooka #include <sys/param.h>
36 1.15 pooka #include <sys/event.h>
37 1.1 pooka #include <sys/mman.h>
38 1.1 pooka #include <sys/socket.h>
39 1.1 pooka
40 1.1 pooka #include <arpa/inet.h>
41 1.1 pooka #include <netinet/in.h>
42 1.1 pooka #include <netinet/tcp.h>
43 1.1 pooka
44 1.1 pooka #include <assert.h>
45 1.13 pooka #include <dlfcn.h>
46 1.16.2.3 bouyer #include <err.h>
47 1.1 pooka #include <errno.h>
48 1.1 pooka #include <fcntl.h>
49 1.13 pooka #include <link.h>
50 1.1 pooka #include <poll.h>
51 1.1 pooka #include <pthread.h>
52 1.11 pooka #include <signal.h>
53 1.1 pooka #include <stdarg.h>
54 1.16.2.1 bouyer #include <stdbool.h>
55 1.1 pooka #include <stdio.h>
56 1.1 pooka #include <stdlib.h>
57 1.1 pooka #include <string.h>
58 1.1 pooka #include <unistd.h>
59 1.1 pooka
60 1.1 pooka #include <rump/rumpclient.h>
61 1.1 pooka
62 1.13 pooka #define HOSTOPS
63 1.13 pooka int (*host_socket)(int, int, int);
64 1.13 pooka int (*host_close)(int);
65 1.13 pooka int (*host_connect)(int, const struct sockaddr *, socklen_t);
66 1.15 pooka int (*host_fcntl)(int, int, ...);
67 1.13 pooka int (*host_poll)(struct pollfd *, nfds_t, int);
68 1.13 pooka ssize_t (*host_read)(int, void *, size_t);
69 1.13 pooka ssize_t (*host_sendto)(int, const void *, size_t, int,
70 1.13 pooka const struct sockaddr *, socklen_t);
71 1.13 pooka int (*host_setsockopt)(int, int, int, const void *, socklen_t);
72 1.16.2.2 bouyer int (*host_dup)(int);
73 1.13 pooka
74 1.16.2.1 bouyer int (*host_kqueue)(void);
75 1.16.2.1 bouyer int (*host_kevent)(int, const struct kevent *, size_t,
76 1.16.2.1 bouyer struct kevent *, size_t, const struct timespec *);
77 1.16.2.1 bouyer
78 1.16.2.2 bouyer int (*host_execve)(const char *, char *const[], char *const[]);
79 1.16.2.2 bouyer
80 1.1 pooka #include "sp_common.c"
81 1.1 pooka
82 1.11 pooka static struct spclient clispc = {
83 1.11 pooka .spc_fd = -1,
84 1.11 pooka };
85 1.1 pooka
86 1.16.2.1 bouyer static int kq = -1;
87 1.15 pooka static sigset_t fullset;
88 1.12 pooka
89 1.16.2.1 bouyer static int doconnect(bool);
90 1.16.2.2 bouyer static int handshake_req(struct spclient *, int, void *, int, bool);
91 1.16.2.1 bouyer
92 1.16.2.2 bouyer /*
93 1.16.2.2 bouyer * Default: don't retry. Most clients can't handle it
94 1.16.2.2 bouyer * (consider e.g. fds suddenly going missing).
95 1.16.2.2 bouyer */
96 1.16.2.2 bouyer static time_t retrytimo = 0;
97 1.16.2.1 bouyer
98 1.12 pooka static int
99 1.16.2.1 bouyer send_with_recon(struct spclient *spc, const void *data, size_t dlen)
100 1.12 pooka {
101 1.16.2.1 bouyer struct timeval starttime, curtime;
102 1.16.2.1 bouyer time_t prevreconmsg;
103 1.16.2.1 bouyer unsigned reconretries;
104 1.16.2.1 bouyer int rv;
105 1.16.2.1 bouyer
106 1.16.2.1 bouyer for (prevreconmsg = 0, reconretries = 0;;) {
107 1.16.2.1 bouyer rv = dosend(spc, data, dlen);
108 1.16.2.1 bouyer if (__predict_false(rv == ENOTCONN || rv == EBADF)) {
109 1.16.2.1 bouyer /* no persistent connections */
110 1.16.2.2 bouyer if (retrytimo == 0) {
111 1.16.2.2 bouyer rv = ENOTCONN;
112 1.16.2.1 bouyer break;
113 1.16.2.2 bouyer }
114 1.16.2.1 bouyer if (retrytimo == RUMPCLIENT_RETRYCONN_DIE)
115 1.16.2.1 bouyer exit(1);
116 1.16.2.1 bouyer
117 1.16.2.1 bouyer if (!prevreconmsg) {
118 1.16.2.1 bouyer prevreconmsg = time(NULL);
119 1.16.2.1 bouyer gettimeofday(&starttime, NULL);
120 1.16.2.1 bouyer }
121 1.16.2.1 bouyer if (reconretries == 1) {
122 1.16.2.1 bouyer if (retrytimo == RUMPCLIENT_RETRYCONN_ONCE) {
123 1.16.2.1 bouyer rv = ENOTCONN;
124 1.16.2.1 bouyer break;
125 1.16.2.1 bouyer }
126 1.16.2.1 bouyer fprintf(stderr, "rump_sp: connection to "
127 1.16.2.1 bouyer "kernel lost, trying to reconnect ...\n");
128 1.16.2.1 bouyer } else if (time(NULL) - prevreconmsg > 120) {
129 1.16.2.1 bouyer fprintf(stderr, "rump_sp: still trying to "
130 1.16.2.1 bouyer "reconnect ...\n");
131 1.16.2.1 bouyer prevreconmsg = time(NULL);
132 1.16.2.1 bouyer }
133 1.16.2.1 bouyer
134 1.16.2.1 bouyer /* check that we aren't over the limit */
135 1.16.2.1 bouyer if (retrytimo > 0) {
136 1.16.2.1 bouyer struct timeval tmp;
137 1.16.2.1 bouyer
138 1.16.2.1 bouyer gettimeofday(&curtime, NULL);
139 1.16.2.1 bouyer timersub(&curtime, &starttime, &tmp);
140 1.16.2.1 bouyer if (tmp.tv_sec >= retrytimo) {
141 1.16.2.1 bouyer fprintf(stderr, "rump_sp: reconnect "
142 1.16.2.1 bouyer "failed, %lld second timeout\n",
143 1.16.2.1 bouyer (long long)retrytimo);
144 1.16.2.1 bouyer return ENOTCONN;
145 1.16.2.1 bouyer }
146 1.16.2.1 bouyer }
147 1.16.2.1 bouyer
148 1.16.2.1 bouyer /* adhoc backoff timer */
149 1.16.2.1 bouyer if (reconretries < 10) {
150 1.16.2.1 bouyer usleep(100000 * reconretries);
151 1.16.2.1 bouyer } else {
152 1.16.2.1 bouyer sleep(MIN(10, reconretries-9));
153 1.16.2.1 bouyer }
154 1.16.2.1 bouyer reconretries++;
155 1.16.2.1 bouyer
156 1.16.2.1 bouyer if ((rv = doconnect(false)) != 0)
157 1.16.2.1 bouyer continue;
158 1.16.2.2 bouyer if ((rv = handshake_req(&clispc, HANDSHAKE_GUEST,
159 1.16.2.2 bouyer NULL, 0, true)) != 0)
160 1.16.2.1 bouyer continue;
161 1.16.2.1 bouyer
162 1.16.2.1 bouyer /*
163 1.16.2.1 bouyer * ok, reconnect succesful. we need to return to
164 1.16.2.1 bouyer * the upper layer to get the entire PDU resent.
165 1.16.2.1 bouyer */
166 1.16.2.1 bouyer if (reconretries != 1)
167 1.16.2.1 bouyer fprintf(stderr, "rump_sp: reconnected!\n");
168 1.16.2.1 bouyer rv = EAGAIN;
169 1.16.2.1 bouyer break;
170 1.16.2.1 bouyer } else {
171 1.16.2.1 bouyer _DIAGASSERT(errno != EAGAIN);
172 1.16.2.1 bouyer break;
173 1.16.2.1 bouyer }
174 1.16.2.1 bouyer }
175 1.16.2.1 bouyer
176 1.16.2.1 bouyer return rv;
177 1.16.2.1 bouyer }
178 1.16.2.1 bouyer
179 1.16.2.1 bouyer static int
180 1.16.2.1 bouyer cliwaitresp(struct spclient *spc, struct respwait *rw, sigset_t *mask,
181 1.16.2.1 bouyer bool keeplock)
182 1.16.2.1 bouyer {
183 1.16.2.1 bouyer uint64_t mygen;
184 1.16.2.1 bouyer bool imalive = true;
185 1.12 pooka
186 1.15 pooka pthread_mutex_lock(&spc->spc_mtx);
187 1.16.2.1 bouyer if (!keeplock)
188 1.16.2.1 bouyer sendunlockl(spc);
189 1.16.2.1 bouyer mygen = spc->spc_generation;
190 1.12 pooka
191 1.12 pooka rw->rw_error = 0;
192 1.16.2.1 bouyer while (!rw->rw_done && rw->rw_error == 0) {
193 1.16.2.1 bouyer if (__predict_false(spc->spc_generation != mygen || !imalive))
194 1.16.2.1 bouyer break;
195 1.16.2.1 bouyer
196 1.12 pooka /* are we free to receive? */
197 1.12 pooka if (spc->spc_istatus == SPCSTATUS_FREE) {
198 1.15 pooka struct kevent kev[8];
199 1.15 pooka int gotresp, dosig, rv, i;
200 1.15 pooka
201 1.12 pooka spc->spc_istatus = SPCSTATUS_BUSY;
202 1.12 pooka pthread_mutex_unlock(&spc->spc_mtx);
203 1.12 pooka
204 1.15 pooka dosig = 0;
205 1.15 pooka for (gotresp = 0; !gotresp; ) {
206 1.15 pooka switch (readframe(spc)) {
207 1.15 pooka case 0:
208 1.16.2.1 bouyer rv = host_kevent(kq, NULL, 0,
209 1.15 pooka kev, __arraycount(kev), NULL);
210 1.16.2.1 bouyer
211 1.16.2.2 bouyer if (__predict_false(rv == -1)) {
212 1.16.2.2 bouyer goto cleanup;
213 1.16.2.2 bouyer }
214 1.16.2.2 bouyer
215 1.16.2.1 bouyer /*
216 1.16.2.1 bouyer * XXX: don't know how this can
217 1.16.2.1 bouyer * happen (timeout cannot expire
218 1.16.2.1 bouyer * since there isn't one), but
219 1.16.2.1 bouyer * it does happen
220 1.16.2.1 bouyer */
221 1.16.2.1 bouyer if (__predict_false(rv == 0))
222 1.16.2.1 bouyer continue;
223 1.16.2.1 bouyer
224 1.15 pooka for (i = 0; i < rv; i++) {
225 1.15 pooka if (kev[i].filter
226 1.15 pooka == EVFILT_SIGNAL)
227 1.15 pooka dosig++;
228 1.15 pooka }
229 1.15 pooka if (dosig)
230 1.15 pooka goto cleanup;
231 1.15 pooka
232 1.15 pooka continue;
233 1.15 pooka case -1:
234 1.16.2.1 bouyer imalive = false;
235 1.15 pooka goto cleanup;
236 1.15 pooka default:
237 1.15 pooka break;
238 1.15 pooka }
239 1.12 pooka
240 1.15 pooka switch (spc->spc_hdr.rsp_class) {
241 1.12 pooka case RUMPSP_RESP:
242 1.12 pooka case RUMPSP_ERROR:
243 1.12 pooka kickwaiter(spc);
244 1.15 pooka gotresp = spc->spc_hdr.rsp_reqno ==
245 1.15 pooka rw->rw_reqno;
246 1.12 pooka break;
247 1.12 pooka case RUMPSP_REQ:
248 1.12 pooka handlereq(spc);
249 1.12 pooka break;
250 1.12 pooka default:
251 1.12 pooka /* panic */
252 1.12 pooka break;
253 1.15 pooka }
254 1.12 pooka }
255 1.12 pooka
256 1.15 pooka cleanup:
257 1.15 pooka pthread_mutex_lock(&spc->spc_mtx);
258 1.15 pooka if (spc->spc_istatus == SPCSTATUS_WANTED)
259 1.15 pooka kickall(spc);
260 1.15 pooka spc->spc_istatus = SPCSTATUS_FREE;
261 1.15 pooka
262 1.15 pooka /* take one for the team */
263 1.15 pooka if (dosig) {
264 1.15 pooka pthread_mutex_unlock(&spc->spc_mtx);
265 1.15 pooka pthread_sigmask(SIG_SETMASK, mask, NULL);
266 1.15 pooka pthread_sigmask(SIG_SETMASK, &fullset, NULL);
267 1.15 pooka pthread_mutex_lock(&spc->spc_mtx);
268 1.15 pooka }
269 1.12 pooka } else {
270 1.12 pooka spc->spc_istatus = SPCSTATUS_WANTED;
271 1.12 pooka pthread_cond_wait(&rw->rw_cv, &spc->spc_mtx);
272 1.12 pooka }
273 1.12 pooka }
274 1.12 pooka TAILQ_REMOVE(&spc->spc_respwait, rw, rw_entries);
275 1.12 pooka pthread_mutex_unlock(&spc->spc_mtx);
276 1.12 pooka pthread_cond_destroy(&rw->rw_cv);
277 1.12 pooka
278 1.16.2.1 bouyer if (spc->spc_generation != mygen || !imalive) {
279 1.12 pooka return ENOTCONN;
280 1.16.2.1 bouyer }
281 1.12 pooka return rw->rw_error;
282 1.12 pooka }
283 1.12 pooka
284 1.1 pooka static int
285 1.16.2.1 bouyer syscall_req(struct spclient *spc, sigset_t *omask, int sysnum,
286 1.3 pooka const void *data, size_t dlen, void **resp)
287 1.1 pooka {
288 1.1 pooka struct rsp_hdr rhdr;
289 1.3 pooka struct respwait rw;
290 1.3 pooka int rv;
291 1.1 pooka
292 1.1 pooka rhdr.rsp_len = sizeof(rhdr) + dlen;
293 1.3 pooka rhdr.rsp_class = RUMPSP_REQ;
294 1.3 pooka rhdr.rsp_type = RUMPSP_SYSCALL;
295 1.1 pooka rhdr.rsp_sysnum = sysnum;
296 1.1 pooka
297 1.6 pooka do {
298 1.6 pooka putwait(spc, &rw, &rhdr);
299 1.16.2.1 bouyer if ((rv = send_with_recon(spc, &rhdr, sizeof(rhdr))) != 0) {
300 1.16.2.1 bouyer unputwait(spc, &rw);
301 1.16.2.1 bouyer continue;
302 1.16.2.1 bouyer }
303 1.16.2.1 bouyer if ((rv = send_with_recon(spc, data, dlen)) != 0) {
304 1.6 pooka unputwait(spc, &rw);
305 1.16.2.1 bouyer continue;
306 1.6 pooka }
307 1.6 pooka
308 1.16.2.1 bouyer rv = cliwaitresp(spc, &rw, omask, false);
309 1.16.2.1 bouyer if (rv == ENOTCONN)
310 1.16.2.1 bouyer rv = EAGAIN;
311 1.6 pooka } while (rv == EAGAIN);
312 1.3 pooka
313 1.3 pooka *resp = rw.rw_data;
314 1.3 pooka return rv;
315 1.1 pooka }
316 1.1 pooka
317 1.1 pooka static int
318 1.16.2.2 bouyer handshake_req(struct spclient *spc, int type, void *data,
319 1.16.2.2 bouyer int cancel, bool haslock)
320 1.10 pooka {
321 1.11 pooka struct handshake_fork rf;
322 1.10 pooka struct rsp_hdr rhdr;
323 1.10 pooka struct respwait rw;
324 1.12 pooka sigset_t omask;
325 1.16.2.1 bouyer size_t bonus;
326 1.10 pooka int rv;
327 1.10 pooka
328 1.16.2.2 bouyer if (type == HANDSHAKE_FORK) {
329 1.16.2.1 bouyer bonus = sizeof(rf);
330 1.16.2.1 bouyer } else {
331 1.16.2.1 bouyer bonus = strlen(getprogname())+1;
332 1.16.2.1 bouyer }
333 1.16.2.1 bouyer
334 1.10 pooka /* performs server handshake */
335 1.16.2.1 bouyer rhdr.rsp_len = sizeof(rhdr) + bonus;
336 1.10 pooka rhdr.rsp_class = RUMPSP_REQ;
337 1.10 pooka rhdr.rsp_type = RUMPSP_HANDSHAKE;
338 1.16.2.2 bouyer rhdr.rsp_handshake = type;
339 1.10 pooka
340 1.12 pooka pthread_sigmask(SIG_SETMASK, &fullset, &omask);
341 1.16.2.1 bouyer if (haslock)
342 1.16.2.1 bouyer putwait_locked(spc, &rw, &rhdr);
343 1.16.2.1 bouyer else
344 1.16.2.1 bouyer putwait(spc, &rw, &rhdr);
345 1.10 pooka rv = dosend(spc, &rhdr, sizeof(rhdr));
346 1.16.2.2 bouyer if (type == HANDSHAKE_FORK) {
347 1.16.2.2 bouyer memcpy(rf.rf_auth, data, sizeof(rf.rf_auth)); /* uh, why? */
348 1.11 pooka rf.rf_cancel = cancel;
349 1.16.2.1 bouyer rv = send_with_recon(spc, &rf, sizeof(rf));
350 1.16.2.1 bouyer } else {
351 1.16.2.1 bouyer rv = dosend(spc, getprogname(), strlen(getprogname())+1);
352 1.16.2.1 bouyer }
353 1.16.2.1 bouyer if (rv || cancel) {
354 1.16.2.1 bouyer if (haslock)
355 1.16.2.1 bouyer unputwait_locked(spc, &rw);
356 1.16.2.1 bouyer else
357 1.16.2.1 bouyer unputwait(spc, &rw);
358 1.16.2.1 bouyer if (cancel) {
359 1.16.2.1 bouyer goto out;
360 1.16.2.1 bouyer }
361 1.16.2.1 bouyer } else {
362 1.16.2.1 bouyer rv = cliwaitresp(spc, &rw, &omask, haslock);
363 1.10 pooka }
364 1.10 pooka if (rv)
365 1.16.2.1 bouyer goto out;
366 1.10 pooka
367 1.10 pooka rv = *(int *)rw.rw_data;
368 1.10 pooka free(rw.rw_data);
369 1.10 pooka
370 1.16.2.1 bouyer out:
371 1.16.2.1 bouyer pthread_sigmask(SIG_SETMASK, &omask, NULL);
372 1.10 pooka return rv;
373 1.10 pooka }
374 1.10 pooka
375 1.10 pooka static int
376 1.16.2.1 bouyer prefork_req(struct spclient *spc, sigset_t *omask, void **resp)
377 1.11 pooka {
378 1.11 pooka struct rsp_hdr rhdr;
379 1.11 pooka struct respwait rw;
380 1.11 pooka int rv;
381 1.11 pooka
382 1.11 pooka rhdr.rsp_len = sizeof(rhdr);
383 1.11 pooka rhdr.rsp_class = RUMPSP_REQ;
384 1.11 pooka rhdr.rsp_type = RUMPSP_PREFORK;
385 1.11 pooka rhdr.rsp_error = 0;
386 1.11 pooka
387 1.16.2.1 bouyer do {
388 1.16.2.1 bouyer putwait(spc, &rw, &rhdr);
389 1.16.2.1 bouyer rv = send_with_recon(spc, &rhdr, sizeof(rhdr));
390 1.16.2.1 bouyer if (rv != 0) {
391 1.16.2.1 bouyer unputwait(spc, &rw);
392 1.16.2.1 bouyer continue;
393 1.16.2.1 bouyer }
394 1.16.2.1 bouyer
395 1.16.2.1 bouyer rv = cliwaitresp(spc, &rw, omask, false);
396 1.16.2.1 bouyer if (rv == ENOTCONN)
397 1.16.2.1 bouyer rv = EAGAIN;
398 1.16.2.1 bouyer } while (rv == EAGAIN);
399 1.11 pooka
400 1.11 pooka *resp = rw.rw_data;
401 1.11 pooka return rv;
402 1.11 pooka }
403 1.11 pooka
404 1.16.2.1 bouyer /*
405 1.16.2.1 bouyer * prevent response code from deadlocking with reconnect code
406 1.16.2.1 bouyer */
407 1.11 pooka static int
408 1.16.2.1 bouyer resp_sendlock(struct spclient *spc)
409 1.16.2.1 bouyer {
410 1.16.2.1 bouyer int rv = 0;
411 1.16.2.1 bouyer
412 1.16.2.1 bouyer pthread_mutex_lock(&spc->spc_mtx);
413 1.16.2.1 bouyer while (spc->spc_ostatus != SPCSTATUS_FREE) {
414 1.16.2.1 bouyer if (__predict_false(spc->spc_reconnecting)) {
415 1.16.2.1 bouyer rv = EBUSY;
416 1.16.2.1 bouyer goto out;
417 1.16.2.1 bouyer }
418 1.16.2.1 bouyer spc->spc_ostatus = SPCSTATUS_WANTED;
419 1.16.2.1 bouyer pthread_cond_wait(&spc->spc_cv, &spc->spc_mtx);
420 1.16.2.1 bouyer }
421 1.16.2.1 bouyer spc->spc_ostatus = SPCSTATUS_BUSY;
422 1.16.2.1 bouyer
423 1.16.2.1 bouyer out:
424 1.16.2.1 bouyer pthread_mutex_unlock(&spc->spc_mtx);
425 1.16.2.1 bouyer return rv;
426 1.16.2.1 bouyer }
427 1.16.2.1 bouyer
428 1.16.2.1 bouyer static void
429 1.5 pooka send_copyin_resp(struct spclient *spc, uint64_t reqno, void *data, size_t dlen,
430 1.5 pooka int wantstr)
431 1.1 pooka {
432 1.1 pooka struct rsp_hdr rhdr;
433 1.1 pooka
434 1.5 pooka if (wantstr)
435 1.5 pooka dlen = MIN(dlen, strlen(data)+1);
436 1.5 pooka
437 1.1 pooka rhdr.rsp_len = sizeof(rhdr) + dlen;
438 1.1 pooka rhdr.rsp_reqno = reqno;
439 1.3 pooka rhdr.rsp_class = RUMPSP_RESP;
440 1.3 pooka rhdr.rsp_type = RUMPSP_COPYIN;
441 1.1 pooka rhdr.rsp_sysnum = 0;
442 1.1 pooka
443 1.16.2.1 bouyer if (resp_sendlock(spc) != 0)
444 1.16.2.1 bouyer return;
445 1.16.2.1 bouyer (void)dosend(spc, &rhdr, sizeof(rhdr));
446 1.16.2.1 bouyer (void)dosend(spc, data, dlen);
447 1.3 pooka sendunlock(spc);
448 1.1 pooka }
449 1.1 pooka
450 1.16.2.1 bouyer static void
451 1.1 pooka send_anonmmap_resp(struct spclient *spc, uint64_t reqno, void *addr)
452 1.1 pooka {
453 1.1 pooka struct rsp_hdr rhdr;
454 1.1 pooka
455 1.1 pooka rhdr.rsp_len = sizeof(rhdr) + sizeof(addr);
456 1.1 pooka rhdr.rsp_reqno = reqno;
457 1.3 pooka rhdr.rsp_class = RUMPSP_RESP;
458 1.3 pooka rhdr.rsp_type = RUMPSP_ANONMMAP;
459 1.1 pooka rhdr.rsp_sysnum = 0;
460 1.1 pooka
461 1.16.2.1 bouyer if (resp_sendlock(spc) != 0)
462 1.16.2.1 bouyer return;
463 1.16.2.1 bouyer (void)dosend(spc, &rhdr, sizeof(rhdr));
464 1.16.2.1 bouyer (void)dosend(spc, &addr, sizeof(addr));
465 1.3 pooka sendunlock(spc);
466 1.1 pooka }
467 1.1 pooka
468 1.1 pooka int
469 1.1 pooka rumpclient_syscall(int sysnum, const void *data, size_t dlen,
470 1.1 pooka register_t *retval)
471 1.1 pooka {
472 1.1 pooka struct rsp_sysresp *resp;
473 1.16.2.1 bouyer sigset_t omask;
474 1.3 pooka void *rdata;
475 1.3 pooka int rv;
476 1.3 pooka
477 1.16.2.1 bouyer pthread_sigmask(SIG_SETMASK, &fullset, &omask);
478 1.16.2.1 bouyer
479 1.3 pooka DPRINTF(("rumpsp syscall_req: syscall %d with %p/%zu\n",
480 1.3 pooka sysnum, data, dlen));
481 1.3 pooka
482 1.16.2.1 bouyer rv = syscall_req(&clispc, &omask, sysnum, data, dlen, &rdata);
483 1.3 pooka if (rv)
484 1.16.2.1 bouyer goto out;
485 1.3 pooka
486 1.3 pooka resp = rdata;
487 1.3 pooka DPRINTF(("rumpsp syscall_resp: syscall %d error %d, rv: %d/%d\n",
488 1.3 pooka sysnum, rv, resp->rsys_retval[0], resp->rsys_retval[1]));
489 1.1 pooka
490 1.3 pooka memcpy(retval, &resp->rsys_retval, sizeof(resp->rsys_retval));
491 1.3 pooka rv = resp->rsys_error;
492 1.3 pooka free(rdata);
493 1.1 pooka
494 1.16.2.1 bouyer out:
495 1.16.2.1 bouyer pthread_sigmask(SIG_SETMASK, &omask, NULL);
496 1.3 pooka return rv;
497 1.3 pooka }
498 1.1 pooka
499 1.3 pooka static void
500 1.3 pooka handlereq(struct spclient *spc)
501 1.3 pooka {
502 1.3 pooka struct rsp_copydata *copydata;
503 1.16 pooka struct rsp_hdr *rhdr = &spc->spc_hdr;
504 1.3 pooka void *mapaddr;
505 1.3 pooka size_t maplen;
506 1.5 pooka int reqtype = spc->spc_hdr.rsp_type;
507 1.1 pooka
508 1.5 pooka switch (reqtype) {
509 1.3 pooka case RUMPSP_COPYIN:
510 1.5 pooka case RUMPSP_COPYINSTR:
511 1.3 pooka /*LINTED*/
512 1.3 pooka copydata = (struct rsp_copydata *)spc->spc_buf;
513 1.3 pooka DPRINTF(("rump_sp handlereq: copyin request: %p/%zu\n",
514 1.3 pooka copydata->rcp_addr, copydata->rcp_len));
515 1.3 pooka send_copyin_resp(spc, spc->spc_hdr.rsp_reqno,
516 1.5 pooka copydata->rcp_addr, copydata->rcp_len,
517 1.5 pooka reqtype == RUMPSP_COPYINSTR);
518 1.3 pooka break;
519 1.3 pooka case RUMPSP_COPYOUT:
520 1.5 pooka case RUMPSP_COPYOUTSTR:
521 1.3 pooka /*LINTED*/
522 1.3 pooka copydata = (struct rsp_copydata *)spc->spc_buf;
523 1.3 pooka DPRINTF(("rump_sp handlereq: copyout request: %p/%zu\n",
524 1.3 pooka copydata->rcp_addr, copydata->rcp_len));
525 1.3 pooka /*LINTED*/
526 1.3 pooka memcpy(copydata->rcp_addr, copydata->rcp_data,
527 1.3 pooka copydata->rcp_len);
528 1.3 pooka break;
529 1.3 pooka case RUMPSP_ANONMMAP:
530 1.3 pooka /*LINTED*/
531 1.3 pooka maplen = *(size_t *)spc->spc_buf;
532 1.3 pooka mapaddr = mmap(NULL, maplen, PROT_READ|PROT_WRITE,
533 1.3 pooka MAP_ANON, -1, 0);
534 1.3 pooka if (mapaddr == MAP_FAILED)
535 1.3 pooka mapaddr = NULL;
536 1.3 pooka DPRINTF(("rump_sp handlereq: anonmmap: %p\n", mapaddr));
537 1.3 pooka send_anonmmap_resp(spc, spc->spc_hdr.rsp_reqno, mapaddr);
538 1.3 pooka break;
539 1.16 pooka case RUMPSP_RAISE:
540 1.16 pooka DPRINTF(("rump_sp handlereq: raise sig %d\n", rhdr->rsp_signo));
541 1.16.2.1 bouyer raise((int)rhdr->rsp_signo);
542 1.16 pooka /*
543 1.16 pooka * We most likely have signals blocked, but the signal
544 1.16 pooka * will be handled soon enough when we return.
545 1.16 pooka */
546 1.16 pooka break;
547 1.3 pooka default:
548 1.12 pooka printf("PANIC: INVALID TYPE %d\n", reqtype);
549 1.3 pooka abort();
550 1.3 pooka break;
551 1.1 pooka }
552 1.1 pooka
553 1.6 pooka spcfreebuf(spc);
554 1.1 pooka }
555 1.1 pooka
556 1.11 pooka static unsigned ptab_idx;
557 1.11 pooka static struct sockaddr *serv_sa;
558 1.11 pooka
559 1.16.2.2 bouyer /* dup until we get a "good" fd which does not collide with stdio */
560 1.16.2.2 bouyer static int
561 1.16.2.2 bouyer dupgood(int myfd, int mustchange)
562 1.16.2.2 bouyer {
563 1.16.2.2 bouyer int ofds[4];
564 1.16.2.2 bouyer int i;
565 1.16.2.2 bouyer
566 1.16.2.2 bouyer for (i = 0; (myfd <= 2 || mustchange) && myfd != -1; i++) {
567 1.16.2.2 bouyer assert(i < __arraycount(ofds));
568 1.16.2.2 bouyer ofds[i] = myfd;
569 1.16.2.2 bouyer myfd = host_dup(myfd);
570 1.16.2.2 bouyer if (mustchange) {
571 1.16.2.2 bouyer i--; /* prevent closing old fd */
572 1.16.2.2 bouyer mustchange = 0;
573 1.16.2.2 bouyer }
574 1.16.2.2 bouyer }
575 1.16.2.2 bouyer
576 1.16.2.2 bouyer for (i--; i >= 0; i--) {
577 1.16.2.2 bouyer host_close(ofds[i]);
578 1.16.2.2 bouyer }
579 1.16.2.2 bouyer
580 1.16.2.2 bouyer return myfd;
581 1.16.2.2 bouyer }
582 1.16.2.2 bouyer
583 1.11 pooka static int
584 1.16.2.1 bouyer doconnect(bool noisy)
585 1.1 pooka {
586 1.16.2.1 bouyer struct respwait rw;
587 1.16.2.1 bouyer struct rsp_hdr rhdr;
588 1.15 pooka struct kevent kev[NSIG+1];
589 1.9 pooka char banner[MAXBANNER];
590 1.16.2.1 bouyer struct pollfd pfd;
591 1.15 pooka int s, error, flags, i;
592 1.9 pooka ssize_t n;
593 1.1 pooka
594 1.16.2.1 bouyer if (kq != -1)
595 1.16.2.1 bouyer host_close(kq);
596 1.16.2.1 bouyer kq = -1;
597 1.16.2.1 bouyer s = -1;
598 1.16.2.1 bouyer
599 1.16.2.1 bouyer if (clispc.spc_fd != -1)
600 1.16.2.1 bouyer host_close(clispc.spc_fd);
601 1.16.2.1 bouyer clispc.spc_fd = -1;
602 1.16.2.1 bouyer
603 1.16.2.1 bouyer /*
604 1.16.2.1 bouyer * for reconnect, gate everyone out of the receiver code
605 1.16.2.1 bouyer */
606 1.16.2.1 bouyer putwait_locked(&clispc, &rw, &rhdr);
607 1.16.2.1 bouyer
608 1.16.2.1 bouyer pthread_mutex_lock(&clispc.spc_mtx);
609 1.16.2.1 bouyer clispc.spc_reconnecting = 1;
610 1.16.2.1 bouyer pthread_cond_broadcast(&clispc.spc_cv);
611 1.16.2.1 bouyer clispc.spc_generation++;
612 1.16.2.1 bouyer while (clispc.spc_istatus != SPCSTATUS_FREE) {
613 1.16.2.1 bouyer clispc.spc_istatus = SPCSTATUS_WANTED;
614 1.16.2.1 bouyer pthread_cond_wait(&rw.rw_cv, &clispc.spc_mtx);
615 1.16.2.1 bouyer }
616 1.16.2.1 bouyer kickall(&clispc);
617 1.16.2.1 bouyer
618 1.16.2.1 bouyer /*
619 1.16.2.1 bouyer * we can release it already since we hold the
620 1.16.2.1 bouyer * send lock during reconnect
621 1.16.2.1 bouyer * XXX: assert it
622 1.16.2.1 bouyer */
623 1.16.2.1 bouyer clispc.spc_istatus = SPCSTATUS_FREE;
624 1.16.2.1 bouyer pthread_mutex_unlock(&clispc.spc_mtx);
625 1.16.2.1 bouyer unputwait_locked(&clispc, &rw);
626 1.16.2.1 bouyer
627 1.16.2.1 bouyer free(clispc.spc_buf);
628 1.16.2.1 bouyer clispc.spc_off = 0;
629 1.16.2.1 bouyer
630 1.16.2.2 bouyer s = dupgood(host_socket(parsetab[ptab_idx].domain, SOCK_STREAM, 0), 0);
631 1.11 pooka if (s == -1)
632 1.2 pooka return -1;
633 1.1 pooka
634 1.16.2.1 bouyer pfd.fd = s;
635 1.16.2.1 bouyer pfd.events = POLLIN;
636 1.16.2.1 bouyer while (host_connect(s, serv_sa, (socklen_t)serv_sa->sa_len) == -1) {
637 1.16.2.1 bouyer if (errno == EINTR)
638 1.16.2.1 bouyer continue;
639 1.11 pooka error = errno;
640 1.16.2.1 bouyer if (noisy)
641 1.16.2.1 bouyer fprintf(stderr, "rump_sp: client connect failed: %s\n",
642 1.16.2.1 bouyer strerror(errno));
643 1.2 pooka errno = error;
644 1.2 pooka return -1;
645 1.2 pooka }
646 1.1 pooka
647 1.11 pooka if ((error = parsetab[ptab_idx].connhook(s)) != 0) {
648 1.2 pooka error = errno;
649 1.16.2.1 bouyer if (noisy)
650 1.16.2.1 bouyer fprintf(stderr, "rump_sp: connect hook failed\n");
651 1.2 pooka errno = error;
652 1.2 pooka return -1;
653 1.1 pooka }
654 1.4 pooka
655 1.13 pooka if ((n = host_read(s, banner, sizeof(banner)-1)) < 0) {
656 1.2 pooka error = errno;
657 1.16.2.1 bouyer if (noisy)
658 1.16.2.1 bouyer fprintf(stderr, "rump_sp: failed to read banner\n");
659 1.2 pooka errno = error;
660 1.2 pooka return -1;
661 1.1 pooka }
662 1.9 pooka
663 1.9 pooka if (banner[n-1] != '\n') {
664 1.16.2.1 bouyer if (noisy)
665 1.16.2.1 bouyer fprintf(stderr, "rump_sp: invalid banner\n");
666 1.9 pooka errno = EINVAL;
667 1.9 pooka return -1;
668 1.9 pooka }
669 1.9 pooka banner[n] = '\0';
670 1.16.2.1 bouyer /* parse the banner some day */
671 1.9 pooka
672 1.15 pooka flags = host_fcntl(s, F_GETFL, 0);
673 1.15 pooka if (host_fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) {
674 1.16.2.1 bouyer if (noisy)
675 1.16.2.1 bouyer fprintf(stderr, "rump_sp: socket fd NONBLOCK: %s\n",
676 1.16.2.1 bouyer strerror(errno));
677 1.15 pooka errno = EINVAL;
678 1.15 pooka return -1;
679 1.15 pooka }
680 1.16.2.1 bouyer clispc.spc_fd = s;
681 1.16.2.1 bouyer clispc.spc_state = SPCSTATE_RUNNING;
682 1.16.2.1 bouyer clispc.spc_reconnecting = 0;
683 1.9 pooka
684 1.15 pooka /* setup kqueue, we want all signals and the fd */
685 1.16.2.2 bouyer if ((kq = dupgood(host_kqueue(), 0)) == -1) {
686 1.15 pooka error = errno;
687 1.16.2.1 bouyer if (noisy)
688 1.16.2.1 bouyer fprintf(stderr, "rump_sp: cannot setup kqueue");
689 1.15 pooka errno = error;
690 1.15 pooka return -1;
691 1.15 pooka }
692 1.15 pooka
693 1.15 pooka for (i = 0; i < NSIG; i++) {
694 1.15 pooka EV_SET(&kev[i], i+1, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0);
695 1.15 pooka }
696 1.16.2.1 bouyer EV_SET(&kev[NSIG], clispc.spc_fd,
697 1.16.2.1 bouyer EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0);
698 1.16.2.1 bouyer if (host_kevent(kq, kev, NSIG+1, NULL, 0, NULL) == -1) {
699 1.15 pooka error = errno;
700 1.16.2.1 bouyer if (noisy)
701 1.16.2.1 bouyer fprintf(stderr, "rump_sp: kevent() failed");
702 1.15 pooka errno = error;
703 1.15 pooka return -1;
704 1.15 pooka }
705 1.15 pooka
706 1.16.2.1 bouyer return 0;
707 1.16.2.1 bouyer }
708 1.16.2.1 bouyer
709 1.16.2.1 bouyer static int
710 1.16.2.1 bouyer doinit(void)
711 1.16.2.1 bouyer {
712 1.16.2.1 bouyer
713 1.11 pooka TAILQ_INIT(&clispc.spc_respwait);
714 1.11 pooka pthread_mutex_init(&clispc.spc_mtx, NULL);
715 1.11 pooka pthread_cond_init(&clispc.spc_cv, NULL);
716 1.11 pooka
717 1.11 pooka return 0;
718 1.11 pooka }
719 1.11 pooka
720 1.16.2.3 bouyer void *rumpclient__dlsym(void *, const char *);
721 1.16.2.3 bouyer void *rumphijack_dlsym(void *, const char *);
722 1.16.2.3 bouyer void *
723 1.16.2.3 bouyer rumpclient__dlsym(void *handle, const char *symbol)
724 1.16.2.3 bouyer {
725 1.16.2.3 bouyer
726 1.16.2.3 bouyer return dlsym(handle, symbol);
727 1.16.2.3 bouyer }
728 1.16.2.3 bouyer __weak_alias(rumphijack_dlsym,rumpclient__dlsym);
729 1.16.2.3 bouyer
730 1.16.2.3 bouyer static pid_t init_done = 0;
731 1.13 pooka
732 1.11 pooka int
733 1.11 pooka rumpclient_init()
734 1.11 pooka {
735 1.11 pooka char *p;
736 1.11 pooka int error;
737 1.16.2.2 bouyer int rv = -1;
738 1.16.2.2 bouyer int hstype;
739 1.16.2.3 bouyer pid_t mypid;
740 1.16.2.2 bouyer
741 1.16.2.3 bouyer /*
742 1.16.2.3 bouyer * Make sure we're not riding the context of a previous
743 1.16.2.3 bouyer * host fork. Note: it's *possible* that after n>1 forks
744 1.16.2.3 bouyer * we have the same pid as one of our exited parents, but
745 1.16.2.3 bouyer * I'm pretty sure there are 0 practical implications, since
746 1.16.2.3 bouyer * it means generations would have to skip rumpclient init.
747 1.16.2.3 bouyer */
748 1.16.2.3 bouyer if (init_done == (mypid = getpid()))
749 1.16.2.2 bouyer return 0;
750 1.11 pooka
751 1.16.2.3 bouyer /* kq does not traverse fork() */
752 1.16.2.3 bouyer if (init_done != 0)
753 1.16.2.3 bouyer kq = -1;
754 1.16.2.3 bouyer init_done = mypid;
755 1.16.2.1 bouyer
756 1.16.2.3 bouyer sigfillset(&fullset);
757 1.13 pooka
758 1.13 pooka /*
759 1.13 pooka * sag mir, wo die symbol sind. zogen fort, der krieg beginnt.
760 1.13 pooka * wann wird man je verstehen? wann wird man je verstehen?
761 1.13 pooka */
762 1.13 pooka #define FINDSYM2(_name_,_syscall_) \
763 1.16.2.3 bouyer if ((host_##_name_ = rumphijack_dlsym(RTLD_NEXT, \
764 1.16.2.3 bouyer #_syscall_)) == NULL) { \
765 1.16.2.3 bouyer if (rumphijack_dlsym == rumpclient__dlsym) \
766 1.16.2.3 bouyer host_##_name_ = _name_; /* static fallback */ \
767 1.16.2.3 bouyer if (host_##_name_ == NULL) \
768 1.16.2.3 bouyer errx(1, "cannot find %s: %s", #_syscall_, \
769 1.16.2.3 bouyer dlerror()); \
770 1.16.2.3 bouyer }
771 1.13 pooka #define FINDSYM(_name_) FINDSYM2(_name_,_name_)
772 1.16.2.3 bouyer FINDSYM2(socket,__socket30)
773 1.16.2.3 bouyer FINDSYM(close)
774 1.16.2.3 bouyer FINDSYM(connect)
775 1.16.2.3 bouyer FINDSYM(fcntl)
776 1.16.2.3 bouyer FINDSYM(poll)
777 1.16.2.3 bouyer FINDSYM(read)
778 1.16.2.3 bouyer FINDSYM(sendto)
779 1.16.2.3 bouyer FINDSYM(setsockopt)
780 1.16.2.3 bouyer FINDSYM(dup)
781 1.16.2.3 bouyer FINDSYM(kqueue)
782 1.16.2.3 bouyer FINDSYM(execve)
783 1.16.2.1 bouyer #if !__NetBSD_Prereq__(5,99,7)
784 1.16.2.3 bouyer FINDSYM(kevent)
785 1.16.2.1 bouyer #else
786 1.16.2.3 bouyer FINDSYM2(kevent,_sys___kevent50)
787 1.16.2.1 bouyer #endif
788 1.13 pooka #undef FINDSYM
789 1.13 pooka #undef FINDSY2
790 1.13 pooka
791 1.16.2.2 bouyer if ((p = getenv("RUMP__PARSEDSERVER")) == NULL) {
792 1.16.2.2 bouyer if ((p = getenv("RUMP_SERVER")) == NULL) {
793 1.16.2.2 bouyer errno = ENOENT;
794 1.16.2.2 bouyer goto out;
795 1.16.2.2 bouyer }
796 1.11 pooka }
797 1.11 pooka
798 1.11 pooka if ((error = parseurl(p, &serv_sa, &ptab_idx, 0)) != 0) {
799 1.11 pooka errno = error;
800 1.16.2.2 bouyer goto out;
801 1.11 pooka }
802 1.11 pooka
803 1.16.2.1 bouyer if (doinit() == -1)
804 1.16.2.2 bouyer goto out;
805 1.16.2.2 bouyer
806 1.16.2.2 bouyer if ((p = getenv("RUMPCLIENT__EXECFD")) != NULL) {
807 1.16.2.2 bouyer sscanf(p, "%d,%d", &clispc.spc_fd, &kq);
808 1.16.2.2 bouyer unsetenv("RUMPCLIENT__EXECFD");
809 1.16.2.2 bouyer hstype = HANDSHAKE_EXEC;
810 1.16.2.2 bouyer } else {
811 1.16.2.2 bouyer if (doconnect(true) == -1)
812 1.16.2.2 bouyer goto out;
813 1.16.2.2 bouyer hstype = HANDSHAKE_GUEST;
814 1.16.2.2 bouyer }
815 1.11 pooka
816 1.16.2.2 bouyer error = handshake_req(&clispc, hstype, NULL, 0, false);
817 1.11 pooka if (error) {
818 1.11 pooka pthread_mutex_destroy(&clispc.spc_mtx);
819 1.11 pooka pthread_cond_destroy(&clispc.spc_cv);
820 1.16.2.1 bouyer if (clispc.spc_fd != -1)
821 1.16.2.1 bouyer host_close(clispc.spc_fd);
822 1.10 pooka errno = error;
823 1.16.2.2 bouyer goto out;
824 1.10 pooka }
825 1.16.2.2 bouyer rv = 0;
826 1.10 pooka
827 1.16.2.2 bouyer out:
828 1.16.2.2 bouyer if (rv == -1)
829 1.16.2.2 bouyer init_done = 0;
830 1.16.2.2 bouyer return rv;
831 1.11 pooka }
832 1.11 pooka
833 1.11 pooka struct rumpclient_fork {
834 1.11 pooka uint32_t fork_auth[AUTHLEN];
835 1.16.2.2 bouyer struct spclient fork_spc;
836 1.16.2.2 bouyer int fork_kq;
837 1.11 pooka };
838 1.11 pooka
839 1.11 pooka struct rumpclient_fork *
840 1.11 pooka rumpclient_prefork(void)
841 1.11 pooka {
842 1.11 pooka struct rumpclient_fork *rpf;
843 1.16.2.1 bouyer sigset_t omask;
844 1.11 pooka void *resp;
845 1.11 pooka int rv;
846 1.11 pooka
847 1.16.2.1 bouyer pthread_sigmask(SIG_SETMASK, &fullset, &omask);
848 1.11 pooka rpf = malloc(sizeof(*rpf));
849 1.11 pooka if (rpf == NULL)
850 1.16.2.2 bouyer goto out;
851 1.11 pooka
852 1.16.2.1 bouyer if ((rv = prefork_req(&clispc, &omask, &resp)) != 0) {
853 1.11 pooka free(rpf);
854 1.11 pooka errno = rv;
855 1.16.2.1 bouyer rpf = NULL;
856 1.16.2.1 bouyer goto out;
857 1.11 pooka }
858 1.11 pooka
859 1.11 pooka memcpy(rpf->fork_auth, resp, sizeof(rpf->fork_auth));
860 1.11 pooka free(resp);
861 1.11 pooka
862 1.16.2.2 bouyer rpf->fork_spc = clispc;
863 1.16.2.2 bouyer rpf->fork_kq = kq;
864 1.16.2.2 bouyer
865 1.16.2.1 bouyer out:
866 1.16.2.1 bouyer pthread_sigmask(SIG_SETMASK, &omask, NULL);
867 1.11 pooka return rpf;
868 1.11 pooka }
869 1.11 pooka
870 1.11 pooka int
871 1.11 pooka rumpclient_fork_init(struct rumpclient_fork *rpf)
872 1.11 pooka {
873 1.11 pooka int error;
874 1.16.2.1 bouyer int osock;
875 1.11 pooka
876 1.16.2.1 bouyer osock = clispc.spc_fd;
877 1.11 pooka memset(&clispc, 0, sizeof(clispc));
878 1.16.2.1 bouyer clispc.spc_fd = osock;
879 1.16.2.1 bouyer
880 1.16.2.1 bouyer kq = -1; /* kqueue descriptor is not copied over fork() */
881 1.11 pooka
882 1.16.2.1 bouyer if (doinit() == -1)
883 1.16.2.1 bouyer return -1;
884 1.16.2.1 bouyer if (doconnect(false) == -1)
885 1.11 pooka return -1;
886 1.10 pooka
887 1.16.2.2 bouyer error = handshake_req(&clispc, HANDSHAKE_FORK, rpf->fork_auth,
888 1.16.2.2 bouyer 0, false);
889 1.10 pooka if (error) {
890 1.10 pooka pthread_mutex_destroy(&clispc.spc_mtx);
891 1.10 pooka pthread_cond_destroy(&clispc.spc_cv);
892 1.11 pooka errno = error;
893 1.11 pooka return -1;
894 1.10 pooka }
895 1.11 pooka
896 1.11 pooka return 0;
897 1.1 pooka }
898 1.16.2.1 bouyer
899 1.16.2.1 bouyer void
900 1.16.2.2 bouyer rumpclient_fork_cancel(struct rumpclient_fork *rpf)
901 1.16.2.2 bouyer {
902 1.16.2.2 bouyer
903 1.16.2.2 bouyer /* EUNIMPL */
904 1.16.2.2 bouyer }
905 1.16.2.2 bouyer
906 1.16.2.2 bouyer void
907 1.16.2.2 bouyer rumpclient_fork_vparent(struct rumpclient_fork *rpf)
908 1.16.2.2 bouyer {
909 1.16.2.2 bouyer
910 1.16.2.2 bouyer clispc = rpf->fork_spc;
911 1.16.2.2 bouyer kq = rpf->fork_kq;
912 1.16.2.2 bouyer }
913 1.16.2.2 bouyer
914 1.16.2.2 bouyer void
915 1.16.2.1 bouyer rumpclient_setconnretry(time_t timeout)
916 1.16.2.1 bouyer {
917 1.16.2.1 bouyer
918 1.16.2.1 bouyer if (timeout < RUMPCLIENT_RETRYCONN_DIE)
919 1.16.2.1 bouyer return; /* gigo */
920 1.16.2.1 bouyer
921 1.16.2.1 bouyer retrytimo = timeout;
922 1.16.2.1 bouyer }
923 1.16.2.2 bouyer
924 1.16.2.2 bouyer int
925 1.16.2.2 bouyer rumpclient__closenotify(int *fdp, enum rumpclient_closevariant variant)
926 1.16.2.2 bouyer {
927 1.16.2.2 bouyer int fd = *fdp;
928 1.16.2.2 bouyer int untilfd, rv;
929 1.16.2.2 bouyer int newfd;
930 1.16.2.2 bouyer
931 1.16.2.2 bouyer switch (variant) {
932 1.16.2.2 bouyer case RUMPCLIENT_CLOSE_FCLOSEM:
933 1.16.2.2 bouyer untilfd = MAX(clispc.spc_fd, kq);
934 1.16.2.2 bouyer for (; fd <= untilfd; fd++) {
935 1.16.2.2 bouyer if (fd == clispc.spc_fd || fd == kq)
936 1.16.2.2 bouyer continue;
937 1.16.2.2 bouyer rv = host_close(fd);
938 1.16.2.2 bouyer if (rv == -1)
939 1.16.2.2 bouyer return -1;
940 1.16.2.2 bouyer }
941 1.16.2.2 bouyer *fdp = fd;
942 1.16.2.2 bouyer break;
943 1.16.2.2 bouyer
944 1.16.2.2 bouyer case RUMPCLIENT_CLOSE_CLOSE:
945 1.16.2.2 bouyer case RUMPCLIENT_CLOSE_DUP2:
946 1.16.2.2 bouyer if (fd == clispc.spc_fd) {
947 1.16.2.2 bouyer struct kevent kev[2];
948 1.16.2.2 bouyer
949 1.16.2.2 bouyer newfd = dupgood(clispc.spc_fd, 1);
950 1.16.2.2 bouyer if (newfd == -1)
951 1.16.2.2 bouyer return -1;
952 1.16.2.2 bouyer /*
953 1.16.2.2 bouyer * now, we have a new socket number, so change
954 1.16.2.2 bouyer * the file descriptor that kqueue is
955 1.16.2.2 bouyer * monitoring. remove old and add new.
956 1.16.2.2 bouyer */
957 1.16.2.2 bouyer EV_SET(&kev[0], clispc.spc_fd,
958 1.16.2.2 bouyer EVFILT_READ, EV_DELETE, 0, 0, 0);
959 1.16.2.2 bouyer EV_SET(&kev[1], newfd,
960 1.16.2.2 bouyer EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0);
961 1.16.2.2 bouyer if (host_kevent(kq, kev, 2, NULL, 0, NULL) == -1) {
962 1.16.2.2 bouyer int sverrno = errno;
963 1.16.2.2 bouyer host_close(newfd);
964 1.16.2.2 bouyer errno = sverrno;
965 1.16.2.2 bouyer return -1;
966 1.16.2.2 bouyer }
967 1.16.2.2 bouyer clispc.spc_fd = newfd;
968 1.16.2.2 bouyer }
969 1.16.2.2 bouyer if (fd == kq) {
970 1.16.2.2 bouyer newfd = dupgood(kq, 1);
971 1.16.2.2 bouyer if (newfd == -1)
972 1.16.2.2 bouyer return -1;
973 1.16.2.2 bouyer kq = newfd;
974 1.16.2.2 bouyer }
975 1.16.2.2 bouyer break;
976 1.16.2.2 bouyer }
977 1.16.2.2 bouyer
978 1.16.2.2 bouyer return 0;
979 1.16.2.2 bouyer }
980 1.16.2.2 bouyer
981 1.16.2.2 bouyer pid_t
982 1.16.2.2 bouyer rumpclient_fork()
983 1.16.2.2 bouyer {
984 1.16.2.2 bouyer
985 1.16.2.2 bouyer return rumpclient__dofork(fork);
986 1.16.2.2 bouyer }
987 1.16.2.2 bouyer
988 1.16.2.2 bouyer /*
989 1.16.2.2 bouyer * Process is about to exec. Save info about our existing connection
990 1.16.2.2 bouyer * in the env. rumpclient will check for this info in init().
991 1.16.2.2 bouyer * This is mostly for the benefit of rumphijack, but regular applications
992 1.16.2.2 bouyer * may use it as well.
993 1.16.2.2 bouyer */
994 1.16.2.2 bouyer int
995 1.16.2.2 bouyer rumpclient_exec(const char *path, char *const argv[], char *const envp[])
996 1.16.2.2 bouyer {
997 1.16.2.2 bouyer char buf[4096];
998 1.16.2.2 bouyer char **newenv;
999 1.16.2.2 bouyer char *envstr, *envstr2;
1000 1.16.2.2 bouyer size_t nelem;
1001 1.16.2.2 bouyer int rv, sverrno;
1002 1.16.2.2 bouyer
1003 1.16.2.2 bouyer snprintf(buf, sizeof(buf), "RUMPCLIENT__EXECFD=%d,%d",
1004 1.16.2.2 bouyer clispc.spc_fd, kq);
1005 1.16.2.2 bouyer envstr = malloc(strlen(buf)+1);
1006 1.16.2.2 bouyer if (envstr == NULL) {
1007 1.16.2.2 bouyer return ENOMEM;
1008 1.16.2.2 bouyer }
1009 1.16.2.2 bouyer strcpy(envstr, buf);
1010 1.16.2.2 bouyer
1011 1.16.2.2 bouyer /* do we have a fully parsed url we want to forward in the env? */
1012 1.16.2.2 bouyer if (*parsedurl != '\0') {
1013 1.16.2.2 bouyer snprintf(buf, sizeof(buf),
1014 1.16.2.2 bouyer "RUMP__PARSEDSERVER=%s", parsedurl);
1015 1.16.2.2 bouyer envstr2 = malloc(strlen(buf)+1);
1016 1.16.2.2 bouyer if (envstr2 == NULL) {
1017 1.16.2.2 bouyer free(envstr);
1018 1.16.2.2 bouyer return ENOMEM;
1019 1.16.2.2 bouyer }
1020 1.16.2.2 bouyer strcpy(envstr2, buf);
1021 1.16.2.2 bouyer } else {
1022 1.16.2.2 bouyer envstr2 = NULL;
1023 1.16.2.2 bouyer }
1024 1.16.2.2 bouyer
1025 1.16.2.2 bouyer for (nelem = 0; envp && envp[nelem]; nelem++)
1026 1.16.2.2 bouyer continue;
1027 1.16.2.2 bouyer
1028 1.16.2.3 bouyer newenv = malloc(sizeof(*newenv) * (nelem+3));
1029 1.16.2.2 bouyer if (newenv == NULL) {
1030 1.16.2.2 bouyer free(envstr2);
1031 1.16.2.2 bouyer free(envstr);
1032 1.16.2.2 bouyer return ENOMEM;
1033 1.16.2.2 bouyer }
1034 1.16.2.2 bouyer memcpy(&newenv[0], envp, nelem*sizeof(*envp));
1035 1.16.2.2 bouyer
1036 1.16.2.2 bouyer newenv[nelem] = envstr;
1037 1.16.2.2 bouyer newenv[nelem+1] = envstr2;
1038 1.16.2.2 bouyer newenv[nelem+2] = NULL;
1039 1.16.2.2 bouyer
1040 1.16.2.2 bouyer rv = host_execve(path, argv, newenv);
1041 1.16.2.2 bouyer
1042 1.16.2.2 bouyer _DIAGASSERT(rv != 0);
1043 1.16.2.2 bouyer sverrno = errno;
1044 1.16.2.2 bouyer free(envstr2);
1045 1.16.2.2 bouyer free(envstr);
1046 1.16.2.2 bouyer free(newenv);
1047 1.16.2.2 bouyer errno = sverrno;
1048 1.16.2.2 bouyer return rv;
1049 1.16.2.2 bouyer }
1050 1.16.2.2 bouyer
1051 1.16.2.2 bouyer int
1052 1.16.2.2 bouyer rumpclient_daemon(int nochdir, int noclose)
1053 1.16.2.2 bouyer {
1054 1.16.2.2 bouyer struct rumpclient_fork *rf;
1055 1.16.2.2 bouyer int sverrno;
1056 1.16.2.2 bouyer
1057 1.16.2.2 bouyer if ((rf = rumpclient_prefork()) == NULL)
1058 1.16.2.2 bouyer return -1;
1059 1.16.2.2 bouyer
1060 1.16.2.2 bouyer if (daemon(nochdir, noclose) == -1) {
1061 1.16.2.2 bouyer sverrno = errno;
1062 1.16.2.2 bouyer rumpclient_fork_cancel(rf);
1063 1.16.2.2 bouyer errno = sverrno;
1064 1.16.2.2 bouyer return -1;
1065 1.16.2.2 bouyer }
1066 1.16.2.2 bouyer
1067 1.16.2.2 bouyer if (rumpclient_fork_init(rf) == -1)
1068 1.16.2.2 bouyer return -1;
1069 1.16.2.2 bouyer
1070 1.16.2.2 bouyer return 0;
1071 1.16.2.2 bouyer }
1072