Home | History | Annotate | Download | only in openssh
      1 /* $OpenBSD: compress.c,v 1.26 2010/09/08 04:13:31 deraadt Exp $ */
      2 /*
      3  * Author: Tatu Ylonen <ylo (at) cs.hut.fi>
      4  * Copyright (c) 1995 Tatu Ylonen <ylo (at) cs.hut.fi>, Espoo, Finland
      5  *                    All rights reserved
      6  * Interface to packet compression for ssh.
      7  *
      8  * As far as I am concerned, the code I have written for this software
      9  * can be used freely for any purpose.  Any derived versions of this
     10  * software must be clearly marked as such, and if the derived work is
     11  * incompatible with the protocol description in the RFC file, it must be
     12  * called by a name other than "ssh" or "Secure Shell".
     13  */
     14 
     15 #include "includes.h"
     16 
     17 #include <sys/types.h>
     18 
     19 #include <stdarg.h>
     20 
     21 #include "log.h"
     22 #include "buffer.h"
     23 #include "compress.h"
     24 
     25 #include <zlib.h>
     26 
     27 z_stream incoming_stream;
     28 z_stream outgoing_stream;
     29 static int compress_init_send_called = 0;
     30 static int compress_init_recv_called = 0;
     31 static int inflate_failed = 0;
     32 static int deflate_failed = 0;
     33 
     34 /*
     35  * Initializes compression; level is compression level from 1 to 9
     36  * (as in gzip).
     37  */
     38 
     39 void
     40 buffer_compress_init_send(int level)
     41 {
     42 	if (compress_init_send_called == 1)
     43 		deflateEnd(&outgoing_stream);
     44 	compress_init_send_called = 1;
     45 	debug("Enabling compression at level %d.", level);
     46 	if (level < 1 || level > 9)
     47 		fatal("Bad compression level %d.", level);
     48 	deflateInit(&outgoing_stream, level);
     49 }
     50 void
     51 buffer_compress_init_recv(void)
     52 {
     53 	if (compress_init_recv_called == 1)
     54 		inflateEnd(&incoming_stream);
     55 	compress_init_recv_called = 1;
     56 	inflateInit(&incoming_stream);
     57 }
     58 
     59 /* Frees any data structures allocated for compression. */
     60 
     61 void
     62 buffer_compress_uninit(void)
     63 {
     64 	debug("compress outgoing: raw data %llu, compressed %llu, factor %.2f",
     65 	    (unsigned long long)outgoing_stream.total_in,
     66 	    (unsigned long long)outgoing_stream.total_out,
     67 	    outgoing_stream.total_in == 0 ? 0.0 :
     68 	    (double) outgoing_stream.total_out / outgoing_stream.total_in);
     69 	debug("compress incoming: raw data %llu, compressed %llu, factor %.2f",
     70 	    (unsigned long long)incoming_stream.total_out,
     71 	    (unsigned long long)incoming_stream.total_in,
     72 	    incoming_stream.total_out == 0 ? 0.0 :
     73 	    (double) incoming_stream.total_in / incoming_stream.total_out);
     74 	if (compress_init_recv_called == 1 && inflate_failed == 0)
     75 		inflateEnd(&incoming_stream);
     76 	if (compress_init_send_called == 1 && deflate_failed == 0)
     77 		deflateEnd(&outgoing_stream);
     78 }
     79 
     80 /*
     81  * Compresses the contents of input_buffer into output_buffer.  All packets
     82  * compressed using this function will form a single compressed data stream;
     83  * however, data will be flushed at the end of every call so that each
     84  * output_buffer can be decompressed independently (but in the appropriate
     85  * order since they together form a single compression stream) by the
     86  * receiver.  This appends the compressed data to the output buffer.
     87  */
     88 
     89 void
     90 buffer_compress(Buffer * input_buffer, Buffer * output_buffer)
     91 {
     92 	u_char buf[4096];
     93 	int status;
     94 
     95 	/* This case is not handled below. */
     96 	if (buffer_len(input_buffer) == 0)
     97 		return;
     98 
     99 	/* Input is the contents of the input buffer. */
    100 	outgoing_stream.next_in = buffer_ptr(input_buffer);
    101 	outgoing_stream.avail_in = buffer_len(input_buffer);
    102 
    103 	/* Loop compressing until deflate() returns with avail_out != 0. */
    104 	do {
    105 		/* Set up fixed-size output buffer. */
    106 		outgoing_stream.next_out = buf;
    107 		outgoing_stream.avail_out = sizeof(buf);
    108 
    109 		/* Compress as much data into the buffer as possible. */
    110 		status = deflate(&outgoing_stream, Z_PARTIAL_FLUSH);
    111 		switch (status) {
    112 		case Z_OK:
    113 			/* Append compressed data to output_buffer. */
    114 			buffer_append(output_buffer, buf,
    115 			    sizeof(buf) - outgoing_stream.avail_out);
    116 			break;
    117 		default:
    118 			deflate_failed = 1;
    119 			fatal("buffer_compress: deflate returned %d", status);
    120 			/* NOTREACHED */
    121 		}
    122 	} while (outgoing_stream.avail_out == 0);
    123 }
    124 
    125 /*
    126  * Uncompresses the contents of input_buffer into output_buffer.  All packets
    127  * uncompressed using this function will form a single compressed data
    128  * stream; however, data will be flushed at the end of every call so that
    129  * each output_buffer.  This must be called for the same size units that the
    130  * buffer_compress was called, and in the same order that buffers compressed
    131  * with that.  This appends the uncompressed data to the output buffer.
    132  */
    133 
    134 void
    135 buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer)
    136 {
    137 	u_char buf[4096];
    138 	int status;
    139 
    140 	incoming_stream.next_in = buffer_ptr(input_buffer);
    141 	incoming_stream.avail_in = buffer_len(input_buffer);
    142 
    143 	for (;;) {
    144 		/* Set up fixed-size output buffer. */
    145 		incoming_stream.next_out = buf;
    146 		incoming_stream.avail_out = sizeof(buf);
    147 
    148 		status = inflate(&incoming_stream, Z_PARTIAL_FLUSH);
    149 		switch (status) {
    150 		case Z_OK:
    151 			buffer_append(output_buffer, buf,
    152 			    sizeof(buf) - incoming_stream.avail_out);
    153 			break;
    154 		case Z_BUF_ERROR:
    155 			/*
    156 			 * Comments in zlib.h say that we should keep calling
    157 			 * inflate() until we get an error.  This appears to
    158 			 * be the error that we get.
    159 			 */
    160 			return;
    161 		default:
    162 			inflate_failed = 1;
    163 			fatal("buffer_uncompress: inflate returned %d", status);
    164 			/* NOTREACHED */
    165 		}
    166 	}
    167 }
    168