rumpclient.c revision 1.27 1 /* $NetBSD: rumpclient.c,v 1.27 2011/02/09 14:29:58 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 int (*host_dup)(int);
72
73 int (*host_kqueue)(void);
74 int (*host_kevent)(int, const struct kevent *, size_t,
75 struct kevent *, size_t, const struct timespec *);
76
77 #include "sp_common.c"
78
79 static struct spclient clispc = {
80 .spc_fd = -1,
81 };
82
83 static int kq = -1;
84 static sigset_t fullset;
85
86 static int doconnect(bool);
87 static int handshake_req(struct spclient *, uint32_t *, int, bool);
88
89 time_t retrytimo = RUMPCLIENT_RETRYCONN_ONCE;
90
91 static int
92 send_with_recon(struct spclient *spc, const void *data, size_t dlen)
93 {
94 struct timeval starttime, curtime;
95 time_t prevreconmsg;
96 unsigned reconretries;
97 int rv;
98
99 for (prevreconmsg = 0, reconretries = 0;;) {
100 rv = dosend(spc, data, dlen);
101 if (__predict_false(rv == ENOTCONN || rv == EBADF)) {
102 /* no persistent connections */
103 if (retrytimo == 0)
104 break;
105 if (retrytimo == RUMPCLIENT_RETRYCONN_DIE)
106 exit(1);
107
108 if (!prevreconmsg) {
109 prevreconmsg = time(NULL);
110 gettimeofday(&starttime, NULL);
111 }
112 if (reconretries == 1) {
113 if (retrytimo == RUMPCLIENT_RETRYCONN_ONCE) {
114 rv = ENOTCONN;
115 break;
116 }
117 fprintf(stderr, "rump_sp: connection to "
118 "kernel lost, trying to reconnect ...\n");
119 } else if (time(NULL) - prevreconmsg > 120) {
120 fprintf(stderr, "rump_sp: still trying to "
121 "reconnect ...\n");
122 prevreconmsg = time(NULL);
123 }
124
125 /* check that we aren't over the limit */
126 if (retrytimo > 0) {
127 struct timeval tmp;
128
129 gettimeofday(&curtime, NULL);
130 timersub(&curtime, &starttime, &tmp);
131 if (tmp.tv_sec >= retrytimo) {
132 fprintf(stderr, "rump_sp: reconnect "
133 "failed, %lld second timeout\n",
134 (long long)retrytimo);
135 return ENOTCONN;
136 }
137 }
138
139 /* adhoc backoff timer */
140 if (reconretries < 10) {
141 usleep(100000 * reconretries);
142 } else {
143 sleep(MIN(10, reconretries-9));
144 }
145 reconretries++;
146
147 if ((rv = doconnect(false)) != 0)
148 continue;
149 if ((rv = handshake_req(&clispc, NULL, 0, true)) != 0)
150 continue;
151
152 /*
153 * ok, reconnect succesful. we need to return to
154 * the upper layer to get the entire PDU resent.
155 */
156 if (reconretries != 1)
157 fprintf(stderr, "rump_sp: reconnected!\n");
158 rv = EAGAIN;
159 break;
160 } else {
161 _DIAGASSERT(errno != EAGAIN);
162 break;
163 }
164 }
165
166 return rv;
167 }
168
169 static int
170 cliwaitresp(struct spclient *spc, struct respwait *rw, sigset_t *mask,
171 bool keeplock)
172 {
173 uint64_t mygen;
174 bool imalive = true;
175
176 pthread_mutex_lock(&spc->spc_mtx);
177 if (!keeplock)
178 sendunlockl(spc);
179 mygen = spc->spc_generation;
180
181 rw->rw_error = 0;
182 while (!rw->rw_done && rw->rw_error == 0) {
183 if (__predict_false(spc->spc_generation != mygen || !imalive))
184 break;
185
186 /* are we free to receive? */
187 if (spc->spc_istatus == SPCSTATUS_FREE) {
188 struct kevent kev[8];
189 int gotresp, dosig, rv, i;
190
191 spc->spc_istatus = SPCSTATUS_BUSY;
192 pthread_mutex_unlock(&spc->spc_mtx);
193
194 dosig = 0;
195 for (gotresp = 0; !gotresp; ) {
196 switch (readframe(spc)) {
197 case 0:
198 rv = host_kevent(kq, NULL, 0,
199 kev, __arraycount(kev), NULL);
200
201 /*
202 * XXX: don't know how this can
203 * happen (timeout cannot expire
204 * since there isn't one), but
205 * it does happen
206 */
207 if (__predict_false(rv == 0))
208 continue;
209
210 for (i = 0; i < rv; i++) {
211 if (kev[i].filter
212 == EVFILT_SIGNAL)
213 dosig++;
214 }
215 if (dosig)
216 goto cleanup;
217
218 continue;
219 case -1:
220 imalive = false;
221 goto cleanup;
222 default:
223 break;
224 }
225
226 switch (spc->spc_hdr.rsp_class) {
227 case RUMPSP_RESP:
228 case RUMPSP_ERROR:
229 kickwaiter(spc);
230 gotresp = spc->spc_hdr.rsp_reqno ==
231 rw->rw_reqno;
232 break;
233 case RUMPSP_REQ:
234 handlereq(spc);
235 break;
236 default:
237 /* panic */
238 break;
239 }
240 }
241
242 cleanup:
243 pthread_mutex_lock(&spc->spc_mtx);
244 if (spc->spc_istatus == SPCSTATUS_WANTED)
245 kickall(spc);
246 spc->spc_istatus = SPCSTATUS_FREE;
247
248 /* take one for the team */
249 if (dosig) {
250 pthread_mutex_unlock(&spc->spc_mtx);
251 pthread_sigmask(SIG_SETMASK, mask, NULL);
252 pthread_sigmask(SIG_SETMASK, &fullset, NULL);
253 pthread_mutex_lock(&spc->spc_mtx);
254 }
255 } else {
256 spc->spc_istatus = SPCSTATUS_WANTED;
257 pthread_cond_wait(&rw->rw_cv, &spc->spc_mtx);
258 }
259 }
260 TAILQ_REMOVE(&spc->spc_respwait, rw, rw_entries);
261 pthread_mutex_unlock(&spc->spc_mtx);
262 pthread_cond_destroy(&rw->rw_cv);
263
264 if (spc->spc_generation != mygen || !imalive) {
265 return ENOTCONN;
266 }
267 return rw->rw_error;
268 }
269
270 static int
271 syscall_req(struct spclient *spc, sigset_t *omask, int sysnum,
272 const void *data, size_t dlen, void **resp)
273 {
274 struct rsp_hdr rhdr;
275 struct respwait rw;
276 int rv;
277
278 rhdr.rsp_len = sizeof(rhdr) + dlen;
279 rhdr.rsp_class = RUMPSP_REQ;
280 rhdr.rsp_type = RUMPSP_SYSCALL;
281 rhdr.rsp_sysnum = sysnum;
282
283 do {
284 putwait(spc, &rw, &rhdr);
285 if ((rv = send_with_recon(spc, &rhdr, sizeof(rhdr))) != 0) {
286 unputwait(spc, &rw);
287 continue;
288 }
289 if ((rv = send_with_recon(spc, data, dlen)) != 0) {
290 unputwait(spc, &rw);
291 continue;
292 }
293
294 rv = cliwaitresp(spc, &rw, omask, false);
295 if (rv == ENOTCONN)
296 rv = EAGAIN;
297 } while (rv == EAGAIN);
298
299 *resp = rw.rw_data;
300 return rv;
301 }
302
303 static int
304 handshake_req(struct spclient *spc, uint32_t *auth, int cancel, bool haslock)
305 {
306 struct handshake_fork rf;
307 struct rsp_hdr rhdr;
308 struct respwait rw;
309 sigset_t omask;
310 size_t bonus;
311 int rv;
312
313 if (auth) {
314 bonus = sizeof(rf);
315 } else {
316 bonus = strlen(getprogname())+1;
317 }
318
319 /* performs server handshake */
320 rhdr.rsp_len = sizeof(rhdr) + bonus;
321 rhdr.rsp_class = RUMPSP_REQ;
322 rhdr.rsp_type = RUMPSP_HANDSHAKE;
323 if (auth)
324 rhdr.rsp_handshake = HANDSHAKE_FORK;
325 else
326 rhdr.rsp_handshake = HANDSHAKE_GUEST;
327
328 pthread_sigmask(SIG_SETMASK, &fullset, &omask);
329 if (haslock)
330 putwait_locked(spc, &rw, &rhdr);
331 else
332 putwait(spc, &rw, &rhdr);
333 rv = dosend(spc, &rhdr, sizeof(rhdr));
334 if (auth) {
335 memcpy(rf.rf_auth, auth, AUTHLEN*sizeof(*auth));
336 rf.rf_cancel = cancel;
337 rv = send_with_recon(spc, &rf, sizeof(rf));
338 } else {
339 rv = dosend(spc, getprogname(), strlen(getprogname())+1);
340 }
341 if (rv || cancel) {
342 if (haslock)
343 unputwait_locked(spc, &rw);
344 else
345 unputwait(spc, &rw);
346 if (cancel) {
347 goto out;
348 }
349 } else {
350 rv = cliwaitresp(spc, &rw, &omask, haslock);
351 }
352 if (rv)
353 goto out;
354
355 rv = *(int *)rw.rw_data;
356 free(rw.rw_data);
357
358 out:
359 pthread_sigmask(SIG_SETMASK, &omask, NULL);
360 return rv;
361 }
362
363 static int
364 prefork_req(struct spclient *spc, sigset_t *omask, void **resp)
365 {
366 struct rsp_hdr rhdr;
367 struct respwait rw;
368 int rv;
369
370 rhdr.rsp_len = sizeof(rhdr);
371 rhdr.rsp_class = RUMPSP_REQ;
372 rhdr.rsp_type = RUMPSP_PREFORK;
373 rhdr.rsp_error = 0;
374
375 do {
376 putwait(spc, &rw, &rhdr);
377 rv = send_with_recon(spc, &rhdr, sizeof(rhdr));
378 if (rv != 0) {
379 unputwait(spc, &rw);
380 continue;
381 }
382
383 rv = cliwaitresp(spc, &rw, omask, false);
384 if (rv == ENOTCONN)
385 rv = EAGAIN;
386 } while (rv == EAGAIN);
387
388 *resp = rw.rw_data;
389 return rv;
390 }
391
392 /*
393 * prevent response code from deadlocking with reconnect code
394 */
395 static int
396 resp_sendlock(struct spclient *spc)
397 {
398 int rv = 0;
399
400 pthread_mutex_lock(&spc->spc_mtx);
401 while (spc->spc_ostatus != SPCSTATUS_FREE) {
402 if (__predict_false(spc->spc_reconnecting)) {
403 rv = EBUSY;
404 goto out;
405 }
406 spc->spc_ostatus = SPCSTATUS_WANTED;
407 pthread_cond_wait(&spc->spc_cv, &spc->spc_mtx);
408 }
409 spc->spc_ostatus = SPCSTATUS_BUSY;
410
411 out:
412 pthread_mutex_unlock(&spc->spc_mtx);
413 return rv;
414 }
415
416 static void
417 send_copyin_resp(struct spclient *spc, uint64_t reqno, void *data, size_t dlen,
418 int wantstr)
419 {
420 struct rsp_hdr rhdr;
421
422 if (wantstr)
423 dlen = MIN(dlen, strlen(data)+1);
424
425 rhdr.rsp_len = sizeof(rhdr) + dlen;
426 rhdr.rsp_reqno = reqno;
427 rhdr.rsp_class = RUMPSP_RESP;
428 rhdr.rsp_type = RUMPSP_COPYIN;
429 rhdr.rsp_sysnum = 0;
430
431 if (resp_sendlock(spc) != 0)
432 return;
433 (void)dosend(spc, &rhdr, sizeof(rhdr));
434 (void)dosend(spc, data, dlen);
435 sendunlock(spc);
436 }
437
438 static void
439 send_anonmmap_resp(struct spclient *spc, uint64_t reqno, void *addr)
440 {
441 struct rsp_hdr rhdr;
442
443 rhdr.rsp_len = sizeof(rhdr) + sizeof(addr);
444 rhdr.rsp_reqno = reqno;
445 rhdr.rsp_class = RUMPSP_RESP;
446 rhdr.rsp_type = RUMPSP_ANONMMAP;
447 rhdr.rsp_sysnum = 0;
448
449 if (resp_sendlock(spc) != 0)
450 return;
451 (void)dosend(spc, &rhdr, sizeof(rhdr));
452 (void)dosend(spc, &addr, sizeof(addr));
453 sendunlock(spc);
454 }
455
456 int
457 rumpclient_syscall(int sysnum, const void *data, size_t dlen,
458 register_t *retval)
459 {
460 struct rsp_sysresp *resp;
461 sigset_t omask;
462 void *rdata;
463 int rv;
464
465 pthread_sigmask(SIG_SETMASK, &fullset, &omask);
466
467 DPRINTF(("rumpsp syscall_req: syscall %d with %p/%zu\n",
468 sysnum, data, dlen));
469
470 rv = syscall_req(&clispc, &omask, sysnum, data, dlen, &rdata);
471 if (rv)
472 goto out;
473
474 resp = rdata;
475 DPRINTF(("rumpsp syscall_resp: syscall %d error %d, rv: %d/%d\n",
476 sysnum, rv, resp->rsys_retval[0], resp->rsys_retval[1]));
477
478 memcpy(retval, &resp->rsys_retval, sizeof(resp->rsys_retval));
479 rv = resp->rsys_error;
480 free(rdata);
481
482 out:
483 pthread_sigmask(SIG_SETMASK, &omask, NULL);
484 return rv;
485 }
486
487 static void
488 handlereq(struct spclient *spc)
489 {
490 struct rsp_copydata *copydata;
491 struct rsp_hdr *rhdr = &spc->spc_hdr;
492 void *mapaddr;
493 size_t maplen;
494 int reqtype = spc->spc_hdr.rsp_type;
495
496 switch (reqtype) {
497 case RUMPSP_COPYIN:
498 case RUMPSP_COPYINSTR:
499 /*LINTED*/
500 copydata = (struct rsp_copydata *)spc->spc_buf;
501 DPRINTF(("rump_sp handlereq: copyin request: %p/%zu\n",
502 copydata->rcp_addr, copydata->rcp_len));
503 send_copyin_resp(spc, spc->spc_hdr.rsp_reqno,
504 copydata->rcp_addr, copydata->rcp_len,
505 reqtype == RUMPSP_COPYINSTR);
506 break;
507 case RUMPSP_COPYOUT:
508 case RUMPSP_COPYOUTSTR:
509 /*LINTED*/
510 copydata = (struct rsp_copydata *)spc->spc_buf;
511 DPRINTF(("rump_sp handlereq: copyout request: %p/%zu\n",
512 copydata->rcp_addr, copydata->rcp_len));
513 /*LINTED*/
514 memcpy(copydata->rcp_addr, copydata->rcp_data,
515 copydata->rcp_len);
516 break;
517 case RUMPSP_ANONMMAP:
518 /*LINTED*/
519 maplen = *(size_t *)spc->spc_buf;
520 mapaddr = mmap(NULL, maplen, PROT_READ|PROT_WRITE,
521 MAP_ANON, -1, 0);
522 if (mapaddr == MAP_FAILED)
523 mapaddr = NULL;
524 DPRINTF(("rump_sp handlereq: anonmmap: %p\n", mapaddr));
525 send_anonmmap_resp(spc, spc->spc_hdr.rsp_reqno, mapaddr);
526 break;
527 case RUMPSP_RAISE:
528 DPRINTF(("rump_sp handlereq: raise sig %d\n", rhdr->rsp_signo));
529 raise((int)rhdr->rsp_signo);
530 /*
531 * We most likely have signals blocked, but the signal
532 * will be handled soon enough when we return.
533 */
534 break;
535 default:
536 printf("PANIC: INVALID TYPE %d\n", reqtype);
537 abort();
538 break;
539 }
540
541 spcfreebuf(spc);
542 }
543
544 static unsigned ptab_idx;
545 static struct sockaddr *serv_sa;
546
547 /* dup until we get a "good" fd which does not collide with stdio */
548 static int
549 dupgood(int myfd)
550 {
551 int ofds[3];
552 int i;
553
554 for (i = 0; myfd <= 2 && myfd != -1; i++) {
555 assert(i < __arraycount(ofds));
556 ofds[i] = myfd;
557 myfd = host_dup(myfd);
558 }
559
560 for (i--; i >= 0; i--) {
561 host_close(ofds[i]);
562 }
563
564 return myfd;
565 }
566
567 static int
568 doconnect(bool noisy)
569 {
570 struct respwait rw;
571 struct rsp_hdr rhdr;
572 struct kevent kev[NSIG+1];
573 char banner[MAXBANNER];
574 struct pollfd pfd;
575 int s, error, flags, i;
576 ssize_t n;
577
578 if (kq != -1)
579 host_close(kq);
580 kq = -1;
581 s = -1;
582
583 if (clispc.spc_fd != -1)
584 host_close(clispc.spc_fd);
585 clispc.spc_fd = -1;
586
587 /*
588 * for reconnect, gate everyone out of the receiver code
589 */
590 putwait_locked(&clispc, &rw, &rhdr);
591
592 pthread_mutex_lock(&clispc.spc_mtx);
593 clispc.spc_reconnecting = 1;
594 pthread_cond_broadcast(&clispc.spc_cv);
595 clispc.spc_generation++;
596 while (clispc.spc_istatus != SPCSTATUS_FREE) {
597 clispc.spc_istatus = SPCSTATUS_WANTED;
598 pthread_cond_wait(&rw.rw_cv, &clispc.spc_mtx);
599 }
600 kickall(&clispc);
601
602 /*
603 * we can release it already since we hold the
604 * send lock during reconnect
605 * XXX: assert it
606 */
607 clispc.spc_istatus = SPCSTATUS_FREE;
608 pthread_mutex_unlock(&clispc.spc_mtx);
609 unputwait_locked(&clispc, &rw);
610
611 free(clispc.spc_buf);
612 clispc.spc_off = 0;
613
614 s = dupgood(host_socket(parsetab[ptab_idx].domain, SOCK_STREAM, 0));
615 if (s == -1)
616 return -1;
617
618 pfd.fd = s;
619 pfd.events = POLLIN;
620 while (host_connect(s, serv_sa, (socklen_t)serv_sa->sa_len) == -1) {
621 if (errno == EINTR)
622 continue;
623 error = errno;
624 if (noisy)
625 fprintf(stderr, "rump_sp: client connect failed: %s\n",
626 strerror(errno));
627 errno = error;
628 return -1;
629 }
630
631 if ((error = parsetab[ptab_idx].connhook(s)) != 0) {
632 error = errno;
633 if (noisy)
634 fprintf(stderr, "rump_sp: connect hook failed\n");
635 errno = error;
636 return -1;
637 }
638
639 if ((n = host_read(s, banner, sizeof(banner)-1)) < 0) {
640 error = errno;
641 if (noisy)
642 fprintf(stderr, "rump_sp: failed to read banner\n");
643 errno = error;
644 return -1;
645 }
646
647 if (banner[n-1] != '\n') {
648 if (noisy)
649 fprintf(stderr, "rump_sp: invalid banner\n");
650 errno = EINVAL;
651 return -1;
652 }
653 banner[n] = '\0';
654 /* parse the banner some day */
655
656 flags = host_fcntl(s, F_GETFL, 0);
657 if (host_fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) {
658 if (noisy)
659 fprintf(stderr, "rump_sp: socket fd NONBLOCK: %s\n",
660 strerror(errno));
661 errno = EINVAL;
662 return -1;
663 }
664 clispc.spc_fd = s;
665 clispc.spc_state = SPCSTATE_RUNNING;
666 clispc.spc_reconnecting = 0;
667
668 /* setup kqueue, we want all signals and the fd */
669 if ((kq = dupgood(host_kqueue())) == -1) {
670 error = errno;
671 if (noisy)
672 fprintf(stderr, "rump_sp: cannot setup kqueue");
673 errno = error;
674 return -1;
675 }
676
677 for (i = 0; i < NSIG; i++) {
678 EV_SET(&kev[i], i+1, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0);
679 }
680 EV_SET(&kev[NSIG], clispc.spc_fd,
681 EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0);
682 if (host_kevent(kq, kev, NSIG+1, NULL, 0, NULL) == -1) {
683 error = errno;
684 if (noisy)
685 fprintf(stderr, "rump_sp: kevent() failed");
686 errno = error;
687 return -1;
688 }
689
690 return 0;
691 }
692
693 static int
694 doinit(void)
695 {
696
697 TAILQ_INIT(&clispc.spc_respwait);
698 pthread_mutex_init(&clispc.spc_mtx, NULL);
699 pthread_cond_init(&clispc.spc_cv, NULL);
700
701 return 0;
702 }
703
704 void *(*rumpclient_dlsym)(void *, const char *);
705
706 int
707 rumpclient_init()
708 {
709 char *p;
710 int error;
711
712 sigfillset(&fullset);
713
714 /* dlsym overrided by rumphijack? */
715 if (!rumpclient_dlsym)
716 rumpclient_dlsym = dlsym;
717
718 /*
719 * sag mir, wo die symbol sind. zogen fort, der krieg beginnt.
720 * wann wird man je verstehen? wann wird man je verstehen?
721 */
722 #define FINDSYM2(_name_,_syscall_) \
723 if ((host_##_name_ = rumpclient_dlsym(RTLD_NEXT, \
724 #_syscall_)) == NULL) \
725 /* host_##_name_ = _syscall_ */;
726 #define FINDSYM(_name_) FINDSYM2(_name_,_name_)
727 FINDSYM2(socket,__socket30);
728 FINDSYM(close);
729 FINDSYM(connect);
730 FINDSYM(fcntl);
731 FINDSYM(poll);
732 FINDSYM(read);
733 FINDSYM(sendto);
734 FINDSYM(setsockopt);
735 FINDSYM(dup);
736 FINDSYM(kqueue);
737 #if !__NetBSD_Prereq__(5,99,7)
738 FINDSYM(kevent);
739 #else
740 FINDSYM2(kevent,_sys___kevent50);
741 #endif
742 #undef FINDSYM
743 #undef FINDSY2
744
745 if ((p = getenv("RUMP_SERVER")) == NULL) {
746 errno = ENOENT;
747 return -1;
748 }
749
750 if ((error = parseurl(p, &serv_sa, &ptab_idx, 0)) != 0) {
751 errno = error;
752 return -1;
753 }
754
755 if (doinit() == -1)
756 return -1;
757 if (doconnect(true) == -1)
758 return -1;
759
760 error = handshake_req(&clispc, NULL, 0, false);
761 if (error) {
762 pthread_mutex_destroy(&clispc.spc_mtx);
763 pthread_cond_destroy(&clispc.spc_cv);
764 if (clispc.spc_fd != -1)
765 host_close(clispc.spc_fd);
766 errno = error;
767 return -1;
768 }
769
770 return 0;
771 }
772
773 struct rumpclient_fork {
774 uint32_t fork_auth[AUTHLEN];
775 };
776
777 struct rumpclient_fork *
778 rumpclient_prefork(void)
779 {
780 struct rumpclient_fork *rpf;
781 sigset_t omask;
782 void *resp;
783 int rv;
784
785 pthread_sigmask(SIG_SETMASK, &fullset, &omask);
786 rpf = malloc(sizeof(*rpf));
787 if (rpf == NULL)
788 return NULL;
789
790 if ((rv = prefork_req(&clispc, &omask, &resp)) != 0) {
791 free(rpf);
792 errno = rv;
793 rpf = NULL;
794 goto out;
795 }
796
797 memcpy(rpf->fork_auth, resp, sizeof(rpf->fork_auth));
798 free(resp);
799
800 out:
801 pthread_sigmask(SIG_SETMASK, &omask, NULL);
802 return rpf;
803 }
804
805 int
806 rumpclient_fork_init(struct rumpclient_fork *rpf)
807 {
808 int error;
809 int osock;
810
811 osock = clispc.spc_fd;
812 memset(&clispc, 0, sizeof(clispc));
813 clispc.spc_fd = osock;
814
815 kq = -1; /* kqueue descriptor is not copied over fork() */
816
817 if (doinit() == -1)
818 return -1;
819 if (doconnect(false) == -1)
820 return -1;
821
822 error = handshake_req(&clispc, rpf->fork_auth, 0, false);
823 if (error) {
824 pthread_mutex_destroy(&clispc.spc_mtx);
825 pthread_cond_destroy(&clispc.spc_cv);
826 errno = error;
827 return -1;
828 }
829
830 return 0;
831 }
832
833 void
834 rumpclient_setconnretry(time_t timeout)
835 {
836
837 if (timeout < RUMPCLIENT_RETRYCONN_DIE)
838 return; /* gigo */
839
840 retrytimo = timeout;
841 }
842