xref: /illumos-gate/usr/src/cmd/bhyve/rfb.c (revision 84659b24)
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>
434c87aefeSPatrick Mooney #include <machine/cpufunc.h>
444c87aefeSPatrick Mooney #include <machine/specialreg.h>
45bf21cd93STycho Nightingale #include <netinet/in.h>
464c87aefeSPatrick Mooney #include <netdb.h>
47bf21cd93STycho Nightingale 
48bf21cd93STycho Nightingale #include <assert.h>
494c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
504c87aefeSPatrick Mooney #include <capsicum_helpers.h>
514c87aefeSPatrick Mooney #endif
524c87aefeSPatrick Mooney #include <err.h>
534c87aefeSPatrick Mooney #include <errno.h>
54bf21cd93STycho Nightingale #include <pthread.h>
554c87aefeSPatrick Mooney #include <pthread_np.h>
56bf21cd93STycho Nightingale #include <signal.h>
57bf21cd93STycho Nightingale #include <stdbool.h>
58bf21cd93STycho Nightingale #include <stdlib.h>
59bf21cd93STycho Nightingale #include <stdio.h>
60bf21cd93STycho Nightingale #include <string.h>
614c87aefeSPatrick Mooney #include <sysexits.h>
62bf21cd93STycho Nightingale #include <unistd.h>
63bf21cd93STycho Nightingale 
644c87aefeSPatrick Mooney #include <zlib.h>
654c87aefeSPatrick Mooney 
664c87aefeSPatrick Mooney #ifndef __FreeBSD__
674c87aefeSPatrick Mooney #include <sys/debug.h>
684c87aefeSPatrick Mooney #endif
694c87aefeSPatrick Mooney 
70bf21cd93STycho Nightingale #include "bhyvegc.h"
71bf21cd93STycho Nightingale #include "console.h"
72bf21cd93STycho Nightingale #include "rfb.h"
734c87aefeSPatrick Mooney #include "sockstream.h"
744c87aefeSPatrick Mooney 
754c87aefeSPatrick Mooney #ifndef NO_OPENSSL
764c87aefeSPatrick Mooney #include <openssl/des.h>
774c87aefeSPatrick Mooney #endif
784c87aefeSPatrick Mooney 
794c87aefeSPatrick Mooney static int rfb_debug = 0;
804c87aefeSPatrick Mooney #define	DPRINTF(params) if (rfb_debug) printf params
814c87aefeSPatrick Mooney #define	WPRINTF(params) printf params
824c87aefeSPatrick Mooney 
834c87aefeSPatrick Mooney #define AUTH_LENGTH	16
844c87aefeSPatrick Mooney #define PASSWD_LENGTH	8
854c87aefeSPatrick Mooney 
864c87aefeSPatrick Mooney #define SECURITY_TYPE_NONE	1
874c87aefeSPatrick Mooney #define SECURITY_TYPE_VNC_AUTH	2
884c87aefeSPatrick Mooney 
894c87aefeSPatrick Mooney #define AUTH_FAILED_UNAUTH	1
904c87aefeSPatrick Mooney #define AUTH_FAILED_ERROR	2
91bf21cd93STycho Nightingale 
92bf21cd93STycho Nightingale struct rfb_softc {
93bf21cd93STycho Nightingale 	int		sfd;
94bf21cd93STycho Nightingale 	pthread_t	tid;
95bf21cd93STycho Nightingale 
964c87aefeSPatrick Mooney 	int		cfd;
974c87aefeSPatrick Mooney 
98bf21cd93STycho Nightingale 	int		width, height;
99bf21cd93STycho Nightingale 
1004c87aefeSPatrick Mooney 	char		*password;
1014c87aefeSPatrick Mooney 
1024c87aefeSPatrick Mooney 	bool	enc_raw_ok;
1034c87aefeSPatrick Mooney 	bool	enc_zlib_ok;
1044c87aefeSPatrick Mooney 	bool	enc_resize_ok;
1054c87aefeSPatrick Mooney 
1064c87aefeSPatrick Mooney 	z_stream	zstream;
1074c87aefeSPatrick Mooney 	uint8_t		*zbuf;
1084c87aefeSPatrick Mooney 	int		zbuflen;
1094c87aefeSPatrick Mooney 
1104c87aefeSPatrick Mooney 	int		conn_wait;
1114c87aefeSPatrick Mooney 	int		sending;
1124c87aefeSPatrick Mooney 	pthread_mutex_t mtx;
1134c87aefeSPatrick Mooney 	pthread_cond_t  cond;
1144c87aefeSPatrick Mooney 
1154c87aefeSPatrick Mooney 	int		hw_crc;
1164c87aefeSPatrick Mooney 	uint32_t	*crc;		/* WxH crc cells */
1174c87aefeSPatrick Mooney 	uint32_t	*crc_tmp;	/* buffer to store single crc row */
1184c87aefeSPatrick Mooney 	int		crc_width, crc_height;
119bf21cd93STycho Nightingale };
120bf21cd93STycho Nightingale 
121bf21cd93STycho Nightingale struct rfb_pixfmt {
122bf21cd93STycho Nightingale 	uint8_t		bpp;
123bf21cd93STycho Nightingale 	uint8_t		depth;
124bf21cd93STycho Nightingale 	uint8_t		bigendian;
125bf21cd93STycho Nightingale 	uint8_t		truecolor;
126bf21cd93STycho Nightingale 	uint16_t	red_max;
127bf21cd93STycho Nightingale 	uint16_t	green_max;
128bf21cd93STycho Nightingale 	uint16_t	blue_max;
129bf21cd93STycho Nightingale 	uint8_t		red_shift;
130bf21cd93STycho Nightingale 	uint8_t		green_shift;
131bf21cd93STycho Nightingale 	uint8_t		blue_shift;
132bf21cd93STycho Nightingale 	uint8_t		pad[3];
133bf21cd93STycho Nightingale };
134bf21cd93STycho Nightingale 
135bf21cd93STycho Nightingale struct rfb_srvr_info {
136bf21cd93STycho Nightingale 	uint16_t		width;
137bf21cd93STycho Nightingale 	uint16_t		height;
138bf21cd93STycho Nightingale 	struct rfb_pixfmt	pixfmt;
139bf21cd93STycho Nightingale 	uint32_t		namelen;
140bf21cd93STycho Nightingale };
141bf21cd93STycho Nightingale 
142bf21cd93STycho Nightingale struct rfb_pixfmt_msg {
143bf21cd93STycho Nightingale 	uint8_t			type;
144bf21cd93STycho Nightingale 	uint8_t			pad[3];
145bf21cd93STycho Nightingale 	struct rfb_pixfmt	pixfmt;
146bf21cd93STycho Nightingale };
147bf21cd93STycho Nightingale 
148bf21cd93STycho Nightingale #define	RFB_ENCODING_RAW		0
1494c87aefeSPatrick Mooney #define	RFB_ENCODING_ZLIB		6
150bf21cd93STycho Nightingale #define	RFB_ENCODING_RESIZE		-223
151bf21cd93STycho Nightingale 
1524c87aefeSPatrick Mooney #define	RFB_MAX_WIDTH			2000
1534c87aefeSPatrick Mooney #define	RFB_MAX_HEIGHT			1200
1544c87aefeSPatrick Mooney #define	RFB_ZLIB_BUFSZ			RFB_MAX_WIDTH*RFB_MAX_HEIGHT*4
1554c87aefeSPatrick Mooney 
1564c87aefeSPatrick Mooney /* percentage changes to screen before sending the entire screen */
1574c87aefeSPatrick Mooney #define	RFB_SEND_ALL_THRESH		25
1584c87aefeSPatrick Mooney 
159bf21cd93STycho Nightingale struct rfb_enc_msg {
160bf21cd93STycho Nightingale 	uint8_t		type;
161bf21cd93STycho Nightingale 	uint8_t		pad;
162bf21cd93STycho Nightingale 	uint16_t	numencs;
163bf21cd93STycho Nightingale };
164bf21cd93STycho Nightingale 
165bf21cd93STycho Nightingale struct rfb_updt_msg {
166bf21cd93STycho Nightingale 	uint8_t		type;
167bf21cd93STycho Nightingale 	uint8_t		incremental;
168bf21cd93STycho Nightingale 	uint16_t	x;
169bf21cd93STycho Nightingale 	uint16_t	y;
170bf21cd93STycho Nightingale 	uint16_t	width;
171bf21cd93STycho Nightingale 	uint16_t	height;
172bf21cd93STycho Nightingale };
173bf21cd93STycho Nightingale 
174bf21cd93STycho Nightingale struct rfb_key_msg {
175bf21cd93STycho Nightingale 	uint8_t		type;
176bf21cd93STycho Nightingale 	uint8_t		down;
177bf21cd93STycho Nightingale 	uint16_t	pad;
178bf21cd93STycho Nightingale 	uint32_t	code;
179bf21cd93STycho Nightingale };
180bf21cd93STycho Nightingale 
181bf21cd93STycho Nightingale struct rfb_ptr_msg {
182bf21cd93STycho Nightingale 	uint8_t		type;
183bf21cd93STycho Nightingale 	uint8_t		button;
184bf21cd93STycho Nightingale 	uint16_t	x;
185bf21cd93STycho Nightingale 	uint16_t	y;
186bf21cd93STycho Nightingale };
187bf21cd93STycho Nightingale 
188bf21cd93STycho Nightingale struct rfb_srvr_updt_msg {
189bf21cd93STycho Nightingale 	uint8_t		type;
190bf21cd93STycho Nightingale 	uint8_t		pad;
191bf21cd93STycho Nightingale 	uint16_t	numrects;
192bf21cd93STycho Nightingale };
193bf21cd93STycho Nightingale 
194bf21cd93STycho Nightingale struct rfb_srvr_rect_hdr {
195bf21cd93STycho Nightingale 	uint16_t	x;
196bf21cd93STycho Nightingale 	uint16_t	y;
197bf21cd93STycho Nightingale 	uint16_t	width;
198bf21cd93STycho Nightingale 	uint16_t	height;
199bf21cd93STycho Nightingale 	uint32_t	encoding;
200bf21cd93STycho Nightingale };
201bf21cd93STycho Nightingale 
2024c87aefeSPatrick Mooney struct rfb_cuttext_msg {
2034c87aefeSPatrick Mooney 	uint8_t		type;
2044c87aefeSPatrick Mooney 	uint8_t		padding[3];
2054c87aefeSPatrick Mooney 	uint32_t	length;
2064c87aefeSPatrick Mooney };
2074c87aefeSPatrick Mooney 
2084c87aefeSPatrick Mooney 
209bf21cd93STycho Nightingale static void
210bf21cd93STycho Nightingale rfb_send_server_init_msg(int cfd)
211bf21cd93STycho Nightingale {
212bf21cd93STycho Nightingale 	struct bhyvegc_image *gc_image;
213bf21cd93STycho Nightingale 	struct rfb_srvr_info sinfo;
214bf21cd93STycho Nightingale 
215bf21cd93STycho Nightingale 	gc_image = console_get_image();
216bf21cd93STycho Nightingale 
2174c87aefeSPatrick Mooney 	sinfo.width = htons(gc_image->width);
2184c87aefeSPatrick Mooney 	sinfo.height = htons(gc_image->height);
219bf21cd93STycho Nightingale 	sinfo.pixfmt.bpp = 32;
220bf21cd93STycho Nightingale 	sinfo.pixfmt.depth = 32;
221bf21cd93STycho Nightingale 	sinfo.pixfmt.bigendian = 0;
222bf21cd93STycho Nightingale 	sinfo.pixfmt.truecolor = 1;
2234c87aefeSPatrick Mooney 	sinfo.pixfmt.red_max = htons(255);
2244c87aefeSPatrick Mooney 	sinfo.pixfmt.green_max = htons(255);
2254c87aefeSPatrick Mooney 	sinfo.pixfmt.blue_max = htons(255);
226bf21cd93STycho Nightingale 	sinfo.pixfmt.red_shift = 16;
227bf21cd93STycho Nightingale 	sinfo.pixfmt.green_shift = 8;
228bf21cd93STycho Nightingale 	sinfo.pixfmt.blue_shift = 0;
2294c87aefeSPatrick Mooney 	sinfo.namelen = htonl(strlen("bhyve"));
2304c87aefeSPatrick Mooney 	(void)stream_write(cfd, &sinfo, sizeof(sinfo));
2314c87aefeSPatrick Mooney 	(void)stream_write(cfd, "bhyve", strlen("bhyve"));
232bf21cd93STycho Nightingale }
233bf21cd93STycho Nightingale 
234bf21cd93STycho Nightingale static void
235bf21cd93STycho Nightingale rfb_send_resize_update_msg(struct rfb_softc *rc, int cfd)
236bf21cd93STycho Nightingale {
237bf21cd93STycho Nightingale 	struct rfb_srvr_updt_msg supdt_msg;
2384c87aefeSPatrick Mooney 	struct rfb_srvr_rect_hdr srect_hdr;
239bf21cd93STycho Nightingale 
240bf21cd93STycho Nightingale 	/* Number of rectangles: 1 */
241bf21cd93STycho Nightingale 	supdt_msg.type = 0;
242bf21cd93STycho Nightingale 	supdt_msg.pad = 0;
2434c87aefeSPatrick Mooney 	supdt_msg.numrects = htons(1);
2444c87aefeSPatrick Mooney 	stream_write(cfd, &supdt_msg, sizeof(struct rfb_srvr_updt_msg));
245bf21cd93STycho Nightingale 
246bf21cd93STycho Nightingale 	/* Rectangle header */
2474c87aefeSPatrick Mooney 	srect_hdr.x = htons(0);
2484c87aefeSPatrick Mooney 	srect_hdr.y = htons(0);
2494c87aefeSPatrick Mooney 	srect_hdr.width = htons(rc->width);
2504c87aefeSPatrick Mooney 	srect_hdr.height = htons(rc->height);
2514c87aefeSPatrick Mooney 	srect_hdr.encoding = htonl(RFB_ENCODING_RESIZE);
2524c87aefeSPatrick Mooney 	stream_write(cfd, &srect_hdr, sizeof(struct rfb_srvr_rect_hdr));
253bf21cd93STycho Nightingale }
254bf21cd93STycho Nightingale 
255bf21cd93STycho Nightingale static void
256bf21cd93STycho Nightingale rfb_recv_set_pixfmt_msg(struct rfb_softc *rc, int cfd)
257bf21cd93STycho Nightingale {
258bf21cd93STycho Nightingale 	struct rfb_pixfmt_msg pixfmt_msg;
259bf21cd93STycho Nightingale 
2604c87aefeSPatrick Mooney 	(void)stream_read(cfd, ((void *)&pixfmt_msg)+1, sizeof(pixfmt_msg)-1);
261bf21cd93STycho Nightingale }
262bf21cd93STycho Nightingale 
263bf21cd93STycho Nightingale 
264bf21cd93STycho Nightingale static void
265bf21cd93STycho Nightingale rfb_recv_set_encodings_msg(struct rfb_softc *rc, int cfd)
266bf21cd93STycho Nightingale {
267bf21cd93STycho Nightingale 	struct rfb_enc_msg enc_msg;
2684c87aefeSPatrick Mooney 	int i;
269bf21cd93STycho Nightingale 	uint32_t encoding;
270bf21cd93STycho Nightingale 
271bf21cd93STycho Nightingale 	assert((sizeof(enc_msg) - 1) == 3);
2724c87aefeSPatrick Mooney 	(void)stream_read(cfd, ((void *)&enc_msg)+1, sizeof(enc_msg)-1);
273bf21cd93STycho Nightingale 
2744c87aefeSPatrick Mooney 	for (i = 0; i < htons(enc_msg.numencs); i++) {
2754c87aefeSPatrick Mooney 		(void)stream_read(cfd, &encoding, sizeof(encoding));
2764c87aefeSPatrick Mooney 		switch (htonl(encoding)) {
277bf21cd93STycho Nightingale 		case RFB_ENCODING_RAW:
278bf21cd93STycho Nightingale 			rc->enc_raw_ok = true;
279bf21cd93STycho Nightingale 			break;
2804c87aefeSPatrick Mooney 		case RFB_ENCODING_ZLIB:
281*84659b24SMichael Zeller 			if (!rc->enc_zlib_ok) {
282*84659b24SMichael Zeller 				deflateInit(&rc->zstream, Z_BEST_SPEED);
283*84659b24SMichael Zeller 				rc->enc_zlib_ok = true;
284*84659b24SMichael Zeller 			}
2854c87aefeSPatrick Mooney 			break;
286bf21cd93STycho Nightingale 		case RFB_ENCODING_RESIZE:
287bf21cd93STycho Nightingale 			rc->enc_resize_ok = true;
288bf21cd93STycho Nightingale 			break;
289bf21cd93STycho Nightingale 		}
290bf21cd93STycho Nightingale 	}
291bf21cd93STycho Nightingale }
292bf21cd93STycho Nightingale 
2934c87aefeSPatrick Mooney /*
2944c87aefeSPatrick Mooney  * Calculate CRC32 using SSE4.2; Intel or AMD Bulldozer+ CPUs only
2954c87aefeSPatrick Mooney  */
2964c87aefeSPatrick Mooney static __inline uint32_t
2974c87aefeSPatrick Mooney fast_crc32(void *buf, int len, uint32_t crcval)
2984c87aefeSPatrick Mooney {
2994c87aefeSPatrick Mooney 	uint32_t q = len / sizeof(uint32_t);
3004c87aefeSPatrick Mooney 	uint32_t *p = (uint32_t *)buf;
3014c87aefeSPatrick Mooney 
3024c87aefeSPatrick Mooney 	while (q--) {
3034c87aefeSPatrick Mooney 		asm volatile (
3044c87aefeSPatrick Mooney 			".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;"
3054c87aefeSPatrick Mooney 			:"=S" (crcval)
3064c87aefeSPatrick Mooney 			:"0" (crcval), "c" (*p)
3074c87aefeSPatrick Mooney 		);
3084c87aefeSPatrick Mooney 		p++;
3094c87aefeSPatrick Mooney 	}
3104c87aefeSPatrick Mooney 
3114c87aefeSPatrick Mooney 	return (crcval);
3124c87aefeSPatrick Mooney }
3134c87aefeSPatrick Mooney 
3144c87aefeSPatrick Mooney 
3154c87aefeSPatrick Mooney static int
3164c87aefeSPatrick Mooney rfb_send_rect(struct rfb_softc *rc, int cfd, struct bhyvegc_image *gc,
3174c87aefeSPatrick Mooney               int x, int y, int w, int h)
3184c87aefeSPatrick Mooney {
3194c87aefeSPatrick Mooney 	struct rfb_srvr_updt_msg supdt_msg;
3204c87aefeSPatrick Mooney 	struct rfb_srvr_rect_hdr srect_hdr;
3214c87aefeSPatrick Mooney 	unsigned long zlen;
3224c87aefeSPatrick Mooney 	ssize_t nwrite, total;
3234c87aefeSPatrick Mooney 	int err;
3244c87aefeSPatrick Mooney 	uint32_t *p;
3254c87aefeSPatrick Mooney 	uint8_t *zbufp;
3264c87aefeSPatrick Mooney 
3274c87aefeSPatrick Mooney 	/*
3284c87aefeSPatrick Mooney 	 * Send a single rectangle of the given x, y, w h dimensions.
3294c87aefeSPatrick Mooney 	 */
3304c87aefeSPatrick Mooney 
3314c87aefeSPatrick Mooney 	/* Number of rectangles: 1 */
3324c87aefeSPatrick Mooney 	supdt_msg.type = 0;
3334c87aefeSPatrick Mooney 	supdt_msg.pad = 0;
3344c87aefeSPatrick Mooney 	supdt_msg.numrects = htons(1);
3354c87aefeSPatrick Mooney 	nwrite = stream_write(cfd, &supdt_msg,
3364c87aefeSPatrick Mooney 	                      sizeof(struct rfb_srvr_updt_msg));
3374c87aefeSPatrick Mooney 	if (nwrite <= 0)
3384c87aefeSPatrick Mooney 		return (nwrite);
3394c87aefeSPatrick Mooney 
3404c87aefeSPatrick Mooney 
3414c87aefeSPatrick Mooney 	/* Rectangle header */
3424c87aefeSPatrick Mooney 	srect_hdr.x = htons(x);
3434c87aefeSPatrick Mooney 	srect_hdr.y = htons(y);
3444c87aefeSPatrick Mooney 	srect_hdr.width = htons(w);
3454c87aefeSPatrick Mooney 	srect_hdr.height = htons(h);
3464c87aefeSPatrick Mooney 
3474c87aefeSPatrick Mooney 	h = y + h;
3484c87aefeSPatrick Mooney 	w *= sizeof(uint32_t);
3494c87aefeSPatrick Mooney 	if (rc->enc_zlib_ok) {
3504c87aefeSPatrick Mooney 		zbufp = rc->zbuf;
3514c87aefeSPatrick Mooney 		rc->zstream.total_in = 0;
3524c87aefeSPatrick Mooney 		rc->zstream.total_out = 0;
3534c87aefeSPatrick Mooney 		for (p = &gc->data[y * gc->width + x]; y < h; y++) {
3544c87aefeSPatrick Mooney 			rc->zstream.next_in = (Bytef *)p;
3554c87aefeSPatrick Mooney 			rc->zstream.avail_in = w;
3564c87aefeSPatrick Mooney 			rc->zstream.next_out = (Bytef *)zbufp;
3574c87aefeSPatrick Mooney 			rc->zstream.avail_out = RFB_ZLIB_BUFSZ + 16 -
3584c87aefeSPatrick Mooney 			                        rc->zstream.total_out;
3594c87aefeSPatrick Mooney 			rc->zstream.data_type = Z_BINARY;
3604c87aefeSPatrick Mooney 
3614c87aefeSPatrick Mooney 			/* Compress with zlib */
3624c87aefeSPatrick Mooney 			err = deflate(&rc->zstream, Z_SYNC_FLUSH);
3634c87aefeSPatrick Mooney 			if (err != Z_OK) {
3644c87aefeSPatrick Mooney 				WPRINTF(("zlib[rect] deflate err: %d\n", err));
3654c87aefeSPatrick Mooney 				rc->enc_zlib_ok = false;
3664c87aefeSPatrick Mooney 				deflateEnd(&rc->zstream);
3674c87aefeSPatrick Mooney 				goto doraw;
3684c87aefeSPatrick Mooney 			}
3694c87aefeSPatrick Mooney 			zbufp = rc->zbuf + rc->zstream.total_out;
3704c87aefeSPatrick Mooney 			p += gc->width;
3714c87aefeSPatrick Mooney 		}
3724c87aefeSPatrick Mooney 		srect_hdr.encoding = htonl(RFB_ENCODING_ZLIB);
3734c87aefeSPatrick Mooney 		nwrite = stream_write(cfd, &srect_hdr,
3744c87aefeSPatrick Mooney 		                      sizeof(struct rfb_srvr_rect_hdr));
3754c87aefeSPatrick Mooney 		if (nwrite <= 0)
3764c87aefeSPatrick Mooney 			return (nwrite);
3774c87aefeSPatrick Mooney 
3784c87aefeSPatrick Mooney 		zlen = htonl(rc->zstream.total_out);
3794c87aefeSPatrick Mooney 		nwrite = stream_write(cfd, &zlen, sizeof(uint32_t));
3804c87aefeSPatrick Mooney 		if (nwrite <= 0)
3814c87aefeSPatrick Mooney 			return (nwrite);
3824c87aefeSPatrick Mooney 		return (stream_write(cfd, rc->zbuf, rc->zstream.total_out));
3834c87aefeSPatrick Mooney 	}
3844c87aefeSPatrick Mooney 
3854c87aefeSPatrick Mooney doraw:
3864c87aefeSPatrick Mooney 
3874c87aefeSPatrick Mooney 	total = 0;
3884c87aefeSPatrick Mooney 	zbufp = rc->zbuf;
3894c87aefeSPatrick Mooney 	for (p = &gc->data[y * gc->width + x]; y < h; y++) {
3904c87aefeSPatrick Mooney 		memcpy(zbufp, p, w);
3914c87aefeSPatrick Mooney 		zbufp += w;
3924c87aefeSPatrick Mooney 		total += w;
3934c87aefeSPatrick Mooney 		p += gc->width;
3944c87aefeSPatrick Mooney 	}
3954c87aefeSPatrick Mooney 
3964c87aefeSPatrick Mooney 	srect_hdr.encoding = htonl(RFB_ENCODING_RAW);
3974c87aefeSPatrick Mooney 	nwrite = stream_write(cfd, &srect_hdr,
3984c87aefeSPatrick Mooney 	                      sizeof(struct rfb_srvr_rect_hdr));
3994c87aefeSPatrick Mooney 	if (nwrite <= 0)
4004c87aefeSPatrick Mooney 		return (nwrite);
4014c87aefeSPatrick Mooney 
4024c87aefeSPatrick Mooney 	total = stream_write(cfd, rc->zbuf, total);
4034c87aefeSPatrick Mooney 
4044c87aefeSPatrick Mooney 	return (total);
4054c87aefeSPatrick Mooney }
4064c87aefeSPatrick Mooney 
4074c87aefeSPatrick Mooney static int
4084c87aefeSPatrick Mooney rfb_send_all(struct rfb_softc *rc, int cfd, struct bhyvegc_image *gc)
409bf21cd93STycho Nightingale {
410bf21cd93STycho Nightingale 	struct rfb_srvr_updt_msg supdt_msg;
411bf21cd93STycho Nightingale         struct rfb_srvr_rect_hdr srect_hdr;
4124c87aefeSPatrick Mooney 	ssize_t nwrite;
4134c87aefeSPatrick Mooney 	unsigned long zlen;
4144c87aefeSPatrick Mooney 	int err;
4154c87aefeSPatrick Mooney 
4164c87aefeSPatrick Mooney 	/*
4174c87aefeSPatrick Mooney 	 * Send the whole thing
4184c87aefeSPatrick Mooney 	 */
419bf21cd93STycho Nightingale 
420bf21cd93STycho Nightingale 	/* Number of rectangles: 1 */
421bf21cd93STycho Nightingale 	supdt_msg.type = 0;
422bf21cd93STycho Nightingale 	supdt_msg.pad = 0;
4234c87aefeSPatrick Mooney 	supdt_msg.numrects = htons(1);
4244c87aefeSPatrick Mooney 	nwrite = stream_write(cfd, &supdt_msg,
4254c87aefeSPatrick Mooney 	                      sizeof(struct rfb_srvr_updt_msg));
4264c87aefeSPatrick Mooney 	if (nwrite <= 0)
4274c87aefeSPatrick Mooney 		return (nwrite);
428bf21cd93STycho Nightingale 
429bf21cd93STycho Nightingale 	/* Rectangle header */
4304c87aefeSPatrick Mooney 	srect_hdr.x = 0;
4314c87aefeSPatrick Mooney 	srect_hdr.y = 0;
4324c87aefeSPatrick Mooney 	srect_hdr.width = htons(gc->width);
4334c87aefeSPatrick Mooney 	srect_hdr.height = htons(gc->height);
4344c87aefeSPatrick Mooney 	if (rc->enc_zlib_ok) {
4354c87aefeSPatrick Mooney 		rc->zstream.next_in = (Bytef *)gc->data;
4364c87aefeSPatrick Mooney 		rc->zstream.avail_in = gc->width * gc->height *
4374c87aefeSPatrick Mooney 		                   sizeof(uint32_t);
4384c87aefeSPatrick Mooney 		rc->zstream.next_out = (Bytef *)rc->zbuf;
4394c87aefeSPatrick Mooney 		rc->zstream.avail_out = RFB_ZLIB_BUFSZ + 16;
4404c87aefeSPatrick Mooney 		rc->zstream.data_type = Z_BINARY;
4414c87aefeSPatrick Mooney 
4424c87aefeSPatrick Mooney 		rc->zstream.total_in = 0;
4434c87aefeSPatrick Mooney 		rc->zstream.total_out = 0;
4444c87aefeSPatrick Mooney 
4454c87aefeSPatrick Mooney 		/* Compress with zlib */
4464c87aefeSPatrick Mooney 		err = deflate(&rc->zstream, Z_SYNC_FLUSH);
4474c87aefeSPatrick Mooney 		if (err != Z_OK) {
4484c87aefeSPatrick Mooney 			WPRINTF(("zlib deflate err: %d\n", err));
4494c87aefeSPatrick Mooney 			rc->enc_zlib_ok = false;
4504c87aefeSPatrick Mooney 			deflateEnd(&rc->zstream);
4514c87aefeSPatrick Mooney 			goto doraw;
4524c87aefeSPatrick Mooney 		}
4534c87aefeSPatrick Mooney 
4544c87aefeSPatrick Mooney 		srect_hdr.encoding = htonl(RFB_ENCODING_ZLIB);
4554c87aefeSPatrick Mooney 		nwrite = stream_write(cfd, &srect_hdr,
4564c87aefeSPatrick Mooney 		                      sizeof(struct rfb_srvr_rect_hdr));
4574c87aefeSPatrick Mooney 		if (nwrite <= 0)
4584c87aefeSPatrick Mooney 			return (nwrite);
4594c87aefeSPatrick Mooney 
4604c87aefeSPatrick Mooney 		zlen = htonl(rc->zstream.total_out);
4614c87aefeSPatrick Mooney 		nwrite = stream_write(cfd, &zlen, sizeof(uint32_t));
4624c87aefeSPatrick Mooney 		if (nwrite <= 0)
4634c87aefeSPatrick Mooney 			return (nwrite);
4644c87aefeSPatrick Mooney 		return (stream_write(cfd, rc->zbuf, rc->zstream.total_out));
4654c87aefeSPatrick Mooney 	}
4664c87aefeSPatrick Mooney 
4674c87aefeSPatrick Mooney doraw:
4684c87aefeSPatrick Mooney 	srect_hdr.encoding = htonl(RFB_ENCODING_RAW);
4694c87aefeSPatrick Mooney 	nwrite = stream_write(cfd, &srect_hdr,
4704c87aefeSPatrick Mooney 	                      sizeof(struct rfb_srvr_rect_hdr));
4714c87aefeSPatrick Mooney 	if (nwrite <= 0)
4724c87aefeSPatrick Mooney 		return (nwrite);
4734c87aefeSPatrick Mooney 
4744c87aefeSPatrick Mooney 	nwrite = stream_write(cfd, gc->data,
4754c87aefeSPatrick Mooney 	               gc->width * gc->height * sizeof(uint32_t));
4764c87aefeSPatrick Mooney 
4774c87aefeSPatrick Mooney 	return (nwrite);
478bf21cd93STycho Nightingale }
479bf21cd93STycho Nightingale 
4804c87aefeSPatrick Mooney #define	PIX_PER_CELL	32
4814c87aefeSPatrick Mooney #define	PIXCELL_SHIFT	5
4824c87aefeSPatrick Mooney #define	PIXCELL_MASK	0x1F
4834c87aefeSPatrick Mooney 
4844c87aefeSPatrick Mooney static int
4854c87aefeSPatrick Mooney rfb_send_screen(struct rfb_softc *rc, int cfd, int all)
4864c87aefeSPatrick Mooney {
4874c87aefeSPatrick Mooney 	struct bhyvegc_image *gc_image;
4884c87aefeSPatrick Mooney 	ssize_t nwrite;
4894c87aefeSPatrick Mooney 	int x, y;
4904c87aefeSPatrick Mooney 	int celly, cellwidth;
4914c87aefeSPatrick Mooney 	int xcells, ycells;
4924c87aefeSPatrick Mooney 	int w, h;
4934c87aefeSPatrick Mooney 	uint32_t *p;
4944c87aefeSPatrick Mooney 	int rem_x, rem_y;   /* remainder for resolutions not x32 pixels ratio */
4954c87aefeSPatrick Mooney 	int retval;
4964c87aefeSPatrick Mooney 	uint32_t *crc_p, *orig_crc;
4974c87aefeSPatrick Mooney 	int changes;
4984c87aefeSPatrick Mooney 
4994c87aefeSPatrick Mooney 	console_refresh();
5004c87aefeSPatrick Mooney 	gc_image = console_get_image();
5014c87aefeSPatrick Mooney 
5024c87aefeSPatrick Mooney 	pthread_mutex_lock(&rc->mtx);
5034c87aefeSPatrick Mooney 	if (rc->sending) {
5044c87aefeSPatrick Mooney 		pthread_mutex_unlock(&rc->mtx);
5054c87aefeSPatrick Mooney 		return (1);
5064c87aefeSPatrick Mooney 	}
5074c87aefeSPatrick Mooney 	rc->sending = 1;
5084c87aefeSPatrick Mooney 	pthread_mutex_unlock(&rc->mtx);
5094c87aefeSPatrick Mooney 
5104c87aefeSPatrick Mooney 	retval = 0;
5114c87aefeSPatrick Mooney 
5124c87aefeSPatrick Mooney 	if (all) {
5134c87aefeSPatrick Mooney 		retval = rfb_send_all(rc, cfd, gc_image);
5144c87aefeSPatrick Mooney 		goto done;
5154c87aefeSPatrick Mooney 	}
5164c87aefeSPatrick Mooney 
5174c87aefeSPatrick Mooney 	/*
5184c87aefeSPatrick Mooney 	 * Calculate the checksum for each 32x32 cell. Send each that
5194c87aefeSPatrick Mooney 	 * has changed since the last scan.
5204c87aefeSPatrick Mooney 	 */
5214c87aefeSPatrick Mooney 
5224c87aefeSPatrick Mooney 	/* Resolution changed */
5234c87aefeSPatrick Mooney 
5244c87aefeSPatrick Mooney 	rc->crc_width = gc_image->width;
5254c87aefeSPatrick Mooney 	rc->crc_height = gc_image->height;
5264c87aefeSPatrick Mooney 
5274c87aefeSPatrick Mooney 	w = rc->crc_width;
5284c87aefeSPatrick Mooney 	h = rc->crc_height;
5294c87aefeSPatrick Mooney 	xcells = howmany(rc->crc_width, PIX_PER_CELL);
5304c87aefeSPatrick Mooney 	ycells = howmany(rc->crc_height, PIX_PER_CELL);
5314c87aefeSPatrick Mooney 
5324c87aefeSPatrick Mooney 	rem_x = w & PIXCELL_MASK;
5334c87aefeSPatrick Mooney 
5344c87aefeSPatrick Mooney 	rem_y = h & PIXCELL_MASK;
5354c87aefeSPatrick Mooney 	if (!rem_y)
5364c87aefeSPatrick Mooney 		rem_y = PIX_PER_CELL;
5374c87aefeSPatrick Mooney 
5384c87aefeSPatrick Mooney 	p = gc_image->data;
5394c87aefeSPatrick Mooney 
5404c87aefeSPatrick Mooney 	/*
5414c87aefeSPatrick Mooney 	 * Go through all cells and calculate crc. If significant number
5424c87aefeSPatrick Mooney 	 * of changes, then send entire screen.
5434c87aefeSPatrick Mooney 	 * crc_tmp is dual purpose: to store the new crc and to flag as
5444c87aefeSPatrick Mooney 	 * a cell that has changed.
5454c87aefeSPatrick Mooney 	 */
5464c87aefeSPatrick Mooney 	crc_p = rc->crc_tmp - xcells;
5474c87aefeSPatrick Mooney 	orig_crc = rc->crc - xcells;
5484c87aefeSPatrick Mooney 	changes = 0;
5494c87aefeSPatrick Mooney 	memset(rc->crc_tmp, 0, sizeof(uint32_t) * xcells * ycells);
5504c87aefeSPatrick Mooney 	for (y = 0; y < h; y++) {
5514c87aefeSPatrick Mooney 		if ((y & PIXCELL_MASK) == 0) {
5524c87aefeSPatrick Mooney 			crc_p += xcells;
5534c87aefeSPatrick Mooney 			orig_crc += xcells;
5544c87aefeSPatrick Mooney 		}
5554c87aefeSPatrick Mooney 
5564c87aefeSPatrick Mooney 		for (x = 0; x < xcells; x++) {
5574c87aefeSPatrick Mooney 			if (x == (xcells - 1) && rem_x > 0)
5584c87aefeSPatrick Mooney 				cellwidth = rem_x;
5594c87aefeSPatrick Mooney 			else
5604c87aefeSPatrick Mooney 				cellwidth = PIX_PER_CELL;
5614c87aefeSPatrick Mooney 
5624c87aefeSPatrick Mooney 			if (rc->hw_crc)
5634c87aefeSPatrick Mooney 				crc_p[x] = fast_crc32(p,
5644c87aefeSPatrick Mooney 				             cellwidth * sizeof(uint32_t),
5654c87aefeSPatrick Mooney 				             crc_p[x]);
5664c87aefeSPatrick Mooney 			else
5674c87aefeSPatrick Mooney 				crc_p[x] = (uint32_t)crc32(crc_p[x],
5684c87aefeSPatrick Mooney 				             (Bytef *)p,
5694c87aefeSPatrick Mooney 				             cellwidth * sizeof(uint32_t));
5704c87aefeSPatrick Mooney 
5714c87aefeSPatrick Mooney 			p += cellwidth;
5724c87aefeSPatrick Mooney 
5734c87aefeSPatrick Mooney 			/* check for crc delta if last row in cell */
5744c87aefeSPatrick Mooney 			if ((y & PIXCELL_MASK) == PIXCELL_MASK || y == (h-1)) {
5754c87aefeSPatrick Mooney 				if (orig_crc[x] != crc_p[x]) {
5764c87aefeSPatrick Mooney 					orig_crc[x] = crc_p[x];
5774c87aefeSPatrick Mooney 					crc_p[x] = 1;
5784c87aefeSPatrick Mooney 					changes++;
5794c87aefeSPatrick Mooney 				} else {
5804c87aefeSPatrick Mooney 					crc_p[x] = 0;
5814c87aefeSPatrick Mooney 				}
5824c87aefeSPatrick Mooney 			}
5834c87aefeSPatrick Mooney 		}
5844c87aefeSPatrick Mooney 	}
5854c87aefeSPatrick Mooney 
5864c87aefeSPatrick Mooney 	/* If number of changes is > THRESH percent, send the whole screen */
5874c87aefeSPatrick Mooney 	if (((changes * 100) / (xcells * ycells)) >= RFB_SEND_ALL_THRESH) {
5884c87aefeSPatrick Mooney 		retval = rfb_send_all(rc, cfd, gc_image);
5894c87aefeSPatrick Mooney 		goto done;
5904c87aefeSPatrick Mooney 	}
5914c87aefeSPatrick Mooney 
5924c87aefeSPatrick Mooney 	/* Go through all cells, and send only changed ones */
5934c87aefeSPatrick Mooney 	crc_p = rc->crc_tmp;
5944c87aefeSPatrick Mooney 	for (y = 0; y < h; y += PIX_PER_CELL) {
5954c87aefeSPatrick Mooney 		/* previous cell's row */
5964c87aefeSPatrick Mooney 		celly = (y >> PIXCELL_SHIFT);
5974c87aefeSPatrick Mooney 
5984c87aefeSPatrick Mooney 		/* Delta check crc to previous set */
5994c87aefeSPatrick Mooney 		for (x = 0; x < xcells; x++) {
6004c87aefeSPatrick Mooney 			if (*crc_p++ == 0)
6014c87aefeSPatrick Mooney 				continue;
6024c87aefeSPatrick Mooney 
6034c87aefeSPatrick Mooney 			if (x == (xcells - 1) && rem_x > 0)
6044c87aefeSPatrick Mooney 				cellwidth = rem_x;
6054c87aefeSPatrick Mooney 			else
6064c87aefeSPatrick Mooney 				cellwidth = PIX_PER_CELL;
6074c87aefeSPatrick Mooney 			nwrite = rfb_send_rect(rc, cfd,
6084c87aefeSPatrick Mooney 				gc_image,
6094c87aefeSPatrick Mooney 				x * PIX_PER_CELL,
6104c87aefeSPatrick Mooney 				celly * PIX_PER_CELL,
6114c87aefeSPatrick Mooney 			        cellwidth,
6124c87aefeSPatrick Mooney 				y + PIX_PER_CELL >= h ? rem_y : PIX_PER_CELL);
6134c87aefeSPatrick Mooney 			if (nwrite <= 0) {
6144c87aefeSPatrick Mooney 				retval = nwrite;
6154c87aefeSPatrick Mooney 				goto done;
6164c87aefeSPatrick Mooney 			}
6174c87aefeSPatrick Mooney 		}
6184c87aefeSPatrick Mooney 	}
6194c87aefeSPatrick Mooney 	retval = 1;
6204c87aefeSPatrick Mooney 
6214c87aefeSPatrick Mooney done:
6224c87aefeSPatrick Mooney 	pthread_mutex_lock(&rc->mtx);
6234c87aefeSPatrick Mooney 	rc->sending = 0;
6244c87aefeSPatrick Mooney 	pthread_mutex_unlock(&rc->mtx);
6254c87aefeSPatrick Mooney 
6264c87aefeSPatrick Mooney 	return (retval);
6274c87aefeSPatrick Mooney }
6284c87aefeSPatrick Mooney 
6294c87aefeSPatrick Mooney 
630bf21cd93STycho Nightingale static void
6314c87aefeSPatrick Mooney rfb_recv_update_msg(struct rfb_softc *rc, int cfd, int discardonly)
632bf21cd93STycho Nightingale {
633bf21cd93STycho Nightingale 	struct rfb_updt_msg updt_msg;
634bf21cd93STycho Nightingale 	struct bhyvegc_image *gc_image;
635bf21cd93STycho Nightingale 
6364c87aefeSPatrick Mooney 	(void)stream_read(cfd, ((void *)&updt_msg) + 1 , sizeof(updt_msg) - 1);
637bf21cd93STycho Nightingale 
638bf21cd93STycho Nightingale 	console_refresh();
639bf21cd93STycho Nightingale 	gc_image = console_get_image();
640bf21cd93STycho Nightingale 
6414c87aefeSPatrick Mooney 	updt_msg.x = htons(updt_msg.x);
6424c87aefeSPatrick Mooney 	updt_msg.y = htons(updt_msg.y);
6434c87aefeSPatrick Mooney 	updt_msg.width = htons(updt_msg.width);
6444c87aefeSPatrick Mooney 	updt_msg.height = htons(updt_msg.height);
6454c87aefeSPatrick Mooney 
6464c87aefeSPatrick Mooney 	if (updt_msg.width != gc_image->width ||
6474c87aefeSPatrick Mooney 	    updt_msg.height != gc_image->height) {
648bf21cd93STycho Nightingale 		rc->width = gc_image->width;
649bf21cd93STycho Nightingale 		rc->height = gc_image->height;
6504c87aefeSPatrick Mooney 		if (rc->enc_resize_ok)
6514c87aefeSPatrick Mooney 			rfb_send_resize_update_msg(rc, cfd);
652bf21cd93STycho Nightingale 	}
653bf21cd93STycho Nightingale 
6544c87aefeSPatrick Mooney 	if (discardonly)
6554c87aefeSPatrick Mooney 		return;
656bf21cd93STycho Nightingale 
6574c87aefeSPatrick Mooney 	rfb_send_screen(rc, cfd, 1);
658bf21cd93STycho Nightingale }
659bf21cd93STycho Nightingale 
660bf21cd93STycho Nightingale static void
661bf21cd93STycho Nightingale rfb_recv_key_msg(struct rfb_softc *rc, int cfd)
662bf21cd93STycho Nightingale {
663bf21cd93STycho Nightingale 	struct rfb_key_msg key_msg;
664bf21cd93STycho Nightingale 
6654c87aefeSPatrick Mooney 	(void)stream_read(cfd, ((void *)&key_msg) + 1, sizeof(key_msg) - 1);
666bf21cd93STycho Nightingale 
6674c87aefeSPatrick Mooney 	console_key_event(key_msg.down, htonl(key_msg.code));
668bf21cd93STycho Nightingale }
669bf21cd93STycho Nightingale 
670bf21cd93STycho Nightingale static void
671bf21cd93STycho Nightingale rfb_recv_ptr_msg(struct rfb_softc *rc, int cfd)
672bf21cd93STycho Nightingale {
673bf21cd93STycho Nightingale 	struct rfb_ptr_msg ptr_msg;
6744c87aefeSPatrick Mooney 
6754c87aefeSPatrick Mooney 	(void)stream_read(cfd, ((void *)&ptr_msg) + 1, sizeof(ptr_msg) - 1);
6764c87aefeSPatrick Mooney 
6774c87aefeSPatrick Mooney 	console_ptr_event(ptr_msg.button, htons(ptr_msg.x), htons(ptr_msg.y));
6784c87aefeSPatrick Mooney }
6794c87aefeSPatrick Mooney 
6804c87aefeSPatrick Mooney static void
6814c87aefeSPatrick Mooney rfb_recv_cuttext_msg(struct rfb_softc *rc, int cfd)
6824c87aefeSPatrick Mooney {
6834c87aefeSPatrick Mooney 	struct rfb_cuttext_msg ct_msg;
6844c87aefeSPatrick Mooney 	unsigned char buf[32];
685bf21cd93STycho Nightingale 	int len;
686bf21cd93STycho Nightingale 
6874c87aefeSPatrick Mooney 	len = stream_read(cfd, ((void *)&ct_msg) + 1, sizeof(ct_msg) - 1);
6884c87aefeSPatrick Mooney 	ct_msg.length = htonl(ct_msg.length);
6894c87aefeSPatrick Mooney 	while (ct_msg.length > 0) {
6904c87aefeSPatrick Mooney 		len = stream_read(cfd, buf, ct_msg.length > sizeof(buf) ?
6914c87aefeSPatrick Mooney 			sizeof(buf) : ct_msg.length);
6924c87aefeSPatrick Mooney 		ct_msg.length -= len;
6934c87aefeSPatrick Mooney 	}
6944c87aefeSPatrick Mooney }
695bf21cd93STycho Nightingale 
6964c87aefeSPatrick Mooney static int64_t
6974c87aefeSPatrick Mooney timeval_delta(struct timeval *prev, struct timeval *now)
6984c87aefeSPatrick Mooney {
6994c87aefeSPatrick Mooney 	int64_t n1, n2;
7004c87aefeSPatrick Mooney 	n1 = now->tv_sec * 1000000 + now->tv_usec;
7014c87aefeSPatrick Mooney 	n2 = prev->tv_sec * 1000000 + prev->tv_usec;
7024c87aefeSPatrick Mooney 	return (n1 - n2);
7034c87aefeSPatrick Mooney }
7044c87aefeSPatrick Mooney 
7054c87aefeSPatrick Mooney static void *
7064c87aefeSPatrick Mooney rfb_wr_thr(void *arg)
7074c87aefeSPatrick Mooney {
7084c87aefeSPatrick Mooney 	struct rfb_softc *rc;
7094c87aefeSPatrick Mooney 	fd_set rfds;
7104c87aefeSPatrick Mooney 	struct timeval tv;
7114c87aefeSPatrick Mooney 	struct timeval prev_tv;
7124c87aefeSPatrick Mooney 	int64_t tdiff;
7134c87aefeSPatrick Mooney 	int cfd;
7144c87aefeSPatrick Mooney 	int err;
7154c87aefeSPatrick Mooney 
7164c87aefeSPatrick Mooney 	rc = arg;
7174c87aefeSPatrick Mooney 	cfd = rc->cfd;
7184c87aefeSPatrick Mooney 
7194c87aefeSPatrick Mooney 	prev_tv.tv_sec = 0;
7204c87aefeSPatrick Mooney 	prev_tv.tv_usec = 0;
7214c87aefeSPatrick Mooney 	while (rc->cfd >= 0) {
7224c87aefeSPatrick Mooney 		FD_ZERO(&rfds);
7234c87aefeSPatrick Mooney 		FD_SET(cfd, &rfds);
7244c87aefeSPatrick Mooney 		tv.tv_sec = 0;
7254c87aefeSPatrick Mooney 		tv.tv_usec = 10000;
7264c87aefeSPatrick Mooney 
7274c87aefeSPatrick Mooney 		err = select(cfd+1, &rfds, NULL, NULL, &tv);
7284c87aefeSPatrick Mooney 		if (err < 0)
7294c87aefeSPatrick Mooney 			return (NULL);
7304c87aefeSPatrick Mooney 
7314c87aefeSPatrick Mooney 		/* Determine if its time to push screen; ~24hz */
7324c87aefeSPatrick Mooney 		gettimeofday(&tv, NULL);
7334c87aefeSPatrick Mooney 		tdiff = timeval_delta(&prev_tv, &tv);
7344c87aefeSPatrick Mooney 		if (tdiff > 40000) {
7354c87aefeSPatrick Mooney 			prev_tv.tv_sec = tv.tv_sec;
7364c87aefeSPatrick Mooney 			prev_tv.tv_usec = tv.tv_usec;
7374c87aefeSPatrick Mooney 			if (rfb_send_screen(rc, cfd, 0) <= 0) {
7384c87aefeSPatrick Mooney 				return (NULL);
7394c87aefeSPatrick Mooney 			}
7404c87aefeSPatrick Mooney 		} else {
7414c87aefeSPatrick Mooney 			/* sleep */
7424c87aefeSPatrick Mooney 			usleep(40000 - tdiff);
7434c87aefeSPatrick Mooney 		}
7444c87aefeSPatrick Mooney 	}
7454c87aefeSPatrick Mooney 
7464c87aefeSPatrick Mooney 	return (NULL);
747bf21cd93STycho Nightingale }
748bf21cd93STycho Nightingale 
749bf21cd93STycho Nightingale void
750bf21cd93STycho Nightingale rfb_handle(struct rfb_softc *rc, int cfd)
751bf21cd93STycho Nightingale {
752bf21cd93STycho Nightingale 	const char *vbuf = "RFB 003.008\n";
753bf21cd93STycho Nightingale 	unsigned char buf[80];
7544c87aefeSPatrick Mooney 	unsigned char *message = NULL;
7554c87aefeSPatrick Mooney 
7564c87aefeSPatrick Mooney #ifndef NO_OPENSSL
7574c87aefeSPatrick Mooney 	unsigned char challenge[AUTH_LENGTH];
7584c87aefeSPatrick Mooney 	unsigned char keystr[PASSWD_LENGTH];
7594c87aefeSPatrick Mooney 	unsigned char crypt_expected[AUTH_LENGTH];
7604c87aefeSPatrick Mooney 
7614c87aefeSPatrick Mooney 	DES_key_schedule ks;
7624c87aefeSPatrick Mooney 	int i;
7634c87aefeSPatrick Mooney #endif
7644c87aefeSPatrick Mooney 
7654c87aefeSPatrick Mooney 	pthread_t tid;
7664c87aefeSPatrick Mooney 	uint32_t sres = 0;
767bf21cd93STycho Nightingale 	int len;
7684c87aefeSPatrick Mooney 	int perror = 1;
7694c87aefeSPatrick Mooney 
7704c87aefeSPatrick Mooney 	rc->cfd = cfd;
771bf21cd93STycho Nightingale 
772bf21cd93STycho Nightingale 	/* 1a. Send server version */
7734c87aefeSPatrick Mooney 	stream_write(cfd, vbuf, strlen(vbuf));
774bf21cd93STycho Nightingale 
775bf21cd93STycho Nightingale 	/* 1b. Read client version */
776bf21cd93STycho Nightingale 	len = read(cfd, buf, sizeof(buf));
777bf21cd93STycho Nightingale 
7784c87aefeSPatrick Mooney 	/* 2a. Send security type */
779bf21cd93STycho Nightingale 	buf[0] = 1;
7804c87aefeSPatrick Mooney #ifndef NO_OPENSSL
7814c87aefeSPatrick Mooney 	if (rc->password)
7824c87aefeSPatrick Mooney 		buf[1] = SECURITY_TYPE_VNC_AUTH;
7834c87aefeSPatrick Mooney 	else
7844c87aefeSPatrick Mooney 		buf[1] = SECURITY_TYPE_NONE;
7854c87aefeSPatrick Mooney #else
7864c87aefeSPatrick Mooney 	buf[1] = SECURITY_TYPE_NONE;
7874c87aefeSPatrick Mooney #endif
7884c87aefeSPatrick Mooney 
7894c87aefeSPatrick Mooney 	stream_write(cfd, buf, 2);
790bf21cd93STycho Nightingale 
791bf21cd93STycho Nightingale 	/* 2b. Read agreed security type */
7924c87aefeSPatrick Mooney 	len = stream_read(cfd, buf, 1);
7934c87aefeSPatrick Mooney 
7944c87aefeSPatrick Mooney 	/* 2c. Do VNC authentication */
7954c87aefeSPatrick Mooney 	switch (buf[0]) {
7964c87aefeSPatrick Mooney 	case SECURITY_TYPE_NONE:
7974c87aefeSPatrick Mooney 		sres = 0;
7984c87aefeSPatrick Mooney 		break;
7994c87aefeSPatrick Mooney 	case SECURITY_TYPE_VNC_AUTH:
8004c87aefeSPatrick Mooney 		/*
8014c87aefeSPatrick Mooney 		 * The client encrypts the challenge with DES, using a password
8024c87aefeSPatrick Mooney 		 * supplied by the user as the key.
8034c87aefeSPatrick Mooney 		 * To form the key, the password is truncated to
8044c87aefeSPatrick Mooney 		 * eight characters, or padded with null bytes on the right.
8054c87aefeSPatrick Mooney 		 * The client then sends the resulting 16-bytes response.
8064c87aefeSPatrick Mooney 		 */
8074c87aefeSPatrick Mooney #ifndef NO_OPENSSL
8084c87aefeSPatrick Mooney 		strncpy(keystr, rc->password, PASSWD_LENGTH);
8094c87aefeSPatrick Mooney 
8104c87aefeSPatrick Mooney 		/* VNC clients encrypts the challenge with all the bit fields
8114c87aefeSPatrick Mooney 		 * in each byte of the password mirrored.
8124c87aefeSPatrick Mooney 		 * Here we flip each byte of the keystr.
8134c87aefeSPatrick Mooney 		 */
8144c87aefeSPatrick Mooney 		for (i = 0; i < PASSWD_LENGTH; i++) {
8154c87aefeSPatrick Mooney 			keystr[i] = (keystr[i] & 0xF0) >> 4
8164c87aefeSPatrick Mooney 				  | (keystr[i] & 0x0F) << 4;
8174c87aefeSPatrick Mooney 			keystr[i] = (keystr[i] & 0xCC) >> 2
8184c87aefeSPatrick Mooney 				  | (keystr[i] & 0x33) << 2;
8194c87aefeSPatrick Mooney 			keystr[i] = (keystr[i] & 0xAA) >> 1
8204c87aefeSPatrick Mooney 				  | (keystr[i] & 0x55) << 1;
8214c87aefeSPatrick Mooney 		}
8224c87aefeSPatrick Mooney 
8234c87aefeSPatrick Mooney 		/* Initialize a 16-byte random challenge */
8244c87aefeSPatrick Mooney 		arc4random_buf(challenge, sizeof(challenge));
8254c87aefeSPatrick Mooney 		stream_write(cfd, challenge, AUTH_LENGTH);
8264c87aefeSPatrick Mooney 
8274c87aefeSPatrick Mooney 		/* Receive the 16-byte challenge response */
8284c87aefeSPatrick Mooney 		stream_read(cfd, buf, AUTH_LENGTH);
8294c87aefeSPatrick Mooney 
8304c87aefeSPatrick Mooney 		memcpy(crypt_expected, challenge, AUTH_LENGTH);
8314c87aefeSPatrick Mooney 
8324c87aefeSPatrick Mooney 		/* Encrypt the Challenge with DES */
8334c87aefeSPatrick Mooney 		DES_set_key((const_DES_cblock *)keystr, &ks);
8344c87aefeSPatrick Mooney 		DES_ecb_encrypt((const_DES_cblock *)challenge,
8354c87aefeSPatrick Mooney 				(const_DES_cblock *)crypt_expected,
8364c87aefeSPatrick Mooney 				&ks, DES_ENCRYPT);
8374c87aefeSPatrick Mooney 		DES_ecb_encrypt((const_DES_cblock *)(challenge + PASSWD_LENGTH),
8384c87aefeSPatrick Mooney 				(const_DES_cblock *)(crypt_expected +
8394c87aefeSPatrick Mooney 				PASSWD_LENGTH),
8404c87aefeSPatrick Mooney 				&ks, DES_ENCRYPT);
8414c87aefeSPatrick Mooney 
8424c87aefeSPatrick Mooney 		if (memcmp(crypt_expected, buf, AUTH_LENGTH) != 0) {
8434c87aefeSPatrick Mooney 			message = "Auth Failed: Invalid Password.";
8444c87aefeSPatrick Mooney 			sres = htonl(1);
8454c87aefeSPatrick Mooney 		} else
8464c87aefeSPatrick Mooney 			sres = 0;
8474c87aefeSPatrick Mooney #else
8484c87aefeSPatrick Mooney 		sres = 0;
8494c87aefeSPatrick Mooney 		WPRINTF(("Auth not supported, no OpenSSL in your system"));
8504c87aefeSPatrick Mooney #endif
851bf21cd93STycho Nightingale 
8524c87aefeSPatrick Mooney 		break;
8534c87aefeSPatrick Mooney 	}
8544c87aefeSPatrick Mooney 
8554c87aefeSPatrick Mooney 	/* 2d. Write back a status */
8564c87aefeSPatrick Mooney 	stream_write(cfd, &sres, 4);
8574c87aefeSPatrick Mooney 
8584c87aefeSPatrick Mooney 	if (sres) {
8594c87aefeSPatrick Mooney #ifdef __FreeBSD__
8604c87aefeSPatrick Mooney 		be32enc(buf, strlen(message));
8614c87aefeSPatrick Mooney 		stream_write(cfd, buf, 4);
8624c87aefeSPatrick Mooney 		stream_write(cfd, message, strlen(message));
8634c87aefeSPatrick Mooney #else
8644c87aefeSPatrick Mooney 		be32enc(buf, strlen((char *)message));
8654c87aefeSPatrick Mooney 		stream_write(cfd, buf, 4);
8664c87aefeSPatrick Mooney 		stream_write(cfd, message, strlen((char *)message));
8674c87aefeSPatrick Mooney #endif
8684c87aefeSPatrick Mooney 		goto done;
8694c87aefeSPatrick Mooney 	}
870bf21cd93STycho Nightingale 
871bf21cd93STycho Nightingale 	/* 3a. Read client shared-flag byte */
8724c87aefeSPatrick Mooney 	len = stream_read(cfd, buf, 1);
873bf21cd93STycho Nightingale 
874bf21cd93STycho Nightingale 	/* 4a. Write server-init info */
875bf21cd93STycho Nightingale 	rfb_send_server_init_msg(cfd);
876bf21cd93STycho Nightingale 
8774c87aefeSPatrick Mooney 	if (!rc->zbuf) {
8784c87aefeSPatrick Mooney 		rc->zbuf = malloc(RFB_ZLIB_BUFSZ + 16);
8794c87aefeSPatrick Mooney 		assert(rc->zbuf != NULL);
8804c87aefeSPatrick Mooney 	}
8814c87aefeSPatrick Mooney 
8824c87aefeSPatrick Mooney 	rfb_send_screen(rc, cfd, 1);
8834c87aefeSPatrick Mooney 
8844c87aefeSPatrick Mooney 	perror = pthread_create(&tid, NULL, rfb_wr_thr, rc);
8854c87aefeSPatrick Mooney 	if (perror == 0)
8864c87aefeSPatrick Mooney 		pthread_set_name_np(tid, "rfbout");
8874c87aefeSPatrick Mooney 
888bf21cd93STycho Nightingale         /* Now read in client requests. 1st byte identifies type */
889bf21cd93STycho Nightingale 	for (;;) {
890bf21cd93STycho Nightingale 		len = read(cfd, buf, 1);
891bf21cd93STycho Nightingale 		if (len <= 0) {
8924c87aefeSPatrick Mooney 			DPRINTF(("rfb client exiting\r\n"));
893bf21cd93STycho Nightingale 			break;
894bf21cd93STycho Nightingale 		}
895bf21cd93STycho Nightingale 
896bf21cd93STycho Nightingale 		switch (buf[0]) {
897bf21cd93STycho Nightingale 		case 0:
898bf21cd93STycho Nightingale 			rfb_recv_set_pixfmt_msg(rc, cfd);
899bf21cd93STycho Nightingale 			break;
900bf21cd93STycho Nightingale 		case 2:
901bf21cd93STycho Nightingale 			rfb_recv_set_encodings_msg(rc, cfd);
902bf21cd93STycho Nightingale 			break;
903bf21cd93STycho Nightingale 		case 3:
9044c87aefeSPatrick Mooney 			rfb_recv_update_msg(rc, cfd, 1);
905bf21cd93STycho Nightingale 			break;
906bf21cd93STycho Nightingale 		case 4:
907bf21cd93STycho Nightingale 			rfb_recv_key_msg(rc, cfd);
908bf21cd93STycho Nightingale 			break;
909bf21cd93STycho Nightingale 		case 5:
910bf21cd93STycho Nightingale 			rfb_recv_ptr_msg(rc, cfd);
911bf21cd93STycho Nightingale 			break;
9124c87aefeSPatrick Mooney 		case 6:
9134c87aefeSPatrick Mooney 			rfb_recv_cuttext_msg(rc, cfd);
9144c87aefeSPatrick Mooney 			break;
915bf21cd93STycho Nightingale 		default:
9164c87aefeSPatrick Mooney 			WPRINTF(("rfb unknown cli-code %d!\n", buf[0] & 0xff));
9174c87aefeSPatrick Mooney 			goto done;
918bf21cd93STycho Nightingale 		}
919bf21cd93STycho Nightingale 	}
9204c87aefeSPatrick Mooney done:
9214c87aefeSPatrick Mooney 	rc->cfd = -1;
9224c87aefeSPatrick Mooney 	if (perror == 0)
9234c87aefeSPatrick Mooney 		pthread_join(tid, NULL);
9244c87aefeSPatrick Mooney 	if (rc->enc_zlib_ok)
9254c87aefeSPatrick Mooney 		deflateEnd(&rc->zstream);
926bf21cd93STycho Nightingale }
927bf21cd93STycho Nightingale 
928bf21cd93STycho Nightingale static void *
929bf21cd93STycho Nightingale rfb_thr(void *arg)
930bf21cd93STycho Nightingale {
931bf21cd93STycho Nightingale 	struct rfb_softc *rc;
932bf21cd93STycho Nightingale 	sigset_t set;
933bf21cd93STycho Nightingale 
934bf21cd93STycho Nightingale 	int cfd;
935bf21cd93STycho Nightingale 
936bf21cd93STycho Nightingale 	rc = arg;
937bf21cd93STycho Nightingale 
938bf21cd93STycho Nightingale 	sigemptyset(&set);
939bf21cd93STycho Nightingale 	sigaddset(&set, SIGPIPE);
940bf21cd93STycho Nightingale 	if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0) {
941bf21cd93STycho Nightingale 		perror("pthread_sigmask");
942bf21cd93STycho Nightingale 		return (NULL);
943bf21cd93STycho Nightingale 	}
944bf21cd93STycho Nightingale 
945bf21cd93STycho Nightingale 	for (;;) {
9464c87aefeSPatrick Mooney 		rc->enc_raw_ok = false;
9474c87aefeSPatrick Mooney 		rc->enc_zlib_ok = false;
9484c87aefeSPatrick Mooney 		rc->enc_resize_ok = false;
9494c87aefeSPatrick Mooney 
950bf21cd93STycho Nightingale 		cfd = accept(rc->sfd, NULL, NULL);
9514c87aefeSPatrick Mooney 		if (rc->conn_wait) {
9524c87aefeSPatrick Mooney 			pthread_mutex_lock(&rc->mtx);
9534c87aefeSPatrick Mooney 			pthread_cond_signal(&rc->cond);
9544c87aefeSPatrick Mooney 			pthread_mutex_unlock(&rc->mtx);
9554c87aefeSPatrick Mooney 			rc->conn_wait = 0;
9564c87aefeSPatrick Mooney 		}
957bf21cd93STycho Nightingale 		rfb_handle(rc, cfd);
9584c87aefeSPatrick Mooney 		close(cfd);
959bf21cd93STycho Nightingale 	}
960bf21cd93STycho Nightingale 
961bf21cd93STycho Nightingale 	/* NOTREACHED */
962bf21cd93STycho Nightingale 	return (NULL);
963bf21cd93STycho Nightingale }
964bf21cd93STycho Nightingale 
9654c87aefeSPatrick Mooney static int
9664c87aefeSPatrick Mooney sse42_supported(void)
9674c87aefeSPatrick Mooney {
9684c87aefeSPatrick Mooney 	u_int cpu_registers[4], ecx;
9694c87aefeSPatrick Mooney 
9704c87aefeSPatrick Mooney 	do_cpuid(1, cpu_registers);
9714c87aefeSPatrick Mooney 
9724c87aefeSPatrick Mooney 	ecx = cpu_registers[2];
9734c87aefeSPatrick Mooney 
9744c87aefeSPatrick Mooney 	return ((ecx & CPUID2_SSE42) != 0);
9754c87aefeSPatrick Mooney }
9764c87aefeSPatrick Mooney 
977bf21cd93STycho Nightingale int
9784c87aefeSPatrick Mooney rfb_init(char *hostname, int port, int wait, char *password)
979bf21cd93STycho Nightingale {
9804c87aefeSPatrick Mooney 	int e;
9814c87aefeSPatrick Mooney 	char servname[6];
982bf21cd93STycho Nightingale 	struct rfb_softc *rc;
983*84659b24SMichael Zeller 	struct addrinfo *ai = NULL;
9844c87aefeSPatrick Mooney 	struct addrinfo hints;
985bf21cd93STycho Nightingale 	int on = 1;
9864c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
9874c87aefeSPatrick Mooney 	cap_rights_t rights;
9884c87aefeSPatrick Mooney #endif
989bf21cd93STycho Nightingale 
990bf21cd93STycho Nightingale 	rc = calloc(1, sizeof(struct rfb_softc));
991bf21cd93STycho Nightingale 
9924c87aefeSPatrick Mooney 	rc->crc = calloc(howmany(RFB_MAX_WIDTH * RFB_MAX_HEIGHT, 32),
9934c87aefeSPatrick Mooney 	                 sizeof(uint32_t));
9944c87aefeSPatrick Mooney 	rc->crc_tmp = calloc(howmany(RFB_MAX_WIDTH * RFB_MAX_HEIGHT, 32),
9954c87aefeSPatrick Mooney 	                     sizeof(uint32_t));
9964c87aefeSPatrick Mooney 	rc->crc_width = RFB_MAX_WIDTH;
9974c87aefeSPatrick Mooney 	rc->crc_height = RFB_MAX_HEIGHT;
998*84659b24SMichael Zeller 	rc->sfd = -1;
9994c87aefeSPatrick Mooney 
10004c87aefeSPatrick Mooney 	rc->password = password;
10014c87aefeSPatrick Mooney 
10024c87aefeSPatrick Mooney 	snprintf(servname, sizeof(servname), "%d", port ? port : 5900);
10034c87aefeSPatrick Mooney 
10044c87aefeSPatrick Mooney 	if (!hostname || strlen(hostname) == 0)
10054c87aefeSPatrick Mooney #if defined(INET)
10064c87aefeSPatrick Mooney 		hostname = "127.0.0.1";
10074c87aefeSPatrick Mooney #elif defined(INET6)
10084c87aefeSPatrick Mooney 		hostname = "[::1]";
10094c87aefeSPatrick Mooney #endif
10104c87aefeSPatrick Mooney 
10114c87aefeSPatrick Mooney 	memset(&hints, 0, sizeof(hints));
10124c87aefeSPatrick Mooney 	hints.ai_family = AF_UNSPEC;
10134c87aefeSPatrick Mooney 	hints.ai_socktype = SOCK_STREAM;
10144c87aefeSPatrick Mooney 	hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV | AI_PASSIVE;
10154c87aefeSPatrick Mooney 
10164c87aefeSPatrick Mooney 	if ((e = getaddrinfo(hostname, servname, &hints, &ai)) != 0) {
10174c87aefeSPatrick Mooney 		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(e));
1018*84659b24SMichael Zeller 		goto error;
10194c87aefeSPatrick Mooney 	}
10204c87aefeSPatrick Mooney 
10214c87aefeSPatrick Mooney 	rc->sfd = socket(ai->ai_family, ai->ai_socktype, 0);
1022bf21cd93STycho Nightingale 	if (rc->sfd < 0) {
1023bf21cd93STycho Nightingale 		perror("socket");
1024*84659b24SMichael Zeller 		goto error;
1025bf21cd93STycho Nightingale 	}
1026bf21cd93STycho Nightingale 
1027bf21cd93STycho Nightingale 	setsockopt(rc->sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
1028bf21cd93STycho Nightingale 
10294c87aefeSPatrick Mooney 	if (bind(rc->sfd, ai->ai_addr, ai->ai_addrlen) < 0) {
1030bf21cd93STycho Nightingale 		perror("bind");
1031*84659b24SMichael Zeller 		goto error;
1032bf21cd93STycho Nightingale 	}
1033bf21cd93STycho Nightingale 
1034bf21cd93STycho Nightingale 	if (listen(rc->sfd, 1) < 0) {
1035bf21cd93STycho Nightingale 		perror("listen");
1036*84659b24SMichael Zeller 		goto error;
1037bf21cd93STycho Nightingale 	}
1038bf21cd93STycho Nightingale 
10394c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
10404c87aefeSPatrick Mooney 	cap_rights_init(&rights, CAP_ACCEPT, CAP_EVENT, CAP_READ, CAP_WRITE);
10414c87aefeSPatrick Mooney 	if (caph_rights_limit(rc->sfd, &rights) == -1)
10424c87aefeSPatrick Mooney 		errx(EX_OSERR, "Unable to apply rights for sandbox");
10434c87aefeSPatrick Mooney #endif
10444c87aefeSPatrick Mooney 
10454c87aefeSPatrick Mooney 	rc->hw_crc = sse42_supported();
10464c87aefeSPatrick Mooney 
10474c87aefeSPatrick Mooney 	rc->conn_wait = wait;
10484c87aefeSPatrick Mooney 	if (wait) {
10494c87aefeSPatrick Mooney 		pthread_mutex_init(&rc->mtx, NULL);
10504c87aefeSPatrick Mooney 		pthread_cond_init(&rc->cond, NULL);
10514c87aefeSPatrick Mooney 	}
10524c87aefeSPatrick Mooney 
1053bf21cd93STycho Nightingale 	pthread_create(&rc->tid, NULL, rfb_thr, rc);
10544c87aefeSPatrick Mooney 	pthread_set_name_np(rc->tid, "rfb");
10554c87aefeSPatrick Mooney 
10564c87aefeSPatrick Mooney 	if (wait) {
10574c87aefeSPatrick Mooney 		DPRINTF(("Waiting for rfb client...\n"));
10584c87aefeSPatrick Mooney 		pthread_mutex_lock(&rc->mtx);
10594c87aefeSPatrick Mooney 		pthread_cond_wait(&rc->cond, &rc->mtx);
10604c87aefeSPatrick Mooney 		pthread_mutex_unlock(&rc->mtx);
10614c87aefeSPatrick Mooney 	}
1062bf21cd93STycho Nightingale 
10634c87aefeSPatrick Mooney 	freeaddrinfo(ai);
1064bf21cd93STycho Nightingale 	return (0);
1065*84659b24SMichael Zeller 
1066*84659b24SMichael Zeller  error:
1067*84659b24SMichael Zeller 	if (ai != NULL)
1068*84659b24SMichael Zeller 		freeaddrinfo(ai);
1069*84659b24SMichael Zeller 	if (rc->sfd != -1)
1070*84659b24SMichael Zeller 		close(rc->sfd);
1071*84659b24SMichael Zeller 	free(rc->crc);
1072*84659b24SMichael Zeller 	free(rc->crc_tmp);
1073*84659b24SMichael Zeller 	free(rc);
1074*84659b24SMichael Zeller 	return (-1);
1075bf21cd93STycho Nightingale }
10764c87aefeSPatrick Mooney 
10774c87aefeSPatrick Mooney #ifndef __FreeBSD__
10784c87aefeSPatrick Mooney int
10794c87aefeSPatrick Mooney rfb_init_unix(char *path, int wait, char *password)
10804c87aefeSPatrick Mooney {
10814c87aefeSPatrick Mooney 	struct rfb_softc *rc;
10824c87aefeSPatrick Mooney 	struct sockaddr_un sock;
10834c87aefeSPatrick Mooney 
10844c87aefeSPatrick Mooney 	if ((rc = calloc(1, sizeof (struct rfb_softc))) == NULL) {
10854c87aefeSPatrick Mooney 		perror("calloc");
10864c87aefeSPatrick Mooney 		return (-1);
10874c87aefeSPatrick Mooney 	}
10884c87aefeSPatrick Mooney 	rc->sfd = -1;
10894c87aefeSPatrick Mooney 
10904c87aefeSPatrick Mooney 	if ((rc->crc = calloc(howmany(RFB_MAX_WIDTH * RFB_MAX_HEIGHT, 32),
10914c87aefeSPatrick Mooney 	    sizeof (uint32_t))) == NULL) {
10924c87aefeSPatrick Mooney 		perror("calloc");
10934c87aefeSPatrick Mooney 		goto fail;
10944c87aefeSPatrick Mooney 	}
10954c87aefeSPatrick Mooney 	if ((rc->crc_tmp = calloc(howmany(RFB_MAX_WIDTH * RFB_MAX_HEIGHT, 32),
10964c87aefeSPatrick Mooney 	    sizeof (uint32_t))) == NULL) {
10974c87aefeSPatrick Mooney 		perror("calloc");
10984c87aefeSPatrick Mooney 		goto fail;
10994c87aefeSPatrick Mooney 	}
11004c87aefeSPatrick Mooney 	rc->crc_width = RFB_MAX_WIDTH;
11014c87aefeSPatrick Mooney 	rc->crc_height = RFB_MAX_HEIGHT;
11024c87aefeSPatrick Mooney 
11034c87aefeSPatrick Mooney 	rc->password = password;
11044c87aefeSPatrick Mooney 
11054c87aefeSPatrick Mooney 	rc->sfd = socket(PF_UNIX, SOCK_STREAM, 0);
11064c87aefeSPatrick Mooney 	if (rc->sfd < 0) {
11074c87aefeSPatrick Mooney 		perror("socket");
11084c87aefeSPatrick Mooney 		goto fail;
11094c87aefeSPatrick Mooney 	}
11104c87aefeSPatrick Mooney 
11114c87aefeSPatrick Mooney 	sock.sun_family = AF_UNIX;
11124c87aefeSPatrick Mooney 	if (strlcpy(sock.sun_path, path, sizeof (sock.sun_path)) >=
11134c87aefeSPatrick Mooney 	    sizeof (sock.sun_path)) {
11144c87aefeSPatrick Mooney 		(void) fprintf(stderr, "socket path '%s' too long\n", path);
11154c87aefeSPatrick Mooney 		goto fail;
11164c87aefeSPatrick Mooney 	}
11174c87aefeSPatrick Mooney 
11184c87aefeSPatrick Mooney 	(void) unlink(path);
11194c87aefeSPatrick Mooney 	if (bind(rc->sfd, (struct sockaddr *)&sock, sizeof (sock)) < 0) {
11204c87aefeSPatrick Mooney 		perror("bind");
11214c87aefeSPatrick Mooney 		goto fail;
11224c87aefeSPatrick Mooney 	}
11234c87aefeSPatrick Mooney 
11244c87aefeSPatrick Mooney 	if (listen(rc->sfd, 1) < 0) {
11254c87aefeSPatrick Mooney 		perror("listen");
11264c87aefeSPatrick Mooney 		goto fail;
11274c87aefeSPatrick Mooney 	}
11284c87aefeSPatrick Mooney 
11294c87aefeSPatrick Mooney 	rc->hw_crc = sse42_supported();
11304c87aefeSPatrick Mooney 
11314c87aefeSPatrick Mooney 	rc->conn_wait = wait;
11324c87aefeSPatrick Mooney 	if (wait) {
11334c87aefeSPatrick Mooney 		VERIFY3S(pthread_mutex_init(&rc->mtx, NULL), ==, 0);
11344c87aefeSPatrick Mooney 		VERIFY3S(pthread_cond_init(&rc->cond, NULL), ==, 0);
11354c87aefeSPatrick Mooney 	}
11364c87aefeSPatrick Mooney 
11374c87aefeSPatrick Mooney 	VERIFY3S(pthread_create(&rc->tid, NULL, rfb_thr, rc), ==, 0);
11384c87aefeSPatrick Mooney 	pthread_set_name_np(rc->tid, "rfb");
11394c87aefeSPatrick Mooney 
11404c87aefeSPatrick Mooney 	if (wait) {
11414c87aefeSPatrick Mooney 		DPRINTF(("Waiting for rfb client...\n"));
11424c87aefeSPatrick Mooney 		VERIFY3S(pthread_mutex_lock(&rc->mtx), ==, 0);
11434c87aefeSPatrick Mooney 		VERIFY3S(pthread_cond_wait(&rc->cond, &rc->mtx), ==, 0);
11444c87aefeSPatrick Mooney 		VERIFY3S(pthread_mutex_unlock(&rc->mtx), ==, 0);
11454c87aefeSPatrick Mooney 	}
11464c87aefeSPatrick Mooney 
11474c87aefeSPatrick Mooney 	return (0);
11484c87aefeSPatrick Mooney 
11494c87aefeSPatrick Mooney fail:
11504c87aefeSPatrick Mooney 	if (rc->sfd != -1) {
11514c87aefeSPatrick Mooney 		VERIFY3S(close(rc->sfd), ==, 0);
11524c87aefeSPatrick Mooney 	}
11534c87aefeSPatrick Mooney 	free(rc->crc);
11544c87aefeSPatrick Mooney 	free(rc->crc_tmp);
11554c87aefeSPatrick Mooney 	free(rc);
11564c87aefeSPatrick Mooney 	return (-1);
11574c87aefeSPatrick Mooney }
11584c87aefeSPatrick Mooney #endif
1159