xref: /netbsd-src/lib/librumpuser/sp_common.c (revision 8774b772cf047ee31624223952c7024c3f15a92d)
1*8774b772Sgson /*      $NetBSD: sp_common.c,v 1.43 2021/12/07 10:39:33 gson Exp $	*/
213e503f1Spooka 
313e503f1Spooka /*
4fd993ea3Spooka  * Copyright (c) 2010, 2011 Antti Kantee.  All Rights Reserved.
513e503f1Spooka  *
613e503f1Spooka  * Redistribution and use in source and binary forms, with or without
713e503f1Spooka  * modification, are permitted provided that the following conditions
813e503f1Spooka  * are met:
913e503f1Spooka  * 1. Redistributions of source code must retain the above copyright
1013e503f1Spooka  *    notice, this list of conditions and the following disclaimer.
1113e503f1Spooka  * 2. Redistributions in binary form must reproduce the above copyright
1213e503f1Spooka  *    notice, this list of conditions and the following disclaimer in the
1313e503f1Spooka  *    documentation and/or other materials provided with the distribution.
1413e503f1Spooka  *
1513e503f1Spooka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
1613e503f1Spooka  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1713e503f1Spooka  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1813e503f1Spooka  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1913e503f1Spooka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2013e503f1Spooka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2113e503f1Spooka  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2213e503f1Spooka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2313e503f1Spooka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2413e503f1Spooka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2513e503f1Spooka  * SUCH DAMAGE.
2613e503f1Spooka  */
2713e503f1Spooka 
2813e503f1Spooka /*
2913e503f1Spooka  * Common client/server sysproxy routines.  #included.
3013e503f1Spooka  */
3113e503f1Spooka 
323b3ffd70Spooka #include "rumpuser_port.h"
3313e503f1Spooka 
3413e503f1Spooka #include <sys/types.h>
3513e503f1Spooka #include <sys/mman.h>
3652f22b2cSpooka #include <sys/queue.h>
3713e503f1Spooka #include <sys/socket.h>
3801eecd68Spooka #include <sys/un.h>
39f67143f6Spooka #include <sys/uio.h>
4013e503f1Spooka 
4113e503f1Spooka #include <arpa/inet.h>
4213e503f1Spooka #include <netinet/in.h>
4313e503f1Spooka #include <netinet/tcp.h>
4413e503f1Spooka 
4513e503f1Spooka #include <assert.h>
4613e503f1Spooka #include <errno.h>
4713e503f1Spooka #include <fcntl.h>
48d402686fSpooka #include <inttypes.h>
493b3ffd70Spooka #include <limits.h>
5013e503f1Spooka #include <poll.h>
5152f22b2cSpooka #include <pthread.h>
5213e503f1Spooka #include <stdarg.h>
536e0e64abSpooka #include <stddef.h>
5413e503f1Spooka #include <stdio.h>
5513e503f1Spooka #include <stdlib.h>
5613e503f1Spooka #include <string.h>
5713e503f1Spooka #include <unistd.h>
5813e503f1Spooka 
593b3ffd70Spooka /*
603b3ffd70Spooka  * XXX: NetBSD's __unused collides with Linux headers, so we cannot
613b3ffd70Spooka  * define it before we've included everything.
623b3ffd70Spooka  */
637bd425ccSdholland #if !defined(__unused) && (defined(__clang__) || defined(__GNUC__))
643b3ffd70Spooka #define __unused __attribute__((__unused__))
653b3ffd70Spooka #endif
667bd425ccSdholland #if !defined(__printflike) && (defined(__clang__) || defined(__GNUC__))
677bd425ccSdholland #define __printflike(a,b) __attribute__((__format__(__printf__, a, b))))
687bd425ccSdholland #endif
693b3ffd70Spooka 
7013e503f1Spooka //#define DEBUG
7113e503f1Spooka #ifdef DEBUG
7213e503f1Spooka #define DPRINTF(x) mydprintf x
737bd425ccSdholland static __printflike(1, 2) void
mydprintf(const char * fmt,...)7413e503f1Spooka mydprintf(const char *fmt, ...)
7513e503f1Spooka {
7613e503f1Spooka 	va_list ap;
7713e503f1Spooka 
7813e503f1Spooka 	va_start(ap, fmt);
7913e503f1Spooka 	vfprintf(stderr, fmt, ap);
8013e503f1Spooka 	va_end(ap);
8113e503f1Spooka }
8213e503f1Spooka #else
8313e503f1Spooka #define DPRINTF(x)
8413e503f1Spooka #endif
8513e503f1Spooka 
8691aad9bdSpooka #ifndef HOSTOPS
8791aad9bdSpooka #define host_poll poll
8891aad9bdSpooka #define host_read read
8900e34b22Spooka #define host_sendmsg sendmsg
9091aad9bdSpooka #define host_setsockopt setsockopt
9191aad9bdSpooka #endif
9291aad9bdSpooka 
9365306217Spooka #define IOVPUT(_io_, _b_) _io_.iov_base = 			\
9465306217Spooka     (void *)&_b_; _io_.iov_len = sizeof(_b_);
9565306217Spooka #define IOVPUT_WITHSIZE(_io_, _b_, _l_) _io_.iov_base =		\
9665306217Spooka     (void *)(_b_); _io_.iov_len = _l_;
9700e34b22Spooka #define SENDIOV(_spc_, _iov_) dosend(_spc_, _iov_, __arraycount(_iov_))
9800e34b22Spooka 
9913e503f1Spooka /*
10013e503f1Spooka  * Bah, I hate writing on-off-wire conversions in C
10113e503f1Spooka  */
10213e503f1Spooka 
103d402686fSpooka enum { RUMPSP_REQ, RUMPSP_RESP, RUMPSP_ERROR };
104393eecc1Spooka enum {	RUMPSP_HANDSHAKE,
105393eecc1Spooka 	RUMPSP_SYSCALL,
1066b71288cSpooka 	RUMPSP_COPYIN, RUMPSP_COPYINSTR,
1076b71288cSpooka 	RUMPSP_COPYOUT, RUMPSP_COPYOUTSTR,
108fd993ea3Spooka 	RUMPSP_ANONMMAP,
1099fba158bSpooka 	RUMPSP_PREFORK,
1109fba158bSpooka 	RUMPSP_RAISE };
11113e503f1Spooka 
1125e301bc4Spooka enum { HANDSHAKE_GUEST, HANDSHAKE_AUTH, HANDSHAKE_FORK, HANDSHAKE_EXEC };
113fd993ea3Spooka 
114bf01f875Spooka /*
115bf01f875Spooka  * error types used for RUMPSP_ERROR
116bf01f875Spooka  */
117bf01f875Spooka enum rumpsp_err { RUMPSP_ERR_NONE = 0, RUMPSP_ERR_TRYAGAIN, RUMPSP_ERR_AUTH,
118bf01f875Spooka 	RUMPSP_ERR_INVALID_PREFORK, RUMPSP_ERR_RFORK_FAILED,
119bf01f875Spooka 	RUMPSP_ERR_INEXEC, RUMPSP_ERR_NOMEM, RUMPSP_ERR_MALFORMED_REQUEST };
120bf01f875Spooka 
121bf01f875Spooka /*
122bf01f875Spooka  * The mapping of the above types to errno.  They are almost never exposed
123bf01f875Spooka  * to the client after handshake (except for a server resource shortage
124bf01f875Spooka  * and the client trying to be funny).  This is a function instead of
125bf01f875Spooka  * an array to catch missing values.  Theoretically, the compiled code
126bf01f875Spooka  * should be the same.
127bf01f875Spooka  */
128bf01f875Spooka static int
errmap(enum rumpsp_err error)129bf01f875Spooka errmap(enum rumpsp_err error)
130bf01f875Spooka {
131bf01f875Spooka 
132bf01f875Spooka 	switch (error) {
133bf01f875Spooka 	/* XXX: no EAUTH on Linux */
134bf01f875Spooka 	case RUMPSP_ERR_NONE:			return 0;
135bf01f875Spooka 	case RUMPSP_ERR_AUTH:			return EPERM;
136bf01f875Spooka 	case RUMPSP_ERR_TRYAGAIN:		return EAGAIN;
137bf01f875Spooka 	case RUMPSP_ERR_INVALID_PREFORK:	return ESRCH;
138bf01f875Spooka 	case RUMPSP_ERR_RFORK_FAILED:		return EIO; /* got a light? */
139bf01f875Spooka 	case RUMPSP_ERR_INEXEC:			return EBUSY;
140bf01f875Spooka 	case RUMPSP_ERR_NOMEM:			return ENOMEM;
141bf01f875Spooka 	case RUMPSP_ERR_MALFORMED_REQUEST:	return EINVAL;
142bf01f875Spooka 	}
143bf01f875Spooka 
144bf01f875Spooka 	return -1;
145bf01f875Spooka }
146bf01f875Spooka 
147fd993ea3Spooka #define AUTHLEN 4 /* 128bit fork auth */
148393eecc1Spooka 
14913e503f1Spooka struct rsp_hdr {
15013e503f1Spooka 	uint64_t rsp_len;
15113e503f1Spooka 	uint64_t rsp_reqno;
15252f22b2cSpooka 	uint16_t rsp_class;
15352f22b2cSpooka 	uint16_t rsp_type;
15413e503f1Spooka 	/*
15513e503f1Spooka 	 * We want this structure 64bit-aligned for typecast fun,
15613e503f1Spooka 	 * so might as well use the following for something.
15713e503f1Spooka 	 */
158d402686fSpooka 	union {
159d402686fSpooka 		uint32_t sysnum;
160d402686fSpooka 		uint32_t error;
161393eecc1Spooka 		uint32_t handshake;
1629fba158bSpooka 		uint32_t signo;
163d402686fSpooka 	} u;
16413e503f1Spooka };
16513e503f1Spooka #define HDRSZ sizeof(struct rsp_hdr)
166d402686fSpooka #define rsp_sysnum u.sysnum
167d402686fSpooka #define rsp_error u.error
168393eecc1Spooka #define rsp_handshake u.handshake
1699fba158bSpooka #define rsp_signo u.signo
17013e503f1Spooka 
1713c4a27f7Spooka #define MAXBANNER 96
1723c4a27f7Spooka 
17313e503f1Spooka /*
17413e503f1Spooka  * Data follows the header.  We have two types of structured data.
17513e503f1Spooka  */
17613e503f1Spooka 
17713e503f1Spooka /* copyin/copyout */
17813e503f1Spooka struct rsp_copydata {
17913e503f1Spooka 	size_t rcp_len;
18013e503f1Spooka 	void *rcp_addr;
18113e503f1Spooka 	uint8_t rcp_data[0];
18213e503f1Spooka };
18313e503f1Spooka 
18413e503f1Spooka /* syscall response */
18513e503f1Spooka struct rsp_sysresp {
18613e503f1Spooka 	int rsys_error;
18713e503f1Spooka 	register_t rsys_retval[2];
18813e503f1Spooka };
18913e503f1Spooka 
190fd993ea3Spooka struct handshake_fork {
191fd993ea3Spooka 	uint32_t rf_auth[4];
192fd993ea3Spooka 	int rf_cancel;
193fd993ea3Spooka };
194fd993ea3Spooka 
19552f22b2cSpooka struct respwait {
19652f22b2cSpooka 	uint64_t rw_reqno;
19752f22b2cSpooka 	void *rw_data;
19852f22b2cSpooka 	size_t rw_dlen;
19955d21df8Spooka 	int rw_done;
200d402686fSpooka 	int rw_error;
20152f22b2cSpooka 
20252f22b2cSpooka 	pthread_cond_t rw_cv;
20352f22b2cSpooka 
20452f22b2cSpooka 	TAILQ_ENTRY(respwait) rw_entries;
20552f22b2cSpooka };
20613e503f1Spooka 
207fd993ea3Spooka struct prefork;
20813e503f1Spooka struct spclient {
20913e503f1Spooka 	int spc_fd;
210adabf684Spooka 	int spc_refcnt;
211393eecc1Spooka 	int spc_state;
212a2b42babSpooka 
2136e0e64abSpooka 	pthread_mutex_t spc_mtx;
2146e0e64abSpooka 	pthread_cond_t spc_cv;
2156e0e64abSpooka 
216a2b42babSpooka 	struct lwp *spc_mainlwp;
217a2b42babSpooka 	pid_t spc_pid;
21813e503f1Spooka 
2196e0e64abSpooka 	TAILQ_HEAD(, respwait) spc_respwait;
2206e0e64abSpooka 
2216e0e64abSpooka 	/* rest of the fields are zeroed upon disconnect */
222f0d58f78Spooka #define SPC_ZEROFF offsetof(struct spclient, spc_pfd)
223adabf684Spooka 	struct pollfd *spc_pfd;
224adabf684Spooka 
22513e503f1Spooka 	struct rsp_hdr spc_hdr;
22613e503f1Spooka 	uint8_t *spc_buf;
22713e503f1Spooka 	size_t spc_off;
22813e503f1Spooka 
22952f22b2cSpooka 	uint64_t spc_nextreq;
2301d9f8678Spooka 	uint64_t spc_syscallreq;
23119a57922Spooka 	uint64_t spc_generation;
23252f22b2cSpooka 	int spc_ostatus, spc_istatus;
23319a57922Spooka 	int spc_reconnecting;
23491240244Spooka 	int spc_inexec;
235fd993ea3Spooka 
236fd993ea3Spooka 	LIST_HEAD(, prefork) spc_pflist;
23713e503f1Spooka };
23852f22b2cSpooka #define SPCSTATUS_FREE 0
23952f22b2cSpooka #define SPCSTATUS_BUSY 1
24052f22b2cSpooka #define SPCSTATUS_WANTED 2
24113e503f1Spooka 
242393eecc1Spooka #define SPCSTATE_NEW     0
243393eecc1Spooka #define SPCSTATE_RUNNING 1
244393eecc1Spooka #define SPCSTATE_DYING   2
245393eecc1Spooka 
24613e503f1Spooka typedef int (*addrparse_fn)(const char *, struct sockaddr **, int);
24713e503f1Spooka typedef int (*connecthook_fn)(int);
24834c82400Spooka typedef void (*cleanup_fn)(struct sockaddr *);
24913e503f1Spooka 
25052f22b2cSpooka static int readframe(struct spclient *);
25152f22b2cSpooka static void handlereq(struct spclient *);
25252f22b2cSpooka 
253d402686fSpooka static __inline void
spcresetbuf(struct spclient * spc)254d402686fSpooka spcresetbuf(struct spclient *spc)
255d402686fSpooka {
256d402686fSpooka 
257d402686fSpooka 	spc->spc_buf = NULL;
258d402686fSpooka 	spc->spc_off = 0;
259d402686fSpooka }
260d402686fSpooka 
261d402686fSpooka static __inline void
spcfreebuf(struct spclient * spc)262d402686fSpooka spcfreebuf(struct spclient *spc)
263d402686fSpooka {
264d402686fSpooka 
265d402686fSpooka 	free(spc->spc_buf);
266d402686fSpooka 	spcresetbuf(spc);
267d402686fSpooka }
268d402686fSpooka 
26952f22b2cSpooka static void
sendlockl(struct spclient * spc)270f0d58f78Spooka sendlockl(struct spclient *spc)
27152f22b2cSpooka {
27252f22b2cSpooka 
27352f22b2cSpooka 	while (spc->spc_ostatus != SPCSTATUS_FREE) {
27452f22b2cSpooka 		spc->spc_ostatus = SPCSTATUS_WANTED;
27552f22b2cSpooka 		pthread_cond_wait(&spc->spc_cv, &spc->spc_mtx);
27652f22b2cSpooka 	}
27752f22b2cSpooka 	spc->spc_ostatus = SPCSTATUS_BUSY;
278f0d58f78Spooka }
279f0d58f78Spooka 
28019a57922Spooka static void __unused
sendlock(struct spclient * spc)281f0d58f78Spooka sendlock(struct spclient *spc)
282f0d58f78Spooka {
283f0d58f78Spooka 
284f0d58f78Spooka 	pthread_mutex_lock(&spc->spc_mtx);
285f0d58f78Spooka 	sendlockl(spc);
28652f22b2cSpooka 	pthread_mutex_unlock(&spc->spc_mtx);
28752f22b2cSpooka }
28852f22b2cSpooka 
28952f22b2cSpooka static void
sendunlockl(struct spclient * spc)290f0d58f78Spooka sendunlockl(struct spclient *spc)
291f0d58f78Spooka {
292f0d58f78Spooka 
293f0d58f78Spooka 	if (spc->spc_ostatus == SPCSTATUS_WANTED)
294f0d58f78Spooka 		pthread_cond_broadcast(&spc->spc_cv);
295f0d58f78Spooka 	spc->spc_ostatus = SPCSTATUS_FREE;
296f0d58f78Spooka }
297f0d58f78Spooka 
298f0d58f78Spooka static void
sendunlock(struct spclient * spc)29952f22b2cSpooka sendunlock(struct spclient *spc)
30052f22b2cSpooka {
30152f22b2cSpooka 
30252f22b2cSpooka 	pthread_mutex_lock(&spc->spc_mtx);
303f0d58f78Spooka 	sendunlockl(spc);
30452f22b2cSpooka 	pthread_mutex_unlock(&spc->spc_mtx);
30552f22b2cSpooka }
30613e503f1Spooka 
30713e503f1Spooka static int
dosend(struct spclient * spc,struct iovec * iov,size_t iovlen)30800e34b22Spooka dosend(struct spclient *spc, struct iovec *iov, size_t iovlen)
30913e503f1Spooka {
31000e34b22Spooka 	struct msghdr msg;
31113e503f1Spooka 	struct pollfd pfd;
31200e34b22Spooka 	ssize_t n = 0;
31313e503f1Spooka 	int fd = spc->spc_fd;
31413e503f1Spooka 
31513e503f1Spooka 	pfd.fd = fd;
31613e503f1Spooka 	pfd.events = POLLOUT;
31713e503f1Spooka 
31800e34b22Spooka 	memset(&msg, 0, sizeof(msg));
31900e34b22Spooka 
32000e34b22Spooka 	for (;;) {
32100e34b22Spooka 		/* not first round?  poll */
32213e503f1Spooka 		if (n) {
32391aad9bdSpooka 			if (host_poll(&pfd, 1, INFTIM) == -1) {
32413e503f1Spooka 				if (errno == EINTR)
32513e503f1Spooka 					continue;
32613e503f1Spooka 				return errno;
32713e503f1Spooka 			}
32813e503f1Spooka 		}
32913e503f1Spooka 
33000e34b22Spooka 		msg.msg_iov = iov;
33100e34b22Spooka 		msg.msg_iovlen = iovlen;
33200e34b22Spooka 		n = host_sendmsg(fd, &msg, MSG_NOSIGNAL);
3336b71288cSpooka 		if (n == -1)  {
33419a57922Spooka 			if (errno == EPIPE)
33519a57922Spooka 				return ENOTCONN;
3366b71288cSpooka 			if (errno != EAGAIN)
337fd993ea3Spooka 				return errno;
3386b71288cSpooka 			continue;
33913e503f1Spooka 		}
34019a57922Spooka 		if (n == 0) {
34119a57922Spooka 			return ENOTCONN;
34219a57922Spooka 		}
34300e34b22Spooka 
34400e34b22Spooka 		/* ok, need to adjust iovec for potential next round */
34505ac20bbSkamil 		while (iovlen && n >= (ssize_t)iov[0].iov_len) {
34600e34b22Spooka 			n -= iov[0].iov_len;
34700e34b22Spooka 			iov++;
34800e34b22Spooka 			iovlen--;
34900e34b22Spooka 		}
35000e34b22Spooka 
35100e34b22Spooka 		if (iovlen == 0) {
35200e34b22Spooka 			_DIAGASSERT(n == 0);
35300e34b22Spooka 			break;
35400e34b22Spooka 		} else {
35565306217Spooka 			iov[0].iov_base =
35665306217Spooka 			    (void *)((uint8_t *)iov[0].iov_base + n);
35700e34b22Spooka 			iov[0].iov_len -= n;
35800e34b22Spooka 		}
35913e503f1Spooka 	}
36013e503f1Spooka 
36113e503f1Spooka 	return 0;
36213e503f1Spooka }
36313e503f1Spooka 
36452f22b2cSpooka static void
doputwait(struct spclient * spc,struct respwait * rw,struct rsp_hdr * rhdr)36519a57922Spooka doputwait(struct spclient *spc, struct respwait *rw, struct rsp_hdr *rhdr)
36652f22b2cSpooka {
36752f22b2cSpooka 
36852f22b2cSpooka 	rw->rw_data = NULL;
36952fffe21Spooka 	rw->rw_dlen = rw->rw_done = rw->rw_error = 0;
37052f22b2cSpooka 	pthread_cond_init(&rw->rw_cv, NULL);
37152f22b2cSpooka 
37252f22b2cSpooka 	pthread_mutex_lock(&spc->spc_mtx);
37352f22b2cSpooka 	rw->rw_reqno = rhdr->rsp_reqno = spc->spc_nextreq++;
37452f22b2cSpooka 	TAILQ_INSERT_TAIL(&spc->spc_respwait, rw, rw_entries);
37519a57922Spooka }
376f0d58f78Spooka 
37719a57922Spooka static void __unused
putwait_locked(struct spclient * spc,struct respwait * rw,struct rsp_hdr * rhdr)37819a57922Spooka putwait_locked(struct spclient *spc, struct respwait *rw, struct rsp_hdr *rhdr)
37919a57922Spooka {
38019a57922Spooka 
38119a57922Spooka 	doputwait(spc, rw, rhdr);
38219a57922Spooka 	pthread_mutex_unlock(&spc->spc_mtx);
38319a57922Spooka }
38419a57922Spooka 
38519a57922Spooka static void
putwait(struct spclient * spc,struct respwait * rw,struct rsp_hdr * rhdr)38619a57922Spooka putwait(struct spclient *spc, struct respwait *rw, struct rsp_hdr *rhdr)
38719a57922Spooka {
38819a57922Spooka 
38919a57922Spooka 	doputwait(spc, rw, rhdr);
390f0d58f78Spooka 	sendlockl(spc);
3915064fa59Spooka 	pthread_mutex_unlock(&spc->spc_mtx);
3920f9bd961Spooka }
3930f9bd961Spooka 
3940f9bd961Spooka static void
dounputwait(struct spclient * spc,struct respwait * rw)39519a57922Spooka dounputwait(struct spclient *spc, struct respwait *rw)
39619a57922Spooka {
39719a57922Spooka 
39819a57922Spooka 	TAILQ_REMOVE(&spc->spc_respwait, rw, rw_entries);
39919a57922Spooka 	pthread_mutex_unlock(&spc->spc_mtx);
40019a57922Spooka 	pthread_cond_destroy(&rw->rw_cv);
40119a57922Spooka 
40219a57922Spooka }
40319a57922Spooka 
40419a57922Spooka static void __unused
unputwait_locked(struct spclient * spc,struct respwait * rw)40519a57922Spooka unputwait_locked(struct spclient *spc, struct respwait *rw)
40619a57922Spooka {
40719a57922Spooka 
40819a57922Spooka 	pthread_mutex_lock(&spc->spc_mtx);
40919a57922Spooka 	dounputwait(spc, rw);
41019a57922Spooka }
41119a57922Spooka 
41219a57922Spooka static void
unputwait(struct spclient * spc,struct respwait * rw)4130f9bd961Spooka unputwait(struct spclient *spc, struct respwait *rw)
4140f9bd961Spooka {
4150f9bd961Spooka 
4165064fa59Spooka 	pthread_mutex_lock(&spc->spc_mtx);
417f0d58f78Spooka 	sendunlockl(spc);
418f0d58f78Spooka 
41919a57922Spooka 	dounputwait(spc, rw);
42052f22b2cSpooka }
42152f22b2cSpooka 
42252f22b2cSpooka static void
kickwaiter(struct spclient * spc)42352f22b2cSpooka kickwaiter(struct spclient *spc)
42452f22b2cSpooka {
42552f22b2cSpooka 	struct respwait *rw;
42652fffe21Spooka 	int error = 0;
42752f22b2cSpooka 
42852f22b2cSpooka 	pthread_mutex_lock(&spc->spc_mtx);
42952f22b2cSpooka 	TAILQ_FOREACH(rw, &spc->spc_respwait, rw_entries) {
43052f22b2cSpooka 		if (rw->rw_reqno == spc->spc_hdr.rsp_reqno)
43152f22b2cSpooka 			break;
43252f22b2cSpooka 	}
43352f22b2cSpooka 	if (rw == NULL) {
434d402686fSpooka 		DPRINTF(("no waiter found, invalid reqno %" PRIu64 "?\n",
435d402686fSpooka 		    spc->spc_hdr.rsp_reqno));
4365064fa59Spooka 		pthread_mutex_unlock(&spc->spc_mtx);
437fd993ea3Spooka 		spcfreebuf(spc);
43852f22b2cSpooka 		return;
43952f22b2cSpooka 	}
4406b71288cSpooka 	DPRINTF(("rump_sp: client %p woke up waiter at %p\n", spc, rw));
44152f22b2cSpooka 	rw->rw_data = spc->spc_buf;
44255d21df8Spooka 	rw->rw_done = 1;
4436e0e64abSpooka 	rw->rw_dlen = (size_t)(spc->spc_off - HDRSZ);
444d402686fSpooka 	if (spc->spc_hdr.rsp_class == RUMPSP_ERROR) {
445bf01f875Spooka 		error = rw->rw_error = errmap(spc->spc_hdr.rsp_error);
446d402686fSpooka 	}
44752f22b2cSpooka 	pthread_cond_signal(&rw->rw_cv);
44852f22b2cSpooka 	pthread_mutex_unlock(&spc->spc_mtx);
44952f22b2cSpooka 
450ff46270eSpooka 	if (error)
451d402686fSpooka 		spcfreebuf(spc);
452d402686fSpooka 	else
453d402686fSpooka 		spcresetbuf(spc);
45452f22b2cSpooka }
45552f22b2cSpooka 
45652f22b2cSpooka static void
kickall(struct spclient * spc)45752f22b2cSpooka kickall(struct spclient *spc)
45852f22b2cSpooka {
45952f22b2cSpooka 	struct respwait *rw;
46052f22b2cSpooka 
46152f22b2cSpooka 	/* DIAGASSERT(mutex_owned(spc_lock)) */
46252f22b2cSpooka 	TAILQ_FOREACH(rw, &spc->spc_respwait, rw_entries)
463f0d58f78Spooka 		pthread_cond_broadcast(&rw->rw_cv);
46452f22b2cSpooka }
46552f22b2cSpooka 
46652f22b2cSpooka static int
readframe(struct spclient * spc)46713e503f1Spooka readframe(struct spclient *spc)
46813e503f1Spooka {
46913e503f1Spooka 	int fd = spc->spc_fd;
47013e503f1Spooka 	size_t left;
47113e503f1Spooka 	size_t framelen;
47213e503f1Spooka 	ssize_t n;
47313e503f1Spooka 
47413e503f1Spooka 	/* still reading header? */
47513e503f1Spooka 	if (spc->spc_off < HDRSZ) {
47613e503f1Spooka 		DPRINTF(("rump_sp: readframe getting header at offset %zu\n",
47713e503f1Spooka 		    spc->spc_off));
47813e503f1Spooka 
47913e503f1Spooka 		left = HDRSZ - spc->spc_off;
48013e503f1Spooka 		/*LINTED: cast ok */
48191aad9bdSpooka 		n = host_read(fd, (uint8_t*)&spc->spc_hdr + spc->spc_off, left);
48213e503f1Spooka 		if (n == 0) {
48313e503f1Spooka 			return -1;
48413e503f1Spooka 		}
48513e503f1Spooka 		if (n == -1) {
48613e503f1Spooka 			if (errno == EAGAIN)
48713e503f1Spooka 				return 0;
48813e503f1Spooka 			return -1;
48913e503f1Spooka 		}
49013e503f1Spooka 
49113e503f1Spooka 		spc->spc_off += n;
49220446f99Spooka 		if (spc->spc_off < HDRSZ) {
49320446f99Spooka 			return 0;
49420446f99Spooka 		}
49513e503f1Spooka 
49613e503f1Spooka 		/*LINTED*/
49713e503f1Spooka 		framelen = spc->spc_hdr.rsp_len;
49813e503f1Spooka 
49913e503f1Spooka 		if (framelen < HDRSZ) {
50013e503f1Spooka 			return -1;
50113e503f1Spooka 		} else if (framelen == HDRSZ) {
50213e503f1Spooka 			return 1;
50313e503f1Spooka 		}
50413e503f1Spooka 
50581f24eb1Schristos 		/* Add an extra byte so that we are always NUL-terminated */
50681f24eb1Schristos 		spc->spc_buf = malloc(framelen - HDRSZ + 1);
50713e503f1Spooka 		if (spc->spc_buf == NULL) {
50813e503f1Spooka 			return -1;
50913e503f1Spooka 		}
51081f24eb1Schristos 		memset(spc->spc_buf, 0, framelen - HDRSZ + 1);
51113e503f1Spooka 
51213e503f1Spooka 		/* "fallthrough" */
51313e503f1Spooka 	} else {
51413e503f1Spooka 		/*LINTED*/
51513e503f1Spooka 		framelen = spc->spc_hdr.rsp_len;
51613e503f1Spooka 	}
51713e503f1Spooka 
51813e503f1Spooka 	left = framelen - spc->spc_off;
51913e503f1Spooka 
52013e503f1Spooka 	DPRINTF(("rump_sp: readframe getting body at offset %zu, left %zu\n",
52113e503f1Spooka 	    spc->spc_off, left));
52213e503f1Spooka 
52313e503f1Spooka 	if (left == 0)
52413e503f1Spooka 		return 1;
52591aad9bdSpooka 	n = host_read(fd, spc->spc_buf + (spc->spc_off - HDRSZ), left);
52613e503f1Spooka 	if (n == 0) {
52713e503f1Spooka 		return -1;
52813e503f1Spooka 	}
52913e503f1Spooka 	if (n == -1) {
53013e503f1Spooka 		if (errno == EAGAIN)
53113e503f1Spooka 			return 0;
53213e503f1Spooka 		return -1;
53313e503f1Spooka 	}
53413e503f1Spooka 	spc->spc_off += n;
53513e503f1Spooka 	left -= n;
53613e503f1Spooka 
53713e503f1Spooka 	/* got everything? */
53813e503f1Spooka 	if (left == 0)
53913e503f1Spooka 		return 1;
54013e503f1Spooka 	else
54113e503f1Spooka 		return 0;
54213e503f1Spooka }
54313e503f1Spooka 
54413e503f1Spooka static int
tcp_parse(const char * addr,struct sockaddr ** sa,int allow_wildcard)54513e503f1Spooka tcp_parse(const char *addr, struct sockaddr **sa, int allow_wildcard)
54613e503f1Spooka {
54713e503f1Spooka 	struct sockaddr_in sin;
54813e503f1Spooka 	char buf[64];
54913e503f1Spooka 	const char *p;
55013e503f1Spooka 	size_t l;
55113e503f1Spooka 	int port;
55213e503f1Spooka 
55313e503f1Spooka 	memset(&sin, 0, sizeof(sin));
5542f567109Spooka 	SIN_SETLEN(sin, sizeof(sin));
55513e503f1Spooka 	sin.sin_family = AF_INET;
55613e503f1Spooka 
55713e503f1Spooka 	p = strchr(addr, ':');
55813e503f1Spooka 	if (!p) {
55913e503f1Spooka 		fprintf(stderr, "rump_sp_tcp: missing port specifier\n");
56013e503f1Spooka 		return EINVAL;
56113e503f1Spooka 	}
56213e503f1Spooka 
56313e503f1Spooka 	l = p - addr;
56413e503f1Spooka 	if (l > sizeof(buf)-1) {
56513e503f1Spooka 		fprintf(stderr, "rump_sp_tcp: address too long\n");
56613e503f1Spooka 		return EINVAL;
56713e503f1Spooka 	}
56813e503f1Spooka 	strncpy(buf, addr, l);
56913e503f1Spooka 	buf[l] = '\0';
57013e503f1Spooka 
57113e503f1Spooka 	/* special INADDR_ANY treatment */
57213e503f1Spooka 	if (strcmp(buf, "*") == 0 || strcmp(buf, "0") == 0) {
57313e503f1Spooka 		sin.sin_addr.s_addr = INADDR_ANY;
57413e503f1Spooka 	} else {
57513e503f1Spooka 		switch (inet_pton(AF_INET, buf, &sin.sin_addr)) {
57613e503f1Spooka 		case 1:
57713e503f1Spooka 			break;
57813e503f1Spooka 		case 0:
57913e503f1Spooka 			fprintf(stderr, "rump_sp_tcp: cannot parse %s\n", buf);
58013e503f1Spooka 			return EINVAL;
58113e503f1Spooka 		case -1:
58213e503f1Spooka 			fprintf(stderr, "rump_sp_tcp: inet_pton failed\n");
58313e503f1Spooka 			return errno;
58413e503f1Spooka 		default:
58513e503f1Spooka 			assert(/*CONSTCOND*/0);
58613e503f1Spooka 			return EINVAL;
58713e503f1Spooka 		}
58813e503f1Spooka 	}
58913e503f1Spooka 
59013e503f1Spooka 	if (!allow_wildcard && sin.sin_addr.s_addr == INADDR_ANY) {
59113e503f1Spooka 		fprintf(stderr, "rump_sp_tcp: client needs !INADDR_ANY\n");
59213e503f1Spooka 		return EINVAL;
59313e503f1Spooka 	}
59413e503f1Spooka 
59513e503f1Spooka 	/* advance to port number & parse */
59613e503f1Spooka 	p++;
59713e503f1Spooka 	l = strspn(p, "0123456789");
59813e503f1Spooka 	if (l == 0) {
59913e503f1Spooka 		fprintf(stderr, "rump_sp_tcp: port now found: %s\n", p);
60013e503f1Spooka 		return EINVAL;
60113e503f1Spooka 	}
60213e503f1Spooka 	strncpy(buf, p, l);
60313e503f1Spooka 	buf[l] = '\0';
60413e503f1Spooka 
60513e503f1Spooka 	if (*(p+l) != '/' && *(p+l) != '\0') {
60613e503f1Spooka 		fprintf(stderr, "rump_sp_tcp: junk at end of port: %s\n", addr);
60713e503f1Spooka 		return EINVAL;
60813e503f1Spooka 	}
60913e503f1Spooka 
61013e503f1Spooka 	port = atoi(buf);
61113e503f1Spooka 	if (port < 0 || port >= (1<<(8*sizeof(in_port_t)))) {
61213e503f1Spooka 		fprintf(stderr, "rump_sp_tcp: port %d out of range\n", port);
61313e503f1Spooka 		return ERANGE;
61413e503f1Spooka 	}
61513e503f1Spooka 	sin.sin_port = htons(port);
61613e503f1Spooka 
61713e503f1Spooka 	*sa = malloc(sizeof(sin));
61813e503f1Spooka 	if (*sa == NULL)
61913e503f1Spooka 		return errno;
62013e503f1Spooka 	memcpy(*sa, &sin, sizeof(sin));
62113e503f1Spooka 	return 0;
62213e503f1Spooka }
62313e503f1Spooka 
62413e503f1Spooka static int
tcp_connecthook(int s)62513e503f1Spooka tcp_connecthook(int s)
62613e503f1Spooka {
62713e503f1Spooka 	int x;
62813e503f1Spooka 
62913e503f1Spooka 	x = 1;
63091aad9bdSpooka 	host_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &x, sizeof(x));
63113e503f1Spooka 
63213e503f1Spooka 	return 0;
63313e503f1Spooka }
63413e503f1Spooka 
6352ba7fe55Spooka static char parsedurl[256];
6362ba7fe55Spooka 
637b82590c0Spooka /*ARGSUSED*/
63801eecd68Spooka static int
unix_parse(const char * addr,struct sockaddr ** sa,int allow_wildcard)63901eecd68Spooka unix_parse(const char *addr, struct sockaddr **sa, int allow_wildcard)
64001eecd68Spooka {
64165306217Spooka 	struct sockaddr_un s_un;
642b82590c0Spooka 	size_t slen;
6432ba7fe55Spooka 	int savepath = 0;
64401eecd68Spooka 
64565306217Spooka 	if (strlen(addr) >= sizeof(s_un.sun_path))
64601eecd68Spooka 		return ENAMETOOLONG;
64701eecd68Spooka 
64801eecd68Spooka 	/*
64901eecd68Spooka 	 * The pathname can be all kinds of spaghetti elementals,
65034c82400Spooka 	 * so meek and obidient we accept everything.  However, use
65134c82400Spooka 	 * full path for easy cleanup in case someone gives a relative
65234c82400Spooka 	 * one and the server does a chdir() between now than the
65334c82400Spooka 	 * cleanup.
65401eecd68Spooka 	 */
65565306217Spooka 	memset(&s_un, 0, sizeof(s_un));
65665306217Spooka 	s_un.sun_family = AF_LOCAL;
65734c82400Spooka 	if (*addr != '/') {
65834c82400Spooka 		char mywd[PATH_MAX];
65934c82400Spooka 
66034c82400Spooka 		if (getcwd(mywd, sizeof(mywd)) == NULL) {
66134c82400Spooka 			fprintf(stderr, "warning: cannot determine cwd, "
66234c82400Spooka 			    "omitting socket cleanup\n");
66334c82400Spooka 		} else {
66465306217Spooka 			if (strlen(addr)+strlen(mywd)+1
66565306217Spooka 			    >= sizeof(s_un.sun_path))
66634c82400Spooka 				return ENAMETOOLONG;
66765306217Spooka 			strcpy(s_un.sun_path, mywd);
66865306217Spooka 			strcat(s_un.sun_path, "/");
6692ba7fe55Spooka 			savepath = 1;
67034c82400Spooka 		}
67134c82400Spooka 	}
67265306217Spooka 	strcat(s_un.sun_path, addr);
673*8774b772Sgson #if !(defined(__linux__) || defined(__sun__) || defined(__CYGWIN__))
67465306217Spooka 	s_un.sun_len = SUN_LEN(&s_un);
6753b3ffd70Spooka #endif
676*8774b772Sgson 	slen = sizeof(s_un);
67701eecd68Spooka 
6782ba7fe55Spooka 	if (savepath && *parsedurl == '\0') {
6792ba7fe55Spooka 		snprintf(parsedurl, sizeof(parsedurl),
68065306217Spooka 		    "unix://%s", s_un.sun_path);
6812ba7fe55Spooka 	}
6822ba7fe55Spooka 
683b82590c0Spooka 	*sa = malloc(slen);
68401eecd68Spooka 	if (*sa == NULL)
68501eecd68Spooka 		return errno;
68665306217Spooka 	memcpy(*sa, &s_un, slen);
68701eecd68Spooka 
68801eecd68Spooka 	return 0;
68901eecd68Spooka }
69001eecd68Spooka 
69134c82400Spooka static void
unix_cleanup(struct sockaddr * sa)69234c82400Spooka unix_cleanup(struct sockaddr *sa)
69334c82400Spooka {
69465306217Spooka 	struct sockaddr_un *s_sun = (void *)sa;
69534c82400Spooka 
69634c82400Spooka 	/*
69734c82400Spooka 	 * cleanup only absolute paths.  see unix_parse() above
69834c82400Spooka 	 */
69965306217Spooka 	if (*s_sun->sun_path == '/') {
70065306217Spooka 		unlink(s_sun->sun_path);
70134c82400Spooka 	}
70234c82400Spooka }
70334c82400Spooka 
70413e503f1Spooka /*ARGSUSED*/
70513e503f1Spooka static int
addrparse_notsupp(const char * addr __unused,struct sockaddr ** sa __unused,int allow_wildcard __unused)706d8442aacSkamil addrparse_notsupp(const char *addr __unused, struct sockaddr **sa __unused,
707d8442aacSkamil 		  int allow_wildcard __unused)
70813e503f1Spooka {
70913e503f1Spooka 
71013e503f1Spooka 	fprintf(stderr, "rump_sp: support not yet implemented\n");
71113e503f1Spooka 	return EOPNOTSUPP;
71213e503f1Spooka }
71313e503f1Spooka 
714d8442aacSkamil static void
cleanup_success(struct sockaddr * sa __unused)715d8442aacSkamil cleanup_success(struct sockaddr *sa __unused)
716d8442aacSkamil {
717d8442aacSkamil }
718d8442aacSkamil 
71913e503f1Spooka static int
connecthook_success(int s __unused)720d8442aacSkamil connecthook_success(int s __unused)
72113e503f1Spooka {
72213e503f1Spooka 
72313e503f1Spooka 	return 0;
72413e503f1Spooka }
72513e503f1Spooka 
72655ffc864Spooka static struct {
72713e503f1Spooka 	const char *id;
72813e503f1Spooka 	int domain;
7293b3ffd70Spooka 	socklen_t slen;
73013e503f1Spooka 	addrparse_fn ap;
73113e503f1Spooka 	connecthook_fn connhook;
73234c82400Spooka 	cleanup_fn cleanup;
73313e503f1Spooka } parsetab[] = {
7343b3ffd70Spooka 	{ "tcp", PF_INET, sizeof(struct sockaddr_in),
735d8442aacSkamil 	    tcp_parse, tcp_connecthook, cleanup_success },
7363b3ffd70Spooka 	{ "unix", PF_LOCAL, sizeof(struct sockaddr_un),
737d8442aacSkamil 	    unix_parse, connecthook_success, unix_cleanup },
7383b3ffd70Spooka 	{ "tcp6", PF_INET6, sizeof(struct sockaddr_in6),
739d8442aacSkamil 	    addrparse_notsupp, connecthook_success,
740d8442aacSkamil 	    cleanup_success },
74113e503f1Spooka };
74213e503f1Spooka #define NPARSE (sizeof(parsetab)/sizeof(parsetab[0]))
74313e503f1Spooka 
74413e503f1Spooka static int
parseurl(const char * url,struct sockaddr ** sap,unsigned * idxp,int allow_wildcard)74513e503f1Spooka parseurl(const char *url, struct sockaddr **sap, unsigned *idxp,
74613e503f1Spooka 	int allow_wildcard)
74713e503f1Spooka {
74813e503f1Spooka 	char id[16];
74913e503f1Spooka 	const char *p, *p2;
75013e503f1Spooka 	size_t l;
75113e503f1Spooka 	unsigned i;
75213e503f1Spooka 	int error;
75313e503f1Spooka 
75413e503f1Spooka 	/*
75513e503f1Spooka 	 * Parse the url
75613e503f1Spooka 	 */
75713e503f1Spooka 
75813e503f1Spooka 	p = url;
75913e503f1Spooka 	p2 = strstr(p, "://");
76013e503f1Spooka 	if (!p2) {
76113e503f1Spooka 		fprintf(stderr, "rump_sp: invalid locator ``%s''\n", p);
76213e503f1Spooka 		return EINVAL;
76313e503f1Spooka 	}
76413e503f1Spooka 	l = p2-p;
76513e503f1Spooka 	if (l > sizeof(id)-1) {
76613e503f1Spooka 		fprintf(stderr, "rump_sp: identifier too long in ``%s''\n", p);
76713e503f1Spooka 		return EINVAL;
76813e503f1Spooka 	}
76913e503f1Spooka 
77013e503f1Spooka 	strncpy(id, p, l);
77113e503f1Spooka 	id[l] = '\0';
77213e503f1Spooka 	p2 += 3; /* beginning of address */
77313e503f1Spooka 
77413e503f1Spooka 	for (i = 0; i < NPARSE; i++) {
77513e503f1Spooka 		if (strcmp(id, parsetab[i].id) == 0) {
77613e503f1Spooka 			error = parsetab[i].ap(p2, sap, allow_wildcard);
77713e503f1Spooka 			if (error)
77813e503f1Spooka 				return error;
77913e503f1Spooka 			break;
78013e503f1Spooka 		}
78113e503f1Spooka 	}
78213e503f1Spooka 	if (i == NPARSE) {
78313e503f1Spooka 		fprintf(stderr, "rump_sp: invalid identifier ``%s''\n", p);
78413e503f1Spooka 		return EINVAL;
78513e503f1Spooka 	}
78613e503f1Spooka 
78713e503f1Spooka 	*idxp = i;
78813e503f1Spooka 	return 0;
78913e503f1Spooka }
790