Home | History | Annotate | Line # | Download | only in librumpclient
rumpclient.c revision 1.64
      1  1.64  justin /*      $NetBSD: rumpclient.c,v 1.64 2014/12/13 17:18:55 justin Exp $	*/
      2   1.1   pooka 
      3   1.1   pooka /*
      4  1.11   pooka  * Copyright (c) 2010, 2011 Antti Kantee.  All Rights Reserved.
      5   1.1   pooka  *
      6   1.1   pooka  * Redistribution and use in source and binary forms, with or without
      7   1.1   pooka  * modification, are permitted provided that the following conditions
      8   1.1   pooka  * are met:
      9   1.1   pooka  * 1. Redistributions of source code must retain the above copyright
     10   1.1   pooka  *    notice, this list of conditions and the following disclaimer.
     11   1.1   pooka  * 2. Redistributions in binary form must reproduce the above copyright
     12   1.1   pooka  *    notice, this list of conditions and the following disclaimer in the
     13   1.1   pooka  *    documentation and/or other materials provided with the distribution.
     14   1.1   pooka  *
     15   1.1   pooka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     16   1.1   pooka  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     17   1.1   pooka  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     18   1.1   pooka  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19   1.1   pooka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20   1.1   pooka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     21   1.1   pooka  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22   1.1   pooka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23   1.1   pooka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24   1.1   pooka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25   1.1   pooka  * SUCH DAMAGE.
     26   1.1   pooka  */
     27   1.1   pooka 
     28   1.1   pooka /*
     29   1.1   pooka  * Client side routines for rump syscall proxy.
     30   1.1   pooka  */
     31   1.1   pooka 
     32  1.55   pooka #include <rump/rumpuser_port.h>
     33  1.49   pooka 
     34  1.49   pooka /*
     35  1.64  justin  * We use kqueue on the BSDs, poll elsewhere.  We
     36  1.49   pooka  * want to use kqueue because it will give us the ability to get signal
     37  1.49   pooka  * notifications but defer their handling to a stage where we do not
     38  1.49   pooka  * hold the communication lock.  Taking a signal while holding on to
     39  1.49   pooka  * that lock may cause a deadlock.  Therefore, block signals throughout
     40  1.58   pooka  * the RPC when using poll.  On Linux, we use signalfd in the same role
     41  1.58   pooka  * as kqueue on NetBSD to be able to take signals while waiting for a
     42  1.58   pooka  * response from the server.
     43  1.49   pooka  */
     44  1.49   pooka 
     45  1.64  justin #if defined(__NetBSD__) || defined(__FreeBSD__) || \
     46  1.64  justin     defined(__DragonFly__) || defined(__OpenBSD__)
     47  1.49   pooka #define USE_KQUEUE
     48  1.49   pooka #endif
     49  1.60  justin #if defined(__linux__) && !defined(__ANDROID__)
     50  1.58   pooka #define USE_SIGNALFD
     51  1.58   pooka #endif
     52  1.49   pooka 
     53  1.64  justin __RCSID("$NetBSD: rumpclient.c,v 1.64 2014/12/13 17:18:55 justin Exp $");
     54   1.1   pooka 
     55   1.5   pooka #include <sys/param.h>
     56   1.1   pooka #include <sys/mman.h>
     57   1.1   pooka #include <sys/socket.h>
     58  1.49   pooka #include <sys/time.h>
     59  1.49   pooka 
     60  1.49   pooka #ifdef USE_KQUEUE
     61  1.49   pooka #include <sys/event.h>
     62  1.49   pooka #endif
     63   1.1   pooka 
     64   1.1   pooka #include <arpa/inet.h>
     65   1.1   pooka #include <netinet/in.h>
     66   1.1   pooka #include <netinet/tcp.h>
     67   1.1   pooka 
     68   1.1   pooka #include <assert.h>
     69  1.13   pooka #include <dlfcn.h>
     70   1.1   pooka #include <errno.h>
     71   1.1   pooka #include <fcntl.h>
     72   1.1   pooka #include <poll.h>
     73   1.1   pooka #include <pthread.h>
     74  1.11   pooka #include <signal.h>
     75   1.1   pooka #include <stdarg.h>
     76  1.18   pooka #include <stdbool.h>
     77   1.1   pooka #include <stdio.h>
     78   1.1   pooka #include <stdlib.h>
     79   1.1   pooka #include <string.h>
     80   1.1   pooka #include <unistd.h>
     81   1.1   pooka 
     82   1.1   pooka #include <rump/rumpclient.h>
     83   1.1   pooka 
     84  1.13   pooka #define HOSTOPS
     85  1.13   pooka int	(*host_socket)(int, int, int);
     86  1.13   pooka int	(*host_close)(int);
     87  1.13   pooka int	(*host_connect)(int, const struct sockaddr *, socklen_t);
     88  1.15   pooka int	(*host_fcntl)(int, int, ...);
     89  1.60  justin #ifdef __ANDROID__
     90  1.60  justin int	(*host_poll)(struct pollfd *, nfds_t, long);
     91  1.60  justin #else
     92  1.13   pooka int	(*host_poll)(struct pollfd *, nfds_t, int);
     93  1.60  justin #endif
     94  1.13   pooka ssize_t	(*host_read)(int, void *, size_t);
     95  1.60  justin #ifdef __ANDROID__
     96  1.60  justin int	(*host_sendmsg)(int, const struct msghdr *, unsigned int);
     97  1.60  justin #else
     98  1.39   pooka ssize_t (*host_sendmsg)(int, const struct msghdr *, int);
     99  1.60  justin #endif
    100  1.13   pooka int	(*host_setsockopt)(int, int, int, const void *, socklen_t);
    101  1.27   pooka int	(*host_dup)(int);
    102  1.13   pooka 
    103  1.49   pooka #ifdef USE_KQUEUE
    104  1.17   pooka int	(*host_kqueue)(void);
    105  1.63  justin #ifdef __NetBSD__
    106  1.17   pooka int	(*host_kevent)(int, const struct kevent *, size_t,
    107  1.17   pooka 		       struct kevent *, size_t, const struct timespec *);
    108  1.63  justin #else
    109  1.63  justin int	(*host_kevent)(int, const struct kevent *, int,
    110  1.63  justin 		       struct kevent *, int, const struct timespec *);
    111  1.63  justin #endif
    112  1.49   pooka #endif
    113  1.17   pooka 
    114  1.58   pooka #ifdef USE_SIGNALFD
    115  1.58   pooka #include <sys/signalfd.h>
    116  1.58   pooka 
    117  1.58   pooka int	(*host_signalfd)(int, const sigset_t *, int);
    118  1.58   pooka #endif
    119  1.58   pooka 
    120  1.30   pooka int	(*host_execve)(const char *, char *const[], char *const[]);
    121  1.30   pooka 
    122   1.1   pooka #include "sp_common.c"
    123  1.56   pooka #include "rumpuser_sigtrans.c"
    124   1.1   pooka 
    125  1.11   pooka static struct spclient clispc = {
    126  1.11   pooka 	.spc_fd = -1,
    127  1.11   pooka };
    128   1.1   pooka 
    129  1.61   pooka static int holyfd = -1;
    130  1.15   pooka static sigset_t fullset;
    131  1.12   pooka 
    132  1.44   pooka static int doconnect(void);
    133  1.29   pooka static int handshake_req(struct spclient *, int, void *, int, bool);
    134  1.18   pooka 
    135  1.32   pooka /*
    136  1.32   pooka  * Default: don't retry.  Most clients can't handle it
    137  1.32   pooka  * (consider e.g. fds suddenly going missing).
    138  1.32   pooka  */
    139  1.32   pooka static time_t retrytimo = 0;
    140  1.18   pooka 
    141  1.44   pooka /* always defined to nothingness for now */
    142  1.44   pooka #define ERRLOG(a)
    143  1.44   pooka 
    144  1.18   pooka static int
    145  1.39   pooka send_with_recon(struct spclient *spc, struct iovec *iov, size_t iovlen)
    146  1.18   pooka {
    147  1.20   pooka 	struct timeval starttime, curtime;
    148  1.20   pooka 	time_t prevreconmsg;
    149  1.20   pooka 	unsigned reconretries;
    150  1.18   pooka 	int rv;
    151  1.18   pooka 
    152  1.20   pooka 	for (prevreconmsg = 0, reconretries = 0;;) {
    153  1.39   pooka 		rv = dosend(spc, iov, iovlen);
    154  1.18   pooka 		if (__predict_false(rv == ENOTCONN || rv == EBADF)) {
    155  1.20   pooka 			/* no persistent connections */
    156  1.32   pooka 			if (retrytimo == 0) {
    157  1.32   pooka 				rv = ENOTCONN;
    158  1.20   pooka 				break;
    159  1.32   pooka 			}
    160  1.24   pooka 			if (retrytimo == RUMPCLIENT_RETRYCONN_DIE)
    161  1.43   pooka 				_exit(1);
    162  1.20   pooka 
    163  1.20   pooka 			if (!prevreconmsg) {
    164  1.20   pooka 				prevreconmsg = time(NULL);
    165  1.20   pooka 				gettimeofday(&starttime, NULL);
    166  1.20   pooka 			}
    167  1.20   pooka 			if (reconretries == 1) {
    168  1.20   pooka 				if (retrytimo == RUMPCLIENT_RETRYCONN_ONCE) {
    169  1.20   pooka 					rv = ENOTCONN;
    170  1.20   pooka 					break;
    171  1.20   pooka 				}
    172  1.20   pooka 				fprintf(stderr, "rump_sp: connection to "
    173  1.20   pooka 				    "kernel lost, trying to reconnect ...\n");
    174  1.20   pooka 			} else if (time(NULL) - prevreconmsg > 120) {
    175  1.20   pooka 				fprintf(stderr, "rump_sp: still trying to "
    176  1.20   pooka 				    "reconnect ...\n");
    177  1.20   pooka 				prevreconmsg = time(NULL);
    178  1.20   pooka 			}
    179  1.20   pooka 
    180  1.20   pooka 			/* check that we aren't over the limit */
    181  1.20   pooka 			if (retrytimo > 0) {
    182  1.54   pooka 				time_t tdiff;
    183  1.20   pooka 
    184  1.20   pooka 				gettimeofday(&curtime, NULL);
    185  1.54   pooka 				tdiff = curtime.tv_sec - starttime.tv_sec;
    186  1.54   pooka 				if (starttime.tv_usec > curtime.tv_usec)
    187  1.54   pooka 					tdiff--;
    188  1.54   pooka 				if (tdiff >= retrytimo) {
    189  1.20   pooka 					fprintf(stderr, "rump_sp: reconnect "
    190  1.20   pooka 					    "failed, %lld second timeout\n",
    191  1.20   pooka 					    (long long)retrytimo);
    192  1.20   pooka 					return ENOTCONN;
    193  1.20   pooka 				}
    194  1.20   pooka 			}
    195  1.20   pooka 
    196  1.20   pooka 			/* adhoc backoff timer */
    197  1.20   pooka 			if (reconretries < 10) {
    198  1.20   pooka 				usleep(100000 * reconretries);
    199  1.20   pooka 			} else {
    200  1.20   pooka 				sleep(MIN(10, reconretries-9));
    201  1.20   pooka 			}
    202  1.20   pooka 			reconretries++;
    203  1.20   pooka 
    204  1.44   pooka 			if ((rv = doconnect()) != 0)
    205  1.18   pooka 				continue;
    206  1.29   pooka 			if ((rv = handshake_req(&clispc, HANDSHAKE_GUEST,
    207  1.29   pooka 			    NULL, 0, true)) != 0)
    208  1.18   pooka 				continue;
    209  1.20   pooka 
    210  1.20   pooka 			/*
    211  1.20   pooka 			 * ok, reconnect succesful.  we need to return to
    212  1.20   pooka 			 * the upper layer to get the entire PDU resent.
    213  1.20   pooka 			 */
    214  1.20   pooka 			if (reconretries != 1)
    215  1.20   pooka 				fprintf(stderr, "rump_sp: reconnected!\n");
    216  1.20   pooka 			rv = EAGAIN;
    217  1.20   pooka 			break;
    218  1.20   pooka 		} else {
    219  1.20   pooka 			_DIAGASSERT(errno != EAGAIN);
    220  1.18   pooka 			break;
    221  1.18   pooka 		}
    222  1.20   pooka 	}
    223  1.18   pooka 
    224  1.18   pooka 	return rv;
    225  1.18   pooka }
    226  1.18   pooka 
    227  1.12   pooka static int
    228  1.18   pooka cliwaitresp(struct spclient *spc, struct respwait *rw, sigset_t *mask,
    229  1.18   pooka 	bool keeplock)
    230  1.12   pooka {
    231  1.18   pooka 	uint64_t mygen;
    232  1.18   pooka 	bool imalive = true;
    233  1.12   pooka 
    234  1.15   pooka 	pthread_mutex_lock(&spc->spc_mtx);
    235  1.18   pooka 	if (!keeplock)
    236  1.18   pooka 		sendunlockl(spc);
    237  1.18   pooka 	mygen = spc->spc_generation;
    238  1.12   pooka 
    239  1.12   pooka 	rw->rw_error = 0;
    240  1.18   pooka 	while (!rw->rw_done && rw->rw_error == 0) {
    241  1.18   pooka 		if (__predict_false(spc->spc_generation != mygen || !imalive))
    242  1.18   pooka 			break;
    243  1.18   pooka 
    244  1.12   pooka 		/* are we free to receive? */
    245  1.12   pooka 		if (spc->spc_istatus == SPCSTATUS_FREE) {
    246  1.49   pooka 			int gotresp, dosig, rv;
    247  1.15   pooka 
    248  1.12   pooka 			spc->spc_istatus = SPCSTATUS_BUSY;
    249  1.12   pooka 			pthread_mutex_unlock(&spc->spc_mtx);
    250  1.12   pooka 
    251  1.15   pooka 			dosig = 0;
    252  1.15   pooka 			for (gotresp = 0; !gotresp; ) {
    253  1.49   pooka #ifdef USE_KQUEUE
    254  1.49   pooka 				struct kevent kev[8];
    255  1.49   pooka 				int i;
    256  1.49   pooka 
    257  1.40   pooka 				/*
    258  1.40   pooka 				 * typically we don't have a frame waiting
    259  1.40   pooka 				 * when we come in here, so call kevent now
    260  1.40   pooka 				 */
    261  1.58   pooka 				rv = host_kevent(holyfd, NULL, 0,
    262  1.40   pooka 				    kev, __arraycount(kev), NULL);
    263  1.40   pooka 
    264  1.40   pooka 				if (__predict_false(rv == -1)) {
    265  1.40   pooka 					goto activity;
    266  1.40   pooka 				}
    267  1.40   pooka 
    268  1.40   pooka 				/*
    269  1.40   pooka 				 * XXX: don't know how this can happen
    270  1.40   pooka 				 * (timeout cannot expire since there
    271  1.40   pooka 				 * isn't one), but it does happen.
    272  1.40   pooka 				 * treat it as an expectional condition
    273  1.40   pooka 				 * and go through tryread to determine
    274  1.40   pooka 				 * alive status.
    275  1.40   pooka 				 */
    276  1.40   pooka 				if (__predict_false(rv == 0))
    277  1.40   pooka 					goto activity;
    278  1.40   pooka 
    279  1.40   pooka 				for (i = 0; i < rv; i++) {
    280  1.40   pooka 					if (kev[i].filter == EVFILT_SIGNAL)
    281  1.40   pooka 						dosig++;
    282  1.40   pooka 				}
    283  1.40   pooka 				if (dosig)
    284  1.40   pooka 					goto cleanup;
    285  1.40   pooka 
    286  1.40   pooka 				/*
    287  1.40   pooka 				 * ok, activity.  try to read a frame to
    288  1.40   pooka 				 * determine what happens next.
    289  1.40   pooka 				 */
    290  1.40   pooka  activity:
    291  1.58   pooka #else /* !USE_KQUEUE */
    292  1.58   pooka 				struct pollfd pfd[2];
    293  1.49   pooka 
    294  1.58   pooka 				pfd[0].fd = clispc.spc_fd;
    295  1.58   pooka 				pfd[0].events = POLLIN;
    296  1.58   pooka 				pfd[1].fd = holyfd;
    297  1.58   pooka 				pfd[1].events = POLLIN;
    298  1.58   pooka 
    299  1.58   pooka 				rv = host_poll(pfd, 2, -1);
    300  1.62   pooka 				if (rv >= 1 && pfd[1].revents & POLLIN) {
    301  1.58   pooka 					dosig = 1;
    302  1.58   pooka 					goto cleanup;
    303  1.58   pooka 				}
    304  1.49   pooka #endif /* !USE_KQUEUE */
    305  1.49   pooka 
    306  1.15   pooka 				switch (readframe(spc)) {
    307  1.15   pooka 				case 0:
    308  1.15   pooka 					continue;
    309  1.15   pooka 				case -1:
    310  1.18   pooka 					imalive = false;
    311  1.15   pooka 					goto cleanup;
    312  1.15   pooka 				default:
    313  1.40   pooka 					/* case 1 */
    314  1.15   pooka 					break;
    315  1.15   pooka 				}
    316  1.12   pooka 
    317  1.15   pooka 				switch (spc->spc_hdr.rsp_class) {
    318  1.12   pooka 				case RUMPSP_RESP:
    319  1.12   pooka 				case RUMPSP_ERROR:
    320  1.12   pooka 					kickwaiter(spc);
    321  1.15   pooka 					gotresp = spc->spc_hdr.rsp_reqno ==
    322  1.15   pooka 					    rw->rw_reqno;
    323  1.12   pooka 					break;
    324  1.12   pooka 				case RUMPSP_REQ:
    325  1.12   pooka 					handlereq(spc);
    326  1.12   pooka 					break;
    327  1.12   pooka 				default:
    328  1.12   pooka 					/* panic */
    329  1.12   pooka 					break;
    330  1.15   pooka 				}
    331  1.12   pooka 			}
    332  1.12   pooka 
    333  1.15   pooka  cleanup:
    334  1.15   pooka 			pthread_mutex_lock(&spc->spc_mtx);
    335  1.15   pooka 			if (spc->spc_istatus == SPCSTATUS_WANTED)
    336  1.15   pooka 				kickall(spc);
    337  1.15   pooka 			spc->spc_istatus = SPCSTATUS_FREE;
    338  1.15   pooka 
    339  1.15   pooka 			/* take one for the team */
    340  1.15   pooka 			if (dosig) {
    341  1.15   pooka 				pthread_mutex_unlock(&spc->spc_mtx);
    342  1.15   pooka 				pthread_sigmask(SIG_SETMASK, mask, NULL);
    343  1.15   pooka 				pthread_sigmask(SIG_SETMASK, &fullset, NULL);
    344  1.15   pooka 				pthread_mutex_lock(&spc->spc_mtx);
    345  1.15   pooka 			}
    346  1.12   pooka 		} else {
    347  1.12   pooka 			spc->spc_istatus = SPCSTATUS_WANTED;
    348  1.12   pooka 			pthread_cond_wait(&rw->rw_cv, &spc->spc_mtx);
    349  1.12   pooka 		}
    350  1.12   pooka 	}
    351  1.12   pooka 	TAILQ_REMOVE(&spc->spc_respwait, rw, rw_entries);
    352  1.12   pooka 	pthread_mutex_unlock(&spc->spc_mtx);
    353  1.12   pooka 	pthread_cond_destroy(&rw->rw_cv);
    354  1.12   pooka 
    355  1.18   pooka 	if (spc->spc_generation != mygen || !imalive) {
    356  1.12   pooka 		return ENOTCONN;
    357  1.18   pooka 	}
    358  1.12   pooka 	return rw->rw_error;
    359  1.12   pooka }
    360  1.12   pooka 
    361   1.1   pooka static int
    362  1.26   pooka syscall_req(struct spclient *spc, sigset_t *omask, int sysnum,
    363   1.3   pooka 	const void *data, size_t dlen, void **resp)
    364   1.1   pooka {
    365   1.1   pooka 	struct rsp_hdr rhdr;
    366   1.3   pooka 	struct respwait rw;
    367  1.39   pooka 	struct iovec iov[2];
    368   1.3   pooka 	int rv;
    369   1.1   pooka 
    370   1.1   pooka 	rhdr.rsp_len = sizeof(rhdr) + dlen;
    371   1.3   pooka 	rhdr.rsp_class = RUMPSP_REQ;
    372   1.3   pooka 	rhdr.rsp_type = RUMPSP_SYSCALL;
    373   1.1   pooka 	rhdr.rsp_sysnum = sysnum;
    374   1.1   pooka 
    375  1.39   pooka 	IOVPUT(iov[0], rhdr);
    376  1.39   pooka 	IOVPUT_WITHSIZE(iov[1], __UNCONST(data), dlen);
    377  1.39   pooka 
    378   1.6   pooka 	do {
    379   1.6   pooka 		putwait(spc, &rw, &rhdr);
    380  1.39   pooka 		if ((rv = send_with_recon(spc, iov, __arraycount(iov))) != 0) {
    381   1.6   pooka 			unputwait(spc, &rw);
    382  1.18   pooka 			continue;
    383   1.6   pooka 		}
    384   1.6   pooka 
    385  1.26   pooka 		rv = cliwaitresp(spc, &rw, omask, false);
    386  1.20   pooka 		if (rv == ENOTCONN)
    387  1.20   pooka 			rv = EAGAIN;
    388  1.20   pooka 	} while (rv == EAGAIN);
    389   1.3   pooka 
    390   1.3   pooka 	*resp = rw.rw_data;
    391   1.3   pooka 	return rv;
    392   1.1   pooka }
    393   1.1   pooka 
    394   1.1   pooka static int
    395  1.29   pooka handshake_req(struct spclient *spc, int type, void *data,
    396  1.29   pooka 	int cancel, bool haslock)
    397  1.10   pooka {
    398  1.11   pooka 	struct handshake_fork rf;
    399  1.43   pooka 	const char *myprogname = NULL; /* XXXgcc */
    400  1.10   pooka 	struct rsp_hdr rhdr;
    401  1.10   pooka 	struct respwait rw;
    402  1.12   pooka 	sigset_t omask;
    403  1.21   pooka 	size_t bonus;
    404  1.39   pooka 	struct iovec iov[2];
    405  1.10   pooka 	int rv;
    406  1.10   pooka 
    407  1.29   pooka 	if (type == HANDSHAKE_FORK) {
    408  1.21   pooka 		bonus = sizeof(rf);
    409  1.21   pooka 	} else {
    410  1.49   pooka #ifdef __NetBSD__
    411  1.49   pooka 		/* would procfs work on NetBSD too? */
    412  1.39   pooka 		myprogname = getprogname();
    413  1.49   pooka #else
    414  1.49   pooka 		int fd = open("/proc/self/comm", O_RDONLY);
    415  1.49   pooka 		if (fd == -1) {
    416  1.49   pooka 			myprogname = "???";
    417  1.49   pooka 		} else {
    418  1.49   pooka 			static char commname[128];
    419  1.49   pooka 
    420  1.50   pooka 			memset(commname, 0, sizeof(commname));
    421  1.49   pooka 			if (read(fd, commname, sizeof(commname)) > 0) {
    422  1.49   pooka 				char *n;
    423  1.49   pooka 
    424  1.49   pooka 				n = strrchr(commname, '\n');
    425  1.49   pooka 				if (n)
    426  1.49   pooka 					*n = '\0';
    427  1.49   pooka 				myprogname = commname;
    428  1.49   pooka 			} else {
    429  1.49   pooka 				myprogname = "???";
    430  1.49   pooka 			}
    431  1.49   pooka 			close(fd);
    432  1.49   pooka 		}
    433  1.49   pooka #endif
    434  1.39   pooka 		bonus = strlen(myprogname)+1;
    435  1.21   pooka 	}
    436  1.21   pooka 
    437  1.10   pooka 	/* performs server handshake */
    438  1.21   pooka 	rhdr.rsp_len = sizeof(rhdr) + bonus;
    439  1.10   pooka 	rhdr.rsp_class = RUMPSP_REQ;
    440  1.10   pooka 	rhdr.rsp_type = RUMPSP_HANDSHAKE;
    441  1.29   pooka 	rhdr.rsp_handshake = type;
    442  1.10   pooka 
    443  1.39   pooka 	IOVPUT(iov[0], rhdr);
    444  1.39   pooka 
    445  1.12   pooka 	pthread_sigmask(SIG_SETMASK, &fullset, &omask);
    446  1.18   pooka 	if (haslock)
    447  1.18   pooka 		putwait_locked(spc, &rw, &rhdr);
    448  1.18   pooka 	else
    449  1.18   pooka 		putwait(spc, &rw, &rhdr);
    450  1.29   pooka 	if (type == HANDSHAKE_FORK) {
    451  1.29   pooka 		memcpy(rf.rf_auth, data, sizeof(rf.rf_auth)); /* uh, why? */
    452  1.11   pooka 		rf.rf_cancel = cancel;
    453  1.39   pooka 		IOVPUT(iov[1], rf);
    454  1.21   pooka 	} else {
    455  1.43   pooka 		IOVPUT_WITHSIZE(iov[1], __UNCONST(myprogname), bonus);
    456  1.11   pooka 	}
    457  1.39   pooka 	rv = send_with_recon(spc, iov, __arraycount(iov));
    458  1.18   pooka 	if (rv || cancel) {
    459  1.18   pooka 		if (haslock)
    460  1.18   pooka 			unputwait_locked(spc, &rw);
    461  1.18   pooka 		else
    462  1.18   pooka 			unputwait(spc, &rw);
    463  1.18   pooka 		if (cancel) {
    464  1.26   pooka 			goto out;
    465  1.18   pooka 		}
    466  1.18   pooka 	} else {
    467  1.18   pooka 		rv = cliwaitresp(spc, &rw, &omask, haslock);
    468  1.10   pooka 	}
    469  1.10   pooka 	if (rv)
    470  1.26   pooka 		goto out;
    471  1.10   pooka 
    472  1.10   pooka 	rv = *(int *)rw.rw_data;
    473  1.10   pooka 	free(rw.rw_data);
    474  1.10   pooka 
    475  1.26   pooka  out:
    476  1.26   pooka 	pthread_sigmask(SIG_SETMASK, &omask, NULL);
    477  1.10   pooka 	return rv;
    478  1.10   pooka }
    479  1.10   pooka 
    480  1.10   pooka static int
    481  1.26   pooka prefork_req(struct spclient *spc, sigset_t *omask, void **resp)
    482  1.11   pooka {
    483  1.11   pooka 	struct rsp_hdr rhdr;
    484  1.11   pooka 	struct respwait rw;
    485  1.39   pooka 	struct iovec iov[1];
    486  1.11   pooka 	int rv;
    487  1.11   pooka 
    488  1.11   pooka 	rhdr.rsp_len = sizeof(rhdr);
    489  1.11   pooka 	rhdr.rsp_class = RUMPSP_REQ;
    490  1.11   pooka 	rhdr.rsp_type = RUMPSP_PREFORK;
    491  1.11   pooka 	rhdr.rsp_error = 0;
    492  1.11   pooka 
    493  1.39   pooka 	IOVPUT(iov[0], rhdr);
    494  1.39   pooka 
    495  1.18   pooka 	do {
    496  1.18   pooka 		putwait(spc, &rw, &rhdr);
    497  1.39   pooka 		rv = send_with_recon(spc, iov, __arraycount(iov));
    498  1.18   pooka 		if (rv != 0) {
    499  1.18   pooka 			unputwait(spc, &rw);
    500  1.18   pooka 			continue;
    501  1.18   pooka 		}
    502  1.11   pooka 
    503  1.26   pooka 		rv = cliwaitresp(spc, &rw, omask, false);
    504  1.20   pooka 		if (rv == ENOTCONN)
    505  1.20   pooka 			rv = EAGAIN;
    506  1.20   pooka 	} while (rv == EAGAIN);
    507  1.18   pooka 
    508  1.11   pooka 	*resp = rw.rw_data;
    509  1.11   pooka 	return rv;
    510  1.11   pooka }
    511  1.11   pooka 
    512  1.18   pooka /*
    513  1.18   pooka  * prevent response code from deadlocking with reconnect code
    514  1.18   pooka  */
    515  1.11   pooka static int
    516  1.18   pooka resp_sendlock(struct spclient *spc)
    517  1.18   pooka {
    518  1.18   pooka 	int rv = 0;
    519  1.18   pooka 
    520  1.18   pooka 	pthread_mutex_lock(&spc->spc_mtx);
    521  1.18   pooka 	while (spc->spc_ostatus != SPCSTATUS_FREE) {
    522  1.18   pooka 		if (__predict_false(spc->spc_reconnecting)) {
    523  1.18   pooka 			rv = EBUSY;
    524  1.18   pooka 			goto out;
    525  1.18   pooka 		}
    526  1.18   pooka 		spc->spc_ostatus = SPCSTATUS_WANTED;
    527  1.18   pooka 		pthread_cond_wait(&spc->spc_cv, &spc->spc_mtx);
    528  1.18   pooka 	}
    529  1.18   pooka 	spc->spc_ostatus = SPCSTATUS_BUSY;
    530  1.18   pooka 
    531  1.18   pooka  out:
    532  1.18   pooka 	pthread_mutex_unlock(&spc->spc_mtx);
    533  1.18   pooka 	return rv;
    534  1.18   pooka }
    535  1.18   pooka 
    536  1.18   pooka static void
    537   1.5   pooka send_copyin_resp(struct spclient *spc, uint64_t reqno, void *data, size_t dlen,
    538   1.5   pooka 	int wantstr)
    539   1.1   pooka {
    540   1.1   pooka 	struct rsp_hdr rhdr;
    541  1.39   pooka 	struct iovec iov[2];
    542   1.1   pooka 
    543   1.5   pooka 	if (wantstr)
    544   1.5   pooka 		dlen = MIN(dlen, strlen(data)+1);
    545   1.5   pooka 
    546   1.1   pooka 	rhdr.rsp_len = sizeof(rhdr) + dlen;
    547   1.1   pooka 	rhdr.rsp_reqno = reqno;
    548   1.3   pooka 	rhdr.rsp_class = RUMPSP_RESP;
    549   1.3   pooka 	rhdr.rsp_type = RUMPSP_COPYIN;
    550   1.1   pooka 	rhdr.rsp_sysnum = 0;
    551   1.1   pooka 
    552  1.39   pooka 	IOVPUT(iov[0], rhdr);
    553  1.39   pooka 	IOVPUT_WITHSIZE(iov[1], data, dlen);
    554  1.39   pooka 
    555  1.18   pooka 	if (resp_sendlock(spc) != 0)
    556  1.18   pooka 		return;
    557  1.39   pooka 	(void)SENDIOV(spc, iov);
    558   1.3   pooka 	sendunlock(spc);
    559   1.1   pooka }
    560   1.1   pooka 
    561  1.18   pooka static void
    562   1.1   pooka send_anonmmap_resp(struct spclient *spc, uint64_t reqno, void *addr)
    563   1.1   pooka {
    564   1.1   pooka 	struct rsp_hdr rhdr;
    565  1.39   pooka 	struct iovec iov[2];
    566   1.1   pooka 
    567   1.1   pooka 	rhdr.rsp_len = sizeof(rhdr) + sizeof(addr);
    568   1.1   pooka 	rhdr.rsp_reqno = reqno;
    569   1.3   pooka 	rhdr.rsp_class = RUMPSP_RESP;
    570   1.3   pooka 	rhdr.rsp_type = RUMPSP_ANONMMAP;
    571   1.1   pooka 	rhdr.rsp_sysnum = 0;
    572   1.1   pooka 
    573  1.39   pooka 	IOVPUT(iov[0], rhdr);
    574  1.39   pooka 	IOVPUT(iov[1], addr);
    575  1.39   pooka 
    576  1.18   pooka 	if (resp_sendlock(spc) != 0)
    577  1.18   pooka 		return;
    578  1.39   pooka 	(void)SENDIOV(spc, iov);
    579   1.3   pooka 	sendunlock(spc);
    580   1.1   pooka }
    581   1.1   pooka 
    582   1.1   pooka int
    583   1.1   pooka rumpclient_syscall(int sysnum, const void *data, size_t dlen,
    584   1.1   pooka 	register_t *retval)
    585   1.1   pooka {
    586   1.1   pooka 	struct rsp_sysresp *resp;
    587  1.26   pooka 	sigset_t omask;
    588   1.3   pooka 	void *rdata;
    589   1.3   pooka 	int rv;
    590   1.3   pooka 
    591  1.26   pooka 	pthread_sigmask(SIG_SETMASK, &fullset, &omask);
    592  1.26   pooka 
    593   1.3   pooka 	DPRINTF(("rumpsp syscall_req: syscall %d with %p/%zu\n",
    594   1.3   pooka 	    sysnum, data, dlen));
    595   1.3   pooka 
    596  1.26   pooka 	rv = syscall_req(&clispc, &omask, sysnum, data, dlen, &rdata);
    597   1.3   pooka 	if (rv)
    598  1.26   pooka 		goto out;
    599   1.3   pooka 
    600   1.3   pooka 	resp = rdata;
    601   1.3   pooka 	DPRINTF(("rumpsp syscall_resp: syscall %d error %d, rv: %d/%d\n",
    602   1.3   pooka 	    sysnum, rv, resp->rsys_retval[0], resp->rsys_retval[1]));
    603   1.1   pooka 
    604   1.3   pooka 	memcpy(retval, &resp->rsys_retval, sizeof(resp->rsys_retval));
    605   1.3   pooka 	rv = resp->rsys_error;
    606   1.3   pooka 	free(rdata);
    607   1.1   pooka 
    608  1.26   pooka  out:
    609  1.26   pooka 	pthread_sigmask(SIG_SETMASK, &omask, NULL);
    610   1.3   pooka 	return rv;
    611   1.3   pooka }
    612   1.1   pooka 
    613   1.3   pooka static void
    614   1.3   pooka handlereq(struct spclient *spc)
    615   1.3   pooka {
    616   1.3   pooka 	struct rsp_copydata *copydata;
    617  1.16   pooka 	struct rsp_hdr *rhdr = &spc->spc_hdr;
    618   1.3   pooka 	void *mapaddr;
    619   1.3   pooka 	size_t maplen;
    620   1.5   pooka 	int reqtype = spc->spc_hdr.rsp_type;
    621  1.56   pooka 	int sig;
    622   1.1   pooka 
    623   1.5   pooka 	switch (reqtype) {
    624   1.3   pooka 	case RUMPSP_COPYIN:
    625   1.5   pooka 	case RUMPSP_COPYINSTR:
    626   1.3   pooka 		/*LINTED*/
    627   1.3   pooka 		copydata = (struct rsp_copydata *)spc->spc_buf;
    628   1.3   pooka 		DPRINTF(("rump_sp handlereq: copyin request: %p/%zu\n",
    629   1.3   pooka 		    copydata->rcp_addr, copydata->rcp_len));
    630   1.3   pooka 		send_copyin_resp(spc, spc->spc_hdr.rsp_reqno,
    631   1.5   pooka 		    copydata->rcp_addr, copydata->rcp_len,
    632   1.5   pooka 		    reqtype == RUMPSP_COPYINSTR);
    633   1.3   pooka 		break;
    634   1.3   pooka 	case RUMPSP_COPYOUT:
    635   1.5   pooka 	case RUMPSP_COPYOUTSTR:
    636   1.3   pooka 		/*LINTED*/
    637   1.3   pooka 		copydata = (struct rsp_copydata *)spc->spc_buf;
    638   1.3   pooka 		DPRINTF(("rump_sp handlereq: copyout request: %p/%zu\n",
    639   1.3   pooka 		    copydata->rcp_addr, copydata->rcp_len));
    640   1.3   pooka 		/*LINTED*/
    641   1.3   pooka 		memcpy(copydata->rcp_addr, copydata->rcp_data,
    642   1.3   pooka 		    copydata->rcp_len);
    643   1.3   pooka 		break;
    644   1.3   pooka 	case RUMPSP_ANONMMAP:
    645   1.3   pooka 		/*LINTED*/
    646   1.3   pooka 		maplen = *(size_t *)spc->spc_buf;
    647   1.3   pooka 		mapaddr = mmap(NULL, maplen, PROT_READ|PROT_WRITE,
    648  1.57   pooka 		    MAP_ANON|MAP_PRIVATE, -1, 0);
    649   1.3   pooka 		if (mapaddr == MAP_FAILED)
    650   1.3   pooka 			mapaddr = NULL;
    651   1.3   pooka 		DPRINTF(("rump_sp handlereq: anonmmap: %p\n", mapaddr));
    652   1.3   pooka 		send_anonmmap_resp(spc, spc->spc_hdr.rsp_reqno, mapaddr);
    653   1.3   pooka 		break;
    654  1.16   pooka 	case RUMPSP_RAISE:
    655  1.56   pooka 		sig = rumpuser__sig_rump2host(rhdr->rsp_signo);
    656  1.56   pooka 		DPRINTF(("rump_sp handlereq: raise sig %d\n", sig));
    657  1.56   pooka 		raise(sig);
    658  1.16   pooka 		/*
    659  1.16   pooka 		 * We most likely have signals blocked, but the signal
    660  1.16   pooka 		 * will be handled soon enough when we return.
    661  1.16   pooka 		 */
    662  1.16   pooka 		break;
    663   1.3   pooka 	default:
    664  1.12   pooka 		printf("PANIC: INVALID TYPE %d\n", reqtype);
    665   1.3   pooka 		abort();
    666   1.3   pooka 		break;
    667   1.1   pooka 	}
    668   1.1   pooka 
    669   1.6   pooka 	spcfreebuf(spc);
    670   1.1   pooka }
    671   1.1   pooka 
    672  1.11   pooka static unsigned ptab_idx;
    673  1.11   pooka static struct sockaddr *serv_sa;
    674  1.11   pooka 
    675  1.27   pooka /* dup until we get a "good" fd which does not collide with stdio */
    676  1.27   pooka static int
    677  1.28   pooka dupgood(int myfd, int mustchange)
    678  1.27   pooka {
    679  1.28   pooka 	int ofds[4];
    680  1.45   alnsn 	int sverrno;
    681  1.48    matt 	unsigned int i;
    682  1.27   pooka 
    683  1.28   pooka 	for (i = 0; (myfd <= 2 || mustchange) && myfd != -1; i++) {
    684  1.27   pooka 		assert(i < __arraycount(ofds));
    685  1.27   pooka 		ofds[i] = myfd;
    686  1.27   pooka 		myfd = host_dup(myfd);
    687  1.28   pooka 		if (mustchange) {
    688  1.28   pooka 			i--; /* prevent closing old fd */
    689  1.28   pooka 			mustchange = 0;
    690  1.28   pooka 		}
    691  1.27   pooka 	}
    692  1.27   pooka 
    693  1.45   alnsn 	sverrno = 0;
    694  1.45   alnsn 	if (myfd == -1 && i > 0)
    695  1.45   alnsn 		sverrno = errno;
    696  1.45   alnsn 
    697  1.48    matt 	while (i-- > 0) {
    698  1.27   pooka 		host_close(ofds[i]);
    699  1.27   pooka 	}
    700  1.27   pooka 
    701  1.45   alnsn 	if (sverrno)
    702  1.45   alnsn 		errno = sverrno;
    703  1.45   alnsn 
    704  1.27   pooka 	return myfd;
    705  1.27   pooka }
    706  1.27   pooka 
    707  1.58   pooka #if defined(USE_KQUEUE)
    708  1.58   pooka 
    709  1.58   pooka static int
    710  1.58   pooka makeholyfd(void)
    711  1.58   pooka {
    712  1.58   pooka 	struct kevent kev[NSIG+1];
    713  1.58   pooka 	int i, fd;
    714  1.58   pooka 
    715  1.58   pooka 	/* setup kqueue, we want all signals and the fd */
    716  1.58   pooka 	if ((fd = dupgood(host_kqueue(), 0)) == -1) {
    717  1.58   pooka 		ERRLOG(("rump_sp: cannot setup kqueue"));
    718  1.58   pooka 		return -1;
    719  1.58   pooka 	}
    720  1.58   pooka 
    721  1.58   pooka 	for (i = 0; i < NSIG; i++) {
    722  1.58   pooka 		EV_SET(&kev[i], i+1, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0);
    723  1.58   pooka 	}
    724  1.58   pooka 	EV_SET(&kev[NSIG], clispc.spc_fd,
    725  1.58   pooka 	    EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0);
    726  1.58   pooka 	if (host_kevent(fd, kev, NSIG+1, NULL, 0, NULL) == -1) {
    727  1.58   pooka 		ERRLOG(("rump_sp: kevent() failed"));
    728  1.59   pooka 		host_close(fd);
    729  1.58   pooka 		return -1;
    730  1.59   pooka 	}
    731  1.58   pooka 
    732  1.58   pooka 	return fd;
    733  1.58   pooka }
    734  1.58   pooka 
    735  1.58   pooka #elif defined(USE_SIGNALFD) /* !USE_KQUEUE */
    736  1.58   pooka 
    737  1.58   pooka static int
    738  1.58   pooka makeholyfd(void)
    739  1.58   pooka {
    740  1.58   pooka 
    741  1.58   pooka 	return host_signalfd(-1, &fullset, 0);
    742  1.58   pooka }
    743  1.58   pooka 
    744  1.58   pooka #else /* !USE_KQUEUE && !USE_SIGNALFD */
    745  1.58   pooka 
    746  1.58   pooka static int
    747  1.58   pooka makeholyfd(void)
    748  1.58   pooka {
    749  1.58   pooka 
    750  1.58   pooka 	return -1;
    751  1.58   pooka }
    752  1.58   pooka 
    753  1.58   pooka #endif
    754  1.58   pooka 
    755  1.11   pooka static int
    756  1.44   pooka doconnect(void)
    757   1.1   pooka {
    758  1.18   pooka 	struct respwait rw;
    759  1.18   pooka 	struct rsp_hdr rhdr;
    760   1.9   pooka 	char banner[MAXBANNER];
    761  1.49   pooka 	int s, error, flags;
    762   1.9   pooka 	ssize_t n;
    763   1.1   pooka 
    764  1.58   pooka 	if (holyfd != -1)
    765  1.58   pooka 		host_close(holyfd);
    766  1.58   pooka 	holyfd = -1;
    767  1.19   pooka 	s = -1;
    768  1.18   pooka 
    769  1.18   pooka 	if (clispc.spc_fd != -1)
    770  1.18   pooka 		host_close(clispc.spc_fd);
    771  1.18   pooka 	clispc.spc_fd = -1;
    772  1.18   pooka 
    773  1.18   pooka 	/*
    774  1.18   pooka 	 * for reconnect, gate everyone out of the receiver code
    775  1.18   pooka 	 */
    776  1.18   pooka 	putwait_locked(&clispc, &rw, &rhdr);
    777  1.18   pooka 
    778  1.18   pooka 	pthread_mutex_lock(&clispc.spc_mtx);
    779  1.18   pooka 	clispc.spc_reconnecting = 1;
    780  1.18   pooka 	pthread_cond_broadcast(&clispc.spc_cv);
    781  1.18   pooka 	clispc.spc_generation++;
    782  1.18   pooka 	while (clispc.spc_istatus != SPCSTATUS_FREE) {
    783  1.18   pooka 		clispc.spc_istatus = SPCSTATUS_WANTED;
    784  1.18   pooka 		pthread_cond_wait(&rw.rw_cv, &clispc.spc_mtx);
    785  1.18   pooka 	}
    786  1.18   pooka 	kickall(&clispc);
    787  1.18   pooka 
    788  1.18   pooka 	/*
    789  1.18   pooka 	 * we can release it already since we hold the
    790  1.18   pooka 	 * send lock during reconnect
    791  1.18   pooka 	 * XXX: assert it
    792  1.18   pooka 	 */
    793  1.18   pooka 	clispc.spc_istatus = SPCSTATUS_FREE;
    794  1.18   pooka 	pthread_mutex_unlock(&clispc.spc_mtx);
    795  1.18   pooka 	unputwait_locked(&clispc, &rw);
    796  1.18   pooka 
    797  1.18   pooka 	free(clispc.spc_buf);
    798  1.18   pooka 	clispc.spc_off = 0;
    799  1.18   pooka 
    800  1.28   pooka 	s = dupgood(host_socket(parsetab[ptab_idx].domain, SOCK_STREAM, 0), 0);
    801  1.11   pooka 	if (s == -1)
    802   1.2   pooka 		return -1;
    803   1.1   pooka 
    804  1.49   pooka 	while (host_connect(s, serv_sa, parsetab[ptab_idx].slen) == -1) {
    805  1.18   pooka 		if (errno == EINTR)
    806  1.18   pooka 			continue;
    807  1.44   pooka 		ERRLOG(("rump_sp: client connect failed: %s\n",
    808  1.44   pooka 		    strerror(errno)));
    809  1.20   pooka 		return -1;
    810   1.2   pooka 	}
    811   1.1   pooka 
    812  1.11   pooka 	if ((error = parsetab[ptab_idx].connhook(s)) != 0) {
    813  1.44   pooka 		ERRLOG(("rump_sp: connect hook failed\n"));
    814   1.2   pooka 		return -1;
    815   1.1   pooka 	}
    816   1.4   pooka 
    817  1.45   alnsn 	if ((n = host_read(s, banner, sizeof(banner)-1)) <= 0) {
    818  1.44   pooka 		ERRLOG(("rump_sp: failed to read banner\n"));
    819   1.2   pooka 		return -1;
    820   1.1   pooka 	}
    821   1.9   pooka 
    822   1.9   pooka 	if (banner[n-1] != '\n') {
    823  1.44   pooka 		ERRLOG(("rump_sp: invalid banner\n"));
    824   1.9   pooka 		return -1;
    825   1.9   pooka 	}
    826   1.9   pooka 	banner[n] = '\0';
    827  1.45   alnsn 	/* XXX parse the banner some day */
    828   1.9   pooka 
    829  1.15   pooka 	flags = host_fcntl(s, F_GETFL, 0);
    830  1.15   pooka 	if (host_fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) {
    831  1.44   pooka 		ERRLOG(("rump_sp: socket fd NONBLOCK: %s\n", strerror(errno)));
    832  1.15   pooka 		return -1;
    833  1.15   pooka 	}
    834  1.18   pooka 	clispc.spc_fd = s;
    835  1.18   pooka 	clispc.spc_state = SPCSTATE_RUNNING;
    836  1.18   pooka 	clispc.spc_reconnecting = 0;
    837  1.58   pooka 	holyfd = makeholyfd();
    838  1.15   pooka 
    839  1.18   pooka 	return 0;
    840  1.18   pooka }
    841  1.18   pooka 
    842  1.18   pooka static int
    843  1.18   pooka doinit(void)
    844  1.18   pooka {
    845  1.18   pooka 
    846  1.11   pooka 	TAILQ_INIT(&clispc.spc_respwait);
    847  1.11   pooka 	pthread_mutex_init(&clispc.spc_mtx, NULL);
    848  1.11   pooka 	pthread_cond_init(&clispc.spc_cv, NULL);
    849  1.11   pooka 
    850  1.11   pooka 	return 0;
    851  1.11   pooka }
    852  1.11   pooka 
    853  1.53   pooka #ifdef RTLD_NEXT
    854  1.35   pooka void *rumpclient__dlsym(void *, const char *);
    855  1.35   pooka void *
    856  1.35   pooka rumpclient__dlsym(void *handle, const char *symbol)
    857  1.35   pooka {
    858  1.35   pooka 
    859  1.35   pooka 	return dlsym(handle, symbol);
    860  1.35   pooka }
    861  1.49   pooka void *rumphijack_dlsym(void *, const char *)
    862  1.49   pooka     __attribute__((__weak__, alias("rumpclient__dlsym")));
    863  1.53   pooka #endif
    864  1.35   pooka 
    865  1.38   pooka static pid_t init_done = 0;
    866  1.13   pooka 
    867  1.11   pooka int
    868  1.46   joerg rumpclient_init(void)
    869  1.11   pooka {
    870  1.11   pooka 	char *p;
    871  1.11   pooka 	int error;
    872  1.29   pooka 	int rv = -1;
    873  1.29   pooka 	int hstype;
    874  1.38   pooka 	pid_t mypid;
    875  1.29   pooka 
    876  1.38   pooka 	/*
    877  1.38   pooka 	 * Make sure we're not riding the context of a previous
    878  1.38   pooka 	 * host fork.  Note: it's *possible* that after n>1 forks
    879  1.38   pooka 	 * we have the same pid as one of our exited parents, but
    880  1.38   pooka 	 * I'm pretty sure there are 0 practical implications, since
    881  1.38   pooka 	 * it means generations would have to skip rumpclient init.
    882  1.38   pooka 	 */
    883  1.38   pooka 	if (init_done == (mypid = getpid()))
    884  1.29   pooka 		return 0;
    885  1.38   pooka 
    886  1.61   pooka #ifdef USE_KQUEUE
    887  1.38   pooka 	/* kq does not traverse fork() */
    888  1.61   pooka 	holyfd = -1;
    889  1.58   pooka #endif
    890  1.38   pooka 	init_done = mypid;
    891  1.11   pooka 
    892  1.25   pooka 	sigfillset(&fullset);
    893  1.25   pooka 
    894  1.13   pooka 	/*
    895  1.49   pooka 	 * sag mir, wo die symbols sind.  zogen fort, der krieg beginnt.
    896  1.13   pooka 	 * wann wird man je verstehen?  wann wird man je verstehen?
    897  1.13   pooka 	 */
    898  1.53   pooka #ifdef RTLD_NEXT
    899  1.13   pooka #define FINDSYM2(_name_,_syscall_)					\
    900  1.35   pooka 	if ((host_##_name_ = rumphijack_dlsym(RTLD_NEXT,		\
    901  1.34   pooka 	    #_syscall_)) == NULL) {					\
    902  1.36   pooka 		if (rumphijack_dlsym == rumpclient__dlsym)		\
    903  1.34   pooka 			host_##_name_ = _name_; /* static fallback */	\
    904  1.54   pooka 		if (host_##_name_ == NULL) {				\
    905  1.54   pooka 			fprintf(stderr,"cannot find %s: %s", #_syscall_,\
    906  1.34   pooka 			    dlerror());					\
    907  1.54   pooka 			exit(1);					\
    908  1.54   pooka 		}							\
    909  1.34   pooka 	}
    910  1.53   pooka #else
    911  1.53   pooka #define FINDSYM2(_name_,_syscall)					\
    912  1.53   pooka 	host_##_name_ = _name_;
    913  1.53   pooka #endif
    914  1.13   pooka #define FINDSYM(_name_) FINDSYM2(_name_,_name_)
    915  1.49   pooka #ifdef __NetBSD__
    916  1.34   pooka 	FINDSYM2(socket,__socket30)
    917  1.49   pooka #else
    918  1.49   pooka 	FINDSYM(socket)
    919  1.49   pooka #endif
    920  1.49   pooka 
    921  1.34   pooka 	FINDSYM(close)
    922  1.34   pooka 	FINDSYM(connect)
    923  1.34   pooka 	FINDSYM(fcntl)
    924  1.34   pooka 	FINDSYM(poll)
    925  1.34   pooka 	FINDSYM(read)
    926  1.39   pooka 	FINDSYM(sendmsg)
    927  1.34   pooka 	FINDSYM(setsockopt)
    928  1.34   pooka 	FINDSYM(dup)
    929  1.49   pooka 	FINDSYM(execve)
    930  1.49   pooka 
    931  1.49   pooka #ifdef USE_KQUEUE
    932  1.34   pooka 	FINDSYM(kqueue)
    933  1.63  justin #ifdef __NetBSD__
    934  1.22   pooka #if !__NetBSD_Prereq__(5,99,7)
    935  1.34   pooka 	FINDSYM(kevent)
    936  1.22   pooka #else
    937  1.34   pooka 	FINDSYM2(kevent,_sys___kevent50)
    938  1.22   pooka #endif
    939  1.63  justin #else
    940  1.63  justin 	FINDSYM(kevent)
    941  1.63  justin #endif
    942  1.49   pooka #endif /* USE_KQUEUE */
    943  1.49   pooka 
    944  1.58   pooka #ifdef USE_SIGNALFD
    945  1.58   pooka 	FINDSYM(signalfd)
    946  1.58   pooka #endif
    947  1.58   pooka 
    948  1.13   pooka #undef	FINDSYM
    949  1.13   pooka #undef	FINDSY2
    950  1.13   pooka 
    951  1.28   pooka 	if ((p = getenv("RUMP__PARSEDSERVER")) == NULL) {
    952  1.28   pooka 		if ((p = getenv("RUMP_SERVER")) == NULL) {
    953  1.52   pooka 			fprintf(stderr, "error: RUMP_SERVER not set\n");
    954  1.28   pooka 			errno = ENOENT;
    955  1.29   pooka 			goto out;
    956  1.28   pooka 		}
    957  1.11   pooka 	}
    958  1.11   pooka 
    959  1.11   pooka 	if ((error = parseurl(p, &serv_sa, &ptab_idx, 0)) != 0) {
    960  1.11   pooka 		errno = error;
    961  1.29   pooka 		goto out;
    962  1.11   pooka 	}
    963  1.11   pooka 
    964  1.18   pooka 	if (doinit() == -1)
    965  1.29   pooka 		goto out;
    966  1.28   pooka 
    967  1.28   pooka 	if ((p = getenv("RUMPCLIENT__EXECFD")) != NULL) {
    968  1.58   pooka 		sscanf(p, "%d,%d", &clispc.spc_fd, &holyfd);
    969  1.28   pooka 		unsetenv("RUMPCLIENT__EXECFD");
    970  1.29   pooka 		hstype = HANDSHAKE_EXEC;
    971  1.29   pooka 	} else {
    972  1.44   pooka 		if (doconnect() == -1)
    973  1.29   pooka 			goto out;
    974  1.29   pooka 		hstype = HANDSHAKE_GUEST;
    975  1.28   pooka 	}
    976  1.28   pooka 
    977  1.29   pooka 	error = handshake_req(&clispc, hstype, NULL, 0, false);
    978  1.11   pooka 	if (error) {
    979  1.11   pooka 		pthread_mutex_destroy(&clispc.spc_mtx);
    980  1.11   pooka 		pthread_cond_destroy(&clispc.spc_cv);
    981  1.18   pooka 		if (clispc.spc_fd != -1)
    982  1.18   pooka 			host_close(clispc.spc_fd);
    983  1.10   pooka 		errno = error;
    984  1.29   pooka 		goto out;
    985  1.10   pooka 	}
    986  1.29   pooka 	rv = 0;
    987  1.10   pooka 
    988  1.29   pooka  out:
    989  1.29   pooka 	if (rv == -1)
    990  1.29   pooka 		init_done = 0;
    991  1.29   pooka 	return rv;
    992  1.11   pooka }
    993  1.11   pooka 
    994  1.11   pooka struct rumpclient_fork {
    995  1.11   pooka 	uint32_t fork_auth[AUTHLEN];
    996  1.31   pooka 	struct spclient fork_spc;
    997  1.58   pooka 	int fork_holyfd;
    998  1.11   pooka };
    999  1.11   pooka 
   1000  1.11   pooka struct rumpclient_fork *
   1001  1.11   pooka rumpclient_prefork(void)
   1002  1.11   pooka {
   1003  1.11   pooka 	struct rumpclient_fork *rpf;
   1004  1.26   pooka 	sigset_t omask;
   1005  1.11   pooka 	void *resp;
   1006  1.11   pooka 	int rv;
   1007  1.11   pooka 
   1008  1.26   pooka 	pthread_sigmask(SIG_SETMASK, &fullset, &omask);
   1009  1.11   pooka 	rpf = malloc(sizeof(*rpf));
   1010  1.11   pooka 	if (rpf == NULL)
   1011  1.30   pooka 		goto out;
   1012  1.11   pooka 
   1013  1.26   pooka 	if ((rv = prefork_req(&clispc, &omask, &resp)) != 0) {
   1014  1.11   pooka 		free(rpf);
   1015  1.11   pooka 		errno = rv;
   1016  1.26   pooka 		rpf = NULL;
   1017  1.26   pooka 		goto out;
   1018  1.11   pooka 	}
   1019  1.11   pooka 
   1020  1.11   pooka 	memcpy(rpf->fork_auth, resp, sizeof(rpf->fork_auth));
   1021  1.11   pooka 	free(resp);
   1022  1.11   pooka 
   1023  1.31   pooka 	rpf->fork_spc = clispc;
   1024  1.58   pooka 	rpf->fork_holyfd = holyfd;
   1025  1.31   pooka 
   1026  1.26   pooka  out:
   1027  1.26   pooka 	pthread_sigmask(SIG_SETMASK, &omask, NULL);
   1028  1.11   pooka 	return rpf;
   1029  1.11   pooka }
   1030  1.11   pooka 
   1031  1.11   pooka int
   1032  1.11   pooka rumpclient_fork_init(struct rumpclient_fork *rpf)
   1033  1.11   pooka {
   1034  1.11   pooka 	int error;
   1035  1.23   pooka 	int osock;
   1036  1.11   pooka 
   1037  1.23   pooka 	osock = clispc.spc_fd;
   1038  1.11   pooka 	memset(&clispc, 0, sizeof(clispc));
   1039  1.23   pooka 	clispc.spc_fd = osock;
   1040  1.23   pooka 
   1041  1.58   pooka #ifdef USE_KQUEUE
   1042  1.58   pooka 	holyfd = -1; /* kqueue descriptor is not copied over fork() */
   1043  1.58   pooka #else
   1044  1.58   pooka 	if (holyfd != -1) {
   1045  1.58   pooka 		host_close(holyfd);
   1046  1.58   pooka 		holyfd = -1;
   1047  1.58   pooka 	}
   1048  1.58   pooka #endif
   1049  1.11   pooka 
   1050  1.18   pooka 	if (doinit() == -1)
   1051  1.18   pooka 		return -1;
   1052  1.44   pooka 	if (doconnect() == -1)
   1053  1.11   pooka 		return -1;
   1054  1.10   pooka 
   1055  1.29   pooka 	error = handshake_req(&clispc, HANDSHAKE_FORK, rpf->fork_auth,
   1056  1.29   pooka 	    0, false);
   1057  1.10   pooka 	if (error) {
   1058  1.10   pooka 		pthread_mutex_destroy(&clispc.spc_mtx);
   1059  1.10   pooka 		pthread_cond_destroy(&clispc.spc_cv);
   1060  1.11   pooka 		errno = error;
   1061  1.11   pooka 		return -1;
   1062  1.10   pooka 	}
   1063  1.11   pooka 
   1064  1.11   pooka 	return 0;
   1065   1.1   pooka }
   1066  1.20   pooka 
   1067  1.42   pooka /*ARGSUSED*/
   1068  1.20   pooka void
   1069  1.31   pooka rumpclient_fork_cancel(struct rumpclient_fork *rpf)
   1070  1.31   pooka {
   1071  1.31   pooka 
   1072  1.31   pooka 	/* EUNIMPL */
   1073  1.31   pooka }
   1074  1.31   pooka 
   1075  1.31   pooka void
   1076  1.31   pooka rumpclient_fork_vparent(struct rumpclient_fork *rpf)
   1077  1.31   pooka {
   1078  1.31   pooka 
   1079  1.31   pooka 	clispc = rpf->fork_spc;
   1080  1.58   pooka 	holyfd = rpf->fork_holyfd;
   1081  1.31   pooka }
   1082  1.31   pooka 
   1083  1.31   pooka void
   1084  1.20   pooka rumpclient_setconnretry(time_t timeout)
   1085  1.20   pooka {
   1086  1.20   pooka 
   1087  1.24   pooka 	if (timeout < RUMPCLIENT_RETRYCONN_DIE)
   1088  1.20   pooka 		return; /* gigo */
   1089  1.20   pooka 
   1090  1.20   pooka 	retrytimo = timeout;
   1091  1.20   pooka }
   1092  1.28   pooka 
   1093  1.28   pooka int
   1094  1.28   pooka rumpclient__closenotify(int *fdp, enum rumpclient_closevariant variant)
   1095  1.28   pooka {
   1096  1.28   pooka 	int fd = *fdp;
   1097  1.28   pooka 	int untilfd, rv;
   1098  1.28   pooka 	int newfd;
   1099  1.28   pooka 
   1100  1.28   pooka 	switch (variant) {
   1101  1.28   pooka 	case RUMPCLIENT_CLOSE_FCLOSEM:
   1102  1.58   pooka 		untilfd = MAX(clispc.spc_fd, holyfd);
   1103  1.28   pooka 		for (; fd <= untilfd; fd++) {
   1104  1.58   pooka 			if (fd == clispc.spc_fd || fd == holyfd)
   1105  1.28   pooka 				continue;
   1106  1.28   pooka 			rv = host_close(fd);
   1107  1.28   pooka 			if (rv == -1)
   1108  1.28   pooka 				return -1;
   1109  1.28   pooka 		}
   1110  1.28   pooka 		*fdp = fd;
   1111  1.28   pooka 		break;
   1112  1.28   pooka 
   1113  1.28   pooka 	case RUMPCLIENT_CLOSE_CLOSE:
   1114  1.28   pooka 	case RUMPCLIENT_CLOSE_DUP2:
   1115  1.28   pooka 		if (fd == clispc.spc_fd) {
   1116  1.28   pooka 			newfd = dupgood(clispc.spc_fd, 1);
   1117  1.28   pooka 			if (newfd == -1)
   1118  1.28   pooka 				return -1;
   1119  1.49   pooka 
   1120  1.49   pooka #ifdef USE_KQUEUE
   1121  1.49   pooka 			{
   1122  1.49   pooka 			struct kevent kev[2];
   1123  1.49   pooka 
   1124  1.28   pooka 			/*
   1125  1.28   pooka 			 * now, we have a new socket number, so change
   1126  1.28   pooka 			 * the file descriptor that kqueue is
   1127  1.28   pooka 			 * monitoring.  remove old and add new.
   1128  1.28   pooka 			 */
   1129  1.28   pooka 			EV_SET(&kev[0], clispc.spc_fd,
   1130  1.28   pooka 			    EVFILT_READ, EV_DELETE, 0, 0, 0);
   1131  1.28   pooka 			EV_SET(&kev[1], newfd,
   1132  1.28   pooka 			    EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0);
   1133  1.58   pooka 			if (host_kevent(holyfd, kev, 2, NULL, 0, NULL) == -1) {
   1134  1.28   pooka 				int sverrno = errno;
   1135  1.28   pooka 				host_close(newfd);
   1136  1.28   pooka 				errno = sverrno;
   1137  1.28   pooka 				return -1;
   1138  1.58   pooka 			}}
   1139  1.58   pooka #endif /* !USE_KQUEUE */
   1140  1.28   pooka 			clispc.spc_fd = newfd;
   1141  1.28   pooka 		}
   1142  1.58   pooka 		if (holyfd != -1 && fd == holyfd) {
   1143  1.58   pooka 			newfd = dupgood(holyfd, 1);
   1144  1.28   pooka 			if (newfd == -1)
   1145  1.28   pooka 				return -1;
   1146  1.58   pooka 			holyfd = newfd;
   1147  1.28   pooka 		}
   1148  1.28   pooka 		break;
   1149  1.28   pooka 	}
   1150  1.28   pooka 
   1151  1.28   pooka 	return 0;
   1152  1.28   pooka }
   1153  1.28   pooka 
   1154  1.30   pooka pid_t
   1155  1.46   joerg rumpclient_fork(void)
   1156  1.30   pooka {
   1157  1.30   pooka 
   1158  1.31   pooka 	return rumpclient__dofork(fork);
   1159  1.30   pooka }
   1160  1.30   pooka 
   1161  1.28   pooka /*
   1162  1.28   pooka  * Process is about to exec.  Save info about our existing connection
   1163  1.28   pooka  * in the env.  rumpclient will check for this info in init().
   1164  1.28   pooka  * This is mostly for the benefit of rumphijack, but regular applications
   1165  1.28   pooka  * may use it as well.
   1166  1.28   pooka  */
   1167  1.28   pooka int
   1168  1.30   pooka rumpclient_exec(const char *path, char *const argv[], char *const envp[])
   1169  1.28   pooka {
   1170  1.28   pooka 	char buf[4096];
   1171  1.28   pooka 	char **newenv;
   1172  1.28   pooka 	char *envstr, *envstr2;
   1173  1.30   pooka 	size_t nelem;
   1174  1.30   pooka 	int rv, sverrno;
   1175  1.28   pooka 
   1176  1.28   pooka 	snprintf(buf, sizeof(buf), "RUMPCLIENT__EXECFD=%d,%d",
   1177  1.58   pooka 	    clispc.spc_fd, holyfd);
   1178  1.28   pooka 	envstr = malloc(strlen(buf)+1);
   1179  1.28   pooka 	if (envstr == NULL) {
   1180  1.28   pooka 		return ENOMEM;
   1181  1.28   pooka 	}
   1182  1.28   pooka 	strcpy(envstr, buf);
   1183  1.28   pooka 
   1184  1.28   pooka 	/* do we have a fully parsed url we want to forward in the env? */
   1185  1.28   pooka 	if (*parsedurl != '\0') {
   1186  1.28   pooka 		snprintf(buf, sizeof(buf),
   1187  1.28   pooka 		    "RUMP__PARSEDSERVER=%s", parsedurl);
   1188  1.28   pooka 		envstr2 = malloc(strlen(buf)+1);
   1189  1.28   pooka 		if (envstr2 == NULL) {
   1190  1.28   pooka 			free(envstr);
   1191  1.28   pooka 			return ENOMEM;
   1192  1.28   pooka 		}
   1193  1.28   pooka 		strcpy(envstr2, buf);
   1194  1.28   pooka 	} else {
   1195  1.28   pooka 		envstr2 = NULL;
   1196  1.28   pooka 	}
   1197  1.28   pooka 
   1198  1.30   pooka 	for (nelem = 0; envp && envp[nelem]; nelem++)
   1199  1.30   pooka 		continue;
   1200  1.28   pooka 
   1201  1.33   pooka 	newenv = malloc(sizeof(*newenv) * (nelem+3));
   1202  1.28   pooka 	if (newenv == NULL) {
   1203  1.28   pooka 		free(envstr2);
   1204  1.28   pooka 		free(envstr);
   1205  1.28   pooka 		return ENOMEM;
   1206  1.28   pooka 	}
   1207  1.30   pooka 	memcpy(&newenv[0], envp, nelem*sizeof(*envp));
   1208  1.28   pooka 
   1209  1.30   pooka 	newenv[nelem] = envstr;
   1210  1.30   pooka 	newenv[nelem+1] = envstr2;
   1211  1.30   pooka 	newenv[nelem+2] = NULL;
   1212  1.30   pooka 
   1213  1.30   pooka 	rv = host_execve(path, argv, newenv);
   1214  1.30   pooka 
   1215  1.30   pooka 	_DIAGASSERT(rv != 0);
   1216  1.30   pooka 	sverrno = errno;
   1217  1.30   pooka 	free(envstr2);
   1218  1.30   pooka 	free(envstr);
   1219  1.30   pooka 	free(newenv);
   1220  1.30   pooka 	errno = sverrno;
   1221  1.30   pooka 	return rv;
   1222  1.28   pooka }
   1223  1.31   pooka 
   1224  1.54   pooka /*
   1225  1.54   pooka  * daemon() is handwritten for the benefit of platforms which
   1226  1.54   pooka  * do not support daemon().
   1227  1.54   pooka  */
   1228  1.31   pooka int
   1229  1.31   pooka rumpclient_daemon(int nochdir, int noclose)
   1230  1.31   pooka {
   1231  1.31   pooka 	struct rumpclient_fork *rf;
   1232  1.31   pooka 	int sverrno;
   1233  1.31   pooka 
   1234  1.31   pooka 	if ((rf = rumpclient_prefork()) == NULL)
   1235  1.31   pooka 		return -1;
   1236  1.31   pooka 
   1237  1.54   pooka 	switch (fork()) {
   1238  1.54   pooka 	case 0:
   1239  1.54   pooka 		break;
   1240  1.54   pooka 	case -1:
   1241  1.54   pooka 		goto daemonerr;
   1242  1.54   pooka 	default:
   1243  1.54   pooka 		_exit(0);
   1244  1.54   pooka 	}
   1245  1.54   pooka 
   1246  1.54   pooka 	if (setsid() == -1)
   1247  1.54   pooka 		goto daemonerr;
   1248  1.54   pooka 	if (!nochdir && chdir("/") == -1)
   1249  1.54   pooka 		goto daemonerr;
   1250  1.54   pooka 	if (!noclose) {
   1251  1.54   pooka 		int fd = open("/dev/null", O_RDWR);
   1252  1.54   pooka 		dup2(fd, 0);
   1253  1.54   pooka 		dup2(fd, 1);
   1254  1.54   pooka 		dup2(fd, 2);
   1255  1.54   pooka 		if (fd > 2)
   1256  1.54   pooka 			close(fd);
   1257  1.31   pooka 	}
   1258  1.31   pooka 
   1259  1.54   pooka 	/* note: fork is either completed or cancelled by the call */
   1260  1.31   pooka 	if (rumpclient_fork_init(rf) == -1)
   1261  1.31   pooka 		return -1;
   1262  1.31   pooka 
   1263  1.31   pooka 	return 0;
   1264  1.54   pooka 
   1265  1.54   pooka  daemonerr:
   1266  1.54   pooka 	sverrno = errno;
   1267  1.54   pooka 	rumpclient_fork_cancel(rf);
   1268  1.54   pooka 	errno = sverrno;
   1269  1.54   pooka 	return -1;
   1270  1.31   pooka }
   1271