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