Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/lib/librumpclient/rumpclient.c,v rcsdiff: /ftp/cvs/cvsroot/src/lib/librumpclient/rumpclient.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.35 retrieving revision 1.47.2.2 diff -u -p -r1.35 -r1.47.2.2 --- src/lib/librumpclient/rumpclient.c 2011/02/24 12:25:44 1.35 +++ src/lib/librumpclient/rumpclient.c 2012/04/23 23:40:41 1.47.2.2 @@ -1,4 +1,4 @@ -/* $NetBSD: rumpclient.c,v 1.35 2011/02/24 12:25:44 pooka Exp $ */ +/* $NetBSD: rumpclient.c,v 1.47.2.2 2012/04/23 23:40:41 riz Exp $ */ /* * Copyright (c) 2010, 2011 Antti Kantee. All Rights Reserved. @@ -30,7 +30,7 @@ */ #include -__RCSID("$NetBSD"); +__RCSID("$NetBSD: rumpclient.c,v 1.47.2.2 2012/04/23 23:40:41 riz Exp $"); #include #include @@ -66,8 +66,7 @@ int (*host_connect)(int, const struct so int (*host_fcntl)(int, int, ...); int (*host_poll)(struct pollfd *, nfds_t, int); ssize_t (*host_read)(int, void *, size_t); -ssize_t (*host_sendto)(int, const void *, size_t, int, - const struct sockaddr *, socklen_t); +ssize_t (*host_sendmsg)(int, const struct msghdr *, int); int (*host_setsockopt)(int, int, int, const void *, socklen_t); int (*host_dup)(int); @@ -86,7 +85,7 @@ static struct spclient clispc = { static int kq = -1; static sigset_t fullset; -static int doconnect(bool); +static int doconnect(void); static int handshake_req(struct spclient *, int, void *, int, bool); /* @@ -95,8 +94,11 @@ static int handshake_req(struct spclient */ static time_t retrytimo = 0; +/* always defined to nothingness for now */ +#define ERRLOG(a) + static int -send_with_recon(struct spclient *spc, const void *data, size_t dlen) +send_with_recon(struct spclient *spc, struct iovec *iov, size_t iovlen) { struct timeval starttime, curtime; time_t prevreconmsg; @@ -104,7 +106,7 @@ send_with_recon(struct spclient *spc, co int rv; for (prevreconmsg = 0, reconretries = 0;;) { - rv = dosend(spc, data, dlen); + rv = dosend(spc, iov, iovlen); if (__predict_false(rv == ENOTCONN || rv == EBADF)) { /* no persistent connections */ if (retrytimo == 0) { @@ -112,7 +114,7 @@ send_with_recon(struct spclient *spc, co break; } if (retrytimo == RUMPCLIENT_RETRYCONN_DIE) - exit(1); + _exit(1); if (!prevreconmsg) { prevreconmsg = time(NULL); @@ -153,7 +155,7 @@ send_with_recon(struct spclient *spc, co } reconretries++; - if ((rv = doconnect(false)) != 0) + if ((rv = doconnect()) != 0) continue; if ((rv = handshake_req(&clispc, HANDSHAKE_GUEST, NULL, 0, true)) != 0) @@ -203,37 +205,48 @@ cliwaitresp(struct spclient *spc, struct dosig = 0; for (gotresp = 0; !gotresp; ) { - switch (readframe(spc)) { - case 0: - rv = host_kevent(kq, NULL, 0, - kev, __arraycount(kev), NULL); + /* + * typically we don't have a frame waiting + * when we come in here, so call kevent now + */ + rv = host_kevent(kq, NULL, 0, + kev, __arraycount(kev), NULL); + + if (__predict_false(rv == -1)) { + goto activity; + } - if (__predict_false(rv == -1)) { - goto cleanup; - } - - /* - * XXX: don't know how this can - * happen (timeout cannot expire - * since there isn't one), but - * it does happen - */ - if (__predict_false(rv == 0)) - continue; - - for (i = 0; i < rv; i++) { - if (kev[i].filter - == EVFILT_SIGNAL) - dosig++; - } - if (dosig) - goto cleanup; + /* + * XXX: don't know how this can happen + * (timeout cannot expire since there + * isn't one), but it does happen. + * treat it as an expectional condition + * and go through tryread to determine + * alive status. + */ + if (__predict_false(rv == 0)) + goto activity; + + for (i = 0; i < rv; i++) { + if (kev[i].filter == EVFILT_SIGNAL) + dosig++; + } + if (dosig) + goto cleanup; + /* + * ok, activity. try to read a frame to + * determine what happens next. + */ + activity: + switch (readframe(spc)) { + case 0: continue; case -1: imalive = false; goto cleanup; default: + /* case 1 */ break; } @@ -287,6 +300,7 @@ syscall_req(struct spclient *spc, sigset { struct rsp_hdr rhdr; struct respwait rw; + struct iovec iov[2]; int rv; rhdr.rsp_len = sizeof(rhdr) + dlen; @@ -294,13 +308,12 @@ syscall_req(struct spclient *spc, sigset rhdr.rsp_type = RUMPSP_SYSCALL; rhdr.rsp_sysnum = sysnum; + IOVPUT(iov[0], rhdr); + IOVPUT_WITHSIZE(iov[1], __UNCONST(data), dlen); + do { putwait(spc, &rw, &rhdr); - if ((rv = send_with_recon(spc, &rhdr, sizeof(rhdr))) != 0) { - unputwait(spc, &rw); - continue; - } - if ((rv = send_with_recon(spc, data, dlen)) != 0) { + if ((rv = send_with_recon(spc, iov, __arraycount(iov))) != 0) { unputwait(spc, &rw); continue; } @@ -319,16 +332,19 @@ handshake_req(struct spclient *spc, int int cancel, bool haslock) { struct handshake_fork rf; + const char *myprogname = NULL; /* XXXgcc */ struct rsp_hdr rhdr; struct respwait rw; sigset_t omask; size_t bonus; + struct iovec iov[2]; int rv; if (type == HANDSHAKE_FORK) { bonus = sizeof(rf); } else { - bonus = strlen(getprogname())+1; + myprogname = getprogname(); + bonus = strlen(myprogname)+1; } /* performs server handshake */ @@ -337,19 +353,21 @@ handshake_req(struct spclient *spc, int rhdr.rsp_type = RUMPSP_HANDSHAKE; rhdr.rsp_handshake = type; + IOVPUT(iov[0], rhdr); + pthread_sigmask(SIG_SETMASK, &fullset, &omask); if (haslock) putwait_locked(spc, &rw, &rhdr); else putwait(spc, &rw, &rhdr); - rv = dosend(spc, &rhdr, sizeof(rhdr)); if (type == HANDSHAKE_FORK) { memcpy(rf.rf_auth, data, sizeof(rf.rf_auth)); /* uh, why? */ rf.rf_cancel = cancel; - rv = send_with_recon(spc, &rf, sizeof(rf)); + IOVPUT(iov[1], rf); } else { - rv = dosend(spc, getprogname(), strlen(getprogname())+1); + IOVPUT_WITHSIZE(iov[1], __UNCONST(myprogname), bonus); } + rv = send_with_recon(spc, iov, __arraycount(iov)); if (rv || cancel) { if (haslock) unputwait_locked(spc, &rw); @@ -377,6 +395,7 @@ prefork_req(struct spclient *spc, sigset { struct rsp_hdr rhdr; struct respwait rw; + struct iovec iov[1]; int rv; rhdr.rsp_len = sizeof(rhdr); @@ -384,9 +403,11 @@ prefork_req(struct spclient *spc, sigset rhdr.rsp_type = RUMPSP_PREFORK; rhdr.rsp_error = 0; + IOVPUT(iov[0], rhdr); + do { putwait(spc, &rw, &rhdr); - rv = send_with_recon(spc, &rhdr, sizeof(rhdr)); + rv = send_with_recon(spc, iov, __arraycount(iov)); if (rv != 0) { unputwait(spc, &rw); continue; @@ -430,6 +451,7 @@ send_copyin_resp(struct spclient *spc, u int wantstr) { struct rsp_hdr rhdr; + struct iovec iov[2]; if (wantstr) dlen = MIN(dlen, strlen(data)+1); @@ -440,10 +462,12 @@ send_copyin_resp(struct spclient *spc, u rhdr.rsp_type = RUMPSP_COPYIN; rhdr.rsp_sysnum = 0; + IOVPUT(iov[0], rhdr); + IOVPUT_WITHSIZE(iov[1], data, dlen); + if (resp_sendlock(spc) != 0) return; - (void)dosend(spc, &rhdr, sizeof(rhdr)); - (void)dosend(spc, data, dlen); + (void)SENDIOV(spc, iov); sendunlock(spc); } @@ -451,6 +475,7 @@ static void send_anonmmap_resp(struct spclient *spc, uint64_t reqno, void *addr) { struct rsp_hdr rhdr; + struct iovec iov[2]; rhdr.rsp_len = sizeof(rhdr) + sizeof(addr); rhdr.rsp_reqno = reqno; @@ -458,10 +483,12 @@ send_anonmmap_resp(struct spclient *spc, rhdr.rsp_type = RUMPSP_ANONMMAP; rhdr.rsp_sysnum = 0; + IOVPUT(iov[0], rhdr); + IOVPUT(iov[1], addr); + if (resp_sendlock(spc) != 0) return; - (void)dosend(spc, &rhdr, sizeof(rhdr)); - (void)dosend(spc, &addr, sizeof(addr)); + (void)SENDIOV(spc, iov); sendunlock(spc); } @@ -562,6 +589,7 @@ dupgood(int myfd, int mustchange) { int ofds[4]; int i; + int sverrno; for (i = 0; (myfd <= 2 || mustchange) && myfd != -1; i++) { assert(i < __arraycount(ofds)); @@ -573,15 +601,22 @@ dupgood(int myfd, int mustchange) } } + sverrno = 0; + if (myfd == -1 && i > 0) + sverrno = errno; + for (i--; i >= 0; i--) { host_close(ofds[i]); } + if (sverrno) + errno = sverrno; + return myfd; } static int -doconnect(bool noisy) +doconnect(void) { struct respwait rw; struct rsp_hdr rhdr; @@ -636,45 +671,31 @@ doconnect(bool noisy) while (host_connect(s, serv_sa, (socklen_t)serv_sa->sa_len) == -1) { if (errno == EINTR) continue; - error = errno; - if (noisy) - fprintf(stderr, "rump_sp: client connect failed: %s\n", - strerror(errno)); - errno = error; + ERRLOG(("rump_sp: client connect failed: %s\n", + strerror(errno))); return -1; } if ((error = parsetab[ptab_idx].connhook(s)) != 0) { - error = errno; - if (noisy) - fprintf(stderr, "rump_sp: connect hook failed\n"); - errno = error; + ERRLOG(("rump_sp: connect hook failed\n")); return -1; } - if ((n = host_read(s, banner, sizeof(banner)-1)) < 0) { - error = errno; - if (noisy) - fprintf(stderr, "rump_sp: failed to read banner\n"); - errno = error; + if ((n = host_read(s, banner, sizeof(banner)-1)) <= 0) { + ERRLOG(("rump_sp: failed to read banner\n")); return -1; } if (banner[n-1] != '\n') { - if (noisy) - fprintf(stderr, "rump_sp: invalid banner\n"); - errno = EINVAL; + ERRLOG(("rump_sp: invalid banner\n")); return -1; } banner[n] = '\0'; - /* parse the banner some day */ + /* XXX parse the banner some day */ flags = host_fcntl(s, F_GETFL, 0); if (host_fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) { - if (noisy) - fprintf(stderr, "rump_sp: socket fd NONBLOCK: %s\n", - strerror(errno)); - errno = EINVAL; + ERRLOG(("rump_sp: socket fd NONBLOCK: %s\n", strerror(errno))); return -1; } clispc.spc_fd = s; @@ -683,10 +704,7 @@ doconnect(bool noisy) /* setup kqueue, we want all signals and the fd */ if ((kq = dupgood(host_kqueue(), 0)) == -1) { - error = errno; - if (noisy) - fprintf(stderr, "rump_sp: cannot setup kqueue"); - errno = error; + ERRLOG(("rump_sp: cannot setup kqueue")); return -1; } @@ -696,10 +714,7 @@ doconnect(bool noisy) EV_SET(&kev[NSIG], clispc.spc_fd, EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0); if (host_kevent(kq, kev, NSIG+1, NULL, 0, NULL) == -1) { - error = errno; - if (noisy) - fprintf(stderr, "rump_sp: kevent() failed"); - errno = error; + ERRLOG(("rump_sp: kevent() failed")); return -1; } @@ -718,7 +733,7 @@ doinit(void) } void *rumpclient__dlsym(void *, const char *); -void *rumphijack_dlsym(void *, const char *); +void *rumphijack_dlsym(void *, const char *) __attribute__((__weak__)); void * rumpclient__dlsym(void *handle, const char *symbol) { @@ -727,19 +742,31 @@ rumpclient__dlsym(void *handle, const ch } __weak_alias(rumphijack_dlsym,rumpclient__dlsym); -static int init_done = 0; +static pid_t init_done = 0; int -rumpclient_init() +rumpclient_init(void) { char *p; int error; int rv = -1; int hstype; + pid_t mypid; - if (init_done) + /* + * Make sure we're not riding the context of a previous + * host fork. Note: it's *possible* that after n>1 forks + * we have the same pid as one of our exited parents, but + * I'm pretty sure there are 0 practical implications, since + * it means generations would have to skip rumpclient init. + */ + if (init_done == (mypid = getpid())) return 0; - init_done = 1; + + /* kq does not traverse fork() */ + if (init_done != 0) + kq = -1; + init_done = mypid; sigfillset(&fullset); @@ -750,9 +777,9 @@ rumpclient_init() #define FINDSYM2(_name_,_syscall_) \ if ((host_##_name_ = rumphijack_dlsym(RTLD_NEXT, \ #_syscall_)) == NULL) { \ - if (rumphijack_dlsym == dlsym) \ + if (rumphijack_dlsym == rumpclient__dlsym) \ host_##_name_ = _name_; /* static fallback */ \ - else \ + if (host_##_name_ == NULL) \ errx(1, "cannot find %s: %s", #_syscall_, \ dlerror()); \ } @@ -763,7 +790,7 @@ rumpclient_init() FINDSYM(fcntl) FINDSYM(poll) FINDSYM(read) - FINDSYM(sendto) + FINDSYM(sendmsg) FINDSYM(setsockopt) FINDSYM(dup) FINDSYM(kqueue) @@ -796,7 +823,7 @@ rumpclient_init() unsetenv("RUMPCLIENT__EXECFD"); hstype = HANDSHAKE_EXEC; } else { - if (doconnect(true) == -1) + if (doconnect() == -1) goto out; hstype = HANDSHAKE_GUEST; } @@ -869,7 +896,7 @@ rumpclient_fork_init(struct rumpclient_f if (doinit() == -1) return -1; - if (doconnect(false) == -1) + if (doconnect() == -1) return -1; error = handshake_req(&clispc, HANDSHAKE_FORK, rpf->fork_auth, @@ -884,6 +911,7 @@ rumpclient_fork_init(struct rumpclient_f return 0; } +/*ARGSUSED*/ void rumpclient_fork_cancel(struct rumpclient_fork *rpf) { @@ -967,7 +995,7 @@ rumpclient__closenotify(int *fdp, enum r } pid_t -rumpclient_fork() +rumpclient_fork(void) { return rumpclient__dofork(fork);