documented updates
[gnutls.git] / lib / gnutls_compress.c
blob9d4380ae82ed381383fb0f5baa981b6e78408cbf
1 /*
2 * Copyright (C) 2000-2012 Free Software Foundation, Inc.
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of GnuTLS.
8 * The GnuTLS is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 3 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
23 /* This file contains the functions which convert the TLS plaintext
24 * packet to TLS compressed packet.
27 #include "gnutls_int.h"
28 #include "gnutls_compress.h"
29 #include "gnutls_errors.h"
30 #include "gnutls_constate.h"
31 #include <algorithms.h>
32 #include <gnutls/gnutls.h>
34 /* Compression Section */
35 #define GNUTLS_COMPRESSION_ENTRY(name, id, wb, ml, cl) \
36 { #name, name, id, wb, ml, cl}
39 #define MAX_COMP_METHODS 5
40 const int _gnutls_comp_algorithms_size = MAX_COMP_METHODS;
42 gnutls_compression_entry _gnutls_compression_algorithms[MAX_COMP_METHODS] = {
43 GNUTLS_COMPRESSION_ENTRY (GNUTLS_COMP_NULL, 0x00, 0, 0, 0),
44 #ifdef HAVE_LIBZ
45 /* draft-ietf-tls-compression-02 */
46 GNUTLS_COMPRESSION_ENTRY (GNUTLS_COMP_DEFLATE, 0x01, 15, 8, 3),
47 #endif
48 {0, 0, 0, 0, 0, 0}
51 static const gnutls_compression_method_t supported_compressions[] = {
52 #ifdef HAVE_LIBZ
53 GNUTLS_COMP_DEFLATE,
54 #endif
55 GNUTLS_COMP_NULL,
59 #define GNUTLS_COMPRESSION_LOOP(b) \
60 const gnutls_compression_entry *p; \
61 for(p = _gnutls_compression_algorithms; p->name != NULL; p++) { b ; }
62 #define GNUTLS_COMPRESSION_ALG_LOOP(a) \
63 GNUTLS_COMPRESSION_LOOP( if(p->id == algorithm) { a; break; } )
64 #define GNUTLS_COMPRESSION_ALG_LOOP_NUM(a) \
65 GNUTLS_COMPRESSION_LOOP( if(p->num == num) { a; break; } )
67 /* Compression Functions */
69 /**
70 * gnutls_compression_get_name:
71 * @algorithm: is a Compression algorithm
73 * Convert a #gnutls_compression_method_t value to a string.
75 * Returns: a pointer to a string that contains the name of the
76 * specified compression algorithm, or %NULL.
77 **/
78 const char *
79 gnutls_compression_get_name (gnutls_compression_method_t algorithm)
81 const char *ret = NULL;
83 /* avoid prefix */
84 GNUTLS_COMPRESSION_ALG_LOOP (ret = p->name + sizeof ("GNUTLS_COMP_") - 1);
86 return ret;
89 /**
90 * gnutls_compression_get_id:
91 * @name: is a compression method name
93 * The names are compared in a case insensitive way.
95 * Returns: an id of the specified in a string compression method, or
96 * %GNUTLS_COMP_UNKNOWN on error.
97 **/
98 gnutls_compression_method_t
99 gnutls_compression_get_id (const char *name)
101 gnutls_compression_method_t ret = GNUTLS_COMP_UNKNOWN;
103 GNUTLS_COMPRESSION_LOOP (if
104 (strcasecmp
105 (p->name + sizeof ("GNUTLS_COMP_") - 1,
106 name) == 0) ret = p->id);
108 return ret;
112 * gnutls_compression_list:
114 * Get a list of compression methods.
116 * Returns: a zero-terminated list of #gnutls_compression_method_t
117 * integers indicating the available compression methods.
119 const gnutls_compression_method_t *
120 gnutls_compression_list (void)
122 return supported_compressions;
125 /* return the tls number of the specified algorithm */
127 _gnutls_compression_get_num (gnutls_compression_method_t algorithm)
129 int ret = -1;
131 /* avoid prefix */
132 GNUTLS_COMPRESSION_ALG_LOOP (ret = p->num);
134 return ret;
137 #ifdef HAVE_LIBZ
139 static int
140 get_wbits (gnutls_compression_method_t algorithm)
142 int ret = -1;
143 /* avoid prefix */
144 GNUTLS_COMPRESSION_ALG_LOOP (ret = p->window_bits);
145 return ret;
148 static int
149 get_mem_level (gnutls_compression_method_t algorithm)
151 int ret = -1;
152 /* avoid prefix */
153 GNUTLS_COMPRESSION_ALG_LOOP (ret = p->mem_level);
154 return ret;
157 static int
158 get_comp_level (gnutls_compression_method_t algorithm)
160 int ret = -1;
161 /* avoid prefix */
162 GNUTLS_COMPRESSION_ALG_LOOP (ret = p->comp_level);
163 return ret;
166 #endif
168 /* returns the gnutls internal ID of the TLS compression
169 * method num
171 gnutls_compression_method_t
172 _gnutls_compression_get_id (int num)
174 gnutls_compression_method_t ret = -1;
176 /* avoid prefix */
177 GNUTLS_COMPRESSION_ALG_LOOP_NUM (ret = p->id);
179 return ret;
183 _gnutls_compression_is_ok (gnutls_compression_method_t algorithm)
185 ssize_t ret = -1;
186 GNUTLS_COMPRESSION_ALG_LOOP (ret = p->id);
187 if (ret >= 0)
188 ret = 0;
189 else
190 ret = 1;
191 return ret;
196 /* For compression */
198 #define MIN_PRIVATE_COMP_ALGO 0xEF
200 /* returns the TLS numbers of the compression methods we support
202 #define SUPPORTED_COMPRESSION_METHODS session->internals.priorities.compression.algorithms
204 _gnutls_supported_compression_methods (gnutls_session_t session,
205 uint8_t * comp, size_t comp_size)
207 unsigned int i, j;
209 if (comp_size < SUPPORTED_COMPRESSION_METHODS)
210 return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
212 for (i = j = 0; i < SUPPORTED_COMPRESSION_METHODS; i++)
214 int tmp =
215 _gnutls_compression_get_num (session->internals.
216 priorities.compression.priority[i]);
218 /* remove private compression algorithms, if requested.
220 if (tmp == -1 || (tmp >= MIN_PRIVATE_COMP_ALGO &&
221 session->internals.enable_private == 0))
223 gnutls_assert ();
224 continue;
227 comp[j] = (uint8_t) tmp;
228 j++;
231 if (j == 0)
233 gnutls_assert ();
234 return GNUTLS_E_NO_COMPRESSION_ALGORITHMS;
236 return j;
240 /* The flag d is the direction (compress, decompress). Non zero is
241 * decompress.
243 int _gnutls_comp_init (comp_hd_st* handle, gnutls_compression_method_t method, int d)
245 handle->algo = method;
246 handle->handle = NULL;
248 switch (method)
250 case GNUTLS_COMP_DEFLATE:
251 #ifdef HAVE_LIBZ
253 int window_bits, mem_level;
254 int comp_level;
255 z_stream *zhandle;
256 int err;
258 window_bits = get_wbits (method);
259 mem_level = get_mem_level (method);
260 comp_level = get_comp_level (method);
262 handle->handle = gnutls_malloc (sizeof (z_stream));
263 if (handle->handle == NULL)
264 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
266 zhandle = handle->handle;
268 zhandle->zalloc = (alloc_func) 0;
269 zhandle->zfree = (free_func) 0;
270 zhandle->opaque = (voidpf) 0;
272 if (d)
273 err = inflateInit2 (zhandle, window_bits);
274 else
276 err = deflateInit2 (zhandle,
277 comp_level, Z_DEFLATED,
278 window_bits, mem_level, Z_DEFAULT_STRATEGY);
280 if (err != Z_OK)
282 gnutls_assert ();
283 gnutls_free (handle->handle);
284 return GNUTLS_E_COMPRESSION_FAILED;
287 break;
288 #endif
289 case GNUTLS_COMP_NULL:
290 case GNUTLS_COMP_UNKNOWN:
291 break;
292 default:
293 return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM;
296 return 0;
299 /* The flag d is the direction (compress, decompress). Non zero is
300 * decompress.
302 void
303 _gnutls_comp_deinit (comp_hd_st* handle, int d)
305 if (handle != NULL)
307 switch (handle->algo)
309 #ifdef HAVE_LIBZ
310 case GNUTLS_COMP_DEFLATE:
312 if (d)
313 inflateEnd (handle->handle);
314 else
315 deflateEnd (handle->handle);
316 break;
318 #endif
319 default:
320 break;
322 gnutls_free (handle->handle);
323 handle->handle = NULL;
327 /* These functions are memory consuming
331 _gnutls_compress (comp_hd_st *handle, const uint8_t * plain,
332 size_t plain_size, uint8_t * compressed,
333 size_t max_comp_size, unsigned int stateless)
335 int compressed_size = GNUTLS_E_COMPRESSION_FAILED;
337 /* NULL compression is not handled here
339 if (handle == NULL)
341 gnutls_assert ();
342 return GNUTLS_E_INTERNAL_ERROR;
345 switch (handle->algo)
347 #ifdef HAVE_LIBZ
348 case GNUTLS_COMP_DEFLATE:
350 z_stream *zhandle;
351 int err;
352 int type;
354 if (stateless)
356 fprintf(stderr, "FULL FLUSH\n");
357 type = Z_FULL_FLUSH;
359 else
360 type = Z_SYNC_FLUSH;
362 zhandle = handle->handle;
364 zhandle->next_in = (Bytef *) plain;
365 zhandle->avail_in = plain_size;
366 zhandle->next_out = (Bytef *) compressed;
367 zhandle->avail_out = max_comp_size;
369 err = deflate (zhandle, type);
370 if (err != Z_OK || zhandle->avail_in != 0)
371 return gnutls_assert_val(GNUTLS_E_COMPRESSION_FAILED);
374 compressed_size = max_comp_size - zhandle->avail_out;
375 break;
377 #endif
378 default:
379 gnutls_assert ();
380 return GNUTLS_E_INTERNAL_ERROR;
381 } /* switch */
383 #ifdef COMPRESSION_DEBUG
384 _gnutls_debug_log ("Compression ratio: %f\n",
385 (float) ((float) compressed_size / (float) plain_size));
386 #endif
388 return compressed_size;
394 _gnutls_decompress (comp_hd_st *handle, uint8_t * compressed,
395 size_t compressed_size, uint8_t * plain,
396 size_t max_plain_size)
398 int plain_size = GNUTLS_E_DECOMPRESSION_FAILED;
400 if (compressed_size > max_plain_size + EXTRA_COMP_SIZE)
402 gnutls_assert ();
403 return GNUTLS_E_DECOMPRESSION_FAILED;
406 /* NULL compression is not handled here
409 if (handle == NULL)
411 gnutls_assert ();
412 return GNUTLS_E_INTERNAL_ERROR;
415 switch (handle->algo)
417 #ifdef HAVE_LIBZ
418 case GNUTLS_COMP_DEFLATE:
420 z_stream *zhandle;
421 int err;
423 zhandle = handle->handle;
425 zhandle->next_in = (Bytef *) compressed;
426 zhandle->avail_in = compressed_size;
428 zhandle->next_out = (Bytef *) plain;
429 zhandle->avail_out = max_plain_size;
430 err = inflate (zhandle, Z_SYNC_FLUSH);
432 if (err != Z_OK)
433 return gnutls_assert_val(GNUTLS_E_DECOMPRESSION_FAILED);
435 plain_size = max_plain_size - zhandle->avail_out;
436 break;
438 #endif
439 default:
440 gnutls_assert ();
441 return GNUTLS_E_INTERNAL_ERROR;
442 } /* switch */
444 return plain_size;