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