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 95static ssize_t safe_recv(int s, void *buf, int len); 96static ssize_t safe_send(int s, const void *msg, int len); 97 98extern int boothowto; 99 100void 101thunk_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 112void 113thunk_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 123int 124thunk_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 138static void 139thunk_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 145static void 146thunk_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 152static void 153thunk_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 159static void 160thunk_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 166static void 167thunk_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 181static void 182thunk_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 196static int 197thunk_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 211static int 212thunk_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 230static int 231thunk_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 251int 252thunk_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 268int 269thunk_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 283unsigned int 284thunk_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 298long 299thunk_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 311timer_t 312thunk_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 326int 327thunk_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 338int 339thunk_timer_getoverrun(timer_t timerid) 340{ 341 return timer_getoverrun(timerid); 342} 343 344int 345thunk_usleep(useconds_t microseconds) 346{ 347 return usleep(microseconds); 348} 349 350void 351thunk_kill(pid_t pid, int sig) 352{ 353 kill(pid, sig); 354} 355 356void 357thunk_exit(int status) 358{ 359 return exit(status); 360} 361 362void 363thunk_abort(void) 364{ 365 abort(); 366} 367 368int 369thunk_geterrno(void) 370{ 371 return errno; 372} 373 374void 375thunk_seterrno(int nerrno) 376{ 377 errno = nerrno; 378} 379 380int 381thunk_getcontext(ucontext_t *ucp) 382{ 383 return getcontext(ucp); 384} 385 386int 387thunk_setcontext(const ucontext_t *ucp) 388{ 389 return setcontext(ucp); 390} 391 392void 393thunk_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 418int 419thunk_swapcontext(ucontext_t *oucp, ucontext_t *ucp) 420{ 421 return swapcontext(oucp, ucp); 422} 423 424int 425thunk_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 437int 438thunk_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 446int 447thunk_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 461int 462thunk_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 482int 483thunk_getchar(void) 484{ 485 return getchar(); 486} 487 488void 489thunk_putchar(int c) 490{ 491 char wc = (char) c; 492 write(1, &wc, 1); 493} 494 495int 496thunk_execv(const char *path, char * const argv[]) 497{ 498 return execv(path, argv); 499} 500 501int 502thunk_open(const char *path, int flags, mode_t mode) 503{ 504 return open(path, flags, mode); 505} 506 507int 508thunk_close(int fd) 509{ 510 return close(fd); 511} 512 513int 514thunk_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 531ssize_t 532thunk_pread(int d, void *buf, size_t nbytes, off_t offset) 533{ 534 return pread(d, buf, nbytes, offset); 535} 536 537ssize_t 538thunk_pwrite(int d, const void *buf, size_t nbytes, off_t offset) 539{ 540 return pwrite(d, buf, nbytes, offset); 541} 542 543ssize_t 544thunk_read(int d, void *buf, size_t nbytes) 545{ 546 return read(d, buf, nbytes); 547} 548 549ssize_t 550thunk_write(int d, const void *buf, size_t nbytes) 551{ 552 return write(d, buf, nbytes); 553} 554 555int 556thunk_fsync(int fd) 557{ 558 return fsync(fd); 559} 560 561int 562thunk_mkstemp(char *template) 563{ 564 return mkstemp(template); 565} 566 567int 568thunk_unlink(const char *path) 569{ 570 return unlink(path); 571} 572 573pid_t 574thunk_getpid(void) 575{ 576 return getpid(); 577} 578 579int 580thunk_sigaction(int sig, const struct sigaction *act, struct sigaction *oact) 581{ 582 return sigaction(sig, act, oact); 583} 584 585int 586thunk_sigaltstack(const stack_t *ss, stack_t *oss) 587{ 588 return sigaltstack(ss, oss); 589} 590 591void 592thunk_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 602int 603thunk_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 612int 613thunk_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 622int 623thunk_sigemptyset(sigset_t *sa_mask) 624{ 625 return sigemptyset(sa_mask); 626} 627 628 629int 630thunk_sigfillset(sigset_t *sa_mask) 631{ 632 return sigfillset(sa_mask); 633} 634 635 636void 637thunk_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 647int 648thunk_sigprocmask(int how, const sigset_t * set, sigset_t *oset) 649{ 650 return sigprocmask(how, set, oset); 651} 652 653int 654thunk_atexit(void (*function)(void)) 655{ 656 return atexit(function); 657} 658 659pid_t 660thunk_fork(void) 661{ 662 return fork(); 663} 664 665int 666thunk_ioctl(int fd, unsigned long request, void *opaque) 667{ 668 return ioctl(fd, request, opaque); 669} 670 671int 672thunk_aio_read(struct aiocb *aiocbp) 673{ 674 return aio_read(aiocbp); 675} 676 677int 678thunk_aio_write(struct aiocb *aiocbp) 679{ 680 return aio_write(aiocbp); 681} 682 683int 684thunk_aio_error(const struct aiocb *aiocbp) 685{ 686 return aio_error(aiocbp); 687} 688 689int 690thunk_aio_return(struct aiocb *aiocbp) 691{ 692 return aio_return(aiocbp); 693} 694 695void * 696thunk_malloc(size_t len) 697{ 698 return malloc(len); 699} 700 701void 702thunk_free(void *addr) 703{ 704 free(addr); 705} 706 707void * 708thunk_sbrk(intptr_t len) 709{ 710 return sbrk(len); 711} 712 713void * 714thunk_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 728int 729thunk_munmap(void *addr, size_t len) 730{ 731 return munmap(addr, len); 732} 733 734int 735thunk_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 744int 745thunk_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 754int 755thunk_posix_memalign(void **ptr, size_t alignment, size_t size) 756{ 757 return posix_memalign(ptr, alignment, size); 758} 759 760char * 761thunk_getenv(const char *name) 762{ 763 return getenv(name); 764} 765 766vaddr_t 767thunk_get_vm_min_address(void) 768{ 769 return VM_MIN_ADDRESS; 770} 771 772int 773thunk_idle(void) 774{ 775 sigset_t sigmask; 776 777 sigemptyset(&sigmask); 778 779 return sigsuspend(&sigmask); 780} 781 782int 783thunk_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; 800out: 801 *len = 0; 802 return -1; 803} 804 805int 806thunk_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 828int 829thunk_setown(int fd) 830{ 831 return fcntl(fd, F_SETOWN, getpid()); 832} 833 834int 835thunk_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 853int 854thunk_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 875int 876thunk_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 */ 889int 890thunk_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 902int 903thunk_audio_open(const char *path) 904{ 905 return open(path, O_RDWR); 906} 907 908int 909thunk_audio_close(int fd) 910{ 911 return close(fd); 912} 913 914int 915thunk_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 939int 940thunk_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 953int 954thunk_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 967ssize_t 968thunk_audio_write(int fd, const void *buf, size_t buflen) 969{ 970 return write(fd, buf, buflen); 971} 972 973ssize_t 974thunk_audio_read(int fd, void *buf, size_t buflen) 975{ 976 return read(fd, buf, buflen); 977} 978 979int 980thunk_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 1017int 1018thunk_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 1054int 1055thunk_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 1077int 1078thunk_kgdb_getc(int fd, char *ch) 1079{ 1080 return safe_recv(fd, ch, 1); 1081} 1082 1083int 1084thunk_kgdb_putc(int fd, char ch) 1085{ 1086 return safe_send(fd, &ch, 1); 1087} 1088 1089static ssize_t 1090safe_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 1111static ssize_t 1112safe_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 1132static ssize_t 1133thunk_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 1160static int 1161thunk_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 1200static void 1201thunk_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 1309disco: 1310 fprintf(stdout, "rfb: client disconnected: %s\n", strerror(errno)); 1311 close(rfb->clientfd); 1312 rfb->clientfd = -1; 1313 rfb->connected = false; 1314} 1315 1316int 1317thunk_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 1505discon: 1506 //printf("rfb: safe_recv failed: %s\n", strerror(errno)); 1507 close(rfb->clientfd); 1508 rfb->clientfd = -1; 1509 1510 return -1; 1511} 1512 1513void 1514thunk_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 1544void 1545thunk_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 1553void 1554thunk_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 1581void 1582thunk_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