1*81f24eb1Schristos /* $NetBSD: rumpuser_sp.c,v 1.77 2020/05/06 12:44:36 christos Exp $ */
2b1842c22Spooka
3b1842c22Spooka /*
4fd993ea3Spooka * Copyright (c) 2010, 2011 Antti Kantee. All Rights Reserved.
5b1842c22Spooka *
6b1842c22Spooka * Redistribution and use in source and binary forms, with or without
7b1842c22Spooka * modification, are permitted provided that the following conditions
8b1842c22Spooka * are met:
9b1842c22Spooka * 1. Redistributions of source code must retain the above copyright
10b1842c22Spooka * notice, this list of conditions and the following disclaimer.
11b1842c22Spooka * 2. Redistributions in binary form must reproduce the above copyright
12b1842c22Spooka * notice, this list of conditions and the following disclaimer in the
13b1842c22Spooka * documentation and/or other materials provided with the distribution.
14b1842c22Spooka *
15b1842c22Spooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16b1842c22Spooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17b1842c22Spooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18b1842c22Spooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19b1842c22Spooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20b1842c22Spooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21b1842c22Spooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22b1842c22Spooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23b1842c22Spooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24b1842c22Spooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25b1842c22Spooka * SUCH DAMAGE.
26b1842c22Spooka */
27b1842c22Spooka
28b1842c22Spooka /*
29b1842c22Spooka * Sysproxy routines. This provides system RPC support over host sockets.
30b1842c22Spooka * The most notable limitation is that the client and server must share
31b1842c22Spooka * the same ABI. This does not mean that they have to be the same
32b1842c22Spooka * machine or that they need to run the same version of the host OS,
33b1842c22Spooka * just that they must agree on the data structures. This even *might*
34b1842c22Spooka * work correctly from one hardware architecture to another.
35b1842c22Spooka */
36b1842c22Spooka
373b3ffd70Spooka #include "rumpuser_port.h"
383b3ffd70Spooka
393b3ffd70Spooka #if !defined(lint)
40*81f24eb1Schristos __RCSID("$NetBSD: rumpuser_sp.c,v 1.77 2020/05/06 12:44:36 christos Exp $");
413b3ffd70Spooka #endif /* !lint */
42b1842c22Spooka
43b1842c22Spooka #include <sys/types.h>
44b1842c22Spooka #include <sys/mman.h>
45b1842c22Spooka #include <sys/socket.h>
46b1842c22Spooka
47b1842c22Spooka #include <arpa/inet.h>
48b1842c22Spooka #include <netinet/in.h>
49b1842c22Spooka #include <netinet/tcp.h>
50b1842c22Spooka
51b1842c22Spooka #include <assert.h>
52b1842c22Spooka #include <errno.h>
53b1842c22Spooka #include <fcntl.h>
54b1842c22Spooka #include <poll.h>
55b1842c22Spooka #include <pthread.h>
56b1842c22Spooka #include <stdarg.h>
57b1842c22Spooka #include <stdio.h>
58b1842c22Spooka #include <stdlib.h>
59b1842c22Spooka #include <string.h>
60b1842c22Spooka #include <unistd.h>
61b1842c22Spooka
623daddc03Spooka #include <rump/rump.h> /* XXX: for rfork flags */
63b1842c22Spooka #include <rump/rumpuser.h>
643b3ffd70Spooka
650f9bd961Spooka #include "rumpuser_int.h"
66b1842c22Spooka
6713e503f1Spooka #include "sp_common.c"
68b1842c22Spooka
69ea8aecd4Spooka #ifndef MAXCLI
70f0d58f78Spooka #define MAXCLI 256
71ea8aecd4Spooka #endif
72ea8aecd4Spooka #ifndef MAXWORKER
73ea8aecd4Spooka #define MAXWORKER 128
74ea8aecd4Spooka #endif
75ea8aecd4Spooka #ifndef IDLEWORKER
76ea8aecd4Spooka #define IDLEWORKER 16
77ea8aecd4Spooka #endif
78ea8aecd4Spooka int rumpsp_maxworker = MAXWORKER;
79ea8aecd4Spooka int rumpsp_idleworker = IDLEWORKER;
80b1842c22Spooka
81b1842c22Spooka static struct pollfd pfdlist[MAXCLI];
82b1842c22Spooka static struct spclient spclist[MAXCLI];
83c21ac41bSpooka static unsigned int disco;
84c59435eeSpooka static volatile int spfini;
85b1842c22Spooka
863c4a27f7Spooka static char banner[MAXBANNER];
873c4a27f7Spooka
883c4a27f7Spooka #define PROTOMAJOR 0
89bf01f875Spooka #define PROTOMINOR 4
90fd993ea3Spooka
913b3ffd70Spooka
929ee0427cSpooka /* either no atomic ops, or we haven't figured out how to use them */
939ee0427cSpooka #if defined(__linux__) || defined(__APPLE__) || defined(__CYGWIN__) || defined(__OpenBSD__) || defined(__GNU__) || defined(__GLIBC__)
943b3ffd70Spooka static pthread_mutex_t discomtx = PTHREAD_MUTEX_INITIALIZER;
953b3ffd70Spooka
963b3ffd70Spooka static void
signaldisco(void)973b3ffd70Spooka signaldisco(void)
983b3ffd70Spooka {
993b3ffd70Spooka
1003b3ffd70Spooka pthread_mutex_lock(&discomtx);
1013b3ffd70Spooka disco++;
1023b3ffd70Spooka pthread_mutex_unlock(&discomtx);
1033b3ffd70Spooka }
1043b3ffd70Spooka
1053b3ffd70Spooka static unsigned int
getdisco(void)1063b3ffd70Spooka getdisco(void)
1073b3ffd70Spooka {
1083b3ffd70Spooka unsigned int discocnt;
1093b3ffd70Spooka
1103b3ffd70Spooka pthread_mutex_lock(&discomtx);
1113b3ffd70Spooka discocnt = disco;
1123b3ffd70Spooka disco = 0;
1133b3ffd70Spooka pthread_mutex_unlock(&discomtx);
1143b3ffd70Spooka
1153b3ffd70Spooka return discocnt;
1163b3ffd70Spooka }
1173b3ffd70Spooka
118149f3bccSpooka #elif defined(__FreeBSD__) || defined(__DragonFly__)
119303e3a3aSpooka
120303e3a3aSpooka #include <machine/atomic.h>
121303e3a3aSpooka #define signaldisco() atomic_add_int(&disco, 1)
122303e3a3aSpooka #define getdisco() atomic_readandclear_int(&disco)
123303e3a3aSpooka
1243b3ffd70Spooka #else /* NetBSD */
1253b3ffd70Spooka
1263b3ffd70Spooka #include <sys/atomic.h>
1273b3ffd70Spooka #define signaldisco() atomic_inc_uint(&disco)
1283b3ffd70Spooka #define getdisco() atomic_swap_uint(&disco, 0)
1293b3ffd70Spooka
1303b3ffd70Spooka #endif
1313b3ffd70Spooka
1323b3ffd70Spooka
133fd993ea3Spooka struct prefork {
134fd993ea3Spooka uint32_t pf_auth[AUTHLEN];
135fd993ea3Spooka struct lwp *pf_lwp;
136fd993ea3Spooka
137fd993ea3Spooka LIST_ENTRY(prefork) pf_entries; /* global list */
138fd993ea3Spooka LIST_ENTRY(prefork) pf_spcentries; /* linked from forking spc */
139fd993ea3Spooka };
140fd993ea3Spooka static LIST_HEAD(, prefork) preforks = LIST_HEAD_INITIALIZER(preforks);
141fd993ea3Spooka static pthread_mutex_t pfmtx;
1423c4a27f7Spooka
1438fc7f907Spooka /*
144c45d9404Spooka * This version is for the server. It's optimized for multiple threads
14552fffe21Spooka * and is *NOT* reentrant wrt to signals.
146c45d9404Spooka */
147c45d9404Spooka static int
waitresp(struct spclient * spc,struct respwait * rw)148c45d9404Spooka waitresp(struct spclient *spc, struct respwait *rw)
149c45d9404Spooka {
1505064fa59Spooka int spcstate;
151c45d9404Spooka int rv = 0;
152c45d9404Spooka
1535064fa59Spooka pthread_mutex_lock(&spc->spc_mtx);
154c45d9404Spooka sendunlockl(spc);
15552fffe21Spooka while (!rw->rw_done && spc->spc_state != SPCSTATE_DYING) {
156c45d9404Spooka pthread_cond_wait(&rw->rw_cv, &spc->spc_mtx);
157c45d9404Spooka }
158c45d9404Spooka TAILQ_REMOVE(&spc->spc_respwait, rw, rw_entries);
1595064fa59Spooka spcstate = spc->spc_state;
160c45d9404Spooka pthread_mutex_unlock(&spc->spc_mtx);
161c45d9404Spooka
162c45d9404Spooka pthread_cond_destroy(&rw->rw_cv);
163c45d9404Spooka
164c45d9404Spooka if (rv)
165c45d9404Spooka return rv;
1665064fa59Spooka if (spcstate == SPCSTATE_DYING)
167c45d9404Spooka return ENOTCONN;
168c45d9404Spooka return rw->rw_error;
169c45d9404Spooka }
170c45d9404Spooka
171c45d9404Spooka /*
1728fc7f907Spooka * Manual wrappers, since librump does not have access to the
1738fc7f907Spooka * user namespace wrapped interfaces.
1748fc7f907Spooka */
1758fc7f907Spooka
1768fc7f907Spooka static void
lwproc_switch(struct lwp * l)1778fc7f907Spooka lwproc_switch(struct lwp *l)
1788fc7f907Spooka {
1798fc7f907Spooka
1805af3856aSpooka rumpuser__hyp.hyp_schedule();
1815af3856aSpooka rumpuser__hyp.hyp_lwproc_switch(l);
1825af3856aSpooka rumpuser__hyp.hyp_unschedule();
1838fc7f907Spooka }
1848fc7f907Spooka
1858fc7f907Spooka static void
lwproc_release(void)1868fc7f907Spooka lwproc_release(void)
1878fc7f907Spooka {
1888fc7f907Spooka
1895af3856aSpooka rumpuser__hyp.hyp_schedule();
1905af3856aSpooka rumpuser__hyp.hyp_lwproc_release();
1915af3856aSpooka rumpuser__hyp.hyp_unschedule();
1928fc7f907Spooka }
1938fc7f907Spooka
1948fc7f907Spooka static int
lwproc_rfork(struct spclient * spc,int flags,const char * comm)195dac4423fSpooka lwproc_rfork(struct spclient *spc, int flags, const char *comm)
1968fc7f907Spooka {
1978fc7f907Spooka int rv;
1988fc7f907Spooka
1995af3856aSpooka rumpuser__hyp.hyp_schedule();
2005af3856aSpooka rv = rumpuser__hyp.hyp_lwproc_rfork(spc, flags, comm);
2015af3856aSpooka rumpuser__hyp.hyp_unschedule();
2028fc7f907Spooka
2038fc7f907Spooka return rv;
2048fc7f907Spooka }
2058fc7f907Spooka
206a2b42babSpooka static int
lwproc_newlwp(pid_t pid)207a2b42babSpooka lwproc_newlwp(pid_t pid)
208a2b42babSpooka {
209a2b42babSpooka int rv;
210a2b42babSpooka
2115af3856aSpooka rumpuser__hyp.hyp_schedule();
2125af3856aSpooka rv = rumpuser__hyp.hyp_lwproc_newlwp(pid);
2135af3856aSpooka rumpuser__hyp.hyp_unschedule();
214a2b42babSpooka
215a2b42babSpooka return rv;
216a2b42babSpooka }
217a2b42babSpooka
2188fc7f907Spooka static struct lwp *
lwproc_curlwp(void)2198fc7f907Spooka lwproc_curlwp(void)
2208fc7f907Spooka {
2218fc7f907Spooka struct lwp *l;
2228fc7f907Spooka
2235af3856aSpooka rumpuser__hyp.hyp_schedule();
2245af3856aSpooka l = rumpuser__hyp.hyp_lwproc_curlwp();
2255af3856aSpooka rumpuser__hyp.hyp_unschedule();
2268fc7f907Spooka
2278fc7f907Spooka return l;
2288fc7f907Spooka }
2298fc7f907Spooka
230a2b42babSpooka static pid_t
lwproc_getpid(void)231a2b42babSpooka lwproc_getpid(void)
232a2b42babSpooka {
233a2b42babSpooka pid_t p;
234a2b42babSpooka
2355af3856aSpooka rumpuser__hyp.hyp_schedule();
2365af3856aSpooka p = rumpuser__hyp.hyp_getpid();
2375af3856aSpooka rumpuser__hyp.hyp_unschedule();
238a2b42babSpooka
239a2b42babSpooka return p;
240a2b42babSpooka }
24191240244Spooka
2425e301bc4Spooka static void
lwproc_execnotify(const char * comm)2435e301bc4Spooka lwproc_execnotify(const char *comm)
2445e301bc4Spooka {
2455e301bc4Spooka
2465af3856aSpooka rumpuser__hyp.hyp_schedule();
2475af3856aSpooka rumpuser__hyp.hyp_execnotify(comm);
2485af3856aSpooka rumpuser__hyp.hyp_unschedule();
2495e301bc4Spooka }
250a2b42babSpooka
2513626eb4bSpooka static void
lwproc_lwpexit(void)25291240244Spooka lwproc_lwpexit(void)
2533626eb4bSpooka {
2543626eb4bSpooka
2555af3856aSpooka rumpuser__hyp.hyp_schedule();
2565af3856aSpooka rumpuser__hyp.hyp_lwpexit();
2575af3856aSpooka rumpuser__hyp.hyp_unschedule();
2583626eb4bSpooka }
2593626eb4bSpooka
2608fc7f907Spooka static int
rumpsyscall(int sysnum,void * data,register_t * regrv)261bd14d4ebSpooka rumpsyscall(int sysnum, void *data, register_t *regrv)
2628fc7f907Spooka {
263bd14d4ebSpooka long retval[2] = {0, 0};
2648fc7f907Spooka int rv;
2658fc7f907Spooka
2665af3856aSpooka rumpuser__hyp.hyp_schedule();
2675af3856aSpooka rv = rumpuser__hyp.hyp_syscall(sysnum, data, retval);
2685af3856aSpooka rumpuser__hyp.hyp_unschedule();
2698fc7f907Spooka
270bd14d4ebSpooka regrv[0] = retval[0];
271bd14d4ebSpooka regrv[1] = retval[1];
2728fc7f907Spooka return rv;
2738fc7f907Spooka }
274b1842c22Spooka
27552f22b2cSpooka static uint64_t
nextreq(struct spclient * spc)27652f22b2cSpooka nextreq(struct spclient *spc)
277b1842c22Spooka {
27852f22b2cSpooka uint64_t nw;
279b1842c22Spooka
28052f22b2cSpooka pthread_mutex_lock(&spc->spc_mtx);
28152f22b2cSpooka nw = spc->spc_nextreq++;
28252f22b2cSpooka pthread_mutex_unlock(&spc->spc_mtx);
283b1842c22Spooka
28452f22b2cSpooka return nw;
285b1842c22Spooka }
286b1842c22Spooka
28700e34b22Spooka /*
28800e34b22Spooka * XXX: we send responses with "blocking" I/O. This is not
28900e34b22Spooka * ok for the main thread. XXXFIXME
29000e34b22Spooka */
29100e34b22Spooka
292d402686fSpooka static void
send_error_resp(struct spclient * spc,uint64_t reqno,enum rumpsp_err error)293bf01f875Spooka send_error_resp(struct spclient *spc, uint64_t reqno, enum rumpsp_err error)
294d402686fSpooka {
295d402686fSpooka struct rsp_hdr rhdr;
29600e34b22Spooka struct iovec iov[1];
297d402686fSpooka
298d402686fSpooka rhdr.rsp_len = sizeof(rhdr);
299d402686fSpooka rhdr.rsp_reqno = reqno;
300d402686fSpooka rhdr.rsp_class = RUMPSP_ERROR;
301d402686fSpooka rhdr.rsp_type = 0;
302d402686fSpooka rhdr.rsp_error = error;
303d402686fSpooka
30400e34b22Spooka IOVPUT(iov[0], rhdr);
30500e34b22Spooka
306d402686fSpooka sendlock(spc);
30700e34b22Spooka (void)SENDIOV(spc, iov);
308d402686fSpooka sendunlock(spc);
309d402686fSpooka }
310d402686fSpooka
311b1842c22Spooka static int
send_handshake_resp(struct spclient * spc,uint64_t reqno,int error)312393eecc1Spooka send_handshake_resp(struct spclient *spc, uint64_t reqno, int error)
313393eecc1Spooka {
314393eecc1Spooka struct rsp_hdr rhdr;
31500e34b22Spooka struct iovec iov[2];
316393eecc1Spooka int rv;
317393eecc1Spooka
318393eecc1Spooka rhdr.rsp_len = sizeof(rhdr) + sizeof(error);
319393eecc1Spooka rhdr.rsp_reqno = reqno;
320393eecc1Spooka rhdr.rsp_class = RUMPSP_RESP;
321393eecc1Spooka rhdr.rsp_type = RUMPSP_HANDSHAKE;
322393eecc1Spooka rhdr.rsp_error = 0;
323393eecc1Spooka
32400e34b22Spooka IOVPUT(iov[0], rhdr);
32500e34b22Spooka IOVPUT(iov[1], error);
32600e34b22Spooka
327393eecc1Spooka sendlock(spc);
32800e34b22Spooka rv = SENDIOV(spc, iov);
329393eecc1Spooka sendunlock(spc);
330393eecc1Spooka
331393eecc1Spooka return rv;
332393eecc1Spooka }
333393eecc1Spooka
334393eecc1Spooka static int
send_syscall_resp(struct spclient * spc,uint64_t reqno,int error,register_t * retval)33552f22b2cSpooka send_syscall_resp(struct spclient *spc, uint64_t reqno, int error,
33652f22b2cSpooka register_t *retval)
33752f22b2cSpooka {
33852f22b2cSpooka struct rsp_hdr rhdr;
33952f22b2cSpooka struct rsp_sysresp sysresp;
34000e34b22Spooka struct iovec iov[2];
34152f22b2cSpooka int rv;
34252f22b2cSpooka
34352f22b2cSpooka rhdr.rsp_len = sizeof(rhdr) + sizeof(sysresp);
34452f22b2cSpooka rhdr.rsp_reqno = reqno;
34552f22b2cSpooka rhdr.rsp_class = RUMPSP_RESP;
34652f22b2cSpooka rhdr.rsp_type = RUMPSP_SYSCALL;
34752f22b2cSpooka rhdr.rsp_sysnum = 0;
34852f22b2cSpooka
34952f22b2cSpooka sysresp.rsys_error = error;
35052f22b2cSpooka memcpy(sysresp.rsys_retval, retval, sizeof(sysresp.rsys_retval));
35152f22b2cSpooka
35200e34b22Spooka IOVPUT(iov[0], rhdr);
35300e34b22Spooka IOVPUT(iov[1], sysresp);
35400e34b22Spooka
35552f22b2cSpooka sendlock(spc);
35600e34b22Spooka rv = SENDIOV(spc, iov);
35752f22b2cSpooka sendunlock(spc);
35852f22b2cSpooka
35952f22b2cSpooka return rv;
36052f22b2cSpooka }
36152f22b2cSpooka
36252f22b2cSpooka static int
send_prefork_resp(struct spclient * spc,uint64_t reqno,uint32_t * auth)363fd993ea3Spooka send_prefork_resp(struct spclient *spc, uint64_t reqno, uint32_t *auth)
364fd993ea3Spooka {
365fd993ea3Spooka struct rsp_hdr rhdr;
36600e34b22Spooka struct iovec iov[2];
367fd993ea3Spooka int rv;
368fd993ea3Spooka
369fd993ea3Spooka rhdr.rsp_len = sizeof(rhdr) + AUTHLEN*sizeof(*auth);
370fd993ea3Spooka rhdr.rsp_reqno = reqno;
371fd993ea3Spooka rhdr.rsp_class = RUMPSP_RESP;
372fd993ea3Spooka rhdr.rsp_type = RUMPSP_PREFORK;
373fd993ea3Spooka rhdr.rsp_sysnum = 0;
374fd993ea3Spooka
37500e34b22Spooka IOVPUT(iov[0], rhdr);
37600e34b22Spooka IOVPUT_WITHSIZE(iov[1], auth, AUTHLEN*sizeof(*auth));
37700e34b22Spooka
378fd993ea3Spooka sendlock(spc);
37900e34b22Spooka rv = SENDIOV(spc, iov);
380fd993ea3Spooka sendunlock(spc);
381fd993ea3Spooka
382fd993ea3Spooka return rv;
383fd993ea3Spooka }
384fd993ea3Spooka
385fd993ea3Spooka static int
copyin_req(struct spclient * spc,const void * remaddr,size_t * dlen,int wantstr,void ** resp)3866b71288cSpooka copyin_req(struct spclient *spc, const void *remaddr, size_t *dlen,
3876b71288cSpooka int wantstr, void **resp)
388b1842c22Spooka {
389b1842c22Spooka struct rsp_hdr rhdr;
390b1842c22Spooka struct rsp_copydata copydata;
39152f22b2cSpooka struct respwait rw;
39200e34b22Spooka struct iovec iov[2];
39352f22b2cSpooka int rv;
39452f22b2cSpooka
3956b71288cSpooka DPRINTF(("copyin_req: %zu bytes from %p\n", *dlen, remaddr));
396b1842c22Spooka
397b1842c22Spooka rhdr.rsp_len = sizeof(rhdr) + sizeof(copydata);
39852f22b2cSpooka rhdr.rsp_class = RUMPSP_REQ;
3996b71288cSpooka if (wantstr)
4006b71288cSpooka rhdr.rsp_type = RUMPSP_COPYINSTR;
4016b71288cSpooka else
40252f22b2cSpooka rhdr.rsp_type = RUMPSP_COPYIN;
403b1842c22Spooka rhdr.rsp_sysnum = 0;
404b1842c22Spooka
405b1842c22Spooka copydata.rcp_addr = __UNCONST(remaddr);
4066b71288cSpooka copydata.rcp_len = *dlen;
407b1842c22Spooka
40800e34b22Spooka IOVPUT(iov[0], rhdr);
40900e34b22Spooka IOVPUT(iov[1], copydata);
41000e34b22Spooka
41152f22b2cSpooka putwait(spc, &rw, &rhdr);
41200e34b22Spooka rv = SENDIOV(spc, iov);
4130f9bd961Spooka if (rv) {
4140f9bd961Spooka unputwait(spc, &rw);
4150f9bd961Spooka return rv;
4160f9bd961Spooka }
41752f22b2cSpooka
41852f22b2cSpooka rv = waitresp(spc, &rw);
41952f22b2cSpooka
42052f22b2cSpooka DPRINTF(("copyin: response %d\n", rv));
42152f22b2cSpooka
42252f22b2cSpooka *resp = rw.rw_data;
4236b71288cSpooka if (wantstr)
4246b71288cSpooka *dlen = rw.rw_dlen;
4256b71288cSpooka
42652f22b2cSpooka return rv;
42752f22b2cSpooka
428b1842c22Spooka }
429b1842c22Spooka
430b1842c22Spooka static int
send_copyout_req(struct spclient * spc,const void * remaddr,const void * data,size_t dlen)431b1842c22Spooka send_copyout_req(struct spclient *spc, const void *remaddr,
432b1842c22Spooka const void *data, size_t dlen)
433b1842c22Spooka {
434b1842c22Spooka struct rsp_hdr rhdr;
435b1842c22Spooka struct rsp_copydata copydata;
43600e34b22Spooka struct iovec iov[3];
43752f22b2cSpooka int rv;
43852f22b2cSpooka
43952f22b2cSpooka DPRINTF(("copyout_req (async): %zu bytes to %p\n", dlen, remaddr));
440b1842c22Spooka
441b1842c22Spooka rhdr.rsp_len = sizeof(rhdr) + sizeof(copydata) + dlen;
44252f22b2cSpooka rhdr.rsp_reqno = nextreq(spc);
44352f22b2cSpooka rhdr.rsp_class = RUMPSP_REQ;
44452f22b2cSpooka rhdr.rsp_type = RUMPSP_COPYOUT;
445b1842c22Spooka rhdr.rsp_sysnum = 0;
446b1842c22Spooka
447b1842c22Spooka copydata.rcp_addr = __UNCONST(remaddr);
448b1842c22Spooka copydata.rcp_len = dlen;
449b1842c22Spooka
45000e34b22Spooka IOVPUT(iov[0], rhdr);
45100e34b22Spooka IOVPUT(iov[1], copydata);
45200e34b22Spooka IOVPUT_WITHSIZE(iov[2], __UNCONST(data), dlen);
45300e34b22Spooka
45452f22b2cSpooka sendlock(spc);
45500e34b22Spooka rv = SENDIOV(spc, iov);
45652f22b2cSpooka sendunlock(spc);
457b1842c22Spooka
45852f22b2cSpooka return rv;
459b1842c22Spooka }
460b1842c22Spooka
461b1842c22Spooka static int
anonmmap_req(struct spclient * spc,size_t howmuch,void ** resp)46252f22b2cSpooka anonmmap_req(struct spclient *spc, size_t howmuch, void **resp)
463b1842c22Spooka {
464b1842c22Spooka struct rsp_hdr rhdr;
46552f22b2cSpooka struct respwait rw;
46600e34b22Spooka struct iovec iov[2];
46752f22b2cSpooka int rv;
46852f22b2cSpooka
46952f22b2cSpooka DPRINTF(("anonmmap_req: %zu bytes\n", howmuch));
470b1842c22Spooka
471b1842c22Spooka rhdr.rsp_len = sizeof(rhdr) + sizeof(howmuch);
47252f22b2cSpooka rhdr.rsp_class = RUMPSP_REQ;
47352f22b2cSpooka rhdr.rsp_type = RUMPSP_ANONMMAP;
474b1842c22Spooka rhdr.rsp_sysnum = 0;
475b1842c22Spooka
47600e34b22Spooka IOVPUT(iov[0], rhdr);
47700e34b22Spooka IOVPUT(iov[1], howmuch);
47800e34b22Spooka
47952f22b2cSpooka putwait(spc, &rw, &rhdr);
48000e34b22Spooka rv = SENDIOV(spc, iov);
4810f9bd961Spooka if (rv) {
4820f9bd961Spooka unputwait(spc, &rw);
4830f9bd961Spooka return rv;
4840f9bd961Spooka }
48552f22b2cSpooka
48652f22b2cSpooka rv = waitresp(spc, &rw);
4870f9bd961Spooka
48852f22b2cSpooka *resp = rw.rw_data;
48952f22b2cSpooka
49052f22b2cSpooka DPRINTF(("anonmmap: mapped at %p\n", **(void ***)resp));
49152f22b2cSpooka
49252f22b2cSpooka return rv;
493b1842c22Spooka }
494b1842c22Spooka
4959fba158bSpooka static int
send_raise_req(struct spclient * spc,int signo)4969fba158bSpooka send_raise_req(struct spclient *spc, int signo)
4979fba158bSpooka {
4989fba158bSpooka struct rsp_hdr rhdr;
49900e34b22Spooka struct iovec iov[1];
5009fba158bSpooka int rv;
5019fba158bSpooka
5029fba158bSpooka rhdr.rsp_len = sizeof(rhdr);
5039fba158bSpooka rhdr.rsp_class = RUMPSP_REQ;
5049fba158bSpooka rhdr.rsp_type = RUMPSP_RAISE;
5059fba158bSpooka rhdr.rsp_signo = signo;
5069fba158bSpooka
50700e34b22Spooka IOVPUT(iov[0], rhdr);
50800e34b22Spooka
5099fba158bSpooka sendlock(spc);
51000e34b22Spooka rv = SENDIOV(spc, iov);
5119fba158bSpooka sendunlock(spc);
5129fba158bSpooka
5139fba158bSpooka return rv;
5149fba158bSpooka }
5159fba158bSpooka
516b1842c22Spooka static void
spcref(struct spclient * spc)517c21ac41bSpooka spcref(struct spclient *spc)
518b1842c22Spooka {
519b1842c22Spooka
520c21ac41bSpooka pthread_mutex_lock(&spc->spc_mtx);
521c21ac41bSpooka spc->spc_refcnt++;
522c21ac41bSpooka pthread_mutex_unlock(&spc->spc_mtx);
523c21ac41bSpooka }
524c21ac41bSpooka
525c21ac41bSpooka static void
spcrelease(struct spclient * spc)526c21ac41bSpooka spcrelease(struct spclient *spc)
527c21ac41bSpooka {
528c21ac41bSpooka int ref;
529c21ac41bSpooka
530c21ac41bSpooka pthread_mutex_lock(&spc->spc_mtx);
531c21ac41bSpooka ref = --spc->spc_refcnt;
53291240244Spooka if (__predict_false(spc->spc_inexec && ref <= 2))
53391240244Spooka pthread_cond_broadcast(&spc->spc_cv);
534c21ac41bSpooka pthread_mutex_unlock(&spc->spc_mtx);
535c21ac41bSpooka
536c21ac41bSpooka if (ref > 0)
537c21ac41bSpooka return;
538c21ac41bSpooka
539fd993ea3Spooka DPRINTF(("rump_sp: spcrelease: spc %p fd %d\n", spc, spc->spc_fd));
540b99a42f8Spooka
5410f9bd961Spooka _DIAGASSERT(TAILQ_EMPTY(&spc->spc_respwait));
542c21ac41bSpooka _DIAGASSERT(spc->spc_buf == NULL);
543b1842c22Spooka
544fd993ea3Spooka if (spc->spc_mainlwp) {
545a2b42babSpooka lwproc_switch(spc->spc_mainlwp);
5468fc7f907Spooka lwproc_release();
547fd993ea3Spooka }
548c21ac41bSpooka spc->spc_mainlwp = NULL;
549f128c061Spooka
550c21ac41bSpooka close(spc->spc_fd);
551c21ac41bSpooka spc->spc_fd = -1;
552393eecc1Spooka spc->spc_state = SPCSTATE_NEW;
553b1842c22Spooka
5543b3ffd70Spooka signaldisco();
555b1842c22Spooka }
556b1842c22Spooka
557c21ac41bSpooka static void
serv_handledisco(unsigned int idx)558c21ac41bSpooka serv_handledisco(unsigned int idx)
559c21ac41bSpooka {
560c21ac41bSpooka struct spclient *spc = &spclist[idx];
56191240244Spooka int dolwpexit;
562c21ac41bSpooka
563c21ac41bSpooka DPRINTF(("rump_sp: disconnecting [%u]\n", idx));
564c21ac41bSpooka
565b99a42f8Spooka pfdlist[idx].fd = -1;
566b99a42f8Spooka pfdlist[idx].revents = 0;
567b99a42f8Spooka pthread_mutex_lock(&spc->spc_mtx);
568393eecc1Spooka spc->spc_state = SPCSTATE_DYING;
569b99a42f8Spooka kickall(spc);
570f4b63a89Spooka sendunlockl(spc);
57191240244Spooka /* exec uses mainlwp in another thread, but also nuked all lwps */
57291240244Spooka dolwpexit = !spc->spc_inexec;
573b99a42f8Spooka pthread_mutex_unlock(&spc->spc_mtx);
5746e0e64abSpooka
57591240244Spooka if (dolwpexit && spc->spc_mainlwp) {
5763626eb4bSpooka lwproc_switch(spc->spc_mainlwp);
57791240244Spooka lwproc_lwpexit();
5783626eb4bSpooka lwproc_switch(NULL);
5793626eb4bSpooka }
5803626eb4bSpooka
5816e0e64abSpooka /*
5826e0e64abSpooka * Nobody's going to attempt to send/receive anymore,
5836e0e64abSpooka * so reinit info relevant to that.
5846e0e64abSpooka */
58503f765ecSpooka /*LINTED:pointer casts may be ok*/
5866e0e64abSpooka memset((char *)spc + SPC_ZEROFF, 0, sizeof(*spc) - SPC_ZEROFF);
5876e0e64abSpooka
588c21ac41bSpooka spcrelease(spc);
589c21ac41bSpooka }
590c21ac41bSpooka
591c59435eeSpooka static void
serv_shutdown(void)592c59435eeSpooka serv_shutdown(void)
593c59435eeSpooka {
594c59435eeSpooka struct spclient *spc;
595c59435eeSpooka unsigned int i;
596c59435eeSpooka
597c59435eeSpooka for (i = 1; i < MAXCLI; i++) {
598c59435eeSpooka spc = &spclist[i];
599c59435eeSpooka if (spc->spc_fd == -1)
600c59435eeSpooka continue;
601c59435eeSpooka
602c59435eeSpooka shutdown(spc->spc_fd, SHUT_RDWR);
603c59435eeSpooka serv_handledisco(i);
604c59435eeSpooka
605c59435eeSpooka spcrelease(spc);
606c59435eeSpooka }
607c59435eeSpooka }
608c59435eeSpooka
609c21ac41bSpooka static unsigned
serv_handleconn(int fd,connecthook_fn connhook,int busy)610c21ac41bSpooka serv_handleconn(int fd, connecthook_fn connhook, int busy)
611b1842c22Spooka {
612b1842c22Spooka struct sockaddr_storage ss;
613b1842c22Spooka socklen_t sl = sizeof(ss);
614c21ac41bSpooka int newfd, flags;
615b1842c22Spooka unsigned i;
616b1842c22Spooka
617b1842c22Spooka /*LINTED: cast ok */
618b1842c22Spooka newfd = accept(fd, (struct sockaddr *)&ss, &sl);
619b1842c22Spooka if (newfd == -1)
620c21ac41bSpooka return 0;
621c21ac41bSpooka
622c21ac41bSpooka if (busy) {
623c21ac41bSpooka close(newfd); /* EBUSY */
624c21ac41bSpooka return 0;
625c21ac41bSpooka }
626b1842c22Spooka
627b1842c22Spooka flags = fcntl(newfd, F_GETFL, 0);
628b1842c22Spooka if (fcntl(newfd, F_SETFL, flags | O_NONBLOCK) == -1) {
629b1842c22Spooka close(newfd);
630c21ac41bSpooka return 0;
631b1842c22Spooka }
632b1842c22Spooka
633c21ac41bSpooka if (connhook(newfd) != 0) {
634b1842c22Spooka close(newfd);
635c21ac41bSpooka return 0;
636b1842c22Spooka }
637b1842c22Spooka
6383c4a27f7Spooka /* write out a banner for the client */
6395064fa59Spooka if (send(newfd, banner, strlen(banner), MSG_NOSIGNAL)
6405064fa59Spooka != (ssize_t)strlen(banner)) {
6413c4a27f7Spooka close(newfd);
6423c4a27f7Spooka return 0;
6433c4a27f7Spooka }
6443c4a27f7Spooka
645b1842c22Spooka /* find empty slot the simple way */
646b1842c22Spooka for (i = 0; i < MAXCLI; i++) {
647393eecc1Spooka if (pfdlist[i].fd == -1 && spclist[i].spc_state == SPCSTATE_NEW)
648b1842c22Spooka break;
649b1842c22Spooka }
650b1842c22Spooka
651f768d01cSpooka /*
652f768d01cSpooka * Although not finding a slot is impossible (cf. how this routine
653f768d01cSpooka * is called), the compiler can still think that i == MAXCLI
654f768d01cSpooka * if this code is either compiled with NDEBUG or the platform
655f768d01cSpooka * does not use __dead for assert(). Therefore, add an explicit
656f768d01cSpooka * check to avoid an array-bounds error.
657f768d01cSpooka */
658f768d01cSpooka /* assert(i < MAXCLI); */
659f768d01cSpooka if (i == MAXCLI)
660f768d01cSpooka abort();
661b1842c22Spooka
662b1842c22Spooka pfdlist[i].fd = newfd;
663b1842c22Spooka spclist[i].spc_fd = newfd;
66452f22b2cSpooka spclist[i].spc_istatus = SPCSTATUS_BUSY; /* dedicated receiver */
665c21ac41bSpooka spclist[i].spc_refcnt = 1;
66652f22b2cSpooka
66752f22b2cSpooka TAILQ_INIT(&spclist[i].spc_respwait);
668b1842c22Spooka
669fd993ea3Spooka DPRINTF(("rump_sp: added new connection fd %d at idx %u\n", newfd, i));
670b1842c22Spooka
671c21ac41bSpooka return i;
672b1842c22Spooka }
673b1842c22Spooka
674b1842c22Spooka static void
serv_handlesyscall(struct spclient * spc,struct rsp_hdr * rhdr,uint8_t * data)675b1842c22Spooka serv_handlesyscall(struct spclient *spc, struct rsp_hdr *rhdr, uint8_t *data)
676b1842c22Spooka {
67752f22b2cSpooka register_t retval[2] = {0, 0};
678b1842c22Spooka int rv, sysnum;
679b1842c22Spooka
680b1842c22Spooka sysnum = (int)rhdr->rsp_sysnum;
681b1842c22Spooka DPRINTF(("rump_sp: handling syscall %d from client %d\n",
682fd993ea3Spooka sysnum, spc->spc_pid));
683b1842c22Spooka
68491240244Spooka if (__predict_false((rv = lwproc_newlwp(spc->spc_pid)) != 0)) {
68591240244Spooka retval[0] = -1;
68691240244Spooka send_syscall_resp(spc, rhdr->rsp_reqno, rv, retval);
68791240244Spooka return;
68891240244Spooka }
6891d9f8678Spooka spc->spc_syscallreq = rhdr->rsp_reqno;
6908fc7f907Spooka rv = rumpsyscall(sysnum, data, retval);
6911d9f8678Spooka spc->spc_syscallreq = 0;
6927ca02beaSpooka lwproc_release();
693b1842c22Spooka
694832d276eSmartin DPRINTF(("rump_sp: got return value %d & %"PRIxREGISTER
695832d276eSmartin "/%"PRIxREGISTER"\n",
696832d276eSmartin rv, retval[0], retval[1]));
69713e503f1Spooka
698b1842c22Spooka send_syscall_resp(spc, rhdr->rsp_reqno, rv, retval);
699b1842c22Spooka }
700b1842c22Spooka
70191240244Spooka static void
serv_handleexec(struct spclient * spc,struct rsp_hdr * rhdr,const char * comm)702*81f24eb1Schristos serv_handleexec(struct spclient *spc, struct rsp_hdr *rhdr, const char *comm)
70391240244Spooka {
70491240244Spooka pthread_mutex_lock(&spc->spc_mtx);
70591240244Spooka /* one for the connection and one for us */
70691240244Spooka while (spc->spc_refcnt > 2)
70791240244Spooka pthread_cond_wait(&spc->spc_cv, &spc->spc_mtx);
70891240244Spooka pthread_mutex_unlock(&spc->spc_mtx);
70991240244Spooka
71091240244Spooka /*
71191240244Spooka * ok, all the threads are dead (or one is still alive and
71291240244Spooka * the connection is dead, in which case this doesn't matter
71391240244Spooka * very much). proceed with exec.
71491240244Spooka */
71591240244Spooka
71691240244Spooka lwproc_switch(spc->spc_mainlwp);
71791240244Spooka lwproc_execnotify(comm);
71891240244Spooka lwproc_switch(NULL);
71991240244Spooka
72091240244Spooka pthread_mutex_lock(&spc->spc_mtx);
72191240244Spooka spc->spc_inexec = 0;
72291240244Spooka pthread_mutex_unlock(&spc->spc_mtx);
72391240244Spooka send_handshake_resp(spc, rhdr->rsp_reqno, 0);
72491240244Spooka }
72591240244Spooka
72691240244Spooka enum sbatype { SBA_SYSCALL, SBA_EXEC };
72791240244Spooka
72891240244Spooka struct servbouncearg {
72952f22b2cSpooka struct spclient *sba_spc;
73052f22b2cSpooka struct rsp_hdr sba_hdr;
73191240244Spooka enum sbatype sba_type;
73252f22b2cSpooka uint8_t *sba_data;
733ea8aecd4Spooka
73491240244Spooka TAILQ_ENTRY(servbouncearg) sba_entries;
73552f22b2cSpooka };
736ea8aecd4Spooka static pthread_mutex_t sbamtx;
737ea8aecd4Spooka static pthread_cond_t sbacv;
7388e6ede8cSpooka static int nworker, idleworker, nwork;
73991240244Spooka static TAILQ_HEAD(, servbouncearg) wrklist = TAILQ_HEAD_INITIALIZER(wrklist);
740ea8aecd4Spooka
741ea8aecd4Spooka /*ARGSUSED*/
74252f22b2cSpooka static void *
serv_workbouncer(void * arg)74391240244Spooka serv_workbouncer(void *arg)
74452f22b2cSpooka {
74591240244Spooka struct servbouncearg *sba;
74652f22b2cSpooka
747ea8aecd4Spooka for (;;) {
748ea8aecd4Spooka pthread_mutex_lock(&sbamtx);
749fc3b8233Spooka if (__predict_false(idleworker - nwork >= rumpsp_idleworker)) {
750ea8aecd4Spooka nworker--;
751ea8aecd4Spooka pthread_mutex_unlock(&sbamtx);
752ea8aecd4Spooka break;
753ea8aecd4Spooka }
754ea8aecd4Spooka idleworker++;
75591240244Spooka while (TAILQ_EMPTY(&wrklist)) {
7568e6ede8cSpooka _DIAGASSERT(nwork == 0);
757ea8aecd4Spooka pthread_cond_wait(&sbacv, &sbamtx);
7588e6ede8cSpooka }
7598e6ede8cSpooka idleworker--;
760ea8aecd4Spooka
76191240244Spooka sba = TAILQ_FIRST(&wrklist);
76291240244Spooka TAILQ_REMOVE(&wrklist, sba, sba_entries);
7638e6ede8cSpooka nwork--;
764ea8aecd4Spooka pthread_mutex_unlock(&sbamtx);
765ea8aecd4Spooka
76691240244Spooka if (__predict_true(sba->sba_type == SBA_SYSCALL)) {
767ea8aecd4Spooka serv_handlesyscall(sba->sba_spc,
768ea8aecd4Spooka &sba->sba_hdr, sba->sba_data);
76991240244Spooka } else {
77091240244Spooka _DIAGASSERT(sba->sba_type == SBA_EXEC);
77191240244Spooka serv_handleexec(sba->sba_spc, &sba->sba_hdr,
77291240244Spooka (char *)sba->sba_data);
77391240244Spooka }
774ea8aecd4Spooka spcrelease(sba->sba_spc);
775ea8aecd4Spooka free(sba->sba_data);
776ea8aecd4Spooka free(sba);
777ea8aecd4Spooka }
778ea8aecd4Spooka
77952f22b2cSpooka return NULL;
78052f22b2cSpooka }
78152f22b2cSpooka
7826b71288cSpooka static int
sp_copyin(void * arg,const void * raddr,void * laddr,size_t * len,int wantstr)7836b71288cSpooka sp_copyin(void *arg, const void *raddr, void *laddr, size_t *len, int wantstr)
784b1842c22Spooka {
7859be03442Spooka struct spclient *spc = arg;
786ad5cf5abSpooka void *rdata = NULL; /* XXXuninit */
7870f9bd961Spooka int rv, nlocks;
7880f9bd961Spooka
7895af3856aSpooka rumpkern_unsched(&nlocks, NULL);
790b1842c22Spooka
7916b71288cSpooka rv = copyin_req(spc, raddr, len, wantstr, &rdata);
792b99a42f8Spooka if (rv)
7930f9bd961Spooka goto out;
794b1842c22Spooka
7956b71288cSpooka memcpy(laddr, rdata, *len);
79652f22b2cSpooka free(rdata);
797b1842c22Spooka
7980f9bd961Spooka out:
7995af3856aSpooka rumpkern_sched(nlocks, NULL);
8000f9bd961Spooka if (rv)
80132a34307Spooka rv = EFAULT;
802be085dcdSpooka ET(rv);
803b1842c22Spooka }
804b1842c22Spooka
805b1842c22Spooka int
rumpuser_sp_copyin(void * arg,const void * raddr,void * laddr,size_t len)8066b71288cSpooka rumpuser_sp_copyin(void *arg, const void *raddr, void *laddr, size_t len)
8076b71288cSpooka {
808be085dcdSpooka int rv;
8096b71288cSpooka
810be085dcdSpooka rv = sp_copyin(arg, raddr, laddr, &len, 0);
811be085dcdSpooka ET(rv);
8126b71288cSpooka }
8136b71288cSpooka
8146b71288cSpooka int
rumpuser_sp_copyinstr(void * arg,const void * raddr,void * laddr,size_t * len)8156b71288cSpooka rumpuser_sp_copyinstr(void *arg, const void *raddr, void *laddr, size_t *len)
8166b71288cSpooka {
817be085dcdSpooka int rv;
8186b71288cSpooka
819be085dcdSpooka rv = sp_copyin(arg, raddr, laddr, len, 1);
820be085dcdSpooka ET(rv);
8216b71288cSpooka }
8226b71288cSpooka
8236b71288cSpooka static int
sp_copyout(void * arg,const void * laddr,void * raddr,size_t dlen)8246b71288cSpooka sp_copyout(void *arg, const void *laddr, void *raddr, size_t dlen)
825b1842c22Spooka {
8269be03442Spooka struct spclient *spc = arg;
8270f9bd961Spooka int nlocks, rv;
828b1842c22Spooka
8295af3856aSpooka rumpkern_unsched(&nlocks, NULL);
8306b71288cSpooka rv = send_copyout_req(spc, raddr, laddr, dlen);
8315af3856aSpooka rumpkern_sched(nlocks, NULL);
8320f9bd961Spooka
8330f9bd961Spooka if (rv)
83432a34307Spooka rv = EFAULT;
835be085dcdSpooka ET(rv);
836b1842c22Spooka }
837b1842c22Spooka
838b1842c22Spooka int
rumpuser_sp_copyout(void * arg,const void * laddr,void * raddr,size_t dlen)8396b71288cSpooka rumpuser_sp_copyout(void *arg, const void *laddr, void *raddr, size_t dlen)
8406b71288cSpooka {
841be085dcdSpooka int rv;
8426b71288cSpooka
843be085dcdSpooka rv = sp_copyout(arg, laddr, raddr, dlen);
844be085dcdSpooka ET(rv);
8456b71288cSpooka }
8466b71288cSpooka
8476b71288cSpooka int
rumpuser_sp_copyoutstr(void * arg,const void * laddr,void * raddr,size_t * dlen)8486b71288cSpooka rumpuser_sp_copyoutstr(void *arg, const void *laddr, void *raddr, size_t *dlen)
8496b71288cSpooka {
850be085dcdSpooka int rv;
8516b71288cSpooka
852be085dcdSpooka rv = sp_copyout(arg, laddr, raddr, *dlen);
853be085dcdSpooka ET(rv);
8546b71288cSpooka }
8556b71288cSpooka
8566b71288cSpooka int
rumpuser_sp_anonmmap(void * arg,size_t howmuch,void ** addr)8579be03442Spooka rumpuser_sp_anonmmap(void *arg, size_t howmuch, void **addr)
858b1842c22Spooka {
8599be03442Spooka struct spclient *spc = arg;
860af1fbf04Sjustin void *resp, *rdata = NULL; /* XXXuninit */
8610f9bd961Spooka int nlocks, rv;
8620f9bd961Spooka
8635af3856aSpooka rumpkern_unsched(&nlocks, NULL);
864b1842c22Spooka
86552f22b2cSpooka rv = anonmmap_req(spc, howmuch, &rdata);
8660f9bd961Spooka if (rv) {
8670f9bd961Spooka rv = EFAULT;
8680f9bd961Spooka goto out;
8690f9bd961Spooka }
870b1842c22Spooka
87152f22b2cSpooka resp = *(void **)rdata;
87252f22b2cSpooka free(rdata);
873b1842c22Spooka
87452f22b2cSpooka if (resp == NULL) {
8750f9bd961Spooka rv = ENOMEM;
87652f22b2cSpooka }
877b1842c22Spooka
878b1842c22Spooka *addr = resp;
8790f9bd961Spooka
8800f9bd961Spooka out:
8815af3856aSpooka rumpkern_sched(nlocks, NULL);
882be085dcdSpooka ET(rv);
883b1842c22Spooka }
884b1842c22Spooka
8859fba158bSpooka int
rumpuser_sp_raise(void * arg,int signo)8869fba158bSpooka rumpuser_sp_raise(void *arg, int signo)
8879fba158bSpooka {
8889fba158bSpooka struct spclient *spc = arg;
8899fba158bSpooka int rv, nlocks;
8909fba158bSpooka
8915af3856aSpooka rumpkern_unsched(&nlocks, NULL);
8929fba158bSpooka rv = send_raise_req(spc, signo);
8935af3856aSpooka rumpkern_sched(nlocks, NULL);
8949fba158bSpooka
8959fba158bSpooka return rv;
8969fba158bSpooka }
8979fba158bSpooka
89891240244Spooka static pthread_attr_t pattr_detached;
89991240244Spooka static void
schedulework(struct spclient * spc,enum sbatype sba_type)90091240244Spooka schedulework(struct spclient *spc, enum sbatype sba_type)
90191240244Spooka {
90291240244Spooka struct servbouncearg *sba;
90391240244Spooka pthread_t pt;
90491240244Spooka uint64_t reqno;
90591240244Spooka int retries = 0;
90691240244Spooka
90791240244Spooka reqno = spc->spc_hdr.rsp_reqno;
90891240244Spooka while ((sba = malloc(sizeof(*sba))) == NULL) {
90912f8bae5Skre if (nworker == 0 || retries++ > 10) {
910bf01f875Spooka send_error_resp(spc, reqno, RUMPSP_ERR_TRYAGAIN);
91191240244Spooka spcfreebuf(spc);
91291240244Spooka return;
91391240244Spooka }
91491240244Spooka /* slim chance of more memory? */
91591240244Spooka usleep(10000);
91691240244Spooka }
91791240244Spooka
91891240244Spooka sba->sba_spc = spc;
91991240244Spooka sba->sba_type = sba_type;
92091240244Spooka sba->sba_hdr = spc->spc_hdr;
92191240244Spooka sba->sba_data = spc->spc_buf;
92291240244Spooka spcresetbuf(spc);
92391240244Spooka
92491240244Spooka spcref(spc);
92591240244Spooka
92691240244Spooka pthread_mutex_lock(&sbamtx);
92791240244Spooka TAILQ_INSERT_TAIL(&wrklist, sba, sba_entries);
92891240244Spooka nwork++;
92991240244Spooka if (nwork <= idleworker) {
93091240244Spooka /* do we have a daemon's tool (i.e. idle threads)? */
93191240244Spooka pthread_cond_signal(&sbacv);
93291240244Spooka } else if (nworker < rumpsp_maxworker) {
93391240244Spooka /*
93491240244Spooka * Else, need to create one
93591240244Spooka * (if we can, otherwise just expect another
93691240244Spooka * worker to pick up the syscall)
93791240244Spooka */
93891240244Spooka if (pthread_create(&pt, &pattr_detached,
93991240244Spooka serv_workbouncer, NULL) == 0) {
94091240244Spooka nworker++;
94191240244Spooka }
94291240244Spooka }
94391240244Spooka pthread_mutex_unlock(&sbamtx);
94491240244Spooka }
94591240244Spooka
946b1842c22Spooka /*
947b1842c22Spooka *
948b1842c22Spooka * Startup routines and mainloop for server.
949b1842c22Spooka *
950b1842c22Spooka */
951b1842c22Spooka
952b1842c22Spooka struct spservarg {
953b1842c22Spooka int sps_sock;
954b1842c22Spooka connecthook_fn sps_connhook;
955b1842c22Spooka };
956b1842c22Spooka
95752f22b2cSpooka static void
handlereq(struct spclient * spc)95852f22b2cSpooka handlereq(struct spclient *spc)
95952f22b2cSpooka {
9605e301bc4Spooka uint64_t reqno;
961b0711f2cSpooka int error;
962393eecc1Spooka
9635e301bc4Spooka reqno = spc->spc_hdr.rsp_reqno;
964393eecc1Spooka if (__predict_false(spc->spc_state == SPCSTATE_NEW)) {
965393eecc1Spooka if (spc->spc_hdr.rsp_type != RUMPSP_HANDSHAKE) {
966bf01f875Spooka send_error_resp(spc, reqno, RUMPSP_ERR_AUTH);
967fd993ea3Spooka shutdown(spc->spc_fd, SHUT_RDWR);
968393eecc1Spooka spcfreebuf(spc);
969393eecc1Spooka return;
970393eecc1Spooka }
971393eecc1Spooka
972fd993ea3Spooka if (spc->spc_hdr.rsp_handshake == HANDSHAKE_GUEST) {
973b124cf15Spooka /* make sure we fork off of proc1 */
974b124cf15Spooka _DIAGASSERT(lwproc_curlwp() == NULL);
975b124cf15Spooka
976*81f24eb1Schristos if ((error = lwproc_rfork(spc, RUMP_RFFD_CLEAR,
977*81f24eb1Schristos (const char *)spc->spc_buf)) != 0) {
978fd993ea3Spooka shutdown(spc->spc_fd, SHUT_RDWR);
979fd993ea3Spooka }
980fd993ea3Spooka
981393eecc1Spooka spcfreebuf(spc);
982fd993ea3Spooka if (error)
983fd993ea3Spooka return;
984fd993ea3Spooka
985fd993ea3Spooka spc->spc_mainlwp = lwproc_curlwp();
986fd993ea3Spooka
9875e301bc4Spooka send_handshake_resp(spc, reqno, 0);
988fd993ea3Spooka } else if (spc->spc_hdr.rsp_handshake == HANDSHAKE_FORK) {
989fd993ea3Spooka struct lwp *tmpmain;
990fd993ea3Spooka struct prefork *pf;
991fd993ea3Spooka struct handshake_fork *rfp;
992fd993ea3Spooka int cancel;
993fd993ea3Spooka
994fd993ea3Spooka if (spc->spc_off-HDRSZ != sizeof(*rfp)) {
995bf01f875Spooka send_error_resp(spc, reqno,
996bf01f875Spooka RUMPSP_ERR_MALFORMED_REQUEST);
997fd993ea3Spooka shutdown(spc->spc_fd, SHUT_RDWR);
998fd993ea3Spooka spcfreebuf(spc);
999fd993ea3Spooka return;
1000fd993ea3Spooka }
1001fd993ea3Spooka
1002fd993ea3Spooka /*LINTED*/
1003fd993ea3Spooka rfp = (void *)spc->spc_buf;
1004fd993ea3Spooka cancel = rfp->rf_cancel;
1005fd993ea3Spooka
1006fd993ea3Spooka pthread_mutex_lock(&pfmtx);
1007fd993ea3Spooka LIST_FOREACH(pf, &preforks, pf_entries) {
1008fd993ea3Spooka if (memcmp(rfp->rf_auth, pf->pf_auth,
1009fd993ea3Spooka sizeof(rfp->rf_auth)) == 0) {
1010fd993ea3Spooka LIST_REMOVE(pf, pf_entries);
1011fd993ea3Spooka LIST_REMOVE(pf, pf_spcentries);
1012fd993ea3Spooka break;
1013fd993ea3Spooka }
1014fd993ea3Spooka }
10158a7d14d1Spooka pthread_mutex_unlock(&pfmtx);
1016fd993ea3Spooka spcfreebuf(spc);
1017fd993ea3Spooka
1018fd993ea3Spooka if (!pf) {
1019bf01f875Spooka send_error_resp(spc, reqno,
1020bf01f875Spooka RUMPSP_ERR_INVALID_PREFORK);
1021393eecc1Spooka shutdown(spc->spc_fd, SHUT_RDWR);
1022393eecc1Spooka return;
1023393eecc1Spooka }
1024fd993ea3Spooka
1025fd993ea3Spooka tmpmain = pf->pf_lwp;
1026fd993ea3Spooka free(pf);
1027fd993ea3Spooka lwproc_switch(tmpmain);
1028fd993ea3Spooka if (cancel) {
1029fd993ea3Spooka lwproc_release();
1030fd993ea3Spooka shutdown(spc->spc_fd, SHUT_RDWR);
1031fd993ea3Spooka return;
1032fd993ea3Spooka }
1033fd993ea3Spooka
1034fd993ea3Spooka /*
1035fd993ea3Spooka * So, we forked already during "prefork" to save
1036fd993ea3Spooka * the file descriptors from a parent exit
1037fd993ea3Spooka * race condition. But now we need to fork
1038fd993ea3Spooka * a second time since the initial fork has
1039fd993ea3Spooka * the wrong spc pointer. (yea, optimize
1040fd993ea3Spooka * interfaces some day if anyone cares)
1041fd993ea3Spooka */
1042b124cf15Spooka if ((error = lwproc_rfork(spc,
1043b124cf15Spooka RUMP_RFFD_SHARE, NULL)) != 0) {
1044bf01f875Spooka send_error_resp(spc, reqno,
1045bf01f875Spooka RUMPSP_ERR_RFORK_FAILED);
1046fd993ea3Spooka shutdown(spc->spc_fd, SHUT_RDWR);
1047fd993ea3Spooka lwproc_release();
1048fd993ea3Spooka return;
1049fd993ea3Spooka }
1050fd993ea3Spooka spc->spc_mainlwp = lwproc_curlwp();
1051fd993ea3Spooka lwproc_switch(tmpmain);
1052fd993ea3Spooka lwproc_release();
1053fd993ea3Spooka lwproc_switch(spc->spc_mainlwp);
1054fd993ea3Spooka
1055fd993ea3Spooka send_handshake_resp(spc, reqno, 0);
105691240244Spooka } else {
1057bf01f875Spooka send_error_resp(spc, reqno, RUMPSP_ERR_AUTH);
105891240244Spooka shutdown(spc->spc_fd, SHUT_RDWR);
105991240244Spooka spcfreebuf(spc);
106091240244Spooka return;
1061fd993ea3Spooka }
1062fd993ea3Spooka
1063fd993ea3Spooka spc->spc_pid = lwproc_getpid();
1064fd993ea3Spooka
1065fd993ea3Spooka DPRINTF(("rump_sp: handshake for client %p complete, pid %d\n",
1066fd993ea3Spooka spc, spc->spc_pid));
1067fd993ea3Spooka
1068fd993ea3Spooka lwproc_switch(NULL);
1069393eecc1Spooka spc->spc_state = SPCSTATE_RUNNING;
1070393eecc1Spooka return;
1071393eecc1Spooka }
107252f22b2cSpooka
1073fd993ea3Spooka if (__predict_false(spc->spc_hdr.rsp_type == RUMPSP_PREFORK)) {
1074fd993ea3Spooka struct prefork *pf;
1075fd993ea3Spooka uint32_t auth[AUTHLEN];
107632a34307Spooka size_t randlen;
107791240244Spooka int inexec;
1078fd993ea3Spooka
1079fd993ea3Spooka DPRINTF(("rump_sp: prefork handler executing for %p\n", spc));
1080fd993ea3Spooka spcfreebuf(spc);
1081fd993ea3Spooka
108291240244Spooka pthread_mutex_lock(&spc->spc_mtx);
108391240244Spooka inexec = spc->spc_inexec;
108491240244Spooka pthread_mutex_unlock(&spc->spc_mtx);
108591240244Spooka if (inexec) {
1086bf01f875Spooka send_error_resp(spc, reqno, RUMPSP_ERR_INEXEC);
108791240244Spooka shutdown(spc->spc_fd, SHUT_RDWR);
108891240244Spooka return;
108991240244Spooka }
109091240244Spooka
1091fd993ea3Spooka pf = malloc(sizeof(*pf));
1092fd993ea3Spooka if (pf == NULL) {
1093bf01f875Spooka send_error_resp(spc, reqno, RUMPSP_ERR_NOMEM);
1094fd993ea3Spooka return;
1095fd993ea3Spooka }
1096fd993ea3Spooka
1097fd993ea3Spooka /*
1098fd993ea3Spooka * Use client main lwp to fork. this is never used by
109991240244Spooka * worker threads (except in exec, but we checked for that
110091240244Spooka * above) so we can safely use it here.
1101fd993ea3Spooka */
1102fd993ea3Spooka lwproc_switch(spc->spc_mainlwp);
1103b124cf15Spooka if ((error = lwproc_rfork(spc, RUMP_RFFD_COPY, NULL)) != 0) {
1104fd993ea3Spooka DPRINTF(("rump_sp: fork failed: %d (%p)\n",error, spc));
1105bf01f875Spooka send_error_resp(spc, reqno, RUMPSP_ERR_RFORK_FAILED);
1106fd993ea3Spooka lwproc_switch(NULL);
1107fd993ea3Spooka free(pf);
1108fd993ea3Spooka return;
1109fd993ea3Spooka }
1110fd993ea3Spooka
1111fd993ea3Spooka /* Ok, we have a new process context and a new curlwp */
111232a34307Spooka rumpuser_getrandom(auth, sizeof(auth), 0, &randlen);
11139dd49679Spooka memcpy(pf->pf_auth, auth, sizeof(pf->pf_auth));
1114fd993ea3Spooka pf->pf_lwp = lwproc_curlwp();
1115fd993ea3Spooka lwproc_switch(NULL);
1116fd993ea3Spooka
1117fd993ea3Spooka pthread_mutex_lock(&pfmtx);
1118fd993ea3Spooka LIST_INSERT_HEAD(&preforks, pf, pf_entries);
1119fd993ea3Spooka LIST_INSERT_HEAD(&spc->spc_pflist, pf, pf_spcentries);
1120fd993ea3Spooka pthread_mutex_unlock(&pfmtx);
1121fd993ea3Spooka
1122fd993ea3Spooka DPRINTF(("rump_sp: prefork handler success %p\n", spc));
1123fd993ea3Spooka
1124fd993ea3Spooka send_prefork_resp(spc, reqno, auth);
1125fd993ea3Spooka return;
1126fd993ea3Spooka }
1127fd993ea3Spooka
11285e301bc4Spooka if (__predict_false(spc->spc_hdr.rsp_type == RUMPSP_HANDSHAKE)) {
112991240244Spooka int inexec;
11305e301bc4Spooka
11315e301bc4Spooka if (spc->spc_hdr.rsp_handshake != HANDSHAKE_EXEC) {
1132bf01f875Spooka send_error_resp(spc, reqno,
1133bf01f875Spooka RUMPSP_ERR_MALFORMED_REQUEST);
113491240244Spooka shutdown(spc->spc_fd, SHUT_RDWR);
11355e301bc4Spooka spcfreebuf(spc);
11365e301bc4Spooka return;
11375e301bc4Spooka }
11385e301bc4Spooka
113991240244Spooka pthread_mutex_lock(&spc->spc_mtx);
114091240244Spooka inexec = spc->spc_inexec;
114191240244Spooka pthread_mutex_unlock(&spc->spc_mtx);
114291240244Spooka if (inexec) {
1143bf01f875Spooka send_error_resp(spc, reqno, RUMPSP_ERR_INEXEC);
114491240244Spooka shutdown(spc->spc_fd, SHUT_RDWR);
114591240244Spooka spcfreebuf(spc);
114691240244Spooka return;
114791240244Spooka }
11485e301bc4Spooka
114991240244Spooka pthread_mutex_lock(&spc->spc_mtx);
115091240244Spooka spc->spc_inexec = 1;
115191240244Spooka pthread_mutex_unlock(&spc->spc_mtx);
115291240244Spooka
115391240244Spooka /*
115491240244Spooka * start to drain lwps. we will wait for it to finish
115591240244Spooka * in another thread
115691240244Spooka */
11575e301bc4Spooka lwproc_switch(spc->spc_mainlwp);
115891240244Spooka lwproc_lwpexit();
11595e301bc4Spooka lwproc_switch(NULL);
11605e301bc4Spooka
116191240244Spooka /*
116291240244Spooka * exec has to wait for lwps to drain, so finish it off
116391240244Spooka * in another thread
116491240244Spooka */
116591240244Spooka schedulework(spc, SBA_EXEC);
11665e301bc4Spooka return;
11675e301bc4Spooka }
11685e301bc4Spooka
1169d402686fSpooka if (__predict_false(spc->spc_hdr.rsp_type != RUMPSP_SYSCALL)) {
1170bf01f875Spooka send_error_resp(spc, reqno, RUMPSP_ERR_MALFORMED_REQUEST);
1171d402686fSpooka spcfreebuf(spc);
1172d402686fSpooka return;
1173d402686fSpooka }
117452f22b2cSpooka
117591240244Spooka schedulework(spc, SBA_SYSCALL);
117652f22b2cSpooka }
117752f22b2cSpooka
1178b1842c22Spooka static void *
spserver(void * arg)1179b1842c22Spooka spserver(void *arg)
1180b1842c22Spooka {
1181b1842c22Spooka struct spservarg *sarg = arg;
1182c21ac41bSpooka struct spclient *spc;
1183b1842c22Spooka unsigned idx;
1184b1842c22Spooka int seen;
1185b1842c22Spooka int rv;
1186c21ac41bSpooka unsigned int nfds, maxidx;
1187b1842c22Spooka
1188c21ac41bSpooka for (idx = 0; idx < MAXCLI; idx++) {
1189b1842c22Spooka pfdlist[idx].fd = -1;
1190b1842c22Spooka pfdlist[idx].events = POLLIN;
1191c21ac41bSpooka
1192c21ac41bSpooka spc = &spclist[idx];
1193c21ac41bSpooka pthread_mutex_init(&spc->spc_mtx, NULL);
1194c21ac41bSpooka pthread_cond_init(&spc->spc_cv, NULL);
1195c59435eeSpooka spc->spc_fd = -1;
1196b1842c22Spooka }
1197c59435eeSpooka pfdlist[0].fd = spclist[0].spc_fd = sarg->sps_sock;
1198b1842c22Spooka pfdlist[0].events = POLLIN;
1199b1842c22Spooka nfds = 1;
1200b1842c22Spooka maxidx = 0;
1201b1842c22Spooka
12026d4b60f2Spooka pthread_attr_init(&pattr_detached);
12036d4b60f2Spooka pthread_attr_setdetachstate(&pattr_detached, PTHREAD_CREATE_DETACHED);
1204a65b1aebSjoerg #if NOTYET
1205bd26e667Spooka pthread_attr_setstacksize(&pattr_detached, 32*1024);
1206a65b1aebSjoerg #endif
12076d4b60f2Spooka
1208ea8aecd4Spooka pthread_mutex_init(&sbamtx, NULL);
1209ea8aecd4Spooka pthread_cond_init(&sbacv, NULL);
1210ea8aecd4Spooka
1211b1842c22Spooka DPRINTF(("rump_sp: server mainloop\n"));
1212b1842c22Spooka
1213b1842c22Spooka for (;;) {
1214c21ac41bSpooka int discoed;
1215c21ac41bSpooka
1216f0d58f78Spooka /* g/c hangarounds (eventually) */
12173b3ffd70Spooka discoed = getdisco();
1218c21ac41bSpooka while (discoed--) {
1219c21ac41bSpooka nfds--;
1220c21ac41bSpooka idx = maxidx;
1221b99a42f8Spooka while (idx) {
1222c21ac41bSpooka if (pfdlist[idx].fd != -1) {
1223c21ac41bSpooka maxidx = idx;
1224c21ac41bSpooka break;
1225c21ac41bSpooka }
1226b99a42f8Spooka idx--;
1227c21ac41bSpooka }
1228c21ac41bSpooka DPRINTF(("rump_sp: set maxidx to [%u]\n",
1229c21ac41bSpooka maxidx));
1230c21ac41bSpooka }
1231c21ac41bSpooka
1232b1842c22Spooka DPRINTF(("rump_sp: loop nfd %d\n", maxidx+1));
1233b1842c22Spooka seen = 0;
1234b1842c22Spooka rv = poll(pfdlist, maxidx+1, INFTIM);
1235b1842c22Spooka assert(maxidx+1 <= MAXCLI);
1236b1842c22Spooka assert(rv != 0);
1237b1842c22Spooka if (rv == -1) {
1238b1842c22Spooka if (errno == EINTR)
1239b1842c22Spooka continue;
1240b1842c22Spooka fprintf(stderr, "rump_spserver: poll returned %d\n",
1241b1842c22Spooka errno);
1242b1842c22Spooka break;
1243b1842c22Spooka }
1244b1842c22Spooka
1245b99a42f8Spooka for (idx = 0; seen < rv && idx < MAXCLI; idx++) {
1246b1842c22Spooka if ((pfdlist[idx].revents & POLLIN) == 0)
1247b1842c22Spooka continue;
1248b1842c22Spooka
1249b1842c22Spooka seen++;
1250b1842c22Spooka DPRINTF(("rump_sp: activity at [%u] %d/%d\n",
1251b1842c22Spooka idx, seen, rv));
1252b1842c22Spooka if (idx > 0) {
1253c21ac41bSpooka spc = &spclist[idx];
1254b1842c22Spooka DPRINTF(("rump_sp: mainloop read [%u]\n", idx));
1255b1842c22Spooka switch (readframe(spc)) {
1256b1842c22Spooka case 0:
1257b1842c22Spooka break;
1258b1842c22Spooka case -1:
1259f128c061Spooka serv_handledisco(idx);
1260b1842c22Spooka break;
1261b1842c22Spooka default:
126252f22b2cSpooka switch (spc->spc_hdr.rsp_class) {
126352f22b2cSpooka case RUMPSP_RESP:
126452f22b2cSpooka kickwaiter(spc);
126552f22b2cSpooka break;
126652f22b2cSpooka case RUMPSP_REQ:
126752f22b2cSpooka handlereq(spc);
126852f22b2cSpooka break;
126952f22b2cSpooka default:
1270d402686fSpooka send_error_resp(spc,
1271d402686fSpooka spc->spc_hdr.rsp_reqno,
1272bf01f875Spooka RUMPSP_ERR_MALFORMED_REQUEST);
1273d402686fSpooka spcfreebuf(spc);
127452f22b2cSpooka break;
127552f22b2cSpooka }
1276b1842c22Spooka break;
1277b1842c22Spooka }
1278c21ac41bSpooka
1279b1842c22Spooka } else {
1280b1842c22Spooka DPRINTF(("rump_sp: mainloop new connection\n"));
1281c21ac41bSpooka
1282c59435eeSpooka if (__predict_false(spfini)) {
1283c59435eeSpooka close(spclist[0].spc_fd);
1284c59435eeSpooka serv_shutdown();
1285c59435eeSpooka goto out;
1286c59435eeSpooka }
1287c59435eeSpooka
1288c21ac41bSpooka idx = serv_handleconn(pfdlist[0].fd,
1289c21ac41bSpooka sarg->sps_connhook, nfds == MAXCLI);
1290c21ac41bSpooka if (idx)
1291c21ac41bSpooka nfds++;
1292c21ac41bSpooka if (idx > maxidx)
1293c21ac41bSpooka maxidx = idx;
1294b99a42f8Spooka DPRINTF(("rump_sp: maxid now %d\n", maxidx));
1295b1842c22Spooka }
1296b1842c22Spooka }
1297b1842c22Spooka }
1298b1842c22Spooka
1299c59435eeSpooka out:
1300b1842c22Spooka return NULL;
1301b1842c22Spooka }
1302b1842c22Spooka
130334c82400Spooka static unsigned cleanupidx;
130434c82400Spooka static struct sockaddr *cleanupsa;
1305b1842c22Spooka int
rumpuser_sp_init(const char * url,const char * ostype,const char * osrelease,const char * machine)13065af3856aSpooka rumpuser_sp_init(const char *url,
13073c4a27f7Spooka const char *ostype, const char *osrelease, const char *machine)
1308b1842c22Spooka {
130913e503f1Spooka pthread_t pt;
1310b1842c22Spooka struct spservarg *sarg;
1311b1842c22Spooka struct sockaddr *sap;
131213e503f1Spooka char *p;
13139f9913ceSpooka unsigned idx = 0; /* XXXgcc */
131413e503f1Spooka int error, s;
1315b1842c22Spooka
131613e503f1Spooka p = strdup(url);
131732a34307Spooka if (p == NULL) {
131832a34307Spooka error = ENOMEM;
131932a34307Spooka goto out;
132032a34307Spooka }
132113e503f1Spooka error = parseurl(p, &sap, &idx, 1);
132213e503f1Spooka free(p);
1323b1842c22Spooka if (error)
132432a34307Spooka goto out;
1325b1842c22Spooka
13263c4a27f7Spooka snprintf(banner, sizeof(banner), "RUMPSP-%d.%d-%s-%s/%s\n",
13273c4a27f7Spooka PROTOMAJOR, PROTOMINOR, ostype, osrelease, machine);
13283c4a27f7Spooka
132913e503f1Spooka s = socket(parsetab[idx].domain, SOCK_STREAM, 0);
133032a34307Spooka if (s == -1) {
133132a34307Spooka error = errno;
133232a34307Spooka goto out;
133332a34307Spooka }
1334b1842c22Spooka
1335b1842c22Spooka sarg = malloc(sizeof(*sarg));
1336b1842c22Spooka if (sarg == NULL) {
1337b1842c22Spooka close(s);
133832a34307Spooka error = ENOMEM;
133932a34307Spooka goto out;
1340b1842c22Spooka }
1341b1842c22Spooka
1342b1842c22Spooka sarg->sps_sock = s;
134313e503f1Spooka sarg->sps_connhook = parsetab[idx].connhook;
1344b1842c22Spooka
134534c82400Spooka cleanupidx = idx;
134634c82400Spooka cleanupsa = sap;
134734c82400Spooka
1348b1842c22Spooka /* sloppy error recovery */
1349b1842c22Spooka
1350b1842c22Spooka /*LINTED*/
13513b3ffd70Spooka if (bind(s, sap, parsetab[idx].slen) == -1) {
135232a34307Spooka error = errno;
13537ee57573Spooka fprintf(stderr, "rump_sp: failed to bind to URL %s\n", url);
135432a34307Spooka goto out;
1355b1842c22Spooka }
1356f0d58f78Spooka if (listen(s, MAXCLI) == -1) {
135732a34307Spooka error = errno;
1358b1842c22Spooka fprintf(stderr, "rump_sp: server listen failed\n");
135932a34307Spooka goto out;
1360b1842c22Spooka }
1361b1842c22Spooka
1362b1842c22Spooka if ((error = pthread_create(&pt, NULL, spserver, sarg)) != 0) {
1363b1842c22Spooka fprintf(stderr, "rump_sp: cannot create wrkr thread\n");
136432a34307Spooka goto out;
1365b1842c22Spooka }
1366b1842c22Spooka pthread_detach(pt);
1367b1842c22Spooka
136832a34307Spooka out:
1369be085dcdSpooka ET(error);
1370b1842c22Spooka }
1371c59435eeSpooka
1372c59435eeSpooka void
rumpuser_sp_fini(void * arg)13731d9f8678Spooka rumpuser_sp_fini(void *arg)
1374c59435eeSpooka {
13751d9f8678Spooka struct spclient *spc = arg;
13761d9f8678Spooka register_t retval[2] = {0, 0};
13771d9f8678Spooka
13783129d3abSpooka if (spclist[0].spc_fd) {
13793129d3abSpooka parsetab[cleanupidx].cleanup(cleanupsa);
13803129d3abSpooka }
13813129d3abSpooka
13821d9f8678Spooka /*
13835fbc8e74Spooka * stuff response into the socket, since the rump kernel container
13845fbc8e74Spooka * is just about to exit
13851d9f8678Spooka */
13861d9f8678Spooka if (spc && spc->spc_syscallreq)
13871d9f8678Spooka send_syscall_resp(spc, spc->spc_syscallreq, 0, retval);
1388c59435eeSpooka
1389c59435eeSpooka if (spclist[0].spc_fd) {
1390c59435eeSpooka shutdown(spclist[0].spc_fd, SHUT_RDWR);
1391c59435eeSpooka spfini = 1;
1392c59435eeSpooka }
13935fbc8e74Spooka
13945fbc8e74Spooka /*
13955fbc8e74Spooka * could release thread, but don't bother, since the container
13965fbc8e74Spooka * will be stone dead in a moment.
13975fbc8e74Spooka */
1398c59435eeSpooka }
1399