Home | History | Annotate | Line # | Download | only in librumpclient
rumpclient.c revision 1.3
      1 /*      $NetBSD: rumpclient.c,v 1.3 2010/11/19 15:25:49 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/types.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 	putwait(spc, &rw, &rhdr);
     74 
     75 	sendlock(spc);
     76 	rv = dosend(spc, &rhdr, sizeof(rhdr));
     77 	rv = dosend(spc, data, dlen);
     78 	sendunlock(spc);
     79 	if (rv)
     80 		return rv; /* XXX: unputwait */
     81 
     82 	rv = waitresp(spc, &rw);
     83 	*resp = rw.rw_data;
     84 	return rv;
     85 }
     86 
     87 static int
     88 send_copyin_resp(struct spclient *spc, uint64_t reqno, void *data, size_t dlen)
     89 {
     90 	struct rsp_hdr rhdr;
     91 	int rv;
     92 
     93 	rhdr.rsp_len = sizeof(rhdr) + dlen;
     94 	rhdr.rsp_reqno = reqno;
     95 	rhdr.rsp_class = RUMPSP_RESP;
     96 	rhdr.rsp_type = RUMPSP_COPYIN;
     97 	rhdr.rsp_sysnum = 0;
     98 
     99 	sendlock(spc);
    100 	rv = dosend(spc, &rhdr, sizeof(rhdr));
    101 	rv = dosend(spc, data, dlen);
    102 	sendunlock(spc);
    103 
    104 	return rv;
    105 }
    106 
    107 static int
    108 send_anonmmap_resp(struct spclient *spc, uint64_t reqno, void *addr)
    109 {
    110 	struct rsp_hdr rhdr;
    111 	int rv;
    112 
    113 	rhdr.rsp_len = sizeof(rhdr) + sizeof(addr);
    114 	rhdr.rsp_reqno = reqno;
    115 	rhdr.rsp_class = RUMPSP_RESP;
    116 	rhdr.rsp_type = RUMPSP_ANONMMAP;
    117 	rhdr.rsp_sysnum = 0;
    118 
    119 	sendlock(spc);
    120 	rv = dosend(spc, &rhdr, sizeof(rhdr));
    121 	rv = dosend(spc, &addr, sizeof(addr));
    122 	sendunlock(spc);
    123 
    124 	return rv;
    125 }
    126 
    127 int
    128 rumpclient_syscall(int sysnum, const void *data, size_t dlen,
    129 	register_t *retval)
    130 {
    131 	struct rsp_sysresp *resp;
    132 	void *rdata;
    133 	int rv;
    134 
    135 	DPRINTF(("rumpsp syscall_req: syscall %d with %p/%zu\n",
    136 	    sysnum, data, dlen));
    137 
    138 	rv = syscall_req(&clispc, sysnum, data, dlen, &rdata);
    139 	if (rv)
    140 		return rv;
    141 
    142 	resp = rdata;
    143 	DPRINTF(("rumpsp syscall_resp: syscall %d error %d, rv: %d/%d\n",
    144 	    sysnum, rv, resp->rsys_retval[0], resp->rsys_retval[1]));
    145 
    146 	memcpy(retval, &resp->rsys_retval, sizeof(resp->rsys_retval));
    147 	rv = resp->rsys_error;
    148 	free(rdata);
    149 
    150 	return rv;
    151 }
    152 
    153 static void
    154 handlereq(struct spclient *spc)
    155 {
    156 	struct rsp_copydata *copydata;
    157 	void *mapaddr;
    158 	size_t maplen;
    159 
    160 	switch (spc->spc_hdr.rsp_type) {
    161 	case RUMPSP_COPYIN:
    162 		/*LINTED*/
    163 		copydata = (struct rsp_copydata *)spc->spc_buf;
    164 		DPRINTF(("rump_sp handlereq: copyin request: %p/%zu\n",
    165 		    copydata->rcp_addr, copydata->rcp_len));
    166 		send_copyin_resp(spc, spc->spc_hdr.rsp_reqno,
    167 		    copydata->rcp_addr, copydata->rcp_len);
    168 		break;
    169 	case RUMPSP_COPYOUT:
    170 		/*LINTED*/
    171 		copydata = (struct rsp_copydata *)spc->spc_buf;
    172 		DPRINTF(("rump_sp handlereq: copyout request: %p/%zu\n",
    173 		    copydata->rcp_addr, copydata->rcp_len));
    174 		/*LINTED*/
    175 		memcpy(copydata->rcp_addr, copydata->rcp_data,
    176 		    copydata->rcp_len);
    177 		break;
    178 	case RUMPSP_ANONMMAP:
    179 		/*LINTED*/
    180 		maplen = *(size_t *)spc->spc_buf;
    181 		mapaddr = mmap(NULL, maplen, PROT_READ|PROT_WRITE,
    182 		    MAP_ANON, -1, 0);
    183 		if (mapaddr == MAP_FAILED)
    184 			mapaddr = NULL;
    185 		DPRINTF(("rump_sp handlereq: anonmmap: %p\n", mapaddr));
    186 		send_anonmmap_resp(spc, spc->spc_hdr.rsp_reqno, mapaddr);
    187 		break;
    188 	default:
    189 		printf("PANIC: INVALID TYPE\n");
    190 		abort();
    191 		break;
    192 	}
    193 
    194 	free(spc->spc_buf);
    195 	spc->spc_off = 0;
    196 	spc->spc_buf = NULL;
    197 }
    198 
    199 int
    200 rumpclient_init()
    201 {
    202 	struct sockaddr *sap;
    203 	char *p;
    204 	unsigned idx;
    205 	int error, s;
    206 
    207 	if ((p = getenv("RUMP_SP_CLIENT")) == NULL) {
    208 		errno = ENOENT;
    209 		return -1;
    210 	}
    211 
    212 	if ((error = parseurl(p, &sap, &idx, 0)) != 0) {
    213 		errno = error;
    214 		return -1;
    215 	}
    216 
    217 	s = socket(parsetab[idx].domain, SOCK_STREAM, 0);
    218 	if (s == -1)
    219 		return -1;
    220 
    221 	if (connect(s, sap, sap->sa_len) == -1) {
    222 		error = errno;
    223 		fprintf(stderr, "rump_sp: client connect failed\n");
    224 		errno = error;
    225 		return -1;
    226 	}
    227 	if ((error = parsetab[idx].connhook(s)) != 0) {
    228 		error = errno;
    229 		fprintf(stderr, "rump_sp: connect hook failed\n");
    230 		errno = error;
    231 		return -1;
    232 	}
    233 	clispc.spc_fd = s;
    234 	TAILQ_INIT(&clispc.spc_respwait);
    235 	pthread_mutex_init(&clispc.spc_mtx, NULL);
    236 	pthread_cond_init(&clispc.spc_cv, NULL);
    237 
    238 	return 0;
    239 }
    240