1221420Sdes/* $OpenBSD: compress.c,v 1.26 2010/09/08 04:13:31 deraadt Exp $ */
257429Smarkm/*
357429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi>
457429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
557429Smarkm *                    All rights reserved
657429Smarkm * Interface to packet compression for ssh.
760573Skris *
865668Skris * As far as I am concerned, the code I have written for this software
965668Skris * can be used freely for any purpose.  Any derived versions of this
1065668Skris * software must be clearly marked as such, and if the derived work is
1165668Skris * incompatible with the protocol description in the RFC file, it must be
1265668Skris * called by a name other than "ssh" or "Secure Shell".
1357429Smarkm */
1457429Smarkm
1557429Smarkm#include "includes.h"
1657429Smarkm
17162852Sdes#include <sys/types.h>
18162852Sdes
19162852Sdes#include <stdarg.h>
20162852Sdes
2176259Sgreen#include "log.h"
2257429Smarkm#include "buffer.h"
2376259Sgreen#include "compress.h"
2457429Smarkm
25221420Sdes#include <zlib.h>
26221420Sdes
2798675Sdesz_stream incoming_stream;
2898675Sdesz_stream outgoing_stream;
2976259Sgreenstatic int compress_init_send_called = 0;
3076259Sgreenstatic int compress_init_recv_called = 0;
3198675Sdesstatic int inflate_failed = 0;
3298675Sdesstatic int deflate_failed = 0;
3357429Smarkm
3457429Smarkm/*
3557429Smarkm * Initializes compression; level is compression level from 1 to 9
3657429Smarkm * (as in gzip).
3757429Smarkm */
3857429Smarkm
3960573Skrisvoid
4076259Sgreenbuffer_compress_init_send(int level)
4157429Smarkm{
4276259Sgreen	if (compress_init_send_called == 1)
4392555Sdes		deflateEnd(&outgoing_stream);
4476259Sgreen	compress_init_send_called = 1;
4557429Smarkm	debug("Enabling compression at level %d.", level);
4657429Smarkm	if (level < 1 || level > 9)
4757429Smarkm		fatal("Bad compression level %d.", level);
4857429Smarkm	deflateInit(&outgoing_stream, level);
4957429Smarkm}
5076259Sgreenvoid
5176259Sgreenbuffer_compress_init_recv(void)
5276259Sgreen{
5376259Sgreen	if (compress_init_recv_called == 1)
5476259Sgreen		inflateEnd(&incoming_stream);
5576259Sgreen	compress_init_recv_called = 1;
5676259Sgreen	inflateInit(&incoming_stream);
5776259Sgreen}
5857429Smarkm
5957429Smarkm/* Frees any data structures allocated for compression. */
6057429Smarkm
6160573Skrisvoid
6276259Sgreenbuffer_compress_uninit(void)
6357429Smarkm{
64126274Sdes	debug("compress outgoing: raw data %llu, compressed %llu, factor %.2f",
65126274Sdes	    (unsigned long long)outgoing_stream.total_in,
66126274Sdes	    (unsigned long long)outgoing_stream.total_out,
6792555Sdes	    outgoing_stream.total_in == 0 ? 0.0 :
6892555Sdes	    (double) outgoing_stream.total_out / outgoing_stream.total_in);
69126274Sdes	debug("compress incoming: raw data %llu, compressed %llu, factor %.2f",
70126274Sdes	    (unsigned long long)incoming_stream.total_out,
71126274Sdes	    (unsigned long long)incoming_stream.total_in,
7292555Sdes	    incoming_stream.total_out == 0 ? 0.0 :
7392555Sdes	    (double) incoming_stream.total_in / incoming_stream.total_out);
7498675Sdes	if (compress_init_recv_called == 1 && inflate_failed == 0)
7576259Sgreen		inflateEnd(&incoming_stream);
7698675Sdes	if (compress_init_send_called == 1 && deflate_failed == 0)
7776259Sgreen		deflateEnd(&outgoing_stream);
7857429Smarkm}
7957429Smarkm
8057429Smarkm/*
8157429Smarkm * Compresses the contents of input_buffer into output_buffer.  All packets
8257429Smarkm * compressed using this function will form a single compressed data stream;
8357429Smarkm * however, data will be flushed at the end of every call so that each
8457429Smarkm * output_buffer can be decompressed independently (but in the appropriate
8557429Smarkm * order since they together form a single compression stream) by the
8657429Smarkm * receiver.  This appends the compressed data to the output buffer.
8757429Smarkm */
8857429Smarkm
8960573Skrisvoid
9057429Smarkmbuffer_compress(Buffer * input_buffer, Buffer * output_buffer)
9157429Smarkm{
9292555Sdes	u_char buf[4096];
9357429Smarkm	int status;
9457429Smarkm
9557429Smarkm	/* This case is not handled below. */
9657429Smarkm	if (buffer_len(input_buffer) == 0)
9757429Smarkm		return;
9857429Smarkm
9957429Smarkm	/* Input is the contents of the input buffer. */
10092555Sdes	outgoing_stream.next_in = buffer_ptr(input_buffer);
10157429Smarkm	outgoing_stream.avail_in = buffer_len(input_buffer);
10257429Smarkm
10357429Smarkm	/* Loop compressing until deflate() returns with avail_out != 0. */
10457429Smarkm	do {
10557429Smarkm		/* Set up fixed-size output buffer. */
10692555Sdes		outgoing_stream.next_out = buf;
10757429Smarkm		outgoing_stream.avail_out = sizeof(buf);
10857429Smarkm
10957429Smarkm		/* Compress as much data into the buffer as possible. */
11057429Smarkm		status = deflate(&outgoing_stream, Z_PARTIAL_FLUSH);
11157429Smarkm		switch (status) {
11257429Smarkm		case Z_OK:
11357429Smarkm			/* Append compressed data to output_buffer. */
11457429Smarkm			buffer_append(output_buffer, buf,
11560573Skris			    sizeof(buf) - outgoing_stream.avail_out);
11657429Smarkm			break;
11757429Smarkm		default:
11898675Sdes			deflate_failed = 1;
11957429Smarkm			fatal("buffer_compress: deflate returned %d", status);
12057429Smarkm			/* NOTREACHED */
12157429Smarkm		}
12260573Skris	} while (outgoing_stream.avail_out == 0);
12357429Smarkm}
12457429Smarkm
12557429Smarkm/*
12657429Smarkm * Uncompresses the contents of input_buffer into output_buffer.  All packets
12757429Smarkm * uncompressed using this function will form a single compressed data
12857429Smarkm * stream; however, data will be flushed at the end of every call so that
12957429Smarkm * each output_buffer.  This must be called for the same size units that the
13057429Smarkm * buffer_compress was called, and in the same order that buffers compressed
13157429Smarkm * with that.  This appends the uncompressed data to the output buffer.
13257429Smarkm */
13357429Smarkm
13460573Skrisvoid
13557429Smarkmbuffer_uncompress(Buffer * input_buffer, Buffer * output_buffer)
13657429Smarkm{
13792555Sdes	u_char buf[4096];
13857429Smarkm	int status;
13957429Smarkm
14092555Sdes	incoming_stream.next_in = buffer_ptr(input_buffer);
14157429Smarkm	incoming_stream.avail_in = buffer_len(input_buffer);
14257429Smarkm
14360573Skris	for (;;) {
14460573Skris		/* Set up fixed-size output buffer. */
14592555Sdes		incoming_stream.next_out = buf;
14660573Skris		incoming_stream.avail_out = sizeof(buf);
14757429Smarkm
14857429Smarkm		status = inflate(&incoming_stream, Z_PARTIAL_FLUSH);
14957429Smarkm		switch (status) {
15057429Smarkm		case Z_OK:
15157429Smarkm			buffer_append(output_buffer, buf,
15260573Skris			    sizeof(buf) - incoming_stream.avail_out);
15357429Smarkm			break;
15457429Smarkm		case Z_BUF_ERROR:
15557429Smarkm			/*
15657429Smarkm			 * Comments in zlib.h say that we should keep calling
15757429Smarkm			 * inflate() until we get an error.  This appears to
15857429Smarkm			 * be the error that we get.
15957429Smarkm			 */
16057429Smarkm			return;
16157429Smarkm		default:
16298675Sdes			inflate_failed = 1;
16357429Smarkm			fatal("buffer_uncompress: inflate returned %d", status);
16460573Skris			/* NOTREACHED */
16557429Smarkm		}
16657429Smarkm	}
16757429Smarkm}
168