xref: /netbsd-src/lib/librumpuser/rumpuser_sp.c (revision 81f24eb1c137bae9ffd46e9d1d5c341e8a078a30)
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