1 /* $NetBSD: rumpclient.c,v 1.10 2010/12/16 17:05:44 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 handshake_req(struct spclient *spc) 91 { 92 struct rsp_hdr rhdr; 93 struct respwait rw; 94 int rv; 95 96 /* performs server handshake */ 97 rhdr.rsp_len = sizeof(rhdr); 98 rhdr.rsp_class = RUMPSP_REQ; 99 rhdr.rsp_type = RUMPSP_HANDSHAKE; 100 rhdr.rsp_handshake = HANDSHAKE_GUEST; 101 102 putwait(spc, &rw, &rhdr); 103 rv = dosend(spc, &rhdr, sizeof(rhdr)); 104 if (rv != 0) { 105 unputwait(spc, &rw); 106 return rv; 107 } 108 109 rv = waitresp(spc, &rw); 110 if (rv) 111 return rv; 112 113 rv = *(int *)rw.rw_data; 114 free(rw.rw_data); 115 116 return rv; 117 } 118 119 static int 120 send_copyin_resp(struct spclient *spc, uint64_t reqno, void *data, size_t dlen, 121 int wantstr) 122 { 123 struct rsp_hdr rhdr; 124 int rv; 125 126 if (wantstr) 127 dlen = MIN(dlen, strlen(data)+1); 128 129 rhdr.rsp_len = sizeof(rhdr) + dlen; 130 rhdr.rsp_reqno = reqno; 131 rhdr.rsp_class = RUMPSP_RESP; 132 rhdr.rsp_type = RUMPSP_COPYIN; 133 rhdr.rsp_sysnum = 0; 134 135 sendlock(spc); 136 rv = dosend(spc, &rhdr, sizeof(rhdr)); 137 rv = dosend(spc, data, dlen); 138 sendunlock(spc); 139 140 return rv; 141 } 142 143 static int 144 send_anonmmap_resp(struct spclient *spc, uint64_t reqno, void *addr) 145 { 146 struct rsp_hdr rhdr; 147 int rv; 148 149 rhdr.rsp_len = sizeof(rhdr) + sizeof(addr); 150 rhdr.rsp_reqno = reqno; 151 rhdr.rsp_class = RUMPSP_RESP; 152 rhdr.rsp_type = RUMPSP_ANONMMAP; 153 rhdr.rsp_sysnum = 0; 154 155 sendlock(spc); 156 rv = dosend(spc, &rhdr, sizeof(rhdr)); 157 rv = dosend(spc, &addr, sizeof(addr)); 158 sendunlock(spc); 159 160 return rv; 161 } 162 163 int 164 rumpclient_syscall(int sysnum, const void *data, size_t dlen, 165 register_t *retval) 166 { 167 struct rsp_sysresp *resp; 168 void *rdata; 169 int rv; 170 171 DPRINTF(("rumpsp syscall_req: syscall %d with %p/%zu\n", 172 sysnum, data, dlen)); 173 174 rv = syscall_req(&clispc, sysnum, data, dlen, &rdata); 175 if (rv) 176 return rv; 177 178 resp = rdata; 179 DPRINTF(("rumpsp syscall_resp: syscall %d error %d, rv: %d/%d\n", 180 sysnum, rv, resp->rsys_retval[0], resp->rsys_retval[1])); 181 182 memcpy(retval, &resp->rsys_retval, sizeof(resp->rsys_retval)); 183 rv = resp->rsys_error; 184 free(rdata); 185 186 return rv; 187 } 188 189 static void 190 handlereq(struct spclient *spc) 191 { 192 struct rsp_copydata *copydata; 193 void *mapaddr; 194 size_t maplen; 195 int reqtype = spc->spc_hdr.rsp_type; 196 197 switch (reqtype) { 198 case RUMPSP_COPYIN: 199 case RUMPSP_COPYINSTR: 200 /*LINTED*/ 201 copydata = (struct rsp_copydata *)spc->spc_buf; 202 DPRINTF(("rump_sp handlereq: copyin request: %p/%zu\n", 203 copydata->rcp_addr, copydata->rcp_len)); 204 send_copyin_resp(spc, spc->spc_hdr.rsp_reqno, 205 copydata->rcp_addr, copydata->rcp_len, 206 reqtype == RUMPSP_COPYINSTR); 207 break; 208 case RUMPSP_COPYOUT: 209 case RUMPSP_COPYOUTSTR: 210 /*LINTED*/ 211 copydata = (struct rsp_copydata *)spc->spc_buf; 212 DPRINTF(("rump_sp handlereq: copyout request: %p/%zu\n", 213 copydata->rcp_addr, copydata->rcp_len)); 214 /*LINTED*/ 215 memcpy(copydata->rcp_addr, copydata->rcp_data, 216 copydata->rcp_len); 217 break; 218 case RUMPSP_ANONMMAP: 219 /*LINTED*/ 220 maplen = *(size_t *)spc->spc_buf; 221 mapaddr = mmap(NULL, maplen, PROT_READ|PROT_WRITE, 222 MAP_ANON, -1, 0); 223 if (mapaddr == MAP_FAILED) 224 mapaddr = NULL; 225 DPRINTF(("rump_sp handlereq: anonmmap: %p\n", mapaddr)); 226 send_anonmmap_resp(spc, spc->spc_hdr.rsp_reqno, mapaddr); 227 break; 228 default: 229 printf("PANIC: INVALID TYPE\n"); 230 abort(); 231 break; 232 } 233 234 spcfreebuf(spc); 235 } 236 237 int 238 rumpclient_init() 239 { 240 char banner[MAXBANNER]; 241 struct sockaddr *sap; 242 char *p; 243 unsigned idx; 244 ssize_t n; 245 int error, s; 246 247 if ((p = getenv("RUMP_SERVER")) == NULL) { 248 errno = ENOENT; 249 return -1; 250 } 251 252 if ((error = parseurl(p, &sap, &idx, 0)) != 0) { 253 errno = error; 254 return -1; 255 } 256 257 s = socket(parsetab[idx].domain, SOCK_STREAM, 0); 258 if (s == -1) 259 return -1; 260 261 if (connect(s, sap, (socklen_t)sap->sa_len) == -1) { 262 error = errno; 263 fprintf(stderr, "rump_sp: client connect failed\n"); 264 errno = error; 265 return -1; 266 } 267 268 if ((n = read(s, banner, sizeof(banner)-1)) < 0) { 269 error = errno; 270 fprintf(stderr, "rump_sp: failed to read banner\n"); 271 errno = error; 272 return -1; 273 } 274 275 if (banner[n-1] != '\n') { 276 fprintf(stderr, "rump_sp: invalid banner\n"); 277 errno = EINVAL; 278 return -1; 279 } 280 banner[n] = '\0'; 281 282 /* parse the banner some day */ 283 284 if ((error = parsetab[idx].connhook(s)) != 0) { 285 error = errno; 286 fprintf(stderr, "rump_sp: connect hook failed\n"); 287 errno = error; 288 return -1; 289 } 290 291 pthread_mutex_init(&clispc.spc_mtx, NULL); 292 pthread_cond_init(&clispc.spc_cv, NULL); 293 clispc.spc_fd = s; 294 TAILQ_INIT(&clispc.spc_respwait); 295 296 error = handshake_req(&clispc); 297 if (error) { 298 pthread_mutex_destroy(&clispc.spc_mtx); 299 pthread_cond_destroy(&clispc.spc_cv); 300 close(s); 301 } 302 return error; 303 } 304