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