Home | History | Annotate | Line # | Download | only in librumpclient
rumpclient.c revision 1.18
      1 /*      $NetBSD: rumpclient.c,v 1.18 2011/01/24 17:47:51 pooka Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2010, 2011 Antti Kantee.  All Rights Reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     16  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     18  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25  * SUCH DAMAGE.
     26  */
     27 
     28 /*
     29  * Client side routines for rump syscall proxy.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __RCSID("$NetBSD");
     34 
     35 #include <sys/param.h>
     36 #include <sys/event.h>
     37 #include <sys/mman.h>
     38 #include <sys/socket.h>
     39 
     40 #include <arpa/inet.h>
     41 #include <netinet/in.h>
     42 #include <netinet/tcp.h>
     43 
     44 #include <assert.h>
     45 #include <dlfcn.h>
     46 #include <errno.h>
     47 #include <fcntl.h>
     48 #include <link.h>
     49 #include <poll.h>
     50 #include <pthread.h>
     51 #include <signal.h>
     52 #include <stdarg.h>
     53 #include <stdbool.h>
     54 #include <stdio.h>
     55 #include <stdlib.h>
     56 #include <string.h>
     57 #include <unistd.h>
     58 
     59 #include <rump/rumpclient.h>
     60 
     61 #define HOSTOPS
     62 int	(*host_socket)(int, int, int);
     63 int	(*host_close)(int);
     64 int	(*host_connect)(int, const struct sockaddr *, socklen_t);
     65 int	(*host_fcntl)(int, int, ...);
     66 int	(*host_poll)(struct pollfd *, nfds_t, int);
     67 ssize_t	(*host_read)(int, void *, size_t);
     68 ssize_t (*host_sendto)(int, const void *, size_t, int,
     69 		       const struct sockaddr *, socklen_t);
     70 int	(*host_setsockopt)(int, int, int, const void *, socklen_t);
     71 
     72 int	(*host_kqueue)(void);
     73 int	(*host_kevent)(int, const struct kevent *, size_t,
     74 		       struct kevent *, size_t, const struct timespec *);
     75 
     76 #include "sp_common.c"
     77 
     78 static struct spclient clispc = {
     79 	.spc_fd = -1,
     80 };
     81 
     82 static int kq = -1;
     83 static sigset_t fullset;
     84 
     85 static int doconnect(int);
     86 static int handshake_req(struct spclient *, uint32_t *, int, bool);
     87 
     88 int didrecon;
     89 
     90 static int
     91 send_with_recon(struct spclient *spc, const void *data, size_t dlen)
     92 {
     93 	int rv;
     94 
     95 	do {
     96 		rv = dosend(spc, data, dlen);
     97 		if (__predict_false(rv == ENOTCONN || rv == EBADF)) {
     98 			if ((rv = doconnect(1)) != 0)
     99 				continue;
    100 			if ((rv = handshake_req(&clispc, NULL, 0, true)) != 0)
    101 				continue;
    102 			rv = ENOTCONN;
    103 			break;
    104 		}
    105 	} while (__predict_false(rv != 0));
    106 
    107 	return rv;
    108 }
    109 
    110 static int
    111 cliwaitresp(struct spclient *spc, struct respwait *rw, sigset_t *mask,
    112 	bool keeplock)
    113 {
    114 	uint64_t mygen;
    115 	bool imalive = true;
    116 
    117 	pthread_mutex_lock(&spc->spc_mtx);
    118 	if (!keeplock)
    119 		sendunlockl(spc);
    120 	mygen = spc->spc_generation;
    121 
    122 	rw->rw_error = 0;
    123 	while (!rw->rw_done && rw->rw_error == 0) {
    124 		if (__predict_false(spc->spc_generation != mygen || !imalive))
    125 			break;
    126 
    127 		/* are we free to receive? */
    128 		if (spc->spc_istatus == SPCSTATUS_FREE) {
    129 			struct kevent kev[8];
    130 			int gotresp, dosig, rv, i;
    131 
    132 			spc->spc_istatus = SPCSTATUS_BUSY;
    133 			pthread_mutex_unlock(&spc->spc_mtx);
    134 
    135 			dosig = 0;
    136 			for (gotresp = 0; !gotresp; ) {
    137 				switch (readframe(spc)) {
    138 				case 0:
    139 					rv = host_kevent(kq, NULL, 0,
    140 					    kev, __arraycount(kev), NULL);
    141 
    142 					/*
    143 					 * XXX: don't know how this can
    144 					 * happen (timeout cannot expire
    145 					 * since there isn't one), but
    146 					 * it does happen
    147 					 */
    148 					if (__predict_false(rv == 0))
    149 						continue;
    150 
    151 					for (i = 0; i < rv; i++) {
    152 						if (kev[i].filter
    153 						    == EVFILT_SIGNAL)
    154 							dosig++;
    155 					}
    156 					if (dosig)
    157 						goto cleanup;
    158 
    159 					continue;
    160 				case -1:
    161 					imalive = false;
    162 					goto cleanup;
    163 				default:
    164 					break;
    165 				}
    166 
    167 				switch (spc->spc_hdr.rsp_class) {
    168 				case RUMPSP_RESP:
    169 				case RUMPSP_ERROR:
    170 					kickwaiter(spc);
    171 					gotresp = spc->spc_hdr.rsp_reqno ==
    172 					    rw->rw_reqno;
    173 					break;
    174 				case RUMPSP_REQ:
    175 					handlereq(spc);
    176 					break;
    177 				default:
    178 					/* panic */
    179 					break;
    180 				}
    181 			}
    182 
    183  cleanup:
    184 			pthread_mutex_lock(&spc->spc_mtx);
    185 			if (spc->spc_istatus == SPCSTATUS_WANTED)
    186 				kickall(spc);
    187 			spc->spc_istatus = SPCSTATUS_FREE;
    188 
    189 			/* take one for the team */
    190 			if (dosig) {
    191 				pthread_mutex_unlock(&spc->spc_mtx);
    192 				pthread_sigmask(SIG_SETMASK, mask, NULL);
    193 				pthread_sigmask(SIG_SETMASK, &fullset, NULL);
    194 				pthread_mutex_lock(&spc->spc_mtx);
    195 			}
    196 		} else {
    197 			spc->spc_istatus = SPCSTATUS_WANTED;
    198 			pthread_cond_wait(&rw->rw_cv, &spc->spc_mtx);
    199 		}
    200 	}
    201 	TAILQ_REMOVE(&spc->spc_respwait, rw, rw_entries);
    202 	pthread_mutex_unlock(&spc->spc_mtx);
    203 	pthread_cond_destroy(&rw->rw_cv);
    204 
    205 	if (spc->spc_generation != mygen || !imalive) {
    206 		return ENOTCONN;
    207 	}
    208 	return rw->rw_error;
    209 }
    210 
    211 static int
    212 syscall_req(struct spclient *spc, int sysnum,
    213 	const void *data, size_t dlen, void **resp)
    214 {
    215 	struct rsp_hdr rhdr;
    216 	struct respwait rw;
    217 	sigset_t omask;
    218 	int rv;
    219 
    220 	rhdr.rsp_len = sizeof(rhdr) + dlen;
    221 	rhdr.rsp_class = RUMPSP_REQ;
    222 	rhdr.rsp_type = RUMPSP_SYSCALL;
    223 	rhdr.rsp_sysnum = sysnum;
    224 
    225 	pthread_sigmask(SIG_SETMASK, &fullset, &omask);
    226 	do {
    227 		putwait(spc, &rw, &rhdr);
    228 		if ((rv = send_with_recon(spc, &rhdr, sizeof(rhdr))) != 0) {
    229 			unputwait(spc, &rw);
    230 			continue;
    231 		}
    232 		if ((rv = send_with_recon(spc, data, dlen)) != 0) {
    233 			unputwait(spc, &rw);
    234 			continue;
    235 		}
    236 
    237 		rv = cliwaitresp(spc, &rw, &omask, false);
    238 	} while (rv == ENOTCONN || rv == EAGAIN);
    239 	pthread_sigmask(SIG_SETMASK, &omask, NULL);
    240 
    241 	*resp = rw.rw_data;
    242 	return rv;
    243 }
    244 
    245 static int
    246 handshake_req(struct spclient *spc, uint32_t *auth, int cancel, bool haslock)
    247 {
    248 	struct handshake_fork rf;
    249 	struct rsp_hdr rhdr;
    250 	struct respwait rw;
    251 	sigset_t omask;
    252 	int rv;
    253 
    254 	/* performs server handshake */
    255 	rhdr.rsp_len = sizeof(rhdr) + (auth ? sizeof(rf) : 0);
    256 	rhdr.rsp_class = RUMPSP_REQ;
    257 	rhdr.rsp_type = RUMPSP_HANDSHAKE;
    258 	if (auth)
    259 		rhdr.rsp_handshake = HANDSHAKE_FORK;
    260 	else
    261 		rhdr.rsp_handshake = HANDSHAKE_GUEST;
    262 
    263 	pthread_sigmask(SIG_SETMASK, &fullset, &omask);
    264 	if (haslock)
    265 		putwait_locked(spc, &rw, &rhdr);
    266 	else
    267 		putwait(spc, &rw, &rhdr);
    268 	rv = dosend(spc, &rhdr, sizeof(rhdr));
    269 	if (auth) {
    270 		memcpy(rf.rf_auth, auth, AUTHLEN*sizeof(*auth));
    271 		rf.rf_cancel = cancel;
    272 		rv = send_with_recon(spc, &rf, sizeof(rf));
    273 	}
    274 	if (rv || cancel) {
    275 		if (haslock)
    276 			unputwait_locked(spc, &rw);
    277 		else
    278 			unputwait(spc, &rw);
    279 		if (cancel) {
    280 			pthread_sigmask(SIG_SETMASK, &omask, NULL);
    281 			return rv;
    282 		}
    283 	} else {
    284 		rv = cliwaitresp(spc, &rw, &omask, haslock);
    285 	}
    286 	pthread_sigmask(SIG_SETMASK, &omask, NULL);
    287 	if (rv)
    288 		return rv;
    289 
    290 	rv = *(int *)rw.rw_data;
    291 	free(rw.rw_data);
    292 
    293 	return rv;
    294 }
    295 
    296 static int
    297 prefork_req(struct spclient *spc, void **resp)
    298 {
    299 	struct rsp_hdr rhdr;
    300 	struct respwait rw;
    301 	sigset_t omask;
    302 	int rv;
    303 
    304 	rhdr.rsp_len = sizeof(rhdr);
    305 	rhdr.rsp_class = RUMPSP_REQ;
    306 	rhdr.rsp_type = RUMPSP_PREFORK;
    307 	rhdr.rsp_error = 0;
    308 
    309 	pthread_sigmask(SIG_SETMASK, &fullset, &omask);
    310 	do {
    311 		putwait(spc, &rw, &rhdr);
    312 		rv = send_with_recon(spc, &rhdr, sizeof(rhdr));
    313 		if (rv != 0) {
    314 			unputwait(spc, &rw);
    315 			continue;
    316 		}
    317 
    318 		rv = cliwaitresp(spc, &rw, &omask, false);
    319 	} while (rv == ENOTCONN || rv == EAGAIN);
    320 	pthread_sigmask(SIG_SETMASK, &omask, NULL);
    321 
    322 	*resp = rw.rw_data;
    323 	return rv;
    324 }
    325 
    326 /*
    327  * prevent response code from deadlocking with reconnect code
    328  */
    329 static int
    330 resp_sendlock(struct spclient *spc)
    331 {
    332 	int rv = 0;
    333 
    334 	pthread_mutex_lock(&spc->spc_mtx);
    335 	while (spc->spc_ostatus != SPCSTATUS_FREE) {
    336 		if (__predict_false(spc->spc_reconnecting)) {
    337 			rv = EBUSY;
    338 			goto out;
    339 		}
    340 		spc->spc_ostatus = SPCSTATUS_WANTED;
    341 		pthread_cond_wait(&spc->spc_cv, &spc->spc_mtx);
    342 	}
    343 	spc->spc_ostatus = SPCSTATUS_BUSY;
    344 
    345  out:
    346 	pthread_mutex_unlock(&spc->spc_mtx);
    347 	return rv;
    348 }
    349 
    350 static void
    351 send_copyin_resp(struct spclient *spc, uint64_t reqno, void *data, size_t dlen,
    352 	int wantstr)
    353 {
    354 	struct rsp_hdr rhdr;
    355 
    356 	if (wantstr)
    357 		dlen = MIN(dlen, strlen(data)+1);
    358 
    359 	rhdr.rsp_len = sizeof(rhdr) + dlen;
    360 	rhdr.rsp_reqno = reqno;
    361 	rhdr.rsp_class = RUMPSP_RESP;
    362 	rhdr.rsp_type = RUMPSP_COPYIN;
    363 	rhdr.rsp_sysnum = 0;
    364 
    365 	if (resp_sendlock(spc) != 0)
    366 		return;
    367 	(void)dosend(spc, &rhdr, sizeof(rhdr));
    368 	(void)dosend(spc, data, dlen);
    369 	sendunlock(spc);
    370 }
    371 
    372 static void
    373 send_anonmmap_resp(struct spclient *spc, uint64_t reqno, void *addr)
    374 {
    375 	struct rsp_hdr rhdr;
    376 
    377 	rhdr.rsp_len = sizeof(rhdr) + sizeof(addr);
    378 	rhdr.rsp_reqno = reqno;
    379 	rhdr.rsp_class = RUMPSP_RESP;
    380 	rhdr.rsp_type = RUMPSP_ANONMMAP;
    381 	rhdr.rsp_sysnum = 0;
    382 
    383 	if (resp_sendlock(spc) != 0)
    384 		return;
    385 	(void)dosend(spc, &rhdr, sizeof(rhdr));
    386 	(void)dosend(spc, &addr, sizeof(addr));
    387 	sendunlock(spc);
    388 }
    389 
    390 int
    391 rumpclient_syscall(int sysnum, const void *data, size_t dlen,
    392 	register_t *retval)
    393 {
    394 	struct rsp_sysresp *resp;
    395 	void *rdata;
    396 	int rv;
    397 
    398 	DPRINTF(("rumpsp syscall_req: syscall %d with %p/%zu\n",
    399 	    sysnum, data, dlen));
    400 
    401 	rv = syscall_req(&clispc, sysnum, data, dlen, &rdata);
    402 	if (rv)
    403 		return rv;
    404 
    405 	resp = rdata;
    406 	DPRINTF(("rumpsp syscall_resp: syscall %d error %d, rv: %d/%d\n",
    407 	    sysnum, rv, resp->rsys_retval[0], resp->rsys_retval[1]));
    408 
    409 	memcpy(retval, &resp->rsys_retval, sizeof(resp->rsys_retval));
    410 	rv = resp->rsys_error;
    411 	free(rdata);
    412 
    413 	return rv;
    414 }
    415 
    416 static void
    417 handlereq(struct spclient *spc)
    418 {
    419 	struct rsp_copydata *copydata;
    420 	struct rsp_hdr *rhdr = &spc->spc_hdr;
    421 	void *mapaddr;
    422 	size_t maplen;
    423 	int reqtype = spc->spc_hdr.rsp_type;
    424 
    425 	switch (reqtype) {
    426 	case RUMPSP_COPYIN:
    427 	case RUMPSP_COPYINSTR:
    428 		/*LINTED*/
    429 		copydata = (struct rsp_copydata *)spc->spc_buf;
    430 		DPRINTF(("rump_sp handlereq: copyin request: %p/%zu\n",
    431 		    copydata->rcp_addr, copydata->rcp_len));
    432 		send_copyin_resp(spc, spc->spc_hdr.rsp_reqno,
    433 		    copydata->rcp_addr, copydata->rcp_len,
    434 		    reqtype == RUMPSP_COPYINSTR);
    435 		break;
    436 	case RUMPSP_COPYOUT:
    437 	case RUMPSP_COPYOUTSTR:
    438 		/*LINTED*/
    439 		copydata = (struct rsp_copydata *)spc->spc_buf;
    440 		DPRINTF(("rump_sp handlereq: copyout request: %p/%zu\n",
    441 		    copydata->rcp_addr, copydata->rcp_len));
    442 		/*LINTED*/
    443 		memcpy(copydata->rcp_addr, copydata->rcp_data,
    444 		    copydata->rcp_len);
    445 		break;
    446 	case RUMPSP_ANONMMAP:
    447 		/*LINTED*/
    448 		maplen = *(size_t *)spc->spc_buf;
    449 		mapaddr = mmap(NULL, maplen, PROT_READ|PROT_WRITE,
    450 		    MAP_ANON, -1, 0);
    451 		if (mapaddr == MAP_FAILED)
    452 			mapaddr = NULL;
    453 		DPRINTF(("rump_sp handlereq: anonmmap: %p\n", mapaddr));
    454 		send_anonmmap_resp(spc, spc->spc_hdr.rsp_reqno, mapaddr);
    455 		break;
    456 	case RUMPSP_RAISE:
    457 		DPRINTF(("rump_sp handlereq: raise sig %d\n", rhdr->rsp_signo));
    458 		raise((int)rhdr->rsp_signo);
    459 		/*
    460 		 * We most likely have signals blocked, but the signal
    461 		 * will be handled soon enough when we return.
    462 		 */
    463 		break;
    464 	default:
    465 		printf("PANIC: INVALID TYPE %d\n", reqtype);
    466 		abort();
    467 		break;
    468 	}
    469 
    470 	spcfreebuf(spc);
    471 }
    472 
    473 static unsigned ptab_idx;
    474 static struct sockaddr *serv_sa;
    475 
    476 static int
    477 doconnect(int retry)
    478 {
    479 	time_t prevreconmsg;
    480 	unsigned reconretries;
    481 	struct respwait rw;
    482 	struct rsp_hdr rhdr;
    483 	struct kevent kev[NSIG+1];
    484 	char banner[MAXBANNER];
    485 	struct pollfd pfd;
    486 	int s, error, flags, i;
    487 	ssize_t n;
    488 
    489 	if (kq != -1)
    490 		host_close(kq);
    491 	kq = -1;
    492 
    493 	prevreconmsg = 0;
    494 	reconretries = 0;
    495 
    496  again:
    497 	if (clispc.spc_fd != -1)
    498 		host_close(clispc.spc_fd);
    499 	clispc.spc_fd = -1;
    500 
    501 	/*
    502 	 * for reconnect, gate everyone out of the receiver code
    503 	 */
    504 	putwait_locked(&clispc, &rw, &rhdr);
    505 
    506 	pthread_mutex_lock(&clispc.spc_mtx);
    507 	clispc.spc_reconnecting = 1;
    508 	pthread_cond_broadcast(&clispc.spc_cv);
    509 	clispc.spc_generation++;
    510 	while (clispc.spc_istatus != SPCSTATUS_FREE) {
    511 		clispc.spc_istatus = SPCSTATUS_WANTED;
    512 		pthread_cond_wait(&rw.rw_cv, &clispc.spc_mtx);
    513 	}
    514 	kickall(&clispc);
    515 
    516 	/*
    517 	 * we can release it already since we hold the
    518 	 * send lock during reconnect
    519 	 * XXX: assert it
    520 	 */
    521 	clispc.spc_istatus = SPCSTATUS_FREE;
    522 	pthread_mutex_unlock(&clispc.spc_mtx);
    523 	unputwait_locked(&clispc, &rw);
    524 
    525 	free(clispc.spc_buf);
    526 	clispc.spc_off = 0;
    527 
    528 	s = host_socket(parsetab[ptab_idx].domain, SOCK_STREAM, 0);
    529 	if (s == -1)
    530 		return -1;
    531 
    532 	pfd.fd = s;
    533 	pfd.events = POLLIN;
    534 	while (host_connect(s, serv_sa, (socklen_t)serv_sa->sa_len) == -1) {
    535 		if (errno == EINTR)
    536 			continue;
    537 		if (!retry) {
    538 			error = errno;
    539 			fprintf(stderr, "rump_sp: client connect failed: %s\n",
    540 			    strerror(errno));
    541 			errno = error;
    542 			return -1;
    543 		}
    544 
    545 		if (prevreconmsg == 0) {
    546 			fprintf(stderr, "rump_sp: connection to kernel lost, "
    547 			    "trying to reconnect ...\n");
    548 			prevreconmsg = time(NULL);
    549 		}
    550 		if (time(NULL) - prevreconmsg > 120) {
    551 			fprintf(stderr, "rump_sp: still trying to "
    552 			    "reconnect ...\n");
    553 			prevreconmsg = time(NULL);
    554 		}
    555 
    556 		/* adhoc backoff timer */
    557 		if (reconretries++ < 10) {
    558 			usleep(100000 * reconretries);
    559 		} else {
    560 			sleep(MIN(10, reconretries-9));
    561 		}
    562 		goto again;
    563 	}
    564 
    565 	if ((error = parsetab[ptab_idx].connhook(s)) != 0) {
    566 		error = errno;
    567 		fprintf(stderr, "rump_sp: connect hook failed\n");
    568 		errno = error;
    569 		return -1;
    570 	}
    571 
    572 	if ((n = host_read(s, banner, sizeof(banner)-1)) < 0) {
    573 		error = errno;
    574 		fprintf(stderr, "rump_sp: failed to read banner\n");
    575 		errno = error;
    576 		return -1;
    577 	}
    578 
    579 	if (banner[n-1] != '\n') {
    580 		fprintf(stderr, "rump_sp: invalid banner\n");
    581 		errno = EINVAL;
    582 		return -1;
    583 	}
    584 	banner[n] = '\0';
    585 	/* parse the banner some day */
    586 
    587 	flags = host_fcntl(s, F_GETFL, 0);
    588 	if (host_fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) {
    589 		fprintf(stderr, "rump_sp: socket fd NONBLOCK: %s\n",
    590 		    strerror(errno));
    591 		errno = EINVAL;
    592 		return -1;
    593 	}
    594 	clispc.spc_fd = s;
    595 	clispc.spc_state = SPCSTATE_RUNNING;
    596 	clispc.spc_reconnecting = 0;
    597 
    598 	if (prevreconmsg) {
    599 		fprintf(stderr, "rump_sp: reconnected!\n");
    600 	}
    601 
    602 	/* setup kqueue, we want all signals and the fd */
    603 	if ((kq = host_kqueue()) == -1) {
    604 		error = errno;
    605 		fprintf(stderr, "rump_sp: cannot setup kqueue");
    606 		errno = error;
    607 		return -1;
    608 	}
    609 
    610 	for (i = 0; i < NSIG; i++) {
    611 		EV_SET(&kev[i], i+1, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0);
    612 	}
    613 	EV_SET(&kev[NSIG], clispc.spc_fd,
    614 	    EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0);
    615 	if (host_kevent(kq, kev, NSIG+1, NULL, 0, NULL) == -1) {
    616 		error = errno;
    617 		fprintf(stderr, "rump_sp: kevent() failed");
    618 		errno = error;
    619 		return -1;
    620 	}
    621 
    622 	return 0;
    623 }
    624 
    625 static int
    626 doinit(void)
    627 {
    628 
    629 	TAILQ_INIT(&clispc.spc_respwait);
    630 	pthread_mutex_init(&clispc.spc_mtx, NULL);
    631 	pthread_cond_init(&clispc.spc_cv, NULL);
    632 
    633 	return 0;
    634 }
    635 
    636 void *(*rumpclient_dlsym)(void *, const char *);
    637 
    638 int
    639 rumpclient_init()
    640 {
    641 	char *p;
    642 	int error;
    643 
    644 	/* dlsym overrided by rumphijack? */
    645 	if (!rumpclient_dlsym)
    646 		rumpclient_dlsym = dlsym;
    647 
    648 	/*
    649 	 * sag mir, wo die symbol sind.  zogen fort, der krieg beginnt.
    650 	 * wann wird man je verstehen?  wann wird man je verstehen?
    651 	 */
    652 #define FINDSYM2(_name_,_syscall_)					\
    653 	if ((host_##_name_ = rumpclient_dlsym(RTLD_NEXT,		\
    654 	    #_syscall_)) == NULL)					\
    655 		/* host_##_name_ = _syscall_ */;
    656 #define FINDSYM(_name_) FINDSYM2(_name_,_name_)
    657 	FINDSYM2(socket,__socket30);
    658 	FINDSYM(close);
    659 	FINDSYM(connect);
    660 	FINDSYM(fcntl);
    661 	FINDSYM(poll);
    662 	FINDSYM(read);
    663 	FINDSYM(sendto);
    664 	FINDSYM(setsockopt);
    665 	FINDSYM(kqueue);
    666 	FINDSYM(kevent);
    667 #undef	FINDSYM
    668 #undef	FINDSY2
    669 
    670 	if ((p = getenv("RUMP_SERVER")) == NULL) {
    671 		errno = ENOENT;
    672 		return -1;
    673 	}
    674 
    675 	if ((error = parseurl(p, &serv_sa, &ptab_idx, 0)) != 0) {
    676 		errno = error;
    677 		return -1;
    678 	}
    679 
    680 	if (doinit() == -1)
    681 		return -1;
    682 	if (doconnect(0) == -1)
    683 		return -1;
    684 
    685 	error = handshake_req(&clispc, NULL, 0, false);
    686 	if (error) {
    687 		pthread_mutex_destroy(&clispc.spc_mtx);
    688 		pthread_cond_destroy(&clispc.spc_cv);
    689 		if (clispc.spc_fd != -1)
    690 			host_close(clispc.spc_fd);
    691 		errno = error;
    692 		return -1;
    693 	}
    694 
    695 	sigfillset(&fullset);
    696 	return 0;
    697 }
    698 
    699 struct rumpclient_fork {
    700 	uint32_t fork_auth[AUTHLEN];
    701 };
    702 
    703 struct rumpclient_fork *
    704 rumpclient_prefork(void)
    705 {
    706 	struct rumpclient_fork *rpf;
    707 	void *resp;
    708 	int rv;
    709 
    710 	rpf = malloc(sizeof(*rpf));
    711 	if (rpf == NULL)
    712 		return NULL;
    713 
    714 	if ((rv = prefork_req(&clispc, &resp)) != 0) {
    715 		free(rpf);
    716 		errno = rv;
    717 		return NULL;
    718 	}
    719 
    720 	memcpy(rpf->fork_auth, resp, sizeof(rpf->fork_auth));
    721 	free(resp);
    722 
    723 	return rpf;
    724 }
    725 
    726 int
    727 rumpclient_fork_init(struct rumpclient_fork *rpf)
    728 {
    729 	int error;
    730 
    731 	memset(&clispc, 0, sizeof(clispc));
    732 	clispc.spc_fd = -1;
    733 	kq = -1;
    734 
    735 	if (doinit() == -1)
    736 		return -1;
    737 	if (doconnect(1) == -1)
    738 		return -1;
    739 
    740 	error = handshake_req(&clispc, rpf->fork_auth, 0, false);
    741 	if (error) {
    742 		pthread_mutex_destroy(&clispc.spc_mtx);
    743 		pthread_cond_destroy(&clispc.spc_cv);
    744 		errno = error;
    745 		return -1;
    746 	}
    747 
    748 	return 0;
    749 }
    750