1 /* $NetBSD: thunk.c,v 1.93 2024/03/17 21:48:01 andvar 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.93 2024/03/17 21:48:01 andvar 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]?"Incremental":"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