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