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