rfb.c revision 302408
1/*-
2 * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
3 * Copyright (c) 2015 Leon Dang
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: stable/11/usr.sbin/bhyve/rfb.c 302408 2016-07-08 00:04:57Z gjb $");
30
31#include <sys/param.h>
32#include <sys/socket.h>
33#include <sys/select.h>
34#include <sys/time.h>
35#include <arpa/inet.h>
36#include <machine/cpufunc.h>
37#include <machine/specialreg.h>
38#include <netinet/in.h>
39
40#include <assert.h>
41#include <pthread.h>
42#include <pthread_np.h>
43#include <signal.h>
44#include <stdbool.h>
45#include <stdlib.h>
46#include <stdio.h>
47#include <string.h>
48#include <unistd.h>
49
50#include <zlib.h>
51
52#include "bhyvegc.h"
53#include "console.h"
54#include "rfb.h"
55#include "sockstream.h"
56
57static int rfb_debug = 0;
58#define	DPRINTF(params) if (rfb_debug) printf params
59#define	WPRINTF(params) printf params
60
61struct rfb_softc {
62	int		sfd;
63	pthread_t	tid;
64
65	int		cfd;
66
67	int		width, height;
68
69	bool		enc_raw_ok;
70	bool		enc_zlib_ok;
71	bool		enc_resize_ok;
72
73	z_stream	zstream;
74	uint8_t		*zbuf;
75	int		zbuflen;
76
77	int		conn_wait;
78	int		sending;
79	pthread_mutex_t mtx;
80	pthread_cond_t  cond;
81
82	int		hw_crc;
83	uint32_t	*crc;		/* WxH crc cells */
84	uint32_t	*crc_tmp;	/* buffer to store single crc row */
85	int		crc_width, crc_height;
86};
87
88struct rfb_pixfmt {
89	uint8_t		bpp;
90	uint8_t		depth;
91	uint8_t		bigendian;
92	uint8_t		truecolor;
93	uint16_t	red_max;
94	uint16_t	green_max;
95	uint16_t	blue_max;
96	uint8_t		red_shift;
97	uint8_t		green_shift;
98	uint8_t		blue_shift;
99	uint8_t		pad[3];
100};
101
102struct rfb_srvr_info {
103	uint16_t		width;
104	uint16_t		height;
105	struct rfb_pixfmt	pixfmt;
106	uint32_t		namelen;
107};
108
109struct rfb_pixfmt_msg {
110	uint8_t			type;
111	uint8_t			pad[3];
112	struct rfb_pixfmt	pixfmt;
113};
114
115#define	RFB_ENCODING_RAW		0
116#define	RFB_ENCODING_ZLIB		6
117#define	RFB_ENCODING_RESIZE		-223
118
119#define RFB_MAX_WIDTH			2000
120#define RFB_MAX_HEIGHT			1200
121#define	RFB_ZLIB_BUFSZ			RFB_MAX_WIDTH*RFB_MAX_HEIGHT*4
122
123/* percentage changes to screen before sending the entire screen */
124#define RFB_SEND_ALL_THRESH             25
125
126struct rfb_enc_msg {
127	uint8_t		type;
128	uint8_t		pad;
129	uint16_t	numencs;
130};
131
132struct rfb_updt_msg {
133	uint8_t		type;
134	uint8_t		incremental;
135	uint16_t	x;
136	uint16_t	y;
137	uint16_t	width;
138	uint16_t	height;
139};
140
141struct rfb_key_msg {
142	uint8_t		type;
143	uint8_t		down;
144	uint16_t	pad;
145	uint32_t	code;
146};
147
148struct rfb_ptr_msg {
149	uint8_t		type;
150	uint8_t		button;
151	uint16_t	x;
152	uint16_t	y;
153};
154
155struct rfb_srvr_updt_msg {
156	uint8_t		type;
157	uint8_t		pad;
158	uint16_t	numrects;
159};
160
161struct rfb_srvr_rect_hdr {
162	uint16_t	x;
163	uint16_t	y;
164	uint16_t	width;
165	uint16_t	height;
166	uint32_t	encoding;
167};
168
169struct rfb_cuttext_msg {
170	uint8_t		type;
171	uint8_t		padding[3];
172	uint32_t	length;
173};
174
175
176static void
177rfb_send_server_init_msg(int cfd)
178{
179	struct bhyvegc_image *gc_image;
180	struct rfb_srvr_info sinfo;
181
182	gc_image = console_get_image();
183
184	sinfo.width = htons(gc_image->width);
185	sinfo.height = htons(gc_image->height);
186	sinfo.pixfmt.bpp = 32;
187	sinfo.pixfmt.depth = 32;
188	sinfo.pixfmt.bigendian = 0;
189	sinfo.pixfmt.truecolor = 1;
190	sinfo.pixfmt.red_max = htons(255);
191	sinfo.pixfmt.green_max = htons(255);
192	sinfo.pixfmt.blue_max = htons(255);
193	sinfo.pixfmt.red_shift = 16;
194	sinfo.pixfmt.green_shift = 8;
195	sinfo.pixfmt.blue_shift = 0;
196	sinfo.namelen = htonl(strlen("bhyve"));
197	(void)stream_write(cfd, &sinfo, sizeof(sinfo));
198	(void)stream_write(cfd, "bhyve", strlen("bhyve"));
199}
200
201static void
202rfb_send_resize_update_msg(struct rfb_softc *rc, int cfd)
203{
204	struct rfb_srvr_updt_msg supdt_msg;
205        struct rfb_srvr_rect_hdr srect_hdr;
206
207	/* Number of rectangles: 1 */
208	supdt_msg.type = 0;
209	supdt_msg.pad = 0;
210	supdt_msg.numrects = htons(1);
211	stream_write(cfd, &supdt_msg, sizeof(struct rfb_srvr_updt_msg));
212
213	/* Rectangle header */
214	srect_hdr.x = htons(0);
215	srect_hdr.y = htons(0);
216	srect_hdr.width = htons(rc->width);
217	srect_hdr.height = htons(rc->height);
218	srect_hdr.encoding = htonl(RFB_ENCODING_RESIZE);
219	stream_write(cfd, &srect_hdr, sizeof(struct rfb_srvr_rect_hdr));
220}
221
222static void
223rfb_recv_set_pixfmt_msg(struct rfb_softc *rc, int cfd)
224{
225	struct rfb_pixfmt_msg pixfmt_msg;
226
227	(void)stream_read(cfd, ((void *)&pixfmt_msg)+1, sizeof(pixfmt_msg)-1);
228}
229
230
231static void
232rfb_recv_set_encodings_msg(struct rfb_softc *rc, int cfd)
233{
234	struct rfb_enc_msg enc_msg;
235	int i;
236	uint32_t encoding;
237
238	assert((sizeof(enc_msg) - 1) == 3);
239	(void)stream_read(cfd, ((void *)&enc_msg)+1, sizeof(enc_msg)-1);
240
241	for (i = 0; i < htons(enc_msg.numencs); i++) {
242		(void)stream_read(cfd, &encoding, sizeof(encoding));
243		switch (htonl(encoding)) {
244		case RFB_ENCODING_RAW:
245			rc->enc_raw_ok = true;
246			break;
247		case RFB_ENCODING_ZLIB:
248			rc->enc_zlib_ok = true;
249			deflateInit(&rc->zstream, Z_BEST_SPEED);
250			break;
251		case RFB_ENCODING_RESIZE:
252			rc->enc_resize_ok = true;
253			break;
254		}
255	}
256}
257
258/*
259 * Calculate CRC32 using SSE4.2; Intel or AMD Bulldozer+ CPUs only
260 */
261static __inline uint32_t
262fast_crc32(void *buf, int len, uint32_t crcval)
263{
264	uint32_t q = len / sizeof(uint32_t);
265	uint32_t *p = (uint32_t *)buf;
266
267	while (q--) {
268		asm volatile (
269			".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;"
270			:"=S" (crcval)
271			:"0" (crcval), "c" (*p)
272		);
273		p++;
274	}
275
276	return (crcval);
277}
278
279
280static int
281rfb_send_rect(struct rfb_softc *rc, int cfd, struct bhyvegc_image *gc,
282              int x, int y, int w, int h)
283{
284	struct rfb_srvr_updt_msg supdt_msg;
285        struct rfb_srvr_rect_hdr srect_hdr;
286	unsigned long zlen;
287	ssize_t nwrite, total;
288	int err;
289	uint32_t *p;
290	uint8_t *zbufp;
291
292	/*
293	 * Send a single rectangle of the given x, y, w h dimensions.
294	 */
295
296	/* Number of rectangles: 1 */
297	supdt_msg.type = 0;
298	supdt_msg.pad = 0;
299	supdt_msg.numrects = htons(1);
300	nwrite = stream_write(cfd, &supdt_msg,
301	                      sizeof(struct rfb_srvr_updt_msg));
302	if (nwrite <= 0)
303		return (nwrite);
304
305
306	/* Rectangle header */
307	srect_hdr.x = htons(x);
308	srect_hdr.y = htons(y);
309	srect_hdr.width = htons(w);
310	srect_hdr.height = htons(h);
311
312	h = y + h;
313	w *= sizeof(uint32_t);
314	if (rc->enc_zlib_ok) {
315		zbufp = rc->zbuf;
316		rc->zstream.total_in = 0;
317		rc->zstream.total_out = 0;
318		for (p = &gc->data[y * gc->width + x]; y < h; y++) {
319			rc->zstream.next_in = (Bytef *)p;
320			rc->zstream.avail_in = w;
321			rc->zstream.next_out = (Bytef *)zbufp;
322			rc->zstream.avail_out = RFB_ZLIB_BUFSZ + 16 -
323			                        rc->zstream.total_out;
324			rc->zstream.data_type = Z_BINARY;
325
326			/* Compress with zlib */
327			err = deflate(&rc->zstream, Z_SYNC_FLUSH);
328			if (err != Z_OK) {
329				WPRINTF(("zlib[rect] deflate err: %d\n", err));
330				rc->enc_zlib_ok = false;
331				deflateEnd(&rc->zstream);
332				goto doraw;
333			}
334			zbufp = rc->zbuf + rc->zstream.total_out;
335			p += gc->width;
336		}
337		srect_hdr.encoding = htonl(RFB_ENCODING_ZLIB);
338		nwrite = stream_write(cfd, &srect_hdr,
339		                      sizeof(struct rfb_srvr_rect_hdr));
340		if (nwrite <= 0)
341			return (nwrite);
342
343		zlen = htonl(rc->zstream.total_out);
344		nwrite = stream_write(cfd, &zlen, sizeof(uint32_t));
345		if (nwrite <= 0)
346			return (nwrite);
347		return (stream_write(cfd, rc->zbuf, rc->zstream.total_out));
348	}
349
350doraw:
351
352	total = 0;
353	zbufp = rc->zbuf;
354	for (p = &gc->data[y * gc->width + x]; y < h; y++) {
355		memcpy(zbufp, p, w);
356		zbufp += w;
357		total += w;
358		p += gc->width;
359	}
360
361	srect_hdr.encoding = htonl(RFB_ENCODING_RAW);
362	nwrite = stream_write(cfd, &srect_hdr,
363	                      sizeof(struct rfb_srvr_rect_hdr));
364	if (nwrite <= 0)
365		return (nwrite);
366
367	total = stream_write(cfd, rc->zbuf, total);
368
369	return (total);
370}
371
372static int
373rfb_send_all(struct rfb_softc *rc, int cfd, struct bhyvegc_image *gc)
374{
375	struct rfb_srvr_updt_msg supdt_msg;
376        struct rfb_srvr_rect_hdr srect_hdr;
377	ssize_t nwrite;
378	unsigned long zlen;
379	int err;
380
381	/*
382	 * Send the whole thing
383	 */
384
385	/* Number of rectangles: 1 */
386	supdt_msg.type = 0;
387	supdt_msg.pad = 0;
388	supdt_msg.numrects = htons(1);
389	nwrite = stream_write(cfd, &supdt_msg,
390	                      sizeof(struct rfb_srvr_updt_msg));
391	if (nwrite <= 0)
392		return (nwrite);
393
394	/* Rectangle header */
395	srect_hdr.x = 0;
396	srect_hdr.y = 0;
397	srect_hdr.width = htons(gc->width);
398	srect_hdr.height = htons(gc->height);
399	if (rc->enc_zlib_ok) {
400		rc->zstream.next_in = (Bytef *)gc->data;
401		rc->zstream.avail_in = gc->width * gc->height *
402		                   sizeof(uint32_t);
403		rc->zstream.next_out = (Bytef *)rc->zbuf;
404		rc->zstream.avail_out = RFB_ZLIB_BUFSZ + 16;
405		rc->zstream.data_type = Z_BINARY;
406
407		rc->zstream.total_in = 0;
408		rc->zstream.total_out = 0;
409
410		/* Compress with zlib */
411		err = deflate(&rc->zstream, Z_SYNC_FLUSH);
412		if (err != Z_OK) {
413			WPRINTF(("zlib deflate err: %d\n", err));
414			rc->enc_zlib_ok = false;
415			deflateEnd(&rc->zstream);
416			goto doraw;
417		}
418
419		srect_hdr.encoding = htonl(RFB_ENCODING_ZLIB);
420		nwrite = stream_write(cfd, &srect_hdr,
421		                      sizeof(struct rfb_srvr_rect_hdr));
422		if (nwrite <= 0)
423			return (nwrite);
424
425		zlen = htonl(rc->zstream.total_out);
426		nwrite = stream_write(cfd, &zlen, sizeof(uint32_t));
427		if (nwrite <= 0)
428			return (nwrite);
429		return (stream_write(cfd, rc->zbuf, rc->zstream.total_out));
430	}
431
432doraw:
433	srect_hdr.encoding = htonl(RFB_ENCODING_RAW);
434	nwrite = stream_write(cfd, &srect_hdr,
435	                      sizeof(struct rfb_srvr_rect_hdr));
436	if (nwrite <= 0)
437		return (nwrite);
438
439	nwrite = stream_write(cfd, gc->data,
440	               gc->width * gc->height * sizeof(uint32_t));
441
442	return (nwrite);
443}
444
445#define PIX_PER_CELL	32
446#define	PIXCELL_SHIFT	5
447#define PIXCELL_MASK	0x1F
448
449static int
450rfb_send_screen(struct rfb_softc *rc, int cfd, int all)
451{
452	struct bhyvegc_image *gc_image;
453	ssize_t nwrite;
454	int x, y;
455	int celly, cellwidth;
456	int xcells, ycells;
457	int w, h;
458	uint32_t *p;
459	int rem_x, rem_y;   /* remainder for resolutions not x32 pixels ratio */
460	int retval;
461	uint32_t *crc_p, *orig_crc;
462	int changes;
463
464	console_refresh();
465	gc_image = console_get_image();
466
467	pthread_mutex_lock(&rc->mtx);
468	if (rc->sending) {
469		pthread_mutex_unlock(&rc->mtx);
470		return (1);
471	}
472	rc->sending = 1;
473	pthread_mutex_unlock(&rc->mtx);
474
475	retval = 0;
476
477	if (all) {
478		retval = rfb_send_all(rc, cfd, gc_image);
479		goto done;
480	}
481
482	/*
483	 * Calculate the checksum for each 32x32 cell. Send each that
484	 * has changed since the last scan.
485	 */
486
487	/* Resolution changed */
488
489	rc->crc_width = gc_image->width;
490	rc->crc_height = gc_image->height;
491
492	w = rc->crc_width;
493	h = rc->crc_height;
494	xcells = howmany(rc->crc_width, PIX_PER_CELL);
495	ycells = howmany(rc->crc_height, PIX_PER_CELL);
496
497	rem_x = w & PIXCELL_MASK;
498
499	rem_y = h & PIXCELL_MASK;
500	if (!rem_y)
501		rem_y = PIX_PER_CELL;
502
503	p = gc_image->data;
504
505	/*
506	 * Go through all cells and calculate crc. If significant number
507	 * of changes, then send entire screen.
508	 * crc_tmp is dual purpose: to store the new crc and to flag as
509	 * a cell that has changed.
510	 */
511	crc_p = rc->crc_tmp - xcells;
512	orig_crc = rc->crc - xcells;
513	changes = 0;
514	memset(rc->crc_tmp, 0, sizeof(uint32_t) * xcells * ycells);
515	for (y = 0; y < h; y++) {
516		if ((y & PIXCELL_MASK) == 0) {
517			crc_p += xcells;
518			orig_crc += xcells;
519		}
520
521		for (x = 0; x < xcells; x++) {
522			if (rc->hw_crc)
523				crc_p[x] = fast_crc32(p,
524				             PIX_PER_CELL * sizeof(uint32_t),
525				             crc_p[x]);
526			else
527				crc_p[x] = (uint32_t)crc32(crc_p[x],
528				             (Bytef *)p,
529				             PIX_PER_CELL * sizeof(uint32_t));
530
531			p += PIX_PER_CELL;
532
533			/* check for crc delta if last row in cell */
534			if ((y & PIXCELL_MASK) == PIXCELL_MASK || y == (h-1)) {
535				if (orig_crc[x] != crc_p[x]) {
536					orig_crc[x] = crc_p[x];
537					crc_p[x] = 1;
538					changes++;
539				} else {
540					crc_p[x] = 0;
541				}
542			}
543		}
544
545		if (rem_x) {
546			if (rc->hw_crc)
547				crc_p[x] = fast_crc32(p,
548				                    rem_x * sizeof(uint32_t),
549				                    crc_p[x]);
550			else
551				crc_p[x] = (uint32_t)crc32(crc_p[x],
552				                    (Bytef *)p,
553				                    rem_x * sizeof(uint32_t));
554			p += rem_x;
555
556			if ((y & PIXCELL_MASK) == PIXCELL_MASK || y == (h-1)) {
557				if (orig_crc[x] != crc_p[x]) {
558					orig_crc[x] = crc_p[x];
559					crc_p[x] = 1;
560					changes++;
561				} else {
562					crc_p[x] = 0;
563				}
564			}
565		}
566	}
567
568	/* If number of changes is > THRESH percent, send the whole screen */
569	if (((changes * 100) / (xcells * ycells)) >= RFB_SEND_ALL_THRESH) {
570		retval = rfb_send_all(rc, cfd, gc_image);
571		goto done;
572	}
573
574	/* Go through all cells, and send only changed ones */
575	crc_p = rc->crc_tmp;
576	for (y = 0; y < h; y += PIX_PER_CELL) {
577		/* previous cell's row */
578		celly = (y >> PIXCELL_SHIFT);
579
580		/* Delta check crc to previous set */
581		for (x = 0; x < xcells; x++) {
582			if (*crc_p++ == 0)
583				continue;
584
585			if (x == (xcells - 1) && rem_x > 0)
586				cellwidth = rem_x;
587			else
588				cellwidth = PIX_PER_CELL;
589			nwrite = rfb_send_rect(rc, cfd,
590				gc_image,
591				x * PIX_PER_CELL,
592				celly * PIX_PER_CELL,
593			        cellwidth,
594				y + PIX_PER_CELL >= h ? rem_y : PIX_PER_CELL);
595			if (nwrite <= 0) {
596				retval = nwrite;
597				goto done;
598			}
599		}
600	}
601	retval = 1;
602
603done:
604	pthread_mutex_lock(&rc->mtx);
605	rc->sending = 0;
606	pthread_mutex_unlock(&rc->mtx);
607
608	return (retval);
609}
610
611
612static void
613rfb_recv_update_msg(struct rfb_softc *rc, int cfd, int discardonly)
614{
615	struct rfb_updt_msg updt_msg;
616	struct bhyvegc_image *gc_image;
617
618	(void)stream_read(cfd, ((void *)&updt_msg) + 1 , sizeof(updt_msg) - 1);
619
620	console_refresh();
621	gc_image = console_get_image();
622
623	updt_msg.x = htons(updt_msg.x);
624	updt_msg.y = htons(updt_msg.y);
625	updt_msg.width = htons(updt_msg.width);
626	updt_msg.height = htons(updt_msg.height);
627
628	if (updt_msg.width != gc_image->width ||
629	    updt_msg.height != gc_image->height) {
630		rc->width = gc_image->width;
631		rc->height = gc_image->height;
632		if (rc->enc_resize_ok)
633			rfb_send_resize_update_msg(rc, cfd);
634	}
635
636	if (discardonly)
637		return;
638
639	rfb_send_screen(rc, cfd, 1);
640}
641
642static void
643rfb_recv_key_msg(struct rfb_softc *rc, int cfd)
644{
645	struct rfb_key_msg key_msg;
646
647	(void)stream_read(cfd, ((void *)&key_msg) + 1, sizeof(key_msg) - 1);
648
649	console_key_event(key_msg.down, htonl(key_msg.code));
650}
651
652static void
653rfb_recv_ptr_msg(struct rfb_softc *rc, int cfd)
654{
655	struct rfb_ptr_msg ptr_msg;
656
657	(void)stream_read(cfd, ((void *)&ptr_msg) + 1, sizeof(ptr_msg) - 1);
658
659	console_ptr_event(ptr_msg.button, htons(ptr_msg.x), htons(ptr_msg.y));
660}
661
662static void
663rfb_recv_cuttext_msg(struct rfb_softc *rc, int cfd)
664{
665	struct rfb_cuttext_msg ct_msg;
666	unsigned char buf[32];
667	int len;
668
669	len = stream_read(cfd, ((void *)&ct_msg) + 1, sizeof(ct_msg) - 1);
670	ct_msg.length = htonl(ct_msg.length);
671	while (ct_msg.length > 0) {
672		len = stream_read(cfd, buf, ct_msg.length > sizeof(buf) ?
673			sizeof(buf) : ct_msg.length);
674		ct_msg.length -= len;
675	}
676}
677
678static int64_t
679timeval_delta(struct timeval *prev, struct timeval *now)
680{
681	int64_t n1, n2;
682	n1 = now->tv_sec * 1000000 + now->tv_usec;
683	n2 = prev->tv_sec * 1000000 + prev->tv_usec;
684	return (n1 - n2);
685}
686
687static void *
688rfb_wr_thr(void *arg)
689{
690	struct rfb_softc *rc;
691	fd_set rfds;
692	struct timeval tv;
693	struct timeval prev_tv;
694	int64_t tdiff;
695	int cfd;
696	int err;
697
698	rc = arg;
699	cfd = rc->cfd;
700
701	prev_tv.tv_sec = 0;
702	prev_tv.tv_usec = 0;
703	while (rc->cfd >= 0) {
704		FD_ZERO(&rfds);
705		FD_SET(cfd, &rfds);
706		tv.tv_sec = 0;
707		tv.tv_usec = 10000;
708
709		err = select(cfd+1, &rfds, NULL, NULL, &tv);
710                if (err < 0)
711			return (NULL);
712
713		/* Determine if its time to push screen; ~24hz */
714		gettimeofday(&tv, NULL);
715		tdiff = timeval_delta(&prev_tv, &tv);
716		if (tdiff > 40000) {
717			prev_tv.tv_sec = tv.tv_sec;
718			prev_tv.tv_usec = tv.tv_usec;
719			if (rfb_send_screen(rc, cfd, 0) <= 0) {
720				return (NULL);
721			}
722		} else {
723			/* sleep */
724			usleep(40000 - tdiff);
725		}
726	}
727
728	return (NULL);
729}
730
731void
732rfb_handle(struct rfb_softc *rc, int cfd)
733{
734	const char *vbuf = "RFB 003.008\n";
735	unsigned char buf[80];
736	pthread_t tid;
737        uint32_t sres;
738	int len;
739
740	rc->cfd = cfd;
741
742	/* 1a. Send server version */
743	stream_write(cfd, vbuf, strlen(vbuf));
744
745	/* 1b. Read client version */
746	len = read(cfd, buf, sizeof(buf));
747
748	/* 2a. Send security type 'none' */
749	buf[0] = 1;
750	buf[1] = 1; /* none */
751	stream_write(cfd, buf, 2);
752
753
754	/* 2b. Read agreed security type */
755	len = stream_read(cfd, buf, 1);
756
757	/* 2c. Write back a status of 0 */
758	sres = 0;
759	stream_write(cfd, &sres, 4);
760
761	/* 3a. Read client shared-flag byte */
762	len = stream_read(cfd, buf, 1);
763
764	/* 4a. Write server-init info */
765	rfb_send_server_init_msg(cfd);
766
767	if (!rc->zbuf) {
768		rc->zbuf = malloc(RFB_ZLIB_BUFSZ + 16);
769		assert(rc->zbuf != NULL);
770	}
771
772	rfb_send_screen(rc, cfd, 1);
773
774	pthread_create(&tid, NULL, rfb_wr_thr, rc);
775	pthread_set_name_np(tid, "rfbout");
776
777        /* Now read in client requests. 1st byte identifies type */
778	for (;;) {
779		len = read(cfd, buf, 1);
780		if (len <= 0) {
781			DPRINTF(("rfb client exiting\r\n"));
782			break;
783		}
784
785		switch (buf[0]) {
786		case 0:
787			rfb_recv_set_pixfmt_msg(rc, cfd);
788			break;
789		case 2:
790			rfb_recv_set_encodings_msg(rc, cfd);
791			break;
792		case 3:
793			rfb_recv_update_msg(rc, cfd, 1);
794			break;
795		case 4:
796			rfb_recv_key_msg(rc, cfd);
797			break;
798		case 5:
799			rfb_recv_ptr_msg(rc, cfd);
800			break;
801		case 6:
802			rfb_recv_cuttext_msg(rc, cfd);
803			break;
804		default:
805			WPRINTF(("rfb unknown cli-code %d!\n", buf[0] & 0xff));
806			goto done;
807		}
808	}
809done:
810	rc->cfd = -1;
811	pthread_join(tid, NULL);
812	if (rc->enc_zlib_ok)
813		deflateEnd(&rc->zstream);
814}
815
816static void *
817rfb_thr(void *arg)
818{
819	struct rfb_softc *rc;
820	sigset_t set;
821
822	int cfd;
823
824	rc = arg;
825
826	sigemptyset(&set);
827	sigaddset(&set, SIGPIPE);
828	if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0) {
829		perror("pthread_sigmask");
830		return (NULL);
831	}
832
833	for (;;) {
834		rc->enc_raw_ok = false;
835		rc->enc_zlib_ok = false;
836		rc->enc_resize_ok = false;
837
838		cfd = accept(rc->sfd, NULL, NULL);
839		if (rc->conn_wait) {
840			pthread_mutex_lock(&rc->mtx);
841			pthread_cond_signal(&rc->cond);
842			pthread_mutex_unlock(&rc->mtx);
843			rc->conn_wait = 0;
844		}
845		rfb_handle(rc, cfd);
846		close(cfd);
847	}
848
849	/* NOTREACHED */
850	return (NULL);
851}
852
853static int
854sse42_supported(void)
855{
856	u_int cpu_registers[4], ecx;
857
858	do_cpuid(1, cpu_registers);
859
860	ecx = cpu_registers[2];
861
862	return ((ecx & CPUID2_SSE42) != 0);
863}
864
865int
866rfb_init(char *hostname, int port, int wait)
867{
868	struct rfb_softc *rc;
869	struct sockaddr_in sin;
870	int on = 1;
871
872	rc = calloc(1, sizeof(struct rfb_softc));
873
874	rc->crc = calloc(howmany(RFB_MAX_WIDTH * RFB_MAX_HEIGHT, 32),
875	                 sizeof(uint32_t));
876	rc->crc_tmp = calloc(howmany(RFB_MAX_WIDTH * RFB_MAX_HEIGHT, 32),
877	                     sizeof(uint32_t));
878	rc->crc_width = RFB_MAX_WIDTH;
879	rc->crc_height = RFB_MAX_HEIGHT;
880
881	rc->sfd = socket(AF_INET, SOCK_STREAM, 0);
882	if (rc->sfd < 0) {
883		perror("socket");
884		return (-1);
885	}
886
887	setsockopt(rc->sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
888
889	sin.sin_len = sizeof(sin);
890	sin.sin_family = AF_INET;
891	sin.sin_port = htons(port);
892	if (hostname && strlen(hostname) > 0)
893		inet_pton(AF_INET, hostname, &(sin.sin_addr));
894	else
895		sin.sin_addr.s_addr = htonl(INADDR_ANY);
896
897	if (bind(rc->sfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
898		perror("bind");
899		return (-1);
900	}
901
902	if (listen(rc->sfd, 1) < 0) {
903		perror("listen");
904		return (-1);
905	}
906
907	rc->hw_crc = sse42_supported();
908
909	rc->conn_wait = wait;
910	if (wait) {
911		pthread_mutex_init(&rc->mtx, NULL);
912		pthread_cond_init(&rc->cond, NULL);
913	}
914
915	pthread_create(&rc->tid, NULL, rfb_thr, rc);
916	pthread_set_name_np(rc->tid, "rfb");
917
918	if (wait) {
919		DPRINTF(("Waiting for rfb client...\n"));
920		pthread_mutex_lock(&rc->mtx);
921		pthread_cond_wait(&rc->cond, &rc->mtx);
922		pthread_mutex_unlock(&rc->mtx);
923	}
924
925	return (0);
926}
927