version 1.35, 2011/02/24 12:25:44 |
version 1.44, 2011/03/15 09:35:05 |
|
|
*/ |
*/ |
|
|
#include <sys/cdefs.h> |
#include <sys/cdefs.h> |
__RCSID("$NetBSD"); |
__RCSID("$NetBSD$"); |
|
|
#include <sys/param.h> |
#include <sys/param.h> |
#include <sys/event.h> |
#include <sys/event.h> |
Line 66 int (*host_connect)(int, const struct so |
|
Line 66 int (*host_connect)(int, const struct so |
|
int (*host_fcntl)(int, int, ...); |
int (*host_fcntl)(int, int, ...); |
int (*host_poll)(struct pollfd *, nfds_t, int); |
int (*host_poll)(struct pollfd *, nfds_t, int); |
ssize_t (*host_read)(int, void *, size_t); |
ssize_t (*host_read)(int, void *, size_t); |
ssize_t (*host_sendto)(int, const void *, size_t, int, |
ssize_t (*host_sendmsg)(int, const struct msghdr *, int); |
const struct sockaddr *, socklen_t); |
|
int (*host_setsockopt)(int, int, int, const void *, socklen_t); |
int (*host_setsockopt)(int, int, int, const void *, socklen_t); |
int (*host_dup)(int); |
int (*host_dup)(int); |
|
|
Line 86 static struct spclient clispc = { |
|
Line 85 static struct spclient clispc = { |
|
static int kq = -1; |
static int kq = -1; |
static sigset_t fullset; |
static sigset_t fullset; |
|
|
static int doconnect(bool); |
static int doconnect(void); |
static int handshake_req(struct spclient *, int, void *, int, bool); |
static int handshake_req(struct spclient *, int, void *, int, bool); |
|
|
/* |
/* |
Line 95 static int handshake_req(struct spclient |
|
Line 94 static int handshake_req(struct spclient |
|
*/ |
*/ |
static time_t retrytimo = 0; |
static time_t retrytimo = 0; |
|
|
|
/* always defined to nothingness for now */ |
|
#define ERRLOG(a) |
|
|
static int |
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; |
struct timeval starttime, curtime; |
time_t prevreconmsg; |
time_t prevreconmsg; |
Line 104 send_with_recon(struct spclient *spc, co |
|
Line 106 send_with_recon(struct spclient *spc, co |
|
int rv; |
int rv; |
|
|
for (prevreconmsg = 0, reconretries = 0;;) { |
for (prevreconmsg = 0, reconretries = 0;;) { |
rv = dosend(spc, data, dlen); |
rv = dosend(spc, iov, iovlen); |
if (__predict_false(rv == ENOTCONN || rv == EBADF)) { |
if (__predict_false(rv == ENOTCONN || rv == EBADF)) { |
/* no persistent connections */ |
/* no persistent connections */ |
if (retrytimo == 0) { |
if (retrytimo == 0) { |
Line 112 send_with_recon(struct spclient *spc, co |
|
Line 114 send_with_recon(struct spclient *spc, co |
|
break; |
break; |
} |
} |
if (retrytimo == RUMPCLIENT_RETRYCONN_DIE) |
if (retrytimo == RUMPCLIENT_RETRYCONN_DIE) |
exit(1); |
_exit(1); |
|
|
if (!prevreconmsg) { |
if (!prevreconmsg) { |
prevreconmsg = time(NULL); |
prevreconmsg = time(NULL); |
Line 153 send_with_recon(struct spclient *spc, co |
|
Line 155 send_with_recon(struct spclient *spc, co |
|
} |
} |
reconretries++; |
reconretries++; |
|
|
if ((rv = doconnect(false)) != 0) |
if ((rv = doconnect()) != 0) |
continue; |
continue; |
if ((rv = handshake_req(&clispc, HANDSHAKE_GUEST, |
if ((rv = handshake_req(&clispc, HANDSHAKE_GUEST, |
NULL, 0, true)) != 0) |
NULL, 0, true)) != 0) |
Line 203 cliwaitresp(struct spclient *spc, struct |
|
Line 205 cliwaitresp(struct spclient *spc, struct |
|
|
|
dosig = 0; |
dosig = 0; |
for (gotresp = 0; !gotresp; ) { |
for (gotresp = 0; !gotresp; ) { |
switch (readframe(spc)) { |
/* |
case 0: |
* typically we don't have a frame waiting |
rv = host_kevent(kq, NULL, 0, |
* when we come in here, so call kevent now |
kev, __arraycount(kev), NULL); |
*/ |
|
rv = host_kevent(kq, NULL, 0, |
|
kev, __arraycount(kev), NULL); |
|
|
if (__predict_false(rv == -1)) { |
if (__predict_false(rv == -1)) { |
goto cleanup; |
goto activity; |
} |
} |
|
|
/* |
/* |
* XXX: don't know how this can |
* XXX: don't know how this can happen |
* happen (timeout cannot expire |
* (timeout cannot expire since there |
* since there isn't one), but |
* isn't one), but it does happen. |
* it does happen |
* treat it as an expectional condition |
*/ |
* and go through tryread to determine |
if (__predict_false(rv == 0)) |
* alive status. |
continue; |
*/ |
|
if (__predict_false(rv == 0)) |
for (i = 0; i < rv; i++) { |
goto activity; |
if (kev[i].filter |
|
== EVFILT_SIGNAL) |
for (i = 0; i < rv; i++) { |
dosig++; |
if (kev[i].filter == EVFILT_SIGNAL) |
} |
dosig++; |
if (dosig) |
} |
goto cleanup; |
if (dosig) |
|
goto cleanup; |
|
|
|
/* |
|
* ok, activity. try to read a frame to |
|
* determine what happens next. |
|
*/ |
|
activity: |
|
switch (readframe(spc)) { |
|
case 0: |
continue; |
continue; |
case -1: |
case -1: |
imalive = false; |
imalive = false; |
goto cleanup; |
goto cleanup; |
default: |
default: |
|
/* case 1 */ |
break; |
break; |
} |
} |
|
|
Line 287 syscall_req(struct spclient *spc, sigset |
|
Line 300 syscall_req(struct spclient *spc, sigset |
|
{ |
{ |
struct rsp_hdr rhdr; |
struct rsp_hdr rhdr; |
struct respwait rw; |
struct respwait rw; |
|
struct iovec iov[2]; |
int rv; |
int rv; |
|
|
rhdr.rsp_len = sizeof(rhdr) + dlen; |
rhdr.rsp_len = sizeof(rhdr) + dlen; |
Line 294 syscall_req(struct spclient *spc, sigset |
|
Line 308 syscall_req(struct spclient *spc, sigset |
|
rhdr.rsp_type = RUMPSP_SYSCALL; |
rhdr.rsp_type = RUMPSP_SYSCALL; |
rhdr.rsp_sysnum = sysnum; |
rhdr.rsp_sysnum = sysnum; |
|
|
|
IOVPUT(iov[0], rhdr); |
|
IOVPUT_WITHSIZE(iov[1], __UNCONST(data), dlen); |
|
|
do { |
do { |
putwait(spc, &rw, &rhdr); |
putwait(spc, &rw, &rhdr); |
if ((rv = send_with_recon(spc, &rhdr, sizeof(rhdr))) != 0) { |
if ((rv = send_with_recon(spc, iov, __arraycount(iov))) != 0) { |
unputwait(spc, &rw); |
|
continue; |
|
} |
|
if ((rv = send_with_recon(spc, data, dlen)) != 0) { |
|
unputwait(spc, &rw); |
unputwait(spc, &rw); |
continue; |
continue; |
} |
} |
Line 319 handshake_req(struct spclient *spc, int |
|
Line 332 handshake_req(struct spclient *spc, int |
|
int cancel, bool haslock) |
int cancel, bool haslock) |
{ |
{ |
struct handshake_fork rf; |
struct handshake_fork rf; |
|
const char *myprogname = NULL; /* XXXgcc */ |
struct rsp_hdr rhdr; |
struct rsp_hdr rhdr; |
struct respwait rw; |
struct respwait rw; |
sigset_t omask; |
sigset_t omask; |
size_t bonus; |
size_t bonus; |
|
struct iovec iov[2]; |
int rv; |
int rv; |
|
|
if (type == HANDSHAKE_FORK) { |
if (type == HANDSHAKE_FORK) { |
bonus = sizeof(rf); |
bonus = sizeof(rf); |
} else { |
} else { |
bonus = strlen(getprogname())+1; |
myprogname = getprogname(); |
|
bonus = strlen(myprogname)+1; |
} |
} |
|
|
/* performs server handshake */ |
/* performs server handshake */ |
Line 337 handshake_req(struct spclient *spc, int |
|
Line 353 handshake_req(struct spclient *spc, int |
|
rhdr.rsp_type = RUMPSP_HANDSHAKE; |
rhdr.rsp_type = RUMPSP_HANDSHAKE; |
rhdr.rsp_handshake = type; |
rhdr.rsp_handshake = type; |
|
|
|
IOVPUT(iov[0], rhdr); |
|
|
pthread_sigmask(SIG_SETMASK, &fullset, &omask); |
pthread_sigmask(SIG_SETMASK, &fullset, &omask); |
if (haslock) |
if (haslock) |
putwait_locked(spc, &rw, &rhdr); |
putwait_locked(spc, &rw, &rhdr); |
else |
else |
putwait(spc, &rw, &rhdr); |
putwait(spc, &rw, &rhdr); |
rv = dosend(spc, &rhdr, sizeof(rhdr)); |
|
if (type == HANDSHAKE_FORK) { |
if (type == HANDSHAKE_FORK) { |
memcpy(rf.rf_auth, data, sizeof(rf.rf_auth)); /* uh, why? */ |
memcpy(rf.rf_auth, data, sizeof(rf.rf_auth)); /* uh, why? */ |
rf.rf_cancel = cancel; |
rf.rf_cancel = cancel; |
rv = send_with_recon(spc, &rf, sizeof(rf)); |
IOVPUT(iov[1], rf); |
} else { |
} 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 (rv || cancel) { |
if (haslock) |
if (haslock) |
unputwait_locked(spc, &rw); |
unputwait_locked(spc, &rw); |
Line 377 prefork_req(struct spclient *spc, sigset |
|
Line 395 prefork_req(struct spclient *spc, sigset |
|
{ |
{ |
struct rsp_hdr rhdr; |
struct rsp_hdr rhdr; |
struct respwait rw; |
struct respwait rw; |
|
struct iovec iov[1]; |
int rv; |
int rv; |
|
|
rhdr.rsp_len = sizeof(rhdr); |
rhdr.rsp_len = sizeof(rhdr); |
Line 384 prefork_req(struct spclient *spc, sigset |
|
Line 403 prefork_req(struct spclient *spc, sigset |
|
rhdr.rsp_type = RUMPSP_PREFORK; |
rhdr.rsp_type = RUMPSP_PREFORK; |
rhdr.rsp_error = 0; |
rhdr.rsp_error = 0; |
|
|
|
IOVPUT(iov[0], rhdr); |
|
|
do { |
do { |
putwait(spc, &rw, &rhdr); |
putwait(spc, &rw, &rhdr); |
rv = send_with_recon(spc, &rhdr, sizeof(rhdr)); |
rv = send_with_recon(spc, iov, __arraycount(iov)); |
if (rv != 0) { |
if (rv != 0) { |
unputwait(spc, &rw); |
unputwait(spc, &rw); |
continue; |
continue; |
Line 430 send_copyin_resp(struct spclient *spc, u |
|
Line 451 send_copyin_resp(struct spclient *spc, u |
|
int wantstr) |
int wantstr) |
{ |
{ |
struct rsp_hdr rhdr; |
struct rsp_hdr rhdr; |
|
struct iovec iov[2]; |
|
|
if (wantstr) |
if (wantstr) |
dlen = MIN(dlen, strlen(data)+1); |
dlen = MIN(dlen, strlen(data)+1); |
Line 440 send_copyin_resp(struct spclient *spc, u |
|
Line 462 send_copyin_resp(struct spclient *spc, u |
|
rhdr.rsp_type = RUMPSP_COPYIN; |
rhdr.rsp_type = RUMPSP_COPYIN; |
rhdr.rsp_sysnum = 0; |
rhdr.rsp_sysnum = 0; |
|
|
|
IOVPUT(iov[0], rhdr); |
|
IOVPUT_WITHSIZE(iov[1], data, dlen); |
|
|
if (resp_sendlock(spc) != 0) |
if (resp_sendlock(spc) != 0) |
return; |
return; |
(void)dosend(spc, &rhdr, sizeof(rhdr)); |
(void)SENDIOV(spc, iov); |
(void)dosend(spc, data, dlen); |
|
sendunlock(spc); |
sendunlock(spc); |
} |
} |
|
|
|
|
send_anonmmap_resp(struct spclient *spc, uint64_t reqno, void *addr) |
send_anonmmap_resp(struct spclient *spc, uint64_t reqno, void *addr) |
{ |
{ |
struct rsp_hdr rhdr; |
struct rsp_hdr rhdr; |
|
struct iovec iov[2]; |
|
|
rhdr.rsp_len = sizeof(rhdr) + sizeof(addr); |
rhdr.rsp_len = sizeof(rhdr) + sizeof(addr); |
rhdr.rsp_reqno = reqno; |
rhdr.rsp_reqno = reqno; |
Line 458 send_anonmmap_resp(struct spclient *spc, |
|
Line 483 send_anonmmap_resp(struct spclient *spc, |
|
rhdr.rsp_type = RUMPSP_ANONMMAP; |
rhdr.rsp_type = RUMPSP_ANONMMAP; |
rhdr.rsp_sysnum = 0; |
rhdr.rsp_sysnum = 0; |
|
|
|
IOVPUT(iov[0], rhdr); |
|
IOVPUT(iov[1], addr); |
|
|
if (resp_sendlock(spc) != 0) |
if (resp_sendlock(spc) != 0) |
return; |
return; |
(void)dosend(spc, &rhdr, sizeof(rhdr)); |
(void)SENDIOV(spc, iov); |
(void)dosend(spc, &addr, sizeof(addr)); |
|
sendunlock(spc); |
sendunlock(spc); |
} |
} |
|
|
Line 581 dupgood(int myfd, int mustchange) |
|
Line 608 dupgood(int myfd, int mustchange) |
|
} |
} |
|
|
static int |
static int |
doconnect(bool noisy) |
doconnect(void) |
{ |
{ |
struct respwait rw; |
struct respwait rw; |
struct rsp_hdr rhdr; |
struct rsp_hdr rhdr; |
Line 636 doconnect(bool noisy) |
|
Line 663 doconnect(bool noisy) |
|
while (host_connect(s, serv_sa, (socklen_t)serv_sa->sa_len) == -1) { |
while (host_connect(s, serv_sa, (socklen_t)serv_sa->sa_len) == -1) { |
if (errno == EINTR) |
if (errno == EINTR) |
continue; |
continue; |
error = errno; |
ERRLOG(("rump_sp: client connect failed: %s\n", |
if (noisy) |
strerror(errno))); |
fprintf(stderr, "rump_sp: client connect failed: %s\n", |
|
strerror(errno)); |
|
errno = error; |
|
return -1; |
return -1; |
} |
} |
|
|
if ((error = parsetab[ptab_idx].connhook(s)) != 0) { |
if ((error = parsetab[ptab_idx].connhook(s)) != 0) { |
error = errno; |
ERRLOG(("rump_sp: connect hook failed\n")); |
if (noisy) |
|
fprintf(stderr, "rump_sp: connect hook failed\n"); |
|
errno = error; |
|
return -1; |
return -1; |
} |
} |
|
|
if ((n = host_read(s, banner, sizeof(banner)-1)) < 0) { |
if ((n = host_read(s, banner, sizeof(banner)-1)) < 0) { |
error = errno; |
ERRLOG(("rump_sp: failed to read banner\n")); |
if (noisy) |
|
fprintf(stderr, "rump_sp: failed to read banner\n"); |
|
errno = error; |
|
return -1; |
return -1; |
} |
} |
|
|
if (banner[n-1] != '\n') { |
if (banner[n-1] != '\n') { |
if (noisy) |
ERRLOG(("rump_sp: invalid banner\n")); |
fprintf(stderr, "rump_sp: invalid banner\n"); |
|
errno = EINVAL; |
|
return -1; |
return -1; |
} |
} |
banner[n] = '\0'; |
banner[n] = '\0'; |
Line 671 doconnect(bool noisy) |
|
Line 687 doconnect(bool noisy) |
|
|
|
flags = host_fcntl(s, F_GETFL, 0); |
flags = host_fcntl(s, F_GETFL, 0); |
if (host_fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) { |
if (host_fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) { |
if (noisy) |
ERRLOG(("rump_sp: socket fd NONBLOCK: %s\n", strerror(errno))); |
fprintf(stderr, "rump_sp: socket fd NONBLOCK: %s\n", |
|
strerror(errno)); |
|
errno = EINVAL; |
|
return -1; |
return -1; |
} |
} |
clispc.spc_fd = s; |
clispc.spc_fd = s; |
Line 683 doconnect(bool noisy) |
|
Line 696 doconnect(bool noisy) |
|
|
|
/* setup kqueue, we want all signals and the fd */ |
/* setup kqueue, we want all signals and the fd */ |
if ((kq = dupgood(host_kqueue(), 0)) == -1) { |
if ((kq = dupgood(host_kqueue(), 0)) == -1) { |
error = errno; |
ERRLOG(("rump_sp: cannot setup kqueue")); |
if (noisy) |
|
fprintf(stderr, "rump_sp: cannot setup kqueue"); |
|
errno = error; |
|
return -1; |
return -1; |
} |
} |
|
|
Line 696 doconnect(bool noisy) |
|
Line 706 doconnect(bool noisy) |
|
EV_SET(&kev[NSIG], clispc.spc_fd, |
EV_SET(&kev[NSIG], clispc.spc_fd, |
EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0); |
EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0); |
if (host_kevent(kq, kev, NSIG+1, NULL, 0, NULL) == -1) { |
if (host_kevent(kq, kev, NSIG+1, NULL, 0, NULL) == -1) { |
error = errno; |
ERRLOG(("rump_sp: kevent() failed")); |
if (noisy) |
|
fprintf(stderr, "rump_sp: kevent() failed"); |
|
errno = error; |
|
return -1; |
return -1; |
} |
} |
|
|
Line 727 rumpclient__dlsym(void *handle, const ch |
|
Line 734 rumpclient__dlsym(void *handle, const ch |
|
} |
} |
__weak_alias(rumphijack_dlsym,rumpclient__dlsym); |
__weak_alias(rumphijack_dlsym,rumpclient__dlsym); |
|
|
static int init_done = 0; |
static pid_t init_done = 0; |
|
|
int |
int |
rumpclient_init() |
rumpclient_init() |
Line 736 rumpclient_init() |
|
Line 743 rumpclient_init() |
|
int error; |
int error; |
int rv = -1; |
int rv = -1; |
int hstype; |
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; |
return 0; |
init_done = 1; |
|
|
/* kq does not traverse fork() */ |
|
if (init_done != 0) |
|
kq = -1; |
|
init_done = mypid; |
|
|
sigfillset(&fullset); |
sigfillset(&fullset); |
|
|
Line 750 rumpclient_init() |
|
Line 769 rumpclient_init() |
|
#define FINDSYM2(_name_,_syscall_) \ |
#define FINDSYM2(_name_,_syscall_) \ |
if ((host_##_name_ = rumphijack_dlsym(RTLD_NEXT, \ |
if ((host_##_name_ = rumphijack_dlsym(RTLD_NEXT, \ |
#_syscall_)) == NULL) { \ |
#_syscall_)) == NULL) { \ |
if (rumphijack_dlsym == dlsym) \ |
if (rumphijack_dlsym == rumpclient__dlsym) \ |
host_##_name_ = _name_; /* static fallback */ \ |
host_##_name_ = _name_; /* static fallback */ \ |
else \ |
if (host_##_name_ == NULL) \ |
errx(1, "cannot find %s: %s", #_syscall_, \ |
errx(1, "cannot find %s: %s", #_syscall_, \ |
dlerror()); \ |
dlerror()); \ |
} |
} |
Line 763 rumpclient_init() |
|
Line 782 rumpclient_init() |
|
FINDSYM(fcntl) |
FINDSYM(fcntl) |
FINDSYM(poll) |
FINDSYM(poll) |
FINDSYM(read) |
FINDSYM(read) |
FINDSYM(sendto) |
FINDSYM(sendmsg) |
FINDSYM(setsockopt) |
FINDSYM(setsockopt) |
FINDSYM(dup) |
FINDSYM(dup) |
FINDSYM(kqueue) |
FINDSYM(kqueue) |
Line 796 rumpclient_init() |
|
Line 815 rumpclient_init() |
|
unsetenv("RUMPCLIENT__EXECFD"); |
unsetenv("RUMPCLIENT__EXECFD"); |
hstype = HANDSHAKE_EXEC; |
hstype = HANDSHAKE_EXEC; |
} else { |
} else { |
if (doconnect(true) == -1) |
if (doconnect() == -1) |
goto out; |
goto out; |
hstype = HANDSHAKE_GUEST; |
hstype = HANDSHAKE_GUEST; |
} |
} |
Line 869 rumpclient_fork_init(struct rumpclient_f |
|
Line 888 rumpclient_fork_init(struct rumpclient_f |
|
|
|
if (doinit() == -1) |
if (doinit() == -1) |
return -1; |
return -1; |
if (doconnect(false) == -1) |
if (doconnect() == -1) |
return -1; |
return -1; |
|
|
error = handshake_req(&clispc, HANDSHAKE_FORK, rpf->fork_auth, |
error = handshake_req(&clispc, HANDSHAKE_FORK, rpf->fork_auth, |
Line 884 rumpclient_fork_init(struct rumpclient_f |
|
Line 903 rumpclient_fork_init(struct rumpclient_f |
|
return 0; |
return 0; |
} |
} |
|
|
|
/*ARGSUSED*/ |
void |
void |
rumpclient_fork_cancel(struct rumpclient_fork *rpf) |
rumpclient_fork_cancel(struct rumpclient_fork *rpf) |
{ |
{ |