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 (×tamp, 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