Home | History | Annotate | Line # | Download | only in librumpclient
rumpclient.c revision 1.16.2.3
      1  1.16.2.3  bouyer /*      $NetBSD: rumpclient.c,v 1.16.2.3 2011/03/05 15:09:23 bouyer 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.1   pooka #include <sys/cdefs.h>
     33  1.16.2.3  bouyer __RCSID("$NetBSD: rumpclient.c,v 1.16.2.3 2011/03/05 15:09:23 bouyer Exp $");
     34       1.1   pooka 
     35       1.5   pooka #include <sys/param.h>
     36      1.15   pooka #include <sys/event.h>
     37       1.1   pooka #include <sys/mman.h>
     38       1.1   pooka #include <sys/socket.h>
     39       1.1   pooka 
     40       1.1   pooka #include <arpa/inet.h>
     41       1.1   pooka #include <netinet/in.h>
     42       1.1   pooka #include <netinet/tcp.h>
     43       1.1   pooka 
     44       1.1   pooka #include <assert.h>
     45      1.13   pooka #include <dlfcn.h>
     46  1.16.2.3  bouyer #include <err.h>
     47       1.1   pooka #include <errno.h>
     48       1.1   pooka #include <fcntl.h>
     49      1.13   pooka #include <link.h>
     50       1.1   pooka #include <poll.h>
     51       1.1   pooka #include <pthread.h>
     52      1.11   pooka #include <signal.h>
     53       1.1   pooka #include <stdarg.h>
     54  1.16.2.1  bouyer #include <stdbool.h>
     55       1.1   pooka #include <stdio.h>
     56       1.1   pooka #include <stdlib.h>
     57       1.1   pooka #include <string.h>
     58       1.1   pooka #include <unistd.h>
     59       1.1   pooka 
     60       1.1   pooka #include <rump/rumpclient.h>
     61       1.1   pooka 
     62      1.13   pooka #define HOSTOPS
     63      1.13   pooka int	(*host_socket)(int, int, int);
     64      1.13   pooka int	(*host_close)(int);
     65      1.13   pooka int	(*host_connect)(int, const struct sockaddr *, socklen_t);
     66      1.15   pooka int	(*host_fcntl)(int, int, ...);
     67      1.13   pooka int	(*host_poll)(struct pollfd *, nfds_t, int);
     68      1.13   pooka ssize_t	(*host_read)(int, void *, size_t);
     69      1.13   pooka ssize_t (*host_sendto)(int, const void *, size_t, int,
     70      1.13   pooka 		       const struct sockaddr *, socklen_t);
     71      1.13   pooka int	(*host_setsockopt)(int, int, int, const void *, socklen_t);
     72  1.16.2.2  bouyer int	(*host_dup)(int);
     73      1.13   pooka 
     74  1.16.2.1  bouyer int	(*host_kqueue)(void);
     75  1.16.2.1  bouyer int	(*host_kevent)(int, const struct kevent *, size_t,
     76  1.16.2.1  bouyer 		       struct kevent *, size_t, const struct timespec *);
     77  1.16.2.1  bouyer 
     78  1.16.2.2  bouyer int	(*host_execve)(const char *, char *const[], char *const[]);
     79  1.16.2.2  bouyer 
     80       1.1   pooka #include "sp_common.c"
     81       1.1   pooka 
     82      1.11   pooka static struct spclient clispc = {
     83      1.11   pooka 	.spc_fd = -1,
     84      1.11   pooka };
     85       1.1   pooka 
     86  1.16.2.1  bouyer static int kq = -1;
     87      1.15   pooka static sigset_t fullset;
     88      1.12   pooka 
     89  1.16.2.1  bouyer static int doconnect(bool);
     90  1.16.2.2  bouyer static int handshake_req(struct spclient *, int, void *, int, bool);
     91  1.16.2.1  bouyer 
     92  1.16.2.2  bouyer /*
     93  1.16.2.2  bouyer  * Default: don't retry.  Most clients can't handle it
     94  1.16.2.2  bouyer  * (consider e.g. fds suddenly going missing).
     95  1.16.2.2  bouyer  */
     96  1.16.2.2  bouyer static time_t retrytimo = 0;
     97  1.16.2.1  bouyer 
     98      1.12   pooka static int
     99  1.16.2.1  bouyer send_with_recon(struct spclient *spc, const void *data, size_t dlen)
    100      1.12   pooka {
    101  1.16.2.1  bouyer 	struct timeval starttime, curtime;
    102  1.16.2.1  bouyer 	time_t prevreconmsg;
    103  1.16.2.1  bouyer 	unsigned reconretries;
    104  1.16.2.1  bouyer 	int rv;
    105  1.16.2.1  bouyer 
    106  1.16.2.1  bouyer 	for (prevreconmsg = 0, reconretries = 0;;) {
    107  1.16.2.1  bouyer 		rv = dosend(spc, data, dlen);
    108  1.16.2.1  bouyer 		if (__predict_false(rv == ENOTCONN || rv == EBADF)) {
    109  1.16.2.1  bouyer 			/* no persistent connections */
    110  1.16.2.2  bouyer 			if (retrytimo == 0) {
    111  1.16.2.2  bouyer 				rv = ENOTCONN;
    112  1.16.2.1  bouyer 				break;
    113  1.16.2.2  bouyer 			}
    114  1.16.2.1  bouyer 			if (retrytimo == RUMPCLIENT_RETRYCONN_DIE)
    115  1.16.2.1  bouyer 				exit(1);
    116  1.16.2.1  bouyer 
    117  1.16.2.1  bouyer 			if (!prevreconmsg) {
    118  1.16.2.1  bouyer 				prevreconmsg = time(NULL);
    119  1.16.2.1  bouyer 				gettimeofday(&starttime, NULL);
    120  1.16.2.1  bouyer 			}
    121  1.16.2.1  bouyer 			if (reconretries == 1) {
    122  1.16.2.1  bouyer 				if (retrytimo == RUMPCLIENT_RETRYCONN_ONCE) {
    123  1.16.2.1  bouyer 					rv = ENOTCONN;
    124  1.16.2.1  bouyer 					break;
    125  1.16.2.1  bouyer 				}
    126  1.16.2.1  bouyer 				fprintf(stderr, "rump_sp: connection to "
    127  1.16.2.1  bouyer 				    "kernel lost, trying to reconnect ...\n");
    128  1.16.2.1  bouyer 			} else if (time(NULL) - prevreconmsg > 120) {
    129  1.16.2.1  bouyer 				fprintf(stderr, "rump_sp: still trying to "
    130  1.16.2.1  bouyer 				    "reconnect ...\n");
    131  1.16.2.1  bouyer 				prevreconmsg = time(NULL);
    132  1.16.2.1  bouyer 			}
    133  1.16.2.1  bouyer 
    134  1.16.2.1  bouyer 			/* check that we aren't over the limit */
    135  1.16.2.1  bouyer 			if (retrytimo > 0) {
    136  1.16.2.1  bouyer 				struct timeval tmp;
    137  1.16.2.1  bouyer 
    138  1.16.2.1  bouyer 				gettimeofday(&curtime, NULL);
    139  1.16.2.1  bouyer 				timersub(&curtime, &starttime, &tmp);
    140  1.16.2.1  bouyer 				if (tmp.tv_sec >= retrytimo) {
    141  1.16.2.1  bouyer 					fprintf(stderr, "rump_sp: reconnect "
    142  1.16.2.1  bouyer 					    "failed, %lld second timeout\n",
    143  1.16.2.1  bouyer 					    (long long)retrytimo);
    144  1.16.2.1  bouyer 					return ENOTCONN;
    145  1.16.2.1  bouyer 				}
    146  1.16.2.1  bouyer 			}
    147  1.16.2.1  bouyer 
    148  1.16.2.1  bouyer 			/* adhoc backoff timer */
    149  1.16.2.1  bouyer 			if (reconretries < 10) {
    150  1.16.2.1  bouyer 				usleep(100000 * reconretries);
    151  1.16.2.1  bouyer 			} else {
    152  1.16.2.1  bouyer 				sleep(MIN(10, reconretries-9));
    153  1.16.2.1  bouyer 			}
    154  1.16.2.1  bouyer 			reconretries++;
    155  1.16.2.1  bouyer 
    156  1.16.2.1  bouyer 			if ((rv = doconnect(false)) != 0)
    157  1.16.2.1  bouyer 				continue;
    158  1.16.2.2  bouyer 			if ((rv = handshake_req(&clispc, HANDSHAKE_GUEST,
    159  1.16.2.2  bouyer 			    NULL, 0, true)) != 0)
    160  1.16.2.1  bouyer 				continue;
    161  1.16.2.1  bouyer 
    162  1.16.2.1  bouyer 			/*
    163  1.16.2.1  bouyer 			 * ok, reconnect succesful.  we need to return to
    164  1.16.2.1  bouyer 			 * the upper layer to get the entire PDU resent.
    165  1.16.2.1  bouyer 			 */
    166  1.16.2.1  bouyer 			if (reconretries != 1)
    167  1.16.2.1  bouyer 				fprintf(stderr, "rump_sp: reconnected!\n");
    168  1.16.2.1  bouyer 			rv = EAGAIN;
    169  1.16.2.1  bouyer 			break;
    170  1.16.2.1  bouyer 		} else {
    171  1.16.2.1  bouyer 			_DIAGASSERT(errno != EAGAIN);
    172  1.16.2.1  bouyer 			break;
    173  1.16.2.1  bouyer 		}
    174  1.16.2.1  bouyer 	}
    175  1.16.2.1  bouyer 
    176  1.16.2.1  bouyer 	return rv;
    177  1.16.2.1  bouyer }
    178  1.16.2.1  bouyer 
    179  1.16.2.1  bouyer static int
    180  1.16.2.1  bouyer cliwaitresp(struct spclient *spc, struct respwait *rw, sigset_t *mask,
    181  1.16.2.1  bouyer 	bool keeplock)
    182  1.16.2.1  bouyer {
    183  1.16.2.1  bouyer 	uint64_t mygen;
    184  1.16.2.1  bouyer 	bool imalive = true;
    185      1.12   pooka 
    186      1.15   pooka 	pthread_mutex_lock(&spc->spc_mtx);
    187  1.16.2.1  bouyer 	if (!keeplock)
    188  1.16.2.1  bouyer 		sendunlockl(spc);
    189  1.16.2.1  bouyer 	mygen = spc->spc_generation;
    190      1.12   pooka 
    191      1.12   pooka 	rw->rw_error = 0;
    192  1.16.2.1  bouyer 	while (!rw->rw_done && rw->rw_error == 0) {
    193  1.16.2.1  bouyer 		if (__predict_false(spc->spc_generation != mygen || !imalive))
    194  1.16.2.1  bouyer 			break;
    195  1.16.2.1  bouyer 
    196      1.12   pooka 		/* are we free to receive? */
    197      1.12   pooka 		if (spc->spc_istatus == SPCSTATUS_FREE) {
    198      1.15   pooka 			struct kevent kev[8];
    199      1.15   pooka 			int gotresp, dosig, rv, i;
    200      1.15   pooka 
    201      1.12   pooka 			spc->spc_istatus = SPCSTATUS_BUSY;
    202      1.12   pooka 			pthread_mutex_unlock(&spc->spc_mtx);
    203      1.12   pooka 
    204      1.15   pooka 			dosig = 0;
    205      1.15   pooka 			for (gotresp = 0; !gotresp; ) {
    206      1.15   pooka 				switch (readframe(spc)) {
    207      1.15   pooka 				case 0:
    208  1.16.2.1  bouyer 					rv = host_kevent(kq, NULL, 0,
    209      1.15   pooka 					    kev, __arraycount(kev), NULL);
    210  1.16.2.1  bouyer 
    211  1.16.2.2  bouyer 					if (__predict_false(rv == -1)) {
    212  1.16.2.2  bouyer 						goto cleanup;
    213  1.16.2.2  bouyer 					}
    214  1.16.2.2  bouyer 
    215  1.16.2.1  bouyer 					/*
    216  1.16.2.1  bouyer 					 * XXX: don't know how this can
    217  1.16.2.1  bouyer 					 * happen (timeout cannot expire
    218  1.16.2.1  bouyer 					 * since there isn't one), but
    219  1.16.2.1  bouyer 					 * it does happen
    220  1.16.2.1  bouyer 					 */
    221  1.16.2.1  bouyer 					if (__predict_false(rv == 0))
    222  1.16.2.1  bouyer 						continue;
    223  1.16.2.1  bouyer 
    224      1.15   pooka 					for (i = 0; i < rv; i++) {
    225      1.15   pooka 						if (kev[i].filter
    226      1.15   pooka 						    == EVFILT_SIGNAL)
    227      1.15   pooka 							dosig++;
    228      1.15   pooka 					}
    229      1.15   pooka 					if (dosig)
    230      1.15   pooka 						goto cleanup;
    231      1.15   pooka 
    232      1.15   pooka 					continue;
    233      1.15   pooka 				case -1:
    234  1.16.2.1  bouyer 					imalive = false;
    235      1.15   pooka 					goto cleanup;
    236      1.15   pooka 				default:
    237      1.15   pooka 					break;
    238      1.15   pooka 				}
    239      1.12   pooka 
    240      1.15   pooka 				switch (spc->spc_hdr.rsp_class) {
    241      1.12   pooka 				case RUMPSP_RESP:
    242      1.12   pooka 				case RUMPSP_ERROR:
    243      1.12   pooka 					kickwaiter(spc);
    244      1.15   pooka 					gotresp = spc->spc_hdr.rsp_reqno ==
    245      1.15   pooka 					    rw->rw_reqno;
    246      1.12   pooka 					break;
    247      1.12   pooka 				case RUMPSP_REQ:
    248      1.12   pooka 					handlereq(spc);
    249      1.12   pooka 					break;
    250      1.12   pooka 				default:
    251      1.12   pooka 					/* panic */
    252      1.12   pooka 					break;
    253      1.15   pooka 				}
    254      1.12   pooka 			}
    255      1.12   pooka 
    256      1.15   pooka  cleanup:
    257      1.15   pooka 			pthread_mutex_lock(&spc->spc_mtx);
    258      1.15   pooka 			if (spc->spc_istatus == SPCSTATUS_WANTED)
    259      1.15   pooka 				kickall(spc);
    260      1.15   pooka 			spc->spc_istatus = SPCSTATUS_FREE;
    261      1.15   pooka 
    262      1.15   pooka 			/* take one for the team */
    263      1.15   pooka 			if (dosig) {
    264      1.15   pooka 				pthread_mutex_unlock(&spc->spc_mtx);
    265      1.15   pooka 				pthread_sigmask(SIG_SETMASK, mask, NULL);
    266      1.15   pooka 				pthread_sigmask(SIG_SETMASK, &fullset, NULL);
    267      1.15   pooka 				pthread_mutex_lock(&spc->spc_mtx);
    268      1.15   pooka 			}
    269      1.12   pooka 		} else {
    270      1.12   pooka 			spc->spc_istatus = SPCSTATUS_WANTED;
    271      1.12   pooka 			pthread_cond_wait(&rw->rw_cv, &spc->spc_mtx);
    272      1.12   pooka 		}
    273      1.12   pooka 	}
    274      1.12   pooka 	TAILQ_REMOVE(&spc->spc_respwait, rw, rw_entries);
    275      1.12   pooka 	pthread_mutex_unlock(&spc->spc_mtx);
    276      1.12   pooka 	pthread_cond_destroy(&rw->rw_cv);
    277      1.12   pooka 
    278  1.16.2.1  bouyer 	if (spc->spc_generation != mygen || !imalive) {
    279      1.12   pooka 		return ENOTCONN;
    280  1.16.2.1  bouyer 	}
    281      1.12   pooka 	return rw->rw_error;
    282      1.12   pooka }
    283      1.12   pooka 
    284       1.1   pooka static int
    285  1.16.2.1  bouyer syscall_req(struct spclient *spc, sigset_t *omask, int sysnum,
    286       1.3   pooka 	const void *data, size_t dlen, void **resp)
    287       1.1   pooka {
    288       1.1   pooka 	struct rsp_hdr rhdr;
    289       1.3   pooka 	struct respwait rw;
    290       1.3   pooka 	int rv;
    291       1.1   pooka 
    292       1.1   pooka 	rhdr.rsp_len = sizeof(rhdr) + dlen;
    293       1.3   pooka 	rhdr.rsp_class = RUMPSP_REQ;
    294       1.3   pooka 	rhdr.rsp_type = RUMPSP_SYSCALL;
    295       1.1   pooka 	rhdr.rsp_sysnum = sysnum;
    296       1.1   pooka 
    297       1.6   pooka 	do {
    298       1.6   pooka 		putwait(spc, &rw, &rhdr);
    299  1.16.2.1  bouyer 		if ((rv = send_with_recon(spc, &rhdr, sizeof(rhdr))) != 0) {
    300  1.16.2.1  bouyer 			unputwait(spc, &rw);
    301  1.16.2.1  bouyer 			continue;
    302  1.16.2.1  bouyer 		}
    303  1.16.2.1  bouyer 		if ((rv = send_with_recon(spc, data, dlen)) != 0) {
    304       1.6   pooka 			unputwait(spc, &rw);
    305  1.16.2.1  bouyer 			continue;
    306       1.6   pooka 		}
    307       1.6   pooka 
    308  1.16.2.1  bouyer 		rv = cliwaitresp(spc, &rw, omask, false);
    309  1.16.2.1  bouyer 		if (rv == ENOTCONN)
    310  1.16.2.1  bouyer 			rv = EAGAIN;
    311       1.6   pooka 	} while (rv == EAGAIN);
    312       1.3   pooka 
    313       1.3   pooka 	*resp = rw.rw_data;
    314       1.3   pooka 	return rv;
    315       1.1   pooka }
    316       1.1   pooka 
    317       1.1   pooka static int
    318  1.16.2.2  bouyer handshake_req(struct spclient *spc, int type, void *data,
    319  1.16.2.2  bouyer 	int cancel, bool haslock)
    320      1.10   pooka {
    321      1.11   pooka 	struct handshake_fork rf;
    322      1.10   pooka 	struct rsp_hdr rhdr;
    323      1.10   pooka 	struct respwait rw;
    324      1.12   pooka 	sigset_t omask;
    325  1.16.2.1  bouyer 	size_t bonus;
    326      1.10   pooka 	int rv;
    327      1.10   pooka 
    328  1.16.2.2  bouyer 	if (type == HANDSHAKE_FORK) {
    329  1.16.2.1  bouyer 		bonus = sizeof(rf);
    330  1.16.2.1  bouyer 	} else {
    331  1.16.2.1  bouyer 		bonus = strlen(getprogname())+1;
    332  1.16.2.1  bouyer 	}
    333  1.16.2.1  bouyer 
    334      1.10   pooka 	/* performs server handshake */
    335  1.16.2.1  bouyer 	rhdr.rsp_len = sizeof(rhdr) + bonus;
    336      1.10   pooka 	rhdr.rsp_class = RUMPSP_REQ;
    337      1.10   pooka 	rhdr.rsp_type = RUMPSP_HANDSHAKE;
    338  1.16.2.2  bouyer 	rhdr.rsp_handshake = type;
    339      1.10   pooka 
    340      1.12   pooka 	pthread_sigmask(SIG_SETMASK, &fullset, &omask);
    341  1.16.2.1  bouyer 	if (haslock)
    342  1.16.2.1  bouyer 		putwait_locked(spc, &rw, &rhdr);
    343  1.16.2.1  bouyer 	else
    344  1.16.2.1  bouyer 		putwait(spc, &rw, &rhdr);
    345      1.10   pooka 	rv = dosend(spc, &rhdr, sizeof(rhdr));
    346  1.16.2.2  bouyer 	if (type == HANDSHAKE_FORK) {
    347  1.16.2.2  bouyer 		memcpy(rf.rf_auth, data, sizeof(rf.rf_auth)); /* uh, why? */
    348      1.11   pooka 		rf.rf_cancel = cancel;
    349  1.16.2.1  bouyer 		rv = send_with_recon(spc, &rf, sizeof(rf));
    350  1.16.2.1  bouyer 	} else {
    351  1.16.2.1  bouyer 		rv = dosend(spc, getprogname(), strlen(getprogname())+1);
    352  1.16.2.1  bouyer 	}
    353  1.16.2.1  bouyer 	if (rv || cancel) {
    354  1.16.2.1  bouyer 		if (haslock)
    355  1.16.2.1  bouyer 			unputwait_locked(spc, &rw);
    356  1.16.2.1  bouyer 		else
    357  1.16.2.1  bouyer 			unputwait(spc, &rw);
    358  1.16.2.1  bouyer 		if (cancel) {
    359  1.16.2.1  bouyer 			goto out;
    360  1.16.2.1  bouyer 		}
    361  1.16.2.1  bouyer 	} else {
    362  1.16.2.1  bouyer 		rv = cliwaitresp(spc, &rw, &omask, haslock);
    363      1.10   pooka 	}
    364      1.10   pooka 	if (rv)
    365  1.16.2.1  bouyer 		goto out;
    366      1.10   pooka 
    367      1.10   pooka 	rv = *(int *)rw.rw_data;
    368      1.10   pooka 	free(rw.rw_data);
    369      1.10   pooka 
    370  1.16.2.1  bouyer  out:
    371  1.16.2.1  bouyer 	pthread_sigmask(SIG_SETMASK, &omask, NULL);
    372      1.10   pooka 	return rv;
    373      1.10   pooka }
    374      1.10   pooka 
    375      1.10   pooka static int
    376  1.16.2.1  bouyer prefork_req(struct spclient *spc, sigset_t *omask, void **resp)
    377      1.11   pooka {
    378      1.11   pooka 	struct rsp_hdr rhdr;
    379      1.11   pooka 	struct respwait rw;
    380      1.11   pooka 	int rv;
    381      1.11   pooka 
    382      1.11   pooka 	rhdr.rsp_len = sizeof(rhdr);
    383      1.11   pooka 	rhdr.rsp_class = RUMPSP_REQ;
    384      1.11   pooka 	rhdr.rsp_type = RUMPSP_PREFORK;
    385      1.11   pooka 	rhdr.rsp_error = 0;
    386      1.11   pooka 
    387  1.16.2.1  bouyer 	do {
    388  1.16.2.1  bouyer 		putwait(spc, &rw, &rhdr);
    389  1.16.2.1  bouyer 		rv = send_with_recon(spc, &rhdr, sizeof(rhdr));
    390  1.16.2.1  bouyer 		if (rv != 0) {
    391  1.16.2.1  bouyer 			unputwait(spc, &rw);
    392  1.16.2.1  bouyer 			continue;
    393  1.16.2.1  bouyer 		}
    394  1.16.2.1  bouyer 
    395  1.16.2.1  bouyer 		rv = cliwaitresp(spc, &rw, omask, false);
    396  1.16.2.1  bouyer 		if (rv == ENOTCONN)
    397  1.16.2.1  bouyer 			rv = EAGAIN;
    398  1.16.2.1  bouyer 	} while (rv == EAGAIN);
    399      1.11   pooka 
    400      1.11   pooka 	*resp = rw.rw_data;
    401      1.11   pooka 	return rv;
    402      1.11   pooka }
    403      1.11   pooka 
    404  1.16.2.1  bouyer /*
    405  1.16.2.1  bouyer  * prevent response code from deadlocking with reconnect code
    406  1.16.2.1  bouyer  */
    407      1.11   pooka static int
    408  1.16.2.1  bouyer resp_sendlock(struct spclient *spc)
    409  1.16.2.1  bouyer {
    410  1.16.2.1  bouyer 	int rv = 0;
    411  1.16.2.1  bouyer 
    412  1.16.2.1  bouyer 	pthread_mutex_lock(&spc->spc_mtx);
    413  1.16.2.1  bouyer 	while (spc->spc_ostatus != SPCSTATUS_FREE) {
    414  1.16.2.1  bouyer 		if (__predict_false(spc->spc_reconnecting)) {
    415  1.16.2.1  bouyer 			rv = EBUSY;
    416  1.16.2.1  bouyer 			goto out;
    417  1.16.2.1  bouyer 		}
    418  1.16.2.1  bouyer 		spc->spc_ostatus = SPCSTATUS_WANTED;
    419  1.16.2.1  bouyer 		pthread_cond_wait(&spc->spc_cv, &spc->spc_mtx);
    420  1.16.2.1  bouyer 	}
    421  1.16.2.1  bouyer 	spc->spc_ostatus = SPCSTATUS_BUSY;
    422  1.16.2.1  bouyer 
    423  1.16.2.1  bouyer  out:
    424  1.16.2.1  bouyer 	pthread_mutex_unlock(&spc->spc_mtx);
    425  1.16.2.1  bouyer 	return rv;
    426  1.16.2.1  bouyer }
    427  1.16.2.1  bouyer 
    428  1.16.2.1  bouyer static void
    429       1.5   pooka send_copyin_resp(struct spclient *spc, uint64_t reqno, void *data, size_t dlen,
    430       1.5   pooka 	int wantstr)
    431       1.1   pooka {
    432       1.1   pooka 	struct rsp_hdr rhdr;
    433       1.1   pooka 
    434       1.5   pooka 	if (wantstr)
    435       1.5   pooka 		dlen = MIN(dlen, strlen(data)+1);
    436       1.5   pooka 
    437       1.1   pooka 	rhdr.rsp_len = sizeof(rhdr) + dlen;
    438       1.1   pooka 	rhdr.rsp_reqno = reqno;
    439       1.3   pooka 	rhdr.rsp_class = RUMPSP_RESP;
    440       1.3   pooka 	rhdr.rsp_type = RUMPSP_COPYIN;
    441       1.1   pooka 	rhdr.rsp_sysnum = 0;
    442       1.1   pooka 
    443  1.16.2.1  bouyer 	if (resp_sendlock(spc) != 0)
    444  1.16.2.1  bouyer 		return;
    445  1.16.2.1  bouyer 	(void)dosend(spc, &rhdr, sizeof(rhdr));
    446  1.16.2.1  bouyer 	(void)dosend(spc, data, dlen);
    447       1.3   pooka 	sendunlock(spc);
    448       1.1   pooka }
    449       1.1   pooka 
    450  1.16.2.1  bouyer static void
    451       1.1   pooka send_anonmmap_resp(struct spclient *spc, uint64_t reqno, void *addr)
    452       1.1   pooka {
    453       1.1   pooka 	struct rsp_hdr rhdr;
    454       1.1   pooka 
    455       1.1   pooka 	rhdr.rsp_len = sizeof(rhdr) + sizeof(addr);
    456       1.1   pooka 	rhdr.rsp_reqno = reqno;
    457       1.3   pooka 	rhdr.rsp_class = RUMPSP_RESP;
    458       1.3   pooka 	rhdr.rsp_type = RUMPSP_ANONMMAP;
    459       1.1   pooka 	rhdr.rsp_sysnum = 0;
    460       1.1   pooka 
    461  1.16.2.1  bouyer 	if (resp_sendlock(spc) != 0)
    462  1.16.2.1  bouyer 		return;
    463  1.16.2.1  bouyer 	(void)dosend(spc, &rhdr, sizeof(rhdr));
    464  1.16.2.1  bouyer 	(void)dosend(spc, &addr, sizeof(addr));
    465       1.3   pooka 	sendunlock(spc);
    466       1.1   pooka }
    467       1.1   pooka 
    468       1.1   pooka int
    469       1.1   pooka rumpclient_syscall(int sysnum, const void *data, size_t dlen,
    470       1.1   pooka 	register_t *retval)
    471       1.1   pooka {
    472       1.1   pooka 	struct rsp_sysresp *resp;
    473  1.16.2.1  bouyer 	sigset_t omask;
    474       1.3   pooka 	void *rdata;
    475       1.3   pooka 	int rv;
    476       1.3   pooka 
    477  1.16.2.1  bouyer 	pthread_sigmask(SIG_SETMASK, &fullset, &omask);
    478  1.16.2.1  bouyer 
    479       1.3   pooka 	DPRINTF(("rumpsp syscall_req: syscall %d with %p/%zu\n",
    480       1.3   pooka 	    sysnum, data, dlen));
    481       1.3   pooka 
    482  1.16.2.1  bouyer 	rv = syscall_req(&clispc, &omask, sysnum, data, dlen, &rdata);
    483       1.3   pooka 	if (rv)
    484  1.16.2.1  bouyer 		goto out;
    485       1.3   pooka 
    486       1.3   pooka 	resp = rdata;
    487       1.3   pooka 	DPRINTF(("rumpsp syscall_resp: syscall %d error %d, rv: %d/%d\n",
    488       1.3   pooka 	    sysnum, rv, resp->rsys_retval[0], resp->rsys_retval[1]));
    489       1.1   pooka 
    490       1.3   pooka 	memcpy(retval, &resp->rsys_retval, sizeof(resp->rsys_retval));
    491       1.3   pooka 	rv = resp->rsys_error;
    492       1.3   pooka 	free(rdata);
    493       1.1   pooka 
    494  1.16.2.1  bouyer  out:
    495  1.16.2.1  bouyer 	pthread_sigmask(SIG_SETMASK, &omask, NULL);
    496       1.3   pooka 	return rv;
    497       1.3   pooka }
    498       1.1   pooka 
    499       1.3   pooka static void
    500       1.3   pooka handlereq(struct spclient *spc)
    501       1.3   pooka {
    502       1.3   pooka 	struct rsp_copydata *copydata;
    503      1.16   pooka 	struct rsp_hdr *rhdr = &spc->spc_hdr;
    504       1.3   pooka 	void *mapaddr;
    505       1.3   pooka 	size_t maplen;
    506       1.5   pooka 	int reqtype = spc->spc_hdr.rsp_type;
    507       1.1   pooka 
    508       1.5   pooka 	switch (reqtype) {
    509       1.3   pooka 	case RUMPSP_COPYIN:
    510       1.5   pooka 	case RUMPSP_COPYINSTR:
    511       1.3   pooka 		/*LINTED*/
    512       1.3   pooka 		copydata = (struct rsp_copydata *)spc->spc_buf;
    513       1.3   pooka 		DPRINTF(("rump_sp handlereq: copyin request: %p/%zu\n",
    514       1.3   pooka 		    copydata->rcp_addr, copydata->rcp_len));
    515       1.3   pooka 		send_copyin_resp(spc, spc->spc_hdr.rsp_reqno,
    516       1.5   pooka 		    copydata->rcp_addr, copydata->rcp_len,
    517       1.5   pooka 		    reqtype == RUMPSP_COPYINSTR);
    518       1.3   pooka 		break;
    519       1.3   pooka 	case RUMPSP_COPYOUT:
    520       1.5   pooka 	case RUMPSP_COPYOUTSTR:
    521       1.3   pooka 		/*LINTED*/
    522       1.3   pooka 		copydata = (struct rsp_copydata *)spc->spc_buf;
    523       1.3   pooka 		DPRINTF(("rump_sp handlereq: copyout request: %p/%zu\n",
    524       1.3   pooka 		    copydata->rcp_addr, copydata->rcp_len));
    525       1.3   pooka 		/*LINTED*/
    526       1.3   pooka 		memcpy(copydata->rcp_addr, copydata->rcp_data,
    527       1.3   pooka 		    copydata->rcp_len);
    528       1.3   pooka 		break;
    529       1.3   pooka 	case RUMPSP_ANONMMAP:
    530       1.3   pooka 		/*LINTED*/
    531       1.3   pooka 		maplen = *(size_t *)spc->spc_buf;
    532       1.3   pooka 		mapaddr = mmap(NULL, maplen, PROT_READ|PROT_WRITE,
    533       1.3   pooka 		    MAP_ANON, -1, 0);
    534       1.3   pooka 		if (mapaddr == MAP_FAILED)
    535       1.3   pooka 			mapaddr = NULL;
    536       1.3   pooka 		DPRINTF(("rump_sp handlereq: anonmmap: %p\n", mapaddr));
    537       1.3   pooka 		send_anonmmap_resp(spc, spc->spc_hdr.rsp_reqno, mapaddr);
    538       1.3   pooka 		break;
    539      1.16   pooka 	case RUMPSP_RAISE:
    540      1.16   pooka 		DPRINTF(("rump_sp handlereq: raise sig %d\n", rhdr->rsp_signo));
    541  1.16.2.1  bouyer 		raise((int)rhdr->rsp_signo);
    542      1.16   pooka 		/*
    543      1.16   pooka 		 * We most likely have signals blocked, but the signal
    544      1.16   pooka 		 * will be handled soon enough when we return.
    545      1.16   pooka 		 */
    546      1.16   pooka 		break;
    547       1.3   pooka 	default:
    548      1.12   pooka 		printf("PANIC: INVALID TYPE %d\n", reqtype);
    549       1.3   pooka 		abort();
    550       1.3   pooka 		break;
    551       1.1   pooka 	}
    552       1.1   pooka 
    553       1.6   pooka 	spcfreebuf(spc);
    554       1.1   pooka }
    555       1.1   pooka 
    556      1.11   pooka static unsigned ptab_idx;
    557      1.11   pooka static struct sockaddr *serv_sa;
    558      1.11   pooka 
    559  1.16.2.2  bouyer /* dup until we get a "good" fd which does not collide with stdio */
    560  1.16.2.2  bouyer static int
    561  1.16.2.2  bouyer dupgood(int myfd, int mustchange)
    562  1.16.2.2  bouyer {
    563  1.16.2.2  bouyer 	int ofds[4];
    564  1.16.2.2  bouyer 	int i;
    565  1.16.2.2  bouyer 
    566  1.16.2.2  bouyer 	for (i = 0; (myfd <= 2 || mustchange) && myfd != -1; i++) {
    567  1.16.2.2  bouyer 		assert(i < __arraycount(ofds));
    568  1.16.2.2  bouyer 		ofds[i] = myfd;
    569  1.16.2.2  bouyer 		myfd = host_dup(myfd);
    570  1.16.2.2  bouyer 		if (mustchange) {
    571  1.16.2.2  bouyer 			i--; /* prevent closing old fd */
    572  1.16.2.2  bouyer 			mustchange = 0;
    573  1.16.2.2  bouyer 		}
    574  1.16.2.2  bouyer 	}
    575  1.16.2.2  bouyer 
    576  1.16.2.2  bouyer 	for (i--; i >= 0; i--) {
    577  1.16.2.2  bouyer 		host_close(ofds[i]);
    578  1.16.2.2  bouyer 	}
    579  1.16.2.2  bouyer 
    580  1.16.2.2  bouyer 	return myfd;
    581  1.16.2.2  bouyer }
    582  1.16.2.2  bouyer 
    583      1.11   pooka static int
    584  1.16.2.1  bouyer doconnect(bool noisy)
    585       1.1   pooka {
    586  1.16.2.1  bouyer 	struct respwait rw;
    587  1.16.2.1  bouyer 	struct rsp_hdr rhdr;
    588      1.15   pooka 	struct kevent kev[NSIG+1];
    589       1.9   pooka 	char banner[MAXBANNER];
    590  1.16.2.1  bouyer 	struct pollfd pfd;
    591      1.15   pooka 	int s, error, flags, i;
    592       1.9   pooka 	ssize_t n;
    593       1.1   pooka 
    594  1.16.2.1  bouyer 	if (kq != -1)
    595  1.16.2.1  bouyer 		host_close(kq);
    596  1.16.2.1  bouyer 	kq = -1;
    597  1.16.2.1  bouyer 	s = -1;
    598  1.16.2.1  bouyer 
    599  1.16.2.1  bouyer 	if (clispc.spc_fd != -1)
    600  1.16.2.1  bouyer 		host_close(clispc.spc_fd);
    601  1.16.2.1  bouyer 	clispc.spc_fd = -1;
    602  1.16.2.1  bouyer 
    603  1.16.2.1  bouyer 	/*
    604  1.16.2.1  bouyer 	 * for reconnect, gate everyone out of the receiver code
    605  1.16.2.1  bouyer 	 */
    606  1.16.2.1  bouyer 	putwait_locked(&clispc, &rw, &rhdr);
    607  1.16.2.1  bouyer 
    608  1.16.2.1  bouyer 	pthread_mutex_lock(&clispc.spc_mtx);
    609  1.16.2.1  bouyer 	clispc.spc_reconnecting = 1;
    610  1.16.2.1  bouyer 	pthread_cond_broadcast(&clispc.spc_cv);
    611  1.16.2.1  bouyer 	clispc.spc_generation++;
    612  1.16.2.1  bouyer 	while (clispc.spc_istatus != SPCSTATUS_FREE) {
    613  1.16.2.1  bouyer 		clispc.spc_istatus = SPCSTATUS_WANTED;
    614  1.16.2.1  bouyer 		pthread_cond_wait(&rw.rw_cv, &clispc.spc_mtx);
    615  1.16.2.1  bouyer 	}
    616  1.16.2.1  bouyer 	kickall(&clispc);
    617  1.16.2.1  bouyer 
    618  1.16.2.1  bouyer 	/*
    619  1.16.2.1  bouyer 	 * we can release it already since we hold the
    620  1.16.2.1  bouyer 	 * send lock during reconnect
    621  1.16.2.1  bouyer 	 * XXX: assert it
    622  1.16.2.1  bouyer 	 */
    623  1.16.2.1  bouyer 	clispc.spc_istatus = SPCSTATUS_FREE;
    624  1.16.2.1  bouyer 	pthread_mutex_unlock(&clispc.spc_mtx);
    625  1.16.2.1  bouyer 	unputwait_locked(&clispc, &rw);
    626  1.16.2.1  bouyer 
    627  1.16.2.1  bouyer 	free(clispc.spc_buf);
    628  1.16.2.1  bouyer 	clispc.spc_off = 0;
    629  1.16.2.1  bouyer 
    630  1.16.2.2  bouyer 	s = dupgood(host_socket(parsetab[ptab_idx].domain, SOCK_STREAM, 0), 0);
    631      1.11   pooka 	if (s == -1)
    632       1.2   pooka 		return -1;
    633       1.1   pooka 
    634  1.16.2.1  bouyer 	pfd.fd = s;
    635  1.16.2.1  bouyer 	pfd.events = POLLIN;
    636  1.16.2.1  bouyer 	while (host_connect(s, serv_sa, (socklen_t)serv_sa->sa_len) == -1) {
    637  1.16.2.1  bouyer 		if (errno == EINTR)
    638  1.16.2.1  bouyer 			continue;
    639      1.11   pooka 		error = errno;
    640  1.16.2.1  bouyer 		if (noisy)
    641  1.16.2.1  bouyer 			fprintf(stderr, "rump_sp: client connect failed: %s\n",
    642  1.16.2.1  bouyer 			    strerror(errno));
    643       1.2   pooka 		errno = error;
    644       1.2   pooka 		return -1;
    645       1.2   pooka 	}
    646       1.1   pooka 
    647      1.11   pooka 	if ((error = parsetab[ptab_idx].connhook(s)) != 0) {
    648       1.2   pooka 		error = errno;
    649  1.16.2.1  bouyer 		if (noisy)
    650  1.16.2.1  bouyer 			fprintf(stderr, "rump_sp: connect hook failed\n");
    651       1.2   pooka 		errno = error;
    652       1.2   pooka 		return -1;
    653       1.1   pooka 	}
    654       1.4   pooka 
    655      1.13   pooka 	if ((n = host_read(s, banner, sizeof(banner)-1)) < 0) {
    656       1.2   pooka 		error = errno;
    657  1.16.2.1  bouyer 		if (noisy)
    658  1.16.2.1  bouyer 			fprintf(stderr, "rump_sp: failed to read banner\n");
    659       1.2   pooka 		errno = error;
    660       1.2   pooka 		return -1;
    661       1.1   pooka 	}
    662       1.9   pooka 
    663       1.9   pooka 	if (banner[n-1] != '\n') {
    664  1.16.2.1  bouyer 		if (noisy)
    665  1.16.2.1  bouyer 			fprintf(stderr, "rump_sp: invalid banner\n");
    666       1.9   pooka 		errno = EINVAL;
    667       1.9   pooka 		return -1;
    668       1.9   pooka 	}
    669       1.9   pooka 	banner[n] = '\0';
    670  1.16.2.1  bouyer 	/* parse the banner some day */
    671       1.9   pooka 
    672      1.15   pooka 	flags = host_fcntl(s, F_GETFL, 0);
    673      1.15   pooka 	if (host_fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) {
    674  1.16.2.1  bouyer 		if (noisy)
    675  1.16.2.1  bouyer 			fprintf(stderr, "rump_sp: socket fd NONBLOCK: %s\n",
    676  1.16.2.1  bouyer 			    strerror(errno));
    677      1.15   pooka 		errno = EINVAL;
    678      1.15   pooka 		return -1;
    679      1.15   pooka 	}
    680  1.16.2.1  bouyer 	clispc.spc_fd = s;
    681  1.16.2.1  bouyer 	clispc.spc_state = SPCSTATE_RUNNING;
    682  1.16.2.1  bouyer 	clispc.spc_reconnecting = 0;
    683       1.9   pooka 
    684      1.15   pooka 	/* setup kqueue, we want all signals and the fd */
    685  1.16.2.2  bouyer 	if ((kq = dupgood(host_kqueue(), 0)) == -1) {
    686      1.15   pooka 		error = errno;
    687  1.16.2.1  bouyer 		if (noisy)
    688  1.16.2.1  bouyer 			fprintf(stderr, "rump_sp: cannot setup kqueue");
    689      1.15   pooka 		errno = error;
    690      1.15   pooka 		return -1;
    691      1.15   pooka 	}
    692      1.15   pooka 
    693      1.15   pooka 	for (i = 0; i < NSIG; i++) {
    694      1.15   pooka 		EV_SET(&kev[i], i+1, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0);
    695      1.15   pooka 	}
    696  1.16.2.1  bouyer 	EV_SET(&kev[NSIG], clispc.spc_fd,
    697  1.16.2.1  bouyer 	    EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0);
    698  1.16.2.1  bouyer 	if (host_kevent(kq, kev, NSIG+1, NULL, 0, NULL) == -1) {
    699      1.15   pooka 		error = errno;
    700  1.16.2.1  bouyer 		if (noisy)
    701  1.16.2.1  bouyer 			fprintf(stderr, "rump_sp: kevent() failed");
    702      1.15   pooka 		errno = error;
    703      1.15   pooka 		return -1;
    704      1.15   pooka 	}
    705      1.15   pooka 
    706  1.16.2.1  bouyer 	return 0;
    707  1.16.2.1  bouyer }
    708  1.16.2.1  bouyer 
    709  1.16.2.1  bouyer static int
    710  1.16.2.1  bouyer doinit(void)
    711  1.16.2.1  bouyer {
    712  1.16.2.1  bouyer 
    713      1.11   pooka 	TAILQ_INIT(&clispc.spc_respwait);
    714      1.11   pooka 	pthread_mutex_init(&clispc.spc_mtx, NULL);
    715      1.11   pooka 	pthread_cond_init(&clispc.spc_cv, NULL);
    716      1.11   pooka 
    717      1.11   pooka 	return 0;
    718      1.11   pooka }
    719      1.11   pooka 
    720  1.16.2.3  bouyer void *rumpclient__dlsym(void *, const char *);
    721  1.16.2.3  bouyer void *rumphijack_dlsym(void *, const char *);
    722  1.16.2.3  bouyer void *
    723  1.16.2.3  bouyer rumpclient__dlsym(void *handle, const char *symbol)
    724  1.16.2.3  bouyer {
    725  1.16.2.3  bouyer 
    726  1.16.2.3  bouyer 	return dlsym(handle, symbol);
    727  1.16.2.3  bouyer }
    728  1.16.2.3  bouyer __weak_alias(rumphijack_dlsym,rumpclient__dlsym);
    729  1.16.2.3  bouyer 
    730  1.16.2.3  bouyer static pid_t init_done = 0;
    731      1.13   pooka 
    732      1.11   pooka int
    733      1.11   pooka rumpclient_init()
    734      1.11   pooka {
    735      1.11   pooka 	char *p;
    736      1.11   pooka 	int error;
    737  1.16.2.2  bouyer 	int rv = -1;
    738  1.16.2.2  bouyer 	int hstype;
    739  1.16.2.3  bouyer 	pid_t mypid;
    740  1.16.2.2  bouyer 
    741  1.16.2.3  bouyer 	/*
    742  1.16.2.3  bouyer 	 * Make sure we're not riding the context of a previous
    743  1.16.2.3  bouyer 	 * host fork.  Note: it's *possible* that after n>1 forks
    744  1.16.2.3  bouyer 	 * we have the same pid as one of our exited parents, but
    745  1.16.2.3  bouyer 	 * I'm pretty sure there are 0 practical implications, since
    746  1.16.2.3  bouyer 	 * it means generations would have to skip rumpclient init.
    747  1.16.2.3  bouyer 	 */
    748  1.16.2.3  bouyer 	if (init_done == (mypid = getpid()))
    749  1.16.2.2  bouyer 		return 0;
    750      1.11   pooka 
    751  1.16.2.3  bouyer 	/* kq does not traverse fork() */
    752  1.16.2.3  bouyer 	if (init_done != 0)
    753  1.16.2.3  bouyer 		kq = -1;
    754  1.16.2.3  bouyer 	init_done = mypid;
    755  1.16.2.1  bouyer 
    756  1.16.2.3  bouyer 	sigfillset(&fullset);
    757      1.13   pooka 
    758      1.13   pooka 	/*
    759      1.13   pooka 	 * sag mir, wo die symbol sind.  zogen fort, der krieg beginnt.
    760      1.13   pooka 	 * wann wird man je verstehen?  wann wird man je verstehen?
    761      1.13   pooka 	 */
    762      1.13   pooka #define FINDSYM2(_name_,_syscall_)					\
    763  1.16.2.3  bouyer 	if ((host_##_name_ = rumphijack_dlsym(RTLD_NEXT,		\
    764  1.16.2.3  bouyer 	    #_syscall_)) == NULL) {					\
    765  1.16.2.3  bouyer 		if (rumphijack_dlsym == rumpclient__dlsym)		\
    766  1.16.2.3  bouyer 			host_##_name_ = _name_; /* static fallback */	\
    767  1.16.2.3  bouyer 		if (host_##_name_ == NULL)				\
    768  1.16.2.3  bouyer 			errx(1, "cannot find %s: %s", #_syscall_,	\
    769  1.16.2.3  bouyer 			    dlerror());					\
    770  1.16.2.3  bouyer 	}
    771      1.13   pooka #define FINDSYM(_name_) FINDSYM2(_name_,_name_)
    772  1.16.2.3  bouyer 	FINDSYM2(socket,__socket30)
    773  1.16.2.3  bouyer 	FINDSYM(close)
    774  1.16.2.3  bouyer 	FINDSYM(connect)
    775  1.16.2.3  bouyer 	FINDSYM(fcntl)
    776  1.16.2.3  bouyer 	FINDSYM(poll)
    777  1.16.2.3  bouyer 	FINDSYM(read)
    778  1.16.2.3  bouyer 	FINDSYM(sendto)
    779  1.16.2.3  bouyer 	FINDSYM(setsockopt)
    780  1.16.2.3  bouyer 	FINDSYM(dup)
    781  1.16.2.3  bouyer 	FINDSYM(kqueue)
    782  1.16.2.3  bouyer 	FINDSYM(execve)
    783  1.16.2.1  bouyer #if !__NetBSD_Prereq__(5,99,7)
    784  1.16.2.3  bouyer 	FINDSYM(kevent)
    785  1.16.2.1  bouyer #else
    786  1.16.2.3  bouyer 	FINDSYM2(kevent,_sys___kevent50)
    787  1.16.2.1  bouyer #endif
    788      1.13   pooka #undef	FINDSYM
    789      1.13   pooka #undef	FINDSY2
    790      1.13   pooka 
    791  1.16.2.2  bouyer 	if ((p = getenv("RUMP__PARSEDSERVER")) == NULL) {
    792  1.16.2.2  bouyer 		if ((p = getenv("RUMP_SERVER")) == NULL) {
    793  1.16.2.2  bouyer 			errno = ENOENT;
    794  1.16.2.2  bouyer 			goto out;
    795  1.16.2.2  bouyer 		}
    796      1.11   pooka 	}
    797      1.11   pooka 
    798      1.11   pooka 	if ((error = parseurl(p, &serv_sa, &ptab_idx, 0)) != 0) {
    799      1.11   pooka 		errno = error;
    800  1.16.2.2  bouyer 		goto out;
    801      1.11   pooka 	}
    802      1.11   pooka 
    803  1.16.2.1  bouyer 	if (doinit() == -1)
    804  1.16.2.2  bouyer 		goto out;
    805  1.16.2.2  bouyer 
    806  1.16.2.2  bouyer 	if ((p = getenv("RUMPCLIENT__EXECFD")) != NULL) {
    807  1.16.2.2  bouyer 		sscanf(p, "%d,%d", &clispc.spc_fd, &kq);
    808  1.16.2.2  bouyer 		unsetenv("RUMPCLIENT__EXECFD");
    809  1.16.2.2  bouyer 		hstype = HANDSHAKE_EXEC;
    810  1.16.2.2  bouyer 	} else {
    811  1.16.2.2  bouyer 		if (doconnect(true) == -1)
    812  1.16.2.2  bouyer 			goto out;
    813  1.16.2.2  bouyer 		hstype = HANDSHAKE_GUEST;
    814  1.16.2.2  bouyer 	}
    815      1.11   pooka 
    816  1.16.2.2  bouyer 	error = handshake_req(&clispc, hstype, NULL, 0, false);
    817      1.11   pooka 	if (error) {
    818      1.11   pooka 		pthread_mutex_destroy(&clispc.spc_mtx);
    819      1.11   pooka 		pthread_cond_destroy(&clispc.spc_cv);
    820  1.16.2.1  bouyer 		if (clispc.spc_fd != -1)
    821  1.16.2.1  bouyer 			host_close(clispc.spc_fd);
    822      1.10   pooka 		errno = error;
    823  1.16.2.2  bouyer 		goto out;
    824      1.10   pooka 	}
    825  1.16.2.2  bouyer 	rv = 0;
    826      1.10   pooka 
    827  1.16.2.2  bouyer  out:
    828  1.16.2.2  bouyer 	if (rv == -1)
    829  1.16.2.2  bouyer 		init_done = 0;
    830  1.16.2.2  bouyer 	return rv;
    831      1.11   pooka }
    832      1.11   pooka 
    833      1.11   pooka struct rumpclient_fork {
    834      1.11   pooka 	uint32_t fork_auth[AUTHLEN];
    835  1.16.2.2  bouyer 	struct spclient fork_spc;
    836  1.16.2.2  bouyer 	int fork_kq;
    837      1.11   pooka };
    838      1.11   pooka 
    839      1.11   pooka struct rumpclient_fork *
    840      1.11   pooka rumpclient_prefork(void)
    841      1.11   pooka {
    842      1.11   pooka 	struct rumpclient_fork *rpf;
    843  1.16.2.1  bouyer 	sigset_t omask;
    844      1.11   pooka 	void *resp;
    845      1.11   pooka 	int rv;
    846      1.11   pooka 
    847  1.16.2.1  bouyer 	pthread_sigmask(SIG_SETMASK, &fullset, &omask);
    848      1.11   pooka 	rpf = malloc(sizeof(*rpf));
    849      1.11   pooka 	if (rpf == NULL)
    850  1.16.2.2  bouyer 		goto out;
    851      1.11   pooka 
    852  1.16.2.1  bouyer 	if ((rv = prefork_req(&clispc, &omask, &resp)) != 0) {
    853      1.11   pooka 		free(rpf);
    854      1.11   pooka 		errno = rv;
    855  1.16.2.1  bouyer 		rpf = NULL;
    856  1.16.2.1  bouyer 		goto out;
    857      1.11   pooka 	}
    858      1.11   pooka 
    859      1.11   pooka 	memcpy(rpf->fork_auth, resp, sizeof(rpf->fork_auth));
    860      1.11   pooka 	free(resp);
    861      1.11   pooka 
    862  1.16.2.2  bouyer 	rpf->fork_spc = clispc;
    863  1.16.2.2  bouyer 	rpf->fork_kq = kq;
    864  1.16.2.2  bouyer 
    865  1.16.2.1  bouyer  out:
    866  1.16.2.1  bouyer 	pthread_sigmask(SIG_SETMASK, &omask, NULL);
    867      1.11   pooka 	return rpf;
    868      1.11   pooka }
    869      1.11   pooka 
    870      1.11   pooka int
    871      1.11   pooka rumpclient_fork_init(struct rumpclient_fork *rpf)
    872      1.11   pooka {
    873      1.11   pooka 	int error;
    874  1.16.2.1  bouyer 	int osock;
    875      1.11   pooka 
    876  1.16.2.1  bouyer 	osock = clispc.spc_fd;
    877      1.11   pooka 	memset(&clispc, 0, sizeof(clispc));
    878  1.16.2.1  bouyer 	clispc.spc_fd = osock;
    879  1.16.2.1  bouyer 
    880  1.16.2.1  bouyer 	kq = -1; /* kqueue descriptor is not copied over fork() */
    881      1.11   pooka 
    882  1.16.2.1  bouyer 	if (doinit() == -1)
    883  1.16.2.1  bouyer 		return -1;
    884  1.16.2.1  bouyer 	if (doconnect(false) == -1)
    885      1.11   pooka 		return -1;
    886      1.10   pooka 
    887  1.16.2.2  bouyer 	error = handshake_req(&clispc, HANDSHAKE_FORK, rpf->fork_auth,
    888  1.16.2.2  bouyer 	    0, false);
    889      1.10   pooka 	if (error) {
    890      1.10   pooka 		pthread_mutex_destroy(&clispc.spc_mtx);
    891      1.10   pooka 		pthread_cond_destroy(&clispc.spc_cv);
    892      1.11   pooka 		errno = error;
    893      1.11   pooka 		return -1;
    894      1.10   pooka 	}
    895      1.11   pooka 
    896      1.11   pooka 	return 0;
    897       1.1   pooka }
    898  1.16.2.1  bouyer 
    899  1.16.2.1  bouyer void
    900  1.16.2.2  bouyer rumpclient_fork_cancel(struct rumpclient_fork *rpf)
    901  1.16.2.2  bouyer {
    902  1.16.2.2  bouyer 
    903  1.16.2.2  bouyer 	/* EUNIMPL */
    904  1.16.2.2  bouyer }
    905  1.16.2.2  bouyer 
    906  1.16.2.2  bouyer void
    907  1.16.2.2  bouyer rumpclient_fork_vparent(struct rumpclient_fork *rpf)
    908  1.16.2.2  bouyer {
    909  1.16.2.2  bouyer 
    910  1.16.2.2  bouyer 	clispc = rpf->fork_spc;
    911  1.16.2.2  bouyer 	kq = rpf->fork_kq;
    912  1.16.2.2  bouyer }
    913  1.16.2.2  bouyer 
    914  1.16.2.2  bouyer void
    915  1.16.2.1  bouyer rumpclient_setconnretry(time_t timeout)
    916  1.16.2.1  bouyer {
    917  1.16.2.1  bouyer 
    918  1.16.2.1  bouyer 	if (timeout < RUMPCLIENT_RETRYCONN_DIE)
    919  1.16.2.1  bouyer 		return; /* gigo */
    920  1.16.2.1  bouyer 
    921  1.16.2.1  bouyer 	retrytimo = timeout;
    922  1.16.2.1  bouyer }
    923  1.16.2.2  bouyer 
    924  1.16.2.2  bouyer int
    925  1.16.2.2  bouyer rumpclient__closenotify(int *fdp, enum rumpclient_closevariant variant)
    926  1.16.2.2  bouyer {
    927  1.16.2.2  bouyer 	int fd = *fdp;
    928  1.16.2.2  bouyer 	int untilfd, rv;
    929  1.16.2.2  bouyer 	int newfd;
    930  1.16.2.2  bouyer 
    931  1.16.2.2  bouyer 	switch (variant) {
    932  1.16.2.2  bouyer 	case RUMPCLIENT_CLOSE_FCLOSEM:
    933  1.16.2.2  bouyer 		untilfd = MAX(clispc.spc_fd, kq);
    934  1.16.2.2  bouyer 		for (; fd <= untilfd; fd++) {
    935  1.16.2.2  bouyer 			if (fd == clispc.spc_fd || fd == kq)
    936  1.16.2.2  bouyer 				continue;
    937  1.16.2.2  bouyer 			rv = host_close(fd);
    938  1.16.2.2  bouyer 			if (rv == -1)
    939  1.16.2.2  bouyer 				return -1;
    940  1.16.2.2  bouyer 		}
    941  1.16.2.2  bouyer 		*fdp = fd;
    942  1.16.2.2  bouyer 		break;
    943  1.16.2.2  bouyer 
    944  1.16.2.2  bouyer 	case RUMPCLIENT_CLOSE_CLOSE:
    945  1.16.2.2  bouyer 	case RUMPCLIENT_CLOSE_DUP2:
    946  1.16.2.2  bouyer 		if (fd == clispc.spc_fd) {
    947  1.16.2.2  bouyer 			struct kevent kev[2];
    948  1.16.2.2  bouyer 
    949  1.16.2.2  bouyer 			newfd = dupgood(clispc.spc_fd, 1);
    950  1.16.2.2  bouyer 			if (newfd == -1)
    951  1.16.2.2  bouyer 				return -1;
    952  1.16.2.2  bouyer 			/*
    953  1.16.2.2  bouyer 			 * now, we have a new socket number, so change
    954  1.16.2.2  bouyer 			 * the file descriptor that kqueue is
    955  1.16.2.2  bouyer 			 * monitoring.  remove old and add new.
    956  1.16.2.2  bouyer 			 */
    957  1.16.2.2  bouyer 			EV_SET(&kev[0], clispc.spc_fd,
    958  1.16.2.2  bouyer 			    EVFILT_READ, EV_DELETE, 0, 0, 0);
    959  1.16.2.2  bouyer 			EV_SET(&kev[1], newfd,
    960  1.16.2.2  bouyer 			    EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0);
    961  1.16.2.2  bouyer 			if (host_kevent(kq, kev, 2, NULL, 0, NULL) == -1) {
    962  1.16.2.2  bouyer 				int sverrno = errno;
    963  1.16.2.2  bouyer 				host_close(newfd);
    964  1.16.2.2  bouyer 				errno = sverrno;
    965  1.16.2.2  bouyer 				return -1;
    966  1.16.2.2  bouyer 			}
    967  1.16.2.2  bouyer 			clispc.spc_fd = newfd;
    968  1.16.2.2  bouyer 		}
    969  1.16.2.2  bouyer 		if (fd == kq) {
    970  1.16.2.2  bouyer 			newfd = dupgood(kq, 1);
    971  1.16.2.2  bouyer 			if (newfd == -1)
    972  1.16.2.2  bouyer 				return -1;
    973  1.16.2.2  bouyer 			kq = newfd;
    974  1.16.2.2  bouyer 		}
    975  1.16.2.2  bouyer 		break;
    976  1.16.2.2  bouyer 	}
    977  1.16.2.2  bouyer 
    978  1.16.2.2  bouyer 	return 0;
    979  1.16.2.2  bouyer }
    980  1.16.2.2  bouyer 
    981  1.16.2.2  bouyer pid_t
    982  1.16.2.2  bouyer rumpclient_fork()
    983  1.16.2.2  bouyer {
    984  1.16.2.2  bouyer 
    985  1.16.2.2  bouyer 	return rumpclient__dofork(fork);
    986  1.16.2.2  bouyer }
    987  1.16.2.2  bouyer 
    988  1.16.2.2  bouyer /*
    989  1.16.2.2  bouyer  * Process is about to exec.  Save info about our existing connection
    990  1.16.2.2  bouyer  * in the env.  rumpclient will check for this info in init().
    991  1.16.2.2  bouyer  * This is mostly for the benefit of rumphijack, but regular applications
    992  1.16.2.2  bouyer  * may use it as well.
    993  1.16.2.2  bouyer  */
    994  1.16.2.2  bouyer int
    995  1.16.2.2  bouyer rumpclient_exec(const char *path, char *const argv[], char *const envp[])
    996  1.16.2.2  bouyer {
    997  1.16.2.2  bouyer 	char buf[4096];
    998  1.16.2.2  bouyer 	char **newenv;
    999  1.16.2.2  bouyer 	char *envstr, *envstr2;
   1000  1.16.2.2  bouyer 	size_t nelem;
   1001  1.16.2.2  bouyer 	int rv, sverrno;
   1002  1.16.2.2  bouyer 
   1003  1.16.2.2  bouyer 	snprintf(buf, sizeof(buf), "RUMPCLIENT__EXECFD=%d,%d",
   1004  1.16.2.2  bouyer 	    clispc.spc_fd, kq);
   1005  1.16.2.2  bouyer 	envstr = malloc(strlen(buf)+1);
   1006  1.16.2.2  bouyer 	if (envstr == NULL) {
   1007  1.16.2.2  bouyer 		return ENOMEM;
   1008  1.16.2.2  bouyer 	}
   1009  1.16.2.2  bouyer 	strcpy(envstr, buf);
   1010  1.16.2.2  bouyer 
   1011  1.16.2.2  bouyer 	/* do we have a fully parsed url we want to forward in the env? */
   1012  1.16.2.2  bouyer 	if (*parsedurl != '\0') {
   1013  1.16.2.2  bouyer 		snprintf(buf, sizeof(buf),
   1014  1.16.2.2  bouyer 		    "RUMP__PARSEDSERVER=%s", parsedurl);
   1015  1.16.2.2  bouyer 		envstr2 = malloc(strlen(buf)+1);
   1016  1.16.2.2  bouyer 		if (envstr2 == NULL) {
   1017  1.16.2.2  bouyer 			free(envstr);
   1018  1.16.2.2  bouyer 			return ENOMEM;
   1019  1.16.2.2  bouyer 		}
   1020  1.16.2.2  bouyer 		strcpy(envstr2, buf);
   1021  1.16.2.2  bouyer 	} else {
   1022  1.16.2.2  bouyer 		envstr2 = NULL;
   1023  1.16.2.2  bouyer 	}
   1024  1.16.2.2  bouyer 
   1025  1.16.2.2  bouyer 	for (nelem = 0; envp && envp[nelem]; nelem++)
   1026  1.16.2.2  bouyer 		continue;
   1027  1.16.2.2  bouyer 
   1028  1.16.2.3  bouyer 	newenv = malloc(sizeof(*newenv) * (nelem+3));
   1029  1.16.2.2  bouyer 	if (newenv == NULL) {
   1030  1.16.2.2  bouyer 		free(envstr2);
   1031  1.16.2.2  bouyer 		free(envstr);
   1032  1.16.2.2  bouyer 		return ENOMEM;
   1033  1.16.2.2  bouyer 	}
   1034  1.16.2.2  bouyer 	memcpy(&newenv[0], envp, nelem*sizeof(*envp));
   1035  1.16.2.2  bouyer 
   1036  1.16.2.2  bouyer 	newenv[nelem] = envstr;
   1037  1.16.2.2  bouyer 	newenv[nelem+1] = envstr2;
   1038  1.16.2.2  bouyer 	newenv[nelem+2] = NULL;
   1039  1.16.2.2  bouyer 
   1040  1.16.2.2  bouyer 	rv = host_execve(path, argv, newenv);
   1041  1.16.2.2  bouyer 
   1042  1.16.2.2  bouyer 	_DIAGASSERT(rv != 0);
   1043  1.16.2.2  bouyer 	sverrno = errno;
   1044  1.16.2.2  bouyer 	free(envstr2);
   1045  1.16.2.2  bouyer 	free(envstr);
   1046  1.16.2.2  bouyer 	free(newenv);
   1047  1.16.2.2  bouyer 	errno = sverrno;
   1048  1.16.2.2  bouyer 	return rv;
   1049  1.16.2.2  bouyer }
   1050  1.16.2.2  bouyer 
   1051  1.16.2.2  bouyer int
   1052  1.16.2.2  bouyer rumpclient_daemon(int nochdir, int noclose)
   1053  1.16.2.2  bouyer {
   1054  1.16.2.2  bouyer 	struct rumpclient_fork *rf;
   1055  1.16.2.2  bouyer 	int sverrno;
   1056  1.16.2.2  bouyer 
   1057  1.16.2.2  bouyer 	if ((rf = rumpclient_prefork()) == NULL)
   1058  1.16.2.2  bouyer 		return -1;
   1059  1.16.2.2  bouyer 
   1060  1.16.2.2  bouyer 	if (daemon(nochdir, noclose) == -1) {
   1061  1.16.2.2  bouyer 		sverrno = errno;
   1062  1.16.2.2  bouyer 		rumpclient_fork_cancel(rf);
   1063  1.16.2.2  bouyer 		errno = sverrno;
   1064  1.16.2.2  bouyer 		return -1;
   1065  1.16.2.2  bouyer 	}
   1066  1.16.2.2  bouyer 
   1067  1.16.2.2  bouyer 	if (rumpclient_fork_init(rf) == -1)
   1068  1.16.2.2  bouyer 		return -1;
   1069  1.16.2.2  bouyer 
   1070  1.16.2.2  bouyer 	return 0;
   1071  1.16.2.2  bouyer }
   1072