2010-11-24 18:17:46 +03:00
|
|
|
/* $NetBSD: rumpuser_sp.c,v 1.12 2010/11/24 15:17:46 pooka Exp $ */
|
2010-10-28 00:44:49 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2010 Antti Kantee. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
|
|
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Sysproxy routines. This provides system RPC support over host sockets.
|
|
|
|
* The most notable limitation is that the client and server must share
|
|
|
|
* the same ABI. This does not mean that they have to be the same
|
|
|
|
* machine or that they need to run the same version of the host OS,
|
|
|
|
* just that they must agree on the data structures. This even *might*
|
|
|
|
* work correctly from one hardware architecture to another.
|
|
|
|
*
|
|
|
|
* Not finished yet, i.e. don't use in production. Lacks locking plus
|
|
|
|
* handling of multiple clients and unexpected connection closes.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/cdefs.h>
|
2010-11-24 18:17:46 +03:00
|
|
|
__RCSID("$NetBSD: rumpuser_sp.c,v 1.12 2010/11/24 15:17:46 pooka Exp $");
|
2010-10-28 00:44:49 +04:00
|
|
|
|
|
|
|
#include <sys/types.h>
|
2010-11-24 14:40:24 +03:00
|
|
|
#include <sys/atomic.h>
|
2010-10-28 00:44:49 +04:00
|
|
|
#include <sys/mman.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/tcp.h>
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <poll.h>
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include <rump/rumpuser.h>
|
|
|
|
|
2010-11-04 23:54:07 +03:00
|
|
|
#include "sp_common.c"
|
2010-10-28 00:44:49 +04:00
|
|
|
|
|
|
|
#define MAXCLI 4
|
|
|
|
|
|
|
|
static struct pollfd pfdlist[MAXCLI];
|
|
|
|
static struct spclient spclist[MAXCLI];
|
2010-11-24 14:40:24 +03:00
|
|
|
static unsigned int disco;
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-01 16:49:10 +03:00
|
|
|
static struct rumpuser_sp_ops spops;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Manual wrappers, since librump does not have access to the
|
|
|
|
* user namespace wrapped interfaces.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void
|
|
|
|
lwproc_switch(struct lwp *l)
|
|
|
|
{
|
|
|
|
|
2010-11-01 16:55:19 +03:00
|
|
|
spops.spop_schedule();
|
2010-11-01 16:49:10 +03:00
|
|
|
spops.spop_lwproc_switch(l);
|
2010-11-01 16:55:19 +03:00
|
|
|
spops.spop_unschedule();
|
2010-11-01 16:49:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
lwproc_release(void)
|
|
|
|
{
|
|
|
|
|
2010-11-01 16:55:19 +03:00
|
|
|
spops.spop_schedule();
|
2010-11-01 16:49:10 +03:00
|
|
|
spops.spop_lwproc_release();
|
2010-11-01 16:55:19 +03:00
|
|
|
spops.spop_unschedule();
|
2010-11-01 16:49:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2010-11-22 23:42:19 +03:00
|
|
|
lwproc_newproc(struct spclient *spc)
|
2010-11-01 16:49:10 +03:00
|
|
|
{
|
|
|
|
int rv;
|
|
|
|
|
2010-11-01 16:55:19 +03:00
|
|
|
spops.spop_schedule();
|
2010-11-22 23:42:19 +03:00
|
|
|
rv = spops.spop_lwproc_newproc(spc);
|
2010-11-01 16:55:19 +03:00
|
|
|
spops.spop_unschedule();
|
2010-11-01 16:49:10 +03:00
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2010-11-19 20:09:44 +03:00
|
|
|
static int
|
|
|
|
lwproc_newlwp(pid_t pid)
|
|
|
|
{
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
spops.spop_schedule();
|
|
|
|
rv = spops.spop_lwproc_newlwp(pid);
|
|
|
|
spops.spop_unschedule();
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2010-11-01 16:49:10 +03:00
|
|
|
static struct lwp *
|
|
|
|
lwproc_curlwp(void)
|
|
|
|
{
|
|
|
|
struct lwp *l;
|
|
|
|
|
2010-11-01 16:55:19 +03:00
|
|
|
spops.spop_schedule();
|
2010-11-01 16:49:10 +03:00
|
|
|
l = spops.spop_lwproc_curlwp();
|
2010-11-01 16:55:19 +03:00
|
|
|
spops.spop_unschedule();
|
2010-11-01 16:49:10 +03:00
|
|
|
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
|
2010-11-19 20:09:44 +03:00
|
|
|
static pid_t
|
|
|
|
lwproc_getpid(void)
|
|
|
|
{
|
|
|
|
pid_t p;
|
|
|
|
|
|
|
|
spops.spop_schedule();
|
|
|
|
p = spops.spop_getpid();
|
|
|
|
spops.spop_unschedule();
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2010-11-01 16:49:10 +03:00
|
|
|
static int
|
|
|
|
rumpsyscall(int sysnum, void *data, register_t *retval)
|
|
|
|
{
|
|
|
|
int rv;
|
|
|
|
|
2010-11-01 16:55:19 +03:00
|
|
|
spops.spop_schedule();
|
2010-11-01 16:49:10 +03:00
|
|
|
rv = spops.spop_syscall(sysnum, data, retval);
|
2010-11-01 16:55:19 +03:00
|
|
|
spops.spop_unschedule();
|
2010-11-01 16:49:10 +03:00
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
static uint64_t
|
|
|
|
nextreq(struct spclient *spc)
|
|
|
|
{
|
|
|
|
uint64_t nw;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&spc->spc_mtx);
|
|
|
|
nw = spc->spc_nextreq++;
|
|
|
|
pthread_mutex_unlock(&spc->spc_mtx);
|
|
|
|
|
|
|
|
return nw;
|
|
|
|
}
|
|
|
|
|
2010-10-28 00:44:49 +04:00
|
|
|
static int
|
|
|
|
send_syscall_resp(struct spclient *spc, uint64_t reqno, int error,
|
2010-11-19 18:25:49 +03:00
|
|
|
register_t *retval)
|
2010-10-28 00:44:49 +04:00
|
|
|
{
|
|
|
|
struct rsp_hdr rhdr;
|
|
|
|
struct rsp_sysresp sysresp;
|
2010-11-19 18:25:49 +03:00
|
|
|
int rv;
|
2010-10-28 00:44:49 +04:00
|
|
|
|
|
|
|
rhdr.rsp_len = sizeof(rhdr) + sizeof(sysresp);
|
|
|
|
rhdr.rsp_reqno = reqno;
|
2010-11-19 18:25:49 +03:00
|
|
|
rhdr.rsp_class = RUMPSP_RESP;
|
|
|
|
rhdr.rsp_type = RUMPSP_SYSCALL;
|
2010-10-28 00:44:49 +04:00
|
|
|
rhdr.rsp_sysnum = 0;
|
|
|
|
|
|
|
|
sysresp.rsys_error = error;
|
2010-11-19 18:25:49 +03:00
|
|
|
memcpy(sysresp.rsys_retval, retval, sizeof(sysresp.rsys_retval));
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
sendlock(spc);
|
|
|
|
rv = dosend(spc, &rhdr, sizeof(rhdr));
|
|
|
|
rv = dosend(spc, &sysresp, sizeof(sysresp));
|
|
|
|
sendunlock(spc);
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
return rv;
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2010-11-19 18:25:49 +03:00
|
|
|
copyin_req(struct spclient *spc, const void *remaddr, size_t dlen, void **resp)
|
2010-10-28 00:44:49 +04:00
|
|
|
{
|
|
|
|
struct rsp_hdr rhdr;
|
|
|
|
struct rsp_copydata copydata;
|
2010-11-19 18:25:49 +03:00
|
|
|
struct respwait rw;
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
DPRINTF(("copyin_req: %zu bytes from %p\n", dlen, remaddr));
|
2010-10-28 00:44:49 +04:00
|
|
|
|
|
|
|
rhdr.rsp_len = sizeof(rhdr) + sizeof(copydata);
|
2010-11-19 18:25:49 +03:00
|
|
|
rhdr.rsp_class = RUMPSP_REQ;
|
|
|
|
rhdr.rsp_type = RUMPSP_COPYIN;
|
2010-10-28 00:44:49 +04:00
|
|
|
rhdr.rsp_sysnum = 0;
|
|
|
|
|
|
|
|
copydata.rcp_addr = __UNCONST(remaddr);
|
|
|
|
copydata.rcp_len = dlen;
|
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
putwait(spc, &rw, &rhdr);
|
|
|
|
|
|
|
|
sendlock(spc);
|
|
|
|
rv = dosend(spc, &rhdr, sizeof(rhdr));
|
|
|
|
rv = dosend(spc, ©data, sizeof(copydata));
|
|
|
|
sendunlock(spc);
|
|
|
|
if (rv)
|
|
|
|
return rv; /* XXX: unputwait */
|
|
|
|
|
|
|
|
rv = waitresp(spc, &rw);
|
|
|
|
|
|
|
|
DPRINTF(("copyin: response %d\n", rv));
|
|
|
|
|
|
|
|
*resp = rw.rw_data;
|
|
|
|
return rv;
|
2010-10-28 00:44:49 +04:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
send_copyout_req(struct spclient *spc, const void *remaddr,
|
|
|
|
const void *data, size_t dlen)
|
|
|
|
{
|
|
|
|
struct rsp_hdr rhdr;
|
|
|
|
struct rsp_copydata copydata;
|
2010-11-19 18:25:49 +03:00
|
|
|
int rv;
|
|
|
|
|
|
|
|
DPRINTF(("copyout_req (async): %zu bytes to %p\n", dlen, remaddr));
|
2010-10-28 00:44:49 +04:00
|
|
|
|
|
|
|
rhdr.rsp_len = sizeof(rhdr) + sizeof(copydata) + dlen;
|
2010-11-19 18:25:49 +03:00
|
|
|
rhdr.rsp_reqno = nextreq(spc);
|
|
|
|
rhdr.rsp_class = RUMPSP_REQ;
|
|
|
|
rhdr.rsp_type = RUMPSP_COPYOUT;
|
2010-10-28 00:44:49 +04:00
|
|
|
rhdr.rsp_sysnum = 0;
|
|
|
|
|
|
|
|
copydata.rcp_addr = __UNCONST(remaddr);
|
|
|
|
copydata.rcp_len = dlen;
|
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
sendlock(spc);
|
|
|
|
rv = dosend(spc, &rhdr, sizeof(rhdr));
|
|
|
|
rv = dosend(spc, ©data, sizeof(copydata));
|
|
|
|
rv = dosend(spc, data, dlen);
|
|
|
|
sendunlock(spc);
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
return rv;
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2010-11-19 18:25:49 +03:00
|
|
|
anonmmap_req(struct spclient *spc, size_t howmuch, void **resp)
|
2010-10-28 00:44:49 +04:00
|
|
|
{
|
|
|
|
struct rsp_hdr rhdr;
|
2010-11-19 18:25:49 +03:00
|
|
|
struct respwait rw;
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
DPRINTF(("anonmmap_req: %zu bytes\n", howmuch));
|
2010-10-28 00:44:49 +04:00
|
|
|
|
|
|
|
rhdr.rsp_len = sizeof(rhdr) + sizeof(howmuch);
|
2010-11-19 18:25:49 +03:00
|
|
|
rhdr.rsp_class = RUMPSP_REQ;
|
|
|
|
rhdr.rsp_type = RUMPSP_ANONMMAP;
|
2010-10-28 00:44:49 +04:00
|
|
|
rhdr.rsp_sysnum = 0;
|
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
putwait(spc, &rw, &rhdr);
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
sendlock(spc);
|
|
|
|
rv = dosend(spc, &rhdr, sizeof(rhdr));
|
|
|
|
rv = dosend(spc, &howmuch, sizeof(howmuch));
|
|
|
|
sendunlock(spc);
|
|
|
|
if (rv)
|
|
|
|
return rv; /* XXX: unputwait */
|
|
|
|
|
|
|
|
rv = waitresp(spc, &rw);
|
|
|
|
*resp = rw.rw_data;
|
|
|
|
|
|
|
|
DPRINTF(("anonmmap: mapped at %p\n", **(void ***)resp));
|
|
|
|
|
|
|
|
return rv;
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2010-11-24 14:40:24 +03:00
|
|
|
spcref(struct spclient *spc)
|
2010-10-28 00:44:49 +04:00
|
|
|
{
|
|
|
|
|
2010-11-24 14:40:24 +03:00
|
|
|
pthread_mutex_lock(&spc->spc_mtx);
|
|
|
|
spc->spc_refcnt++;
|
|
|
|
pthread_mutex_unlock(&spc->spc_mtx);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
spcrelease(struct spclient *spc)
|
|
|
|
{
|
|
|
|
int ref;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&spc->spc_mtx);
|
|
|
|
ref = --spc->spc_refcnt;
|
|
|
|
pthread_mutex_unlock(&spc->spc_mtx);
|
|
|
|
|
|
|
|
if (ref > 0)
|
|
|
|
return;
|
|
|
|
|
2010-11-24 18:17:46 +03:00
|
|
|
DPRINTF(("spcrelease: spc %p fd %d\n", spc, spc->spc_fd));
|
|
|
|
|
|
|
|
_DIAGASSERT(TAILQ_EMPTY(spc->spc_respwait));
|
2010-11-24 14:40:24 +03:00
|
|
|
_DIAGASSERT(spc->spc_buf == NULL);
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-19 20:09:44 +03:00
|
|
|
lwproc_switch(spc->spc_mainlwp);
|
2010-11-01 16:49:10 +03:00
|
|
|
lwproc_release();
|
2010-11-24 14:40:24 +03:00
|
|
|
spc->spc_mainlwp = NULL;
|
|
|
|
|
|
|
|
close(spc->spc_fd);
|
|
|
|
spc->spc_fd = -1;
|
2010-11-24 18:17:46 +03:00
|
|
|
spc->spc_dying = 0;
|
2010-11-24 14:40:24 +03:00
|
|
|
|
|
|
|
atomic_inc_uint(&disco);
|
2010-10-28 18:37:29 +04:00
|
|
|
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
|
2010-11-24 14:40:24 +03:00
|
|
|
static void
|
|
|
|
serv_handledisco(unsigned int idx)
|
|
|
|
{
|
|
|
|
struct spclient *spc = &spclist[idx];
|
|
|
|
|
|
|
|
DPRINTF(("rump_sp: disconnecting [%u]\n", idx));
|
|
|
|
|
2010-11-24 18:17:46 +03:00
|
|
|
pfdlist[idx].fd = -1;
|
|
|
|
pfdlist[idx].revents = 0;
|
|
|
|
pthread_mutex_lock(&spc->spc_mtx);
|
|
|
|
spc->spc_dying = 1;
|
|
|
|
kickall(spc);
|
|
|
|
pthread_mutex_unlock(&spc->spc_mtx);
|
2010-11-24 14:40:24 +03:00
|
|
|
spcrelease(spc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned
|
|
|
|
serv_handleconn(int fd, connecthook_fn connhook, int busy)
|
2010-10-28 00:44:49 +04:00
|
|
|
{
|
|
|
|
struct sockaddr_storage ss;
|
|
|
|
socklen_t sl = sizeof(ss);
|
2010-11-24 14:40:24 +03:00
|
|
|
int newfd, flags;
|
2010-10-28 00:44:49 +04:00
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
/*LINTED: cast ok */
|
|
|
|
newfd = accept(fd, (struct sockaddr *)&ss, &sl);
|
|
|
|
if (newfd == -1)
|
2010-11-24 14:40:24 +03:00
|
|
|
return 0;
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-24 14:40:24 +03:00
|
|
|
if (busy) {
|
2010-10-28 00:44:49 +04:00
|
|
|
close(newfd); /* EBUSY */
|
2010-11-24 14:40:24 +03:00
|
|
|
return 0;
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
|
2010-11-24 14:40:24 +03:00
|
|
|
/* XXX: should do some sort of handshake too */
|
|
|
|
|
2010-10-28 00:44:49 +04:00
|
|
|
flags = fcntl(newfd, F_GETFL, 0);
|
|
|
|
if (fcntl(newfd, F_SETFL, flags | O_NONBLOCK) == -1) {
|
|
|
|
close(newfd);
|
2010-11-24 14:40:24 +03:00
|
|
|
return 0;
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
|
2010-11-24 14:40:24 +03:00
|
|
|
if (connhook(newfd) != 0) {
|
2010-10-28 00:44:49 +04:00
|
|
|
close(newfd);
|
2010-11-24 14:40:24 +03:00
|
|
|
return 0;
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* find empty slot the simple way */
|
|
|
|
for (i = 0; i < MAXCLI; i++) {
|
2010-11-24 18:17:46 +03:00
|
|
|
if (pfdlist[i].fd == -1 && spclist[i].spc_dying == 0)
|
2010-10-28 18:37:29 +04:00
|
|
|
break;
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
|
2010-11-24 14:40:24 +03:00
|
|
|
if (lwproc_newproc(&spclist[i]) != 0) {
|
2010-11-22 23:42:19 +03:00
|
|
|
close(newfd);
|
2010-11-24 14:40:24 +03:00
|
|
|
return 0;
|
2010-11-22 23:42:19 +03:00
|
|
|
}
|
|
|
|
|
2010-10-28 00:44:49 +04:00
|
|
|
assert(i < MAXCLI);
|
|
|
|
|
|
|
|
pfdlist[i].fd = newfd;
|
|
|
|
spclist[i].spc_fd = newfd;
|
2010-11-19 20:09:44 +03:00
|
|
|
spclist[i].spc_mainlwp = lwproc_curlwp();
|
2010-11-19 18:25:49 +03:00
|
|
|
spclist[i].spc_istatus = SPCSTATUS_BUSY; /* dedicated receiver */
|
2010-11-19 20:09:44 +03:00
|
|
|
spclist[i].spc_pid = lwproc_getpid();
|
2010-11-24 14:40:24 +03:00
|
|
|
spclist[i].spc_refcnt = 1;
|
2010-11-19 18:25:49 +03:00
|
|
|
|
|
|
|
TAILQ_INIT(&spclist[i].spc_respwait);
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-10-28 18:37:29 +04:00
|
|
|
DPRINTF(("rump_sp: added new connection at idx %u, pid %d\n",
|
2010-11-19 20:09:44 +03:00
|
|
|
i, lwproc_getpid()));
|
2010-10-28 18:37:29 +04:00
|
|
|
|
2010-11-01 16:49:10 +03:00
|
|
|
lwproc_switch(NULL);
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-24 14:40:24 +03:00
|
|
|
return i;
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
serv_handlesyscall(struct spclient *spc, struct rsp_hdr *rhdr, uint8_t *data)
|
|
|
|
{
|
2010-11-19 18:25:49 +03:00
|
|
|
register_t retval[2] = {0, 0};
|
2010-10-28 00:44:49 +04:00
|
|
|
int rv, sysnum;
|
|
|
|
|
|
|
|
sysnum = (int)rhdr->rsp_sysnum;
|
|
|
|
DPRINTF(("rump_sp: handling syscall %d from client %d\n",
|
|
|
|
sysnum, 0));
|
|
|
|
|
2010-11-19 20:09:44 +03:00
|
|
|
lwproc_newlwp(spc->spc_pid);
|
2010-11-01 16:49:10 +03:00
|
|
|
rv = rumpsyscall(sysnum, data, retval);
|
|
|
|
lwproc_switch(NULL);
|
2010-11-17 20:36:14 +03:00
|
|
|
free(data);
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
DPRINTF(("rump_sp: got return value %d & %d/%d\n",
|
|
|
|
rv, retval[0], retval[1]));
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-04 23:54:07 +03:00
|
|
|
send_syscall_resp(spc, rhdr->rsp_reqno, rv, retval);
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
struct sysbouncearg {
|
|
|
|
struct spclient *sba_spc;
|
|
|
|
struct rsp_hdr sba_hdr;
|
|
|
|
uint8_t *sba_data;
|
|
|
|
};
|
|
|
|
static void *
|
|
|
|
serv_syscallbouncer(void *arg)
|
|
|
|
{
|
|
|
|
struct sysbouncearg *barg = arg;
|
|
|
|
|
|
|
|
serv_handlesyscall(barg->sba_spc, &barg->sba_hdr, barg->sba_data);
|
2010-11-24 18:17:46 +03:00
|
|
|
spcrelease(barg->sba_spc);
|
2010-11-19 18:25:49 +03:00
|
|
|
free(arg);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-10-28 00:44:49 +04:00
|
|
|
int
|
2010-11-22 23:42:19 +03:00
|
|
|
rumpuser_sp_copyin(void *arg, const void *uaddr, void *kaddr, size_t len)
|
2010-10-28 00:44:49 +04:00
|
|
|
{
|
2010-11-22 23:42:19 +03:00
|
|
|
struct spclient *spc = arg;
|
2010-11-19 20:47:44 +03:00
|
|
|
void *rdata = NULL; /* XXXuninit */
|
2010-11-24 18:17:46 +03:00
|
|
|
int rv;
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-24 18:17:46 +03:00
|
|
|
rv = copyin_req(spc, uaddr, len, &rdata);
|
|
|
|
if (rv)
|
|
|
|
return EFAULT;
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
memcpy(kaddr, rdata, len);
|
|
|
|
free(rdata);
|
2010-10-28 00:44:49 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2010-11-22 23:42:19 +03:00
|
|
|
rumpuser_sp_copyout(void *arg, const void *kaddr, void *uaddr, size_t dlen)
|
2010-10-28 00:44:49 +04:00
|
|
|
{
|
2010-11-22 23:42:19 +03:00
|
|
|
struct spclient *spc = arg;
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
if (send_copyout_req(spc, uaddr, kaddr, dlen) != 0)
|
|
|
|
return EFAULT;
|
2010-10-28 00:44:49 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2010-11-22 23:42:19 +03:00
|
|
|
rumpuser_sp_anonmmap(void *arg, size_t howmuch, void **addr)
|
2010-10-28 00:44:49 +04:00
|
|
|
{
|
2010-11-22 23:42:19 +03:00
|
|
|
struct spclient *spc = arg;
|
2010-11-19 18:25:49 +03:00
|
|
|
void *resp, *rdata;
|
|
|
|
int rv;
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
rv = anonmmap_req(spc, howmuch, &rdata);
|
|
|
|
if (rv)
|
|
|
|
return rv;
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
resp = *(void **)rdata;
|
|
|
|
free(rdata);
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
if (resp == NULL) {
|
2010-10-28 00:44:49 +04:00
|
|
|
return ENOMEM;
|
2010-11-19 18:25:49 +03:00
|
|
|
}
|
2010-10-28 00:44:49 +04:00
|
|
|
|
|
|
|
*addr = resp;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Startup routines and mainloop for server.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct spservarg {
|
|
|
|
int sps_sock;
|
|
|
|
connecthook_fn sps_connhook;
|
|
|
|
};
|
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
static void
|
|
|
|
handlereq(struct spclient *spc)
|
|
|
|
{
|
|
|
|
struct sysbouncearg *sba;
|
|
|
|
pthread_attr_t pattr;
|
|
|
|
pthread_t pt;
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
/* XXX: check that it's a syscall */
|
|
|
|
|
|
|
|
sba = malloc(sizeof(*sba));
|
|
|
|
if (sba == NULL) {
|
|
|
|
/* panic */
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
sba->sba_spc = spc;
|
|
|
|
sba->sba_hdr = spc->spc_hdr;
|
|
|
|
sba->sba_data = spc->spc_buf;
|
|
|
|
|
|
|
|
spc->spc_buf = NULL;
|
|
|
|
spc->spc_off = 0;
|
|
|
|
|
|
|
|
pthread_attr_init(&pattr);
|
|
|
|
pthread_attr_setdetachstate(&pattr, 1);
|
|
|
|
|
2010-11-24 14:40:24 +03:00
|
|
|
spcref(spc);
|
2010-11-19 18:25:49 +03:00
|
|
|
if ((rv = pthread_create(&pt, &pattr, serv_syscallbouncer, sba)) != 0) {
|
|
|
|
/* panic */
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-28 00:44:49 +04:00
|
|
|
static void *
|
|
|
|
spserver(void *arg)
|
|
|
|
{
|
|
|
|
struct spservarg *sarg = arg;
|
2010-11-24 14:40:24 +03:00
|
|
|
struct spclient *spc;
|
2010-10-28 00:44:49 +04:00
|
|
|
unsigned idx;
|
|
|
|
int seen;
|
|
|
|
int rv;
|
2010-11-24 14:40:24 +03:00
|
|
|
unsigned int nfds, maxidx;
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-24 14:40:24 +03:00
|
|
|
for (idx = 0; idx < MAXCLI; idx++) {
|
2010-10-28 00:44:49 +04:00
|
|
|
pfdlist[idx].fd = -1;
|
|
|
|
pfdlist[idx].events = POLLIN;
|
2010-11-24 14:40:24 +03:00
|
|
|
|
|
|
|
spc = &spclist[idx];
|
|
|
|
pthread_mutex_init(&spc->spc_mtx, NULL);
|
|
|
|
pthread_cond_init(&spc->spc_cv, NULL);
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
pfdlist[0].fd = sarg->sps_sock;
|
|
|
|
pfdlist[0].events = POLLIN;
|
|
|
|
nfds = 1;
|
|
|
|
maxidx = 0;
|
|
|
|
|
|
|
|
DPRINTF(("rump_sp: server mainloop\n"));
|
|
|
|
|
|
|
|
for (;;) {
|
2010-11-24 14:40:24 +03:00
|
|
|
/* g/c hangarounds (eventually) */
|
|
|
|
if (disco) {
|
|
|
|
int discoed;
|
|
|
|
|
|
|
|
discoed = atomic_swap_uint(&disco, 0);
|
|
|
|
while (discoed--) {
|
|
|
|
nfds--;
|
|
|
|
idx = maxidx;
|
2010-11-24 18:17:46 +03:00
|
|
|
while (idx) {
|
2010-11-24 14:40:24 +03:00
|
|
|
if (pfdlist[idx].fd != -1) {
|
|
|
|
maxidx = idx;
|
|
|
|
break;
|
|
|
|
}
|
2010-11-24 18:17:46 +03:00
|
|
|
idx--;
|
2010-11-24 14:40:24 +03:00
|
|
|
}
|
|
|
|
DPRINTF(("rump_sp: set maxidx to [%u]\n",
|
|
|
|
maxidx));
|
2010-11-24 18:17:46 +03:00
|
|
|
assert(maxidx+1 >= nfds);
|
2010-11-24 14:40:24 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-28 00:44:49 +04:00
|
|
|
DPRINTF(("rump_sp: loop nfd %d\n", maxidx+1));
|
|
|
|
seen = 0;
|
|
|
|
rv = poll(pfdlist, maxidx+1, INFTIM);
|
|
|
|
assert(maxidx+1 <= MAXCLI);
|
|
|
|
assert(rv != 0);
|
|
|
|
if (rv == -1) {
|
|
|
|
if (errno == EINTR)
|
|
|
|
continue;
|
|
|
|
fprintf(stderr, "rump_spserver: poll returned %d\n",
|
|
|
|
errno);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-11-24 18:17:46 +03:00
|
|
|
for (idx = 0; seen < rv && idx < MAXCLI; idx++) {
|
2010-10-28 00:44:49 +04:00
|
|
|
if ((pfdlist[idx].revents & POLLIN) == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
seen++;
|
|
|
|
DPRINTF(("rump_sp: activity at [%u] %d/%d\n",
|
|
|
|
idx, seen, rv));
|
|
|
|
if (idx > 0) {
|
2010-11-24 14:40:24 +03:00
|
|
|
spc = &spclist[idx];
|
2010-10-28 00:44:49 +04:00
|
|
|
DPRINTF(("rump_sp: mainloop read [%u]\n", idx));
|
|
|
|
switch (readframe(spc)) {
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
case -1:
|
2010-10-28 18:37:29 +04:00
|
|
|
serv_handledisco(idx);
|
2010-10-28 00:44:49 +04:00
|
|
|
break;
|
|
|
|
default:
|
2010-11-19 18:25:49 +03:00
|
|
|
switch (spc->spc_hdr.rsp_class) {
|
|
|
|
case RUMPSP_RESP:
|
|
|
|
kickwaiter(spc);
|
|
|
|
break;
|
|
|
|
case RUMPSP_REQ:
|
|
|
|
handlereq(spc);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
printf("PANIC\n");
|
|
|
|
abort();
|
|
|
|
break;
|
|
|
|
}
|
2010-10-28 00:44:49 +04:00
|
|
|
break;
|
|
|
|
}
|
2010-11-24 14:40:24 +03:00
|
|
|
|
2010-10-28 00:44:49 +04:00
|
|
|
} else {
|
|
|
|
DPRINTF(("rump_sp: mainloop new connection\n"));
|
2010-11-24 14:40:24 +03:00
|
|
|
|
|
|
|
idx = serv_handleconn(pfdlist[0].fd,
|
|
|
|
sarg->sps_connhook, nfds == MAXCLI);
|
|
|
|
if (idx)
|
|
|
|
nfds++;
|
|
|
|
if (idx > maxidx)
|
|
|
|
maxidx = idx;
|
2010-11-24 18:17:46 +03:00
|
|
|
DPRINTF(("rump_sp: maxid now %d\n", maxidx));
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2010-11-04 23:54:07 +03:00
|
|
|
rumpuser_sp_init(const struct rumpuser_sp_ops *spopsp, const char *url)
|
2010-10-28 00:44:49 +04:00
|
|
|
{
|
2010-11-04 23:54:07 +03:00
|
|
|
pthread_t pt;
|
2010-10-28 00:44:49 +04:00
|
|
|
struct spservarg *sarg;
|
|
|
|
struct sockaddr *sap;
|
2010-11-04 23:54:07 +03:00
|
|
|
char *p;
|
|
|
|
unsigned idx;
|
|
|
|
int error, s;
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-04 23:54:07 +03:00
|
|
|
p = strdup(url);
|
|
|
|
if (p == NULL)
|
|
|
|
return ENOMEM;
|
|
|
|
error = parseurl(p, &sap, &idx, 1);
|
|
|
|
free(p);
|
|
|
|
if (error)
|
|
|
|
return error;
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-04 23:54:07 +03:00
|
|
|
s = socket(parsetab[idx].domain, SOCK_STREAM, 0);
|
|
|
|
if (s == -1)
|
|
|
|
return errno;
|
|
|
|
|
|
|
|
spops = *spopsp;
|
|
|
|
sarg = malloc(sizeof(*sarg));
|
|
|
|
if (sarg == NULL) {
|
|
|
|
close(s);
|
|
|
|
return ENOMEM;
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
|
2010-11-04 23:54:07 +03:00
|
|
|
sarg->sps_sock = s;
|
|
|
|
sarg->sps_connhook = parsetab[idx].connhook;
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-04 23:54:07 +03:00
|
|
|
/* sloppy error recovery */
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-04 23:54:07 +03:00
|
|
|
/*LINTED*/
|
|
|
|
if (bind(s, sap, sap->sa_len) == -1) {
|
|
|
|
fprintf(stderr, "rump_sp: server bind failed\n");
|
|
|
|
return errno;
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
2010-11-04 23:54:07 +03:00
|
|
|
if (listen(s, 20) == -1) {
|
|
|
|
fprintf(stderr, "rump_sp: server listen failed\n");
|
|
|
|
return errno;
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
|
2010-11-04 23:54:07 +03:00
|
|
|
if ((error = pthread_create(&pt, NULL, spserver, sarg)) != 0) {
|
|
|
|
fprintf(stderr, "rump_sp: cannot create wrkr thread\n");
|
2010-10-28 00:44:49 +04:00
|
|
|
return errno;
|
|
|
|
}
|
2010-11-04 23:54:07 +03:00
|
|
|
pthread_detach(pt);
|
2010-10-28 00:44:49 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|