xref: /illumos-gate/usr/src/cmd/bhyve/rfb.c (revision dc8050e8)
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