Home | History | Annotate | Line # | Download | only in librumpclient
rumpclient.c revision 1.6
      1 /*      $NetBSD: rumpclient.c,v 1.6 2010/11/29 16:08:03 pooka Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2010 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/mman.h>
     37 #include <sys/socket.h>
     38 
     39 #include <arpa/inet.h>
     40 #include <netinet/in.h>
     41 #include <netinet/tcp.h>
     42 
     43 #include <assert.h>
     44 #include <errno.h>
     45 #include <fcntl.h>
     46 #include <poll.h>
     47 #include <pthread.h>
     48 #include <stdarg.h>
     49 #include <stdio.h>
     50 #include <stdlib.h>
     51 #include <string.h>
     52 #include <unistd.h>
     53 
     54 #include <rump/rumpclient.h>
     55 
     56 #include "sp_common.c"
     57 
     58 static struct spclient clispc;
     59 
     60 static int
     61 syscall_req(struct spclient *spc, int sysnum,
     62 	const void *data, size_t dlen, void **resp)
     63 {
     64 	struct rsp_hdr rhdr;
     65 	struct respwait rw;
     66 	int rv;
     67 
     68 	rhdr.rsp_len = sizeof(rhdr) + dlen;
     69 	rhdr.rsp_class = RUMPSP_REQ;
     70 	rhdr.rsp_type = RUMPSP_SYSCALL;
     71 	rhdr.rsp_sysnum = sysnum;
     72 
     73 	do {
     74 		putwait(spc, &rw, &rhdr);
     75 		rv = dosend(spc, &rhdr, sizeof(rhdr));
     76 		rv = dosend(spc, data, dlen);
     77 		if (rv) {
     78 			unputwait(spc, &rw);
     79 			return rv;
     80 		}
     81 
     82 		rv = waitresp(spc, &rw);
     83 	} while (rv == EAGAIN);
     84 
     85 	*resp = rw.rw_data;
     86 	return rv;
     87 }
     88 
     89 static int
     90 send_copyin_resp(struct spclient *spc, uint64_t reqno, void *data, size_t dlen,
     91 	int wantstr)
     92 {
     93 	struct rsp_hdr rhdr;
     94 	int rv;
     95 
     96 	if (wantstr)
     97 		dlen = MIN(dlen, strlen(data)+1);
     98 
     99 	rhdr.rsp_len = sizeof(rhdr) + dlen;
    100 	rhdr.rsp_reqno = reqno;
    101 	rhdr.rsp_class = RUMPSP_RESP;
    102 	rhdr.rsp_type = RUMPSP_COPYIN;
    103 	rhdr.rsp_sysnum = 0;
    104 
    105 	sendlock(spc);
    106 	rv = dosend(spc, &rhdr, sizeof(rhdr));
    107 	rv = dosend(spc, data, dlen);
    108 	sendunlock(spc);
    109 
    110 	return rv;
    111 }
    112 
    113 static int
    114 send_anonmmap_resp(struct spclient *spc, uint64_t reqno, void *addr)
    115 {
    116 	struct rsp_hdr rhdr;
    117 	int rv;
    118 
    119 	rhdr.rsp_len = sizeof(rhdr) + sizeof(addr);
    120 	rhdr.rsp_reqno = reqno;
    121 	rhdr.rsp_class = RUMPSP_RESP;
    122 	rhdr.rsp_type = RUMPSP_ANONMMAP;
    123 	rhdr.rsp_sysnum = 0;
    124 
    125 	sendlock(spc);
    126 	rv = dosend(spc, &rhdr, sizeof(rhdr));
    127 	rv = dosend(spc, &addr, sizeof(addr));
    128 	sendunlock(spc);
    129 
    130 	return rv;
    131 }
    132 
    133 int
    134 rumpclient_syscall(int sysnum, const void *data, size_t dlen,
    135 	register_t *retval)
    136 {
    137 	struct rsp_sysresp *resp;
    138 	void *rdata;
    139 	int rv;
    140 
    141 	DPRINTF(("rumpsp syscall_req: syscall %d with %p/%zu\n",
    142 	    sysnum, data, dlen));
    143 
    144 	rv = syscall_req(&clispc, sysnum, data, dlen, &rdata);
    145 	if (rv)
    146 		return rv;
    147 
    148 	resp = rdata;
    149 	DPRINTF(("rumpsp syscall_resp: syscall %d error %d, rv: %d/%d\n",
    150 	    sysnum, rv, resp->rsys_retval[0], resp->rsys_retval[1]));
    151 
    152 	memcpy(retval, &resp->rsys_retval, sizeof(resp->rsys_retval));
    153 	rv = resp->rsys_error;
    154 	free(rdata);
    155 
    156 	return rv;
    157 }
    158 
    159 static void
    160 handlereq(struct spclient *spc)
    161 {
    162 	struct rsp_copydata *copydata;
    163 	void *mapaddr;
    164 	size_t maplen;
    165 	int reqtype = spc->spc_hdr.rsp_type;
    166 
    167 	switch (reqtype) {
    168 	case RUMPSP_COPYIN:
    169 	case RUMPSP_COPYINSTR:
    170 		/*LINTED*/
    171 		copydata = (struct rsp_copydata *)spc->spc_buf;
    172 		DPRINTF(("rump_sp handlereq: copyin request: %p/%zu\n",
    173 		    copydata->rcp_addr, copydata->rcp_len));
    174 		send_copyin_resp(spc, spc->spc_hdr.rsp_reqno,
    175 		    copydata->rcp_addr, copydata->rcp_len,
    176 		    reqtype == RUMPSP_COPYINSTR);
    177 		break;
    178 	case RUMPSP_COPYOUT:
    179 	case RUMPSP_COPYOUTSTR:
    180 		/*LINTED*/
    181 		copydata = (struct rsp_copydata *)spc->spc_buf;
    182 		DPRINTF(("rump_sp handlereq: copyout request: %p/%zu\n",
    183 		    copydata->rcp_addr, copydata->rcp_len));
    184 		/*LINTED*/
    185 		memcpy(copydata->rcp_addr, copydata->rcp_data,
    186 		    copydata->rcp_len);
    187 		break;
    188 	case RUMPSP_ANONMMAP:
    189 		/*LINTED*/
    190 		maplen = *(size_t *)spc->spc_buf;
    191 		mapaddr = mmap(NULL, maplen, PROT_READ|PROT_WRITE,
    192 		    MAP_ANON, -1, 0);
    193 		if (mapaddr == MAP_FAILED)
    194 			mapaddr = NULL;
    195 		DPRINTF(("rump_sp handlereq: anonmmap: %p\n", mapaddr));
    196 		send_anonmmap_resp(spc, spc->spc_hdr.rsp_reqno, mapaddr);
    197 		break;
    198 	default:
    199 		printf("PANIC: INVALID TYPE\n");
    200 		abort();
    201 		break;
    202 	}
    203 
    204 	spcfreebuf(spc);
    205 }
    206 
    207 int
    208 rumpclient_init()
    209 {
    210 	struct sockaddr *sap;
    211 	char *p;
    212 	unsigned idx;
    213 	int error, s;
    214 
    215 	if ((p = getenv("RUMP_SP_CLIENT")) == NULL) {
    216 		errno = ENOENT;
    217 		return -1;
    218 	}
    219 
    220 	if ((error = parseurl(p, &sap, &idx, 0)) != 0) {
    221 		errno = error;
    222 		return -1;
    223 	}
    224 
    225 	s = socket(parsetab[idx].domain, SOCK_STREAM, 0);
    226 	if (s == -1)
    227 		return -1;
    228 
    229 	if (connect(s, sap, sap->sa_len) == -1) {
    230 		error = errno;
    231 		fprintf(stderr, "rump_sp: client connect failed\n");
    232 		errno = error;
    233 		return -1;
    234 	}
    235 
    236 	if ((error = parsetab[idx].connhook(s)) != 0) {
    237 		error = errno;
    238 		fprintf(stderr, "rump_sp: connect hook failed\n");
    239 		errno = error;
    240 		return -1;
    241 	}
    242 	clispc.spc_fd = s;
    243 	TAILQ_INIT(&clispc.spc_respwait);
    244 	pthread_mutex_init(&clispc.spc_mtx, NULL);
    245 	pthread_cond_init(&clispc.spc_cv, NULL);
    246 
    247 	return 0;
    248 }
    249