1bf21cd93STycho Nightingale /*- 24c87aefeSPatrick Mooney * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 34c87aefeSPatrick Mooney * 4bf21cd93STycho Nightingale * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com> 54c87aefeSPatrick Mooney * Copyright (c) 2015 Leon Dang 64c87aefeSPatrick Mooney * Copyright 2018 Joyent, Inc. 7bf21cd93STycho Nightingale * All rights reserved. 8bf21cd93STycho Nightingale * 9bf21cd93STycho Nightingale * Redistribution and use in source and binary forms, with or without 10bf21cd93STycho Nightingale * modification, are permitted provided that the following conditions 11bf21cd93STycho Nightingale * are met: 12bf21cd93STycho Nightingale * 1. Redistributions of source code must retain the above copyright 13bf21cd93STycho Nightingale * notice, this list of conditions and the following disclaimer. 14bf21cd93STycho Nightingale * 2. Redistributions in binary form must reproduce the above copyright 15bf21cd93STycho Nightingale * notice, this list of conditions and the following disclaimer in the 16bf21cd93STycho Nightingale * documentation and/or other materials provided with the distribution. 17bf21cd93STycho Nightingale * 18bf21cd93STycho Nightingale * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 19bf21cd93STycho Nightingale * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20bf21cd93STycho Nightingale * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21bf21cd93STycho Nightingale * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22bf21cd93STycho Nightingale * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23bf21cd93STycho Nightingale * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24bf21cd93STycho Nightingale * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25bf21cd93STycho Nightingale * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26bf21cd93STycho Nightingale * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27bf21cd93STycho Nightingale * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28bf21cd93STycho Nightingale * SUCH DAMAGE. 29bf21cd93STycho Nightingale */ 30bf21cd93STycho Nightingale 31bf21cd93STycho Nightingale #include <sys/cdefs.h> 32bf21cd93STycho Nightingale __FBSDID("$FreeBSD$"); 33bf21cd93STycho Nightingale 344c87aefeSPatrick Mooney #include <sys/param.h> 354c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 364c87aefeSPatrick Mooney #include <sys/capsicum.h> 374c87aefeSPatrick Mooney #endif 384c87aefeSPatrick Mooney #include <sys/endian.h> 39bf21cd93STycho Nightingale #include <sys/socket.h> 404c87aefeSPatrick Mooney #include <sys/select.h> 414c87aefeSPatrick Mooney #include <sys/time.h> 424c87aefeSPatrick Mooney #include <arpa/inet.h> 43*dc8050e8SMarko Kiiskila #include <stdatomic.h> 444c87aefeSPatrick Mooney #include <machine/cpufunc.h> 454c87aefeSPatrick Mooney #include <machine/specialreg.h> 46bf21cd93STycho Nightingale #include <netinet/in.h> 474c87aefeSPatrick Mooney #include <netdb.h> 48bf21cd93STycho Nightingale 49bf21cd93STycho Nightingale #include <assert.h> 504c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 514c87aefeSPatrick Mooney #include <capsicum_helpers.h> 524c87aefeSPatrick Mooney #endif 534c87aefeSPatrick Mooney #include <err.h> 544c87aefeSPatrick Mooney #include <errno.h> 55bf21cd93STycho Nightingale #include <pthread.h> 564c87aefeSPatrick Mooney #include <pthread_np.h> 57bf21cd93STycho Nightingale #include <signal.h> 58bf21cd93STycho Nightingale #include <stdbool.h> 59bf21cd93STycho Nightingale #include <stdlib.h> 60bf21cd93STycho Nightingale #include <stdio.h> 61bf21cd93STycho Nightingale #include <string.h> 624c87aefeSPatrick Mooney #include <sysexits.h> 63bf21cd93STycho Nightingale #include <unistd.h> 64bf21cd93STycho Nightingale 654c87aefeSPatrick Mooney #include <zlib.h> 664c87aefeSPatrick Mooney 674c87aefeSPatrick Mooney #ifndef __FreeBSD__ 684c87aefeSPatrick Mooney #include <sys/debug.h> 694c87aefeSPatrick Mooney #endif 704c87aefeSPatrick Mooney 71bf21cd93STycho Nightingale #include "bhyvegc.h" 72154972afSPatrick Mooney #include "debug.h" 73bf21cd93STycho Nightingale #include "console.h" 74bf21cd93STycho Nightingale #include "rfb.h" 754c87aefeSPatrick Mooney #include "sockstream.h" 764c87aefeSPatrick Mooney 774c87aefeSPatrick Mooney #ifndef NO_OPENSSL 784c87aefeSPatrick Mooney #include <openssl/des.h> 794c87aefeSPatrick Mooney #endif 804c87aefeSPatrick Mooney 81*dc8050e8SMarko Kiiskila /* Delays in microseconds */ 82*dc8050e8SMarko Kiiskila #define CFD_SEL_DELAY 10000 83*dc8050e8SMarko Kiiskila #define SCREEN_REFRESH_DELAY 33300 /* 30Hz */ 84*dc8050e8SMarko Kiiskila #define SCREEN_POLL_DELAY (SCREEN_REFRESH_DELAY / 2) 85*dc8050e8SMarko Kiiskila 864c87aefeSPatrick Mooney static int rfb_debug = 0; 87154972afSPatrick Mooney #define DPRINTF(params) if (rfb_debug) PRINTLN params 88154972afSPatrick Mooney #define WPRINTF(params) PRINTLN params 894c87aefeSPatrick Mooney 90154972afSPatrick Mooney #define VERSION_LENGTH 12 914c87aefeSPatrick Mooney #define AUTH_LENGTH 16 924c87aefeSPatrick Mooney #define PASSWD_LENGTH 8 934c87aefeSPatrick Mooney 94*dc8050e8SMarko Kiiskila /* Protocol versions */ 95*dc8050e8SMarko Kiiskila #define CVERS_3_3 '3' 96*dc8050e8SMarko Kiiskila #define CVERS_3_7 '7' 97*dc8050e8SMarko Kiiskila #define CVERS_3_8 '8' 98*dc8050e8SMarko Kiiskila 99*dc8050e8SMarko Kiiskila /* Client-to-server msg types */ 100*dc8050e8SMarko Kiiskila #define CS_SET_PIXEL_FORMAT 0 101*dc8050e8SMarko Kiiskila #define CS_SET_ENCODINGS 2 102*dc8050e8SMarko Kiiskila #define CS_UPDATE_MSG 3 103*dc8050e8SMarko Kiiskila #define CS_KEY_EVENT 4 104*dc8050e8SMarko Kiiskila #define CS_POINTER_EVENT 5 105*dc8050e8SMarko Kiiskila #define CS_CUT_TEXT 6 106*dc8050e8SMarko Kiiskila 1074c87aefeSPatrick Mooney #define SECURITY_TYPE_NONE 1 1084c87aefeSPatrick Mooney #define SECURITY_TYPE_VNC_AUTH 2 1094c87aefeSPatrick Mooney 1104c87aefeSPatrick Mooney #define AUTH_FAILED_UNAUTH 1 1114c87aefeSPatrick Mooney #define AUTH_FAILED_ERROR 2 112bf21cd93STycho Nightingale 113bf21cd93STycho Nightingale struct rfb_softc { 114bf21cd93STycho Nightingale int sfd; 115bf21cd93STycho Nightingale pthread_t tid; 116bf21cd93STycho Nightingale 1174c87aefeSPatrick Mooney int cfd; 1184c87aefeSPatrick Mooney 119bf21cd93STycho Nightingale int width, height; 120bf21cd93STycho Nightingale 1214c87aefeSPatrick Mooney char *password; 1224c87aefeSPatrick Mooney 123*dc8050e8SMarko Kiiskila bool enc_raw_ok; 124*dc8050e8SMarko Kiiskila bool enc_zlib_ok; 125*dc8050e8SMarko Kiiskila bool enc_resize_ok; 1264c87aefeSPatrick Mooney 1274c87aefeSPatrick Mooney z_stream zstream; 1284c87aefeSPatrick Mooney uint8_t *zbuf; 1294c87aefeSPatrick Mooney int zbuflen; 1304c87aefeSPatrick Mooney 1314c87aefeSPatrick Mooney int conn_wait; 132*dc8050e8SMarko Kiiskila int wrcount; 133*dc8050e8SMarko Kiiskila 134*dc8050e8SMarko Kiiskila atomic_bool sending; 135*dc8050e8SMarko Kiiskila atomic_bool pending; 136*dc8050e8SMarko Kiiskila atomic_bool update_all; 137*dc8050e8SMarko Kiiskila atomic_bool input_detected; 138*dc8050e8SMarko Kiiskila 1394c87aefeSPatrick Mooney pthread_mutex_t mtx; 1404c87aefeSPatrick Mooney pthread_cond_t cond; 1414c87aefeSPatrick Mooney 1424c87aefeSPatrick Mooney int hw_crc; 1434c87aefeSPatrick Mooney uint32_t *crc; /* WxH crc cells */ 1444c87aefeSPatrick Mooney uint32_t *crc_tmp; /* buffer to store single crc row */ 1454c87aefeSPatrick Mooney int crc_width, crc_height; 146bf21cd93STycho Nightingale }; 147bf21cd93STycho Nightingale 148bf21cd93STycho Nightingale struct rfb_pixfmt { 149bf21cd93STycho Nightingale uint8_t bpp; 150bf21cd93STycho Nightingale uint8_t depth; 151bf21cd93STycho Nightingale uint8_t bigendian; 152bf21cd93STycho Nightingale uint8_t truecolor; 153bf21cd93STycho Nightingale uint16_t red_max; 154bf21cd93STycho Nightingale uint16_t green_max; 155bf21cd93STycho Nightingale uint16_t blue_max; 156bf21cd93STycho Nightingale uint8_t red_shift; 157bf21cd93STycho Nightingale uint8_t green_shift; 158bf21cd93STycho Nightingale uint8_t blue_shift; 159bf21cd93STycho Nightingale uint8_t pad[3]; 160bf21cd93STycho Nightingale }; 161bf21cd93STycho Nightingale 162bf21cd93STycho Nightingale struct rfb_srvr_info { 163bf21cd93STycho Nightingale uint16_t width; 164bf21cd93STycho Nightingale uint16_t height; 165bf21cd93STycho Nightingale struct rfb_pixfmt pixfmt; 166bf21cd93STycho Nightingale uint32_t namelen; 167bf21cd93STycho Nightingale }; 168bf21cd93STycho Nightingale 169bf21cd93STycho Nightingale struct rfb_pixfmt_msg { 170bf21cd93STycho Nightingale uint8_t type; 171bf21cd93STycho Nightingale uint8_t pad[3]; 172bf21cd93STycho Nightingale struct rfb_pixfmt pixfmt; 173bf21cd93STycho Nightingale }; 174bf21cd93STycho Nightingale 175bf21cd93STycho Nightingale #define RFB_ENCODING_RAW 0 1764c87aefeSPatrick Mooney #define RFB_ENCODING_ZLIB 6 177bf21cd93STycho Nightingale #define RFB_ENCODING_RESIZE -223 178bf21cd93STycho Nightingale 1794c87aefeSPatrick Mooney #define RFB_MAX_WIDTH 2000 1804c87aefeSPatrick Mooney #define RFB_MAX_HEIGHT 1200 1814c87aefeSPatrick Mooney #define RFB_ZLIB_BUFSZ RFB_MAX_WIDTH*RFB_MAX_HEIGHT*4 1824c87aefeSPatrick Mooney 1834c87aefeSPatrick Mooney /* percentage changes to screen before sending the entire screen */ 1844c87aefeSPatrick Mooney #define RFB_SEND_ALL_THRESH 25 1854c87aefeSPatrick Mooney 186bf21cd93STycho Nightingale struct rfb_enc_msg { 187bf21cd93STycho Nightingale uint8_t type; 188bf21cd93STycho Nightingale uint8_t pad; 189bf21cd93STycho Nightingale uint16_t numencs; 190bf21cd93STycho Nightingale }; 191bf21cd93STycho Nightingale 192bf21cd93STycho Nightingale struct rfb_updt_msg { 193bf21cd93STycho Nightingale uint8_t type; 194bf21cd93STycho Nightingale uint8_t incremental; 195bf21cd93STycho Nightingale uint16_t x; 196bf21cd93STycho Nightingale uint16_t y; 197bf21cd93STycho Nightingale uint16_t width; 198bf21cd93STycho Nightingale uint16_t height; 199bf21cd93STycho Nightingale }; 200bf21cd93STycho Nightingale 201bf21cd93STycho Nightingale struct rfb_key_msg { 202bf21cd93STycho Nightingale uint8_t type; 203bf21cd93STycho Nightingale uint8_t down; 204bf21cd93STycho Nightingale uint16_t pad; 205bf21cd93STycho Nightingale uint32_t code; 206bf21cd93STycho Nightingale }; 207bf21cd93STycho Nightingale 208bf21cd93STycho Nightingale struct rfb_ptr_msg { 209bf21cd93STycho Nightingale uint8_t type; 210bf21cd93STycho Nightingale uint8_t button; 211bf21cd93STycho Nightingale uint16_t x; 212bf21cd93STycho Nightingale uint16_t y; 213bf21cd93STycho Nightingale }; 214bf21cd93STycho Nightingale 215bf21cd93STycho Nightingale struct rfb_srvr_updt_msg { 216bf21cd93STycho Nightingale uint8_t type; 217bf21cd93STycho Nightingale uint8_t pad; 218bf21cd93STycho Nightingale uint16_t numrects; 219bf21cd93STycho Nightingale }; 220bf21cd93STycho Nightingale 221bf21cd93STycho Nightingale struct rfb_srvr_rect_hdr { 222bf21cd93STycho Nightingale uint16_t x; 223bf21cd93STycho Nightingale uint16_t y; 224bf21cd93STycho Nightingale uint16_t width; 225bf21cd93STycho Nightingale uint16_t height; 226bf21cd93STycho Nightingale uint32_t encoding; 227bf21cd93STycho Nightingale }; 228bf21cd93STycho Nightingale 2294c87aefeSPatrick Mooney struct rfb_cuttext_msg { 2304c87aefeSPatrick Mooney uint8_t type; 2314c87aefeSPatrick Mooney uint8_t padding[3]; 2324c87aefeSPatrick Mooney uint32_t length; 2334c87aefeSPatrick Mooney }; 2344c87aefeSPatrick Mooney 235bf21cd93STycho Nightingale static void 236bf21cd93STycho Nightingale rfb_send_server_init_msg(int cfd) 237bf21cd93STycho Nightingale { 238bf21cd93STycho Nightingale struct bhyvegc_image *gc_image; 239bf21cd93STycho Nightingale struct rfb_srvr_info sinfo; 240bf21cd93STycho Nightingale 241bf21cd93STycho Nightingale gc_image = console_get_image(); 242bf21cd93STycho Nightingale 2434c87aefeSPatrick Mooney sinfo.width = htons(gc_image->width); 2444c87aefeSPatrick Mooney sinfo.height = htons(gc_image->height); 245bf21cd93STycho Nightingale sinfo.pixfmt.bpp = 32; 246bf21cd93STycho Nightingale sinfo.pixfmt.depth = 32; 247bf21cd93STycho Nightingale sinfo.pixfmt.bigendian = 0; 248bf21cd93STycho Nightingale sinfo.pixfmt.truecolor = 1; 2494c87aefeSPatrick Mooney sinfo.pixfmt.red_max = htons(255); 2504c87aefeSPatrick Mooney sinfo.pixfmt.green_max = htons(255); 2514c87aefeSPatrick Mooney sinfo.pixfmt.blue_max = htons(255); 252bf21cd93STycho Nightingale sinfo.pixfmt.red_shift = 16; 253bf21cd93STycho Nightingale sinfo.pixfmt.green_shift = 8; 254bf21cd93STycho Nightingale sinfo.pixfmt.blue_shift = 0; 255*dc8050e8SMarko Kiiskila sinfo.pixfmt.pad[0] = 0; 256*dc8050e8SMarko Kiiskila sinfo.pixfmt.pad[1] = 0; 257*dc8050e8SMarko Kiiskila sinfo.pixfmt.pad[2] = 0; 2584c87aefeSPatrick Mooney sinfo.namelen = htonl(strlen("bhyve")); 2594c87aefeSPatrick Mooney (void)stream_write(cfd, &sinfo, sizeof(sinfo)); 2604c87aefeSPatrick Mooney (void)stream_write(cfd, "bhyve", strlen("bhyve")); 261bf21cd93STycho Nightingale } 262bf21cd93STycho Nightingale 263bf21cd93STycho Nightingale static void 264bf21cd93STycho Nightingale rfb_send_resize_update_msg(struct rfb_softc *rc, int cfd) 265bf21cd93STycho Nightingale { 266bf21cd93STycho Nightingale struct rfb_srvr_updt_msg supdt_msg; 2674c87aefeSPatrick Mooney struct rfb_srvr_rect_hdr srect_hdr; 268bf21cd93STycho Nightingale 269bf21cd93STycho Nightingale /* Number of rectangles: 1 */ 270bf21cd93STycho Nightingale supdt_msg.type = 0; 271bf21cd93STycho Nightingale supdt_msg.pad = 0; 2724c87aefeSPatrick Mooney supdt_msg.numrects = htons(1); 2734c87aefeSPatrick Mooney stream_write(cfd, &supdt_msg, sizeof(struct rfb_srvr_updt_msg)); 274bf21cd93STycho Nightingale 275bf21cd93STycho Nightingale /* Rectangle header */ 2764c87aefeSPatrick Mooney srect_hdr.x = htons(0); 2774c87aefeSPatrick Mooney srect_hdr.y = htons(0); 2784c87aefeSPatrick Mooney srect_hdr.width = htons(rc->width); 2794c87aefeSPatrick Mooney srect_hdr.height = htons(rc->height); 2804c87aefeSPatrick Mooney srect_hdr.encoding = htonl(RFB_ENCODING_RESIZE); 2814c87aefeSPatrick Mooney stream_write(cfd, &srect_hdr, sizeof(struct rfb_srvr_rect_hdr)); 282bf21cd93STycho Nightingale } 283bf21cd93STycho Nightingale 284bf21cd93STycho Nightingale static void 285bf21cd93STycho Nightingale rfb_recv_set_pixfmt_msg(struct rfb_softc *rc, int cfd) 286bf21cd93STycho Nightingale { 287bf21cd93STycho Nightingale struct rfb_pixfmt_msg pixfmt_msg; 288bf21cd93STycho Nightingale 2894c87aefeSPatrick Mooney (void)stream_read(cfd, ((void *)&pixfmt_msg)+1, sizeof(pixfmt_msg)-1); 290bf21cd93STycho Nightingale } 291bf21cd93STycho Nightingale 292bf21cd93STycho Nightingale 293bf21cd93STycho Nightingale static void 294bf21cd93STycho Nightingale rfb_recv_set_encodings_msg(struct rfb_softc *rc, int cfd) 295bf21cd93STycho Nightingale { 296bf21cd93STycho Nightingale struct rfb_enc_msg enc_msg; 2974c87aefeSPatrick Mooney int i; 298bf21cd93STycho Nightingale uint32_t encoding; 299bf21cd93STycho Nightingale 3004c87aefeSPatrick Mooney (void)stream_read(cfd, ((void *)&enc_msg)+1, sizeof(enc_msg)-1); 301bf21cd93STycho Nightingale 3024c87aefeSPatrick Mooney for (i = 0; i < htons(enc_msg.numencs); i++) { 3034c87aefeSPatrick Mooney (void)stream_read(cfd, &encoding, sizeof(encoding)); 3044c87aefeSPatrick Mooney switch (htonl(encoding)) { 305bf21cd93STycho Nightingale case RFB_ENCODING_RAW: 306bf21cd93STycho Nightingale rc->enc_raw_ok = true; 307bf21cd93STycho Nightingale break; 3084c87aefeSPatrick Mooney case RFB_ENCODING_ZLIB: 30984659b24SMichael Zeller if (!rc->enc_zlib_ok) { 31084659b24SMichael Zeller deflateInit(&rc->zstream, Z_BEST_SPEED); 31184659b24SMichael Zeller rc->enc_zlib_ok = true; 31284659b24SMichael Zeller } 3134c87aefeSPatrick Mooney break; 314bf21cd93STycho Nightingale case RFB_ENCODING_RESIZE: 315bf21cd93STycho Nightingale rc->enc_resize_ok = true; 316bf21cd93STycho Nightingale break; 317bf21cd93STycho Nightingale } 318bf21cd93STycho Nightingale } 319bf21cd93STycho Nightingale } 320bf21cd93STycho Nightingale 3214c87aefeSPatrick Mooney /* 3224c87aefeSPatrick Mooney * Calculate CRC32 using SSE4.2; Intel or AMD Bulldozer+ CPUs only 3234c87aefeSPatrick Mooney */ 3244c87aefeSPatrick Mooney static __inline uint32_t 3254c87aefeSPatrick Mooney fast_crc32(void *buf, int len, uint32_t crcval) 3264c87aefeSPatrick Mooney { 3274c87aefeSPatrick Mooney uint32_t q = len / sizeof(uint32_t); 3284c87aefeSPatrick Mooney uint32_t *p = (uint32_t *)buf; 3294c87aefeSPatrick Mooney 3304c87aefeSPatrick Mooney while (q--) { 3314c87aefeSPatrick Mooney asm volatile ( 3324c87aefeSPatrick Mooney ".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;" 3334c87aefeSPatrick Mooney :"=S" (crcval) 3344c87aefeSPatrick Mooney :"0" (crcval), "c" (*p) 3354c87aefeSPatrick Mooney ); 3364c87aefeSPatrick Mooney p++; 3374c87aefeSPatrick Mooney } 3384c87aefeSPatrick Mooney 3394c87aefeSPatrick Mooney return (crcval); 3404c87aefeSPatrick Mooney } 3414c87aefeSPatrick Mooney 342*dc8050e8SMarko Kiiskila static int 343*dc8050e8SMarko Kiiskila rfb_send_update_header(struct rfb_softc *rc, int cfd, int numrects) 344*dc8050e8SMarko Kiiskila { 345*dc8050e8SMarko Kiiskila struct rfb_srvr_updt_msg supdt_msg; 346*dc8050e8SMarko Kiiskila 347*dc8050e8SMarko Kiiskila supdt_msg.type = 0; 348*dc8050e8SMarko Kiiskila supdt_msg.pad = 0; 349*dc8050e8SMarko Kiiskila supdt_msg.numrects = htons(numrects); 350*dc8050e8SMarko Kiiskila 351*dc8050e8SMarko Kiiskila return stream_write(cfd, &supdt_msg, 352*dc8050e8SMarko Kiiskila sizeof(struct rfb_srvr_updt_msg)); 353*dc8050e8SMarko Kiiskila } 3544c87aefeSPatrick Mooney 3554c87aefeSPatrick Mooney static int 3564c87aefeSPatrick Mooney rfb_send_rect(struct rfb_softc *rc, int cfd, struct bhyvegc_image *gc, 3574c87aefeSPatrick Mooney int x, int y, int w, int h) 3584c87aefeSPatrick Mooney { 3594c87aefeSPatrick Mooney struct rfb_srvr_rect_hdr srect_hdr; 3604c87aefeSPatrick Mooney unsigned long zlen; 3614c87aefeSPatrick Mooney ssize_t nwrite, total; 3624c87aefeSPatrick Mooney int err; 3634c87aefeSPatrick Mooney uint32_t *p; 3644c87aefeSPatrick Mooney uint8_t *zbufp; 3654c87aefeSPatrick Mooney 3664c87aefeSPatrick Mooney /* 3674c87aefeSPatrick Mooney * Send a single rectangle of the given x, y, w h dimensions. 3684c87aefeSPatrick Mooney */ 3694c87aefeSPatrick Mooney 3704c87aefeSPatrick Mooney /* Rectangle header */ 3714c87aefeSPatrick Mooney srect_hdr.x = htons(x); 3724c87aefeSPatrick Mooney srect_hdr.y = htons(y); 3734c87aefeSPatrick Mooney srect_hdr.width = htons(w); 3744c87aefeSPatrick Mooney srect_hdr.height = htons(h); 3754c87aefeSPatrick Mooney 3764c87aefeSPatrick Mooney h = y + h; 3774c87aefeSPatrick Mooney w *= sizeof(uint32_t); 3784c87aefeSPatrick Mooney if (rc->enc_zlib_ok) { 3794c87aefeSPatrick Mooney zbufp = rc->zbuf; 3804c87aefeSPatrick Mooney rc->zstream.total_in = 0; 3814c87aefeSPatrick Mooney rc->zstream.total_out = 0; 3824c87aefeSPatrick Mooney for (p = &gc->data[y * gc->width + x]; y < h; y++) { 3834c87aefeSPatrick Mooney rc->zstream.next_in = (Bytef *)p; 3844c87aefeSPatrick Mooney rc->zstream.avail_in = w; 3854c87aefeSPatrick Mooney rc->zstream.next_out = (Bytef *)zbufp; 3864c87aefeSPatrick Mooney rc->zstream.avail_out = RFB_ZLIB_BUFSZ + 16 - 3874c87aefeSPatrick Mooney rc->zstream.total_out; 3884c87aefeSPatrick Mooney rc->zstream.data_type = Z_BINARY; 3894c87aefeSPatrick Mooney 3904c87aefeSPatrick Mooney /* Compress with zlib */ 3914c87aefeSPatrick Mooney err = deflate(&rc->zstream, Z_SYNC_FLUSH); 3924c87aefeSPatrick Mooney if (err != Z_OK) { 393154972afSPatrick Mooney WPRINTF(("zlib[rect] deflate err: %d", err)); 3944c87aefeSPatrick Mooney rc->enc_zlib_ok = false; 3954c87aefeSPatrick Mooney deflateEnd(&rc->zstream); 3964c87aefeSPatrick Mooney goto doraw; 3974c87aefeSPatrick Mooney } 3984c87aefeSPatrick Mooney zbufp = rc->zbuf + rc->zstream.total_out; 3994c87aefeSPatrick Mooney p += gc->width; 4004c87aefeSPatrick Mooney } 4014c87aefeSPatrick Mooney srect_hdr.encoding = htonl(RFB_ENCODING_ZLIB); 4024c87aefeSPatrick Mooney nwrite = stream_write(cfd, &srect_hdr, 4034c87aefeSPatrick Mooney sizeof(struct rfb_srvr_rect_hdr)); 4044c87aefeSPatrick Mooney if (nwrite <= 0) 4054c87aefeSPatrick Mooney return (nwrite); 4064c87aefeSPatrick Mooney 4074c87aefeSPatrick Mooney zlen = htonl(rc->zstream.total_out); 4084c87aefeSPatrick Mooney nwrite = stream_write(cfd, &zlen, sizeof(uint32_t)); 4094c87aefeSPatrick Mooney if (nwrite <= 0) 4104c87aefeSPatrick Mooney return (nwrite); 4114c87aefeSPatrick Mooney return (stream_write(cfd, rc->zbuf, rc->zstream.total_out)); 4124c87aefeSPatrick Mooney } 4134c87aefeSPatrick Mooney 4144c87aefeSPatrick Mooney doraw: 4154c87aefeSPatrick Mooney 4164c87aefeSPatrick Mooney total = 0; 4174c87aefeSPatrick Mooney zbufp = rc->zbuf; 4184c87aefeSPatrick Mooney for (p = &gc->data[y * gc->width + x]; y < h; y++) { 4194c87aefeSPatrick Mooney memcpy(zbufp, p, w); 4204c87aefeSPatrick Mooney zbufp += w; 4214c87aefeSPatrick Mooney total += w; 4224c87aefeSPatrick Mooney p += gc->width; 4234c87aefeSPatrick Mooney } 4244c87aefeSPatrick Mooney 4254c87aefeSPatrick Mooney srect_hdr.encoding = htonl(RFB_ENCODING_RAW); 4264c87aefeSPatrick Mooney nwrite = stream_write(cfd, &srect_hdr, 4274c87aefeSPatrick Mooney sizeof(struct rfb_srvr_rect_hdr)); 4284c87aefeSPatrick Mooney if (nwrite <= 0) 4294c87aefeSPatrick Mooney return (nwrite); 4304c87aefeSPatrick Mooney 4314c87aefeSPatrick Mooney total = stream_write(cfd, rc->zbuf, total); 4324c87aefeSPatrick Mooney 4334c87aefeSPatrick Mooney return (total); 4344c87aefeSPatrick Mooney } 4354c87aefeSPatrick Mooney 4364c87aefeSPatrick Mooney static int 4374c87aefeSPatrick Mooney rfb_send_all(struct rfb_softc *rc, int cfd, struct bhyvegc_image *gc) 438bf21cd93STycho Nightingale { 439bf21cd93STycho Nightingale struct rfb_srvr_updt_msg supdt_msg; 440*dc8050e8SMarko Kiiskila struct rfb_srvr_rect_hdr srect_hdr; 4414c87aefeSPatrick Mooney ssize_t nwrite; 4424c87aefeSPatrick Mooney unsigned long zlen; 4434c87aefeSPatrick Mooney int err; 4444c87aefeSPatrick Mooney 4454c87aefeSPatrick Mooney /* 4464c87aefeSPatrick Mooney * Send the whole thing 4474c87aefeSPatrick Mooney */ 448bf21cd93STycho Nightingale 449bf21cd93STycho Nightingale /* Number of rectangles: 1 */ 450bf21cd93STycho Nightingale supdt_msg.type = 0; 451bf21cd93STycho Nightingale supdt_msg.pad = 0; 4524c87aefeSPatrick Mooney supdt_msg.numrects = htons(1); 4534c87aefeSPatrick Mooney nwrite = stream_write(cfd, &supdt_msg, 4544c87aefeSPatrick Mooney sizeof(struct rfb_srvr_updt_msg)); 4554c87aefeSPatrick Mooney if (nwrite <= 0) 4564c87aefeSPatrick Mooney return (nwrite); 457bf21cd93STycho Nightingale 458bf21cd93STycho Nightingale /* Rectangle header */ 4594c87aefeSPatrick Mooney srect_hdr.x = 0; 4604c87aefeSPatrick Mooney srect_hdr.y = 0; 4614c87aefeSPatrick Mooney srect_hdr.width = htons(gc->width); 4624c87aefeSPatrick Mooney srect_hdr.height = htons(gc->height); 4634c87aefeSPatrick Mooney if (rc->enc_zlib_ok) { 4644c87aefeSPatrick Mooney rc->zstream.next_in = (Bytef *)gc->data; 4654c87aefeSPatrick Mooney rc->zstream.avail_in = gc->width * gc->height * 4664c87aefeSPatrick Mooney sizeof(uint32_t); 4674c87aefeSPatrick Mooney rc->zstream.next_out = (Bytef *)rc->zbuf; 4684c87aefeSPatrick Mooney rc->zstream.avail_out = RFB_ZLIB_BUFSZ + 16; 4694c87aefeSPatrick Mooney rc->zstream.data_type = Z_BINARY; 4704c87aefeSPatrick Mooney 4714c87aefeSPatrick Mooney rc->zstream.total_in = 0; 4724c87aefeSPatrick Mooney rc->zstream.total_out = 0; 4734c87aefeSPatrick Mooney 4744c87aefeSPatrick Mooney /* Compress with zlib */ 4754c87aefeSPatrick Mooney err = deflate(&rc->zstream, Z_SYNC_FLUSH); 4764c87aefeSPatrick Mooney if (err != Z_OK) { 477154972afSPatrick Mooney WPRINTF(("zlib deflate err: %d", err)); 4784c87aefeSPatrick Mooney rc->enc_zlib_ok = false; 4794c87aefeSPatrick Mooney deflateEnd(&rc->zstream); 4804c87aefeSPatrick Mooney goto doraw; 4814c87aefeSPatrick Mooney } 4824c87aefeSPatrick Mooney 4834c87aefeSPatrick Mooney srect_hdr.encoding = htonl(RFB_ENCODING_ZLIB); 4844c87aefeSPatrick Mooney nwrite = stream_write(cfd, &srect_hdr, 4854c87aefeSPatrick Mooney sizeof(struct rfb_srvr_rect_hdr)); 4864c87aefeSPatrick Mooney if (nwrite <= 0) 4874c87aefeSPatrick Mooney return (nwrite); 4884c87aefeSPatrick Mooney 4894c87aefeSPatrick Mooney zlen = htonl(rc->zstream.total_out); 4904c87aefeSPatrick Mooney nwrite = stream_write(cfd, &zlen, sizeof(uint32_t)); 4914c87aefeSPatrick Mooney if (nwrite <= 0) 4924c87aefeSPatrick Mooney return (nwrite); 4934c87aefeSPatrick Mooney return (stream_write(cfd, rc->zbuf, rc->zstream.total_out)); 4944c87aefeSPatrick Mooney } 4954c87aefeSPatrick Mooney 4964c87aefeSPatrick Mooney doraw: 4974c87aefeSPatrick Mooney srect_hdr.encoding = htonl(RFB_ENCODING_RAW); 4984c87aefeSPatrick Mooney nwrite = stream_write(cfd, &srect_hdr, 4994c87aefeSPatrick Mooney sizeof(struct rfb_srvr_rect_hdr)); 5004c87aefeSPatrick Mooney if (nwrite <= 0) 5014c87aefeSPatrick Mooney return (nwrite); 5024c87aefeSPatrick Mooney 5034c87aefeSPatrick Mooney nwrite = stream_write(cfd, gc->data, 5044c87aefeSPatrick Mooney gc->width * gc->height * sizeof(uint32_t)); 5054c87aefeSPatrick Mooney 5064c87aefeSPatrick Mooney return (nwrite); 507bf21cd93STycho Nightingale } 508bf21cd93STycho Nightingale 5094c87aefeSPatrick Mooney #define PIX_PER_CELL 32 5104c87aefeSPatrick Mooney #define PIXCELL_SHIFT 5 5114c87aefeSPatrick Mooney #define PIXCELL_MASK 0x1F 5124c87aefeSPatrick Mooney 5134c87aefeSPatrick Mooney static int 514*dc8050e8SMarko Kiiskila rfb_send_screen(struct rfb_softc *rc, int cfd) 5154c87aefeSPatrick Mooney { 5164c87aefeSPatrick Mooney struct bhyvegc_image *gc_image; 5174c87aefeSPatrick Mooney ssize_t nwrite; 5184c87aefeSPatrick Mooney int x, y; 5194c87aefeSPatrick Mooney int celly, cellwidth; 5204c87aefeSPatrick Mooney int xcells, ycells; 5214c87aefeSPatrick Mooney int w, h; 5224c87aefeSPatrick Mooney uint32_t *p; 5234c87aefeSPatrick Mooney int rem_x, rem_y; /* remainder for resolutions not x32 pixels ratio */ 5244c87aefeSPatrick Mooney int retval; 5254c87aefeSPatrick Mooney uint32_t *crc_p, *orig_crc; 5264c87aefeSPatrick Mooney int changes; 527*dc8050e8SMarko Kiiskila bool expected; 528*dc8050e8SMarko Kiiskila 529*dc8050e8SMarko Kiiskila /* Return if another thread sending */ 530*dc8050e8SMarko Kiiskila expected = false; 531*dc8050e8SMarko Kiiskila if (atomic_compare_exchange_strong(&rc->sending, &expected, true) == false) 532*dc8050e8SMarko Kiiskila return (1); 533*dc8050e8SMarko Kiiskila 534*dc8050e8SMarko Kiiskila retval = 1; 535*dc8050e8SMarko Kiiskila 536*dc8050e8SMarko Kiiskila /* Updates require a preceding update request */ 537*dc8050e8SMarko Kiiskila if (atomic_exchange(&rc->pending, false) == false) 538*dc8050e8SMarko Kiiskila goto done; 5394c87aefeSPatrick Mooney 5404c87aefeSPatrick Mooney console_refresh(); 5414c87aefeSPatrick Mooney gc_image = console_get_image(); 5424c87aefeSPatrick Mooney 543*dc8050e8SMarko Kiiskila /* Clear old CRC values when the size changes */ 544*dc8050e8SMarko Kiiskila if (rc->crc_width != gc_image->width || 545*dc8050e8SMarko Kiiskila rc->crc_height != gc_image->height) { 546*dc8050e8SMarko Kiiskila memset(rc->crc, 0, sizeof(uint32_t) * 547*dc8050e8SMarko Kiiskila howmany(RFB_MAX_WIDTH, PIX_PER_CELL) * 548*dc8050e8SMarko Kiiskila howmany(RFB_MAX_HEIGHT, PIX_PER_CELL)); 549*dc8050e8SMarko Kiiskila rc->crc_width = gc_image->width; 550*dc8050e8SMarko Kiiskila rc->crc_height = gc_image->height; 5514c87aefeSPatrick Mooney } 5524c87aefeSPatrick Mooney 553*dc8050e8SMarko Kiiskila /* A size update counts as an update in itself */ 554*dc8050e8SMarko Kiiskila if (rc->width != gc_image->width || 555*dc8050e8SMarko Kiiskila rc->height != gc_image->height) { 556*dc8050e8SMarko Kiiskila rc->width = gc_image->width; 557*dc8050e8SMarko Kiiskila rc->height = gc_image->height; 558*dc8050e8SMarko Kiiskila if (rc->enc_resize_ok) { 559*dc8050e8SMarko Kiiskila rfb_send_resize_update_msg(rc, cfd); 560*dc8050e8SMarko Kiiskila rc->update_all = true; 561*dc8050e8SMarko Kiiskila goto done; 562*dc8050e8SMarko Kiiskila } 563*dc8050e8SMarko Kiiskila } 5644c87aefeSPatrick Mooney 565*dc8050e8SMarko Kiiskila if (atomic_exchange(&rc->update_all, false) == true) { 5664c87aefeSPatrick Mooney retval = rfb_send_all(rc, cfd, gc_image); 5674c87aefeSPatrick Mooney goto done; 5684c87aefeSPatrick Mooney } 5694c87aefeSPatrick Mooney 5704c87aefeSPatrick Mooney /* 5714c87aefeSPatrick Mooney * Calculate the checksum for each 32x32 cell. Send each that 5724c87aefeSPatrick Mooney * has changed since the last scan. 5734c87aefeSPatrick Mooney */ 5744c87aefeSPatrick Mooney 5754c87aefeSPatrick Mooney w = rc->crc_width; 5764c87aefeSPatrick Mooney h = rc->crc_height; 5774c87aefeSPatrick Mooney xcells = howmany(rc->crc_width, PIX_PER_CELL); 5784c87aefeSPatrick Mooney ycells = howmany(rc->crc_height, PIX_PER_CELL); 5794c87aefeSPatrick Mooney 5804c87aefeSPatrick Mooney rem_x = w & PIXCELL_MASK; 5814c87aefeSPatrick Mooney 5824c87aefeSPatrick Mooney rem_y = h & PIXCELL_MASK; 5834c87aefeSPatrick Mooney if (!rem_y) 5844c87aefeSPatrick Mooney rem_y = PIX_PER_CELL; 5854c87aefeSPatrick Mooney 5864c87aefeSPatrick Mooney p = gc_image->data; 5874c87aefeSPatrick Mooney 5884c87aefeSPatrick Mooney /* 5894c87aefeSPatrick Mooney * Go through all cells and calculate crc. If significant number 5904c87aefeSPatrick Mooney * of changes, then send entire screen. 5914c87aefeSPatrick Mooney * crc_tmp is dual purpose: to store the new crc and to flag as 5924c87aefeSPatrick Mooney * a cell that has changed. 5934c87aefeSPatrick Mooney */ 5944c87aefeSPatrick Mooney crc_p = rc->crc_tmp - xcells; 5954c87aefeSPatrick Mooney orig_crc = rc->crc - xcells; 5964c87aefeSPatrick Mooney changes = 0; 5974c87aefeSPatrick Mooney memset(rc->crc_tmp, 0, sizeof(uint32_t) * xcells * ycells); 5984c87aefeSPatrick Mooney for (y = 0; y < h; y++) { 5994c87aefeSPatrick Mooney if ((y & PIXCELL_MASK) == 0) { 6004c87aefeSPatrick Mooney crc_p += xcells; 6014c87aefeSPatrick Mooney orig_crc += xcells; 6024c87aefeSPatrick Mooney } 6034c87aefeSPatrick Mooney 6044c87aefeSPatrick Mooney for (x = 0; x < xcells; x++) { 6054c87aefeSPatrick Mooney if (x == (xcells - 1) && rem_x > 0) 6064c87aefeSPatrick Mooney cellwidth = rem_x; 6074c87aefeSPatrick Mooney else 6084c87aefeSPatrick Mooney cellwidth = PIX_PER_CELL; 6094c87aefeSPatrick Mooney 6104c87aefeSPatrick Mooney if (rc->hw_crc) 6114c87aefeSPatrick Mooney crc_p[x] = fast_crc32(p, 6124c87aefeSPatrick Mooney cellwidth * sizeof(uint32_t), 6134c87aefeSPatrick Mooney crc_p[x]); 6144c87aefeSPatrick Mooney else 6154c87aefeSPatrick Mooney crc_p[x] = (uint32_t)crc32(crc_p[x], 6164c87aefeSPatrick Mooney (Bytef *)p, 6174c87aefeSPatrick Mooney cellwidth * sizeof(uint32_t)); 6184c87aefeSPatrick Mooney 6194c87aefeSPatrick Mooney p += cellwidth; 6204c87aefeSPatrick Mooney 6214c87aefeSPatrick Mooney /* check for crc delta if last row in cell */ 6224c87aefeSPatrick Mooney if ((y & PIXCELL_MASK) == PIXCELL_MASK || y == (h-1)) { 6234c87aefeSPatrick Mooney if (orig_crc[x] != crc_p[x]) { 6244c87aefeSPatrick Mooney orig_crc[x] = crc_p[x]; 6254c87aefeSPatrick Mooney crc_p[x] = 1; 6264c87aefeSPatrick Mooney changes++; 6274c87aefeSPatrick Mooney } else { 6284c87aefeSPatrick Mooney crc_p[x] = 0; 6294c87aefeSPatrick Mooney } 6304c87aefeSPatrick Mooney } 6314c87aefeSPatrick Mooney } 6324c87aefeSPatrick Mooney } 6334c87aefeSPatrick Mooney 634*dc8050e8SMarko Kiiskila /* 635*dc8050e8SMarko Kiiskila * We only send the update if there are changes. 636*dc8050e8SMarko Kiiskila * Restore the pending flag since it was unconditionally cleared 637*dc8050e8SMarko Kiiskila * above. 638*dc8050e8SMarko Kiiskila */ 639*dc8050e8SMarko Kiiskila if (!changes) { 640*dc8050e8SMarko Kiiskila rc->pending = true; 641*dc8050e8SMarko Kiiskila goto done; 642*dc8050e8SMarko Kiiskila } 643*dc8050e8SMarko Kiiskila 6444c87aefeSPatrick Mooney /* If number of changes is > THRESH percent, send the whole screen */ 6454c87aefeSPatrick Mooney if (((changes * 100) / (xcells * ycells)) >= RFB_SEND_ALL_THRESH) { 6464c87aefeSPatrick Mooney retval = rfb_send_all(rc, cfd, gc_image); 6474c87aefeSPatrick Mooney goto done; 6484c87aefeSPatrick Mooney } 649*dc8050e8SMarko Kiiskila 650*dc8050e8SMarko Kiiskila rfb_send_update_header(rc, cfd, changes); 651*dc8050e8SMarko Kiiskila 6524c87aefeSPatrick Mooney /* Go through all cells, and send only changed ones */ 6534c87aefeSPatrick Mooney crc_p = rc->crc_tmp; 6544c87aefeSPatrick Mooney for (y = 0; y < h; y += PIX_PER_CELL) { 6554c87aefeSPatrick Mooney /* previous cell's row */ 6564c87aefeSPatrick Mooney celly = (y >> PIXCELL_SHIFT); 6574c87aefeSPatrick Mooney 6584c87aefeSPatrick Mooney /* Delta check crc to previous set */ 6594c87aefeSPatrick Mooney for (x = 0; x < xcells; x++) { 6604c87aefeSPatrick Mooney if (*crc_p++ == 0) 6614c87aefeSPatrick Mooney continue; 6624c87aefeSPatrick Mooney 6634c87aefeSPatrick Mooney if (x == (xcells - 1) && rem_x > 0) 6644c87aefeSPatrick Mooney cellwidth = rem_x; 6654c87aefeSPatrick Mooney else 6664c87aefeSPatrick Mooney cellwidth = PIX_PER_CELL; 6674c87aefeSPatrick Mooney nwrite = rfb_send_rect(rc, cfd, 6684c87aefeSPatrick Mooney gc_image, 6694c87aefeSPatrick Mooney x * PIX_PER_CELL, 6704c87aefeSPatrick Mooney celly * PIX_PER_CELL, 6714c87aefeSPatrick Mooney cellwidth, 6724c87aefeSPatrick Mooney y + PIX_PER_CELL >= h ? rem_y : PIX_PER_CELL); 6734c87aefeSPatrick Mooney if (nwrite <= 0) { 6744c87aefeSPatrick Mooney retval = nwrite; 6754c87aefeSPatrick Mooney goto done; 6764c87aefeSPatrick Mooney } 6774c87aefeSPatrick Mooney } 6784c87aefeSPatrick Mooney } 6794c87aefeSPatrick Mooney 6804c87aefeSPatrick Mooney done: 681*dc8050e8SMarko Kiiskila rc->sending = false; 682*dc8050e8SMarko Kiiskila 6834c87aefeSPatrick Mooney return (retval); 6844c87aefeSPatrick Mooney } 6854c87aefeSPatrick Mooney 6864c87aefeSPatrick Mooney 687bf21cd93STycho Nightingale static void 688*dc8050e8SMarko Kiiskila rfb_recv_update_msg(struct rfb_softc *rc, int cfd) 689bf21cd93STycho Nightingale { 690bf21cd93STycho Nightingale struct rfb_updt_msg updt_msg; 691bf21cd93STycho Nightingale 6924c87aefeSPatrick Mooney (void)stream_read(cfd, ((void *)&updt_msg) + 1 , sizeof(updt_msg) - 1); 693bf21cd93STycho Nightingale 694*dc8050e8SMarko Kiiskila rc->pending = true; 695*dc8050e8SMarko Kiiskila if (!updt_msg.incremental) 696*dc8050e8SMarko Kiiskila rc->update_all = true; 697bf21cd93STycho Nightingale } 698bf21cd93STycho Nightingale 699bf21cd93STycho Nightingale static void 700bf21cd93STycho Nightingale rfb_recv_key_msg(struct rfb_softc *rc, int cfd) 701bf21cd93STycho Nightingale { 702bf21cd93STycho Nightingale struct rfb_key_msg key_msg; 703bf21cd93STycho Nightingale 7044c87aefeSPatrick Mooney (void)stream_read(cfd, ((void *)&key_msg) + 1, sizeof(key_msg) - 1); 705bf21cd93STycho Nightingale 7064c87aefeSPatrick Mooney console_key_event(key_msg.down, htonl(key_msg.code)); 707*dc8050e8SMarko Kiiskila rc->input_detected = true; 708bf21cd93STycho Nightingale } 709bf21cd93STycho Nightingale 710bf21cd93STycho Nightingale static void 711bf21cd93STycho Nightingale rfb_recv_ptr_msg(struct rfb_softc *rc, int cfd) 712bf21cd93STycho Nightingale { 713bf21cd93STycho Nightingale struct rfb_ptr_msg ptr_msg; 7144c87aefeSPatrick Mooney 7154c87aefeSPatrick Mooney (void)stream_read(cfd, ((void *)&ptr_msg) + 1, sizeof(ptr_msg) - 1); 7164c87aefeSPatrick Mooney 7174c87aefeSPatrick Mooney console_ptr_event(ptr_msg.button, htons(ptr_msg.x), htons(ptr_msg.y)); 718*dc8050e8SMarko Kiiskila rc->input_detected = true; 7194c87aefeSPatrick Mooney } 7204c87aefeSPatrick Mooney 7214c87aefeSPatrick Mooney static void 7224c87aefeSPatrick Mooney rfb_recv_cuttext_msg(struct rfb_softc *rc, int cfd) 7234c87aefeSPatrick Mooney { 7244c87aefeSPatrick Mooney struct rfb_cuttext_msg ct_msg; 7254c87aefeSPatrick Mooney unsigned char buf[32]; 726bf21cd93STycho Nightingale int len; 727bf21cd93STycho Nightingale 7284c87aefeSPatrick Mooney len = stream_read(cfd, ((void *)&ct_msg) + 1, sizeof(ct_msg) - 1); 7294c87aefeSPatrick Mooney ct_msg.length = htonl(ct_msg.length); 7304c87aefeSPatrick Mooney while (ct_msg.length > 0) { 7314c87aefeSPatrick Mooney len = stream_read(cfd, buf, ct_msg.length > sizeof(buf) ? 7324c87aefeSPatrick Mooney sizeof(buf) : ct_msg.length); 7334c87aefeSPatrick Mooney ct_msg.length -= len; 7344c87aefeSPatrick Mooney } 7354c87aefeSPatrick Mooney } 736bf21cd93STycho Nightingale 7374c87aefeSPatrick Mooney static int64_t 7384c87aefeSPatrick Mooney timeval_delta(struct timeval *prev, struct timeval *now) 7394c87aefeSPatrick Mooney { 7404c87aefeSPatrick Mooney int64_t n1, n2; 7414c87aefeSPatrick Mooney n1 = now->tv_sec * 1000000 + now->tv_usec; 7424c87aefeSPatrick Mooney n2 = prev->tv_sec * 1000000 + prev->tv_usec; 7434c87aefeSPatrick Mooney return (n1 - n2); 7444c87aefeSPatrick Mooney } 7454c87aefeSPatrick Mooney 7464c87aefeSPatrick Mooney static void * 7474c87aefeSPatrick Mooney rfb_wr_thr(void *arg) 7484c87aefeSPatrick Mooney { 7494c87aefeSPatrick Mooney struct rfb_softc *rc; 7504c87aefeSPatrick Mooney fd_set rfds; 7514c87aefeSPatrick Mooney struct timeval tv; 7524c87aefeSPatrick Mooney struct timeval prev_tv; 7534c87aefeSPatrick Mooney int64_t tdiff; 7544c87aefeSPatrick Mooney int cfd; 7554c87aefeSPatrick Mooney int err; 7564c87aefeSPatrick Mooney 7574c87aefeSPatrick Mooney rc = arg; 7584c87aefeSPatrick Mooney cfd = rc->cfd; 7594c87aefeSPatrick Mooney 7604c87aefeSPatrick Mooney prev_tv.tv_sec = 0; 7614c87aefeSPatrick Mooney prev_tv.tv_usec = 0; 7624c87aefeSPatrick Mooney while (rc->cfd >= 0) { 7634c87aefeSPatrick Mooney FD_ZERO(&rfds); 7644c87aefeSPatrick Mooney FD_SET(cfd, &rfds); 7654c87aefeSPatrick Mooney tv.tv_sec = 0; 766*dc8050e8SMarko Kiiskila tv.tv_usec = CFD_SEL_DELAY; 7674c87aefeSPatrick Mooney 7684c87aefeSPatrick Mooney err = select(cfd+1, &rfds, NULL, NULL, &tv); 7694c87aefeSPatrick Mooney if (err < 0) 7704c87aefeSPatrick Mooney return (NULL); 7714c87aefeSPatrick Mooney 7724c87aefeSPatrick Mooney /* Determine if its time to push screen; ~24hz */ 7734c87aefeSPatrick Mooney gettimeofday(&tv, NULL); 7744c87aefeSPatrick Mooney tdiff = timeval_delta(&prev_tv, &tv); 775*dc8050e8SMarko Kiiskila if (tdiff >= SCREEN_POLL_DELAY) { 776*dc8050e8SMarko Kiiskila bool input; 7774c87aefeSPatrick Mooney prev_tv.tv_sec = tv.tv_sec; 7784c87aefeSPatrick Mooney prev_tv.tv_usec = tv.tv_usec; 779*dc8050e8SMarko Kiiskila input = atomic_exchange(&rc->input_detected, false); 780*dc8050e8SMarko Kiiskila /* 781*dc8050e8SMarko Kiiskila * Refresh the screen on every second trip through the loop, 782*dc8050e8SMarko Kiiskila * or if keyboard/mouse input has been detected. 783*dc8050e8SMarko Kiiskila */ 784*dc8050e8SMarko Kiiskila if ((++rc->wrcount & 1) || input) { 785*dc8050e8SMarko Kiiskila if (rfb_send_screen(rc, cfd) <= 0) { 786*dc8050e8SMarko Kiiskila return (NULL); 787*dc8050e8SMarko Kiiskila } 7884c87aefeSPatrick Mooney } 7894c87aefeSPatrick Mooney } else { 7904c87aefeSPatrick Mooney /* sleep */ 791*dc8050e8SMarko Kiiskila usleep(SCREEN_POLL_DELAY - tdiff); 7924c87aefeSPatrick Mooney } 7934c87aefeSPatrick Mooney } 7944c87aefeSPatrick Mooney 7954c87aefeSPatrick Mooney return (NULL); 796bf21cd93STycho Nightingale } 797bf21cd93STycho Nightingale 798bf21cd93STycho Nightingale void 799bf21cd93STycho Nightingale rfb_handle(struct rfb_softc *rc, int cfd) 800bf21cd93STycho Nightingale { 801bf21cd93STycho Nightingale const char *vbuf = "RFB 003.008\n"; 802bf21cd93STycho Nightingale unsigned char buf[80]; 8034c87aefeSPatrick Mooney unsigned char *message = NULL; 8044c87aefeSPatrick Mooney 8054c87aefeSPatrick Mooney #ifndef NO_OPENSSL 8064c87aefeSPatrick Mooney unsigned char challenge[AUTH_LENGTH]; 8074c87aefeSPatrick Mooney unsigned char keystr[PASSWD_LENGTH]; 8084c87aefeSPatrick Mooney unsigned char crypt_expected[AUTH_LENGTH]; 8094c87aefeSPatrick Mooney 8104c87aefeSPatrick Mooney DES_key_schedule ks; 8114c87aefeSPatrick Mooney int i; 8124c87aefeSPatrick Mooney #endif 813*dc8050e8SMarko Kiiskila uint8_t client_ver; 814*dc8050e8SMarko Kiiskila uint8_t auth_type; 8154c87aefeSPatrick Mooney pthread_t tid; 8164c87aefeSPatrick Mooney uint32_t sres = 0; 817bf21cd93STycho Nightingale int len; 8184c87aefeSPatrick Mooney int perror = 1; 8194c87aefeSPatrick Mooney 8204c87aefeSPatrick Mooney rc->cfd = cfd; 821bf21cd93STycho Nightingale 822bf21cd93STycho Nightingale /* 1a. Send server version */ 8234c87aefeSPatrick Mooney stream_write(cfd, vbuf, strlen(vbuf)); 824bf21cd93STycho Nightingale 825bf21cd93STycho Nightingale /* 1b. Read client version */ 826154972afSPatrick Mooney len = stream_read(cfd, buf, VERSION_LENGTH); 827*dc8050e8SMarko Kiiskila #ifdef __FreeBSD__ 828*dc8050e8SMarko Kiiskila if (len == VERSION_LENGTH && !strncmp(vbuf, buf, VERSION_LENGTH - 2)) { 829*dc8050e8SMarko Kiiskila client_ver = buf[VERSION_LENGTH - 2]; 830*dc8050e8SMarko Kiiskila } 831*dc8050e8SMarko Kiiskila #else 832*dc8050e8SMarko Kiiskila /* Work around gcc7 maybe-uninitialized warning */ 833*dc8050e8SMarko Kiiskila client_ver = CVERS_3_3; 834*dc8050e8SMarko Kiiskila if (len == VERSION_LENGTH && !strncmp(vbuf, (char *)buf, 835*dc8050e8SMarko Kiiskila VERSION_LENGTH - 2)) { 836*dc8050e8SMarko Kiiskila client_ver = buf[VERSION_LENGTH - 2]; 837*dc8050e8SMarko Kiiskila } 838*dc8050e8SMarko Kiiskila #endif 839*dc8050e8SMarko Kiiskila if (client_ver != CVERS_3_8 && client_ver != CVERS_3_7) { 840*dc8050e8SMarko Kiiskila /* only recognize 3.3, 3.7 & 3.8. Others dflt to 3.3 */ 841*dc8050e8SMarko Kiiskila client_ver = CVERS_3_3; 842*dc8050e8SMarko Kiiskila } 843bf21cd93STycho Nightingale 8444c87aefeSPatrick Mooney /* 2a. Send security type */ 845bf21cd93STycho Nightingale buf[0] = 1; 846*dc8050e8SMarko Kiiskila 847*dc8050e8SMarko Kiiskila /* In versions 3.7 & 3.8, it's 2-way handshake */ 848*dc8050e8SMarko Kiiskila /* For version 3.3, server says what the authentication type must be */ 8494c87aefeSPatrick Mooney #ifndef NO_OPENSSL 850*dc8050e8SMarko Kiiskila if (rc->password) { 851*dc8050e8SMarko Kiiskila auth_type = SECURITY_TYPE_VNC_AUTH; 852*dc8050e8SMarko Kiiskila } else { 853*dc8050e8SMarko Kiiskila auth_type = SECURITY_TYPE_NONE; 854*dc8050e8SMarko Kiiskila } 8554c87aefeSPatrick Mooney #else 856*dc8050e8SMarko Kiiskila auth_type = SECURITY_TYPE_NONE; 8574c87aefeSPatrick Mooney #endif 8584c87aefeSPatrick Mooney 859*dc8050e8SMarko Kiiskila switch (client_ver) { 860*dc8050e8SMarko Kiiskila case CVERS_3_7: 861*dc8050e8SMarko Kiiskila case CVERS_3_8: 862*dc8050e8SMarko Kiiskila buf[0] = 1; 863*dc8050e8SMarko Kiiskila buf[1] = auth_type; 864*dc8050e8SMarko Kiiskila stream_write(cfd, buf, 2); 865*dc8050e8SMarko Kiiskila 866*dc8050e8SMarko Kiiskila /* 2b. Read agreed security type */ 867*dc8050e8SMarko Kiiskila len = stream_read(cfd, buf, 1); 868*dc8050e8SMarko Kiiskila if (buf[0] != auth_type) { 869*dc8050e8SMarko Kiiskila /* deny */ 870*dc8050e8SMarko Kiiskila sres = htonl(1); 871*dc8050e8SMarko Kiiskila #ifdef __FreeBSD__ 872*dc8050e8SMarko Kiiskila message = "Auth failed: authentication type mismatch"; 873*dc8050e8SMarko Kiiskila #else 874*dc8050e8SMarko Kiiskila message = (unsigned char *)"Auth failed: authentication type mismatch"; 875*dc8050e8SMarko Kiiskila #endif 876*dc8050e8SMarko Kiiskila goto report_and_done; 877*dc8050e8SMarko Kiiskila } 878*dc8050e8SMarko Kiiskila break; 879*dc8050e8SMarko Kiiskila case CVERS_3_3: 880*dc8050e8SMarko Kiiskila default: 881*dc8050e8SMarko Kiiskila be32enc(buf, auth_type); 882*dc8050e8SMarko Kiiskila stream_write(cfd, buf, 4); 883*dc8050e8SMarko Kiiskila break; 884*dc8050e8SMarko Kiiskila } 8854c87aefeSPatrick Mooney 8864c87aefeSPatrick Mooney /* 2c. Do VNC authentication */ 887*dc8050e8SMarko Kiiskila switch (auth_type) { 8884c87aefeSPatrick Mooney case SECURITY_TYPE_NONE: 8894c87aefeSPatrick Mooney break; 8904c87aefeSPatrick Mooney case SECURITY_TYPE_VNC_AUTH: 8914c87aefeSPatrick Mooney /* 8924c87aefeSPatrick Mooney * The client encrypts the challenge with DES, using a password 8934c87aefeSPatrick Mooney * supplied by the user as the key. 8944c87aefeSPatrick Mooney * To form the key, the password is truncated to 8954c87aefeSPatrick Mooney * eight characters, or padded with null bytes on the right. 8964c87aefeSPatrick Mooney * The client then sends the resulting 16-bytes response. 8974c87aefeSPatrick Mooney */ 8984c87aefeSPatrick Mooney #ifndef NO_OPENSSL 8994c87aefeSPatrick Mooney strncpy(keystr, rc->password, PASSWD_LENGTH); 9004c87aefeSPatrick Mooney 9014c87aefeSPatrick Mooney /* VNC clients encrypts the challenge with all the bit fields 9024c87aefeSPatrick Mooney * in each byte of the password mirrored. 9034c87aefeSPatrick Mooney * Here we flip each byte of the keystr. 9044c87aefeSPatrick Mooney */ 9054c87aefeSPatrick Mooney for (i = 0; i < PASSWD_LENGTH; i++) { 9064c87aefeSPatrick Mooney keystr[i] = (keystr[i] & 0xF0) >> 4 9074c87aefeSPatrick Mooney | (keystr[i] & 0x0F) << 4; 9084c87aefeSPatrick Mooney keystr[i] = (keystr[i] & 0xCC) >> 2 9094c87aefeSPatrick Mooney | (keystr[i] & 0x33) << 2; 9104c87aefeSPatrick Mooney keystr[i] = (keystr[i] & 0xAA) >> 1 9114c87aefeSPatrick Mooney | (keystr[i] & 0x55) << 1; 9124c87aefeSPatrick Mooney } 9134c87aefeSPatrick Mooney 9144c87aefeSPatrick Mooney /* Initialize a 16-byte random challenge */ 9154c87aefeSPatrick Mooney arc4random_buf(challenge, sizeof(challenge)); 9164c87aefeSPatrick Mooney stream_write(cfd, challenge, AUTH_LENGTH); 9174c87aefeSPatrick Mooney 9184c87aefeSPatrick Mooney /* Receive the 16-byte challenge response */ 9194c87aefeSPatrick Mooney stream_read(cfd, buf, AUTH_LENGTH); 9204c87aefeSPatrick Mooney 9214c87aefeSPatrick Mooney memcpy(crypt_expected, challenge, AUTH_LENGTH); 9224c87aefeSPatrick Mooney 9234c87aefeSPatrick Mooney /* Encrypt the Challenge with DES */ 9244c87aefeSPatrick Mooney DES_set_key((const_DES_cblock *)keystr, &ks); 9254c87aefeSPatrick Mooney DES_ecb_encrypt((const_DES_cblock *)challenge, 9264c87aefeSPatrick Mooney (const_DES_cblock *)crypt_expected, 9274c87aefeSPatrick Mooney &ks, DES_ENCRYPT); 9284c87aefeSPatrick Mooney DES_ecb_encrypt((const_DES_cblock *)(challenge + PASSWD_LENGTH), 9294c87aefeSPatrick Mooney (const_DES_cblock *)(crypt_expected + 9304c87aefeSPatrick Mooney PASSWD_LENGTH), 9314c87aefeSPatrick Mooney &ks, DES_ENCRYPT); 9324c87aefeSPatrick Mooney 9334c87aefeSPatrick Mooney if (memcmp(crypt_expected, buf, AUTH_LENGTH) != 0) { 9344c87aefeSPatrick Mooney message = "Auth Failed: Invalid Password."; 9354c87aefeSPatrick Mooney sres = htonl(1); 936*dc8050e8SMarko Kiiskila } else { 9374c87aefeSPatrick Mooney sres = 0; 938*dc8050e8SMarko Kiiskila } 9394c87aefeSPatrick Mooney #else 940*dc8050e8SMarko Kiiskila sres = htonl(1); 9414c87aefeSPatrick Mooney WPRINTF(("Auth not supported, no OpenSSL in your system")); 9424c87aefeSPatrick Mooney #endif 943bf21cd93STycho Nightingale 9444c87aefeSPatrick Mooney break; 9454c87aefeSPatrick Mooney } 9464c87aefeSPatrick Mooney 947*dc8050e8SMarko Kiiskila switch (client_ver) { 948*dc8050e8SMarko Kiiskila case CVERS_3_7: 949*dc8050e8SMarko Kiiskila case CVERS_3_8: 950*dc8050e8SMarko Kiiskila report_and_done: 951*dc8050e8SMarko Kiiskila /* 2d. Write back a status */ 952*dc8050e8SMarko Kiiskila stream_write(cfd, &sres, 4); 9534c87aefeSPatrick Mooney 954*dc8050e8SMarko Kiiskila if (sres) { 955*dc8050e8SMarko Kiiskila /* 3.7 does not want string explaining cause */ 956*dc8050e8SMarko Kiiskila if (client_ver == CVERS_3_8) { 9574c87aefeSPatrick Mooney #ifdef __FreeBSD__ 958*dc8050e8SMarko Kiiskila be32enc(buf, strlen(message)); 959*dc8050e8SMarko Kiiskila stream_write(cfd, buf, 4); 960*dc8050e8SMarko Kiiskila stream_write(cfd, message, strlen(message)); 9614c87aefeSPatrick Mooney #else 962*dc8050e8SMarko Kiiskila be32enc(buf, strlen((char *)message)); 963*dc8050e8SMarko Kiiskila stream_write(cfd, buf, 4); 964*dc8050e8SMarko Kiiskila stream_write(cfd, message, 965*dc8050e8SMarko Kiiskila strlen((char *)message)); 9664c87aefeSPatrick Mooney #endif 967*dc8050e8SMarko Kiiskila } 968*dc8050e8SMarko Kiiskila goto done; 969*dc8050e8SMarko Kiiskila } 970*dc8050e8SMarko Kiiskila break; 971*dc8050e8SMarko Kiiskila case CVERS_3_3: 972*dc8050e8SMarko Kiiskila default: 973*dc8050e8SMarko Kiiskila /* for VNC auth case send status */ 974*dc8050e8SMarko Kiiskila if (auth_type == SECURITY_TYPE_VNC_AUTH) { 975*dc8050e8SMarko Kiiskila /* 2d. Write back a status */ 976*dc8050e8SMarko Kiiskila stream_write(cfd, &sres, 4); 977*dc8050e8SMarko Kiiskila } 978*dc8050e8SMarko Kiiskila if (sres) { 979*dc8050e8SMarko Kiiskila goto done; 980*dc8050e8SMarko Kiiskila } 981*dc8050e8SMarko Kiiskila break; 9824c87aefeSPatrick Mooney } 983bf21cd93STycho Nightingale /* 3a. Read client shared-flag byte */ 9844c87aefeSPatrick Mooney len = stream_read(cfd, buf, 1); 985bf21cd93STycho Nightingale 986bf21cd93STycho Nightingale /* 4a. Write server-init info */ 987bf21cd93STycho Nightingale rfb_send_server_init_msg(cfd); 988bf21cd93STycho Nightingale 9894c87aefeSPatrick Mooney if (!rc->zbuf) { 9904c87aefeSPatrick Mooney rc->zbuf = malloc(RFB_ZLIB_BUFSZ + 16); 9914c87aefeSPatrick Mooney assert(rc->zbuf != NULL); 9924c87aefeSPatrick Mooney } 9934c87aefeSPatrick Mooney 9944c87aefeSPatrick Mooney perror = pthread_create(&tid, NULL, rfb_wr_thr, rc); 9954c87aefeSPatrick Mooney if (perror == 0) 9964c87aefeSPatrick Mooney pthread_set_name_np(tid, "rfbout"); 9974c87aefeSPatrick Mooney 998*dc8050e8SMarko Kiiskila /* Now read in client requests. 1st byte identifies type */ 999bf21cd93STycho Nightingale for (;;) { 1000bf21cd93STycho Nightingale len = read(cfd, buf, 1); 1001bf21cd93STycho Nightingale if (len <= 0) { 1002154972afSPatrick Mooney DPRINTF(("rfb client exiting")); 1003bf21cd93STycho Nightingale break; 1004bf21cd93STycho Nightingale } 1005bf21cd93STycho Nightingale 1006bf21cd93STycho Nightingale switch (buf[0]) { 1007*dc8050e8SMarko Kiiskila case CS_SET_PIXEL_FORMAT: 1008bf21cd93STycho Nightingale rfb_recv_set_pixfmt_msg(rc, cfd); 1009bf21cd93STycho Nightingale break; 1010*dc8050e8SMarko Kiiskila case CS_SET_ENCODINGS: 1011bf21cd93STycho Nightingale rfb_recv_set_encodings_msg(rc, cfd); 1012bf21cd93STycho Nightingale break; 1013*dc8050e8SMarko Kiiskila case CS_UPDATE_MSG: 1014*dc8050e8SMarko Kiiskila rfb_recv_update_msg(rc, cfd); 1015bf21cd93STycho Nightingale break; 1016*dc8050e8SMarko Kiiskila case CS_KEY_EVENT: 1017bf21cd93STycho Nightingale rfb_recv_key_msg(rc, cfd); 1018bf21cd93STycho Nightingale break; 1019*dc8050e8SMarko Kiiskila case CS_POINTER_EVENT: 1020bf21cd93STycho Nightingale rfb_recv_ptr_msg(rc, cfd); 1021bf21cd93STycho Nightingale break; 1022*dc8050e8SMarko Kiiskila case CS_CUT_TEXT: 10234c87aefeSPatrick Mooney rfb_recv_cuttext_msg(rc, cfd); 10244c87aefeSPatrick Mooney break; 1025bf21cd93STycho Nightingale default: 1026154972afSPatrick Mooney WPRINTF(("rfb unknown cli-code %d!", buf[0] & 0xff)); 10274c87aefeSPatrick Mooney goto done; 1028bf21cd93STycho Nightingale } 1029bf21cd93STycho Nightingale } 10304c87aefeSPatrick Mooney done: 10314c87aefeSPatrick Mooney rc->cfd = -1; 10324c87aefeSPatrick Mooney if (perror == 0) 10334c87aefeSPatrick Mooney pthread_join(tid, NULL); 10344c87aefeSPatrick Mooney if (rc->enc_zlib_ok) 10354c87aefeSPatrick Mooney deflateEnd(&rc->zstream); 1036bf21cd93STycho Nightingale } 1037bf21cd93STycho Nightingale 1038bf21cd93STycho Nightingale static void * 1039bf21cd93STycho Nightingale rfb_thr(void *arg) 1040bf21cd93STycho Nightingale { 1041bf21cd93STycho Nightingale struct rfb_softc *rc; 1042bf21cd93STycho Nightingale sigset_t set; 1043bf21cd93STycho Nightingale 1044bf21cd93STycho Nightingale int cfd; 1045bf21cd93STycho Nightingale 1046bf21cd93STycho Nightingale rc = arg; 1047bf21cd93STycho Nightingale 1048bf21cd93STycho Nightingale sigemptyset(&set); 1049bf21cd93STycho Nightingale sigaddset(&set, SIGPIPE); 1050bf21cd93STycho Nightingale if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0) { 1051bf21cd93STycho Nightingale perror("pthread_sigmask"); 1052bf21cd93STycho Nightingale return (NULL); 1053bf21cd93STycho Nightingale } 1054bf21cd93STycho Nightingale 1055bf21cd93STycho Nightingale for (;;) { 10564c87aefeSPatrick Mooney rc->enc_raw_ok = false; 10574c87aefeSPatrick Mooney rc->enc_zlib_ok = false; 10584c87aefeSPatrick Mooney rc->enc_resize_ok = false; 10594c87aefeSPatrick Mooney 1060bf21cd93STycho Nightingale cfd = accept(rc->sfd, NULL, NULL); 10614c87aefeSPatrick Mooney if (rc->conn_wait) { 10624c87aefeSPatrick Mooney pthread_mutex_lock(&rc->mtx); 10634c87aefeSPatrick Mooney pthread_cond_signal(&rc->cond); 10644c87aefeSPatrick Mooney pthread_mutex_unlock(&rc->mtx); 10654c87aefeSPatrick Mooney rc->conn_wait = 0; 10664c87aefeSPatrick Mooney } 1067bf21cd93STycho Nightingale rfb_handle(rc, cfd); 10684c87aefeSPatrick Mooney close(cfd); 1069bf21cd93STycho Nightingale } 1070bf21cd93STycho Nightingale 1071bf21cd93STycho Nightingale /* NOTREACHED */ 1072bf21cd93STycho Nightingale return (NULL); 1073bf21cd93STycho Nightingale } 1074bf21cd93STycho Nightingale 10754c87aefeSPatrick Mooney static int 10764c87aefeSPatrick Mooney sse42_supported(void) 10774c87aefeSPatrick Mooney { 10784c87aefeSPatrick Mooney u_int cpu_registers[4], ecx; 10794c87aefeSPatrick Mooney 10804c87aefeSPatrick Mooney do_cpuid(1, cpu_registers); 10814c87aefeSPatrick Mooney 10824c87aefeSPatrick Mooney ecx = cpu_registers[2]; 10834c87aefeSPatrick Mooney 10844c87aefeSPatrick Mooney return ((ecx & CPUID2_SSE42) != 0); 10854c87aefeSPatrick Mooney } 10864c87aefeSPatrick Mooney 1087bf21cd93STycho Nightingale int 10884c87aefeSPatrick Mooney rfb_init(char *hostname, int port, int wait, char *password) 1089bf21cd93STycho Nightingale { 10904c87aefeSPatrick Mooney int e; 10914c87aefeSPatrick Mooney char servname[6]; 1092bf21cd93STycho Nightingale struct rfb_softc *rc; 109384659b24SMichael Zeller struct addrinfo *ai = NULL; 10944c87aefeSPatrick Mooney struct addrinfo hints; 1095bf21cd93STycho Nightingale int on = 1; 1096*dc8050e8SMarko Kiiskila int cnt; 10974c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 10984c87aefeSPatrick Mooney cap_rights_t rights; 10994c87aefeSPatrick Mooney #endif 1100bf21cd93STycho Nightingale 1101bf21cd93STycho Nightingale rc = calloc(1, sizeof(struct rfb_softc)); 1102bf21cd93STycho Nightingale 1103*dc8050e8SMarko Kiiskila cnt = howmany(RFB_MAX_WIDTH, PIX_PER_CELL) * 1104*dc8050e8SMarko Kiiskila howmany(RFB_MAX_HEIGHT, PIX_PER_CELL); 1105*dc8050e8SMarko Kiiskila rc->crc = calloc(cnt, sizeof(uint32_t)); 1106*dc8050e8SMarko Kiiskila rc->crc_tmp = calloc(cnt, sizeof(uint32_t)); 11074c87aefeSPatrick Mooney rc->crc_width = RFB_MAX_WIDTH; 11084c87aefeSPatrick Mooney rc->crc_height = RFB_MAX_HEIGHT; 110984659b24SMichael Zeller rc->sfd = -1; 11104c87aefeSPatrick Mooney 11114c87aefeSPatrick Mooney rc->password = password; 11124c87aefeSPatrick Mooney 11134c87aefeSPatrick Mooney snprintf(servname, sizeof(servname), "%d", port ? port : 5900); 11144c87aefeSPatrick Mooney 11154c87aefeSPatrick Mooney if (!hostname || strlen(hostname) == 0) 11164c87aefeSPatrick Mooney #if defined(INET) 11174c87aefeSPatrick Mooney hostname = "127.0.0.1"; 11184c87aefeSPatrick Mooney #elif defined(INET6) 11194c87aefeSPatrick Mooney hostname = "[::1]"; 11204c87aefeSPatrick Mooney #endif 11214c87aefeSPatrick Mooney 11224c87aefeSPatrick Mooney memset(&hints, 0, sizeof(hints)); 11234c87aefeSPatrick Mooney hints.ai_family = AF_UNSPEC; 11244c87aefeSPatrick Mooney hints.ai_socktype = SOCK_STREAM; 11254c87aefeSPatrick Mooney hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV | AI_PASSIVE; 11264c87aefeSPatrick Mooney 11274c87aefeSPatrick Mooney if ((e = getaddrinfo(hostname, servname, &hints, &ai)) != 0) { 1128154972afSPatrick Mooney EPRINTLN("getaddrinfo: %s", gai_strerror(e)); 112984659b24SMichael Zeller goto error; 11304c87aefeSPatrick Mooney } 11314c87aefeSPatrick Mooney 11324c87aefeSPatrick Mooney rc->sfd = socket(ai->ai_family, ai->ai_socktype, 0); 1133bf21cd93STycho Nightingale if (rc->sfd < 0) { 1134bf21cd93STycho Nightingale perror("socket"); 113584659b24SMichael Zeller goto error; 1136bf21cd93STycho Nightingale } 1137bf21cd93STycho Nightingale 1138bf21cd93STycho Nightingale setsockopt(rc->sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 1139bf21cd93STycho Nightingale 11404c87aefeSPatrick Mooney if (bind(rc->sfd, ai->ai_addr, ai->ai_addrlen) < 0) { 1141bf21cd93STycho Nightingale perror("bind"); 114284659b24SMichael Zeller goto error; 1143bf21cd93STycho Nightingale } 1144bf21cd93STycho Nightingale 1145bf21cd93STycho Nightingale if (listen(rc->sfd, 1) < 0) { 1146bf21cd93STycho Nightingale perror("listen"); 114784659b24SMichael Zeller goto error; 1148bf21cd93STycho Nightingale } 1149bf21cd93STycho Nightingale 11504c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 11514c87aefeSPatrick Mooney cap_rights_init(&rights, CAP_ACCEPT, CAP_EVENT, CAP_READ, CAP_WRITE); 11524c87aefeSPatrick Mooney if (caph_rights_limit(rc->sfd, &rights) == -1) 11534c87aefeSPatrick Mooney errx(EX_OSERR, "Unable to apply rights for sandbox"); 11544c87aefeSPatrick Mooney #endif 11554c87aefeSPatrick Mooney 11564c87aefeSPatrick Mooney rc->hw_crc = sse42_supported(); 11574c87aefeSPatrick Mooney 11584c87aefeSPatrick Mooney rc->conn_wait = wait; 11594c87aefeSPatrick Mooney if (wait) { 11604c87aefeSPatrick Mooney pthread_mutex_init(&rc->mtx, NULL); 11614c87aefeSPatrick Mooney pthread_cond_init(&rc->cond, NULL); 11624c87aefeSPatrick Mooney } 11634c87aefeSPatrick Mooney 1164bf21cd93STycho Nightingale pthread_create(&rc->tid, NULL, rfb_thr, rc); 11654c87aefeSPatrick Mooney pthread_set_name_np(rc->tid, "rfb"); 11664c87aefeSPatrick Mooney 11674c87aefeSPatrick Mooney if (wait) { 1168154972afSPatrick Mooney DPRINTF(("Waiting for rfb client...")); 11694c87aefeSPatrick Mooney pthread_mutex_lock(&rc->mtx); 11704c87aefeSPatrick Mooney pthread_cond_wait(&rc->cond, &rc->mtx); 11714c87aefeSPatrick Mooney pthread_mutex_unlock(&rc->mtx); 1172154972afSPatrick Mooney DPRINTF(("rfb client connected")); 11734c87aefeSPatrick Mooney } 1174bf21cd93STycho Nightingale 11754c87aefeSPatrick Mooney freeaddrinfo(ai); 1176bf21cd93STycho Nightingale return (0); 117784659b24SMichael Zeller 117884659b24SMichael Zeller error: 117984659b24SMichael Zeller if (ai != NULL) 118084659b24SMichael Zeller freeaddrinfo(ai); 118184659b24SMichael Zeller if (rc->sfd != -1) 118284659b24SMichael Zeller close(rc->sfd); 118384659b24SMichael Zeller free(rc->crc); 118484659b24SMichael Zeller free(rc->crc_tmp); 118584659b24SMichael Zeller free(rc); 118684659b24SMichael Zeller return (-1); 1187bf21cd93STycho Nightingale } 11884c87aefeSPatrick Mooney 11894c87aefeSPatrick Mooney #ifndef __FreeBSD__ 11904c87aefeSPatrick Mooney int 11914c87aefeSPatrick Mooney rfb_init_unix(char *path, int wait, char *password) 11924c87aefeSPatrick Mooney { 11934c87aefeSPatrick Mooney struct rfb_softc *rc; 11944c87aefeSPatrick Mooney struct sockaddr_un sock; 11954c87aefeSPatrick Mooney 11964c87aefeSPatrick Mooney if ((rc = calloc(1, sizeof (struct rfb_softc))) == NULL) { 11974c87aefeSPatrick Mooney perror("calloc"); 11984c87aefeSPatrick Mooney return (-1); 11994c87aefeSPatrick Mooney } 12004c87aefeSPatrick Mooney rc->sfd = -1; 12014c87aefeSPatrick Mooney 12024c87aefeSPatrick Mooney if ((rc->crc = calloc(howmany(RFB_MAX_WIDTH * RFB_MAX_HEIGHT, 32), 12034c87aefeSPatrick Mooney sizeof (uint32_t))) == NULL) { 12044c87aefeSPatrick Mooney perror("calloc"); 12054c87aefeSPatrick Mooney goto fail; 12064c87aefeSPatrick Mooney } 12074c87aefeSPatrick Mooney if ((rc->crc_tmp = calloc(howmany(RFB_MAX_WIDTH * RFB_MAX_HEIGHT, 32), 12084c87aefeSPatrick Mooney sizeof (uint32_t))) == NULL) { 12094c87aefeSPatrick Mooney perror("calloc"); 12104c87aefeSPatrick Mooney goto fail; 12114c87aefeSPatrick Mooney } 12124c87aefeSPatrick Mooney rc->crc_width = RFB_MAX_WIDTH; 12134c87aefeSPatrick Mooney rc->crc_height = RFB_MAX_HEIGHT; 12144c87aefeSPatrick Mooney 12154c87aefeSPatrick Mooney rc->password = password; 12164c87aefeSPatrick Mooney 12174c87aefeSPatrick Mooney rc->sfd = socket(PF_UNIX, SOCK_STREAM, 0); 12184c87aefeSPatrick Mooney if (rc->sfd < 0) { 12194c87aefeSPatrick Mooney perror("socket"); 12204c87aefeSPatrick Mooney goto fail; 12214c87aefeSPatrick Mooney } 12224c87aefeSPatrick Mooney 12234c87aefeSPatrick Mooney sock.sun_family = AF_UNIX; 12244c87aefeSPatrick Mooney if (strlcpy(sock.sun_path, path, sizeof (sock.sun_path)) >= 12254c87aefeSPatrick Mooney sizeof (sock.sun_path)) { 12264c87aefeSPatrick Mooney (void) fprintf(stderr, "socket path '%s' too long\n", path); 12274c87aefeSPatrick Mooney goto fail; 12284c87aefeSPatrick Mooney } 12294c87aefeSPatrick Mooney 12304c87aefeSPatrick Mooney (void) unlink(path); 12314c87aefeSPatrick Mooney if (bind(rc->sfd, (struct sockaddr *)&sock, sizeof (sock)) < 0) { 12324c87aefeSPatrick Mooney perror("bind"); 12334c87aefeSPatrick Mooney goto fail; 12344c87aefeSPatrick Mooney } 12354c87aefeSPatrick Mooney 12364c87aefeSPatrick Mooney if (listen(rc->sfd, 1) < 0) { 12374c87aefeSPatrick Mooney perror("listen"); 12384c87aefeSPatrick Mooney goto fail; 12394c87aefeSPatrick Mooney } 12404c87aefeSPatrick Mooney 12414c87aefeSPatrick Mooney rc->hw_crc = sse42_supported(); 12424c87aefeSPatrick Mooney 12434c87aefeSPatrick Mooney rc->conn_wait = wait; 12444c87aefeSPatrick Mooney if (wait) { 12454c87aefeSPatrick Mooney VERIFY3S(pthread_mutex_init(&rc->mtx, NULL), ==, 0); 12464c87aefeSPatrick Mooney VERIFY3S(pthread_cond_init(&rc->cond, NULL), ==, 0); 12474c87aefeSPatrick Mooney } 12484c87aefeSPatrick Mooney 12494c87aefeSPatrick Mooney VERIFY3S(pthread_create(&rc->tid, NULL, rfb_thr, rc), ==, 0); 12504c87aefeSPatrick Mooney pthread_set_name_np(rc->tid, "rfb"); 12514c87aefeSPatrick Mooney 12524c87aefeSPatrick Mooney if (wait) { 12534c87aefeSPatrick Mooney DPRINTF(("Waiting for rfb client...\n")); 12544c87aefeSPatrick Mooney VERIFY3S(pthread_mutex_lock(&rc->mtx), ==, 0); 12554c87aefeSPatrick Mooney VERIFY3S(pthread_cond_wait(&rc->cond, &rc->mtx), ==, 0); 12564c87aefeSPatrick Mooney VERIFY3S(pthread_mutex_unlock(&rc->mtx), ==, 0); 12574c87aefeSPatrick Mooney } 12584c87aefeSPatrick Mooney 12594c87aefeSPatrick Mooney return (0); 12604c87aefeSPatrick Mooney 12614c87aefeSPatrick Mooney fail: 12624c87aefeSPatrick Mooney if (rc->sfd != -1) { 12634c87aefeSPatrick Mooney VERIFY3S(close(rc->sfd), ==, 0); 12644c87aefeSPatrick Mooney } 12654c87aefeSPatrick Mooney free(rc->crc); 12664c87aefeSPatrick Mooney free(rc->crc_tmp); 12674c87aefeSPatrick Mooney free(rc); 12684c87aefeSPatrick Mooney return (-1); 12694c87aefeSPatrick Mooney } 12704c87aefeSPatrick Mooney #endif 1271