1/*      $NetBSD: rumpuser_sp.c,v 1.68 2014/12/08 00:12:03 justin Exp $	*/
2
3/*
4 * Copyright (c) 2010, 2011 Antti Kantee.  All Rights Reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28/*
29 * Sysproxy routines.  This provides system RPC support over host sockets.
30 * The most notable limitation is that the client and server must share
31 * the same ABI.  This does not mean that they have to be the same
32 * machine or that they need to run the same version of the host OS,
33 * just that they must agree on the data structures.  This even *might*
34 * work correctly from one hardware architecture to another.
35 */
36
37#include <sys/cdefs.h>
38
39#if !defined(lint)
40__RCSID("$NetBSD: rumpuser_sp.c,v 1.68 2014/12/08 00:12:03 justin Exp $");
41#endif /* !lint */
42
43#include <sys/types.h>
44#include <sys/mman.h>
45#include <sys/socket.h>
46
47#include <arpa/inet.h>
48#include <netinet/in.h>
49#include <netinet/tcp.h>
50
51#include <assert.h>
52#include <errno.h>
53#include <fcntl.h>
54#include <poll.h>
55#include <pthread.h>
56#include <stdarg.h>
57#include <stdio.h>
58#include <stdlib.h>
59#include <string.h>
60#include <unistd.h>
61
62#include <rump/rump.h> /* XXX: for rfork flags */
63#define LIBRUMPUSER /* XXX */
64#include <rump/rumpuser.h>
65
66extern struct rumpuser_hyperup rumpuser__hyp;
67
68static inline void
69rumpkern_unsched(int *nlocks, void *interlock)
70{
71
72	rumpuser__hyp.hyp_backend_unschedule(0, nlocks, interlock);
73}
74
75static inline void
76rumpkern_sched(int nlocks, void *interlock)
77{
78
79	rumpuser__hyp.hyp_backend_schedule(nlocks, interlock);
80}
81
82#define ET(x) return(x);
83
84/*      $NetBSD: sp_common.c,v 1.38 2014/01/08 01:45:29 pooka Exp $	*/
85
86/*
87 * Copyright (c) 2010, 2011 Antti Kantee.  All Rights Reserved.
88 *
89 * Redistribution and use in source and binary forms, with or without
90 * modification, are permitted provided that the following conditions
91 * are met:
92 * 1. Redistributions of source code must retain the above copyright
93 *    notice, this list of conditions and the following disclaimer.
94 * 2. Redistributions in binary form must reproduce the above copyright
95 *    notice, this list of conditions and the following disclaimer in the
96 *    documentation and/or other materials provided with the distribution.
97 *
98 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
99 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
100 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
101 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
102 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
103 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
104 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
105 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
106 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
107 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
108 * SUCH DAMAGE.
109 */
110
111/*
112 * Common client/server sysproxy routines.  #included.
113 */
114
115#include <sys/types.h>
116#include <sys/mman.h>
117#include <sys/queue.h>
118#include <sys/socket.h>
119#include <sys/un.h>
120#include <sys/uio.h>
121
122#include <arpa/inet.h>
123#include <netinet/in.h>
124#include <netinet/tcp.h>
125
126#include <assert.h>
127#include <errno.h>
128#include <fcntl.h>
129#include <inttypes.h>
130#include <limits.h>
131#include <poll.h>
132#include <pthread.h>
133#include <stdarg.h>
134#include <stddef.h>
135#include <stdio.h>
136#include <stdlib.h>
137#include <string.h>
138#include <unistd.h>
139
140//#define DEBUG
141#ifdef DEBUG
142#define DPRINTF(x) mydprintf x
143static void
144mydprintf(const char *fmt, ...)
145{
146	va_list ap;
147
148	va_start(ap, fmt);
149	vfprintf(stderr, fmt, ap);
150	va_end(ap);
151}
152#else
153#define DPRINTF(x)
154#endif
155
156#ifndef HOSTOPS
157#define host_poll poll
158#define host_read read
159#define host_sendmsg sendmsg
160#define host_setsockopt setsockopt
161#endif
162
163#define IOVPUT(_io_, _b_) _io_.iov_base = 			\
164    (void *)&_b_; _io_.iov_len = sizeof(_b_);
165#define IOVPUT_WITHSIZE(_io_, _b_, _l_) _io_.iov_base =		\
166    (void *)(_b_); _io_.iov_len = _l_;
167#define SENDIOV(_spc_, _iov_) dosend(_spc_, _iov_, __arraycount(_iov_))
168
169static int lwproc_newlwp(pid_t);
170static struct lwp *lwproc_curlwp(void);
171static void lwproc_release(void);
172static void lwproc_switch(struct lwp *);
173
174/*
175 * Bah, I hate writing on-off-wire conversions in C
176 */
177
178enum { RUMPSP_REQ, RUMPSP_RESP, RUMPSP_ERROR };
179enum {	RUMPSP_HANDSHAKE,
180	RUMPSP_SYSCALL,
181	RUMPSP_COPYIN, RUMPSP_COPYINSTR,
182	RUMPSP_COPYOUT, RUMPSP_COPYOUTSTR,
183	RUMPSP_ANONMMAP,
184	RUMPSP_PREFORK,
185	RUMPSP_RAISE };
186
187enum { HANDSHAKE_GUEST, HANDSHAKE_AUTH, HANDSHAKE_FORK, HANDSHAKE_EXEC };
188
189/*
190 * error types used for RUMPSP_ERROR
191 */
192enum rumpsp_err { RUMPSP_ERR_NONE = 0, RUMPSP_ERR_TRYAGAIN, RUMPSP_ERR_AUTH,
193	RUMPSP_ERR_INVALID_PREFORK, RUMPSP_ERR_RFORK_FAILED,
194	RUMPSP_ERR_INEXEC, RUMPSP_ERR_NOMEM, RUMPSP_ERR_MALFORMED_REQUEST };
195
196/*
197 * The mapping of the above types to errno.  They are almost never exposed
198 * to the client after handshake (except for a server resource shortage
199 * and the client trying to be funny).  This is a function instead of
200 * an array to catch missing values.  Theoretically, the compiled code
201 * should be the same.
202 */
203static int
204errmap(enum rumpsp_err error)
205{
206
207	switch (error) {
208	/* XXX: no EAUTH on Linux */
209	case RUMPSP_ERR_NONE:			return 0;
210	case RUMPSP_ERR_AUTH:			return EPERM;
211	case RUMPSP_ERR_TRYAGAIN:		return EAGAIN;
212	case RUMPSP_ERR_INVALID_PREFORK:	return ESRCH;
213	case RUMPSP_ERR_RFORK_FAILED:		return EIO; /* got a light? */
214	case RUMPSP_ERR_INEXEC:			return EBUSY;
215	case RUMPSP_ERR_NOMEM:			return ENOMEM;
216	case RUMPSP_ERR_MALFORMED_REQUEST:	return EINVAL;
217	}
218
219	return -1;
220}
221
222#define AUTHLEN 4 /* 128bit fork auth */
223
224struct rsp_hdr {
225	uint64_t rsp_len;
226	uint64_t rsp_reqno;
227	uint16_t rsp_class;
228	uint16_t rsp_type;
229	/*
230	 * We want this structure 64bit-aligned for typecast fun,
231	 * so might as well use the following for something.
232	 */
233	union {
234		uint32_t sysnum;
235		uint32_t error;
236		uint32_t handshake;
237		uint32_t signo;
238	} u;
239};
240#define HDRSZ sizeof(struct rsp_hdr)
241#define rsp_sysnum u.sysnum
242#define rsp_error u.error
243#define rsp_handshake u.handshake
244#define rsp_signo u.signo
245
246#define MAXBANNER 96
247
248/*
249 * Data follows the header.  We have two types of structured data.
250 */
251
252/* copyin/copyout */
253struct rsp_copydata {
254	size_t rcp_len;
255	void *rcp_addr;
256	uint8_t rcp_data[0];
257};
258
259/* syscall response */
260struct rsp_sysresp {
261	int rsys_error;
262	register_t rsys_retval[2];
263};
264
265struct handshake_fork {
266	uint32_t rf_auth[4];
267	int rf_cancel;
268};
269
270struct respwait {
271	uint64_t rw_reqno;
272	void *rw_data;
273	size_t rw_dlen;
274	int rw_done;
275	int rw_error;
276
277	pthread_cond_t rw_cv;
278
279	TAILQ_ENTRY(respwait) rw_entries;
280};
281
282struct prefork;
283struct spclient {
284	int spc_fd;
285	int spc_refcnt;
286	int spc_state;
287
288	pthread_mutex_t spc_mtx;
289	pthread_cond_t spc_cv;
290
291	struct lwp *spc_mainlwp;
292	pid_t spc_pid;
293
294	TAILQ_HEAD(, respwait) spc_respwait;
295
296	/* rest of the fields are zeroed upon disconnect */
297#define SPC_ZEROFF offsetof(struct spclient, spc_pfd)
298	struct pollfd *spc_pfd;
299
300	struct rsp_hdr spc_hdr;
301	uint8_t *spc_buf;
302	size_t spc_off;
303
304	uint64_t spc_nextreq;
305	uint64_t spc_syscallreq;
306	uint64_t spc_generation;
307	int spc_ostatus, spc_istatus;
308	int spc_reconnecting;
309	int spc_inexec;
310
311	LIST_HEAD(, prefork) spc_pflist;
312};
313#define SPCSTATUS_FREE 0
314#define SPCSTATUS_BUSY 1
315#define SPCSTATUS_WANTED 2
316
317#define SPCSTATE_NEW     0
318#define SPCSTATE_RUNNING 1
319#define SPCSTATE_DYING   2
320
321typedef int (*addrparse_fn)(const char *, struct sockaddr **, int);
322typedef int (*connecthook_fn)(int);
323typedef void (*cleanup_fn)(struct sockaddr *);
324
325static int readframe(struct spclient *);
326static void handlereq(struct spclient *);
327
328static __inline void
329spcresetbuf(struct spclient *spc)
330{
331
332	spc->spc_buf = NULL;
333	spc->spc_off = 0;
334}
335
336static __inline void
337spcfreebuf(struct spclient *spc)
338{
339
340	free(spc->spc_buf);
341	spcresetbuf(spc);
342}
343
344static void
345sendlockl(struct spclient *spc)
346{
347
348	while (spc->spc_ostatus != SPCSTATUS_FREE) {
349		spc->spc_ostatus = SPCSTATUS_WANTED;
350		pthread_cond_wait(&spc->spc_cv, &spc->spc_mtx);
351	}
352	spc->spc_ostatus = SPCSTATUS_BUSY;
353}
354
355static void __unused
356sendlock(struct spclient *spc)
357{
358
359	pthread_mutex_lock(&spc->spc_mtx);
360	sendlockl(spc);
361	pthread_mutex_unlock(&spc->spc_mtx);
362}
363
364static void
365sendunlockl(struct spclient *spc)
366{
367
368	if (spc->spc_ostatus == SPCSTATUS_WANTED)
369		pthread_cond_broadcast(&spc->spc_cv);
370	spc->spc_ostatus = SPCSTATUS_FREE;
371}
372
373static void
374sendunlock(struct spclient *spc)
375{
376
377	pthread_mutex_lock(&spc->spc_mtx);
378	sendunlockl(spc);
379	pthread_mutex_unlock(&spc->spc_mtx);
380}
381
382static int
383dosend(struct spclient *spc, struct iovec *iov, size_t iovlen)
384{
385	struct msghdr msg;
386	struct pollfd pfd;
387	ssize_t n = 0;
388	int fd = spc->spc_fd;
389	struct lwp *mylwp;
390	int error = 0;
391
392	pfd.fd = fd;
393	pfd.events = POLLOUT;
394
395	mylwp = lwproc_curlwp();
396	lwproc_newlwp(1);
397
398	memset(&msg, 0, sizeof(msg));
399
400	for (;;) {
401		/* not first round?  poll */
402		if (n) {
403			if (host_poll(&pfd, 1, INFTIM) == -1) {
404				if (errno == EINTR)
405					continue;
406				error = errno;
407				goto out;
408			}
409		}
410
411		msg.msg_iov = iov;
412		msg.msg_iovlen = iovlen;
413		n = host_sendmsg(fd, &msg, MSG_NOSIGNAL);
414		if (n == -1)  {
415			if (errno == EPIPE)
416				error = ENOTCONN;
417			if (errno != EAGAIN)
418				error = errno;
419			if (error)
420				goto out;
421			continue;
422		}
423		if (n == 0) {
424			error = ENOTCONN;
425			goto out;
426		}
427
428		/* ok, need to adjust iovec for potential next round */
429		while (n >= (ssize_t)iov[0].iov_len && iovlen) {
430			n -= iov[0].iov_len;
431			iov++;
432			iovlen--;
433		}
434
435		if (iovlen == 0) {
436			_DIAGASSERT(n == 0);
437			break;
438		} else {
439			iov[0].iov_base =
440			    (void *)((uint8_t *)iov[0].iov_base + n);
441			iov[0].iov_len -= n;
442		}
443	}
444
445	lwproc_release();
446	if (mylwp)
447		lwproc_switch(mylwp);
448
449 out:
450	return error;
451}
452
453static void
454doputwait(struct spclient *spc, struct respwait *rw, struct rsp_hdr *rhdr)
455{
456
457	rw->rw_data = NULL;
458	rw->rw_dlen = rw->rw_done = rw->rw_error = 0;
459	pthread_cond_init(&rw->rw_cv, NULL);
460
461	pthread_mutex_lock(&spc->spc_mtx);
462	rw->rw_reqno = rhdr->rsp_reqno = spc->spc_nextreq++;
463	TAILQ_INSERT_TAIL(&spc->spc_respwait, rw, rw_entries);
464}
465
466static void __unused
467putwait_locked(struct spclient *spc, struct respwait *rw, struct rsp_hdr *rhdr)
468{
469
470	doputwait(spc, rw, rhdr);
471	pthread_mutex_unlock(&spc->spc_mtx);
472}
473
474static void
475putwait(struct spclient *spc, struct respwait *rw, struct rsp_hdr *rhdr)
476{
477
478	doputwait(spc, rw, rhdr);
479	sendlockl(spc);
480	pthread_mutex_unlock(&spc->spc_mtx);
481}
482
483static void
484dounputwait(struct spclient *spc, struct respwait *rw)
485{
486
487	TAILQ_REMOVE(&spc->spc_respwait, rw, rw_entries);
488	pthread_mutex_unlock(&spc->spc_mtx);
489	pthread_cond_destroy(&rw->rw_cv);
490
491}
492
493static void __unused
494unputwait_locked(struct spclient *spc, struct respwait *rw)
495{
496
497	pthread_mutex_lock(&spc->spc_mtx);
498	dounputwait(spc, rw);
499}
500
501static void
502unputwait(struct spclient *spc, struct respwait *rw)
503{
504
505	pthread_mutex_lock(&spc->spc_mtx);
506	sendunlockl(spc);
507
508	dounputwait(spc, rw);
509}
510
511static void
512kickwaiter(struct spclient *spc)
513{
514	struct respwait *rw;
515	int error = 0;
516
517	pthread_mutex_lock(&spc->spc_mtx);
518	TAILQ_FOREACH(rw, &spc->spc_respwait, rw_entries) {
519		if (rw->rw_reqno == spc->spc_hdr.rsp_reqno)
520			break;
521	}
522	if (rw == NULL) {
523		DPRINTF(("no waiter found, invalid reqno %" PRIu64 "?\n",
524		    spc->spc_hdr.rsp_reqno));
525		pthread_mutex_unlock(&spc->spc_mtx);
526		spcfreebuf(spc);
527		return;
528	}
529	DPRINTF(("rump_sp: client %p woke up waiter at %p\n", spc, rw));
530	rw->rw_data = spc->spc_buf;
531	rw->rw_done = 1;
532	rw->rw_dlen = (size_t)(spc->spc_off - HDRSZ);
533	if (spc->spc_hdr.rsp_class == RUMPSP_ERROR) {
534		error = rw->rw_error = errmap(spc->spc_hdr.rsp_error);
535	}
536	pthread_cond_signal(&rw->rw_cv);
537	pthread_mutex_unlock(&spc->spc_mtx);
538
539	if (error)
540		spcfreebuf(spc);
541	else
542		spcresetbuf(spc);
543}
544
545static void
546kickall(struct spclient *spc)
547{
548	struct respwait *rw;
549
550	/* DIAGASSERT(mutex_owned(spc_lock)) */
551	TAILQ_FOREACH(rw, &spc->spc_respwait, rw_entries)
552		pthread_cond_broadcast(&rw->rw_cv);
553}
554
555static int
556readframe(struct spclient *spc)
557{
558	int fd = spc->spc_fd;
559	size_t left;
560	size_t framelen;
561	ssize_t n;
562
563	/* still reading header? */
564	if (spc->spc_off < HDRSZ) {
565		DPRINTF(("rump_sp: readframe getting header at offset %zu\n",
566		    spc->spc_off));
567
568		left = HDRSZ - spc->spc_off;
569		/*LINTED: cast ok */
570		n = host_read(fd, (uint8_t*)&spc->spc_hdr + spc->spc_off, left);
571		if (n == 0) {
572			return -1;
573		}
574		if (n == -1) {
575			if (errno == EAGAIN)
576				return 0;
577			return -1;
578		}
579
580		spc->spc_off += n;
581		if (spc->spc_off < HDRSZ) {
582			return 0;
583		}
584
585		/*LINTED*/
586		framelen = spc->spc_hdr.rsp_len;
587
588		if (framelen < HDRSZ) {
589			return -1;
590		} else if (framelen == HDRSZ) {
591			return 1;
592		}
593
594		spc->spc_buf = malloc(framelen - HDRSZ);
595		if (spc->spc_buf == NULL) {
596			return -1;
597		}
598		memset(spc->spc_buf, 0, framelen - HDRSZ);
599
600		/* "fallthrough" */
601	} else {
602		/*LINTED*/
603		framelen = spc->spc_hdr.rsp_len;
604	}
605
606	left = framelen - spc->spc_off;
607
608	DPRINTF(("rump_sp: readframe getting body at offset %zu, left %zu\n",
609	    spc->spc_off, left));
610
611	if (left == 0)
612		return 1;
613	n = host_read(fd, spc->spc_buf + (spc->spc_off - HDRSZ), left);
614	if (n == 0) {
615		return -1;
616	}
617	if (n == -1) {
618		if (errno == EAGAIN)
619			return 0;
620		return -1;
621	}
622	spc->spc_off += n;
623	left -= n;
624
625	/* got everything? */
626	if (left == 0)
627		return 1;
628	else
629		return 0;
630}
631
632static int
633tcp_parse(const char *addr, struct sockaddr **sa, int allow_wildcard)
634{
635	struct sockaddr_in sin;
636	char buf[64];
637	const char *p;
638	size_t l;
639	int port;
640
641	memset(&sin, 0, sizeof(sin));
642	sin.sin_len = sizeof(sin);
643	sin.sin_family = AF_INET;
644
645	p = strchr(addr, ':');
646	if (!p) {
647		fprintf(stderr, "rump_sp_tcp: missing port specifier\n");
648		return EINVAL;
649	}
650
651	l = p - addr;
652	if (l > sizeof(buf)-1) {
653		fprintf(stderr, "rump_sp_tcp: address too long\n");
654		return EINVAL;
655	}
656	strncpy(buf, addr, l);
657	buf[l] = '\0';
658
659	/* special INADDR_ANY treatment */
660	if (strcmp(buf, "*") == 0 || strcmp(buf, "0") == 0) {
661		sin.sin_addr.s_addr = INADDR_ANY;
662	} else {
663		switch (inet_pton(AF_INET, buf, &sin.sin_addr)) {
664		case 1:
665			break;
666		case 0:
667			fprintf(stderr, "rump_sp_tcp: cannot parse %s\n", buf);
668			return EINVAL;
669		case -1:
670			fprintf(stderr, "rump_sp_tcp: inet_pton failed\n");
671			return errno;
672		default:
673			assert(/*CONSTCOND*/0);
674			return EINVAL;
675		}
676	}
677
678	if (!allow_wildcard && sin.sin_addr.s_addr == INADDR_ANY) {
679		fprintf(stderr, "rump_sp_tcp: client needs !INADDR_ANY\n");
680		return EINVAL;
681	}
682
683	/* advance to port number & parse */
684	p++;
685	l = strspn(p, "0123456789");
686	if (l == 0) {
687		fprintf(stderr, "rump_sp_tcp: port now found: %s\n", p);
688		return EINVAL;
689	}
690	strncpy(buf, p, l);
691	buf[l] = '\0';
692
693	if (*(p+l) != '/' && *(p+l) != '\0') {
694		fprintf(stderr, "rump_sp_tcp: junk at end of port: %s\n", addr);
695		return EINVAL;
696	}
697
698	port = atoi(buf);
699	if (port < 0 || port >= (1<<(8*sizeof(in_port_t)))) {
700		fprintf(stderr, "rump_sp_tcp: port %d out of range\n", port);
701		return ERANGE;
702	}
703	sin.sin_port = htons(port);
704
705	*sa = malloc(sizeof(sin));
706	if (*sa == NULL)
707		return errno;
708	memcpy(*sa, &sin, sizeof(sin));
709	return 0;
710}
711
712static int
713tcp_connecthook(int s)
714{
715	int x;
716
717	x = 1;
718	host_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &x, sizeof(x));
719
720	return 0;
721}
722
723static char parsedurl[256];
724
725/*ARGSUSED*/
726static int
727unix_parse(const char *addr, struct sockaddr **sa, int allow_wildcard)
728{
729	struct sockaddr_un s_un;
730	size_t slen;
731	int savepath = 0;
732
733	if (strlen(addr) >= sizeof(s_un.sun_path))
734		return ENAMETOOLONG;
735
736	/*
737	 * The pathname can be all kinds of spaghetti elementals,
738	 * so meek and obidient we accept everything.  However, use
739	 * full path for easy cleanup in case someone gives a relative
740	 * one and the server does a chdir() between now than the
741	 * cleanup.
742	 */
743	memset(&s_un, 0, sizeof(s_un));
744	s_un.sun_family = AF_LOCAL;
745	if (*addr != '/') {
746		char mywd[PATH_MAX];
747
748		if (getcwd(mywd, sizeof(mywd)) == NULL) {
749			fprintf(stderr, "warning: cannot determine cwd, "
750			    "omitting socket cleanup\n");
751		} else {
752			if (strlen(addr)+strlen(mywd)+1
753			    >= sizeof(s_un.sun_path))
754				return ENAMETOOLONG;
755			strcpy(s_un.sun_path, mywd);
756			strcat(s_un.sun_path, "/");
757			savepath = 1;
758		}
759	}
760	strcat(s_un.sun_path, addr);
761#if defined(__linux__) || defined(__sun__) || defined(__CYGWIN__)
762	slen = sizeof(s_un);
763#else
764	s_un.sun_len = SUN_LEN(&s_un);
765	slen = s_un.sun_len+1; /* get the 0 too */
766#endif
767
768	if (savepath && *parsedurl == '\0') {
769		snprintf(parsedurl, sizeof(parsedurl),
770		    "unix://%s", s_un.sun_path);
771	}
772
773	*sa = malloc(slen);
774	if (*sa == NULL)
775		return errno;
776	memcpy(*sa, &s_un, slen);
777
778	return 0;
779}
780
781static void
782unix_cleanup(struct sockaddr *sa)
783{
784	struct sockaddr_un *s_sun = (void *)sa;
785
786	/*
787	 * cleanup only absolute paths.  see unix_parse() above
788	 */
789	if (*s_sun->sun_path == '/') {
790		unlink(s_sun->sun_path);
791	}
792}
793
794/*ARGSUSED*/
795static int
796notsupp(void)
797{
798
799	fprintf(stderr, "rump_sp: support not yet implemented\n");
800	return EOPNOTSUPP;
801}
802
803static int
804success(void)
805{
806
807	return 0;
808}
809
810static struct {
811	const char *id;
812	int domain;
813	socklen_t slen;
814	addrparse_fn ap;
815	connecthook_fn connhook;
816	cleanup_fn cleanup;
817} parsetab[] = {
818	{ "tcp", PF_INET, sizeof(struct sockaddr_in),
819	    tcp_parse, tcp_connecthook, (cleanup_fn)success },
820	{ "unix", PF_LOCAL, sizeof(struct sockaddr_un),
821	    unix_parse, (connecthook_fn)success, unix_cleanup },
822	{ "tcp6", PF_INET6, sizeof(struct sockaddr_in6),
823	    (addrparse_fn)notsupp, (connecthook_fn)success,
824	    (cleanup_fn)success },
825};
826#define NPARSE (sizeof(parsetab)/sizeof(parsetab[0]))
827
828static int
829parseurl(const char *url, struct sockaddr **sap, unsigned *idxp,
830	int allow_wildcard)
831{
832	char id[16];
833	const char *p, *p2;
834	size_t l;
835	unsigned i;
836	int error;
837
838	/*
839	 * Parse the url
840	 */
841
842	p = url;
843	p2 = strstr(p, "://");
844	if (!p2) {
845		fprintf(stderr, "rump_sp: invalid locator ``%s''\n", p);
846		return EINVAL;
847	}
848	l = p2-p;
849	if (l > sizeof(id)-1) {
850		fprintf(stderr, "rump_sp: identifier too long in ``%s''\n", p);
851		return EINVAL;
852	}
853
854	strncpy(id, p, l);
855	id[l] = '\0';
856	p2 += 3; /* beginning of address */
857
858	for (i = 0; i < NPARSE; i++) {
859		if (strcmp(id, parsetab[i].id) == 0) {
860			error = parsetab[i].ap(p2, sap, allow_wildcard);
861			if (error)
862				return error;
863			break;
864		}
865	}
866	if (i == NPARSE) {
867		fprintf(stderr, "rump_sp: invalid identifier ``%s''\n", p);
868		return EINVAL;
869	}
870
871	*idxp = i;
872	return 0;
873}
874
875#ifndef MAXCLI
876#define MAXCLI 256
877#endif
878#ifndef MAXWORKER
879#define MAXWORKER 128
880#endif
881#ifndef IDLEWORKER
882#define IDLEWORKER 16
883#endif
884int rumpsp_maxworker = MAXWORKER;
885int rumpsp_idleworker = IDLEWORKER;
886
887static struct pollfd pfdlist[MAXCLI];
888static struct spclient spclist[MAXCLI];
889static unsigned int disco;
890static volatile int spfini;
891
892static char banner[MAXBANNER];
893
894#define PROTOMAJOR 0
895#define PROTOMINOR 4
896
897
898/* how to use atomic ops on Linux? */
899#if defined(__linux__) || defined(__APPLE__) || defined(__CYGWIN__) || defined(__OpenBSD__)
900static pthread_mutex_t discomtx = PTHREAD_MUTEX_INITIALIZER;
901
902static void
903signaldisco(void)
904{
905
906	pthread_mutex_lock(&discomtx);
907	disco++;
908	pthread_mutex_unlock(&discomtx);
909}
910
911static unsigned int
912getdisco(void)
913{
914	unsigned int discocnt;
915
916	pthread_mutex_lock(&discomtx);
917	discocnt = disco;
918	disco = 0;
919	pthread_mutex_unlock(&discomtx);
920
921	return discocnt;
922}
923
924#elif defined(__FreeBSD__) || defined(__DragonFly__)
925
926#include <machine/atomic.h>
927#define signaldisco()	atomic_add_int(&disco, 1)
928#define getdisco()	atomic_readandclear_int(&disco)
929
930#else /* NetBSD */
931
932#include <sys/atomic.h>
933#define signaldisco() atomic_inc_uint(&disco)
934#define getdisco() atomic_swap_uint(&disco, 0)
935
936#endif
937
938
939struct prefork {
940	uint32_t pf_auth[AUTHLEN];
941	struct lwp *pf_lwp;
942
943	LIST_ENTRY(prefork) pf_entries;		/* global list */
944	LIST_ENTRY(prefork) pf_spcentries;	/* linked from forking spc */
945};
946static LIST_HEAD(, prefork) preforks = LIST_HEAD_INITIALIZER(preforks);
947static pthread_mutex_t pfmtx;
948
949/*
950 * This version is for the server.  It's optimized for multiple threads
951 * and is *NOT* reentrant wrt to signals.
952 */
953static int
954waitresp(struct spclient *spc, struct respwait *rw)
955{
956	int spcstate;
957	int rv = 0;
958
959	pthread_mutex_lock(&spc->spc_mtx);
960	sendunlockl(spc);
961	while (!rw->rw_done && spc->spc_state != SPCSTATE_DYING) {
962		pthread_cond_wait(&rw->rw_cv, &spc->spc_mtx);
963	}
964	TAILQ_REMOVE(&spc->spc_respwait, rw, rw_entries);
965	spcstate = spc->spc_state;
966	pthread_mutex_unlock(&spc->spc_mtx);
967
968	pthread_cond_destroy(&rw->rw_cv);
969
970	if (rv)
971		return rv;
972	if (spcstate == SPCSTATE_DYING)
973		return ENOTCONN;
974	return rw->rw_error;
975}
976
977/*
978 * Manual wrappers, since librump does not have access to the
979 * user namespace wrapped interfaces.
980 */
981
982static void
983lwproc_switch(struct lwp *l)
984{
985
986	rumpuser__hyp.hyp_schedule();
987	rumpuser__hyp.hyp_lwproc_switch(l);
988	rumpuser__hyp.hyp_unschedule();
989}
990
991static void
992lwproc_release(void)
993{
994
995	rumpuser__hyp.hyp_schedule();
996	rumpuser__hyp.hyp_lwproc_release();
997	rumpuser__hyp.hyp_unschedule();
998}
999
1000static int
1001lwproc_rfork(struct spclient *spc, int flags, const char *comm)
1002{
1003	int rv;
1004
1005	rumpuser__hyp.hyp_schedule();
1006	rv = rumpuser__hyp.hyp_lwproc_rfork(spc, flags, comm);
1007	rumpuser__hyp.hyp_unschedule();
1008
1009	return rv;
1010}
1011
1012static int
1013lwproc_newlwp(pid_t pid)
1014{
1015	int rv;
1016
1017	rumpuser__hyp.hyp_schedule();
1018	rv = rumpuser__hyp.hyp_lwproc_newlwp(pid);
1019	rumpuser__hyp.hyp_unschedule();
1020
1021	return rv;
1022}
1023
1024static struct lwp *
1025lwproc_curlwp(void)
1026{
1027	struct lwp *l;
1028
1029	rumpuser__hyp.hyp_schedule();
1030	l = rumpuser__hyp.hyp_lwproc_curlwp();
1031	rumpuser__hyp.hyp_unschedule();
1032
1033	return l;
1034}
1035
1036static pid_t
1037lwproc_getpid(void)
1038{
1039	pid_t p;
1040
1041	rumpuser__hyp.hyp_schedule();
1042	p = rumpuser__hyp.hyp_getpid();
1043	rumpuser__hyp.hyp_unschedule();
1044
1045	return p;
1046}
1047
1048static void
1049lwproc_execnotify(const char *comm)
1050{
1051
1052	rumpuser__hyp.hyp_schedule();
1053	rumpuser__hyp.hyp_execnotify(comm);
1054	rumpuser__hyp.hyp_unschedule();
1055}
1056
1057static void
1058lwproc_lwpexit(void)
1059{
1060
1061	rumpuser__hyp.hyp_schedule();
1062	rumpuser__hyp.hyp_lwpexit();
1063	rumpuser__hyp.hyp_unschedule();
1064}
1065
1066static int
1067rumpsyscall(int sysnum, void *data, register_t *regrv)
1068{
1069	long retval[2] = {0, 0};
1070	int rv;
1071
1072	rumpuser__hyp.hyp_schedule();
1073	rv = rumpuser__hyp.hyp_syscall(sysnum, data, retval);
1074	rumpuser__hyp.hyp_unschedule();
1075
1076	regrv[0] = retval[0];
1077	regrv[1] = retval[1];
1078	return rv;
1079}
1080
1081static uint64_t
1082nextreq(struct spclient *spc)
1083{
1084	uint64_t nw;
1085
1086	pthread_mutex_lock(&spc->spc_mtx);
1087	nw = spc->spc_nextreq++;
1088	pthread_mutex_unlock(&spc->spc_mtx);
1089
1090	return nw;
1091}
1092
1093/*
1094 * XXX: we send responses with "blocking" I/O.  This is not
1095 * ok for the main thread.  XXXFIXME
1096 */
1097
1098static void
1099send_error_resp(struct spclient *spc, uint64_t reqno, enum rumpsp_err error)
1100{
1101	struct rsp_hdr rhdr;
1102	struct iovec iov[1];
1103
1104	rhdr.rsp_len = sizeof(rhdr);
1105	rhdr.rsp_reqno = reqno;
1106	rhdr.rsp_class = RUMPSP_ERROR;
1107	rhdr.rsp_type = 0;
1108	rhdr.rsp_error = error;
1109
1110	IOVPUT(iov[0], rhdr);
1111
1112	sendlock(spc);
1113	(void)SENDIOV(spc, iov);
1114	sendunlock(spc);
1115}
1116
1117static int
1118send_handshake_resp(struct spclient *spc, uint64_t reqno, int error)
1119{
1120	struct rsp_hdr rhdr;
1121	struct iovec iov[2];
1122	int rv;
1123
1124	rhdr.rsp_len = sizeof(rhdr) + sizeof(error);
1125	rhdr.rsp_reqno = reqno;
1126	rhdr.rsp_class = RUMPSP_RESP;
1127	rhdr.rsp_type = RUMPSP_HANDSHAKE;
1128	rhdr.rsp_error = 0;
1129
1130	IOVPUT(iov[0], rhdr);
1131	IOVPUT(iov[1], error);
1132
1133	sendlock(spc);
1134	rv = SENDIOV(spc, iov);
1135	sendunlock(spc);
1136
1137	return rv;
1138}
1139
1140static int
1141send_syscall_resp(struct spclient *spc, uint64_t reqno, int error,
1142	register_t *retval)
1143{
1144	struct rsp_hdr rhdr;
1145	struct rsp_sysresp sysresp;
1146	struct iovec iov[2];
1147	int rv;
1148
1149	rhdr.rsp_len = sizeof(rhdr) + sizeof(sysresp);
1150	rhdr.rsp_reqno = reqno;
1151	rhdr.rsp_class = RUMPSP_RESP;
1152	rhdr.rsp_type = RUMPSP_SYSCALL;
1153	rhdr.rsp_sysnum = 0;
1154
1155	sysresp.rsys_error = error;
1156	memcpy(sysresp.rsys_retval, retval, sizeof(sysresp.rsys_retval));
1157
1158	IOVPUT(iov[0], rhdr);
1159	IOVPUT(iov[1], sysresp);
1160
1161	sendlock(spc);
1162	rv = SENDIOV(spc, iov);
1163	sendunlock(spc);
1164
1165	return rv;
1166}
1167
1168static int
1169send_prefork_resp(struct spclient *spc, uint64_t reqno, uint32_t *auth)
1170{
1171	struct rsp_hdr rhdr;
1172	struct iovec iov[2];
1173	int rv;
1174
1175	rhdr.rsp_len = sizeof(rhdr) + AUTHLEN*sizeof(*auth);
1176	rhdr.rsp_reqno = reqno;
1177	rhdr.rsp_class = RUMPSP_RESP;
1178	rhdr.rsp_type = RUMPSP_PREFORK;
1179	rhdr.rsp_sysnum = 0;
1180
1181	IOVPUT(iov[0], rhdr);
1182	IOVPUT_WITHSIZE(iov[1], auth, AUTHLEN*sizeof(*auth));
1183
1184	sendlock(spc);
1185	rv = SENDIOV(spc, iov);
1186	sendunlock(spc);
1187
1188	return rv;
1189}
1190
1191static int
1192copyin_req(struct spclient *spc, const void *remaddr, size_t *dlen,
1193	int wantstr, void **resp)
1194{
1195	struct rsp_hdr rhdr;
1196	struct rsp_copydata copydata;
1197	struct respwait rw;
1198	struct iovec iov[2];
1199	int rv;
1200
1201	DPRINTF(("copyin_req: %zu bytes from %p\n", *dlen, remaddr));
1202
1203	rhdr.rsp_len = sizeof(rhdr) + sizeof(copydata);
1204	rhdr.rsp_class = RUMPSP_REQ;
1205	if (wantstr)
1206		rhdr.rsp_type = RUMPSP_COPYINSTR;
1207	else
1208		rhdr.rsp_type = RUMPSP_COPYIN;
1209	rhdr.rsp_sysnum = 0;
1210
1211	copydata.rcp_addr = __UNCONST(remaddr);
1212	copydata.rcp_len = *dlen;
1213
1214	IOVPUT(iov[0], rhdr);
1215	IOVPUT(iov[1], copydata);
1216
1217	putwait(spc, &rw, &rhdr);
1218	rv = SENDIOV(spc, iov);
1219	if (rv) {
1220		unputwait(spc, &rw);
1221		return rv;
1222	}
1223
1224	rv = waitresp(spc, &rw);
1225
1226	DPRINTF(("copyin: response %d\n", rv));
1227
1228	*resp = rw.rw_data;
1229	if (wantstr)
1230		*dlen = rw.rw_dlen;
1231
1232	return rv;
1233
1234}
1235
1236static int
1237send_copyout_req(struct spclient *spc, const void *remaddr,
1238	const void *data, size_t dlen)
1239{
1240	struct rsp_hdr rhdr;
1241	struct rsp_copydata copydata;
1242	struct iovec iov[3];
1243	int rv;
1244
1245	DPRINTF(("copyout_req (async): %zu bytes to %p\n", dlen, remaddr));
1246
1247	rhdr.rsp_len = sizeof(rhdr) + sizeof(copydata) + dlen;
1248	rhdr.rsp_reqno = nextreq(spc);
1249	rhdr.rsp_class = RUMPSP_REQ;
1250	rhdr.rsp_type = RUMPSP_COPYOUT;
1251	rhdr.rsp_sysnum = 0;
1252
1253	copydata.rcp_addr = __UNCONST(remaddr);
1254	copydata.rcp_len = dlen;
1255
1256	IOVPUT(iov[0], rhdr);
1257	IOVPUT(iov[1], copydata);
1258	IOVPUT_WITHSIZE(iov[2], __UNCONST(data), dlen);
1259
1260	sendlock(spc);
1261	rv = SENDIOV(spc, iov);
1262	sendunlock(spc);
1263
1264	return rv;
1265}
1266
1267static int
1268anonmmap_req(struct spclient *spc, size_t howmuch, void **resp)
1269{
1270	struct rsp_hdr rhdr;
1271	struct respwait rw;
1272	struct iovec iov[2];
1273	int rv;
1274
1275	DPRINTF(("anonmmap_req: %zu bytes\n", howmuch));
1276
1277	rhdr.rsp_len = sizeof(rhdr) + sizeof(howmuch);
1278	rhdr.rsp_class = RUMPSP_REQ;
1279	rhdr.rsp_type = RUMPSP_ANONMMAP;
1280	rhdr.rsp_sysnum = 0;
1281
1282	IOVPUT(iov[0], rhdr);
1283	IOVPUT(iov[1], howmuch);
1284
1285	putwait(spc, &rw, &rhdr);
1286	rv = SENDIOV(spc, iov);
1287	if (rv) {
1288		unputwait(spc, &rw);
1289		return rv;
1290	}
1291
1292	rv = waitresp(spc, &rw);
1293
1294	*resp = rw.rw_data;
1295
1296	DPRINTF(("anonmmap: mapped at %p\n", **(void ***)resp));
1297
1298	return rv;
1299}
1300
1301static int
1302send_raise_req(struct spclient *spc, int signo)
1303{
1304	struct rsp_hdr rhdr;
1305	struct iovec iov[1];
1306	int rv;
1307
1308	rhdr.rsp_len = sizeof(rhdr);
1309	rhdr.rsp_class = RUMPSP_REQ;
1310	rhdr.rsp_type = RUMPSP_RAISE;
1311	rhdr.rsp_signo = signo;
1312
1313	IOVPUT(iov[0], rhdr);
1314
1315	sendlock(spc);
1316	rv = SENDIOV(spc, iov);
1317	sendunlock(spc);
1318
1319	return rv;
1320}
1321
1322static void
1323spcref(struct spclient *spc)
1324{
1325
1326	pthread_mutex_lock(&spc->spc_mtx);
1327	spc->spc_refcnt++;
1328	pthread_mutex_unlock(&spc->spc_mtx);
1329}
1330
1331static void
1332spcrelease(struct spclient *spc)
1333{
1334	int ref;
1335
1336	pthread_mutex_lock(&spc->spc_mtx);
1337	ref = --spc->spc_refcnt;
1338	if (__predict_false(spc->spc_inexec && ref <= 2))
1339		pthread_cond_broadcast(&spc->spc_cv);
1340	pthread_mutex_unlock(&spc->spc_mtx);
1341
1342	if (ref > 0)
1343		return;
1344
1345	DPRINTF(("rump_sp: spcrelease: spc %p fd %d\n", spc, spc->spc_fd));
1346
1347	_DIAGASSERT(TAILQ_EMPTY(&spc->spc_respwait));
1348	_DIAGASSERT(spc->spc_buf == NULL);
1349
1350	if (spc->spc_mainlwp) {
1351		lwproc_switch(spc->spc_mainlwp);
1352		lwproc_release();
1353	}
1354	spc->spc_mainlwp = NULL;
1355
1356	close(spc->spc_fd);
1357	spc->spc_fd = -1;
1358	spc->spc_state = SPCSTATE_NEW;
1359
1360	signaldisco();
1361}
1362
1363static void
1364serv_handledisco(unsigned int idx)
1365{
1366	struct spclient *spc = &spclist[idx];
1367	int dolwpexit;
1368
1369	DPRINTF(("rump_sp: disconnecting [%u]\n", idx));
1370
1371	pfdlist[idx].fd = -1;
1372	pfdlist[idx].revents = 0;
1373	pthread_mutex_lock(&spc->spc_mtx);
1374	spc->spc_state = SPCSTATE_DYING;
1375	kickall(spc);
1376	sendunlockl(spc);
1377	/* exec uses mainlwp in another thread, but also nuked all lwps */
1378	dolwpexit = !spc->spc_inexec;
1379	pthread_mutex_unlock(&spc->spc_mtx);
1380
1381	if (dolwpexit && spc->spc_mainlwp) {
1382		lwproc_switch(spc->spc_mainlwp);
1383		lwproc_lwpexit();
1384		lwproc_switch(NULL);
1385	}
1386
1387	/*
1388	 * Nobody's going to attempt to send/receive anymore,
1389	 * so reinit info relevant to that.
1390	 */
1391	/*LINTED:pointer casts may be ok*/
1392	memset((char *)spc + SPC_ZEROFF, 0, sizeof(*spc) - SPC_ZEROFF);
1393
1394	spcrelease(spc);
1395}
1396
1397static void
1398serv_shutdown(void)
1399{
1400	struct spclient *spc;
1401	unsigned int i;
1402
1403	for (i = 1; i < MAXCLI; i++) {
1404		spc = &spclist[i];
1405		if (spc->spc_fd == -1)
1406			continue;
1407
1408		shutdown(spc->spc_fd, SHUT_RDWR);
1409		serv_handledisco(i);
1410
1411		spcrelease(spc);
1412	}
1413}
1414
1415static unsigned
1416serv_handleconn(int fd, connecthook_fn connhook, int busy)
1417{
1418	struct sockaddr_storage ss;
1419	socklen_t sl = sizeof(ss);
1420	int newfd, flags;
1421	unsigned i;
1422
1423	/*LINTED: cast ok */
1424	newfd = accept(fd, (struct sockaddr *)&ss, &sl);
1425	if (newfd == -1)
1426		return 0;
1427
1428	if (busy) {
1429		close(newfd); /* EBUSY */
1430		return 0;
1431	}
1432
1433	flags = fcntl(newfd, F_GETFL, 0);
1434	if (fcntl(newfd, F_SETFL, flags | O_NONBLOCK) == -1) {
1435		close(newfd);
1436		return 0;
1437	}
1438
1439	if (connhook(newfd) != 0) {
1440		close(newfd);
1441		return 0;
1442	}
1443
1444	/* write out a banner for the client */
1445	if (send(newfd, banner, strlen(banner), MSG_NOSIGNAL)
1446	    != (ssize_t)strlen(banner)) {
1447		close(newfd);
1448		return 0;
1449	}
1450
1451	/* find empty slot the simple way */
1452	for (i = 0; i < MAXCLI; i++) {
1453		if (pfdlist[i].fd == -1 && spclist[i].spc_state == SPCSTATE_NEW)
1454			break;
1455	}
1456
1457	/*
1458	 * Although not finding a slot is impossible (cf. how this routine
1459	 * is called), the compiler can still think that i == MAXCLI
1460	 * if this code is either compiled with NDEBUG or the platform
1461	 * does not use __dead for assert().  Therefore, add an explicit
1462	 * check to avoid an array-bounds error.
1463	 */
1464	/* assert(i < MAXCLI); */
1465	if (i == MAXCLI)
1466		abort();
1467
1468	pfdlist[i].fd = newfd;
1469	spclist[i].spc_fd = newfd;
1470	spclist[i].spc_istatus = SPCSTATUS_BUSY; /* dedicated receiver */
1471	spclist[i].spc_refcnt = 1;
1472
1473	TAILQ_INIT(&spclist[i].spc_respwait);
1474
1475	DPRINTF(("rump_sp: added new connection fd %d at idx %u\n", newfd, i));
1476
1477	return i;
1478}
1479
1480static void
1481serv_handlesyscall(struct spclient *spc, struct rsp_hdr *rhdr, uint8_t *data)
1482{
1483	register_t retval[2] = {0, 0};
1484	int rv, sysnum;
1485
1486	sysnum = (int)rhdr->rsp_sysnum;
1487	DPRINTF(("rump_sp: handling syscall %d from client %d\n",
1488	    sysnum, spc->spc_pid));
1489
1490	if (__predict_false((rv = lwproc_newlwp(spc->spc_pid)) != 0)) {
1491		retval[0] = -1;
1492		send_syscall_resp(spc, rhdr->rsp_reqno, rv, retval);
1493		return;
1494	}
1495	spc->spc_syscallreq = rhdr->rsp_reqno;
1496	rv = rumpsyscall(sysnum, data, retval);
1497	spc->spc_syscallreq = 0;
1498	lwproc_release();
1499
1500	DPRINTF(("rump_sp: got return value %d & %d/%d\n",
1501	    rv, retval[0], retval[1]));
1502
1503	send_syscall_resp(spc, rhdr->rsp_reqno, rv, retval);
1504}
1505
1506static void
1507serv_handleexec(struct spclient *spc, struct rsp_hdr *rhdr, char *comm)
1508{
1509	size_t commlen = rhdr->rsp_len - HDRSZ;
1510
1511	pthread_mutex_lock(&spc->spc_mtx);
1512	/* one for the connection and one for us */
1513	while (spc->spc_refcnt > 2)
1514		pthread_cond_wait(&spc->spc_cv, &spc->spc_mtx);
1515	pthread_mutex_unlock(&spc->spc_mtx);
1516
1517	/*
1518	 * ok, all the threads are dead (or one is still alive and
1519	 * the connection is dead, in which case this doesn't matter
1520	 * very much).  proceed with exec.
1521	 */
1522
1523	/* ensure comm is 0-terminated */
1524	/* TODO: make sure it contains sensible chars? */
1525	comm[commlen] = '\0';
1526
1527	lwproc_switch(spc->spc_mainlwp);
1528	lwproc_execnotify(comm);
1529	lwproc_switch(NULL);
1530
1531	pthread_mutex_lock(&spc->spc_mtx);
1532	spc->spc_inexec = 0;
1533	pthread_mutex_unlock(&spc->spc_mtx);
1534	send_handshake_resp(spc, rhdr->rsp_reqno, 0);
1535}
1536
1537enum sbatype { SBA_SYSCALL, SBA_EXEC };
1538
1539struct servbouncearg {
1540	struct spclient *sba_spc;
1541	struct rsp_hdr sba_hdr;
1542	enum sbatype sba_type;
1543	uint8_t *sba_data;
1544
1545	TAILQ_ENTRY(servbouncearg) sba_entries;
1546};
1547static pthread_mutex_t sbamtx;
1548static pthread_cond_t sbacv;
1549static int nworker, idleworker, nwork;
1550static TAILQ_HEAD(, servbouncearg) wrklist = TAILQ_HEAD_INITIALIZER(wrklist);
1551
1552/*ARGSUSED*/
1553static void *
1554serv_workbouncer(void *arg)
1555{
1556	struct servbouncearg *sba;
1557
1558	for (;;) {
1559		pthread_mutex_lock(&sbamtx);
1560		if (__predict_false(idleworker - nwork >= rumpsp_idleworker)) {
1561			nworker--;
1562			pthread_mutex_unlock(&sbamtx);
1563			break;
1564		}
1565		idleworker++;
1566		while (TAILQ_EMPTY(&wrklist)) {
1567			_DIAGASSERT(nwork == 0);
1568			pthread_cond_wait(&sbacv, &sbamtx);
1569		}
1570		idleworker--;
1571
1572		sba = TAILQ_FIRST(&wrklist);
1573		TAILQ_REMOVE(&wrklist, sba, sba_entries);
1574		nwork--;
1575		pthread_mutex_unlock(&sbamtx);
1576
1577		if (__predict_true(sba->sba_type == SBA_SYSCALL)) {
1578			serv_handlesyscall(sba->sba_spc,
1579			    &sba->sba_hdr, sba->sba_data);
1580		} else {
1581			_DIAGASSERT(sba->sba_type == SBA_EXEC);
1582			serv_handleexec(sba->sba_spc, &sba->sba_hdr,
1583			    (char *)sba->sba_data);
1584		}
1585		spcrelease(sba->sba_spc);
1586		free(sba->sba_data);
1587		free(sba);
1588	}
1589
1590	return NULL;
1591}
1592
1593static int
1594sp_copyin(void *arg, const void *raddr, void *laddr, size_t *len, int wantstr)
1595{
1596	struct spclient *spc = arg;
1597	void *rdata = NULL; /* XXXuninit */
1598	int rv, nlocks;
1599
1600	rumpkern_unsched(&nlocks, NULL);
1601
1602	rv = copyin_req(spc, raddr, len, wantstr, &rdata);
1603	if (rv)
1604		goto out;
1605
1606	memcpy(laddr, rdata, *len);
1607	free(rdata);
1608
1609 out:
1610	rumpkern_sched(nlocks, NULL);
1611	if (rv)
1612		rv = EFAULT;
1613	ET(rv);
1614}
1615
1616int
1617rumpuser_sp_copyin(void *arg, const void *raddr, void *laddr, size_t len)
1618{
1619	int rv;
1620
1621	rv = sp_copyin(arg, raddr, laddr, &len, 0);
1622	ET(rv);
1623}
1624
1625int
1626rumpuser_sp_copyinstr(void *arg, const void *raddr, void *laddr, size_t *len)
1627{
1628	int rv;
1629
1630	rv = sp_copyin(arg, raddr, laddr, len, 1);
1631	ET(rv);
1632}
1633
1634static int
1635sp_copyout(void *arg, const void *laddr, void *raddr, size_t dlen)
1636{
1637	struct spclient *spc = arg;
1638	int nlocks, rv;
1639
1640	rumpkern_unsched(&nlocks, NULL);
1641	rv = send_copyout_req(spc, raddr, laddr, dlen);
1642	rumpkern_sched(nlocks, NULL);
1643
1644	if (rv)
1645		rv = EFAULT;
1646	ET(rv);
1647}
1648
1649int
1650rumpuser_sp_copyout(void *arg, const void *laddr, void *raddr, size_t dlen)
1651{
1652	int rv;
1653
1654	rv = sp_copyout(arg, laddr, raddr, dlen);
1655	ET(rv);
1656}
1657
1658int
1659rumpuser_sp_copyoutstr(void *arg, const void *laddr, void *raddr, size_t *dlen)
1660{
1661	int rv;
1662
1663	rv = sp_copyout(arg, laddr, raddr, *dlen);
1664	ET(rv);
1665}
1666
1667int
1668rumpuser_sp_anonmmap(void *arg, size_t howmuch, void **addr)
1669{
1670	struct spclient *spc = arg;
1671	void *resp, *rdata = NULL; /* XXXuninit */
1672	int nlocks, rv;
1673
1674	rumpkern_unsched(&nlocks, NULL);
1675
1676	rv = anonmmap_req(spc, howmuch, &rdata);
1677	if (rv) {
1678		rv = EFAULT;
1679		goto out;
1680	}
1681
1682	resp = *(void **)rdata;
1683	free(rdata);
1684
1685	if (resp == NULL) {
1686		rv = ENOMEM;
1687	}
1688
1689	*addr = resp;
1690
1691 out:
1692	rumpkern_sched(nlocks, NULL);
1693	ET(rv);
1694}
1695
1696int
1697rumpuser_sp_raise(void *arg, int signo)
1698{
1699	struct spclient *spc = arg;
1700	int rv, nlocks;
1701
1702	rumpkern_unsched(&nlocks, NULL);
1703	rv = send_raise_req(spc, signo);
1704	rumpkern_sched(nlocks, NULL);
1705
1706	return rv;
1707}
1708
1709static pthread_attr_t pattr_detached;
1710static void
1711schedulework(struct spclient *spc, enum sbatype sba_type)
1712{
1713	struct servbouncearg *sba;
1714	pthread_t pt;
1715	uint64_t reqno;
1716	int retries = 0;
1717
1718	reqno = spc->spc_hdr.rsp_reqno;
1719	while ((sba = malloc(sizeof(*sba))) == NULL) {
1720		if (nworker == 0 || retries > 10) {
1721			send_error_resp(spc, reqno, RUMPSP_ERR_TRYAGAIN);
1722			spcfreebuf(spc);
1723			return;
1724		}
1725		/* slim chance of more memory? */
1726		usleep(10000);
1727	}
1728
1729	sba->sba_spc = spc;
1730	sba->sba_type = sba_type;
1731	sba->sba_hdr = spc->spc_hdr;
1732	sba->sba_data = spc->spc_buf;
1733	spcresetbuf(spc);
1734
1735	spcref(spc);
1736
1737	pthread_mutex_lock(&sbamtx);
1738	TAILQ_INSERT_TAIL(&wrklist, sba, sba_entries);
1739	nwork++;
1740	if (nwork <= idleworker) {
1741		/* do we have a daemon's tool (i.e. idle threads)? */
1742		pthread_cond_signal(&sbacv);
1743	} else if (nworker < rumpsp_maxworker) {
1744		/*
1745		 * Else, need to create one
1746		 * (if we can, otherwise just expect another
1747		 * worker to pick up the syscall)
1748		 */
1749		if (pthread_create(&pt, &pattr_detached,
1750		    serv_workbouncer, NULL) == 0) {
1751			nworker++;
1752		}
1753	}
1754	pthread_mutex_unlock(&sbamtx);
1755}
1756
1757/*
1758 *
1759 * Startup routines and mainloop for server.
1760 *
1761 */
1762
1763struct spservarg {
1764	int sps_sock;
1765	connecthook_fn sps_connhook;
1766};
1767
1768static void
1769handlereq(struct spclient *spc)
1770{
1771	uint64_t reqno;
1772	int error;
1773
1774	reqno = spc->spc_hdr.rsp_reqno;
1775	if (__predict_false(spc->spc_state == SPCSTATE_NEW)) {
1776		if (spc->spc_hdr.rsp_type != RUMPSP_HANDSHAKE) {
1777			send_error_resp(spc, reqno, RUMPSP_ERR_AUTH);
1778			shutdown(spc->spc_fd, SHUT_RDWR);
1779			spcfreebuf(spc);
1780			return;
1781		}
1782
1783		if (spc->spc_hdr.rsp_handshake == HANDSHAKE_GUEST) {
1784			char *comm = (char *)spc->spc_buf;
1785			size_t commlen = spc->spc_hdr.rsp_len - HDRSZ;
1786
1787			/* ensure it's 0-terminated */
1788			/* XXX make sure it contains sensible chars? */
1789			comm[commlen] = '\0';
1790
1791			/* make sure we fork off of proc1 */
1792			_DIAGASSERT(lwproc_curlwp() == NULL);
1793
1794			if ((error = lwproc_rfork(spc,
1795			    RUMP_RFFD_CLEAR, comm)) != 0) {
1796				shutdown(spc->spc_fd, SHUT_RDWR);
1797			}
1798
1799			spcfreebuf(spc);
1800			if (error)
1801				return;
1802
1803			spc->spc_mainlwp = lwproc_curlwp();
1804
1805			send_handshake_resp(spc, reqno, 0);
1806		} else if (spc->spc_hdr.rsp_handshake == HANDSHAKE_FORK) {
1807			struct lwp *tmpmain;
1808			struct prefork *pf;
1809			struct handshake_fork *rfp;
1810			int cancel;
1811
1812			if (spc->spc_off-HDRSZ != sizeof(*rfp)) {
1813				send_error_resp(spc, reqno,
1814				    RUMPSP_ERR_MALFORMED_REQUEST);
1815				shutdown(spc->spc_fd, SHUT_RDWR);
1816				spcfreebuf(spc);
1817				return;
1818			}
1819
1820			/*LINTED*/
1821			rfp = (void *)spc->spc_buf;
1822			cancel = rfp->rf_cancel;
1823
1824			pthread_mutex_lock(&pfmtx);
1825			LIST_FOREACH(pf, &preforks, pf_entries) {
1826				if (memcmp(rfp->rf_auth, pf->pf_auth,
1827				    sizeof(rfp->rf_auth)) == 0) {
1828					LIST_REMOVE(pf, pf_entries);
1829					LIST_REMOVE(pf, pf_spcentries);
1830					break;
1831				}
1832			}
1833			pthread_mutex_unlock(&pfmtx);
1834			spcfreebuf(spc);
1835
1836			if (!pf) {
1837				send_error_resp(spc, reqno,
1838				    RUMPSP_ERR_INVALID_PREFORK);
1839				shutdown(spc->spc_fd, SHUT_RDWR);
1840				return;
1841			}
1842
1843			tmpmain = pf->pf_lwp;
1844			free(pf);
1845			lwproc_switch(tmpmain);
1846			if (cancel) {
1847				lwproc_release();
1848				shutdown(spc->spc_fd, SHUT_RDWR);
1849				return;
1850			}
1851
1852			/*
1853			 * So, we forked already during "prefork" to save
1854			 * the file descriptors from a parent exit
1855			 * race condition.  But now we need to fork
1856			 * a second time since the initial fork has
1857			 * the wrong spc pointer.  (yea, optimize
1858			 * interfaces some day if anyone cares)
1859			 */
1860			if ((error = lwproc_rfork(spc,
1861			    RUMP_RFFD_SHARE, NULL)) != 0) {
1862				send_error_resp(spc, reqno,
1863				    RUMPSP_ERR_RFORK_FAILED);
1864				shutdown(spc->spc_fd, SHUT_RDWR);
1865				lwproc_release();
1866				return;
1867			}
1868			spc->spc_mainlwp = lwproc_curlwp();
1869			lwproc_switch(tmpmain);
1870			lwproc_release();
1871			lwproc_switch(spc->spc_mainlwp);
1872
1873			send_handshake_resp(spc, reqno, 0);
1874		} else {
1875			send_error_resp(spc, reqno, RUMPSP_ERR_AUTH);
1876			shutdown(spc->spc_fd, SHUT_RDWR);
1877			spcfreebuf(spc);
1878			return;
1879		}
1880
1881		spc->spc_pid = lwproc_getpid();
1882
1883		DPRINTF(("rump_sp: handshake for client %p complete, pid %d\n",
1884		    spc, spc->spc_pid));
1885
1886		lwproc_switch(NULL);
1887		spc->spc_state = SPCSTATE_RUNNING;
1888		return;
1889	}
1890
1891	if (__predict_false(spc->spc_hdr.rsp_type == RUMPSP_PREFORK)) {
1892		struct prefork *pf;
1893		uint32_t auth[AUTHLEN];
1894		size_t randlen;
1895		int inexec;
1896
1897		DPRINTF(("rump_sp: prefork handler executing for %p\n", spc));
1898		spcfreebuf(spc);
1899
1900		pthread_mutex_lock(&spc->spc_mtx);
1901		inexec = spc->spc_inexec;
1902		pthread_mutex_unlock(&spc->spc_mtx);
1903		if (inexec) {
1904			send_error_resp(spc, reqno, RUMPSP_ERR_INEXEC);
1905			shutdown(spc->spc_fd, SHUT_RDWR);
1906			return;
1907		}
1908
1909		pf = malloc(sizeof(*pf));
1910		if (pf == NULL) {
1911			send_error_resp(spc, reqno, RUMPSP_ERR_NOMEM);
1912			return;
1913		}
1914
1915		/*
1916		 * Use client main lwp to fork.  this is never used by
1917		 * worker threads (except in exec, but we checked for that
1918		 * above) so we can safely use it here.
1919		 */
1920		lwproc_switch(spc->spc_mainlwp);
1921		if ((error = lwproc_rfork(spc, RUMP_RFFD_COPY, NULL)) != 0) {
1922			DPRINTF(("rump_sp: fork failed: %d (%p)\n",error, spc));
1923			send_error_resp(spc, reqno, RUMPSP_ERR_RFORK_FAILED);
1924			lwproc_switch(NULL);
1925			free(pf);
1926			return;
1927		}
1928
1929		/* Ok, we have a new process context and a new curlwp */
1930		rumpuser_getrandom(auth, sizeof(auth), 0, &randlen);
1931		memcpy(pf->pf_auth, auth, sizeof(pf->pf_auth));
1932		pf->pf_lwp = lwproc_curlwp();
1933		lwproc_switch(NULL);
1934
1935		pthread_mutex_lock(&pfmtx);
1936		LIST_INSERT_HEAD(&preforks, pf, pf_entries);
1937		LIST_INSERT_HEAD(&spc->spc_pflist, pf, pf_spcentries);
1938		pthread_mutex_unlock(&pfmtx);
1939
1940		DPRINTF(("rump_sp: prefork handler success %p\n", spc));
1941
1942		send_prefork_resp(spc, reqno, auth);
1943		return;
1944	}
1945
1946	if (__predict_false(spc->spc_hdr.rsp_type == RUMPSP_HANDSHAKE)) {
1947		int inexec;
1948
1949		if (spc->spc_hdr.rsp_handshake != HANDSHAKE_EXEC) {
1950			send_error_resp(spc, reqno,
1951			    RUMPSP_ERR_MALFORMED_REQUEST);
1952			shutdown(spc->spc_fd, SHUT_RDWR);
1953			spcfreebuf(spc);
1954			return;
1955		}
1956
1957		pthread_mutex_lock(&spc->spc_mtx);
1958		inexec = spc->spc_inexec;
1959		pthread_mutex_unlock(&spc->spc_mtx);
1960		if (inexec) {
1961			send_error_resp(spc, reqno, RUMPSP_ERR_INEXEC);
1962			shutdown(spc->spc_fd, SHUT_RDWR);
1963			spcfreebuf(spc);
1964			return;
1965		}
1966
1967		pthread_mutex_lock(&spc->spc_mtx);
1968		spc->spc_inexec = 1;
1969		pthread_mutex_unlock(&spc->spc_mtx);
1970
1971		/*
1972		 * start to drain lwps.  we will wait for it to finish
1973		 * in another thread
1974		 */
1975		lwproc_switch(spc->spc_mainlwp);
1976		lwproc_lwpexit();
1977		lwproc_switch(NULL);
1978
1979		/*
1980		 * exec has to wait for lwps to drain, so finish it off
1981		 * in another thread
1982		 */
1983		schedulework(spc, SBA_EXEC);
1984		return;
1985	}
1986
1987	if (__predict_false(spc->spc_hdr.rsp_type != RUMPSP_SYSCALL)) {
1988		send_error_resp(spc, reqno, RUMPSP_ERR_MALFORMED_REQUEST);
1989		spcfreebuf(spc);
1990		return;
1991	}
1992
1993	schedulework(spc, SBA_SYSCALL);
1994}
1995
1996static void *
1997spserver(void *arg)
1998{
1999	struct spservarg *sarg = arg;
2000	struct spclient *spc;
2001	unsigned idx;
2002	int seen;
2003	int rv;
2004	unsigned int nfds, maxidx;
2005
2006	for (idx = 0; idx < MAXCLI; idx++) {
2007		pfdlist[idx].fd = -1;
2008		pfdlist[idx].events = POLLIN;
2009
2010		spc = &spclist[idx];
2011		pthread_mutex_init(&spc->spc_mtx, NULL);
2012		pthread_cond_init(&spc->spc_cv, NULL);
2013		spc->spc_fd = -1;
2014	}
2015	pfdlist[0].fd = spclist[0].spc_fd = sarg->sps_sock;
2016	pfdlist[0].events = POLLIN;
2017	nfds = 1;
2018	maxidx = 0;
2019
2020	pthread_attr_init(&pattr_detached);
2021	pthread_attr_setdetachstate(&pattr_detached, PTHREAD_CREATE_DETACHED);
2022#if NOTYET
2023	pthread_attr_setstacksize(&pattr_detached, 32*1024);
2024#endif
2025
2026	pthread_mutex_init(&sbamtx, NULL);
2027	pthread_cond_init(&sbacv, NULL);
2028
2029	DPRINTF(("rump_sp: server mainloop\n"));
2030
2031	for (;;) {
2032		int discoed;
2033
2034		/* g/c hangarounds (eventually) */
2035		discoed = getdisco();
2036		while (discoed--) {
2037			nfds--;
2038			idx = maxidx;
2039			while (idx) {
2040				if (pfdlist[idx].fd != -1) {
2041					maxidx = idx;
2042					break;
2043				}
2044				idx--;
2045			}
2046			DPRINTF(("rump_sp: set maxidx to [%u]\n",
2047			    maxidx));
2048		}
2049
2050		DPRINTF(("rump_sp: loop nfd %d\n", maxidx+1));
2051		seen = 0;
2052		rv = poll(pfdlist, maxidx+1, INFTIM);
2053		assert(maxidx+1 <= MAXCLI);
2054		assert(rv != 0);
2055		if (rv == -1) {
2056			if (errno == EINTR)
2057				continue;
2058			fprintf(stderr, "rump_spserver: poll returned %d\n",
2059			    errno);
2060			break;
2061		}
2062
2063		for (idx = 0; seen < rv && idx < MAXCLI; idx++) {
2064			if ((pfdlist[idx].revents & POLLIN) == 0)
2065				continue;
2066
2067			seen++;
2068			DPRINTF(("rump_sp: activity at [%u] %d/%d\n",
2069			    idx, seen, rv));
2070			if (idx > 0) {
2071				spc = &spclist[idx];
2072				DPRINTF(("rump_sp: mainloop read [%u]\n", idx));
2073				switch (readframe(spc)) {
2074				case 0:
2075					break;
2076				case -1:
2077					serv_handledisco(idx);
2078					break;
2079				default:
2080					switch (spc->spc_hdr.rsp_class) {
2081					case RUMPSP_RESP:
2082						kickwaiter(spc);
2083						break;
2084					case RUMPSP_REQ:
2085						handlereq(spc);
2086						break;
2087					default:
2088						send_error_resp(spc,
2089						  spc->spc_hdr.rsp_reqno,
2090						  RUMPSP_ERR_MALFORMED_REQUEST);
2091						spcfreebuf(spc);
2092						break;
2093					}
2094					break;
2095				}
2096
2097			} else {
2098				DPRINTF(("rump_sp: mainloop new connection\n"));
2099
2100				if (__predict_false(spfini)) {
2101					close(spclist[0].spc_fd);
2102					serv_shutdown();
2103					goto out;
2104				}
2105
2106				idx = serv_handleconn(pfdlist[0].fd,
2107				    sarg->sps_connhook, nfds == MAXCLI);
2108				if (idx)
2109					nfds++;
2110				if (idx > maxidx)
2111					maxidx = idx;
2112				DPRINTF(("rump_sp: maxid now %d\n", maxidx));
2113			}
2114		}
2115	}
2116
2117 out:
2118	return NULL;
2119}
2120
2121static unsigned cleanupidx;
2122static struct sockaddr *cleanupsa;
2123int
2124rumpuser_sp_init(const char *url,
2125	const char *ostype, const char *osrelease, const char *machine)
2126{
2127	pthread_t pt;
2128	struct spservarg *sarg;
2129	struct sockaddr *sap;
2130	char *p;
2131	unsigned idx = 0; /* XXXgcc */
2132	int error, s;
2133
2134	p = strdup(url);
2135	if (p == NULL) {
2136		error = ENOMEM;
2137		goto out;
2138	}
2139	error = parseurl(p, &sap, &idx, 1);
2140	free(p);
2141	if (error)
2142		goto out;
2143
2144	snprintf(banner, sizeof(banner), "RUMPSP-%d.%d-%s-%s/%s\n",
2145	    PROTOMAJOR, PROTOMINOR, ostype, osrelease, machine);
2146
2147	s = socket(parsetab[idx].domain, SOCK_STREAM, 0);
2148	if (s == -1) {
2149		error = errno;
2150		goto out;
2151	}
2152
2153	sarg = malloc(sizeof(*sarg));
2154	if (sarg == NULL) {
2155		close(s);
2156		error = ENOMEM;
2157		goto out;
2158	}
2159
2160	sarg->sps_sock = s;
2161	sarg->sps_connhook = parsetab[idx].connhook;
2162
2163	cleanupidx = idx;
2164	cleanupsa = sap;
2165
2166	/* sloppy error recovery */
2167
2168	/*LINTED*/
2169	if (bind(s, sap, parsetab[idx].slen) == -1) {
2170		error = errno;
2171		fprintf(stderr, "rump_sp: server bind failed\n");
2172		goto out;
2173	}
2174	if (listen(s, MAXCLI) == -1) {
2175		error = errno;
2176		fprintf(stderr, "rump_sp: server listen failed\n");
2177		goto out;
2178	}
2179
2180	if ((error = pthread_create(&pt, NULL, spserver, sarg)) != 0) {
2181		fprintf(stderr, "rump_sp: cannot create wrkr thread\n");
2182		goto out;
2183	}
2184	pthread_detach(pt);
2185
2186 out:
2187	ET(error);
2188}
2189
2190void
2191rumpuser_sp_fini(void *arg)
2192{
2193	struct spclient *spc = arg;
2194	register_t retval[2] = {0, 0};
2195	int nlocks;
2196
2197	/*
2198	 * ok, so, um, our lwp will change in this routine.
2199	 * that's, ahm, um, eh, "interesting".  However, it
2200	 * shouldn't matter too much, since we're shutting down
2201	 * anyway, and this call is most likely following by
2202	 * rumpuser_exit()
2203	 *
2204	 * (strictly speaking, one could shut down the sysproxy
2205	 * service without halting ... but you know what, we'll
2206	 * call it a feature)
2207	 */
2208
2209	rumpkern_unsched(&nlocks, NULL);
2210	lwproc_newlwp(1);
2211
2212	if (spclist[0].spc_fd) {
2213		parsetab[cleanupidx].cleanup(cleanupsa);
2214	}
2215
2216	/*
2217	 * stuff response into the socket, since the rump kernel container
2218	 * is just about to exit
2219	 */
2220	if (spc && spc->spc_syscallreq)
2221		send_syscall_resp(spc, spc->spc_syscallreq, 0, retval);
2222
2223	if (spclist[0].spc_fd) {
2224		shutdown(spclist[0].spc_fd, SHUT_RDWR);
2225		spfini = 1;
2226	}
2227
2228}
2229