1 /* rfbproxy - a record/playback VNC proxy
2  * Copyright (C) 2000-3  Tim Waugh <twaugh@redhat.com>
3  * Copyright (C) 2005  Brent Baccala <baccala@freesoft.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
20 
21 /*
22  * rfbproxy is a program to record, playback, and export VNC sessions.
23  * It derives its name both from the RFB protocol used by VNC, and
24  * from Tim Waugh's original concept of a program to sit between a VNC
25  * client and a VNC server, holding network connections to both and
26  * copying the RFB protocol from one to the other while recording the
27  * server-to-client traffic to a file.  rfbproxy can still be used in
28  * this way, or it can be used in a shared-session mode, where it
29  * implements a simple client that connects to a VNC server in shared
30  * mode (i.e, simultaneously with other clients) and constantly
31  * requests framebuffer updates, which it copies to a file.  After
32  * recording a session, rfbproxy can either play it back to a VNC
33  * client (the original concept), or export it as a series of PPM
34  * frames suitable for further processing (conversion to MPEG video,
35  * mainly).
36  *
37  * Since clients can send a message to the server requesting whatever
38  * pixel format they please, a disadvantage of recording only the
39  * server-to-client traffic is that you can never be quite sure what
40  * pixel format the client has requested, and thus what format the
41  * recorded file is in!  Worse, since part of the configurable pixel
42  * format is the size of a pixel, you can never even be quite sure how
43  * long a framebuffer update is.  The original FBS 1.0 file format
44  * left this issue unaddressed.  FBS 1.1 is idential to FBS 1.0,
45  * except that it demands the server's native pixel format to be used
46  * throughout the recorded file.  FBS 1.1 files are created by a
47  * shared-session record; FBS 1.0 files are still created by a proxy
48  * record.
49  *
50  * If you want to play back an FBS 1.0 session to a VNC client, you
51  * should playback with the same client used to record.  This yields
52  * the best chances of the pixel format(s) in it matching what the
53  * client will request during playback.  xvncviewer 3.3.7, for
54  * example, requests first a small pixel format when it first
55  * connects, then switches to a larger pixel format if the network
56  * throughput seems acceptable.  A different client might not match
57  * these changes exactly, and thus be unable to playback an FBS 1.0
58  * session recorded with xvncviewer 3.3.7.
59  *
60  * FBS 1.1 playback is not without its problems, however.  rfbproxy
61  * correctly translates to the pixel format the client requests, but
62  * otherwise makes no attempt to understand the client messages.  In
63  * particular, a client that was partially obscured and requests an
64  * update to display a now-exposed region will find this request
65  * ignored.  rfbproxy simply feeds the client the framebuffer updates
66  * as they were recorded.
67  *
68  * On the other hand, if you want to export the recorded session as
69  * PPM frames, then you almost certainly want FBS 1.1 (shared-session
70  * record).  A proxy (FBS 1.0) session recorded from xvncviewer 3.3.7,
71  * for example, would be unusable for PPM export due the
72  * client-initiated changes to pixel format.
73  *
74  * Tim found that hextile encoding gives the best results.
75  *
76  * See also: the TODO file.
77  */
78 
79 /*
80  * The FBS (framebuffer stream) file format is this:
81  *
82  * <capture file> ::- <version><data>
83  * <version>      ::- 'FBS 001.000\n' | 'FBS 001.001\n'
84  * <data>         ::- <byte-count><raw-data><timestamp><data>
85  *                  | <byte-count><raw-data><timestamp>
86  * <byte-count>   ::- 32-bit number of bytes, big-endian
87  * <raw-data>     ::- data received at timestamp <timestamp>, which is
88  *                    <byte-count> bytes in length, padded to multiple
89  *                    of 32-bits
90  * <timestamp>    ::- 32-bit number of milliseconds since beginning of
91  *                    capture, big-endian
92  *
93  * Note that we don't capture any of the client messages (only the
94  * server messages are saved).
95  *
96  * A zero byte-count packet is interpreted as EOF (timestamped).
97  *
98  * FBS 001.000 leaves the pixel format in the file unspecified
99  * FBS 001.001 specify guarantees that the server's native
100  *    pixel format (announced in the initialization) is used throughout
101  *
102  * The RFM (remote framebuffer macro) file format is documented here:
103  * <URL:ftp://people.redhat.com/twaugh/rfbplaymacro/script-spec>
104  */
105 
106 #ifdef HAVE_CONFIG_H
107 #include "config.h"
108 #endif
109 
110 #include <stdio.h>
111 #include <ctype.h>
112 #include <unistd.h>
113 #include <stdlib.h>
114 #include <string.h>
115 #include <fcntl.h>
116 #include <getopt.h>
117 #include <netdb.h>
118 #include <time.h>
119 #include <signal.h>
120 #include <errno.h>
121 #include <setjmp.h>
122 
123 #if HAVE_STDINT_H
124 # include <stdint.h>
125 #else
126 # if HAVE_U_INTXX_T
127 #  ifndef __FreeBSD__
128 typedef u_int16_t uint16_t;
129 typedef u_int32_t uint32_t;
130 #  endif
131 # else
132 typedef unsigned short uint16_t;
133 typedef unsigned long uint32_t;
134 # endif
135 #endif
136 
137 #include <sys/types.h>
138 #include <sys/socket.h>
139 #include <sys/time.h>
140 #include <sys/stat.h>
141 #include <sys/mman.h>
142 #include <netinet/in.h>
143 #include <arpa/inet.h>
144 
145 #if HAVE_LIBVNCAUTH
146 void vncEncryptBytes(char *, char *);
147 #endif
148 
149 #define VNC_BASE 5900
150 #define DEFAULT_DISPLAY ":10"
151 #define DEFAULT_SERVER ":1"
152 #define BUFSIZE 65535
153 
154 #ifndef INADDR_LOOPBACK
155 # define INADDR_LOOPBACK ((in_addr_t) 0x7f000001)
156 #endif
157 
158 static int verbose = 0;
159 
160 /* struct pixel - holds one pixel in PPM format */
161 
162 struct pixel {
163 	unsigned char red;
164 	unsigned char green;
165 	unsigned char blue;
166 };
167 
168 /* struct FramebufferFormat - describes the layout of a VNC framebuffer */
169 
170 struct FramebufferFormat {
171 	uint16_t width, height;
172 	int bits_per_pixel, bytes_per_pixel, depth, big_endian, true_color;
173 	uint16_t red_max, green_max, blue_max;
174 	int red_bits, green_bits, blue_bits;
175 	int red_shift, green_shift, blue_shift;
176 };
177 
178 /********** struct FramebufferFormat FUNCTIONS **********/
179 
180 /* decode the network format in 'buf' and store it in 'fbf' */
181 
decode_PixelFormat(unsigned char * buf,struct FramebufferFormat * fbf)182 void decode_PixelFormat (unsigned char *buf,
183 			 struct FramebufferFormat *fbf)
184 {
185 	fbf->bits_per_pixel = buf[0];
186 	fbf->bytes_per_pixel = fbf->bits_per_pixel / 8;
187 	fbf->depth = buf[1];
188 	fbf->big_endian = buf[2];
189 	fbf->true_color = buf[3];
190 
191 	memcpy (&fbf->red_max, buf+4, 2);
192 	memcpy (&fbf->green_max, buf+6, 2);
193 	memcpy (&fbf->blue_max, buf+8, 2);
194 	fbf->red_max = ntohs(fbf->red_max);
195 	fbf->green_max = ntohs(fbf->green_max);
196 	fbf->blue_max = ntohs(fbf->blue_max);
197 	for (fbf->red_bits = 1; (1 << fbf->red_bits) < fbf->red_max; )
198 		fbf->red_bits ++;
199 	for (fbf->green_bits = 1; (1 << fbf->green_bits) < fbf->green_max; )
200 		fbf->green_bits ++;
201 	for (fbf->blue_bits = 1; (1 << fbf->blue_bits) < fbf->blue_max; )
202 		fbf->blue_bits ++;
203 
204 	fbf->red_shift=buf[10];
205 	fbf->green_shift=buf[11];
206 	fbf->blue_shift=buf[12];
207 }
208 
decode_FramebufferFormat(unsigned char * buf,struct FramebufferFormat * fbf)209 void decode_FramebufferFormat (unsigned char *buf,
210 			       struct FramebufferFormat *fbf)
211 {
212 	memcpy (&fbf->width, buf, 2);
213 	memcpy (&fbf->height, buf+2, 2);
214 	fbf->width = ntohs(fbf->width);
215 	fbf->height = ntohs(fbf->height);
216 
217 	decode_PixelFormat (buf+4, fbf);
218 }
219 
220 /* encode the format in 'fbf' into 20-byte, network-ready 'buf' */
221 
encode_FramebufferFormat(unsigned char * buf,struct FramebufferFormat * fbf)222 void encode_FramebufferFormat (unsigned char *buf,
223 			       struct FramebufferFormat *fbf)
224 {
225 	uint16_t val;
226 
227 	val = htons(fbf->width);
228 	memcpy(buf, &val, 2);
229 	val = htons(fbf->height);
230 	memcpy(buf+2, &val, 2);
231 
232 	buf += 4;
233 
234 	buf[0] = (unsigned char) fbf->bits_per_pixel;
235 	buf[1] = (unsigned char) fbf->depth;
236 	buf[2] = (unsigned char) fbf->big_endian;
237 	buf[3] = (unsigned char) fbf->true_color;
238 
239 	val = htons(fbf->red_max);
240 	memcpy(buf+4, &val, 2);
241 	val = htons(fbf->green_max);
242 	memcpy(buf+6, &val, 2);
243 	val = htons(fbf->blue_max);
244 	memcpy(buf+8, &val, 2);
245 
246 	buf[10] = (unsigned char) fbf->red_shift;
247 	buf[11] = (unsigned char) fbf->green_shift;
248 	buf[12] = (unsigned char) fbf->blue_shift;
249 
250 	/* three bytes of padding bring us to 15, the four we added earlier
251 	 * gives 19 (or 20)
252 	 */
253 }
254 
print_FramebufferFormat(FILE * file,struct FramebufferFormat * format)255 void print_FramebufferFormat(FILE *file, struct FramebufferFormat *format)
256 {
257 	fprintf(file, "%dx%dx%d %s endian %s RFB session\n",
258 		format->width, format->height, format->bits_per_pixel,
259 		format->big_endian ? "big" : "little",
260 		format->true_color ? "true color" : "colormap");
261 	fprintf(file, "red %x/%d, green %x/%d, blue %x/%d\n",
262 		format->red_max, format->red_shift,
263 		format->green_max, format->green_shift,
264 		format->blue_max, format->blue_shift);
265 }
266 
267 /********** read/write UTILITY FUNCTIONS **********/
268 
269 /* These functions repeatedly call read(2) or write(2) until the
270  * requested number of bytes have been transfered or there's
271  * been an error (in which case they exit the program).
272  */
273 
do_write(int fd,const void * buf,size_t len)274 static ssize_t do_write (int fd, const void *buf, size_t len)
275 {
276 	while (len) {
277 		ssize_t wrote = write (fd, buf, len);
278 		if (wrote < 0) {
279 			perror ("write");
280 			exit (1);
281 		}
282 		buf += wrote;
283 		len -= wrote;
284 	}
285 	return len;
286 }
287 
do_read(int fd,void * buf,size_t len)288 static ssize_t do_read (int fd, void *buf, size_t len)
289 {
290 	while (len) {
291 		ssize_t got = read (fd, buf, len);
292 		if (got < 0) {
293 			perror ("read");
294 			exit (1);
295 		}
296 		if (!got)
297 			break;
298 		buf += got;
299 		len -= got;
300 	}
301 	return len;
302 }
303 
304 /********** WRITING FBS FILES **********/
305 
write_packet(FILE * f,const void * buf,size_t len,struct timeval * tvp)306 static int write_packet (FILE *f, const void *buf, size_t len,
307 			 struct timeval *tvp)
308 {
309 	uint32_t timestamp = htonl (1000 * tvp->tv_sec + tvp->tv_usec / 1000);
310 	uint32_t dlen = htonl (len);
311 	len = 4 * ((len + 3) / 4);
312 	fwrite (&dlen, 4, 1, f);
313 	fwrite (buf, 1, len, f);
314 	fwrite (&timestamp, 4, 1, f);
315 	return 0;
316 }
317 
318 /********** READING FBS FILES **********/
319 
320 /* These functions are here because we might have RFB messages
321  * spanning multiple packets in the FBS file.  So we need to
322  * 'automatically' move to the next packet whenever we run out of data
323  * in the current one.  Of course, with computers, nothing happens
324  * 'automatically'.  Sigh.  We use a 'fileptr' structure to keep trace
325  * of where we are in the recorded file.  'next_packet' always points
326  * to the next FBS packet in the mmap'ed file; 'buf' points to the
327  * current byte in the current packet; 'len' indicates how many
328  * bytes are left in the current packet; 'ms' is the timestamp
329  * on the current packet.
330  */
331 
332 typedef struct fbs_fileptr {
333 	unsigned char *map;
334 	size_t map_size;
335 
336 	int major_version;
337 	int minor_version;
338 
339 	unsigned char *next_packet;
340 	unsigned char *buf;
341 	size_t len;
342 	unsigned long ms;
343 } FBSfile;
344 
345 /* next_packet() advances to the next FBS packet in the input steam
346  *
347  * We really don't have to consider read errors, since we've mmap()'ed
348  * the entire FBS file, but if the file is truncated (a common
349  * occurance) or we get out sync somehow, we can hit EOF way down deep
350  * inside these routines.  This is particularly an issue when we're
351  * playing back a series of files and one of them is truncated.
352  * We've got to make sure we cleanly end the last FramebufferUpdate,
353  * so we keep reading zeros after EOF.  This can produce a bunch
354  * of zero-sized rectangles, which generate only warnings with
355  * xvncviewer.
356  */
357 
fbs_at_eof(FBSfile * file)358 static int fbs_at_eof(FBSfile *file) {
359 	return (file->len == 0);
360 }
361 
next_packet(FBSfile * file)362 static void next_packet(FBSfile *file) {
363 
364 	uint32_t *bit32;
365 
366 	if (file->len == 0) {
367 		/* past EOF - do nothing */
368 		return;
369 	}
370 
371 	if (file->map + file->map_size - file->next_packet
372 	    < (2 * sizeof (uint32_t))) {
373 		/* at EOF - set EOF flag */
374 		file->len = 0;
375 		return;
376 	}
377 
378 	bit32 = (uint32_t *) file->next_packet;
379 	file->len = ntohl (*bit32);
380 
381 	if (file->map + file->map_size - file->next_packet
382 	    < (2 * sizeof (uint32_t)) + file->len) {
383 		/* something's wrong with this file - the next packet
384 		 * appears to go past EOF.  Signal EOF now.
385 		 */
386 		file->len = 0;
387 		return;
388 	}
389 
390 	/* delay from start of capture in milliseconds */
391 
392 	bit32 = (uint32_t *) (4 + file->next_packet
393 			      + 4 * ((file->len + 3)/ 4));
394 	file->ms = ntohl (*bit32);
395 
396 	/* set buf to start of data packet */
397 	file->buf = file->next_packet + sizeof (uint32_t);
398 
399 	/* set next_packet to start of next data packet */
400 	file->next_packet += 2 * sizeof (uint32_t) + 4 * ((file->len + 3) / 4);
401 
402 	if (verbose >= 3) {
403 		fprintf(stderr, "next_packet(): offset=%d len=%d ms=%ld\n",
404 			file->buf - file->map, file->len, file->ms);
405 	}
406 }
407 
FBSclose(FBSfile * file)408 static void FBSclose(FBSfile *file)
409 {
410 	if ((file->map != NULL)  &&  (file->map != MAP_FAILED)) {
411 		munmap (file->map, file->map_size);
412 	}
413 	file->map = NULL;
414 }
415 
FBSopen(const char * filename,FBSfile * fileptr)416 static int FBSopen (const char *filename, FBSfile *fileptr)
417 {
418 	int fd;
419 	struct stat st;
420 
421 	if ((fd = open (filename, O_RDONLY)) < 0) {
422 		perror(filename);
423 		return -1;
424 	}
425 
426 	if (fstat (fd, &st) == -1) {
427 		perror(filename);
428 		close(fd);
429 		return -1;
430 	}
431 
432 	fileptr->map = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
433 	fileptr->map_size = st.st_size;
434 
435 	if (fileptr->map == MAP_FAILED) {
436 		perror ("Couldn't map input file");
437 		close (fd);
438 		return -1;
439 	}
440 
441 	close (fd);
442 
443 	if (strncmp (fileptr->map, "FBS 001.", 8) != 0) {
444 		fprintf (stderr, "%s: Incorrect FBS version\n", filename);
445 		FBSclose(fileptr);
446 		return -1;
447 	}
448 
449 	fileptr->major_version = 1;
450 	fileptr->minor_version = fileptr->map[10] - '0';
451 
452 	fileptr->next_packet = fileptr->map + 12; /* Skip version */
453 	fileptr->len = 12;
454 
455 	next_packet(fileptr);
456 	return 0;
457 }
458 
459 /* Copy a number of bytes from the mmap'ed data stream, jumping to
460  * additional FBS packets if needed.  'dest' can be NULL, which
461  * advances the pointer past the bytes without copying them.
462  */
463 
get_bytes(FBSfile * file,void * dest,int bytes)464 void get_bytes(FBSfile *file, void *dest, int bytes)
465 {
466 	/* The difference between ">=" and ">" here is quite
467 	 * pronounced.  Often (but not always), the end of an FBS
468 	 * packet corresponds to the end of an RFB packet in the
469 	 * underlying stream.  Often this corresponds to a jump
470 	 * discontinuity in the timestamps, since if the session is
471 	 * quiet for a while, there'll be a final RFB packet ending a
472 	 * final FBS packet, then the next FBS (and RFB) packet will
473 	 * correspond to the moment when the session starts changing
474 	 * again.
475 	 *
476 	 * Obviously, we've got to handle this case right, or the
477 	 * last change made to the framebuffer before a pause will
478 	 * be exported after the pause, or the first change made
479 	 * after the pause will appear before the pause.
480 	 *
481 	 * That's where the ">=" comes in.  When we read exactly to
482 	 * the end of an FBS packet, we immediately advance to the
483 	 * next packet (without waiting for the next read).  This
484 	 * updates our timestamp to the next packet's.  So, if a
485 	 * framebuffer update ends on a packet boundary, when we're
486 	 * done processing the update, we will have advanced to the
487 	 * next packet's timestamp.  This causes a series of frames to
488 	 * be exported before we begin processing the next packet.
489 	 */
490 
491 	while ((bytes >= file->len) && !fbs_at_eof(file)) {
492 		bytes -= file->len;
493 		if (dest) {
494 			memcpy(dest, file->buf, file->len);
495 			dest += file->len;
496 		}
497 		next_packet(file);
498 	}
499 
500 	if (bytes > 0) {
501 		if (fbs_at_eof(file)) {
502 			if (dest) bzero(dest, bytes);
503 		} else {
504 			if (dest) memcpy(dest, file->buf, bytes);
505 			file->buf += bytes;
506 			file->len -= bytes;
507 		}
508 	}
509 }
510 
get_uchar(FBSfile * file)511 unsigned char get_uchar(FBSfile *file) {
512 	unsigned char val;
513 	get_bytes(file, &val, 1);
514 	return val;
515 }
516 
get_short(FBSfile * file)517 uint16_t get_short(FBSfile *file) {
518 	uint16_t val;
519 	get_bytes(file, (unsigned char *) &val, 2);
520 	return ntohs(val);
521 }
522 
get_long(FBSfile * file)523 uint32_t get_long(FBSfile *file) {
524 	uint32_t val;
525 	get_bytes(file, &val, 4);
526 	return ntohl(val);
527 }
528 
529 /* Read an RFB-format pixel from the input stream in the specified
530  * FramebufferFormat, convert it to PPM format and store it in *pptr.
531  *
532  * This function tacitly assumes that fbf->bytes_per_pixel is <= 4
533  * here (i.e, the pixel will fit into a uint32_t)
534  */
535 
get_pixel(FBSfile * file,struct FramebufferFormat * format,struct pixel * pptr)536 void get_pixel(FBSfile *file, struct FramebufferFormat *format,
537 	       struct pixel *pptr) {
538 
539 	unsigned char buf[4];
540 	int i;
541 	uint32_t rawpixel=0, pixel;
542 
543 	get_bytes(file, buf, format->bytes_per_pixel);
544 
545 	if (format->big_endian) {
546 		for (i = 0; i < format->bytes_per_pixel; i++) {
547 			rawpixel <<= 8;
548 			rawpixel |= buf[i];
549 		}
550 	} else {
551 		for (i = 0; i < format->bytes_per_pixel; i++) {
552 			rawpixel |= buf[i] << (8*i);
553 		}
554 	}
555 
556 	pixel = rawpixel;
557 	pixel >>= format->red_shift;
558 	pixel &= format->red_max;
559 	pixel <<= (8 - format->red_bits);
560 	pptr->red = (unsigned char) pixel;
561 
562 	pixel = rawpixel;
563 	pixel >>= format->green_shift;
564 	pixel &= format->green_max;
565 	pixel <<= (8 - format->green_bits);
566 	pptr->green = (unsigned char) pixel;
567 
568 	pixel = rawpixel;
569 	pixel >>= format->blue_shift;
570 	pixel &= format->blue_max;
571 	pixel <<= (8 - format->blue_bits);
572 	pptr->blue = (unsigned char) pixel;
573 }
574 
get_initial_RFB_handshake(FBSfile * file,struct FramebufferFormat * format)575 static int get_initial_RFB_handshake(FBSfile *file,
576 				     struct FramebufferFormat *format)
577 {
578 	int minor_protocol_version;
579 	char buffer[32];
580 	int auth;
581 	int length;
582 
583 	/* The server hello (RFB version 3.x, we hope) */
584 
585 	get_bytes(file, &buffer, 12);
586 	if (strncmp(buffer, "RFB 003.", 8) != 0) {
587 		fprintf(stderr, "Unknown RFB protocol\n");
588 		return -1;
589 	}
590 	minor_protocol_version = buffer[10] - '0';
591 
592 	if (minor_protocol_version == 3) {
593 
594 		/* The authentication scheme */
595 
596 		auth = get_long(file);
597 
598 		if (auth == 0) {
599 
600 			/* a real useful session! */
601 			fprintf(stderr, "session failed authentication!\n");
602 			return -1;
603 
604 		} else if (auth == 1) {
605 
606 			/* No authentication used (or none recorded) */
607 
608 		} else if (auth == 2) {
609 
610 			/* first a sixteen byte challenge */
611 			get_bytes(file, NULL, 16);
612 
613 			/* we don't see the client response */
614 
615 			/* now the result of the authentication */
616 			auth = get_long(file);
617 
618 			if (auth != 0) {
619 				/* another real useful session! */
620 				fprintf(stderr,
621 					"session failed authentication!\n");
622 				return -1;
623 			}
624 
625 		} else {
626 			fprintf(stderr,
627 				"session used unknown authentication!\n");
628 			return -1;
629 		}
630 
631 	} else {
632 
633 		int num_security_types = get_uchar(file);
634 
635 		get_bytes(file, NULL, num_security_types);
636 
637 		/* Now we've got a problem.  In version 3.7 (and newer),
638 		 * the client now picks on of the security types for
639 		 * authentication.  But since we only record server
640 		 * messages, there's no way to know which one got picked.
641 		 * Sigh.  We assume that the record code discarded
642 		 * all the authentication details and proceed...
643 		 */
644 	}
645 
646 	/* ServerInitialisation */
647 
648 	get_bytes(file, &buffer, 20);
649 	decode_FramebufferFormat(buffer, format);
650 
651 	if (verbose > 0) {
652 		fprintf(stderr, "file uses format:\n");
653 		print_FramebufferFormat(stderr, format);
654 	}
655 
656 	/* name of desktop */
657 
658 	length = get_long(file);
659 	get_bytes(file, NULL, length);
660 
661 	return 0;
662 }
663 
664 /********** BUFFERED OUTPUT **********/
665 
fput_short(uint16_t val,FILE * file)666 int fput_short(uint16_t val, FILE *file)
667 {
668 	val = htons(val);
669 	return fwrite(&val, 2, 1, file);
670 }
671 
fput_long(uint32_t val,FILE * file)672 int fput_long(uint32_t val, FILE *file)
673 {
674 	val = htonl(val);
675 	return fwrite(&val, 4, 1, file);
676 }
677 
678 /* just like get_pixel, we assume the pixel will fit into 32 bits */
679 
fput_pixel(struct pixel * pptr,struct FramebufferFormat * format,FILE * file)680 int fput_pixel(struct pixel *pptr, struct FramebufferFormat *format,
681 	       FILE *file)
682 {
683 	uint32_t pixel;
684 	int ret;
685 
686 	pixel = ((pptr->red >> (8 - format->red_bits))
687 		 << format->red_shift)
688 		| ((pptr->green >> (8 - format->green_bits))
689 		   << format->green_shift)
690 		| ((pptr->blue >> (8 - format->blue_bits))
691 		   << format->blue_shift);
692 
693 	if (format->big_endian) {
694 		switch (format->bytes_per_pixel) {
695 		case 4:
696 			fputc(pixel>>24, file);
697 		case 3:
698 			fputc((pixel>>16) & 0xff, file);
699 		case 2:
700 			fputc((pixel>>8) & 0xff, file);
701 		case 1:
702 		default:
703 			return fputc(pixel & 0xff, file);
704 		}
705 	} else {
706 		ret = fputc(pixel & 0xff, file);
707 		if (format->bytes_per_pixel >= 2)
708 			ret = fputc((pixel>>8) & 0xff, file);
709 		if (format->bytes_per_pixel >= 3)
710 			ret = fputc((pixel>>16) & 0xff, file);
711 		if (format->bytes_per_pixel == 4)
712 			ret =  fputc(pixel>>24, file);
713 		return ret;
714 	}
715 }
716 
717 /********** VARIOUS AUTHENTICATION SCHEMES **********/
718 
719 /* Passthrough authentication is when we have a client connecting
720  * through this program to a server.  We let them authenticate with
721  * each other and just record the key information about the session.
722  * This can get tricky as we do need to track the authentication as it
723  * happens, and have no direct control over which protocol version is
724  * used.  We support RFB protocol versions 3.3, 3.7, and 3.8.
725  *
726  * The FBS log file is 'f' and the server's default format is written
727  * to 'fbf'
728  */
729 
do_passthrough_authentication(int server,int clientr,int clientw,FILE * f,int do_events_instead,struct FramebufferFormat * fbf)730 static int do_passthrough_authentication (int server, int clientr, int clientw,
731 					  FILE *f, int do_events_instead,
732 					  struct FramebufferFormat *fbf)
733 {
734 	char packet[24];
735 	size_t packet_size;
736 	struct timeval start;
737 	uint32_t auth;
738 	int protocol_minor_version;
739 
740 	start.tv_sec = 0;
741 	start.tv_usec = 0;
742 
743 	/* ProtocolVersion */
744 	if (do_read (server, packet, 12)) {
745 		fprintf(stderr, "Can't read server ProtocolVersion\n");
746 		return 1;
747 	}
748 	do_write (clientw, packet, 12);
749 	if (do_read (clientr, packet, 12)) {
750 		fprintf(stderr, "Can't read client ProtocolVersion\n");
751 		return 1;
752 	}
753 	do_write (server, packet, 12);
754 	if (!do_events_instead)
755 		/* Record the protocol in use */
756 		write_packet (f, packet, 12, &start);
757 	packet_size = 4;
758 	protocol_minor_version = packet[10] - '0';
759 	if (protocol_minor_version >= 7) {
760 		packet_size = 1;
761 	}
762 
763 	/* Authentication */
764 	if (do_read (server, packet, packet_size)) {
765 		fprintf(stderr, "Can't read server authentication start\n");
766 		return 1;
767 	}
768 
769 	if (protocol_minor_version == 3) {
770 		uint32_t noauth = htonl (1);
771 		do_write (clientw, packet, 4);
772 		memcpy (&auth, packet, 4);
773 		auth = ntohl (auth);
774 		if (!do_events_instead) {
775 			memcpy (packet, &noauth, 4);
776 			write_packet (f, packet, 4, &start);
777 		}
778 	} else {
779 		size_t num_types;
780 		num_types = (size_t) packet[0];
781 		if (num_types == 0) {
782 			uint32_t reason_length;
783 			if (do_read (server, &reason_length, 4)) {
784 				fprintf(stderr,
785 					"Can't read server reason length\n");
786 				return 1;
787 			}
788 			reason_length = ntohl(reason_length);
789 			if (do_read (server, packet, reason_length)) {
790 				fprintf(stderr, "Can't read server reason\n");
791 				return 1;
792 			}
793 			fprintf(stderr, "Connection failed: %.*s\n",
794 				(int) reason_length, packet);
795 			return 1;
796 		}
797 		if (do_read (server, packet + 1, num_types)) {
798 			fprintf(stderr, "Can't read server auth type list\n");
799 			return 1;
800 		}
801 		do_write (clientw, packet, num_types + 1);
802 		if (do_read (clientr, packet, 1)) {
803 			fprintf(stderr, "Can't read client auth type\n");
804 			return 1;
805 		}
806 		do_write (server, packet, 1);
807 		auth = (uint32_t) packet[0];
808 		if (!do_events_instead) {
809 			packet[0] = 1;
810 			packet[1] = 1;
811 			write_packet (f, packet, 2, &start);
812 		}
813 	}
814 
815 	/* auth type 0 (authentication failed) can be ignored,
816 	 * and auth type 1 (no authentication) just skips ahead
817 	 * in pre-3.8 protocol versions.
818 	 */
819 
820 	if ((auth == 1) && (protocol_minor_version >= 8)) {
821 		if (do_read (server, packet, 4)) {
822 			fprintf(stderr, "Can't read server auth response\n");
823 			return 1;
824 		}
825 		do_write (clientw, packet, 4);
826 	}
827 
828 	if (auth == 2) {
829 		/* Don't record this stuff. */
830 		if (do_read (server, packet, 16)) {
831 			fprintf(stderr, "Can't read server challenge\n");
832 			return 1;
833 		}
834 		do_write (clientw, packet, 16);
835 		if (do_read (clientr, packet, 16)) {
836 			fprintf(stderr, "Can't read client response\n");
837 			return 1;
838 		}
839 		do_write (server, packet, 16);
840 		if (do_read (server, packet, 4)) {
841 			fprintf(stderr, "Can't read server auth response\n");
842 			return 1;
843 		}
844 		do_write (clientw, packet, 4);
845 	}
846 
847 	if (auth > 2) {
848 		fprintf(stderr, "Authentication type %d not understood\n",
849 			auth);
850 	}
851 
852 	/* ClientInitialisation */
853 	if (do_read (clientr, packet, 1)) {
854 		fprintf(stderr, "Can't read client shared-session flag\n");
855 		return 1;
856 	}
857 	do_write (server, packet, 1);
858 
859 	/* ServerInitialisation */
860 	if (do_read (server, packet, 24)) {
861 		fprintf(stderr, "Can't read ServerInitialization\n");
862 		return 1;
863 	} else {
864 		uint32_t name_length;
865 		char *buffer;
866 
867 		if (fbf != NULL) {
868 			decode_FramebufferFormat(packet, fbf);
869 		}
870 
871 		memcpy (&name_length, packet + 20, 4);
872 		name_length = ntohl (name_length);
873 		buffer = malloc (name_length);
874 		if (!buffer) {
875 			fprintf(stderr, "Can't malloc desktop name\n");
876 			return 1;
877 		}
878 		if (do_read (server, buffer, name_length)) {
879 			fprintf(stderr, "Can't read server desktop name\n");
880 			free (buffer);
881 			return 1;
882 		}
883 		do_write (clientw, packet, 24);
884 		do_write (clientw, buffer, name_length);
885 		if (!do_events_instead) {
886 			write_packet (f, packet, 24, &start);
887 			if (name_length > 0) {
888 				write_packet (f, buffer, name_length, &start);
889 			}
890 		}
891 		free (buffer);
892 	}
893 
894 	return 0;
895 }
896 
897 /* Standalone authentication occurs when we don't have a client to 'help'
898  * us authenticate to a server.  We do VNC 3.3 authentication ourselves.
899  *
900  * The FBS log file is 'f' and the server's default format is written to 'fbf'
901  */
902 
do_standalone_authentication(int server,FILE * f,struct FramebufferFormat * fbf)903 static int do_standalone_authentication (int server, FILE *f,
904 					 struct FramebufferFormat * fbf)
905 {
906 	char packet[24];
907 	size_t packet_size;
908 	struct timeval start;
909 	uint32_t auth;
910 	uint32_t noauth = htonl (1);
911 
912 	start.tv_sec = 0;
913 	start.tv_usec = 0;
914 
915 	/* ProtocolVersion */
916 	if (do_read (server, packet, 12))
917 		return 1;
918 
919 	/* If the server announced a version higher than 3.3, then
920 	 * we'll downgrade to 3.3.  Make sure the file version
921 	 * reflects this - otherwise it will look like a higher
922 	 * version than it is.
923 	 */
924 	if ((packet[6] > '3') || (packet[10] > '3')) {
925 		packet[6] = '3';
926 		packet[10] = '3';
927 	}
928 	write_packet (f, packet, 12, &start);
929 
930 	do_write (server, "RFB 003.003\n", 12);
931 
932 	/* Authentication */
933 	packet_size = 4;
934 	if (do_read (server, packet, packet_size))
935 		return 1;
936 
937 	memcpy (&auth, packet, 4);
938 	auth = ntohl (auth);
939 	/* we record a 'noauth' packet in the trace file
940 	 * because we don't want to record the authentication
941 	 */
942 	memcpy (packet, &noauth, 4);
943 	write_packet (f, packet, 4, &start);
944 
945 	if (auth != 1) {
946 #if HAVE_LIBVNCAUTH
947 		char *passwd;
948 		char challenge[16];
949 		int i;
950 		uint32_t authResult;
951 
952 		if (do_read (server, challenge, sizeof(challenge)))
953 			return 1;
954 
955 		passwd = getpass("Password: ");
956 
957 		if ((!passwd) || (strlen(passwd) == 0)) {
958 			fprintf(stderr,"Reading password failed\n");
959 			return 1;
960 		}
961 
962 		if (strlen(passwd) > 8) {
963 			passwd[8] = '\0';
964 		}
965 
966 		vncEncryptBytes(challenge, passwd);
967 
968 		/* Lose the password from memory */
969 		for (i = strlen(passwd); i >= 0; i--) {
970 			passwd[i] = '\0';
971 		}
972 
973 		do_write (server, challenge, sizeof(challenge));
974 
975 		packet_size = 4;
976 		if (do_read (server, packet, packet_size))
977 			return 1;
978 
979 		memcpy (&authResult, packet, 4);
980 		authResult = ntohl(authResult);
981 
982 		switch (authResult) {
983 		case 0:
984 			fprintf(stderr,"VNC authentication succeeded\n");
985 			break;
986 		case 1:
987 			fprintf(stderr,"VNC authentication failed -"
988 				"bad password\n");
989 			return 1;
990 		case 2:
991 			fprintf(stderr,"VNC authentication failed - "
992 				"too many tries\n");
993 			return 1;
994 		default:
995 			fprintf(stderr,"Unknown VNC authentication result: %d\n",
996 				(int)authResult);
997 			return 1;
998 		}
999 #else
1000 		fprintf (stderr, "rfbproxy compiled without libvncauth: "
1001 			 "can't authenticate!\n");
1002 		return 1;
1003 #endif
1004 	}
1005 
1006 	/* ClientInitialisation - ask for a shared session */
1007 	do_write (server, "s", 1);
1008 
1009 	/* ServerInitialisation */
1010 	if (do_read (server, packet, 24))
1011 		return 1;
1012 	else {
1013 		uint32_t name_length;
1014 		char *buffer;
1015 
1016 		if (fbf != NULL) {
1017 			decode_FramebufferFormat(packet, fbf);
1018 		}
1019 
1020 		memcpy (&name_length, packet + 20, 4);
1021 		name_length = ntohl (name_length);
1022 		buffer = malloc (name_length);
1023 		if (!buffer)
1024 			return 1;
1025 		if (do_read (server, buffer, name_length)) {
1026 			free (buffer);
1027 			return 1;
1028 		}
1029 		write_packet (f, packet, 24, &start);
1030 		if (name_length > 0) {
1031 			write_packet (f, buffer, name_length, &start);
1032 		}
1033 		free (buffer);
1034 	}
1035 
1036 	return 0;
1037 }
1038 
1039 /* This is used when a client is connecting to us as the server.
1040  * We use VNC 3.3.
1041  *
1042  * 'fbf' needs to be initialized before this function is called; it's
1043  * the default server format this function announces to the client.
1044  */
1045 
do_server_initialization(int clientr,int clientw,struct FramebufferFormat * fbf)1046 static int do_server_initialization (int clientr, int clientw,
1047 				     struct FramebufferFormat *fbf)
1048 {
1049 	char packet[24];
1050 	uint32_t noauth = htonl(1);
1051 
1052 	/* s->c ProtocolVersion */
1053 	do_write (clientw, "RFB 003.003\n", 12);
1054 
1055 	/* c->s ProtocolVersion */
1056 	if (do_read (clientr, packet, 12))
1057 		return 1;
1058 
1059 	/* s->c no authentication */
1060 	do_write (clientw, &noauth, 4);
1061 
1062 	/* c->s client initialization - shared flag - ignored  */
1063 	if (do_read (clientr, packet, 1))
1064 		return 1;
1065 
1066 	/* s->c server initialization - 20 bytes of format plus four byte
1067 	 * integer indicating a zero length name string
1068 	 */
1069 	bzero(packet, 24);
1070 	encode_FramebufferFormat(packet, fbf);
1071 	do_write (clientw, packet, 24);
1072 
1073 	return 0;
1074 }
1075 
1076 /********** RECORDING **********/
1077 
1078 /* RFB client messages can be regarded as having two parts - a
1079  * constant-sized part followed by a variable-sized part.  The size of
1080  * the variable part depends only on the constant part.  This function
1081  * returns the size of a variable part, given a pointer to a constant
1082  * part.
1083  */
1084 
variable_part(char * buffer)1085 static size_t variable_part (char *buffer)
1086 {
1087 	int message = (int) *buffer;
1088 	switch (message) {
1089 	case 0: /* SetPixelFormat */
1090 	case 3: /* FramebufferUpdateRequest */
1091 	case 4: /* KeyEvent */
1092 	case 5: /* PointerEvent */
1093 		/* No variable part */
1094 		return 0;
1095 	case 1: /* FixColourMapEntries */
1096 	{
1097 		uint16_t number_of_colours;
1098 		memcpy (&number_of_colours, buffer + 4, 2);
1099 		number_of_colours = ntohs (number_of_colours);
1100 		return number_of_colours * 6;
1101 	}
1102 	case 2: /* SetEncodings */
1103 	{
1104 		uint16_t number_of_encodings;
1105 		memcpy (&number_of_encodings, buffer + 2, 2);
1106 		number_of_encodings = ntohs (number_of_encodings);
1107 		return number_of_encodings * 4;
1108 	}
1109 	case 6: /* ClientCutText */
1110 	{
1111 		uint32_t length;
1112 		memcpy (&length, buffer + 4, 4);
1113 		length = ntohl (length);
1114 		return length;
1115 	}
1116 	} /* switch */
1117 
1118 	/* Caught earlier anwyay */
1119 	fprintf (stderr, "Protocol error\n");
1120 	exit (1);
1121 }
1122 
1123 /* For recording */
process_client_message(char * fixed,char * variable,FILE * f)1124 static int process_client_message (char *fixed, char *variable, FILE *f)
1125 {
1126 	static int first = 1;
1127 	static char delayed_output[100];
1128 	static int elapsed;
1129 	static struct timeval last_tv, first_tv;
1130 	struct timeval tv, diff;
1131 	struct timezone tz;
1132 	static unsigned int last_was_key_down;
1133 	static unsigned int current_x, current_y;
1134 	static unsigned char current_buttons;
1135 	int ms;
1136 	int message = (int) *fixed;
1137 
1138 	gettimeofday (&tv, &tz);
1139 	if (!last_tv.tv_sec && !last_tv.tv_usec)
1140 		first_tv = last_tv = tv;
1141 	diff.tv_sec = tv.tv_sec - last_tv.tv_sec;
1142 	diff.tv_usec = tv.tv_usec - last_tv.tv_usec;
1143 	ms = diff.tv_sec * 1000 + diff.tv_usec / 1000;
1144 
1145 	if (first) {
1146 		first = 0;
1147 		fputs ("RFM 001.000\nshared\n", f);
1148 	} else if (*delayed_output && (!last_was_key_down || message > 4)) {
1149 		/* We need to output a deferred line after calculating
1150 		 * the delay */
1151 		if (ms > 0) {
1152 			char *p = delayed_output + strlen (delayed_output);
1153 			sprintf (p, " delay %dms", ms);
1154 		}
1155 		strcat (delayed_output, "\n");
1156 		fputs (delayed_output, f);
1157 		last_tv = tv;
1158 		*delayed_output = '\0';
1159 	}
1160 
1161 	switch (message) {
1162 	case 0: /* SetPixelFormat */
1163 	case 1: /* FixColourMapEntries */
1164 	case 2: /* SetEncodings */
1165 	case 3: /* FramebufferUpdateRequest */
1166 		diff.tv_sec = tv.tv_sec - first_tv.tv_sec;
1167 		diff.tv_usec = tv.tv_usec - first_tv.tv_usec;
1168 		ms = diff.tv_sec * 1000 + diff.tv_usec / 1000;
1169 		if (ms > (1000 * (1 + elapsed))) {
1170 			fprintf (f, "# At %dms from start\n", ms);
1171 			elapsed = ms / 1000;
1172 		}
1173 		return 0;
1174 	case 4: /* KeyEvent */
1175 	{
1176 		char *p = delayed_output;
1177 		const char *down_flag = "up";
1178 		uint32_t key;
1179 
1180 		memcpy (&key, fixed + 4, 4);
1181 		key = ntohl (key);
1182 
1183 		/* We might be changing key up/down into press */
1184 		if (*delayed_output) {
1185 			/* last_was_key_down is the last key down */
1186 			if (fixed[1] || last_was_key_down != key || ms > 400) {
1187 				/* Can't make a press out of that */
1188 				char *p = delayed_output;
1189 				p += strlen (p);
1190 				if (ms > 0)
1191 					sprintf (p, " delay %dms", ms);
1192 				strcat (delayed_output, "\n");
1193 				fputs (delayed_output, f);
1194 				last_tv = tv;
1195 				*delayed_output = '\0';
1196 				last_was_key_down = 0;
1197 			} else {
1198 				char *p = delayed_output;
1199 				char *end;
1200 				p += strcspn (p, " \t");
1201 				p += strspn (p, " \t");
1202 				end = p + strcspn (p, " \t");
1203 				*end = '\0';
1204 				end = strdup (p);
1205 				sprintf (delayed_output, "press %s", end);
1206 				last_was_key_down = 0;
1207 				break;
1208 			}
1209 		}
1210 
1211 		if (fixed[1]) {
1212 			last_was_key_down = key;
1213 			down_flag = "down";
1214 		}
1215 		sprintf (p, "key ");
1216 		p += strlen (p);
1217 		if (key < 256 && isprint ((char) key) && !isspace ((char) key))
1218 			*p++ = (char) key;
1219 		else {
1220 			sprintf (p, "%#x", key);
1221 			p += strlen (p);
1222 		}
1223 
1224 		sprintf (p, " %s", down_flag);
1225 		break;
1226 	}
1227 	case 5: /* PointerEvent */
1228 	{
1229 		uint16_t x, y;
1230 		unsigned char buttons = fixed[1];
1231 		memcpy (&x, fixed + 2, 2);
1232 		memcpy (&y, fixed + 4, 2);
1233 		x = ntohs (x);
1234 		y = ntohs (y);
1235 
1236 		/* First deal with buttons */
1237 		if (buttons != current_buttons) {
1238 			int i;
1239 			int diff = buttons ^ current_buttons;
1240 			while ((i = ffs (diff))) {
1241 				if (*delayed_output) {
1242 					strcat (delayed_output, "\n");
1243 					fputs (delayed_output, f);
1244 				}
1245 				i--;
1246 				sprintf (delayed_output,
1247 					 "button %d %s", i,
1248 					 (buttons & (1<<i)) ? "down" : "up");
1249 				diff ^= 1<<i;
1250 			}
1251 			current_buttons = buttons;
1252 		}
1253 
1254 		/* Now deal with position */
1255 		if (current_x != x || current_y != y) {
1256 			if (*delayed_output) {
1257 				strcat (delayed_output, "\n");
1258 				fputs (delayed_output, f);
1259 			}
1260 			sprintf (delayed_output,
1261 				 "pointer %d %d", x, y);
1262 			current_x = x;
1263 			current_y = y;
1264 		}
1265 		break;
1266 	}
1267 	case 6: /* ClientCutText */
1268 		fputs ("# ClientCutText not supported yet\n", f);
1269 		break;
1270 	default:
1271 		fprintf (stderr, "Protocol error\n");
1272 		exit (1);
1273 	}
1274 	return 0;
1275 }
1276 
1277 /* At the end of a shared-session record we'll probably be terminated
1278  * by a signal (a proxy record will probably be terminated by a client
1279  * disconnect).  We'll want to write a trailing packet and neatly
1280  * flush our buffers, so arrange for the first signal (i.e, CNTL-C) to
1281  * just set a flag.  A second CNTL-C will terminate the program.
1282  */
1283 
1284 int terminating=0;
1285 
signal_handler(int signum)1286 void signal_handler(int signum)
1287 {
1288 	if (!terminating) {
1289 		terminating = 1;
1290 	} else {
1291 		exit(0);
1292 	}
1293 }
1294 
record(const char * file,int clientr,int clientw,struct sockaddr_in server_addr,int do_events_instead,int appenddate,int shared_session)1295 static int record (const char *file, int clientr, int clientw,
1296 		   struct sockaddr_in server_addr, int do_events_instead,
1297 		   int appenddate, int shared_session)
1298 {
1299 	const char *version0 = "FBS 001.000\n";
1300 	const char *version1 = "FBS 001.001\n";
1301 	FILE *f;
1302 	int server = -1;
1303 	struct timeval epoch;
1304 	struct timeval tv;
1305 	struct timeval diff;
1306 	struct timezone tz;
1307 	int first = 1;
1308 	char *buf = malloc (BUFSIZE);
1309 	unsigned char FramebufferUpdateRequest[10];
1310 	struct FramebufferFormat fbf;
1311 	time_t now;
1312 
1313 	if (!buf) {
1314 		fprintf (stderr, "Couldn't allocate buffer\n");
1315 		exit (1);
1316 	}
1317 
1318 	if (appenddate)
1319 	{ /* if we're appending the date, make the new filename in 'buf'.  if we're not, just call
1320 	     fopen directly on 'file' */
1321 		if (strlen(file)+17 > BUFSIZE)
1322 		{	/* Ya, like this is going to happen.  whatever */
1323 			fprintf (stderr, "Filename is bigger than filename buffer size.  Increase BUFSIZE and recompile\n");
1324 			exit (1);
1325 		}
1326 		time(&now);
1327 		strftime(buf+sprintf(buf, "%s-", file), 16, "%Y%m%d-%H%M%S", localtime(&now));
1328 		f = fopen (buf, "wb");
1329 	} else {
1330 		f = fopen (file, "wb");
1331 	}
1332 	if (!f) {
1333 		perror ("fopen");
1334 		exit (1);
1335 	}
1336 
1337 	if (!do_events_instead) {
1338 		if (shared_session) {
1339 			fwrite (version1, 1, 12, f);
1340 		} else {
1341 			fwrite (version0, 1, 12, f);
1342 		}
1343 	}
1344 
1345 	server = socket (PF_INET, SOCK_STREAM, IPPROTO_IP);
1346 	if (server == -1) {
1347 		perror ("socket");
1348 		goto out;
1349 	}
1350 
1351 	if (connect (server, (struct sockaddr *) &server_addr,
1352 		     sizeof (struct sockaddr_in))) {
1353 		perror ("connect");
1354 		goto out;
1355 	}
1356 
1357 	if (!shared_session) {
1358 		if (do_passthrough_authentication (server, clientr, clientw,
1359 						   f, do_events_instead, &fbf)) {
1360 			fprintf (stderr, "Error during authentication\n");
1361 			exit (1);
1362 		}
1363 	} else {
1364 		if (do_standalone_authentication (server, f, &fbf)) {
1365 			fprintf (stderr, "Error during authentication\n");
1366 			exit (1);
1367 		}
1368 	}
1369 
1370 	/* For a shared session, we now tell the server which pixel
1371 	 * encodings we support.  For a non-shared (i.e, passthrough)
1372 	 * session, we just use whatever our client requests.  This is
1373 	 * different from the pixel format - we can tell from the
1374 	 * framebuffer update which pixel encodings are actually used.
1375 	 * Codings are listed in order of preference.  The ones
1376 	 * our export and translate code currently understand are:
1377 	 *
1378 	 * 5 - hextile
1379 	 * 4 - CoRRE
1380 	 * 2 - RRE
1381 	 * 1 - copyrect
1382 	 * 0 - raw
1383 	 */
1384 
1385 	if (shared_session) {
1386 		int codings[] = {5, 4, 2, 1, 0};
1387 		int ncodings = sizeof(codings)/sizeof(int);
1388 		uint16_t nncodings;
1389 		int i;
1390 		unsigned char SetEncodings[32];
1391 
1392 		memset(SetEncodings, 0, sizeof(SetEncodings));
1393 		SetEncodings[0] = 2;
1394 		nncodings = htons(ncodings);
1395 		memcpy(SetEncodings+2, &nncodings, 2);
1396 		for (i=0; i<ncodings; i++) {
1397 			uint32_t coding = htonl(codings[i]);
1398 			memcpy(SetEncodings+4*(i+1), &coding, 4);
1399 		}
1400 
1401 		do_write (server, SetEncodings, 4*(ncodings+1));
1402 	}
1403 
1404 	/* We need to 'prime' a shared session by requesting a copy of
1405 	 * the screen, then constantly re-requesting it.  Construct
1406 	 * an incremental FramebufferUpdateRequest for this purpose.
1407 	 */
1408 
1409 	if (shared_session) {
1410 		uint16_t val;
1411 		memset(FramebufferUpdateRequest, 0, 10);
1412 		FramebufferUpdateRequest[0] = 3;
1413 		FramebufferUpdateRequest[1] = 1;
1414 		val = htons(fbf.width);
1415 		memcpy(FramebufferUpdateRequest+6, &val, 2);
1416 		val = htons(fbf.height);
1417 		memcpy(FramebufferUpdateRequest+8, &val, 2);
1418 
1419 		do_write (server, FramebufferUpdateRequest, 10);
1420 	}
1421 
1422 	fprintf(stderr, "rfbproxy: recording session to %s\n",
1423 		appenddate ? buf : file);
1424 
1425 	/* Arrange for clean termination - especially for a shared session */
1426 
1427 	signal(SIGINT, signal_handler);		/* CNTL-C */
1428 	signal(SIGTERM, signal_handler);	/* kill's default signal */
1429 
1430 	while (1) {
1431 		ssize_t bufs;
1432 		fd_set rfds;
1433 		FD_ZERO (&rfds);
1434 		FD_SET (server, &rfds);
1435 		if (!shared_session) FD_SET (clientr, &rfds);
1436 
1437 		if (terminating == 1) {
1438 			shutdown(server, SHUT_WR);
1439 			terminating = 2;
1440 		}
1441 
1442 		if ((select(FD_SETSIZE, &rfds, NULL, NULL, NULL) < 0)
1443 		    && errno != EINTR) {
1444 			perror ("select");
1445 			goto out;
1446 		}
1447 
1448 		if (FD_ISSET (server, &rfds)) {
1449 
1450 			gettimeofday (&tv, &tz);
1451 			if (first) {
1452 				first = 0;
1453 				epoch = tv;
1454 			}
1455 			bufs = read (server, buf, BUFSIZE);
1456 			if (!bufs) break;
1457 			if (!shared_session) do_write (clientw, buf, bufs);
1458 			diff.tv_sec = tv.tv_sec - epoch.tv_sec;
1459 			diff.tv_usec = tv.tv_usec - epoch.tv_usec;
1460 			if (!do_events_instead)
1461 				write_packet (f, buf, bufs, &diff);
1462 			if (shared_session && !terminating)
1463 				do_write(server, FramebufferUpdateRequest, 10);
1464 		}
1465 
1466 		if (!shared_session && FD_ISSET(clientr, &rfds)) {
1467 			/* We want to actually listen to the
1468 			 * individual client messages.
1469 			 *
1470 			 * The largest non-variable part of a
1471 			 * client->server message is 20 bytes.  */
1472 			static char tmp_buffer[20];
1473 			static char client_buffer[20];
1474 			static char *variable_buffer;
1475 			static size_t variable_bytes_left;
1476 			static size_t variable_bytes_got;
1477 			static size_t client_bytes_got;
1478 			static size_t client_bytes_left;
1479 			static const size_t mlen[] = {
1480 				20, 6, 4, 10, 8, 6, 8
1481 			}; /* message lengths */
1482 			char *at = tmp_buffer;
1483 
1484 			/* Read the available data */
1485 			bufs = read (clientr, tmp_buffer, 20);
1486 			if (!bufs) break;
1487 			if (!terminating) do_write (server, tmp_buffer, bufs);
1488 
1489 			if (!do_events_instead)
1490 				continue;
1491 
1492 			while (bufs) {
1493 				size_t length;
1494 
1495 				/* Figure out where to put it  */
1496 				if (variable_bytes_left) {
1497 					size_t need = bufs;
1498 					if (variable_bytes_left < need)
1499 						need = variable_bytes_left;
1500 					memcpy (variable_buffer +
1501 						variable_bytes_got,
1502 						at, need);
1503 					variable_bytes_got += need;
1504 					variable_bytes_left -= need;
1505 					at += need;
1506 					bufs -= need;
1507 				} else if (client_bytes_left) {
1508 					size_t need = bufs;
1509 					if (client_bytes_left < need)
1510 						need = client_bytes_left;
1511 					memcpy (client_buffer +
1512 						client_bytes_got,
1513 						at, need);
1514 					client_bytes_got += need;
1515 					client_bytes_left -= need;
1516 					at += need;
1517 					bufs -= need;
1518 				} else {
1519 					/* Clean slate */
1520 					*client_buffer = *at++;
1521 					bufs--;
1522 					client_bytes_got = 1;
1523 				}
1524 
1525 				/* Figure out what to do with it */
1526 				if (client_buffer[0] > 6) {
1527 					fprintf (stderr,
1528 						 "Protocol error\n");
1529 					exit (1);
1530 				}
1531 				length = mlen[(int) client_buffer[0]];
1532 				if (client_bytes_got < length) {
1533 					client_bytes_left = (length -
1534 							     client_bytes_got);
1535 					/* Incomplete fixed part */
1536 					continue;
1537 				}
1538 
1539 				length = variable_part (client_buffer);
1540 				if (variable_bytes_got < length) {
1541 					int need_alloc = !variable_bytes_left;
1542 					variable_bytes_left = length -
1543 						variable_bytes_got;
1544 					if (need_alloc)
1545 						variable_buffer = malloc
1546 							(variable_bytes_left);
1547 					/* Incomplete variable part */
1548 					continue;
1549 				}
1550 
1551 				process_client_message (client_buffer,
1552 							variable_buffer, f);
1553 				if (variable_bytes_got) {
1554 					variable_bytes_got = 0;
1555 					free (variable_buffer);
1556 				}
1557 				client_bytes_got = 0;
1558 			}
1559 		}
1560 	}
1561 
1562 	/* The last thing we write to the file is a zero length packet
1563 	 * to signal EOF.  It's here to make sure we've got a
1564 	 * timestamped event at the end of the file.
1565 	 */
1566 
1567 	if (!do_events_instead) {
1568 
1569 		gettimeofday (&tv, &tz);
1570 		diff.tv_sec = tv.tv_sec - epoch.tv_sec;
1571 		diff.tv_usec = tv.tv_usec - epoch.tv_usec;
1572 
1573 		write_packet (f, &diff, 0, &diff);
1574 	}
1575 
1576 
1577  out:
1578 	free (buf);
1579 	if (server != -1)
1580 		close (server);
1581 
1582 	if (fclose (f))
1583 		perror ("Error writing file");
1584 
1585 	return 0;
1586 }
1587 
1588 /********** PLAYBACK **********/
1589 
1590 /* Returns bitmask:
1591  *
1592  * bit 0: cycle
1593  * bit 1: pause
1594  * bit 2: client did a SetFormat (and it was decoded into 'fbf')
1595  * bit 3: client did a RequestFramebufferUpdate
1596  */
handle_client_during_playback(int clientr,int cycle,int pause,struct FramebufferFormat * fbf)1597 static int handle_client_during_playback (int clientr, int cycle, int pause,
1598 					  struct FramebufferFormat *fbf)
1599 {
1600 	/* We want to actually listen to the
1601 	 * individual client messages.
1602 	 *
1603 	 * The largest non-variable part of a
1604 	 * client->server message is 20 bytes.  */
1605 	static char tmp_buffer[20];
1606 	static char client_buffer[20];
1607 	static char *variable_buffer;
1608 	static size_t variable_bytes_left;
1609 	static size_t variable_bytes_got;
1610 	static size_t client_bytes_got;
1611 	static size_t client_bytes_left;
1612 	static const size_t mlen[] = {
1613 		20, 6, 4, 10, 8, 6, 8
1614 	}; /* message lengths */
1615 	char *at = tmp_buffer;
1616 	ssize_t bufs;
1617 	int do_pause = 0;
1618 	int do_cycle = 0;
1619 	int do_setformat = 0;
1620 	int do_updaterequest = 0;
1621 
1622 	/* Read the available data */
1623 	bufs = read (clientr, tmp_buffer, 20);
1624 	if (bufs < 1)
1625 		return -1;
1626 
1627 	while (bufs) {
1628 		size_t length;
1629 
1630 		/* Figure out where to put it  */
1631 		if (variable_bytes_left) {
1632 			size_t need = bufs;
1633 			if (variable_bytes_left < need)
1634 				need = variable_bytes_left;
1635 			memcpy (variable_buffer +
1636 				variable_bytes_got,
1637 				at, need);
1638 			variable_bytes_got += need;
1639 			variable_bytes_left -= need;
1640 			at += need;
1641 			bufs -= need;
1642 		} else if (client_bytes_left) {
1643 			size_t need = bufs;
1644 			if (client_bytes_left < need)
1645 				need = client_bytes_left;
1646 			memcpy (client_buffer +
1647 				client_bytes_got,
1648 				at, need);
1649 			client_bytes_got += need;
1650 			client_bytes_left -= need;
1651 			at += need;
1652 			bufs -= need;
1653 		} else {
1654 			/* Clean slate */
1655 			*client_buffer = *at++;
1656 			bufs--;
1657 			client_bytes_got = 1;
1658 		}
1659 
1660 		/* Figure out what to do with it */
1661 		if (client_buffer[0] > 6) {
1662 			fprintf (stderr,
1663 				 "Protocol error (%d)\n", client_buffer[0]);
1664 			exit (1);
1665 		}
1666 		length = mlen[(int) client_buffer[0]];
1667 		if (client_bytes_got < length) {
1668 			client_bytes_left = (length -
1669 					     client_bytes_got);
1670 			/* Incomplete fixed part */
1671 			continue;
1672 		}
1673 
1674 		length = variable_part (client_buffer);
1675 		if (variable_bytes_got < length) {
1676 			int need_alloc = !variable_bytes_left;
1677 			variable_bytes_left = length -
1678 				variable_bytes_got;
1679 			if (need_alloc)
1680 				variable_buffer = malloc
1681 					(variable_bytes_left);
1682 			/* Incomplete variable part */
1683 			continue;
1684 		}
1685 
1686 		if (client_buffer[0] == 0) {
1687 			/* SetPixelFormat */
1688 			decode_PixelFormat(client_buffer + 4, fbf);
1689 			if (verbose > 0) {
1690 				fprintf(stderr, "client SetPixelFormat:\n");
1691 				print_FramebufferFormat(stderr, fbf);
1692 			}
1693 			do_setformat = 4;
1694 		}
1695 
1696 		if (client_buffer[0] == 3) {
1697 			/* FramebufferUpdateRequest */
1698 			if (verbose > 2) {
1699 				fprintf(stderr, "FramebufferUpdateRequest\n");
1700 			}
1701 			do_updaterequest = 8;
1702 		}
1703 
1704 		if (client_buffer[0] == 4 /* KeyEvent */ &&
1705 		    client_buffer[1] /* Key down */) {
1706 			uint32_t key;
1707 			memcpy (&key, client_buffer + 4, 4);
1708 			key = ntohl (key);
1709 			if (key == pause)
1710 				do_pause = 2 - do_pause;
1711 			if (key == cycle)
1712 				do_cycle = 1;
1713 		}
1714 
1715 		if (variable_bytes_got) {
1716 			variable_bytes_got = 0;
1717 			free (variable_buffer);
1718 		}
1719 		client_bytes_got = 0;
1720 	}
1721 
1722 	return do_updaterequest | do_setformat | do_pause | do_cycle;
1723 }
1724 
1725 /* translate_FramebufferUpdate - translate a single FramebufferUpdate
1726  * message that starts at the point 'infile' is pointing to and is
1727  * encoded using 'informat', and write to it 'outfile' using 'outformat'.
1728  */
1729 
1730 /* hextile encoding is complex enough to get its own function */
1731 
translate_hextile(FBSfile * infile,struct FramebufferFormat * informat,FILE * outfile,struct FramebufferFormat * outformat,int rectx,int recty,int rectw,int recth)1732 static void translate_hextile(FBSfile *infile,
1733 			      struct FramebufferFormat *informat,
1734 			      FILE *outfile,
1735 			      struct FramebufferFormat *outformat,
1736 			      int rectx, int recty, int rectw, int recth) {
1737 
1738 	int subx, suby;
1739 	int subencoding;
1740 	int subrects, subrect;
1741 	int x, y, xy, wh;
1742 	struct pixel pix, background, foreground;
1743 
1744 	for (suby=0; suby<recth; suby+=16) {
1745 		for (subx=0; subx<rectw; subx+=16) {
1746 			fputc(subencoding = get_uchar(infile), outfile);
1747 			if (subencoding & 1) {
1748 				for (y = recty + suby;
1749 				     (y < recty + suby + 16)
1750 					     && (y < recty + recth); y++) {
1751 					for (x = rectx + subx;
1752 					     (x < rectx + subx + 16)
1753 						     && (x < rectx + rectw);
1754 					     x++) {
1755 						get_pixel(infile, informat,
1756 							  &pix);
1757 						fput_pixel(&pix, outformat,
1758 							   outfile);
1759 					}
1760 				}
1761 			} else {
1762 				if (subencoding & 2) {
1763 					get_pixel(infile, informat,
1764 						  &background);
1765 					fput_pixel(&background, outformat,
1766 						   outfile);
1767 				}
1768 				if (subencoding & 4) {
1769 					get_pixel(infile, informat,
1770 						  &foreground);
1771 					fput_pixel(&foreground, outformat,
1772 						   outfile);
1773 				}
1774 				if (subencoding & 8) {
1775 					fputc(subrects = get_uchar(infile),
1776 					      outfile);
1777 					for (subrect = 0; subrect < subrects;
1778 					     subrect ++) {
1779 						if (subencoding & 16) {
1780 							get_pixel(infile,
1781 								  informat,
1782 								  &pix);
1783 							fput_pixel(&pix,
1784 								   outformat,
1785 								   outfile);
1786 						}
1787 						fputc(xy = get_uchar(infile),
1788 						      outfile);
1789 						fputc(wh = get_uchar(infile),
1790 						      outfile);
1791 					}
1792 				}
1793 			}
1794 		}
1795 	}
1796 }
1797 
translate_FramebufferUpdate(FBSfile * infile,FILE * outfile,struct FramebufferFormat * informat,struct FramebufferFormat * outformat)1798 static void translate_FramebufferUpdate(FBSfile *infile, FILE *outfile,
1799 					struct FramebufferFormat *informat,
1800 					struct FramebufferFormat *outformat)
1801 {
1802 	int rect, subrect, x, y;
1803 	int srcx, srcy;
1804 	uint16_t nrects;
1805 	uint16_t rectx, recty, rectw, recth;
1806 	uint32_t type;
1807 	uint32_t nsubrects;
1808 	uint16_t subx, suby, subw, subh;
1809 	struct pixel pix;
1810 
1811 	fput_short(get_short(infile), outfile);
1812 	fput_short(nrects = get_short(infile), outfile);
1813 
1814 	if (verbose > 2)
1815 		fprintf(stderr, "Framebuffer update (%d rects)\n", nrects);
1816 
1817 	for (rect = 0; rect < nrects; rect ++) {
1818 
1819 		fput_short(rectx = get_short(infile), outfile);
1820 		fput_short(recty = get_short(infile), outfile);
1821 		fput_short(rectw = get_short(infile), outfile);
1822 		fput_short(recth = get_short(infile), outfile);
1823 		fput_long(type = get_long(infile), outfile);
1824 
1825 		if (verbose > 3)
1826 			fprintf(stderr, "rect %d: (%d,%d) %dx%d type %d\n",
1827 				rect, rectx, recty, rectw, recth, type);
1828 
1829 		switch (type) {
1830 		case 0:
1831 			/* raw */
1832 			for (y = recty; y < recty+recth; y++) {
1833 				for (x = rectx; x < rectx+rectw; x++) {
1834 					get_pixel(infile, informat, &pix);
1835 					fput_pixel(&pix, outformat, outfile);
1836 				}
1837 			}
1838 			break;
1839 
1840 		case 1:
1841 			/* copy rect */
1842 			fput_short(srcx = get_short(infile), outfile);
1843 			fput_short(srcy = get_short(infile), outfile);
1844 			break;
1845 
1846 		case 2:
1847 			/* RRE */
1848 			fput_long(nsubrects = get_long(infile), outfile);
1849 			get_pixel(infile, informat, &pix);
1850 			fput_pixel(&pix, outformat, outfile);
1851 
1852 			for (subrect=0; subrect<nsubrects; subrect++) {
1853 				get_pixel(infile, informat, &pix);
1854 				fput_pixel(&pix, outformat, outfile);
1855 				fput_short(subx = get_short(infile), outfile);
1856 				fput_short(suby = get_short(infile), outfile);
1857 				fput_short(subw = get_short(infile), outfile);
1858 				fput_short(subh = get_short(infile), outfile);
1859 			}
1860 			break;
1861 
1862 		case 4:
1863 			/* CoRRE */
1864 			fput_long(nsubrects = get_long(infile), outfile);
1865 			get_pixel(infile, informat, &pix);
1866 			fput_pixel(&pix, outformat, outfile);
1867 
1868 			for (subrect=0; subrect<nsubrects; subrect++) {
1869 				get_pixel(infile, informat, &pix);
1870 				fput_pixel(&pix, outformat, outfile);
1871 				fputc(subx = get_uchar(infile), outfile);
1872 				fputc(suby = get_uchar(infile), outfile);
1873 				fputc(subw = get_uchar(infile), outfile);
1874 				fputc(subh = get_uchar(infile), outfile);
1875 			}
1876 			break;
1877 
1878 		case 5:
1879 			translate_hextile (infile, informat,
1880 					   outfile, outformat,
1881 					   rectx, recty, rectw, recth);
1882 			break;
1883 
1884 		default:
1885 
1886 			/* We don't understand the pixel encoding.
1887 			 * Maybe we should just bail here, but try to
1888 			 * keep going.  Skip to next packet, and do an
1889 			 * immediate return to halt processing of this
1890 			 * FramebufferUpdate.
1891 			 */
1892 
1893 			fprintf(stderr, "Unknown pixel encoding (%d)\n", type);
1894 			next_packet(infile);
1895 			return;
1896 
1897 		}
1898 	}
1899 }
1900 
playback(const char * filename,int clientr,int clientw,int loop,int cycle,int pause)1901 static int playback (const char *filename, int clientr, int clientw, int loop,
1902 		     int cycle, int pause)
1903 {
1904 	FBSfile fileptr;
1905 	struct FramebufferFormat server_fbf;
1906 	FILE *outfile;
1907 
1908 	unsigned long last_packet_ms;
1909 	int ret = -1;
1910 	int paused = 0;
1911 	int finish = 0;
1912 
1913 	/* These next two are static because they need to be preserved
1914 	 * over repeated calls to this function during a looping and/or
1915 	 * multi-file playback: the client framebuffer format and a flag
1916 	 * to keep FramebufferUpdatesRequests and FramebufferUpdates
1917 	 * syncronized during FBS 1.1 playbacks.
1918 	 *
1919 	 * 'can_update' is cleared ever time we send a FramebufferUpdate,
1920 	 * is set every time the client sends a FramebufferUpdateRequest,
1921 	 * and we won't send a FramebufferUpdate unless it is set.
1922 	 * The net net is that after sending an update, we wait to hear
1923 	 * a request back from the client before sending more updates.
1924 	 * This is done for two reasons:
1925 	 *
1926 	 *   1) we can (FBS 1.0 playback can't do this because we can't
1927 	 *      find its message boundaries), and
1928 	 *   2) we don't want to be in the middle of sending a update
1929 	 *      when the client changes pixel formats on us!
1930 	 */
1931 
1932 	static struct FramebufferFormat client_fbf;
1933 	static int can_update = 0;
1934 
1935 	if (FBSopen(filename, &fileptr) == -1) {
1936 		return -1;
1937 	}
1938 
1939 	if (get_initial_RFB_handshake(&fileptr, &server_fbf) == -1) {
1940 		FBSclose(&fileptr);
1941 		return -1;
1942 	}
1943 
1944 	if (!loop) {
1945 		do_server_initialization(clientr, clientw, &server_fbf);
1946 		client_fbf = server_fbf;
1947 	}
1948 
1949 	/* the dup() is done so we can fclose() at the end of this function */
1950 
1951 	if ((clientw = dup(clientw)) == -1) {
1952 		perror("dup");
1953 		FBSclose(&fileptr);
1954 		return -1;
1955 	}
1956 	outfile = fdopen(clientw, "w");
1957 
1958 	/* now this is the timestamp on the first thing _following_
1959          * server init
1960 	 */
1961 	last_packet_ms = fileptr.ms;
1962 
1963 	if (verbose > 0) {
1964 		fprintf(stderr, "Playing %s\n", filename);
1965 	}
1966 
1967 	while (!fbs_at_eof(&fileptr)) {
1968 
1969 		struct timeval tv, deadline;
1970 		struct timezone tz;
1971 		fd_set rfds;
1972 		FD_ZERO (&rfds);
1973 		FD_SET (clientr, &rfds);
1974 
1975 		tv.tv_sec = (fileptr.ms - last_packet_ms) / 1000;
1976 		tv.tv_usec = 1000 * ((fileptr.ms - last_packet_ms) % 1000);
1977 		gettimeofday (&deadline, &tz);
1978 		deadline.tv_sec += tv.tv_sec;
1979 		deadline.tv_usec += tv.tv_usec;
1980 		if (deadline.tv_usec >= 1000000) {
1981 			deadline.tv_usec -= 1000000;
1982 			deadline.tv_sec++;
1983 		}
1984 
1985 		/* FBS 1.0 only - guesstimate message boundaries.
1986 		 * Heuristic: if the delay is >= 0.1s, we are at a message
1987 		 * boundary.  THIS WILL BREAK FOR SLOW CONNECTIONS!
1988 		 */
1989 		if (finish && (tv.tv_sec || tv.tv_usec > 100000)) {
1990 			ret = 1;
1991 			goto out;
1992 		}
1993 
1994 		while (select(FD_SETSIZE, &rfds, NULL, NULL,
1995 			      (!can_update || paused) ? NULL : &tv) != 0) {
1996 
1997 			int stuff;
1998 			stuff = handle_client_during_playback
1999 				(clientr, cycle, pause, &client_fbf);
2000 			if (stuff == -1)
2001 				/* Connection closed. */
2002 				goto out;
2003 			if (stuff & 8) {
2004 				can_update = 1;
2005 			}
2006 			if (stuff & 4) {
2007 				/* Client changed pixel format on us.
2008 				 * We could use this fact to optimize
2009 				 * translations into copies if the new
2010 				 * format is identical to the file's
2011 				 * format, but we don't.
2012 				 */
2013 			}
2014 			if (stuff & 2) {
2015 				paused = 1 - paused;
2016 			}
2017 			if (stuff & 1) {
2018 				/* user hit key to cycle to next file */
2019 
2020 				if (fileptr.minor_version == 0) {
2021 					/* FBS 1.0 - not sure if this
2022 					 * is a message boundary, so
2023 					 * set a flag and guesstimate
2024 					 */
2025 					finish = 1;
2026 				} else {
2027 					/* FBS 1.1 - we transfer entire
2028 					 * server messages below and
2029 					 * only come through this loop
2030 					 * on a message boundary, so
2031 					 * it's OK to just leave.
2032 					 */
2033 					ret = 1;
2034 					goto out;
2035 				}
2036 			}
2037 
2038 			/* Recalculate delay */
2039 			gettimeofday (&tv, &tz);
2040 			if (tv.tv_sec > deadline.tv_sec ||
2041 			    (tv.tv_sec == deadline.tv_sec &&
2042 			     tv.tv_usec >= deadline.tv_usec))
2043 				/* Deadline already passed */
2044 				break;
2045 
2046 			tv.tv_sec = deadline.tv_sec - tv.tv_sec;
2047 			tv.tv_usec = deadline.tv_usec - tv.tv_usec;
2048 			if (tv.tv_usec < 0) {
2049 				tv.tv_usec += 1000000;
2050 				tv.tv_sec--;
2051 			}
2052 		}
2053 
2054 		if (!can_update || paused)
2055 			continue;
2056 
2057 		last_packet_ms = fileptr.ms;
2058 
2059 		if (fileptr.minor_version == 0) {
2060 
2061 			/* We can't reliably find message boundaries in
2062 			 * an FBS 1.0 file, so just send what we recorded
2063 			 * verbatim and hope it makes sense to the client.
2064 			 *
2065 			 * It's also pretty pointless to try and stay
2066 			 * synchronized by turning off 'can_update'
2067 			 * (since we don't know when we've sent
2068 			 * FramebufferUpdates), so just leave it on.
2069 			 */
2070 
2071 			do_write (clientw, fileptr.buf, fileptr.len);
2072 			next_packet(&fileptr);
2073 
2074 		} else {
2075 
2076 			/* We translate an entire FramebufferUpdate
2077 			 * here and _then_ come back through this loop
2078 			 * to check timestamps and delay if needed,
2079 			 * making no attempt to delay within a
2080 			 * FramebufferUpdate.  This is noticeable if
2081 			 * the session was recorded over a slow
2082 			 * connection.  During playback, a large
2083 			 * update that originally took some time to
2084 			 * transfer will appear instantaneously and
2085 			 * then be followed by a delay.  Doesn't seem
2086 			 * important enough to fix.
2087 			 */
2088 
2089 			int length;
2090 
2091 			switch (fileptr.buf[0]) {
2092 			case 0:
2093 				translate_FramebufferUpdate(&fileptr, outfile,
2094 							    &server_fbf,
2095 							    &client_fbf);
2096 				can_update = 0;
2097 				break;
2098 
2099 			case 2:
2100 				/* bell */
2101 				fputc(get_uchar(&fileptr), outfile);
2102 				break;
2103 
2104 			case 3:
2105 				/* ServerCutText */
2106 				fput_long(get_long(&fileptr), outfile);
2107 				fput_long(length = get_long(&fileptr),
2108 					  outfile);
2109 				while (length --) {
2110 					fputc(get_uchar(&fileptr), outfile);
2111 				}
2112 				break;
2113 
2114 			default:
2115 				fprintf(stderr, "Unknown RFB message\n");
2116 				break;
2117 			}
2118 		}
2119 
2120 		fflush(outfile);
2121 	}
2122 
2123 	ret = 1;
2124 
2125  out:
2126 	if (verbose > 0) {
2127 		fprintf(stderr, "Playback (%s) done; ret=%d\n", filename, ret);
2128 	}
2129 
2130 	fclose(outfile);
2131 	FBSclose(&fileptr);
2132 	return ret;
2133 }
2134 
2135 /********** EXPORT **********/
2136 
2137 /* We store the framebuffer as an array of PPM-format pixels to make it
2138  * easy to spit it out with a single write().  Since we're writing
2139  * about 30 frames per second (NTSC) on our output stream, this is
2140  * a big speed win over storing the framebuffer in RFB format and
2141  * converting everytime we write.
2142  */
2143 
2144 struct pixel *framebuffer=NULL;
2145 
2146 /* This function outputs the framebuffer as a PPM.  If outfilename is
2147  * NULL, we append to stdout.  Maybe I should fix this to use
2148  * non-buffered I/O exclusively.  As it is, it works on Linux; I just
2149  * make sure I fflush() before attempting a write().
2150  */
2151 
write_framebuffer_as_ppm(char * outfilename,struct FramebufferFormat * fbf)2152 static int write_framebuffer_as_ppm (char *outfilename,
2153 				     struct FramebufferFormat *fbf) {
2154 
2155 	FILE * outfile;
2156 
2157 	if (outfilename != NULL) {
2158 		outfile = fopen(outfilename, "wb");
2159 		if (!outfile) { perror("fopen"); return -1; }
2160 	} else {
2161 		outfile = stdout;
2162 	}
2163 
2164 	fprintf(outfile, "P6 %d %d 255\n", fbf->width, fbf->height);
2165 	fflush(outfile);
2166 
2167 	do_write (fileno(outfile), framebuffer,
2168 		  fbf->width * fbf->height * sizeof(struct pixel));
2169 
2170 	if (outfilename != NULL) fclose(outfile);
2171 
2172 	return 0;
2173 }
2174 
2175 /* These are the functions that write into the framebuffer. */
2176 
set_pixel(struct pixel * framebuffer,struct FramebufferFormat * fbf,int x,int y,struct pixel * pptr)2177 void set_pixel(struct pixel *framebuffer, struct FramebufferFormat *fbf,
2178 	       int x, int y, struct pixel *pptr)
2179 {
2180 	memcpy(&framebuffer[y*fbf->width + x], pptr, sizeof(struct pixel));
2181 }
2182 
copy_rect(struct pixel * framebuffer,struct FramebufferFormat * fbf,int srcx,int srcy,int destx,int desty,int w,int h)2183 void copy_rect(struct pixel *framebuffer, struct FramebufferFormat *fbf,
2184 	       int srcx, int srcy, int destx, int desty, int w, int h)
2185 {
2186 	int y;
2187 
2188 	/* Brent learned through experience to be careful in this
2189 	 * function about using memmove() instead of memcpy() and
2190 	 * making sure we order the rows so we don't overwrite
2191 	 * ourselves in the middle of a copy.
2192 	 */
2193 
2194 	if (desty <= srcy) {
2195 		for (y = 0; y < h; y++) {
2196 			memmove(&framebuffer[((desty + y) * fbf->width)+destx],
2197 				&framebuffer[((srcy + y) * fbf->width) +srcx],
2198 				w * sizeof(struct pixel));
2199 		}
2200 	} else {
2201 		for (y = h-1; y >= 0; y--) {
2202 			memmove(&framebuffer[((desty + y) * fbf->width)+destx],
2203 				&framebuffer[((srcy + y) * fbf->width) +srcx],
2204 				w * sizeof(struct pixel));
2205 		}
2206 	}
2207 }
2208 
fill_rect(struct pixel * framebuffer,struct FramebufferFormat * fbf,struct pixel * pixelptr,int rectx,int recty,int rectw,int recth)2209 static void fill_rect(struct pixel *framebuffer, struct FramebufferFormat *fbf,
2210 		      struct pixel *pixelptr,
2211 		      int rectx, int recty, int rectw, int recth)
2212 {
2213 	int x, y;
2214 	for (y = recty; y < recty+recth; y++) {
2215 		for (x = rectx; x < rectx+rectw; x++) {
2216 			set_pixel(framebuffer, fbf, x, y, pixelptr);
2217 		}
2218 	}
2219 }
2220 
2221 /* Output framerates for export function, specified as a fraction
2222  * (n/m) in frames per second.  I pulled them out of the mpeg2enc man
2223  * page.  "ntsc" is the only one I've actually used (to create DVD
2224  * content).
2225  *
2226  * The first framerate structure in the array is the default.
2227  */
2228 
2229 struct framerate {
2230 	char * name;
2231 	int n;
2232 	int m;
2233 };
2234 
2235 struct framerate preset_framerates[] = {
2236 	{"ntsc", 30000, 1001},
2237 	{"pal", 25, 1},
2238 	{"film", 24, 1},
2239 	{NULL, 0, 0}
2240 };
2241 
2242 /* process_FramebufferUpdate - process a single FramebufferUpdate
2243  * message that starts at the point 'file' is pointing to, and update
2244  * the in-memory 'framebuffer' array accordingly.  This is the
2245  * function that pulls together the two sets of functions above -
2246  * those that write into the framebuffer and those that read from the
2247  * recorded RFB session.
2248  */
2249 
2250 /* hextile encoding is complex enough to get its own function */
2251 
process_hextile(FBSfile * file,struct FramebufferFormat * format,int rectx,int recty,int rectw,int recth)2252 static void process_hextile(FBSfile *file, struct FramebufferFormat *format,
2253 			    int rectx, int recty, int rectw, int recth) {
2254 
2255 	int subx, suby;
2256 	int subencoding;
2257 	int subrects, subrect;
2258 	int x, y, xy, wh;
2259 	struct pixel pix, background, foreground;
2260 
2261 	for (suby=0; suby<recth; suby+=16) {
2262 		for (subx=0; subx<rectw; subx+=16) {
2263 			subencoding = get_uchar(file);
2264 			if (subencoding & 1) {
2265 				for (y = recty + suby;
2266 				     (y < recty + suby + 16)
2267 					     && (y < recty + recth); y++) {
2268 					for (x = rectx + subx;
2269 					     (x < rectx + subx + 16)
2270 						     && (x < rectx + rectw);
2271 					     x++) {
2272 						get_pixel(file, format, &pix);
2273 						set_pixel(framebuffer, format,
2274 							  x, y, &pix);
2275 					}
2276 				}
2277 			} else {
2278 				if (subencoding & 2) {
2279 					get_pixel(file, format, &background);
2280 				}
2281 				if (subencoding & 4) {
2282 					get_pixel(file, format, &foreground);
2283 				}
2284 				fill_rect (framebuffer, format, &background,
2285 					   rectx + subx, recty + suby,
2286 					   (rectw - subx < 16)
2287 					   ? rectw - subx : 16,
2288 					   (recth - suby < 16)
2289 					   ? recth - suby : 16);
2290 				if (subencoding & 8) {
2291 					subrects = get_uchar(file);
2292 					for (subrect = 0; subrect < subrects;
2293 					     subrect ++) {
2294 						if (subencoding & 16) {
2295 							get_pixel(file,
2296 								  format,
2297 								  &pix);
2298 						}
2299 						xy = get_uchar(file);
2300 						wh = get_uchar(file);
2301 						fill_rect (framebuffer,
2302 							   format,
2303 							   subencoding & 16 ?
2304 							   &pix : &foreground,
2305 							   rectx + subx
2306 							   + (xy >> 4),
2307 							   recty + suby
2308 							   + (xy & 15),
2309 							   (wh >> 4) + 1,
2310 							   (wh & 15) + 1);
2311 					}
2312 				}
2313 			}
2314 		}
2315 	}
2316 }
2317 
process_FramebufferUpdate(FBSfile * file,struct FramebufferFormat * format)2318 static void process_FramebufferUpdate(FBSfile *file,
2319 				      struct FramebufferFormat *format)
2320 {
2321 	int rect, subrect, x, y;
2322 	int srcx, srcy;
2323 	uint16_t nrects;
2324 	uint16_t rectx, recty, rectw, recth;
2325 	uint32_t type;
2326 	uint32_t nsubrects;
2327 	uint16_t subx, suby, subw, subh;
2328 	struct pixel pix;
2329 
2330 	get_short(file);
2331 	nrects = get_short(file);
2332 
2333 	if (verbose > 2)
2334 		fprintf(stderr, "Framebuffer update (%d rects)\n", nrects);
2335 
2336 	for (rect = 0; rect < nrects; rect ++) {
2337 
2338 		rectx = get_short(file);
2339 		recty = get_short(file);
2340 		rectw = get_short(file);
2341 		recth = get_short(file);
2342 		type = get_long(file);
2343 
2344 		if (verbose > 3)
2345 			fprintf(stderr, "rect %d: (%d,%d) %dx%d type %d\n",
2346 				rect, rectx, recty, rectw, recth, type);
2347 
2348 		switch (type) {
2349 		case 0:
2350 			/* raw */
2351 			for (y = recty; y < recty+recth; y++) {
2352 				for (x = rectx; x < rectx+rectw; x++) {
2353 					get_pixel(file, format, &pix);
2354 					set_pixel(framebuffer, format,
2355 						  x, y, &pix);
2356 				}
2357 			}
2358 			break;
2359 
2360 		case 1:
2361 			/* copy rect */
2362 			srcx = get_short(file);
2363 			srcy = get_short(file);
2364 			copy_rect(framebuffer, format,
2365 				  srcx, srcy, rectx, recty, rectw, recth);
2366 			break;
2367 
2368 		case 2:
2369 			/* RRE */
2370 			nsubrects = get_long(file);
2371 			get_pixel(file, format, &pix);
2372 			fill_rect(framebuffer, format, &pix,
2373 				  rectx, recty, rectw, recth);
2374 
2375 			for (subrect=0; subrect<nsubrects; subrect++) {
2376 				get_pixel(file, format, &pix);
2377 				subx = get_short(file);
2378 				suby = get_short(file);
2379 				subw = get_short(file);
2380 				subh = get_short(file);
2381 				fill_rect(framebuffer, format, &pix,
2382 					  rectx + subx, recty + suby,
2383 					  subw, subh);
2384 			}
2385 			break;
2386 
2387 		case 4:
2388 			/* CoRRE */
2389 			nsubrects = get_long(file);
2390 			get_pixel(file, format, &pix);
2391 			fill_rect(framebuffer, format, &pix,
2392 				  rectx, recty, rectw, recth);
2393 
2394 			for (subrect=0; subrect<nsubrects; subrect++) {
2395 				get_pixel(file, format, &pix);
2396 				subx = get_uchar(file);
2397 				suby = get_uchar(file);
2398 				subw = get_uchar(file);
2399 				subh = get_uchar(file);
2400 				fill_rect(framebuffer, format, &pix,
2401 					  rectx + subx, recty + suby,
2402 					  subw, subh);
2403 			}
2404 			break;
2405 
2406 		case 5:
2407 			process_hextile (file, format,
2408 					 rectx, recty, rectw, recth);
2409 			break;
2410 
2411 		default:
2412 
2413 			/* We don't understand the pixel encoding.
2414 			 * Maybe we should just bail here, but try to
2415 			 * keep going.  Skip to next packet, and do an
2416 			 * immediate return to halt processing of this
2417 			 * FramebufferUpdate.
2418 			 */
2419 
2420 			fprintf(stderr, "Unknown pixel encoding (%d)\n", type);
2421 			next_packet(file);
2422 			return;
2423 
2424 		}
2425 	}
2426 
2427 }
2428 
2429 /* export() - called from main() runs through a recorded file (in FBS
2430  * format) from beginning to end, spitting out PPM frames to stdout at
2431  * a framerate specified as a fraction (n/m) in frames per second.
2432  */
2433 
export(const char * filename,int framerate_n,int framerate_m)2434 static int export (const char *filename, int framerate_n, int framerate_m)
2435 {
2436 	FBSfile fileptr;
2437 	struct FramebufferFormat fbfs;
2438 	struct FramebufferFormat *format = &fbfs;
2439 	int last_frame = 0;
2440 	int length;
2441 
2442 	if (FBSopen(filename, &fileptr) == -1) {
2443 		return -1;
2444 	}
2445 
2446 	if (fileptr.minor_version == 0) {
2447 		fprintf(stderr,	"Warning: "
2448 			"FBS version 1.0 file with ambiguous pixel format\n");
2449 	}
2450 
2451 	if (get_initial_RFB_handshake(&fileptr, format) == -1) {
2452 		FBSclose(&fileptr);
2453 		return -1;
2454 	}
2455 
2456 	framebuffer = (struct pixel *)
2457 		malloc(format->width * format->height * sizeof(struct pixel));
2458 	if (framebuffer == NULL) {
2459 		fprintf (stderr,"couldn't malloc framebuffer");
2460 		FBSclose(&fileptr);
2461 		return -1;
2462 	}
2463 
2464 	while (!fbs_at_eof(&fileptr)) {
2465 
2466 		switch (fileptr.buf[0]) {
2467 		case 0:
2468 			process_FramebufferUpdate(&fileptr, format);
2469 
2470 			/* fileptr.ms has now advanced to the
2471 			 * timestamp on the next byte after the
2472 			 * FramebufferUpdate we just processed,
2473 			 * so see if we need to spit out any frames.
2474 			 *
2475 			 * We don't do anything at timestamp 0.  We
2476 			 * output frame 1 at timestamp m/n sec, and so
2477 			 * on.  Maybe we should output a "frame 0" as
2478 			 * soon as we've processed the first
2479 			 * framebuffer update, I don't know.
2480 			 *
2481 			 * And I use floating point math simply
2482 			 * because fileptr.ms * 30000 (NTSC's
2483 			 * framerate_n) overflows a 32-bit long at
2484 			 * around (2^32)/30000/1000 = 143 seconds.
2485 			 */
2486 
2487 			while (1000.0 * (last_frame + 1) * framerate_m
2488 			       < (double) fileptr.ms * framerate_n) {
2489 
2490 				write_framebuffer_as_ppm(NULL, format);
2491 				last_frame ++;
2492 				if ((verbose > 0) &&
2493 				    ((verbose > 1) || (last_frame % 100) == 0))
2494 					fprintf(stderr, "Encoded frame %d\n",
2495 						last_frame);
2496 			}
2497 
2498 			break;
2499 
2500 		case 2:
2501 			/* Bell */
2502 			get_uchar(&fileptr);
2503 			break;
2504 
2505 		case 3:
2506 			/* ServerCutText */
2507 			get_long(&fileptr);
2508 			length = get_long(&fileptr);
2509 			get_bytes(&fileptr, NULL, length);
2510 			break;
2511 
2512 		default:
2513 
2514 			/* If we couldn't understand the server
2515 			 * message, jump to the start of the next FBS
2516 			 * packet and hope it's something we do
2517 			 * understand.
2518 			 */
2519 
2520 			fprintf(stderr, "Unknown RFB message\n");
2521 			next_packet(&fileptr);
2522 			break;
2523 		}
2524 	}
2525 
2526 	/* Normal return */
2527 	FBSclose(&fileptr);
2528 	return 0;
2529 }
2530 
2531 /********** MAIN AND FRIENDS **********/
2532 
version(void)2533 static void version (void)
2534 {
2535 	fprintf (stderr, "rfbproxy version %s\n", VERSION);
2536 }
2537 
usage(const char * name)2538 static void usage (const char *name)
2539 {
2540 	fprintf (stderr,
2541 		 "usage: %s [OPTIONS] ACTION files\n"
2542 		 "where OPTIONS are:\n\n"
2543 		 " -c, --stdout  Use stdin and stdout for communications\n"
2544 		 "               with the client. Useful in conjunction\n"
2545 		 "               with inetd.\n"
2546 		 " -l, --loop    (playback only) When file is finished,\n"
2547 		 "               replay from first FrameBufferUpdate\n"
2548 		 " -d, --date    (record only) Append Date to end of filename\n"
2549 		 " -s, --shared  (record only) attach to a shared session\n"
2550 		 "               incompatible with --stdout\n"
2551 		 " -v, --verbose increase verbosity\n"
2552 		 " --pause=key   (playback only) When the key is pressed,\n"
2553 		 "               playback will be paused until it is pressed\n"
2554 		 "               again.\n"
2555 		 " --cycle=key   (playback only) When multiple files are specified\n"
2556 		 "               pressing the key will cycle between them.\n"
2557 		 " --type=[screen|events]\n"
2558 		 "               (record only) Capture either screen updates\n"
2559 		 "               (\"screen\") or keyboard/mouse events (\"events\").\n"
2560 		 "               The default is \"screen\".\n"
2561 		 " --framerate=[ntsc|pal|film|m/n]\n"
2562 		 "               (export only) Specify framerate by name\n"
2563 		 "               or rational fraction (frames per second)\n"
2564 		 " :n            Occupy VNC display localhost:n (not valid with\n"
2565 		 "               -c option). The default is \""
2566 		 DEFAULT_DISPLAY "\".\n"
2567 		 " --server=[server]:display\n"
2568 		 "               (record only) Use specified VNC server. The\n"
2569 		 "               default is \"" DEFAULT_SERVER "\".\n"
2570 		 "\nACTION is one of:\n"
2571 		 " -r, --record\n"
2572 		 "               Record RFB communications and store them in\n"
2573 		 "               the file.\n"
2574 		 " -p, --playback\n"
2575 		 "               Play back the RFB communications that were\n"
2576 		 "               captured to the file or files.\n"
2577 		 " -x, --export\n"
2578 		 "               Export recorded RFB communication as PPMs\n"
2579 		 "               First step in creating an MPEG.\n"
2580 		 " --version\n"
2581 		 "               Report program version (" VERSION ")\n",
2582 		 name);
2583 	exit (1);
2584 }
2585 
accept_connection(int port)2586 int accept_connection (int port)
2587 {
2588 	int bound;
2589 	int sock;
2590 	struct sockaddr_in sin;
2591 	int on = 1;
2592 	sin.sin_family = AF_INET;
2593 	sin.sin_addr.s_addr = INADDR_ANY;
2594 	sin.sin_port = htons (VNC_BASE + port);
2595 	bound = socket (AF_INET, SOCK_STREAM, IPPROTO_IP);
2596 	if (bound < 0) {
2597 		perror ("socket");
2598 		exit (1);
2599 	}
2600 	setsockopt (bound, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on));
2601 	if (bind (bound, (struct sockaddr *) &sin,
2602 		  sizeof (struct sockaddr_in))) {
2603 		perror ("bind");
2604 		exit (1);
2605 	}
2606 	listen (bound, 1);
2607 	sock = accept (bound, NULL, 0);
2608 	close (bound);
2609 	return sock;
2610 }
2611 
main(int argc,char * argv[])2612 int main (int argc, char *argv[])
2613 {
2614 	int use_stdout = 0;
2615 	int loop = 0;
2616 	int appenddate = 0;
2617 	int shared_session = 0;
2618 	const char **file = NULL;
2619 	int files = 0;
2620 	char action = '\0';
2621 	char type = '\0';
2622 	char *server = NULL;
2623 	char *display = NULL;
2624 	int clientr, clientw;
2625 	struct sockaddr_in server_addr;
2626 	int orig_optind;
2627 	int cycle = 0, pause = 0;
2628 	struct framerate *framerate = &preset_framerates[0];
2629 
2630 	/* Options */
2631 	for (;;) {
2632 		static struct option long_options[] = {
2633 			{"playback", 0, 0, 'p'},
2634 			{"record", 0, 0, 'r'},
2635 			{"export", 0, 0, 'x'},
2636 			{"type", 1, 0, 't'},
2637 			{"date", 0, 0, 'd'},
2638 			{"loop", 0, 0, 'l'},
2639 			{"stdout", 0, 0, 'c'},
2640 			{"shared", 0, 0, 's'},
2641 			{"server", 1, 0, 'S'},
2642 			{"framerate", 1, 0, 'F'},
2643 			{"help", 0, 0, 'h'},
2644 			{"version", 0, 0, 'V'},
2645 			{"verbose", 0, 0, 'v'},
2646 			{"pause", 1, 0, 'P'},
2647 			{"cycle", 1, 0, 'C'},
2648 			{0, 0, 0, 0}
2649 		};
2650 		int l;
2651 		int c = getopt_long (argc, argv, "prxcldsv",
2652 				     long_options, NULL);
2653 		if (c == -1)
2654 			break;
2655 
2656 		switch (c) {
2657 			char *p;
2658 		case 'P':
2659 			pause = strtoul (optarg, &p, 16);
2660 			if (optarg == p)
2661 				pause = *optarg;
2662 			break;
2663 		case 'C':
2664 			cycle = strtoul (optarg, &p, 16);
2665 			if (optarg == p)
2666 				cycle = *optarg;
2667 			break;
2668 		case 'V':
2669 			version ();
2670 			exit (0);
2671 		case 'h':
2672 			version ();
2673 			usage (argv[0]);
2674 		case 'c':
2675 			if (use_stdout)
2676 				usage (argv[0]);
2677 			use_stdout = 1;
2678 			break;
2679 		case 'l':
2680 			if (loop)
2681 				usage (argv[0]);
2682 			loop = 1;
2683 			break;
2684 		case 'd':
2685 			if (appenddate)
2686 				usage (argv[0]);
2687 			appenddate = 1;
2688 			break;
2689 		case 't':
2690 			if (type)
2691 				usage (argv[0]);
2692 			l = strlen (optarg);
2693 			if (!strncmp (optarg, "screen", l))
2694 				type = 's';
2695 			else if (!strncmp (optarg, "events", l))
2696 				type = 'e';
2697 			else usage (argv[0]);
2698 			break;
2699 		case 'S':
2700 			if (server)
2701 				usage (argv[0]);
2702 			server = optarg;
2703 			break;
2704 		case 's':
2705 			if (shared_session)
2706 				usage (argv[0]);
2707 			shared_session = 1;
2708 			break;
2709 		case 'F':
2710 			for (framerate = preset_framerates;
2711 			     framerate->name != NULL;
2712 			     framerate ++) {
2713 				if (!strcmp(framerate->name, optarg)) break;
2714 			}
2715 			if (framerate->name == NULL) {
2716 				framerate->m = 1;
2717 				if (sscanf(optarg, "%d%*[:/]%d",
2718 					   &framerate->n,&framerate->m) == 0) {
2719 					usage(argv[0]);
2720 				}
2721 			}
2722 			break;
2723 		case 'v':
2724 			verbose ++;
2725 			break;
2726 		case 'p':
2727 		case 'r':
2728 		case 'x':
2729 			if (action)
2730 				usage (argv[0]);
2731 			action = c;
2732 			break;
2733 		}
2734 	}
2735 
2736 	orig_optind = optind;
2737 	for (; optind < argc; optind++) {
2738 		if (!display && argv[optind][0] == ':') {
2739 			display = argv[optind];
2740 			continue;
2741 		}
2742 
2743 		files++;
2744 	}
2745 	file = malloc ((files + 1) * sizeof (char *));
2746 	if (!file) {
2747 		fprintf (stderr, "out of memory\n");
2748 		exit (1);
2749 	}
2750 	files = 0;
2751 	for (optind = orig_optind; optind < argc; optind++)
2752 		if (argv[optind][0] != ':')
2753 			file[files++] = argv[optind];
2754 	file[files] = NULL;
2755 
2756 	/* Invalid option combinations */
2757 	if (!action ||
2758 	    (loop && action != 'p') ||
2759 	    (type && action != 'r') ||
2760 	    (server && action != 'r') ||
2761 	    (shared_session && action != 'r') ||
2762 	    (shared_session && type == 'e') ||
2763 	    (shared_session && use_stdout) ||
2764 	    ((framerate != &preset_framerates[0]) && action != 'x') ||
2765 	    (use_stdout && display))
2766 		usage (argv[0]);
2767 
2768 	if (files < 1)
2769 		/* No files specified */
2770 		usage (argv[0]);
2771 
2772 	/* Defaults */
2773 	if (!server)
2774 		server = strdup (DEFAULT_SERVER);
2775 	if (!display)
2776 		display = strdup (DEFAULT_DISPLAY);
2777 	if (!type)
2778 		type = 's';
2779 
2780 	if (action == 'r') {
2781 		int port;
2782 		char *end;
2783 		char *cl = strchr (server, ':');
2784 		if (files > 1)
2785 			/* Can't record to more than one file */
2786 			usage (argv[0]);
2787 		if (!cl)
2788 			usage (argv[0]);
2789 		*cl++ = '\0';
2790 		port = VNC_BASE + strtoul (cl, &end, 10);
2791 		if (cl == end)
2792 			usage (argv[0]);
2793 		server_addr.sin_family = AF_INET;
2794 		if (!server[0])
2795 			server_addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
2796 		else {
2797 			struct hostent *hp;
2798 			if ((server_addr.sin_addr.s_addr =
2799 			     inet_addr (server)) == -1) {
2800 				hp = gethostbyname (server);
2801 				if (!hp) {
2802 					perror (server);
2803 					exit (1);
2804 				}
2805 				memcpy (&server_addr.sin_addr.s_addr,
2806 					hp->h_addr_list[0],
2807 					hp->h_length);
2808 			}
2809 		}
2810 		server_addr.sin_port = htons (port);
2811 	}
2812 
2813 	/* Export */
2814 	if (action == 'x') {
2815 		int file_to_export;
2816 
2817 		for (file_to_export = 0;
2818 		     file_to_export < files; file_to_export++) {
2819 			export(file[file_to_export],
2820 			       framerate->n, framerate->m);
2821 		}
2822 
2823 		return 0;
2824 	}
2825 
2826 	/* Record or playback - get client's file descriptors */
2827 	if (use_stdout) {
2828 		clientr = fileno (stdin);
2829 		clientw = fileno (stdout);
2830 	} else if (!shared_session) {
2831 		unsigned long port;
2832 		char *end;
2833 		display++;
2834 		port = strtoul (display, &end, 10);
2835 		if (display == end)
2836 			usage (argv[0]);
2837 		clientr = clientw = accept_connection (port);
2838 	} else {
2839 		/* Above we made sure that shared_session was only
2840 		 * set if we were recording, so the only case we've
2841 		 * got left is a shared_session record, which doesn't
2842 		 * talk directly to a client at all.
2843 		 */
2844 		clientr = clientw = -1;
2845 	}
2846 
2847 	/* Do it */
2848 	if (action == 'r') {
2849 		record (file[0], clientr, clientw, server_addr, type == 'e', appenddate, shared_session);
2850 	} else {
2851 		int file_to_play = 0;
2852 		int looping = 0;
2853 		while (playback (file[file_to_play],
2854 				 clientr, clientw, looping,
2855 				 cycle, pause) > 0) {
2856 			file_to_play++;
2857 			if (file_to_play == files) {
2858 				if (!loop)
2859 					break;
2860 				file_to_play = 0;
2861 			}
2862 			looping = 1;
2863 		}
2864 	}
2865 
2866 	/* Clean up */
2867 	if (!use_stdout)
2868 		close (clientr);
2869 
2870 	return 0;
2871 }
2872