combined more tests with eagain-common.h.
[gnutls.git] / lib / gnutls_compress.c
blob2520832edd9749a30b4b0c144f3e71e6f3e28855
1 /*
2 * Copyright (C) 2000, 2004, 2005, 2007, 2008, 2010 Free Software
3 * Foundation, Inc.
5 * Author: Nikos Mavrogiannopoulos
7 * This file is part of GnuTLS.
9 * The GnuTLS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1 of
12 * the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22 * USA
26 /* This file contains the functions which convert the TLS plaintext
27 * packet to TLS compressed packet.
30 #include "gnutls_int.h"
31 #include "gnutls_compress.h"
32 #include "gnutls_errors.h"
33 #include "gnutls_constate.h"
34 #include <gnutls_algorithms.h>
35 #include <gnutls/gnutls.h>
37 /* These functions allocate the return value internally
39 int
40 _gnutls_m_plaintext2compressed (gnutls_session_t session,
41 gnutls_datum_t * compressed,
42 const gnutls_datum_t * plaintext,
43 const record_parameters_st * params)
45 int size;
46 opaque *data;
48 size =
49 _gnutls_compress (params->write.compression_state,
50 plaintext->data, plaintext->size, &data,
51 MAX_RECORD_SEND_SIZE + EXTRA_COMP_SIZE);
52 if (size < 0)
54 gnutls_assert ();
55 return GNUTLS_E_COMPRESSION_FAILED;
57 compressed->data = data;
58 compressed->size = size;
60 return 0;
63 int
64 _gnutls_m_compressed2plaintext (gnutls_session_t session,
65 gnutls_datum_t * plain,
66 const gnutls_datum_t * compressed,
67 const record_parameters_st * params)
69 int size;
70 opaque *data;
72 size =
73 _gnutls_decompress (params->read.compression_state,
74 compressed->data, compressed->size, &data,
75 MAX_RECORD_RECV_SIZE);
76 if (size < 0)
78 gnutls_assert ();
79 return GNUTLS_E_DECOMPRESSION_FAILED;
81 plain->data = data;
82 plain->size = size;
84 return 0;
88 /* Compression Section */
89 #define GNUTLS_COMPRESSION_ENTRY(name, id, wb, ml, cl) \
90 { #name, name, id, wb, ml, cl}
93 #define MAX_COMP_METHODS 5
94 const int _gnutls_comp_algorithms_size = MAX_COMP_METHODS;
96 gnutls_compression_entry _gnutls_compression_algorithms[MAX_COMP_METHODS] = {
97 GNUTLS_COMPRESSION_ENTRY (GNUTLS_COMP_NULL, 0x00, 0, 0, 0),
98 #ifdef HAVE_LIBZ
99 /* draft-ietf-tls-compression-02 */
100 GNUTLS_COMPRESSION_ENTRY (GNUTLS_COMP_DEFLATE, 0x01, 15, 8, 3),
101 #endif
102 {0, 0, 0, 0, 0, 0}
105 static const gnutls_compression_method_t supported_compressions[] = {
106 #ifdef USE_LZO
107 GNUTLS_COMP_LZO,
108 #endif
109 #ifdef HAVE_LIBZ
110 GNUTLS_COMP_DEFLATE,
111 #endif
112 GNUTLS_COMP_NULL,
116 #define GNUTLS_COMPRESSION_LOOP(b) \
117 const gnutls_compression_entry *p; \
118 for(p = _gnutls_compression_algorithms; p->name != NULL; p++) { b ; }
119 #define GNUTLS_COMPRESSION_ALG_LOOP(a) \
120 GNUTLS_COMPRESSION_LOOP( if(p->id == algorithm) { a; break; } )
121 #define GNUTLS_COMPRESSION_ALG_LOOP_NUM(a) \
122 GNUTLS_COMPRESSION_LOOP( if(p->num == num) { a; break; } )
124 /* Compression Functions */
127 * gnutls_compression_get_name:
128 * @algorithm: is a Compression algorithm
130 * Convert a #gnutls_compression_method_t value to a string.
132 * Returns: a pointer to a string that contains the name of the
133 * specified compression algorithm, or %NULL.
135 const char *
136 gnutls_compression_get_name (gnutls_compression_method_t algorithm)
138 const char *ret = NULL;
140 /* avoid prefix */
141 GNUTLS_COMPRESSION_ALG_LOOP (ret = p->name + sizeof ("GNUTLS_COMP_") - 1);
143 return ret;
147 * gnutls_compression_get_id:
148 * @name: is a compression method name
150 * The names are compared in a case insensitive way.
152 * Returns: an id of the specified in a string compression method, or
153 * %GNUTLS_COMP_UNKNOWN on error.
155 gnutls_compression_method_t
156 gnutls_compression_get_id (const char *name)
158 gnutls_compression_method_t ret = GNUTLS_COMP_UNKNOWN;
160 GNUTLS_COMPRESSION_LOOP (if
161 (strcasecmp
162 (p->name + sizeof ("GNUTLS_COMP_") - 1,
163 name) == 0) ret = p->id);
165 return ret;
169 * gnutls_compression_list:
171 * Get a list of compression methods. Note that to be able to use LZO
172 * compression, you must link to libgnutls-extra and call
173 * gnutls_global_init_extra().
175 * Returns: a zero-terminated list of #gnutls_compression_method_t
176 * integers indicating the available compression methods.
178 const gnutls_compression_method_t *
179 gnutls_compression_list (void)
181 return supported_compressions;
184 /* return the tls number of the specified algorithm */
186 _gnutls_compression_get_num (gnutls_compression_method_t algorithm)
188 int ret = -1;
190 /* avoid prefix */
191 GNUTLS_COMPRESSION_ALG_LOOP (ret = p->num);
193 return ret;
196 #ifdef HAVE_LIBZ
198 static int
199 get_wbits (gnutls_compression_method_t algorithm)
201 int ret = -1;
202 /* avoid prefix */
203 GNUTLS_COMPRESSION_ALG_LOOP (ret = p->window_bits);
204 return ret;
207 static int
208 get_mem_level (gnutls_compression_method_t algorithm)
210 int ret = -1;
211 /* avoid prefix */
212 GNUTLS_COMPRESSION_ALG_LOOP (ret = p->mem_level);
213 return ret;
216 static int
217 get_comp_level (gnutls_compression_method_t algorithm)
219 int ret = -1;
220 /* avoid prefix */
221 GNUTLS_COMPRESSION_ALG_LOOP (ret = p->comp_level);
222 return ret;
225 #endif
227 /* returns the gnutls internal ID of the TLS compression
228 * method num
230 gnutls_compression_method_t
231 _gnutls_compression_get_id (int num)
233 gnutls_compression_method_t ret = -1;
235 /* avoid prefix */
236 GNUTLS_COMPRESSION_ALG_LOOP_NUM (ret = p->id);
238 return ret;
242 _gnutls_compression_is_ok (gnutls_compression_method_t algorithm)
244 ssize_t ret = -1;
245 GNUTLS_COMPRESSION_ALG_LOOP (ret = p->id);
246 if (ret >= 0)
247 ret = 0;
248 else
249 ret = 1;
250 return ret;
255 /* For compression */
257 #define MIN_PRIVATE_COMP_ALGO 0xEF
259 /* returns the TLS numbers of the compression methods we support
261 #define SUPPORTED_COMPRESSION_METHODS session->internals.priorities.compression.algorithms
263 _gnutls_supported_compression_methods (gnutls_session_t session,
264 uint8_t ** comp)
266 unsigned int i, j;
268 *comp = gnutls_malloc (sizeof (uint8_t) * SUPPORTED_COMPRESSION_METHODS);
269 if (*comp == NULL)
270 return GNUTLS_E_MEMORY_ERROR;
272 for (i = j = 0; i < SUPPORTED_COMPRESSION_METHODS; i++)
274 int tmp =
275 _gnutls_compression_get_num (session->internals.
276 priorities.compression.priority[i]);
278 /* remove private compression algorithms, if requested.
280 if (tmp == -1 || (tmp >= MIN_PRIVATE_COMP_ALGO &&
281 session->internals.enable_private == 0))
283 gnutls_assert ();
284 continue;
287 (*comp)[j] = (uint8_t) tmp;
288 j++;
291 if (j == 0)
293 gnutls_assert ();
294 gnutls_free (*comp);
295 *comp = NULL;
296 return GNUTLS_E_NO_COMPRESSION_ALGORITHMS;
298 return j;
302 #ifdef USE_LZO
303 #ifdef USE_MINILZO
304 /* Get the prototypes only. Since LZO is a GPLed library, the
305 * gnutls_global_init_extra() has to be called, before LZO compression
306 * can be used.
308 #include "../libextra/minilzo/minilzo.h"
309 #elif HAVE_LZO_LZO1X_H
310 #include <lzo/lzo1x.h>
311 #elif HAVE_LZO1X_H
312 #include <lzo1x.h>
313 #endif
315 typedef int (*LZO_FUNC) ();
317 LZO_FUNC _gnutls_lzo1x_decompress_safe = NULL;
318 LZO_FUNC _gnutls_lzo1x_1_compress = NULL;
320 #endif
322 /* The flag d is the direction (compress, decompress). Non zero is
323 * decompress.
325 comp_hd_t
326 _gnutls_comp_init (gnutls_compression_method_t method, int d)
328 comp_hd_t ret;
330 ret = gnutls_malloc (sizeof (struct comp_hd_t_STRUCT));
331 if (ret == NULL)
333 gnutls_assert ();
334 return NULL;
337 ret->algo = method;
338 ret->handle = NULL;
340 switch (method)
342 case GNUTLS_COMP_DEFLATE:
343 #ifdef HAVE_LIBZ
345 int window_bits, mem_level;
346 int comp_level;
347 z_stream *zhandle;
348 int err;
350 window_bits = get_wbits (method);
351 mem_level = get_mem_level (method);
352 comp_level = get_comp_level (method);
354 ret->handle = gnutls_malloc (sizeof (z_stream));
355 if (ret->handle == NULL)
357 gnutls_assert ();
358 goto cleanup_ret;
361 zhandle = ret->handle;
363 zhandle->zalloc = (alloc_func) 0;
364 zhandle->zfree = (free_func) 0;
365 zhandle->opaque = (voidpf) 0;
367 if (d)
368 err = inflateInit2 (zhandle, window_bits);
369 else
371 err = deflateInit2 (zhandle,
372 comp_level, Z_DEFLATED,
373 window_bits, mem_level, Z_DEFAULT_STRATEGY);
375 if (err != Z_OK)
377 gnutls_assert ();
378 gnutls_free (ret->handle);
379 goto cleanup_ret;
382 break;
383 #endif
384 case GNUTLS_COMP_LZO:
385 #ifdef USE_LZO
386 /* LZO does not use memory on decompressor */
387 if (!d)
389 ret->handle = gnutls_malloc (LZO1X_1_MEM_COMPRESS);
391 if (ret->handle == NULL)
393 gnutls_assert ();
394 goto cleanup_ret;
397 break;
398 #endif
399 case GNUTLS_COMP_NULL:
400 case GNUTLS_COMP_UNKNOWN:
401 break;
404 return ret;
406 cleanup_ret:
407 gnutls_free (ret);
408 return NULL;
411 /* The flag d is the direction (compress, decompress). Non zero is
412 * decompress.
414 void
415 _gnutls_comp_deinit (comp_hd_t handle, int d)
417 if (handle != NULL)
419 switch (handle->algo)
421 #ifdef HAVE_LIBZ
422 case GNUTLS_COMP_DEFLATE:
424 int err;
426 if (d)
427 err = inflateEnd (handle->handle);
428 else
429 err = deflateEnd (handle->handle);
430 break;
432 #endif
433 default:
434 break;
436 gnutls_free (handle->handle);
437 gnutls_free (handle);
442 /* These functions are memory consuming
446 _gnutls_compress (comp_hd_t handle, const opaque * plain,
447 size_t plain_size, opaque ** compressed,
448 size_t max_comp_size)
450 int compressed_size = GNUTLS_E_COMPRESSION_FAILED;
452 /* NULL compression is not handled here
454 if (handle == NULL)
456 gnutls_assert ();
457 return GNUTLS_E_INTERNAL_ERROR;
460 switch (handle->algo)
462 #ifdef USE_LZO
463 case GNUTLS_COMP_LZO:
465 lzo_uint out_len;
466 size_t size;
467 int err;
469 if (_gnutls_lzo1x_1_compress == NULL)
470 return GNUTLS_E_COMPRESSION_FAILED;
472 size = plain_size + plain_size / 64 + 16 + 3;
473 *compressed = gnutls_malloc (size);
474 if (*compressed == NULL)
476 gnutls_assert ();
477 return GNUTLS_E_MEMORY_ERROR;
480 err = _gnutls_lzo1x_1_compress (plain, plain_size, *compressed,
481 &out_len, handle->handle);
483 if (err != LZO_E_OK)
485 gnutls_assert ();
486 gnutls_free (*compressed);
487 *compressed = NULL;
488 return GNUTLS_E_COMPRESSION_FAILED;
491 compressed_size = out_len;
492 break;
494 #endif
495 #ifdef HAVE_LIBZ
496 case GNUTLS_COMP_DEFLATE:
498 uLongf size;
499 z_stream *zhandle;
500 int err;
502 size = (plain_size + plain_size) + 10;
503 *compressed = gnutls_malloc (size);
504 if (*compressed == NULL)
506 gnutls_assert ();
507 return GNUTLS_E_MEMORY_ERROR;
510 zhandle = handle->handle;
512 zhandle->next_in = (Bytef *) plain;
513 zhandle->avail_in = plain_size;
514 zhandle->next_out = (Bytef *) * compressed;
515 zhandle->avail_out = size;
517 err = deflate (zhandle, Z_SYNC_FLUSH);
519 if (err != Z_OK || zhandle->avail_in != 0)
521 gnutls_assert ();
522 gnutls_free (*compressed);
523 *compressed = NULL;
524 return GNUTLS_E_COMPRESSION_FAILED;
527 compressed_size = size - zhandle->avail_out;
528 break;
530 #endif
531 default:
532 gnutls_assert ();
533 return GNUTLS_E_INTERNAL_ERROR;
534 } /* switch */
536 #ifdef COMPRESSION_DEBUG
537 _gnutls_debug_log ("Compression ratio: %f\n",
538 (float) ((float) compressed_size / (float) plain_size));
539 #endif
541 if ((size_t) compressed_size > max_comp_size)
543 gnutls_free (*compressed);
544 *compressed = NULL;
545 return GNUTLS_E_COMPRESSION_FAILED;
548 return compressed_size;
554 _gnutls_decompress (comp_hd_t handle, opaque * compressed,
555 size_t compressed_size, opaque ** plain,
556 size_t max_record_size)
558 int plain_size = GNUTLS_E_DECOMPRESSION_FAILED;
560 if (compressed_size > max_record_size + EXTRA_COMP_SIZE)
562 gnutls_assert ();
563 return GNUTLS_E_DECOMPRESSION_FAILED;
566 /* NULL compression is not handled here
569 if (handle == NULL)
571 gnutls_assert ();
572 return GNUTLS_E_INTERNAL_ERROR;
575 switch (handle->algo)
577 #ifdef USE_LZO
578 case GNUTLS_COMP_LZO:
580 lzo_uint out_size;
581 lzo_uint new_size;
582 int err;
584 if (_gnutls_lzo1x_decompress_safe == NULL)
585 return GNUTLS_E_DECOMPRESSION_FAILED;
587 *plain = NULL;
588 out_size = compressed_size + compressed_size;
589 plain_size = 0;
593 out_size += 512;
594 *plain = gnutls_realloc_fast (*plain, out_size);
595 if (*plain == NULL)
597 gnutls_assert ();
598 return GNUTLS_E_MEMORY_ERROR;
601 new_size = out_size;
602 err =
603 _gnutls_lzo1x_decompress_safe (compressed,
604 compressed_size, *plain,
605 &new_size, NULL);
608 while ((err == LZO_E_OUTPUT_OVERRUN && out_size < max_record_size));
610 if (err != LZO_E_OK)
612 gnutls_assert ();
613 gnutls_free (*plain);
614 *plain = NULL;
615 return GNUTLS_E_DECOMPRESSION_FAILED;
618 plain_size = new_size;
619 break;
621 #endif
622 #ifdef HAVE_LIBZ
623 case GNUTLS_COMP_DEFLATE:
625 uLongf out_size;
626 z_stream *zhandle;
627 int cur_pos;
628 int err;
630 *plain = NULL;
631 out_size = compressed_size + compressed_size;
632 plain_size = 0;
634 zhandle = handle->handle;
636 zhandle->next_in = (Bytef *) compressed;
637 zhandle->avail_in = compressed_size;
639 cur_pos = 0;
643 out_size += 512;
644 *plain = gnutls_realloc_fast (*plain, out_size);
645 if (*plain == NULL)
647 gnutls_assert ();
648 return GNUTLS_E_MEMORY_ERROR;
651 zhandle->next_out = (Bytef *) (*plain + cur_pos);
652 zhandle->avail_out = out_size - cur_pos;
654 err = inflate (zhandle, Z_SYNC_FLUSH);
656 cur_pos = out_size - zhandle->avail_out;
659 while ((err == Z_BUF_ERROR && zhandle->avail_out == 0
660 && out_size < max_record_size)
661 || (err == Z_OK && zhandle->avail_in != 0));
663 if (err != Z_OK)
665 gnutls_assert ();
666 gnutls_free (*plain);
667 *plain = NULL;
668 return GNUTLS_E_DECOMPRESSION_FAILED;
671 plain_size = out_size - zhandle->avail_out;
672 break;
674 #endif
675 default:
676 gnutls_assert ();
677 return GNUTLS_E_INTERNAL_ERROR;
678 } /* switch */
680 if ((size_t) plain_size > max_record_size)
682 gnutls_assert ();
683 gnutls_free (*plain);
684 *plain = NULL;
685 return GNUTLS_E_DECOMPRESSION_FAILED;
688 return plain_size;