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