rumpclient.c revision 1.16 1 /* $NetBSD: rumpclient.c,v 1.16 2011/01/14 13:12:15 pooka Exp $ */
2
3 /*
4 * Copyright (c) 2010, 2011 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/event.h>
37 #include <sys/mman.h>
38 #include <sys/socket.h>
39
40 #include <arpa/inet.h>
41 #include <netinet/in.h>
42 #include <netinet/tcp.h>
43
44 #include <assert.h>
45 #include <dlfcn.h>
46 #include <errno.h>
47 #include <fcntl.h>
48 #include <link.h>
49 #include <poll.h>
50 #include <pthread.h>
51 #include <signal.h>
52 #include <stdarg.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <unistd.h>
57
58 #include <rump/rumpclient.h>
59
60 #define HOSTOPS
61 int (*host_socket)(int, int, int);
62 int (*host_close)(int);
63 int (*host_connect)(int, const struct sockaddr *, socklen_t);
64 int (*host_fcntl)(int, int, ...);
65 int (*host_poll)(struct pollfd *, nfds_t, int);
66 int (*host_pollts)(struct pollfd *, nfds_t, const struct timespec *,
67 const sigset_t *);
68 ssize_t (*host_read)(int, void *, size_t);
69 ssize_t (*host_sendto)(int, const void *, size_t, int,
70 const struct sockaddr *, socklen_t);
71 int (*host_setsockopt)(int, int, int, const void *, socklen_t);
72
73 #include "sp_common.c"
74
75 static struct spclient clispc = {
76 .spc_fd = -1,
77 };
78
79 static int kq;
80 static sigset_t fullset;
81
82 static int
83 waitresp(struct spclient *spc, struct respwait *rw, sigset_t *mask)
84 {
85
86 pthread_mutex_lock(&spc->spc_mtx);
87 sendunlockl(spc);
88
89 rw->rw_error = 0;
90 while (!rw->rw_done && rw->rw_error == 0
91 && spc->spc_state != SPCSTATE_DYING){
92 /* are we free to receive? */
93 if (spc->spc_istatus == SPCSTATUS_FREE) {
94 struct kevent kev[8];
95 int gotresp, dosig, rv, i;
96
97 spc->spc_istatus = SPCSTATUS_BUSY;
98 pthread_mutex_unlock(&spc->spc_mtx);
99
100 dosig = 0;
101 for (gotresp = 0; !gotresp; ) {
102 switch (readframe(spc)) {
103 case 0:
104 rv = kevent(kq, NULL, 0,
105 kev, __arraycount(kev), NULL);
106 assert(rv > 0);
107 for (i = 0; i < rv; i++) {
108 if (kev[i].filter
109 == EVFILT_SIGNAL)
110 dosig++;
111 }
112 if (dosig)
113 goto cleanup;
114
115 continue;
116 case -1:
117 spc->spc_state = SPCSTATE_DYING;
118 goto cleanup;
119 default:
120 break;
121 }
122
123 switch (spc->spc_hdr.rsp_class) {
124 case RUMPSP_RESP:
125 case RUMPSP_ERROR:
126 kickwaiter(spc);
127 gotresp = spc->spc_hdr.rsp_reqno ==
128 rw->rw_reqno;
129 break;
130 case RUMPSP_REQ:
131 handlereq(spc);
132 break;
133 default:
134 /* panic */
135 break;
136 }
137 }
138
139 cleanup:
140 pthread_mutex_lock(&spc->spc_mtx);
141 if (spc->spc_istatus == SPCSTATUS_WANTED)
142 kickall(spc);
143 spc->spc_istatus = SPCSTATUS_FREE;
144
145 /* take one for the team */
146 if (dosig) {
147 pthread_mutex_unlock(&spc->spc_mtx);
148 pthread_sigmask(SIG_SETMASK, mask, NULL);
149 pthread_sigmask(SIG_SETMASK, &fullset, NULL);
150 pthread_mutex_lock(&spc->spc_mtx);
151 }
152 } else {
153 spc->spc_istatus = SPCSTATUS_WANTED;
154 pthread_cond_wait(&rw->rw_cv, &spc->spc_mtx);
155 }
156 }
157 TAILQ_REMOVE(&spc->spc_respwait, rw, rw_entries);
158 pthread_mutex_unlock(&spc->spc_mtx);
159 pthread_cond_destroy(&rw->rw_cv);
160
161 if (spc->spc_state == SPCSTATE_DYING)
162 return ENOTCONN;
163 return rw->rw_error;
164 }
165
166
167 static int
168 syscall_req(struct spclient *spc, int sysnum,
169 const void *data, size_t dlen, void **resp)
170 {
171 struct rsp_hdr rhdr;
172 struct respwait rw;
173 sigset_t omask;
174 int rv;
175
176 rhdr.rsp_len = sizeof(rhdr) + dlen;
177 rhdr.rsp_class = RUMPSP_REQ;
178 rhdr.rsp_type = RUMPSP_SYSCALL;
179 rhdr.rsp_sysnum = sysnum;
180
181 pthread_sigmask(SIG_SETMASK, &fullset, &omask);
182 do {
183
184 putwait(spc, &rw, &rhdr);
185 rv = dosend(spc, &rhdr, sizeof(rhdr));
186 rv = dosend(spc, data, dlen);
187 if (rv) {
188 unputwait(spc, &rw);
189 pthread_sigmask(SIG_SETMASK, &omask, NULL);
190 return rv;
191 }
192
193 rv = waitresp(spc, &rw, &omask);
194 } while (rv == EAGAIN);
195 pthread_sigmask(SIG_SETMASK, &omask, NULL);
196
197 *resp = rw.rw_data;
198 return rv;
199 }
200
201 static int
202 handshake_req(struct spclient *spc, uint32_t *auth, int cancel)
203 {
204 struct handshake_fork rf;
205 struct rsp_hdr rhdr;
206 struct respwait rw;
207 sigset_t omask;
208 int rv;
209
210 /* performs server handshake */
211 rhdr.rsp_len = sizeof(rhdr) + (auth ? sizeof(rf) : 0);
212 rhdr.rsp_class = RUMPSP_REQ;
213 rhdr.rsp_type = RUMPSP_HANDSHAKE;
214 if (auth)
215 rhdr.rsp_handshake = HANDSHAKE_FORK;
216 else
217 rhdr.rsp_handshake = HANDSHAKE_GUEST;
218
219 pthread_sigmask(SIG_SETMASK, &fullset, &omask);
220 putwait(spc, &rw, &rhdr);
221 rv = dosend(spc, &rhdr, sizeof(rhdr));
222 if (auth) {
223 memcpy(rf.rf_auth, auth, AUTHLEN*sizeof(*auth));
224 rf.rf_cancel = cancel;
225 rv = dosend(spc, &rf, sizeof(rf));
226 }
227 if (rv != 0 || cancel) {
228 unputwait(spc, &rw);
229 pthread_sigmask(SIG_SETMASK, &omask, NULL);
230 return rv;
231 }
232
233 rv = waitresp(spc, &rw, &omask);
234 pthread_sigmask(SIG_SETMASK, &omask, NULL);
235 if (rv)
236 return rv;
237
238 rv = *(int *)rw.rw_data;
239 free(rw.rw_data);
240
241 return rv;
242 }
243
244 static int
245 prefork_req(struct spclient *spc, void **resp)
246 {
247 struct rsp_hdr rhdr;
248 struct respwait rw;
249 sigset_t omask;
250 int rv;
251
252 rhdr.rsp_len = sizeof(rhdr);
253 rhdr.rsp_class = RUMPSP_REQ;
254 rhdr.rsp_type = RUMPSP_PREFORK;
255 rhdr.rsp_error = 0;
256
257 pthread_sigmask(SIG_SETMASK, &fullset, &omask);
258 putwait(spc, &rw, &rhdr);
259 rv = dosend(spc, &rhdr, sizeof(rhdr));
260 if (rv != 0) {
261 unputwait(spc, &rw);
262 pthread_sigmask(SIG_SETMASK, &omask, NULL);
263 return rv;
264 }
265
266 rv = waitresp(spc, &rw, &omask);
267 pthread_sigmask(SIG_SETMASK, &omask, NULL);
268 *resp = rw.rw_data;
269 return rv;
270 }
271
272 static int
273 send_copyin_resp(struct spclient *spc, uint64_t reqno, void *data, size_t dlen,
274 int wantstr)
275 {
276 struct rsp_hdr rhdr;
277 int rv;
278
279 if (wantstr)
280 dlen = MIN(dlen, strlen(data)+1);
281
282 rhdr.rsp_len = sizeof(rhdr) + dlen;
283 rhdr.rsp_reqno = reqno;
284 rhdr.rsp_class = RUMPSP_RESP;
285 rhdr.rsp_type = RUMPSP_COPYIN;
286 rhdr.rsp_sysnum = 0;
287
288 sendlock(spc);
289 rv = dosend(spc, &rhdr, sizeof(rhdr));
290 rv = dosend(spc, data, dlen);
291 sendunlock(spc);
292
293 return rv;
294 }
295
296 static int
297 send_anonmmap_resp(struct spclient *spc, uint64_t reqno, void *addr)
298 {
299 struct rsp_hdr rhdr;
300 int rv;
301
302 rhdr.rsp_len = sizeof(rhdr) + sizeof(addr);
303 rhdr.rsp_reqno = reqno;
304 rhdr.rsp_class = RUMPSP_RESP;
305 rhdr.rsp_type = RUMPSP_ANONMMAP;
306 rhdr.rsp_sysnum = 0;
307
308 sendlock(spc);
309 rv = dosend(spc, &rhdr, sizeof(rhdr));
310 rv = dosend(spc, &addr, sizeof(addr));
311 sendunlock(spc);
312
313 return rv;
314 }
315
316 int
317 rumpclient_syscall(int sysnum, const void *data, size_t dlen,
318 register_t *retval)
319 {
320 struct rsp_sysresp *resp;
321 void *rdata;
322 int rv;
323
324 DPRINTF(("rumpsp syscall_req: syscall %d with %p/%zu\n",
325 sysnum, data, dlen));
326
327 rv = syscall_req(&clispc, sysnum, data, dlen, &rdata);
328 if (rv)
329 return rv;
330
331 resp = rdata;
332 DPRINTF(("rumpsp syscall_resp: syscall %d error %d, rv: %d/%d\n",
333 sysnum, rv, resp->rsys_retval[0], resp->rsys_retval[1]));
334
335 memcpy(retval, &resp->rsys_retval, sizeof(resp->rsys_retval));
336 rv = resp->rsys_error;
337 free(rdata);
338
339 return rv;
340 }
341
342 static void
343 handlereq(struct spclient *spc)
344 {
345 struct rsp_copydata *copydata;
346 struct rsp_hdr *rhdr = &spc->spc_hdr;
347 void *mapaddr;
348 size_t maplen;
349 int reqtype = spc->spc_hdr.rsp_type;
350
351 switch (reqtype) {
352 case RUMPSP_COPYIN:
353 case RUMPSP_COPYINSTR:
354 /*LINTED*/
355 copydata = (struct rsp_copydata *)spc->spc_buf;
356 DPRINTF(("rump_sp handlereq: copyin request: %p/%zu\n",
357 copydata->rcp_addr, copydata->rcp_len));
358 send_copyin_resp(spc, spc->spc_hdr.rsp_reqno,
359 copydata->rcp_addr, copydata->rcp_len,
360 reqtype == RUMPSP_COPYINSTR);
361 break;
362 case RUMPSP_COPYOUT:
363 case RUMPSP_COPYOUTSTR:
364 /*LINTED*/
365 copydata = (struct rsp_copydata *)spc->spc_buf;
366 DPRINTF(("rump_sp handlereq: copyout request: %p/%zu\n",
367 copydata->rcp_addr, copydata->rcp_len));
368 /*LINTED*/
369 memcpy(copydata->rcp_addr, copydata->rcp_data,
370 copydata->rcp_len);
371 break;
372 case RUMPSP_ANONMMAP:
373 /*LINTED*/
374 maplen = *(size_t *)spc->spc_buf;
375 mapaddr = mmap(NULL, maplen, PROT_READ|PROT_WRITE,
376 MAP_ANON, -1, 0);
377 if (mapaddr == MAP_FAILED)
378 mapaddr = NULL;
379 DPRINTF(("rump_sp handlereq: anonmmap: %p\n", mapaddr));
380 send_anonmmap_resp(spc, spc->spc_hdr.rsp_reqno, mapaddr);
381 break;
382 case RUMPSP_RAISE:
383 DPRINTF(("rump_sp handlereq: raise sig %d\n", rhdr->rsp_signo));
384 raise(rhdr->rsp_signo);
385 /*
386 * We most likely have signals blocked, but the signal
387 * will be handled soon enough when we return.
388 */
389 break;
390 default:
391 printf("PANIC: INVALID TYPE %d\n", reqtype);
392 abort();
393 break;
394 }
395
396 spcfreebuf(spc);
397 }
398
399 static unsigned ptab_idx;
400 static struct sockaddr *serv_sa;
401
402 static int
403 doconnect(void)
404 {
405 struct kevent kev[NSIG+1];
406 char banner[MAXBANNER];
407 int s, error, flags, i;
408 ssize_t n;
409
410 s = host_socket(parsetab[ptab_idx].domain, SOCK_STREAM, 0);
411 if (s == -1)
412 return -1;
413
414 if (host_connect(s, serv_sa, (socklen_t)serv_sa->sa_len) == -1) {
415 error = errno;
416 fprintf(stderr, "rump_sp: client connect failed\n");
417 errno = error;
418 return -1;
419 }
420
421 if ((error = parsetab[ptab_idx].connhook(s)) != 0) {
422 error = errno;
423 fprintf(stderr, "rump_sp: connect hook failed\n");
424 errno = error;
425 return -1;
426 }
427
428 if ((n = host_read(s, banner, sizeof(banner)-1)) < 0) {
429 error = errno;
430 fprintf(stderr, "rump_sp: failed to read banner\n");
431 errno = error;
432 return -1;
433 }
434
435 if (banner[n-1] != '\n') {
436 fprintf(stderr, "rump_sp: invalid banner\n");
437 errno = EINVAL;
438 return -1;
439 }
440 banner[n] = '\0';
441
442 flags = host_fcntl(s, F_GETFL, 0);
443 if (host_fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) {
444 fprintf(stderr, "rump_sp: cannot set socket fd to nonblock\n");
445 errno = EINVAL;
446 return -1;
447 }
448
449 /* parse the banner some day */
450
451 /* setup kqueue, we want all signals and the fd */
452 if ((kq = kqueue()) == -1) {
453 error = errno;
454 fprintf(stderr, "rump_sp: cannot setup kqueue");
455 errno = error;
456 return -1;
457 }
458
459 for (i = 0; i < NSIG; i++) {
460 EV_SET(&kev[i], i+1, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0);
461 }
462 EV_SET(&kev[NSIG], s, EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0);
463 if (kevent(kq, kev, NSIG+1, NULL, 0, NULL) == -1) {
464 error = errno;
465 fprintf(stderr, "rump_sp: kevent() failed");
466 errno = error;
467 return -1;
468 }
469
470 clispc.spc_fd = s;
471 TAILQ_INIT(&clispc.spc_respwait);
472 pthread_mutex_init(&clispc.spc_mtx, NULL);
473 pthread_cond_init(&clispc.spc_cv, NULL);
474
475 return 0;
476 }
477
478 void *(*rumpclient_dlsym)(void *, const char *);
479
480 int
481 rumpclient_init()
482 {
483 char *p;
484 int error;
485
486 /* dlsym overrided by rumphijack? */
487 if (!rumpclient_dlsym)
488 rumpclient_dlsym = dlsym;
489
490 /*
491 * sag mir, wo die symbol sind. zogen fort, der krieg beginnt.
492 * wann wird man je verstehen? wann wird man je verstehen?
493 */
494 #define FINDSYM2(_name_,_syscall_) \
495 if ((host_##_name_ = rumpclient_dlsym(RTLD_NEXT, \
496 #_syscall_)) == NULL) \
497 /* host_##_name_ = _syscall_ */;
498 #define FINDSYM(_name_) FINDSYM2(_name_,_name_)
499 FINDSYM2(socket,__socket30);
500 FINDSYM(close);
501 FINDSYM(connect);
502 FINDSYM(fcntl);
503 FINDSYM(poll);
504 FINDSYM(pollts);
505 FINDSYM(read);
506 FINDSYM(sendto);
507 FINDSYM(setsockopt);
508 #undef FINDSYM
509 #undef FINDSY2
510
511 if ((p = getenv("RUMP_SERVER")) == NULL) {
512 errno = ENOENT;
513 return -1;
514 }
515
516 if ((error = parseurl(p, &serv_sa, &ptab_idx, 0)) != 0) {
517 errno = error;
518 return -1;
519 }
520
521 if (doconnect() == -1)
522 return -1;
523
524 error = handshake_req(&clispc, NULL, 0);
525 if (error) {
526 pthread_mutex_destroy(&clispc.spc_mtx);
527 pthread_cond_destroy(&clispc.spc_cv);
528 host_close(clispc.spc_fd);
529 errno = error;
530 return -1;
531 }
532
533 sigfillset(&fullset);
534 return 0;
535 }
536
537 struct rumpclient_fork {
538 uint32_t fork_auth[AUTHLEN];
539 };
540
541 struct rumpclient_fork *
542 rumpclient_prefork(void)
543 {
544 struct rumpclient_fork *rpf;
545 void *resp;
546 int rv;
547
548 rpf = malloc(sizeof(*rpf));
549 if (rpf == NULL)
550 return NULL;
551
552 if ((rv = prefork_req(&clispc, &resp)) != 0) {
553 free(rpf);
554 errno = rv;
555 return NULL;
556 }
557
558 memcpy(rpf->fork_auth, resp, sizeof(rpf->fork_auth));
559 free(resp);
560
561 return rpf;
562 }
563
564 int
565 rumpclient_fork_init(struct rumpclient_fork *rpf)
566 {
567 int error;
568
569 host_close(clispc.spc_fd);
570 host_close(kq);
571 kq = -1;
572 memset(&clispc, 0, sizeof(clispc));
573 clispc.spc_fd = -1;
574
575 if (doconnect() == -1)
576 return -1;
577
578 error = handshake_req(&clispc, rpf->fork_auth, 0);
579 if (error) {
580 pthread_mutex_destroy(&clispc.spc_mtx);
581 pthread_cond_destroy(&clispc.spc_cv);
582 errno = error;
583 return -1;
584 }
585
586 return 0;
587 }
588