hijack.c revision 1.7 1 1.7 pooka /* $NetBSD: hijack.c,v 1.7 2011/01/09 19:56:33 pooka Exp $ */
2 1.1 pooka
3 1.1 pooka /*-
4 1.1 pooka * Copyright (c) 2011 Antti Kantee. All Rights Reserved.
5 1.1 pooka *
6 1.1 pooka * Redistribution and use in source and binary forms, with or without
7 1.1 pooka * modification, are permitted provided that the following conditions
8 1.1 pooka * are met:
9 1.1 pooka * 1. Redistributions of source code must retain the above copyright
10 1.1 pooka * notice, this list of conditions and the following disclaimer.
11 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright
12 1.1 pooka * notice, this list of conditions and the following disclaimer in the
13 1.1 pooka * documentation and/or other materials provided with the distribution.
14 1.1 pooka *
15 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 1.1 pooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 1.1 pooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 1.1 pooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 1.1 pooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 1.1 pooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 1.1 pooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 1.1 pooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 1.1 pooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 1.1 pooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 1.1 pooka * SUCH DAMAGE.
26 1.1 pooka */
27 1.1 pooka
28 1.1 pooka #include <sys/cdefs.h>
29 1.7 pooka __RCSID("$NetBSD: hijack.c,v 1.7 2011/01/09 19:56:33 pooka Exp $");
30 1.1 pooka
31 1.1 pooka #include <sys/param.h>
32 1.1 pooka #include <sys/types.h>
33 1.1 pooka #include <sys/ioctl.h>
34 1.1 pooka #include <sys/socket.h>
35 1.1 pooka #include <sys/poll.h>
36 1.1 pooka
37 1.1 pooka #include <rump/rump.h>
38 1.1 pooka #include <rump/rumpclient.h>
39 1.1 pooka #include <rump/rump_syscalls.h>
40 1.1 pooka
41 1.1 pooka #include <assert.h>
42 1.1 pooka #include <dlfcn.h>
43 1.1 pooka #include <err.h>
44 1.1 pooka #include <errno.h>
45 1.1 pooka #include <fcntl.h>
46 1.1 pooka #include <poll.h>
47 1.1 pooka #include <pthread.h>
48 1.3 pooka #include <signal.h>
49 1.1 pooka #include <stdarg.h>
50 1.1 pooka #include <stdio.h>
51 1.1 pooka #include <stdlib.h>
52 1.3 pooka #include <time.h>
53 1.1 pooka #include <unistd.h>
54 1.1 pooka
55 1.1 pooka enum { RUMPCALL_SOCKET, RUMPCALL_ACCEPT, RUMPCALL_BIND, RUMPCALL_CONNECT,
56 1.1 pooka RUMPCALL_GETPEERNAME, RUMPCALL_GETSOCKNAME, RUMPCALL_LISTEN,
57 1.1 pooka RUMPCALL_RECVFROM, RUMPCALL_RECVMSG,
58 1.1 pooka RUMPCALL_SENDTO, RUMPCALL_SENDMSG,
59 1.1 pooka RUMPCALL_GETSOCKOPT, RUMPCALL_SETSOCKOPT,
60 1.1 pooka RUMPCALL_SHUTDOWN,
61 1.1 pooka RUMPCALL_READ, RUMPCALL_READV,
62 1.1 pooka RUMPCALL_WRITE, RUMPCALL_WRITEV,
63 1.1 pooka RUMPCALL_IOCTL, RUMPCALL_FCNTL,
64 1.1 pooka RUMPCALL_CLOSE,
65 1.4 pooka RUMPCALL_POLLTS,
66 1.1 pooka RUMPCALL__NUM
67 1.1 pooka };
68 1.1 pooka
69 1.1 pooka const char *sysnames[] = {
70 1.1 pooka "__socket30",
71 1.1 pooka "accept",
72 1.1 pooka "bind",
73 1.1 pooka "connect",
74 1.1 pooka "getpeername",
75 1.1 pooka "getsockname",
76 1.1 pooka "listen",
77 1.1 pooka "recvfrom",
78 1.1 pooka "recvmsg",
79 1.1 pooka "sendto",
80 1.1 pooka "sendmsg",
81 1.1 pooka "getsockopt",
82 1.1 pooka "setsockopt",
83 1.1 pooka "shutdown",
84 1.1 pooka "read",
85 1.1 pooka "readv",
86 1.1 pooka "write",
87 1.1 pooka "writev",
88 1.1 pooka "ioctl",
89 1.1 pooka "fcntl",
90 1.1 pooka "close",
91 1.1 pooka "__pollts50",
92 1.1 pooka };
93 1.1 pooka
94 1.7 pooka static int (*host_socket)(int, int, int);
95 1.7 pooka static int (*host_connect)(int, const struct sockaddr *, socklen_t);
96 1.7 pooka static int (*host_bind)(int, const struct sockaddr *, socklen_t);
97 1.7 pooka static int (*host_listen)(int, int);
98 1.7 pooka static int (*host_accept)(int, struct sockaddr *, socklen_t *);
99 1.7 pooka static int (*host_getpeername)(int, struct sockaddr *, socklen_t *);
100 1.7 pooka static int (*host_getsockname)(int, struct sockaddr *, socklen_t *);
101 1.7 pooka static int (*host_setsockopt)(int, int, int, const void *, socklen_t);
102 1.7 pooka
103 1.1 pooka static ssize_t (*host_read)(int, void *, size_t);
104 1.1 pooka static ssize_t (*host_readv)(int, const struct iovec *, int);
105 1.1 pooka static ssize_t (*host_write)(int, const void *, size_t);
106 1.1 pooka static ssize_t (*host_writev)(int, const struct iovec *, int);
107 1.1 pooka static int (*host_ioctl)(int, unsigned long, ...);
108 1.1 pooka static int (*host_fcntl)(int, int, ...);
109 1.1 pooka static int (*host_close)(int);
110 1.3 pooka static int (*host_pollts)(struct pollfd *, nfds_t,
111 1.3 pooka const struct timespec *, const sigset_t *);
112 1.2 pooka static pid_t (*host_fork)(void);
113 1.2 pooka static int (*host_dup2)(int, int);
114 1.1 pooka
115 1.1 pooka static void *rumpcalls[RUMPCALL__NUM];
116 1.1 pooka
117 1.1 pooka /*
118 1.1 pooka * This is called from librumpclient in case of LD_PRELOAD.
119 1.1 pooka * It ensures correct RTLD_NEXT.
120 1.1 pooka */
121 1.1 pooka static void *
122 1.1 pooka hijackdlsym(void *handle, const char *symbol)
123 1.1 pooka {
124 1.1 pooka
125 1.1 pooka return dlsym(handle, symbol);
126 1.1 pooka }
127 1.1 pooka
128 1.7 pooka /* low calorie sockets? */
129 1.7 pooka static bool hostlocalsockets = false;
130 1.7 pooka
131 1.1 pooka static void __attribute__((constructor))
132 1.1 pooka rcinit(void)
133 1.1 pooka {
134 1.1 pooka int (*rumpcinit)(void);
135 1.1 pooka void **rumpcdlsym;
136 1.1 pooka void *hand;
137 1.1 pooka int i;
138 1.1 pooka
139 1.1 pooka hand = dlopen("librumpclient.so", RTLD_LAZY|RTLD_GLOBAL);
140 1.1 pooka if (!hand)
141 1.1 pooka err(1, "cannot open librumpclient.so");
142 1.1 pooka rumpcinit = dlsym(hand, "rumpclient_init");
143 1.1 pooka _DIAGASSERT(rumpcinit);
144 1.1 pooka
145 1.1 pooka rumpcdlsym = dlsym(hand, "rumpclient_dlsym");
146 1.1 pooka *rumpcdlsym = hijackdlsym;
147 1.1 pooka
148 1.7 pooka host_socket = dlsym(RTLD_NEXT, "__socket30");
149 1.7 pooka host_listen = dlsym(RTLD_NEXT, "listen");
150 1.7 pooka host_connect = dlsym(RTLD_NEXT, "connect");
151 1.7 pooka host_bind = dlsym(RTLD_NEXT, "bind");
152 1.7 pooka host_accept = dlsym(RTLD_NEXT, "accept");
153 1.7 pooka host_getpeername = dlsym(RTLD_NEXT, "getpeername");
154 1.7 pooka host_getsockname = dlsym(RTLD_NEXT, "getsockname");
155 1.7 pooka host_setsockopt = dlsym(RTLD_NEXT, "setsockopt");
156 1.7 pooka
157 1.1 pooka host_read = dlsym(RTLD_NEXT, "read");
158 1.1 pooka host_readv = dlsym(RTLD_NEXT, "readv");
159 1.1 pooka host_write = dlsym(RTLD_NEXT, "write");
160 1.1 pooka host_writev = dlsym(RTLD_NEXT, "writev");
161 1.1 pooka host_ioctl = dlsym(RTLD_NEXT, "ioctl");
162 1.1 pooka host_fcntl = dlsym(RTLD_NEXT, "fcntl");
163 1.1 pooka host_close = dlsym(RTLD_NEXT, "close");
164 1.3 pooka host_pollts = dlsym(RTLD_NEXT, "pollts");
165 1.2 pooka host_fork = dlsym(RTLD_NEXT, "fork");
166 1.2 pooka host_dup2 = dlsym(RTLD_NEXT, "dup2");
167 1.1 pooka
168 1.1 pooka for (i = 0; i < RUMPCALL__NUM; i++) {
169 1.1 pooka char sysname[128];
170 1.1 pooka
171 1.1 pooka snprintf(sysname, sizeof(sysname), "rump_sys_%s", sysnames[i]);
172 1.1 pooka rumpcalls[i] = dlsym(hand, sysname);
173 1.1 pooka if (!rumpcalls[i]) {
174 1.3 pooka fprintf(stderr, "cannot find symbol: %s\n", sysname);
175 1.1 pooka exit(1);
176 1.1 pooka }
177 1.1 pooka }
178 1.1 pooka
179 1.1 pooka if (rumpcinit() == -1)
180 1.1 pooka err(1, "rumpclient init");
181 1.1 pooka }
182 1.1 pooka
183 1.5 pooka static unsigned dup2mask;
184 1.5 pooka #define ISDUP2D(fd) (((fd+1) & dup2mask) == ((fd)+1))
185 1.5 pooka
186 1.1 pooka //#define DEBUGJACK
187 1.1 pooka #ifdef DEBUGJACK
188 1.5 pooka #define DPRINTF(x) mydprintf x
189 1.5 pooka static void
190 1.5 pooka mydprintf(const char *fmt, ...)
191 1.5 pooka {
192 1.5 pooka va_list ap;
193 1.5 pooka
194 1.5 pooka if (ISDUP2D(STDERR_FILENO))
195 1.5 pooka return;
196 1.5 pooka
197 1.5 pooka va_start(ap, fmt);
198 1.5 pooka vfprintf(stderr, fmt, ap);
199 1.5 pooka va_end(ap);
200 1.5 pooka }
201 1.5 pooka
202 1.1 pooka #else
203 1.1 pooka #define DPRINTF(x)
204 1.1 pooka #endif
205 1.1 pooka
206 1.2 pooka /* XXX: need runtime selection. low for now due to FD_SETSIZE */
207 1.2 pooka #define HIJACK_FDOFF 128
208 1.2 pooka #define HIJACK_SELECT 128 /* XXX */
209 1.2 pooka #define HIJACK_ASSERT 128 /* XXX */
210 1.2 pooka static int
211 1.2 pooka fd_rump2host(int fd)
212 1.2 pooka {
213 1.2 pooka
214 1.2 pooka if (fd == -1)
215 1.2 pooka return fd;
216 1.2 pooka
217 1.2 pooka if (!ISDUP2D(fd))
218 1.2 pooka fd += HIJACK_FDOFF;
219 1.2 pooka
220 1.2 pooka return fd;
221 1.2 pooka }
222 1.2 pooka
223 1.2 pooka static int
224 1.2 pooka fd_host2rump(int fd)
225 1.2 pooka {
226 1.2 pooka
227 1.2 pooka if (!ISDUP2D(fd))
228 1.2 pooka fd -= HIJACK_FDOFF;
229 1.2 pooka return fd;
230 1.2 pooka }
231 1.2 pooka
232 1.2 pooka static bool
233 1.2 pooka fd_isrump(int fd)
234 1.2 pooka {
235 1.2 pooka
236 1.2 pooka return ISDUP2D(fd) || fd >= HIJACK_FDOFF;
237 1.2 pooka }
238 1.2 pooka
239 1.2 pooka #define assertfd(_fd_) assert(ISDUP2D(_fd_) || (_fd_) >= HIJACK_ASSERT)
240 1.2 pooka #undef HIJACK_FDOFF
241 1.2 pooka
242 1.1 pooka /*
243 1.1 pooka * Following wrappers always call the rump kernel.
244 1.1 pooka */
245 1.1 pooka
246 1.1 pooka int __socket30(int, int, int);
247 1.1 pooka int
248 1.1 pooka __socket30(int domain, int type, int protocol)
249 1.1 pooka {
250 1.1 pooka int (*rc_socket)(int, int, int);
251 1.1 pooka int fd;
252 1.7 pooka bool dohost;
253 1.7 pooka
254 1.7 pooka dohost = hostlocalsockets && (domain == AF_LOCAL);
255 1.1 pooka
256 1.7 pooka if (dohost)
257 1.7 pooka rc_socket = host_socket;
258 1.7 pooka else
259 1.7 pooka rc_socket = rumpcalls[RUMPCALL_SOCKET];
260 1.1 pooka fd = rc_socket(domain, type, protocol);
261 1.2 pooka
262 1.7 pooka if (!dohost)
263 1.7 pooka fd = fd_rump2host(fd);
264 1.7 pooka DPRINTF(("socket <- %d\n", fd));
265 1.2 pooka
266 1.7 pooka return fd;
267 1.1 pooka }
268 1.1 pooka
269 1.1 pooka int
270 1.1 pooka accept(int s, struct sockaddr *addr, socklen_t *addrlen)
271 1.1 pooka {
272 1.1 pooka int (*rc_accept)(int, struct sockaddr *, socklen_t *);
273 1.1 pooka int fd;
274 1.7 pooka bool isrump;
275 1.7 pooka
276 1.7 pooka isrump = fd_isrump(s);
277 1.1 pooka
278 1.2 pooka DPRINTF(("accept -> %d", s));
279 1.7 pooka if (isrump) {
280 1.7 pooka rc_accept = rumpcalls[RUMPCALL_ACCEPT];
281 1.7 pooka s = fd_host2rump(s);
282 1.7 pooka } else {
283 1.7 pooka rc_accept = host_accept;
284 1.7 pooka }
285 1.7 pooka fd = rc_accept(s, addr, addrlen);
286 1.7 pooka if (fd != -1 && isrump)
287 1.7 pooka fd = fd_rump2host(fd);
288 1.7 pooka
289 1.7 pooka DPRINTF((" <- %d\n", fd));
290 1.2 pooka
291 1.7 pooka return fd;
292 1.1 pooka }
293 1.1 pooka
294 1.1 pooka int
295 1.1 pooka bind(int s, const struct sockaddr *name, socklen_t namelen)
296 1.1 pooka {
297 1.1 pooka int (*rc_bind)(int, const struct sockaddr *, socklen_t);
298 1.1 pooka
299 1.2 pooka DPRINTF(("bind -> %d\n", s));
300 1.7 pooka if (fd_isrump(s)) {
301 1.7 pooka rc_bind = rumpcalls[RUMPCALL_BIND];
302 1.7 pooka s = fd_host2rump(s);
303 1.7 pooka } else {
304 1.7 pooka rc_bind = host_bind;
305 1.7 pooka }
306 1.7 pooka return rc_bind(s, name, namelen);
307 1.1 pooka }
308 1.1 pooka
309 1.1 pooka int
310 1.1 pooka connect(int s, const struct sockaddr *name, socklen_t namelen)
311 1.1 pooka {
312 1.1 pooka int (*rc_connect)(int, const struct sockaddr *, socklen_t);
313 1.1 pooka
314 1.2 pooka DPRINTF(("connect -> %d\n", s));
315 1.7 pooka if (fd_isrump(s)) {
316 1.7 pooka rc_connect = rumpcalls[RUMPCALL_CONNECT];
317 1.7 pooka s = fd_host2rump(s);
318 1.7 pooka } else {
319 1.7 pooka rc_connect = host_connect;
320 1.7 pooka }
321 1.2 pooka
322 1.7 pooka return rc_connect(s, name, namelen);
323 1.1 pooka }
324 1.1 pooka
325 1.1 pooka int
326 1.1 pooka getpeername(int s, struct sockaddr *name, socklen_t *namelen)
327 1.1 pooka {
328 1.1 pooka int (*rc_getpeername)(int, struct sockaddr *, socklen_t *);
329 1.1 pooka
330 1.2 pooka DPRINTF(("getpeername -> %d\n", s));
331 1.7 pooka if (fd_isrump(s)) {
332 1.7 pooka rc_getpeername = rumpcalls[RUMPCALL_GETPEERNAME];
333 1.7 pooka s = fd_host2rump(s);
334 1.7 pooka } else {
335 1.7 pooka rc_getpeername = host_getpeername;
336 1.7 pooka }
337 1.7 pooka return rc_getpeername(s, name, namelen);
338 1.1 pooka }
339 1.1 pooka
340 1.1 pooka int
341 1.1 pooka getsockname(int s, struct sockaddr *name, socklen_t *namelen)
342 1.1 pooka {
343 1.1 pooka int (*rc_getsockname)(int, struct sockaddr *, socklen_t *);
344 1.1 pooka
345 1.2 pooka DPRINTF(("getsockname -> %d\n", s));
346 1.7 pooka if (fd_isrump(s)) {
347 1.7 pooka rc_getsockname = rumpcalls[RUMPCALL_GETSOCKNAME];
348 1.7 pooka s = fd_host2rump(s);
349 1.7 pooka } else {
350 1.7 pooka rc_getsockname = host_getsockname;
351 1.7 pooka }
352 1.7 pooka return rc_getsockname(s, name, namelen);
353 1.1 pooka }
354 1.1 pooka
355 1.1 pooka int
356 1.1 pooka listen(int s, int backlog)
357 1.1 pooka {
358 1.1 pooka int (*rc_listen)(int, int);
359 1.1 pooka
360 1.2 pooka DPRINTF(("listen -> %d\n", s));
361 1.7 pooka if (fd_isrump(s)) {
362 1.7 pooka rc_listen = rumpcalls[RUMPCALL_LISTEN];
363 1.7 pooka s = fd_host2rump(s);
364 1.7 pooka } else {
365 1.7 pooka rc_listen = host_listen;
366 1.7 pooka }
367 1.7 pooka return rc_listen(s, backlog);
368 1.1 pooka }
369 1.1 pooka
370 1.1 pooka ssize_t
371 1.1 pooka recv(int s, void *buf, size_t len, int flags)
372 1.1 pooka {
373 1.1 pooka
374 1.1 pooka return recvfrom(s, buf, len, flags, NULL, NULL);
375 1.1 pooka }
376 1.1 pooka
377 1.1 pooka ssize_t
378 1.1 pooka recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from,
379 1.1 pooka socklen_t *fromlen)
380 1.1 pooka {
381 1.1 pooka int (*rc_recvfrom)(int, void *, size_t, int,
382 1.1 pooka struct sockaddr *, socklen_t *);
383 1.1 pooka
384 1.1 pooka DPRINTF(("recvfrom\n"));
385 1.1 pooka assertfd(s);
386 1.1 pooka rc_recvfrom = rumpcalls[RUMPCALL_RECVFROM];
387 1.2 pooka return rc_recvfrom(fd_host2rump(s), buf, len, flags, from, fromlen);
388 1.1 pooka }
389 1.1 pooka
390 1.1 pooka ssize_t
391 1.1 pooka recvmsg(int s, struct msghdr *msg, int flags)
392 1.1 pooka {
393 1.1 pooka int (*rc_recvmsg)(int, struct msghdr *, int);
394 1.1 pooka
395 1.1 pooka DPRINTF(("recvmsg\n"));
396 1.1 pooka assertfd(s);
397 1.1 pooka rc_recvmsg = rumpcalls[RUMPCALL_RECVMSG];
398 1.2 pooka return rc_recvmsg(fd_host2rump(s), msg, flags);
399 1.1 pooka }
400 1.1 pooka
401 1.1 pooka ssize_t
402 1.1 pooka send(int s, const void *buf, size_t len, int flags)
403 1.1 pooka {
404 1.1 pooka
405 1.1 pooka return sendto(s, buf, len, flags, NULL, 0);
406 1.1 pooka }
407 1.1 pooka
408 1.1 pooka ssize_t
409 1.1 pooka sendto(int s, const void *buf, size_t len, int flags,
410 1.1 pooka const struct sockaddr *to, socklen_t tolen)
411 1.1 pooka {
412 1.1 pooka int (*rc_sendto)(int, const void *, size_t, int,
413 1.1 pooka const struct sockaddr *, socklen_t);
414 1.1 pooka
415 1.1 pooka if (s == -1)
416 1.1 pooka return len;
417 1.1 pooka
418 1.1 pooka DPRINTF(("sendto\n"));
419 1.1 pooka assertfd(s);
420 1.1 pooka rc_sendto = rumpcalls[RUMPCALL_SENDTO];
421 1.2 pooka return rc_sendto(fd_host2rump(s), buf, len, flags, to, tolen);
422 1.1 pooka }
423 1.1 pooka
424 1.1 pooka ssize_t
425 1.1 pooka sendmsg(int s, const struct msghdr *msg, int flags)
426 1.1 pooka {
427 1.1 pooka int (*rc_sendmsg)(int, const struct msghdr *, int);
428 1.1 pooka
429 1.1 pooka DPRINTF(("sendmsg\n"));
430 1.1 pooka assertfd(s);
431 1.1 pooka rc_sendmsg = rumpcalls[RUMPCALL_SENDTO];
432 1.2 pooka return rc_sendmsg(fd_host2rump(s), msg, flags);
433 1.1 pooka }
434 1.1 pooka
435 1.1 pooka int
436 1.1 pooka getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
437 1.1 pooka {
438 1.1 pooka int (*rc_getsockopt)(int, int, int, void *, socklen_t *);
439 1.1 pooka
440 1.7 pooka DPRINTF(("getsockopt -> %d\n", s));
441 1.1 pooka assertfd(s);
442 1.1 pooka rc_getsockopt = rumpcalls[RUMPCALL_GETSOCKOPT];
443 1.2 pooka return rc_getsockopt(fd_host2rump(s), level, optname, optval, optlen);
444 1.1 pooka }
445 1.1 pooka
446 1.1 pooka int
447 1.1 pooka setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
448 1.1 pooka {
449 1.1 pooka int (*rc_setsockopt)(int, int, int, const void *, socklen_t);
450 1.1 pooka
451 1.7 pooka DPRINTF(("setsockopt -> %d\n", s));
452 1.7 pooka if (fd_isrump(s)) {
453 1.7 pooka rc_setsockopt = rumpcalls[RUMPCALL_SETSOCKOPT];
454 1.7 pooka s = fd_host2rump(s);
455 1.7 pooka } else {
456 1.7 pooka rc_setsockopt = host_setsockopt;
457 1.7 pooka }
458 1.7 pooka return rc_setsockopt(s, level, optname, optval, optlen);
459 1.1 pooka }
460 1.1 pooka
461 1.1 pooka int
462 1.1 pooka shutdown(int s, int how)
463 1.1 pooka {
464 1.1 pooka int (*rc_shutdown)(int, int);
465 1.1 pooka
466 1.7 pooka DPRINTF(("shutdown -> %d\n", s));
467 1.1 pooka assertfd(s);
468 1.1 pooka rc_shutdown = rumpcalls[RUMPCALL_SHUTDOWN];
469 1.2 pooka return rc_shutdown(fd_host2rump(s), how);
470 1.2 pooka }
471 1.2 pooka
472 1.2 pooka /*
473 1.2 pooka * dup2 is special. we allow dup2 of a rump kernel fd to 0-2 since
474 1.2 pooka * many programs do that. dup2 of a rump kernel fd to another value
475 1.2 pooka * not >= fdoff is an error.
476 1.2 pooka *
477 1.2 pooka * Note: cannot rump2host newd, because it is often hardcoded.
478 1.2 pooka *
479 1.2 pooka * XXX: should disable debug prints after stdout/stderr are dup2'd
480 1.2 pooka */
481 1.2 pooka int
482 1.2 pooka dup2(int oldd, int newd)
483 1.2 pooka {
484 1.2 pooka int rv;
485 1.2 pooka
486 1.2 pooka DPRINTF(("dup2 -> %d (o) -> %d (n)\n", oldd, newd));
487 1.2 pooka
488 1.2 pooka if (fd_isrump(oldd)) {
489 1.2 pooka if (!(newd >= 0 && newd <= 2))
490 1.2 pooka return EBADF;
491 1.2 pooka oldd = fd_host2rump(oldd);
492 1.2 pooka rv = rump_sys_dup2(oldd, newd);
493 1.2 pooka if (rv != -1)
494 1.2 pooka dup2mask |= newd+1;
495 1.2 pooka return rv;
496 1.2 pooka } else {
497 1.2 pooka return host_dup2(oldd, newd);
498 1.2 pooka }
499 1.2 pooka }
500 1.2 pooka
501 1.2 pooka /*
502 1.2 pooka * We just wrap fork the appropriate rump client calls to preserve
503 1.2 pooka * the file descriptors of the forked parent in the child, but
504 1.2 pooka * prevent double use of connection fd.
505 1.2 pooka */
506 1.2 pooka
507 1.2 pooka pid_t
508 1.2 pooka fork()
509 1.2 pooka {
510 1.2 pooka struct rumpclient_fork *rf;
511 1.2 pooka pid_t rv;
512 1.2 pooka
513 1.2 pooka DPRINTF(("fork\n"));
514 1.2 pooka
515 1.2 pooka if ((rf = rumpclient_prefork()) == NULL)
516 1.2 pooka return -1;
517 1.2 pooka
518 1.2 pooka switch ((rv = host_fork())) {
519 1.2 pooka case -1:
520 1.2 pooka /* XXX: cancel rf */
521 1.2 pooka break;
522 1.2 pooka case 0:
523 1.2 pooka if (rumpclient_fork_init(rf) == -1)
524 1.2 pooka rv = -1;
525 1.2 pooka break;
526 1.2 pooka default:
527 1.2 pooka break;
528 1.2 pooka }
529 1.2 pooka
530 1.2 pooka DPRINTF(("fork returns %d\n", rv));
531 1.2 pooka return rv;
532 1.1 pooka }
533 1.1 pooka
534 1.1 pooka /*
535 1.1 pooka * Hybrids
536 1.1 pooka */
537 1.1 pooka
538 1.1 pooka ssize_t
539 1.1 pooka read(int fd, void *buf, size_t len)
540 1.1 pooka {
541 1.1 pooka int (*op_read)(int, void *, size_t);
542 1.1 pooka ssize_t n;
543 1.1 pooka
544 1.1 pooka DPRINTF(("read %d\n", fd));
545 1.2 pooka if (fd_isrump(fd)) {
546 1.2 pooka fd = fd_host2rump(fd);
547 1.2 pooka op_read = rumpcalls[RUMPCALL_READ];
548 1.2 pooka } else {
549 1.1 pooka op_read = host_read;
550 1.1 pooka }
551 1.1 pooka
552 1.1 pooka n = op_read(fd, buf, len);
553 1.1 pooka return n;
554 1.1 pooka }
555 1.1 pooka
556 1.1 pooka ssize_t
557 1.1 pooka readv(int fd, const struct iovec *iov, int iovcnt)
558 1.1 pooka {
559 1.1 pooka int (*op_readv)(int, const struct iovec *, int);
560 1.1 pooka
561 1.7 pooka DPRINTF(("readv %d\n", fd));
562 1.2 pooka if (fd_isrump(fd)) {
563 1.2 pooka fd = fd_host2rump(fd);
564 1.2 pooka op_readv = rumpcalls[RUMPCALL_READV];
565 1.2 pooka } else {
566 1.1 pooka op_readv = host_readv;
567 1.1 pooka }
568 1.1 pooka
569 1.1 pooka return op_readv(fd, iov, iovcnt);
570 1.1 pooka }
571 1.1 pooka
572 1.1 pooka ssize_t
573 1.1 pooka write(int fd, const void *buf, size_t len)
574 1.1 pooka {
575 1.1 pooka int (*op_write)(int, const void *, size_t);
576 1.1 pooka
577 1.2 pooka if (fd_isrump(fd)) {
578 1.2 pooka fd = fd_host2rump(fd);
579 1.2 pooka op_write = rumpcalls[RUMPCALL_WRITE];
580 1.2 pooka } else {
581 1.1 pooka op_write = host_write;
582 1.1 pooka }
583 1.1 pooka
584 1.1 pooka return op_write(fd, buf, len);
585 1.1 pooka }
586 1.1 pooka
587 1.1 pooka ssize_t
588 1.1 pooka writev(int fd, const struct iovec *iov, int iovcnt)
589 1.1 pooka {
590 1.1 pooka int (*op_writev)(int, const struct iovec *, int);
591 1.1 pooka
592 1.7 pooka DPRINTF(("writev %d\n", fd));
593 1.2 pooka if (fd_isrump(fd)) {
594 1.2 pooka fd = fd_host2rump(fd);
595 1.2 pooka op_writev = rumpcalls[RUMPCALL_WRITEV];
596 1.2 pooka } else {
597 1.1 pooka op_writev = host_writev;
598 1.1 pooka }
599 1.1 pooka
600 1.1 pooka return op_writev(fd, iov, iovcnt);
601 1.1 pooka }
602 1.1 pooka
603 1.1 pooka int
604 1.1 pooka ioctl(int fd, unsigned long cmd, ...)
605 1.1 pooka {
606 1.1 pooka int (*op_ioctl)(int, unsigned long cmd, ...);
607 1.1 pooka va_list ap;
608 1.1 pooka int rv;
609 1.1 pooka
610 1.1 pooka DPRINTF(("ioctl\n"));
611 1.2 pooka if (fd_isrump(fd)) {
612 1.2 pooka fd = fd_host2rump(fd);
613 1.2 pooka op_ioctl = rumpcalls[RUMPCALL_IOCTL];
614 1.2 pooka } else {
615 1.1 pooka op_ioctl = host_ioctl;
616 1.1 pooka }
617 1.1 pooka
618 1.1 pooka va_start(ap, cmd);
619 1.1 pooka rv = op_ioctl(fd, cmd, va_arg(ap, void *));
620 1.1 pooka va_end(ap);
621 1.1 pooka return rv;
622 1.1 pooka }
623 1.1 pooka
624 1.1 pooka int
625 1.1 pooka fcntl(int fd, int cmd, ...)
626 1.1 pooka {
627 1.1 pooka int (*op_fcntl)(int, int, ...);
628 1.1 pooka va_list ap;
629 1.1 pooka int rv;
630 1.1 pooka
631 1.1 pooka DPRINTF(("fcntl\n"));
632 1.2 pooka if (fd_isrump(fd)) {
633 1.2 pooka fd = fd_host2rump(fd);
634 1.2 pooka op_fcntl = rumpcalls[RUMPCALL_FCNTL];
635 1.2 pooka } else {
636 1.1 pooka op_fcntl = host_fcntl;
637 1.1 pooka }
638 1.1 pooka
639 1.1 pooka va_start(ap, cmd);
640 1.1 pooka rv = op_fcntl(fd, cmd, va_arg(ap, void *));
641 1.1 pooka va_end(ap);
642 1.1 pooka return rv;
643 1.1 pooka }
644 1.1 pooka
645 1.1 pooka int
646 1.1 pooka close(int fd)
647 1.1 pooka {
648 1.1 pooka int (*op_close)(int);
649 1.1 pooka
650 1.1 pooka DPRINTF(("close %d\n", fd));
651 1.2 pooka if (fd_isrump(fd)) {
652 1.2 pooka fd = fd_host2rump(fd);
653 1.2 pooka op_close = rumpcalls[RUMPCALL_CLOSE];
654 1.2 pooka } else {
655 1.1 pooka op_close = host_close;
656 1.1 pooka }
657 1.1 pooka
658 1.1 pooka return op_close(fd);
659 1.1 pooka }
660 1.1 pooka
661 1.4 pooka int
662 1.4 pooka select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
663 1.4 pooka struct timeval *timeout)
664 1.1 pooka {
665 1.4 pooka struct pollfd *pfds;
666 1.4 pooka struct timespec ts, *tsp = NULL;
667 1.4 pooka nfds_t i, j, realnfds;
668 1.4 pooka int rv, incr;
669 1.4 pooka
670 1.7 pooka DPRINTF(("select\n"));
671 1.7 pooka
672 1.4 pooka /*
673 1.4 pooka * Well, first we must scan the fds to figure out how many
674 1.4 pooka * fds there really are. This is because up to and including
675 1.4 pooka * nb5 poll() silently refuses nfds > process_open_fds.
676 1.4 pooka * Seems to be fixed in current, thank the maker.
677 1.4 pooka * god damn cluster...bomb.
678 1.4 pooka */
679 1.4 pooka
680 1.4 pooka for (i = 0, realnfds = 0; i < nfds; i++) {
681 1.4 pooka if (readfds && FD_ISSET(i, readfds)) {
682 1.4 pooka realnfds++;
683 1.4 pooka continue;
684 1.4 pooka }
685 1.4 pooka if (writefds && FD_ISSET(i, writefds)) {
686 1.4 pooka realnfds++;
687 1.4 pooka continue;
688 1.4 pooka }
689 1.4 pooka if (exceptfds && FD_ISSET(i, exceptfds)) {
690 1.4 pooka realnfds++;
691 1.4 pooka continue;
692 1.1 pooka }
693 1.1 pooka }
694 1.1 pooka
695 1.6 pooka if (realnfds) {
696 1.6 pooka pfds = malloc(sizeof(*pfds) * realnfds);
697 1.6 pooka if (!pfds)
698 1.6 pooka return -1;
699 1.6 pooka } else {
700 1.6 pooka pfds = NULL;
701 1.6 pooka }
702 1.1 pooka
703 1.4 pooka for (i = 0, j = 0; i < nfds; i++) {
704 1.4 pooka incr = 0;
705 1.4 pooka pfds[j].events = pfds[j].revents = 0;
706 1.4 pooka if (readfds && FD_ISSET(i, readfds)) {
707 1.4 pooka pfds[j].fd = i;
708 1.4 pooka pfds[j].events |= POLLIN;
709 1.4 pooka incr=1;
710 1.4 pooka }
711 1.4 pooka if (writefds && FD_ISSET(i, writefds)) {
712 1.4 pooka pfds[j].fd = i;
713 1.4 pooka pfds[j].events |= POLLOUT;
714 1.4 pooka incr=1;
715 1.4 pooka }
716 1.4 pooka if (exceptfds && FD_ISSET(i, exceptfds)) {
717 1.4 pooka pfds[j].fd = i;
718 1.4 pooka pfds[j].events |= POLLHUP|POLLERR;
719 1.4 pooka incr=1;
720 1.1 pooka }
721 1.4 pooka if (incr)
722 1.4 pooka j++;
723 1.1 pooka }
724 1.1 pooka
725 1.4 pooka if (timeout) {
726 1.4 pooka TIMEVAL_TO_TIMESPEC(timeout, &ts);
727 1.4 pooka tsp = &ts;
728 1.4 pooka }
729 1.4 pooka rv = pollts(pfds, realnfds, tsp, NULL);
730 1.4 pooka if (rv <= 0)
731 1.4 pooka goto out;
732 1.4 pooka
733 1.4 pooka /*
734 1.4 pooka * ok, harvest results. first zero out entries (can't use
735 1.4 pooka * FD_ZERO for the obvious select-me-not reason). whee.
736 1.4 pooka */
737 1.4 pooka for (i = 0; i < nfds; i++) {
738 1.4 pooka if (readfds)
739 1.4 pooka FD_CLR(i, readfds);
740 1.4 pooka if (writefds)
741 1.4 pooka FD_CLR(i, writefds);
742 1.4 pooka if (exceptfds)
743 1.4 pooka FD_CLR(i, exceptfds);
744 1.1 pooka }
745 1.1 pooka
746 1.4 pooka /* and then plug in the results */
747 1.4 pooka for (i = 0; i < realnfds; i++) {
748 1.4 pooka if (readfds) {
749 1.4 pooka if (pfds[i].revents & POLLIN) {
750 1.4 pooka FD_SET(pfds[i].fd, readfds);
751 1.4 pooka }
752 1.4 pooka }
753 1.4 pooka if (writefds) {
754 1.4 pooka if (pfds[i].revents & POLLOUT) {
755 1.4 pooka FD_SET(pfds[i].fd, writefds);
756 1.4 pooka }
757 1.4 pooka }
758 1.4 pooka if (exceptfds) {
759 1.4 pooka if (pfds[i].revents & (POLLHUP|POLLERR)) {
760 1.4 pooka FD_SET(pfds[i].fd, exceptfds);
761 1.4 pooka }
762 1.4 pooka }
763 1.1 pooka }
764 1.1 pooka
765 1.4 pooka out:
766 1.4 pooka free(pfds);
767 1.1 pooka return rv;
768 1.1 pooka }
769 1.1 pooka
770 1.1 pooka static void
771 1.1 pooka checkpoll(struct pollfd *fds, nfds_t nfds, int *hostcall, int *rumpcall)
772 1.1 pooka {
773 1.1 pooka nfds_t i;
774 1.1 pooka
775 1.1 pooka for (i = 0; i < nfds; i++) {
776 1.2 pooka if (fd_isrump(fds[i].fd))
777 1.2 pooka (*rumpcall)++;
778 1.2 pooka else
779 1.1 pooka (*hostcall)++;
780 1.1 pooka }
781 1.1 pooka }
782 1.1 pooka
783 1.1 pooka static void
784 1.2 pooka adjustpoll(struct pollfd *fds, nfds_t nfds, int (*fdadj)(int))
785 1.1 pooka {
786 1.1 pooka nfds_t i;
787 1.1 pooka
788 1.1 pooka for (i = 0; i < nfds; i++) {
789 1.2 pooka fds[i].fd = fdadj(fds[i].fd);
790 1.1 pooka }
791 1.1 pooka }
792 1.1 pooka
793 1.3 pooka struct mytimespec {
794 1.3 pooka uint64_t tv_sec;
795 1.3 pooka long tv_nsec;
796 1.3 pooka };
797 1.3 pooka
798 1.1 pooka /*
799 1.1 pooka * poll is easy as long as the call comes in the fds only in one
800 1.1 pooka * kernel. otherwise its quite tricky...
801 1.1 pooka */
802 1.1 pooka struct pollarg {
803 1.1 pooka struct pollfd *pfds;
804 1.1 pooka nfds_t nfds;
805 1.3 pooka const struct timespec *ts;
806 1.3 pooka const sigset_t *sigmask;
807 1.1 pooka int pipefd;
808 1.1 pooka int errnum;
809 1.1 pooka };
810 1.1 pooka
811 1.1 pooka static void *
812 1.1 pooka hostpoll(void *arg)
813 1.1 pooka {
814 1.1 pooka struct pollarg *parg = arg;
815 1.1 pooka intptr_t rv;
816 1.1 pooka
817 1.3 pooka rv = host_pollts(parg->pfds, parg->nfds, parg->ts, parg->sigmask);
818 1.1 pooka if (rv == -1)
819 1.1 pooka parg->errnum = errno;
820 1.1 pooka rump_sys_write(parg->pipefd, &rv, sizeof(rv));
821 1.1 pooka
822 1.1 pooka return (void *)(intptr_t)rv;
823 1.1 pooka }
824 1.1 pooka
825 1.1 pooka int
826 1.3 pooka pollts(struct pollfd *fds, nfds_t nfds, const struct timespec *ts,
827 1.3 pooka const sigset_t *sigmask)
828 1.1 pooka {
829 1.3 pooka int (*op_pollts)(struct pollfd *, nfds_t, const struct timespec *,
830 1.3 pooka const sigset_t *);
831 1.1 pooka int hostcall = 0, rumpcall = 0;
832 1.1 pooka pthread_t pt;
833 1.1 pooka nfds_t i;
834 1.1 pooka int rv;
835 1.1 pooka
836 1.3 pooka #if 0
837 1.3 pooka /* XXX: quick 5.0 kludge. do syscall compat in rumpclient properly */
838 1.3 pooka struct mytimespec mts;
839 1.3 pooka if (ts) {
840 1.3 pooka mts.tv_sec = ts->tv_sec;
841 1.3 pooka mts.tv_nsec = ts->tv_nsec;
842 1.3 pooka ts = (struct timespec *)&mts;
843 1.3 pooka }
844 1.3 pooka #endif
845 1.3 pooka
846 1.2 pooka DPRINTF(("poll\n"));
847 1.1 pooka checkpoll(fds, nfds, &hostcall, &rumpcall);
848 1.1 pooka
849 1.1 pooka if (hostcall && rumpcall) {
850 1.1 pooka struct pollfd *pfd_host = NULL, *pfd_rump = NULL;
851 1.1 pooka int rpipe[2] = {-1,-1}, hpipe[2] = {-1,-1};
852 1.1 pooka struct pollarg parg;
853 1.1 pooka uintptr_t lrv;
854 1.1 pooka int sverrno = 0, trv;
855 1.1 pooka
856 1.1 pooka /*
857 1.1 pooka * ok, this is where it gets tricky. We must support
858 1.1 pooka * this since it's a very common operation in certain
859 1.1 pooka * types of software (telnet, netcat, etc). We allocate
860 1.1 pooka * two vectors and run two poll commands in separate
861 1.1 pooka * threads. Whichever returns first "wins" and the
862 1.1 pooka * other kernel's fds won't show activity.
863 1.1 pooka */
864 1.1 pooka rv = -1;
865 1.1 pooka
866 1.1 pooka /* allocate full vector for O(n) joining after call */
867 1.1 pooka pfd_host = malloc(sizeof(*pfd_host)*(nfds+1));
868 1.1 pooka if (!pfd_host)
869 1.1 pooka goto out;
870 1.1 pooka pfd_rump = malloc(sizeof(*pfd_rump)*(nfds+1));
871 1.1 pooka if (!pfd_rump) {
872 1.1 pooka goto out;
873 1.1 pooka }
874 1.1 pooka
875 1.1 pooka /* split vectors */
876 1.1 pooka for (i = 0; i < nfds; i++) {
877 1.3 pooka if (fds[i].fd == -1) {
878 1.3 pooka pfd_host[i].fd = -1;
879 1.3 pooka pfd_rump[i].fd = -1;
880 1.3 pooka } else if (fd_isrump(fds[i].fd)) {
881 1.2 pooka pfd_host[i].fd = -1;
882 1.2 pooka pfd_rump[i].fd = fd_host2rump(fds[i].fd);
883 1.2 pooka pfd_rump[i].events = fds[i].events;
884 1.2 pooka } else {
885 1.2 pooka pfd_rump[i].fd = -1;
886 1.1 pooka pfd_host[i].fd = fds[i].fd;
887 1.1 pooka pfd_host[i].events = fds[i].events;
888 1.1 pooka }
889 1.1 pooka }
890 1.1 pooka
891 1.1 pooka /*
892 1.1 pooka * then, open two pipes, one for notifications
893 1.1 pooka * to each kernel.
894 1.1 pooka */
895 1.1 pooka if (rump_sys_pipe(rpipe) == -1)
896 1.1 pooka goto out;
897 1.1 pooka if (pipe(hpipe) == -1)
898 1.1 pooka goto out;
899 1.1 pooka
900 1.1 pooka pfd_host[nfds].fd = hpipe[0];
901 1.1 pooka pfd_host[nfds].events = POLLIN;
902 1.1 pooka pfd_rump[nfds].fd = rpipe[0];
903 1.1 pooka pfd_rump[nfds].events = POLLIN;
904 1.1 pooka
905 1.1 pooka /*
906 1.1 pooka * then, create a thread to do host part and meanwhile
907 1.1 pooka * do rump kernel part right here
908 1.1 pooka */
909 1.1 pooka
910 1.1 pooka parg.pfds = pfd_host;
911 1.1 pooka parg.nfds = nfds+1;
912 1.3 pooka parg.ts = ts;
913 1.3 pooka parg.sigmask = sigmask;
914 1.1 pooka parg.pipefd = rpipe[1];
915 1.1 pooka pthread_create(&pt, NULL, hostpoll, &parg);
916 1.1 pooka
917 1.3 pooka op_pollts = rumpcalls[RUMPCALL_POLLTS];
918 1.3 pooka lrv = op_pollts(pfd_rump, nfds+1, ts, NULL);
919 1.1 pooka sverrno = errno;
920 1.1 pooka write(hpipe[1], &rv, sizeof(rv));
921 1.1 pooka pthread_join(pt, (void *)&trv);
922 1.1 pooka
923 1.1 pooka /* check who "won" and merge results */
924 1.1 pooka if (lrv != 0 && pfd_host[nfds].revents & POLLIN) {
925 1.1 pooka rv = trv;
926 1.1 pooka
927 1.1 pooka for (i = 0; i < nfds; i++) {
928 1.1 pooka if (pfd_rump[i].fd != -1)
929 1.1 pooka fds[i].revents = pfd_rump[i].revents;
930 1.1 pooka }
931 1.1 pooka sverrno = parg.errnum;
932 1.1 pooka } else if (trv != 0 && pfd_rump[nfds].revents & POLLIN) {
933 1.1 pooka rv = trv;
934 1.1 pooka
935 1.1 pooka for (i = 0; i < nfds; i++) {
936 1.1 pooka if (pfd_host[i].fd != -1)
937 1.1 pooka fds[i].revents = pfd_host[i].revents;
938 1.1 pooka }
939 1.1 pooka } else {
940 1.1 pooka rv = 0;
941 1.1 pooka }
942 1.1 pooka
943 1.1 pooka out:
944 1.1 pooka if (rpipe[0] != -1)
945 1.1 pooka rump_sys_close(rpipe[0]);
946 1.1 pooka if (rpipe[1] != -1)
947 1.1 pooka rump_sys_close(rpipe[1]);
948 1.1 pooka if (hpipe[0] != -1)
949 1.1 pooka close(hpipe[0]);
950 1.1 pooka if (hpipe[1] != -1)
951 1.1 pooka close(hpipe[1]);
952 1.1 pooka free(pfd_host);
953 1.1 pooka free(pfd_rump);
954 1.1 pooka errno = sverrno;
955 1.1 pooka } else {
956 1.1 pooka if (hostcall) {
957 1.3 pooka op_pollts = host_pollts;
958 1.1 pooka } else {
959 1.3 pooka op_pollts = rumpcalls[RUMPCALL_POLLTS];
960 1.2 pooka adjustpoll(fds, nfds, fd_host2rump);
961 1.1 pooka }
962 1.1 pooka
963 1.3 pooka rv = op_pollts(fds, nfds, ts, sigmask);
964 1.1 pooka if (rumpcall)
965 1.2 pooka adjustpoll(fds, nfds, fd_rump2host);
966 1.1 pooka }
967 1.1 pooka
968 1.1 pooka return rv;
969 1.1 pooka }
970 1.1 pooka
971 1.1 pooka int
972 1.3 pooka poll(struct pollfd *fds, nfds_t nfds, int timeout)
973 1.1 pooka {
974 1.3 pooka struct timespec ts;
975 1.3 pooka struct timespec *tsp = NULL;
976 1.3 pooka
977 1.3 pooka if (timeout != INFTIM) {
978 1.3 pooka ts.tv_sec = timeout / 1000;
979 1.3 pooka ts.tv_nsec = (timeout % 1000) * 1000;
980 1.3 pooka
981 1.3 pooka tsp = &ts;
982 1.3 pooka }
983 1.1 pooka
984 1.3 pooka return pollts(fds, nfds, tsp, NULL);
985 1.1 pooka }
986