xref: /netbsd/sys/arch/usermode/usermode/thunk.c (revision b950503f)
1 /* $NetBSD: thunk.c,v 1.92 2019/05/08 13:40:16 isaki Exp $ */
2 
3 /*-
4  * Copyright (c) 2011 Jared D. McNeill <jmcneill@invisible.ca>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 #ifdef __NetBSD__
31 __RCSID("$NetBSD: thunk.c,v 1.92 2019/05/08 13:40:16 isaki Exp $");
32 #endif
33 
34 #define _KMEMUSER
35 #define _X86_64_MACHTYPES_H_
36 #define _I386_MACHTYPES_H_
37 
38 #include "../include/types.h"
39 
40 #include <sys/mman.h>
41 #include <stdarg.h>
42 #include <sys/reboot.h>
43 #include <sys/poll.h>
44 #include <sys/sysctl.h>
45 #include <sys/socket.h>
46 #include <sys/audioio.h>
47 #include <sys/shm.h>
48 #include <sys/ioctl.h>
49 
50 #include <machine/vmparam.h>
51 
52 #include <net/if.h>
53 #include <net/if_dl.h>
54 #include <net/if_ether.h>
55 #include <net/if_tap.h>
56 #include <netinet/in.h>
57 #include <arpa/inet.h>
58 
59 #include <aio.h>
60 #include <assert.h>
61 #include <ctype.h>
62 #include <err.h>
63 #include <errno.h>
64 #include <fcntl.h>
65 #include <ifaddrs.h>
66 #include <sched.h>
67 #include <stdarg.h>
68 #include <stdint.h>
69 #include <stdio.h>
70 #include <stdlib.h>
71 #include <signal.h>
72 #include <string.h>
73 #include <termios.h>
74 #include <time.h>
75 #include <ucontext.h>
76 #include <unistd.h>
77 #include <stdbool.h>
78 
79 #include "../include/thunk.h"
80 
81 #ifdef __NetBSD__
82 #define SYS_syscallemu	511
83 #endif
84 
85 #ifndef __arraycount
86 #define __arraycount(x)	(sizeof((x)) / sizeof((x)[0]))
87 #endif
88 
89 #ifndef MAP_ANON
90 #define MAP_ANON MAP_ANONYMOUS
91 #endif
92 
93 //#define RFB_DEBUG
94 
95 static ssize_t safe_recv(int s, void *buf, int len);
96 static ssize_t safe_send(int s, const void *msg, int len);
97 
98 extern int boothowto;
99 
100 void
thunk_printf_debug(const char * fmt,...)101 thunk_printf_debug(const char *fmt, ...)
102 {
103 	if (boothowto & AB_DEBUG) {
104 		va_list ap;
105 
106 		va_start(ap, fmt);
107 		vfprintf(stderr, fmt, ap);
108 		va_end(ap);
109 	}
110 }
111 
112 void
thunk_printf(const char * fmt,...)113 thunk_printf(const char *fmt, ...)
114 {
115 	va_list ap;
116 
117 	va_start(ap, fmt);
118 	vfprintf(stderr, fmt, ap);
119 	va_end(ap);
120 	fflush(stderr);
121 }
122 
123 int
thunk_syscallemu_init(void * ustart,void * uend)124 thunk_syscallemu_init(void *ustart, void *uend)
125 {
126 	int error;
127 
128 	errno = 0;
129 	error = syscall(SYS_syscallemu, (uintptr_t)ustart, (uintptr_t)uend);
130 	if (error == -1 && errno == EACCES) {
131 		/* syscallemu already active for this pid */
132 		error = 0;
133 	}
134 
135 	return error;
136 }
137 
138 static void
thunk_to_timeval(const struct thunk_timeval * ttv,struct timeval * tv)139 thunk_to_timeval(const struct thunk_timeval *ttv, struct timeval *tv)
140 {
141 	tv->tv_sec = ttv->tv_sec;
142 	tv->tv_usec = ttv->tv_usec;
143 }
144 
145 static void
thunk_from_timeval(const struct timeval * tv,struct thunk_timeval * ttv)146 thunk_from_timeval(const struct timeval *tv, struct thunk_timeval *ttv)
147 {
148 	ttv->tv_sec = tv->tv_sec;
149 	ttv->tv_usec = tv->tv_usec;
150 }
151 
152 static void
thunk_to_itimerval(const struct thunk_itimerval * tit,struct itimerval * it)153 thunk_to_itimerval(const struct thunk_itimerval *tit, struct itimerval *it)
154 {
155 	thunk_to_timeval(&tit->it_interval, &it->it_interval);
156 	thunk_to_timeval(&tit->it_value, &it->it_value);
157 }
158 
159 static void
thunk_from_itimerval(const struct itimerval * it,struct thunk_itimerval * tit)160 thunk_from_itimerval(const struct itimerval *it, struct thunk_itimerval *tit)
161 {
162 	thunk_from_timeval(&it->it_interval, &tit->it_interval);
163 	thunk_from_timeval(&it->it_value, &tit->it_value);
164 }
165 
166 static void
thunk_to_termios(const struct thunk_termios * tt,struct termios * t)167 thunk_to_termios(const struct thunk_termios *tt, struct termios *t)
168 {
169 	int i;
170 
171 	t->c_iflag = tt->c_iflag;
172 	t->c_oflag = tt->c_oflag;
173 	t->c_cflag = tt->c_cflag;
174 	t->c_lflag = tt->c_lflag;
175 	for (i = 0; i < __arraycount(t->c_cc); i++)
176 		t->c_cc[i] = tt->c_cc[i];
177 	t->c_ispeed = tt->c_ispeed;
178 	t->c_ospeed= tt->c_ospeed;
179 }
180 
181 static void
thunk_from_termios(const struct termios * t,struct thunk_termios * tt)182 thunk_from_termios(const struct termios *t, struct thunk_termios *tt)
183 {
184 	int i;
185 
186 	tt->c_iflag = t->c_iflag;
187 	tt->c_oflag = t->c_oflag;
188 	tt->c_cflag = t->c_cflag;
189 	tt->c_lflag = t->c_lflag;
190 	for (i = 0; i < __arraycount(tt->c_cc); i++)
191 		tt->c_cc[i] = t->c_cc[i];
192 	tt->c_ispeed = t->c_ispeed;
193 	tt->c_ospeed= t->c_ospeed;
194 }
195 
196 static int
thunk_to_native_prot(int prot)197 thunk_to_native_prot(int prot)
198 {
199 	int nprot = PROT_NONE;
200 
201 	if (prot & THUNK_PROT_READ)
202 		nprot |= PROT_READ;
203 	if (prot & THUNK_PROT_WRITE)
204 		nprot |= PROT_WRITE;
205 	if (prot & THUNK_PROT_EXEC)
206 		nprot |= PROT_EXEC;
207 
208 	return nprot;
209 }
210 
211 static int
thunk_to_native_mapflags(int flags)212 thunk_to_native_mapflags(int flags)
213 {
214 	int nflags = 0;
215 
216 	if (flags & THUNK_MAP_ANON)
217 		nflags |= MAP_ANON;
218 	if (flags & THUNK_MAP_FIXED)
219 		nflags |= MAP_FIXED;
220 	if (flags & THUNK_MAP_FILE)
221 		nflags |= MAP_FILE;
222 	if (flags & THUNK_MAP_SHARED)
223 		nflags |= MAP_SHARED;
224 	if (flags & THUNK_MAP_PRIVATE)
225 		nflags |= MAP_PRIVATE;
226 
227 	return nflags;
228 }
229 
230 static int
thunk_to_native_madviseflags(int flags)231 thunk_to_native_madviseflags(int flags)
232 {
233 	int nflags = 0;
234 
235 	if (flags & THUNK_MADV_NORMAL)
236 		nflags |= MADV_NORMAL;
237 	if (flags & THUNK_MADV_RANDOM)
238 		nflags |= MADV_RANDOM;
239 	if (flags & THUNK_MADV_SEQUENTIAL)
240 		nflags |= MADV_SEQUENTIAL;
241 	if (flags & THUNK_MADV_WILLNEED)
242 		nflags |= MADV_WILLNEED;
243 	if (flags & THUNK_MADV_DONTNEED)
244 		nflags |= MADV_DONTNEED;
245 	if (flags & THUNK_MADV_FREE)
246 		nflags |= MADV_FREE;
247 
248 	return nflags;
249 }
250 
251 int
thunk_setitimer(int which,const struct thunk_itimerval * value,struct thunk_itimerval * ovalue)252 thunk_setitimer(int which, const struct thunk_itimerval *value,
253     struct thunk_itimerval *ovalue)
254 {
255 	struct itimerval it, oit;
256 	int error;
257 
258 	thunk_to_itimerval(value, &it);
259 	error = setitimer(which, &it, &oit);
260 	if (error)
261 		return error;
262 	if (ovalue)
263 		thunk_from_itimerval(&oit, ovalue);
264 
265 	return 0;
266 }
267 
268 int
thunk_gettimeofday(struct thunk_timeval * tp,void * tzp)269 thunk_gettimeofday(struct thunk_timeval *tp, void *tzp)
270 {
271 	struct timeval tv;
272 	int error;
273 
274 	error = gettimeofday(&tv, tzp);
275 	if (error)
276 		return error;
277 
278 	thunk_from_timeval(&tv, tp);
279 
280 	return 0;
281 }
282 
283 unsigned int
thunk_getcounter(void)284 thunk_getcounter(void)
285 {
286 	struct timespec ts;
287 	int error;
288 
289 	error = clock_gettime(CLOCK_MONOTONIC, &ts);
290 	if (error == -1) {
291 		warn("clock_gettime CLOCK_MONOTONIC");
292 		abort();
293 	}
294 
295 	return (unsigned int)(ts.tv_nsec % 1000000000ULL);
296 }
297 
298 long
thunk_clock_getres_monotonic(void)299 thunk_clock_getres_monotonic(void)
300 {
301 	struct timespec res;
302 	int error;
303 
304 	error = clock_getres(CLOCK_MONOTONIC, &res);
305 	if (error == -1)
306 		return -1;
307 
308 	return (long)(res.tv_sec * 1000000000ULL + res.tv_nsec);
309 }
310 
311 timer_t
thunk_timer_attach(void)312 thunk_timer_attach(void)
313 {
314 	timer_t timerid;
315 	int error;
316 
317 	error = timer_create(CLOCK_MONOTONIC, NULL, &timerid);
318 	if (error == -1) {
319 		warn("timer_create CLOCK_MONOTONIC");
320 		abort();
321 	}
322 
323 	return timerid;
324 }
325 
326 int
thunk_timer_start(timer_t timerid,int freq)327 thunk_timer_start(timer_t timerid, int freq)
328 {
329 	struct itimerspec tim;
330 
331 	tim.it_interval.tv_sec = 0;
332 	tim.it_interval.tv_nsec = 1000000000 / freq;
333 	tim.it_value = tim.it_interval;
334 
335 	return timer_settime(timerid, TIMER_RELTIME, &tim, NULL);
336 }
337 
338 int
thunk_timer_getoverrun(timer_t timerid)339 thunk_timer_getoverrun(timer_t timerid)
340 {
341 	return timer_getoverrun(timerid);
342 }
343 
344 int
thunk_usleep(useconds_t microseconds)345 thunk_usleep(useconds_t microseconds)
346 {
347 	return usleep(microseconds);
348 }
349 
350 void
thunk_kill(pid_t pid,int sig)351 thunk_kill(pid_t pid, int sig)
352 {
353 	kill(pid, sig);
354 }
355 
356 void
thunk_exit(int status)357 thunk_exit(int status)
358 {
359 	return exit(status);
360 }
361 
362 void
thunk_abort(void)363 thunk_abort(void)
364 {
365 	abort();
366 }
367 
368 int
thunk_geterrno(void)369 thunk_geterrno(void)
370 {
371 	return errno;
372 }
373 
374 void
thunk_seterrno(int nerrno)375 thunk_seterrno(int nerrno)
376 {
377 	errno = nerrno;
378 }
379 
380 int
thunk_getcontext(ucontext_t * ucp)381 thunk_getcontext(ucontext_t *ucp)
382 {
383 	return getcontext(ucp);
384 }
385 
386 int
thunk_setcontext(const ucontext_t * ucp)387 thunk_setcontext(const ucontext_t *ucp)
388 {
389 	return setcontext(ucp);
390 }
391 
392 void
thunk_makecontext(ucontext_t * ucp,void (* func)(void),int nargs,void * arg1,void * arg2,void * arg3,void * arg4)393 thunk_makecontext(ucontext_t *ucp, void (*func)(void),
394     int nargs, void *arg1, void *arg2, void *arg3, void *arg4)
395 {
396 	switch (nargs) {
397 	case 0:
398 		makecontext(ucp, func, 0);
399 		break;
400 	case 1:
401 		makecontext(ucp, func, 1, arg1);
402 		break;
403 	case 2:
404 		makecontext(ucp, func, 2, arg1, arg2);
405 		break;
406 	case 3:
407 		makecontext(ucp, func, 3, arg1, arg2, arg3);
408 		break;
409 	case 4:
410 		makecontext(ucp, func, 4, arg1, arg2, arg3, arg4);
411 		break;
412 	default:
413 		warnx("%s: nargs (%d) too big\n", __func__, nargs);
414 		abort();
415 	}
416 }
417 
418 int
thunk_swapcontext(ucontext_t * oucp,ucontext_t * ucp)419 thunk_swapcontext(ucontext_t *oucp, ucontext_t *ucp)
420 {
421 	return swapcontext(oucp, ucp);
422 }
423 
424 int
thunk_tcgetattr(int fd,struct thunk_termios * tt)425 thunk_tcgetattr(int fd, struct thunk_termios *tt)
426 {
427 	struct termios t;
428 	int error;
429 
430 	error = tcgetattr(fd, &t);
431 	if (error == -1)
432 		return error;
433 	thunk_from_termios(&t, tt);
434 	return 0;
435 }
436 
437 int
thunk_tcsetattr(int fd,int action,const struct thunk_termios * tt)438 thunk_tcsetattr(int fd, int action, const struct thunk_termios *tt)
439 {
440 	struct termios t;
441 
442 	thunk_to_termios(tt, &t);
443 	return tcsetattr(fd, action, &t);
444 }
445 
446 int
thunk_set_stdin_sigio(int onoff)447 thunk_set_stdin_sigio(int onoff)
448 {
449 	int flags;
450 
451 	flags = fcntl(STDIN_FILENO, F_GETFL, 0);
452 
453 	if (onoff)
454 		flags |= O_ASYNC;
455 	else
456 		flags &= ~O_ASYNC;
457 
458 	return fcntl(STDIN_FILENO, F_SETFL, flags);
459 }
460 
461 int
thunk_pollchar(void)462 thunk_pollchar(void)
463 {
464 	struct pollfd fds[1];
465 	uint8_t c;
466 
467 	fds[0].fd = STDIN_FILENO;
468 	fds[0].events = POLLIN;
469 	fds[0].revents = 0;
470 
471 	if (poll(fds, __arraycount(fds), 0) > 0) {
472 		if (fds[0].revents & POLLIN) {
473 			if (read(STDIN_FILENO, &c, 1) != 1)
474 				return EOF;
475 			return c;
476 		}
477 	}
478 
479 	return EOF;
480 }
481 
482 int
thunk_getchar(void)483 thunk_getchar(void)
484 {
485 	return getchar();
486 }
487 
488 void
thunk_putchar(int c)489 thunk_putchar(int c)
490 {
491 	char wc = (char) c;
492 	write(1, &wc, 1);
493 }
494 
495 int
thunk_execv(const char * path,char * const argv[])496 thunk_execv(const char *path, char * const argv[])
497 {
498 	return execv(path, argv);
499 }
500 
501 int
thunk_open(const char * path,int flags,mode_t mode)502 thunk_open(const char *path, int flags, mode_t mode)
503 {
504 	return open(path, flags, mode);
505 }
506 
507 int
thunk_close(int fd)508 thunk_close(int fd)
509 {
510 	return close(fd);
511 }
512 
513 int
thunk_fstat_getsize(int fd,off_t * size,ssize_t * blksize)514 thunk_fstat_getsize(int fd, off_t *size, ssize_t *blksize)
515 {
516 	struct stat st;
517 	int error;
518 
519 	error = fstat(fd, &st);
520 	if (error)
521 		return -1;
522 
523 	if (size)
524 		*size = st.st_size;
525 	if (blksize)
526 		*blksize = st.st_blksize;
527 
528 	return 0;
529 }
530 
531 ssize_t
thunk_pread(int d,void * buf,size_t nbytes,off_t offset)532 thunk_pread(int d, void *buf, size_t nbytes, off_t offset)
533 {
534 	return pread(d, buf, nbytes, offset);
535 }
536 
537 ssize_t
thunk_pwrite(int d,const void * buf,size_t nbytes,off_t offset)538 thunk_pwrite(int d, const void *buf, size_t nbytes, off_t offset)
539 {
540 	return pwrite(d, buf, nbytes, offset);
541 }
542 
543 ssize_t
thunk_read(int d,void * buf,size_t nbytes)544 thunk_read(int d, void *buf, size_t nbytes)
545 {
546 	return read(d, buf, nbytes);
547 }
548 
549 ssize_t
thunk_write(int d,const void * buf,size_t nbytes)550 thunk_write(int d, const void *buf, size_t nbytes)
551 {
552 	return write(d, buf, nbytes);
553 }
554 
555 int
thunk_fsync(int fd)556 thunk_fsync(int fd)
557 {
558 	return fsync(fd);
559 }
560 
561 int
thunk_mkstemp(char * template)562 thunk_mkstemp(char *template)
563 {
564 	return mkstemp(template);
565 }
566 
567 int
thunk_unlink(const char * path)568 thunk_unlink(const char *path)
569 {
570 	return unlink(path);
571 }
572 
573 pid_t
thunk_getpid(void)574 thunk_getpid(void)
575 {
576 	return getpid();
577 }
578 
579 int
thunk_sigaction(int sig,const struct sigaction * act,struct sigaction * oact)580 thunk_sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
581 {
582 	return sigaction(sig, act, oact);
583 }
584 
585 int
thunk_sigaltstack(const stack_t * ss,stack_t * oss)586 thunk_sigaltstack(const stack_t *ss, stack_t *oss)
587 {
588 	return sigaltstack(ss, oss);
589 }
590 
591 void
thunk_signal(int sig,void (* func)(int))592 thunk_signal(int sig, void (*func)(int))
593 {
594 	struct sigaction sa;
595 
596 	sa.sa_flags = SA_RESTART | SA_ONSTACK;
597 	sa.sa_sigaction = (void (*)(int, siginfo_t *, void *))func;
598 	sigemptyset(&sa.sa_mask);
599 	sigaction(sig, &sa, NULL);
600 }
601 
602 int
thunk_sigblock(int sig)603 thunk_sigblock(int sig)
604 {
605 	sigset_t set;
606 
607 	sigemptyset(&set);
608 	sigaddset(&set, sig);
609 	return sigprocmask(SIG_BLOCK, &set, NULL);
610 }
611 
612 int
thunk_sigunblock(int sig)613 thunk_sigunblock(int sig)
614 {
615 	sigset_t set;
616 
617 	sigemptyset(&set);
618 	sigaddset(&set, sig);
619 	return sigprocmask(SIG_UNBLOCK, &set, NULL);
620 }
621 
622 int
thunk_sigemptyset(sigset_t * sa_mask)623 thunk_sigemptyset(sigset_t *sa_mask)
624 {
625 	return sigemptyset(sa_mask);
626 }
627 
628 
629 int
thunk_sigfillset(sigset_t * sa_mask)630 thunk_sigfillset(sigset_t *sa_mask)
631 {
632 	return sigfillset(sa_mask);
633 }
634 
635 
636 void
thunk_sigaddset(sigset_t * sa_mask,int sig)637 thunk_sigaddset(sigset_t *sa_mask, int sig)
638 {
639 	int retval;
640 	retval = sigaddset(sa_mask, sig);
641 	if (retval == -1) {
642 		warn("bad signal added");
643 		abort();
644 	}
645 }
646 
647 int
thunk_sigprocmask(int how,const sigset_t * set,sigset_t * oset)648 thunk_sigprocmask(int how, const sigset_t * set, sigset_t *oset)
649 {
650 	return sigprocmask(how, set, oset);
651 }
652 
653 int
thunk_atexit(void (* function)(void))654 thunk_atexit(void (*function)(void))
655 {
656 	return atexit(function);
657 }
658 
659 pid_t
thunk_fork(void)660 thunk_fork(void)
661 {
662 	return fork();
663 }
664 
665 int
thunk_ioctl(int fd,unsigned long request,void * opaque)666 thunk_ioctl(int fd, unsigned long request, void *opaque)
667 {
668 	return ioctl(fd, request, opaque);
669 }
670 
671 int
thunk_aio_read(struct aiocb * aiocbp)672 thunk_aio_read(struct aiocb *aiocbp)
673 {
674 	return aio_read(aiocbp);
675 }
676 
677 int
thunk_aio_write(struct aiocb * aiocbp)678 thunk_aio_write(struct aiocb *aiocbp)
679 {
680 	return aio_write(aiocbp);
681 }
682 
683 int
thunk_aio_error(const struct aiocb * aiocbp)684 thunk_aio_error(const struct aiocb *aiocbp)
685 {
686 	return aio_error(aiocbp);
687 }
688 
689 int
thunk_aio_return(struct aiocb * aiocbp)690 thunk_aio_return(struct aiocb *aiocbp)
691 {
692 	return aio_return(aiocbp);
693 }
694 
695 void *
thunk_malloc(size_t len)696 thunk_malloc(size_t len)
697 {
698 	return malloc(len);
699 }
700 
701 void
thunk_free(void * addr)702 thunk_free(void *addr)
703 {
704 	free(addr);
705 }
706 
707 void *
thunk_sbrk(intptr_t len)708 thunk_sbrk(intptr_t len)
709 {
710 	return sbrk(len);
711 }
712 
713 void *
thunk_mmap(void * addr,size_t len,int prot,int flags,int fd,off_t offset)714 thunk_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
715 {
716 	int nflags, nprot;
717 	void *a;
718 
719 	nprot = thunk_to_native_prot(prot);
720 	nflags = thunk_to_native_mapflags(flags);
721 
722 	a = mmap(addr, len, nprot, nflags, fd, offset);
723 	if (a == MAP_FAILED)
724 		warn("mmap");
725 	return a;
726 }
727 
728 int
thunk_munmap(void * addr,size_t len)729 thunk_munmap(void *addr, size_t len)
730 {
731 	return munmap(addr, len);
732 }
733 
734 int
thunk_mprotect(void * addr,size_t len,int prot)735 thunk_mprotect(void *addr, size_t len, int prot)
736 {
737 	int nprot;
738 
739 	nprot = thunk_to_native_prot(prot);
740 
741 	return mprotect(addr, len, nprot);
742 }
743 
744 int
thunk_madvise(void * addr,size_t len,int behav)745 thunk_madvise(void *addr, size_t len, int behav)
746 {
747 	int nbehav;
748 
749 	nbehav = thunk_to_native_madviseflags(behav);
750 
751 	return madvise(addr, len, nbehav);
752 }
753 
754 int
thunk_posix_memalign(void ** ptr,size_t alignment,size_t size)755 thunk_posix_memalign(void **ptr, size_t alignment, size_t size)
756 {
757 	return posix_memalign(ptr, alignment, size);
758 }
759 
760 char *
thunk_getenv(const char * name)761 thunk_getenv(const char *name)
762 {
763 	return getenv(name);
764 }
765 
766 vaddr_t
thunk_get_vm_min_address(void)767 thunk_get_vm_min_address(void)
768 {
769 	return VM_MIN_ADDRESS;
770 }
771 
772 int
thunk_idle(void)773 thunk_idle(void)
774 {
775 	sigset_t sigmask;
776 
777 	sigemptyset(&sigmask);
778 
779 	return sigsuspend(&sigmask);
780 }
781 
782 int
thunk_getcpuinfo(char * cp,size_t * len)783 thunk_getcpuinfo(char *cp, size_t *len)
784 {
785 	ssize_t rlen;
786 	int fd;
787 
788 	fd = open("/proc/cpuinfo", O_RDONLY);
789 	if (fd == -1)
790 		goto out;
791 	rlen = read(fd, cp, *len);
792 	close(fd);
793 
794 	if (rlen == -1)
795 		goto out;
796 
797 	cp[rlen ? rlen - 1 : 0] = '\0';
798 	*len = rlen;
799 	return 0;
800 out:
801 	*len = 0;
802 	return -1;
803 }
804 
805 int
thunk_getmachine(char * machine,size_t machinelen,char * machine_arch,size_t machine_archlen)806 thunk_getmachine(char *machine, size_t machinelen,
807     char *machine_arch, size_t machine_archlen)
808 {
809 	size_t len;
810 
811 	memset(machine, 0, machinelen);
812 	len = machinelen - 1;
813 	if (sysctlbyname("hw.machine", machine, &len, NULL, 0) == -1) {
814 		warn("sysctlbyname hw.machine failed");
815 		abort();
816 	}
817 
818 	memset(machine_arch, 0, machine_archlen);
819 	len = machine_archlen - 1;
820 	if (sysctlbyname("hw.machine_arch", machine_arch, &len, NULL, 0) == -1) {
821 		warn("sysctlbyname hw.machine_arch failed");
822 		abort();
823 	}
824 
825 	return 0;
826 }
827 
828 int
thunk_setown(int fd)829 thunk_setown(int fd)
830 {
831 	return fcntl(fd, F_SETOWN, getpid());
832 }
833 
834 int
thunk_open_tap(const char * device)835 thunk_open_tap(const char *device)
836 {
837 	int fd, error, enable;
838 
839 	/* open tap device */
840 	fd = open(device, O_RDWR);
841 	if (fd == -1)
842 		return -1;
843 
844 	/* set async mode */
845 	enable = 1;
846 	error = ioctl(fd, FIOASYNC, &enable);
847 	if (error == -1)
848 		return -1;
849 
850 	return fd;
851 }
852 
853 int
thunk_pollin_tap(int fd,int timeout)854 thunk_pollin_tap(int fd, int timeout)
855 {
856 #if 0
857 	struct pollfd fds[1];
858 
859 	fds[0].fd = fd;
860 	fds[0].events = POLLIN|POLLRDNORM;
861 	fds[0].revents = 0;
862 
863 	return poll(fds, __arraycount(fds), timeout);
864 #else
865 	int error, len;
866 
867 	error = ioctl(fd, FIONREAD, &len);
868 	if (error == -1)
869 		return 0;
870 
871 	return len;
872 #endif
873 }
874 
875 int
thunk_pollout_tap(int fd,int timeout)876 thunk_pollout_tap(int fd, int timeout)
877 {
878 	struct pollfd fds[1];
879 
880 	fds[0].fd = fd;
881 	fds[0].events = POLLOUT|POLLWRNORM;
882 	fds[0].revents = 0;
883 
884 	return poll(fds, __arraycount(fds), timeout);
885 }
886 
887 
888 /* simply make sure its present... yeah its silly */
889 int
thunk_assert_presence(vaddr_t from,size_t size)890 thunk_assert_presence(vaddr_t from, size_t size)
891 {
892 	vaddr_t va;
893 	int t = 0;
894 
895 	for (va = from; va < from + (vaddr_t) size; va += PAGE_SIZE) {
896 		t += *(int *) va;
897 	}
898 	return t;
899 }
900 
901 
902 int
thunk_audio_open(const char * path)903 thunk_audio_open(const char *path)
904 {
905 	return open(path, O_RDWR);
906 }
907 
908 int
thunk_audio_close(int fd)909 thunk_audio_close(int fd)
910 {
911 	return close(fd);
912 }
913 
914 int
thunk_audio_config(int fd,const thunk_audio_config_t * pconf,const thunk_audio_config_t * rconf)915 thunk_audio_config(int fd, const thunk_audio_config_t *pconf,
916     const thunk_audio_config_t *rconf)
917 {
918 	struct audio_info info;
919 	int error;
920 
921 	AUDIO_INITINFO(&info);
922 	info.play.sample_rate = pconf->sample_rate;
923 	info.play.channels = pconf->channels;
924 	info.play.precision = pconf->precision;
925 	info.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
926 	info.record.sample_rate = rconf->sample_rate;
927 	info.record.channels = rconf->channels;
928 	info.record.precision = rconf->precision;
929 	info.record.encoding = AUDIO_ENCODING_SLINEAR_LE;
930 	info.mode = AUMODE_PLAY_ALL|AUMODE_RECORD;
931 
932 	error = ioctl(fd, AUDIO_SETINFO, &info);
933 	if (error == -1)
934 		printf("AUDIO_SETINFO failed: %s\n", strerror(errno));
935 
936 	return error;
937 }
938 
939 int
thunk_audio_pollout(int fd)940 thunk_audio_pollout(int fd)
941 {
942 	struct audio_info info;
943 	int error;
944 
945 	AUDIO_INITINFO(&info);
946 	error = ioctl(fd, AUDIO_GETBUFINFO, &info);
947 	if (error == -1)
948 		return -1;
949 
950 	return info.play.buffer_size - info.play.seek;
951 }
952 
953 int
thunk_audio_pollin(int fd)954 thunk_audio_pollin(int fd)
955 {
956 	struct audio_info info;
957 	int error;
958 
959 	AUDIO_INITINFO(&info);
960 	error = ioctl(fd, AUDIO_GETBUFINFO, &info);
961 	if (error == -1)
962 		return -1;
963 
964 	return info.record.seek;
965 }
966 
967 ssize_t
thunk_audio_write(int fd,const void * buf,size_t buflen)968 thunk_audio_write(int fd, const void *buf, size_t buflen)
969 {
970 	return write(fd, buf, buflen);
971 }
972 
973 ssize_t
thunk_audio_read(int fd,void * buf,size_t buflen)974 thunk_audio_read(int fd, void *buf, size_t buflen)
975 {
976 	return read(fd, buf, buflen);
977 }
978 
979 int
thunk_rfb_open(thunk_rfb_t * rfb,uint16_t port)980 thunk_rfb_open(thunk_rfb_t *rfb, uint16_t port)
981 {
982 	struct sockaddr_in sin;
983 	int serrno;
984 
985 	rfb->clientfd = -1;
986 	rfb->connected = false;
987 
988 	/* create socket */
989 	rfb->sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
990 	if (rfb->sockfd == -1) {
991 		serrno = errno;
992 		warn("rfb: couldn't create socket");
993 		return serrno;
994 	}
995 	/* bind to requested port */
996 	memset(&sin, 0, sizeof(sin));
997 	sin.sin_family = AF_INET;
998 	sin.sin_addr.s_addr = htonl(INADDR_ANY);
999 	sin.sin_port = htons(port);
1000 	if (bind(rfb->sockfd, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
1001 		serrno = errno;
1002 		warn("rfb: couldn't bind port %d", port);
1003 		close(rfb->sockfd);
1004 		return serrno;
1005 	}
1006 	/* listen for connections */
1007 	if (listen(rfb->sockfd, 1) != 0) {
1008 		serrno = errno;
1009 		warn("rfb: couldn't listen on socket");
1010 		close(rfb->sockfd);
1011 		return errno;
1012 	}
1013 
1014 	return 0;
1015 }
1016 
1017 int
thunk_gdb_open(void)1018 thunk_gdb_open(void)
1019 {
1020 	struct sockaddr_in sin;
1021 	int sockfd;
1022 	int portnr = 5001;	/* XXX configurable or random */
1023 
1024 	/* create socket */
1025 	sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1026 	if (sockfd < 0) {
1027 		warn("kgdb stub: couldn't create socket");
1028 		return 0;
1029 	}
1030 
1031 	/* bind to requested port */
1032 	memset(&sin, 0, sizeof(sin));
1033 	sin.sin_family      = AF_INET;
1034 	sin.sin_addr.s_addr = htonl(INADDR_ANY);
1035 	sin.sin_port        = htons(portnr);
1036 
1037 	if (bind(sockfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
1038 		warn("kgdb stub: couldn't bind port %d", portnr);
1039 		close(sockfd);
1040 		return 0;
1041 	}
1042 
1043 	/* listen for connections */
1044 	if (listen(sockfd, 1) < 0) {
1045 		warn("kgdb stub: couldn't listen on socket");
1046 		close(sockfd);
1047 		return 0;
1048 	}
1049 	printf("kgdb stub: accepting connections on port %d\n", portnr);
1050 
1051 	return sockfd;
1052 }
1053 
1054 int
thunk_gdb_accept(int sockfd)1055 thunk_gdb_accept(int sockfd)
1056 {
1057 	struct sockaddr_in client_addr;
1058 	socklen_t client_addrlen;
1059 	int fd, flags;
1060 
1061 	fd = accept(sockfd, (struct sockaddr *) &client_addr, &client_addrlen);
1062 	if (fd < 0) {
1063 		warn("kgdb_stub: connect error");
1064 		return 0;
1065 	}
1066 
1067   	/* make FIFO unblocking */
1068 	flags = fcntl(fd, F_GETFL, 0);
1069 	if (flags == -1)
1070 		flags = 0;
1071 	if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
1072 		warn("kgdb_stub: can't make socket non blocking");
1073 	}
1074 	return fd;
1075 }
1076 
1077 int
thunk_kgdb_getc(int fd,char * ch)1078 thunk_kgdb_getc(int fd, char *ch)
1079 {
1080 	return safe_recv(fd, ch, 1);
1081 }
1082 
1083 int
thunk_kgdb_putc(int fd,char ch)1084 thunk_kgdb_putc(int fd, char ch)
1085 {
1086 	return safe_send(fd, &ch, 1);
1087 }
1088 
1089 static ssize_t
safe_send(int s,const void * msg,int len)1090 safe_send(int s, const void *msg, int len)
1091 {
1092 	const uint8_t *p;
1093 	ssize_t sent_len;
1094 
1095 	p = msg;
1096 	while (len) {
1097 		assert(len >= 0);
1098 		sent_len = send(s, p, len, MSG_NOSIGNAL);
1099 		if (sent_len == -1) {
1100 			if (errno == EAGAIN || errno == EINTR)
1101 				continue;
1102 			return -1;
1103 		}
1104 
1105 		p   += sent_len;
1106 		len -= sent_len;
1107 	}
1108 	return len;
1109 }
1110 
1111 static ssize_t
safe_recv(int s,void * buf,int len)1112 safe_recv(int s, void *buf, int len)
1113 {
1114 	uint8_t *p;
1115 	int recv_len;
1116 
1117 	p = buf;
1118 	while (len) {
1119 		assert(len >= 0);
1120 		recv_len = recv(s, p, len, MSG_NOSIGNAL);
1121 		if (recv_len == -1)  {
1122 			if (errno == EAGAIN || errno == EINTR)
1123 				continue;
1124 			return -1;
1125 		}
1126 		p   += recv_len;
1127 		len -= recv_len;
1128 	}
1129 	return len;
1130 }
1131 
1132 static ssize_t
thunk_rfb_server_init(thunk_rfb_t * rfb)1133 thunk_rfb_server_init(thunk_rfb_t *rfb)
1134 {
1135 	char msgbuf[80];
1136 	char *p = msgbuf;
1137 	uint32_t namelen = strlen(rfb->name);
1138 
1139 	*(uint16_t *)p = htons(rfb->width);	p += 2;
1140 	*(uint16_t *)p = htons(rfb->height);	p += 2;
1141 	*(uint8_t *)p = rfb->depth;		p += 1;
1142 	*(uint8_t *)p = rfb->depth;		p += 1;
1143 	*(uint8_t *)p = 0;			p += 1;	/* endian */
1144 	*(uint8_t *)p = 1;			p += 1; /* true color */
1145 	*(uint16_t *)p = htons(0xff);		p += 2;	/* red max */
1146 	*(uint16_t *)p = htons(0xff);		p += 2;	/* green max */
1147 	*(uint16_t *)p = htons(0xff);		p += 2;	/* blue max */
1148 	*(uint8_t *)p = 0;			p += 1;	/* red shift */
1149 	*(uint8_t *)p = 8;			p += 1;	/* green shift */
1150 	*(uint8_t *)p = 16;			p += 1;	/* blue shift */
1151 	*(uint8_t *)p = 0;			p += 1;	/* padding x3 */
1152 	*(uint8_t *)p = 0;			p += 1;
1153 	*(uint8_t *)p = 0;			p += 1;
1154 	*(uint32_t *)p = htonl(namelen);	p += 4;	/* name length */
1155 	memcpy(p, rfb->name, namelen);		p += namelen;
1156 
1157 	return safe_send(rfb->clientfd, msgbuf, p - msgbuf);
1158 }
1159 
1160 static int
thunk_rfb_handshake(thunk_rfb_t * rfb)1161 thunk_rfb_handshake(thunk_rfb_t *rfb)
1162 {
1163 	ssize_t len;
1164 	const char *protover = "RFB 003.003\n";
1165 	uint32_t security_type;
1166 	uint8_t shared_flag;
1167 	char dummy;
1168 
1169 	/* send server protocol version */
1170 	len = safe_send(rfb->clientfd, protover, strlen(protover));
1171 	if (len == -1)
1172 		return errno;
1173 
1174 	/* receive client protocol version */
1175 	do {
1176 		len = safe_recv(rfb->clientfd, &dummy, sizeof(dummy));
1177 		if (len == -1)
1178 			return errno;
1179 	} while (dummy != '\n');
1180 
1181 	/* send security capabilities */
1182 	security_type = htonl(1);	/* no security */
1183 	len = safe_send(rfb->clientfd, &security_type, sizeof(security_type));
1184 	if (len == -1)
1185 		return errno;
1186 
1187 	/* receive client init message */
1188 	len = safe_recv(rfb->clientfd, &shared_flag, sizeof(shared_flag));
1189 	if (len == -1)
1190 		return errno;
1191 
1192 	/* send server init message */
1193 	len = thunk_rfb_server_init(rfb);
1194 	if (len == -1)
1195 		return errno;
1196 
1197 	return 0;
1198 }
1199 
1200 static void
thunk_rfb_send_pending(thunk_rfb_t * rfb)1201 thunk_rfb_send_pending(thunk_rfb_t *rfb)
1202 {
1203 	thunk_rfb_update_t *update;
1204 	uint8_t buf[32];
1205 	uint8_t *p;
1206 	unsigned int n;
1207 	unsigned int bytes_per_pixel;
1208 	ssize_t stride, line_len, len;
1209 
1210 	if (rfb->connected == false || rfb->nupdates == 0)
1211 		return;
1212 
1213 	/* If we have too many updates queued, just send a single update */
1214 	if (rfb->nupdates >= __arraycount(rfb->update)) {
1215 		rfb->nupdates = 1;
1216 		rfb->update[0].enc = THUNK_RFB_TYPE_RAW;
1217 		rfb->update[0].x = 0;
1218 		rfb->update[0].y = 0;
1219 		rfb->update[0].w = rfb->width;
1220 		rfb->update[0].h = rfb->height;
1221 	}
1222 
1223 #ifdef RFB_DEBUG
1224 	fprintf(stdout, "rfb: sending %d updates\n", rfb->nupdates);
1225 #endif
1226 
1227 	p = buf;
1228 	*(uint8_t *)p = 0;		p += 1;		/* FramebufferUpdate */
1229 	*(uint8_t *)p = 0;		p += 1;		/* padding */
1230 	*(uint16_t *)p = htons(rfb->nupdates);	p += 2;	/* # rects */
1231 
1232 	len = safe_send(rfb->clientfd, buf, 4);
1233 	if (len == -1)
1234 		goto disco;
1235 
1236 	bytes_per_pixel = rfb->depth / 8;
1237 	stride = rfb->width * bytes_per_pixel;
1238 	for (n = 0; n < rfb->nupdates; n++) {
1239 		p = buf;
1240 		update = &rfb->update[n];
1241 		*(uint16_t *)p = htons(update->x);	p += 2;
1242 		*(uint16_t *)p = htons(update->y);	p += 2;
1243 		*(uint16_t *)p = htons(update->w);	p += 2;
1244 		*(uint16_t *)p = htons(update->h);	p += 2;
1245 		*(uint32_t *)p = htonl(update->enc);	p += 4;	/* encoding */
1246 
1247 #ifdef RFB_DEBUG
1248 		fprintf(stdout, "rfb: [%u] enc %d, [%d, %d] - [%d, %d]",
1249 		    n, update->enc, update->x, update->y, update->w, update->h);
1250 		if (update->enc == THUNK_RFB_TYPE_COPYRECT)
1251 			fprintf(stdout, " from [%d, %d]",
1252 			    update->srcx, update->srcy);
1253 		if (update->enc == THUNK_RFB_TYPE_RRE)
1254 			fprintf(stdout, " pixel [%02x %02x %02x %02x]",
1255 			    update->pixel[0], update->pixel[1],
1256 			    update->pixel[2], update->pixel[3]);
1257 		fprintf(stdout, "\n");
1258 #endif
1259 
1260 		len = safe_send(rfb->clientfd, buf, 12);
1261 		if (len == -1)
1262 			goto disco;
1263 
1264 		if (update->enc == THUNK_RFB_TYPE_COPYRECT) {
1265 			p = buf;
1266 			*(uint16_t *)p = htons(update->srcx);	p += 2;
1267 			*(uint16_t *)p = htons(update->srcy);	p += 2;
1268 			len = safe_send(rfb->clientfd, buf, 4);
1269 			if (len == -1)
1270 				goto disco;
1271 		}
1272 
1273 		if (update->enc == THUNK_RFB_TYPE_RRE) {
1274 			p = buf;
1275 
1276 			/* header */
1277 			*(uint32_t *)p = htonl(1);		p += 4;
1278 			memcpy(p, update->pixel, 4);		p += 4;
1279 			/* subrectangle */
1280 			memcpy(p, update->pixel, 4);		p += 4;
1281 			*(uint16_t *)p = htons(update->x);	p += 2;
1282 			*(uint16_t *)p = htons(update->y);	p += 2;
1283 			*(uint16_t *)p = htons(update->w);	p += 2;
1284 			*(uint16_t *)p = htons(update->h);	p += 2;
1285 			/* send it */
1286 			len = safe_send(rfb->clientfd, buf, 20);
1287 			if (len == -1)
1288 				goto disco;
1289 		}
1290 
1291 		if (update->enc == THUNK_RFB_TYPE_RAW) {
1292 			p = rfb->framebuf + (update->y * stride)
1293 				+ (update->x * bytes_per_pixel);
1294 			line_len = update->w * bytes_per_pixel;
1295 			while (update->h-- > 0) {
1296 				len = safe_send(rfb->clientfd, p, line_len);
1297 				if (len == -1)
1298 					goto disco;
1299 				p += stride;
1300 			}
1301 		}
1302 	}
1303 
1304 	rfb->nupdates = 0;
1305 	rfb->first_mergable = 0;
1306 
1307 	return;
1308 
1309 disco:
1310 	fprintf(stdout, "rfb: client disconnected: %s\n", strerror(errno));
1311 	close(rfb->clientfd);
1312 	rfb->clientfd = -1;
1313 	rfb->connected = false;
1314 }
1315 
1316 int
thunk_rfb_poll(thunk_rfb_t * rfb,thunk_rfb_event_t * event)1317 thunk_rfb_poll(thunk_rfb_t *rfb, thunk_rfb_event_t *event)
1318 {
1319 	int error, len, msg_len;
1320 	uint8_t set_pixel_format[19];
1321 	uint8_t set_encodings[3];
1322 	uint8_t framebuffer_update_request[9];
1323 	uint8_t key_event[7];
1324 	uint8_t pointer_event[5];
1325 	uint8_t client_cut_text[7];
1326 	uint8_t ch;
1327 
1328 	if (rfb->clientfd == -1) {
1329 		struct sockaddr_in sin;
1330 		struct pollfd fds[1];
1331 		socklen_t sinlen;
1332 		int flags;
1333 
1334 #ifdef RFB_DEBUG
1335 		fprintf(stdout, "rfb: poll connection\n");
1336 #endif
1337 
1338 		/* poll for connections */
1339 		fds[0].fd = rfb->sockfd;
1340 		fds[0].events = POLLIN;
1341 		fds[0].revents = 0;
1342 		if (poll(fds, __arraycount(fds), 0) != 1) {
1343 #ifdef RFB_DEBUG
1344 			fprintf(stdout, "rfb: NO connection\n");
1345 #endif
1346 			return -1;
1347 		}
1348 
1349 #ifdef RFB_DEBUG
1350 		fprintf(stdout, "rfb: try accept\n");
1351 #endif
1352 
1353 		sinlen = sizeof(sin);
1354 		rfb->clientfd = accept(rfb->sockfd, (struct sockaddr *)&sin,
1355 		    &sinlen);
1356 		if (rfb->clientfd == -1)
1357 			return -1;
1358 
1359 		fprintf(stdout, "rfb: connection from %s:%d\n",
1360 		    inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
1361 
1362 		/* rfb handshake */
1363 		if (thunk_rfb_handshake(rfb) != 0) {
1364 			fprintf(stdout, "rfb: handshake failed\n");
1365 			close(rfb->clientfd);
1366 			rfb->clientfd = -1;
1367 			return -1;
1368 		}
1369 
1370 		rfb->connected = true;
1371 
1372 		/* enable sigio on input */
1373 		flags = fcntl(rfb->clientfd, F_GETFL, 0);
1374 		fcntl(rfb->clientfd, F_SETFL, flags | O_ASYNC);
1375 		error = fcntl(rfb->clientfd, F_SETOWN, getpid());
1376 		if (error) {
1377 			fprintf(stdout, "rfb: setown failed: %s\n",
1378 			    strerror(errno));
1379 			close(rfb->clientfd);
1380 			rfb->clientfd = -1;
1381 			return -1;
1382 		}
1383 
1384 		rfb->schedule_bell = false;
1385 		rfb->nupdates = 0;
1386 		rfb->first_mergable = 0;
1387 		thunk_rfb_update(rfb, 0, 0, rfb->width, rfb->height);
1388 	}
1389 
1390 	thunk_rfb_send_pending(rfb);
1391 
1392 	if (rfb->clientfd == -1)
1393 		return -1;
1394 
1395 	if (event == NULL)
1396 		return 0;
1397 
1398 	if (rfb->schedule_bell) {
1399 		uint8_t msg_type = 2;	/* bell */
1400 		safe_send(rfb->clientfd, &msg_type, sizeof(msg_type));
1401 		rfb->schedule_bell = false;
1402 	}
1403 
1404 	error = ioctl(rfb->clientfd, FIONREAD, &len);
1405 	if (error == -1)
1406 		goto discon;
1407 	if (len == 0)
1408 		return 0;
1409 
1410 	len = safe_recv(rfb->clientfd, &ch, sizeof(ch));
1411 	if (len == -1)
1412 		goto discon;
1413 
1414 	event->message_type = ch;
1415 	switch (ch) {
1416 	case THUNK_RFB_SET_PIXEL_FORMAT:
1417 		msg_len = sizeof(set_pixel_format);
1418 		break;
1419 	case THUNK_RFB_SET_ENCODINGS:
1420 		len = safe_recv(rfb->clientfd,
1421 			set_encodings, sizeof(set_encodings));
1422 		if (len == -1)
1423 			goto discon;
1424 		msg_len = 4 * ntohs(*(uint16_t *)&set_encodings[1]);
1425 		break;
1426 	case THUNK_RFB_FRAMEBUFFER_UPDATE_REQUEST:
1427 		len = safe_recv(rfb->clientfd,
1428 			framebuffer_update_request,
1429 			sizeof(framebuffer_update_request));
1430 		if (len == -1)
1431 			goto discon;
1432 #ifdef RFB_DEBUG
1433 		fprintf(stdout, "framebuffer update request: ");
1434 		fprintf(stdout, "[%d, %d] + [%d, %d] %s\n",
1435 			framebuffer_update_request[1],
1436 			framebuffer_update_request[2],
1437 			framebuffer_update_request[3],
1438 			framebuffer_update_request[4],
1439 			framebuffer_update_request[0]?"Incrmental":"Complete");
1440 #endif
1441 
1442 		if (framebuffer_update_request[0] == 0) {
1443 			/* complete redraw request -> buffer full */
1444 			rfb->nupdates = __arraycount(rfb->update) + 1;
1445 		}
1446 //		thunk_rfb_send_pending(rfb);
1447 		msg_len = 0;
1448 		break;
1449 	case THUNK_RFB_KEY_EVENT:
1450 		len = safe_recv(rfb->clientfd, key_event, sizeof(key_event));
1451 		if (len == -1)
1452 			goto discon;
1453 		event->data.key_event.down_flag = key_event[0];
1454 		event->data.key_event.keysym =
1455 		    ntohl(*(uint32_t *)&key_event[3]);
1456 #ifdef RFB_DEBUG
1457 		fprintf(stdout, "rfb: key %04x %s\n",
1458 		    event->data.key_event.keysym,
1459 		    event->data.key_event.down_flag ? "pressed" : "released");
1460 #endif
1461 		msg_len = 0;
1462 		break;
1463 	case THUNK_RFB_POINTER_EVENT:
1464 		len = safe_recv(rfb->clientfd,
1465 			pointer_event, sizeof(pointer_event));
1466 		if (len == -1)
1467 			goto discon;
1468 		event->data.pointer_event.button_mask = pointer_event[0];
1469 		event->data.pointer_event.absx =
1470 		    ntohs(*(uint16_t *)&pointer_event[1]);
1471 		event->data.pointer_event.absy =
1472 		    ntohs(*(uint16_t *)&pointer_event[3]);
1473 #ifdef RFB_DEBUG
1474 		fprintf(stdout, "rfb: pointer mask %02x abs %dx%d\n",
1475 		    event->data.pointer_event.button_mask,
1476 		    event->data.pointer_event.absx,
1477 		    event->data.pointer_event.absy);
1478 #endif
1479 		msg_len = 0;
1480 		break;
1481 	case THUNK_RFB_CLIENT_CUT_TEXT:
1482 		len = safe_recv(rfb->clientfd,
1483 			client_cut_text, sizeof(client_cut_text));
1484 		if (len == -1)
1485 			goto discon;
1486 		msg_len = ntohl(*(uint32_t *)&client_cut_text[3]);
1487 		break;
1488 	default:
1489 		fprintf(stdout, "rfb: unknown message type %d\n", ch);
1490 		goto discon;
1491 	}
1492 
1493 	if (len == -1)
1494 		goto discon;
1495 
1496 	/* discard any remaining bytes */
1497 	while (msg_len-- > 0) {
1498 		len = safe_recv(rfb->clientfd, &ch, sizeof(ch));
1499 		if (len == -1)
1500 			goto discon;
1501 	}
1502 
1503 	return 1;
1504 
1505 discon:
1506 	//printf("rfb: safe_recv failed: %s\n", strerror(errno));
1507 	close(rfb->clientfd);
1508 	rfb->clientfd = -1;
1509 
1510 	return -1;
1511 }
1512 
1513 void
thunk_rfb_update(thunk_rfb_t * rfb,int x,int y,int w,int h)1514 thunk_rfb_update(thunk_rfb_t *rfb, int x, int y, int w, int h)
1515 {
1516 	thunk_rfb_update_t *update = NULL;
1517 	unsigned int n;
1518 
1519 	/* if the queue is full, just return */
1520 	if (rfb->nupdates >= __arraycount(rfb->update))
1521 		return;
1522 
1523 	/* no sense in queueing duplicate updates */
1524 	for (n = rfb->first_mergable; n < rfb->nupdates; n++) {
1525 		if (rfb->update[n].x == x && rfb->update[n].y == y &&
1526 		    rfb->update[n].w == w && rfb->update[n].h == h)
1527 			return;
1528 	}
1529 
1530 #ifdef RFB_DEBUG
1531 	fprintf(stdout, "rfb: update queue slot %d, x=%d y=%d w=%d h=%d\n",
1532 	    rfb->nupdates, x, y, w, h);
1533 #endif
1534 
1535 	/* add the update request to the queue */
1536 	update = &rfb->update[rfb->nupdates++];
1537 	update->enc = THUNK_RFB_TYPE_RAW;
1538 	update->x = x;
1539 	update->y = y;
1540 	update->w = w;
1541 	update->h = h;
1542 }
1543 
1544 void
thunk_rfb_bell(thunk_rfb_t * rfb)1545 thunk_rfb_bell(thunk_rfb_t *rfb)
1546 {
1547 #ifdef RFB_DEBUG
1548 	fprintf(stdout, "rfb: schedule bell\n");
1549 #endif
1550 	rfb->schedule_bell = true;
1551 }
1552 
1553 void
thunk_rfb_copyrect(thunk_rfb_t * rfb,int x,int y,int w,int h,int srcx,int srcy)1554 thunk_rfb_copyrect(thunk_rfb_t *rfb, int x, int y, int w, int h,
1555 	int srcx, int srcy)
1556 {
1557 	thunk_rfb_update_t *update = NULL;
1558 
1559 	/* if the queue is full, just return */
1560 	if (rfb->nupdates >= __arraycount(rfb->update))
1561 		return;
1562 
1563 #ifdef RFB_DEBUG
1564 	fprintf(stdout, "rfb: copyrect queue slot %d, x=%d y=%d w=%d h=%d\n",
1565 	    rfb->nupdates, x, y, w, h);
1566 #endif
1567 
1568 	/* add the update request to the queue */
1569 	update = &rfb->update[rfb->nupdates++];
1570 	update->enc = THUNK_RFB_TYPE_COPYRECT;
1571 	update->x = x;
1572 	update->y = y;
1573 	update->w = w;
1574 	update->h = h;
1575 	update->srcx = srcx;
1576 	update->srcy = srcy;
1577 
1578 	rfb->first_mergable = rfb->nupdates;
1579 }
1580 
1581 void
thunk_rfb_fillrect(thunk_rfb_t * rfb,int x,int y,int w,int h,uint8_t * pixel)1582 thunk_rfb_fillrect(thunk_rfb_t *rfb, int x, int y, int w, int h, uint8_t *pixel)
1583 {
1584 	thunk_rfb_update_t *update = NULL;
1585 
1586 	/* if the queue is full, just return */
1587 	if (rfb->nupdates >= __arraycount(rfb->update))
1588 		return;
1589 
1590 #ifdef RFB_DEBUG
1591 	fprintf(stdout, "rfb: fillrect queue slot %d, x=%d y=%d w=%d h=%d\n",
1592 	    rfb->nupdates, x, y, w, h);
1593 #endif
1594 
1595 	/* add the update request to the queue */
1596 	update = &rfb->update[rfb->nupdates++];
1597 	update->enc = THUNK_RFB_TYPE_RRE;
1598 	update->x = x;
1599 	update->y = y;
1600 	update->w = w;
1601 	update->h = h;
1602 	memcpy(update->pixel, pixel, 4);
1603 
1604 	rfb->first_mergable = rfb->nupdates;
1605 }
1606