compression.c
Go to the documentation of this file.
1 /* ========================================================================== */
2 /*! \file
3  * \brief Data compression and decompression
4  *
5  * Copyright (c) 2015-2024 by the developers. See the LICENSE file for details.
6  *
7  * If nothing else is specified, function return zero to indicate success
8  * and a negative value to indicate an error.
9  */
10 
11 
12 /* ========================================================================== */
13 /* Include headers */
14 
15 #include "posix.h" /* Include this first because of feature test macros */
16 
17 #include "config.h"
18 
19 # if CFG_USE_ZLIB /* This requires data from "config.h" */
20 # include <zlib.h>
21 # endif /* CFG_USE_ZLIB */
22 # include <string.h>
23 
24 # include "compression.h"
25 # include "main.h"
26 
27 
28 /* ========================================================================== */
29 /*! \defgroup COMPRESSION COMPR: COMPRESS extension for NNTP
30  *
31  * This module provides optional support for data compression and decompression
32  * according to RFC 8054.
33  *
34  * Currently the following algorithms are supported:
35  * <br>
36  * - DEFLATE according to RFC 1951
37  *
38  * \note
39  * This module currently works only if the zlib library is available.
40  */
41 /*! @{ */
42 
43 
44 #if !CFG_CMPR_DISABLE
45 
46 
47 /* ========================================================================== */
48 /* Constants */
49 
50 /*! \brief Message prefix for COMPRESSION module */
51 #define MAIN_ERR_PREFIX "COMPR: "
52 
53 
54 /* ========================================================================== */
55 /* Data types */
56 
57 struct cmpr_stream
58 {
59  unsigned int alg; /* Compression algorithm (\c CMPR_ALG_xxx constant ) */
60  int sd; /* Socket descriptor or stream handle of undelaying protocol */
61  ssize_t (*tx_send)(int, const void*, size_t, int); /* Send function */
62  ssize_t (*rx_recv)(int, void*, size_t, int); /* Receive function */
63  char* tx_buf_in; /* TX data buffer (uncompressed data) */
64  char* tx_buf_out; /* TX data buffer (compressed data) */
65  char* rx_buf_in; /* RX data buffer (compressed data) */
66  char* rx_buf_out; /* RX data buffer (uncompressed data) */
67  void* tx; /* Stream object for TX direction (compression) */
68  void* rx; /* Stream object for RX direction (decompression) */
69 };
70 
71 
72 /* ========================================================================== */
73 /* Constants */
74 
75 /*! \brief Print debug messages to stdout if nonzero */
76 # define CMPR_DEBUG 0
77 
78 /*! \name Flush options for TX direction of compressed data streams
79  *
80  * The flags can be bitwise ORed together.
81  */
82 /*! @{ */
83 # define CMPR_FLUSH_NO 0
84 # define CMPR_FLUSH_YES 1
85 # define CMPR_FLUSH_END 2
86 /*! @} */
87 
88 
89 /*! \brief Size of internal data buffers
90  *
91  * \attention
92  * The zlib data type \c uInt must be capable of holding this value.
93  */
94 # define CMPR_BUFSIZE (size_t) 32768
95 
96 
97 # if CFG_USE_ZLIB
98 
99 
100 /*! \brief Window size for DEFLATE algorithm
101  *
102  * Compression ratio vs. memory usage tradeoff (integer value from -8 to -15).
103  * Negative base two logarithm of the window size (size of the history buffer)
104  * for zlib. The negative sign selects raw data without container.
105  * <br>
106  * -8: Worst compression and minimum memory usage (256 Byte)
107  * <br>
108  * -15: Best compression and maximum memory usage (32 KiByte)
109  *
110  * \attention
111  * Don't change this value until you know what you are doing. It must match the
112  * setup of the peer.
113  */
114 # define CMPR_ZLIB_WINDOW_BITS -15
115 
116 /*! \brief Memory usage for DEFLATE algorithm
117  *
118  * Speed vs. memory usage tradeoff for zlib (integer value from 1 to 9)
119  * <br>
120  * 1: Minimum memory usage for minimum speed
121  * <br>
122  * 9: Maximum memory usage for maximum speed
123  */
124 # define CMPR_ZLIB_MEM_LEVEL 9
125 
126 
127 # endif /* CFG_USE_ZLIB */
128 
129 
130 /* ========================================================================== */
131 /* Variables */
132 
133 # if CMPR_DEBUG
134 static size_t tx_u = 0;
135 static size_t tx_c = 0;
136 static size_t rx_u = 0;
137 static size_t rx_c = 0;
138 # endif /* CMPR_DEBUG */
139 
140 
141 # if CFG_USE_ZLIB
142 
143 
144 /* ========================================================================== */
145 /* Memory manager for zlib (allocation)
146  *
147  * \param[in] opaque Ignored
148  * \param[in] items Number of items
149  * \param[in] size Size of item
150  *
151  * This function allocates \e items * \e size bytes of memory.
152  *
153  * \return
154  * - Pointer to allocated data block on success
155  * - \c Z_NULL on error
156  */
157 
158 static voidpf cmpr_zlib_alloc(voidpf opaque, uInt items, uInt size)
159 {
160  voidpf res = Z_NULL;
161  void* rv;
162  size_t len = (size_t) items * (size_t) size;
163 
164  (void) opaque;
165  rv = api_posix_malloc(len);
166  if(NULL != rv) { res = (voidpf) rv; }
167 
168  return(res);
169 }
170 
171 
172 /* ========================================================================== */
173 /* Memory manager for zlib (release)
174  *
175  * \param[in] opaque Ignored
176  * \param[in] address Address of memory block to release
177  */
178 
179 static void cmpr_zlib_free(voidpf opaque, voidpf address)
180 {
181  (void) opaque;
182  api_posix_free((void*) address);
183 
184  return;
185 }
186 
187 
188 # endif /* CFG_USE_ZLIB */
189 
190 
191 /* ========================================================================== */
192 /*! \brief Send data
193  *
194  * \param[in] stream Pointer to stream object pointer
195  * \param[in] buf Pointer to data buffer
196  * \param[in] len Number of octets to send
197  * \param[in] flush Flush TX direction (use \c COMPR_FLUSH_xxx constants)
198  *
199  * \return
200  * - Number of bytes sent
201  * - -1 on error
202  */
203 
204 static api_posix_ssize_t cmpr_send_i(void* stream, const void* buf,
205  size_t len, int flush)
206 {
207  struct cmpr_stream* s = (struct cmpr_stream*) stream;
208  api_posix_ssize_t res = -1;
209 # if CFG_USE_ZLIB
210  z_streamp p;
211  int rv;
212  api_posix_ssize_t rv2;
213  size_t i;
214  size_t len2;
215  int zflush;
216 # endif /* CFG_USE_ZLIB */
217 
218  /* Check stream */
219  if(NULL == stream)
220  {
221  PRINT_ERROR("cmpr_send(): Invalid pointer to stream object");
222  }
223  /* Check size */
224  else if(INT_MAX < len)
225  {
226  PRINT_ERROR("cmpr_send(): Data length too large");
227  }
228  else if(!len && CMPR_FLUSH_NO == flush)
229  {
230  /* NOP and no error */
231  res = 0;
232  }
233  else
234  {
235  res = 0;
236  /* Clamp data length to buffer size */
237  if(CMPR_BUFSIZE < len) { len = CMPR_BUFSIZE; }
238  /* Compress data */
239  switch(s->alg)
240  {
241 # if CFG_USE_ZLIB
242  case CMPR_ALG_DEFLATE:
243  {
244  p = (z_streamp) s->tx;
245  while(!res)
246  {
247  /* Check whether TX input buffer is empty */
248  if(!p->avail_in)
249  {
250  /* Yes => Feed TX buffer with uncompressed data */
251  memcpy((void*) s->tx_buf_in, buf, len);
252  p->next_in = (Bytef*) s->tx_buf_in;
253  p->avail_in = (uInt) len;
254  res = (api_posix_ssize_t) len;
255  }
256  /* Check whether TX output buffer is full */
257  if(p->avail_out)
258  {
259  /* No => Drive compression engine */
260  zflush = Z_NO_FLUSH;
261  if(CMPR_FLUSH_NO != flush)
262  {
263  if(CMPR_FLUSH_END != flush) { zflush = Z_PARTIAL_FLUSH; }
264  else { zflush = Z_FINISH; }
265  }
266  rv = deflate(p, zflush);
267  switch(rv)
268  {
269  case Z_OK:
270  case Z_BUF_ERROR:
271  {
272  break;
273  }
274  case Z_STREAM_END:
275  {
276  if(CMPR_FLUSH_END != flush) { res = -1; }
277  break;
278  }
279  case Z_STREAM_ERROR:
280  {
281  PRINT_ERROR("cmpr_send(): "
282  "Stream object corrupted");
283  /* No break here is intended */
284  }
285  /* FALLTHROUGH */
286  default:
287  {
288  /* Fatal error */
289  res = -1;
290  break;
291  }
292  }
293  }
294  /* Write TX output buffer to underlaying protocol */
295  if(!res && (uInt) CMPR_BUFSIZE > p->avail_out)
296  {
297  len2 = CMPR_BUFSIZE - (size_t) p->avail_out;
298 # if CMPR_DEBUG
299  printf("%sSend %u compressed bytes\n",
300  MAIN_ERR_PREFIX, (unsigned int) len2);
301  tx_c += len2;
302 # endif /* CMPR_DEBUG */
303  i = 0;
304  while(!res && len2 > i)
305  {
306  do
307  {
308  /* Use function registered by stream constructor */
309  rv2 = (*s->tx_send)(s->sd,
310  &s->tx_buf_out[i], len2 - i, 0);
311  }
312  while( (api_posix_ssize_t) -1 == rv2
313  && API_POSIX_EINTR == api_posix_errno );
314  if((api_posix_ssize_t) -1 == rv2)
315  {
316  PRINT_ERROR("cmpr_send(): Writing data "
317  "to underlaying protocol failed");
318  res = -1;
319  break;
320  }
321  i += (size_t) rv2;
322  }
323  p->next_out = (Bytef*) s->tx_buf_out;
324  p->avail_out = (uInt) CMPR_BUFSIZE;
325  }
326  /* Check whether flush is finished */
327  if(CMPR_FLUSH_NO != flush)
328  {
329  if(!p->avail_in && (uInt) CMPR_BUFSIZE == p->avail_out)
330  {
331  /* No more data to compress and all data flushed */
332  break;
333  }
334  }
335  }
336  break;
337  }
338 # endif /* CFG_USE_ZLIB */
339  default:
340  {
341  /* Compression algorithm not supported */
342  PRINT_ERROR("cmpr_send(): "
343  "Compression algorithm not supported");
344  break;
345  }
346  }
347  }
348 
349  return(res);
350 }
351 
352 
353 /* ========================================================================== */
354 /*! \brief Send data
355  *
356  * \param[in] stream Pointer to stream object pointer
357  * \param[in] buf Pointer to data buffer
358  * \param[in] len Number of octets to send
359  *
360  * \return
361  * - Number of bytes sent
362  * - -1 on error
363  */
364 
365 api_posix_ssize_t cmpr_send(void* stream, const void* buf, size_t len)
366 {
367 # if CMPR_DEBUG
368  printf("%s--- TX ------------------------\n", MAIN_ERR_PREFIX);
369  printf("%sAccepted %u uncompressed bytes\n", MAIN_ERR_PREFIX,
370  (unsigned int) len);
371  tx_u += len;
372 # endif /* CMPR_DEBUG */
373  return(cmpr_send_i(stream, buf, len, CMPR_FLUSH_NO));
374 }
375 
376 
377 /* ========================================================================== */
378 /*! \brief Flush TX direction
379  *
380  * \param[in] stream Pointer to stream object pointer
381  *
382  * \return
383  * - 0 on success
384  * - -1 on error
385  */
386 
387 int cmpr_flush(void* stream)
388 {
389  int res = -1;
390  char buf = 0;
391  api_posix_ssize_t rv;
392 
393 # if CMPR_DEBUG
394  printf("%sFlush requested\n", MAIN_ERR_PREFIX);
395 # endif /* CMPR_DEBUG */
396  rv = cmpr_send_i(stream, (void*) &buf, (size_t) 0, CMPR_FLUSH_YES);
397  if(0 <= rv) { res = 0; }
398 
399  return(res);
400 }
401 
402 
403 /* ========================================================================== */
404 /*! \brief Flush TX direction and terminate data stream
405  *
406  * \param[in] stream Pointer to stream object pointer
407  *
408  * \return
409  * - 0 on success
410  * - -1 on error
411  */
412 
413 int cmpr_terminate(void* stream)
414 {
415  int res = -1;
416  char buf = 0;
417  api_posix_ssize_t rv;
418 
419 # if CMPR_DEBUG
420  printf("%sTerminate requested\n", MAIN_ERR_PREFIX);
421 # endif /* CMPR_DEBUG */
422  rv = cmpr_send_i(stream, (void*) &buf, (size_t) 0, CMPR_FLUSH_END);
423  if(0 <= rv) { res = 0; }
424 
425  return(res);
426 }
427 
428 
429 /* ========================================================================== */
430 /*! \brief Receive data
431  *
432  * \param[in] stream Pointer to stream object pointer
433  * \param[out] buf Pointer to data buffer
434  * \param[in] len Number of octets to receive
435  * \param[in] peek Data should stay available for reading if nonzero
436  *
437  * \attention
438  * A nonzero value must be used for the \e len parameter!
439  *
440  * \return
441  * - Number of bytes received
442  * - 0 if underlaying protocol lost connection
443  * - -1 on error
444  */
445 
446 api_posix_ssize_t cmpr_recv(void* stream, void* buf, size_t len, int peek)
447 {
448  struct cmpr_stream* s = (struct cmpr_stream*) stream;
449  api_posix_ssize_t res = -1;
450 # if CFG_USE_ZLIB
451  z_streamp p;
452  int rv;
453  api_posix_ssize_t rv2;
454  size_t len2;
455  size_t remain;
456 # endif /* CFG_USE_ZLIB */
457 
458  /* Check stream */
459  if(NULL == stream)
460  {
461  PRINT_ERROR("cmpr_recv(): Invalid pointer to stream object");
462  }
463  /* Check size */
464  else if(INT_MAX < len)
465  {
466  PRINT_ERROR("cmpr_recv(): Data length too large");
467  }
468  else if(!len)
469  {
470  PRINT_ERROR("cmpr_recv(): Zero data length not supported");
471  }
472  else
473  {
474  res = 0;
475  if(len)
476  {
477  /* Compress data */
478  switch(s->alg)
479  {
480 # if CFG_USE_ZLIB
481  case CMPR_ALG_DEFLATE:
482  {
483  p = (z_streamp) s->rx;
484  while(!res)
485  {
486  /* Check whether RX output buffer is full */
487  if(p->avail_out)
488  {
489  /* No => Drive decompression engine */
490  rv = inflate(p, Z_SYNC_FLUSH);
491  switch(rv)
492  {
493  case Z_OK:
494  case Z_BUF_ERROR:
495  {
496  break;
497  }
498  case Z_DATA_ERROR:
499  case Z_STREAM_ERROR:
500  {
501  PRINT_ERROR("cmpr_recv(): Data or"
502  "stream object corrupted");
503  /* No break here is intended */
504  }
505  /* FALLTHROUGH */
506  case Z_NEED_DICT:
507  case Z_MEM_ERROR:
508  default:
509  {
510  /* Fatal error */
511  res = -1;
512  break;
513  }
514  }
515  }
516  /* Check whether RX output buffer contains data */
517  if(!res && (uInt) CMPR_BUFSIZE > p->avail_out)
518  {
519  /* Yes => Decompressed data in RX output buffer present */
520  len2 = CMPR_BUFSIZE - (size_t) p->avail_out;
521  if(len < len2)
522  {
523  remain = len2 - len;
524  len2 = len;
525  }
526  else { remain = 0; }
527  memcpy(buf, (void*) s->rx_buf_out, len2);
528  if(!peek)
529  {
530 # if CMPR_DEBUG
531  printf("%sProviding %u uncompressed bytes\n",
532  MAIN_ERR_PREFIX, (unsigned int) len);
533  rx_u += len2;
534 # endif /* CMPR_DEBUG */
535  /* Consume data (remove it from RX output buffer) */
536  if(remain)
537  {
538  memmove((void*) s->rx_buf_out,
539  (void*) &s->rx_buf_out[len2], remain);
540  p->next_out = (Bytef*) &s->rx_buf_out[remain];
541  p->avail_out = (uInt) CMPR_BUFSIZE - (uInt) remain;
542  }
543  else
544  {
545  p->next_out = (Bytef*) s->rx_buf_out;
546  p->avail_out = (uInt) CMPR_BUFSIZE;
547  }
548  }
549  res = (api_posix_ssize_t) len2;
550  }
551  /* Check whether RX input buffer is empty */
552  if(!res && !p->avail_in)
553  {
554  /* Yes => Read from underlaying proto to RX input buffer */
555  /* Do this last to avoid blocking */
556  len2 = CMPR_BUFSIZE;
557  do
558  {
559  /* Use function registered by stream constructor */
560  rv2 = (*s->rx_recv)(s->sd, s->rx_buf_in, len2, 0);
561  }
562  while( (api_posix_ssize_t) -1 == rv2
563  && API_POSIX_EINTR == api_posix_errno );
564  if((api_posix_ssize_t) -1 == rv2)
565  {
566  PRINT_ERROR("cmpr_recv(): Reading data "
567  "from underlaying protocol failed");
568  res = -1;
569  break;
570  }
571 # if CMPR_DEBUG
572  printf("%s--- RX ------------------------\n");
573  printf("%sReceived %d compressed bytes\n",
574  MAIN_ERR_PREFIX, (int) rv2);
575  rx_c += (size_t) rv2;
576 # endif /* CMPR_DEBUG */
577  p->next_in = (Bytef*) s->rx_buf_in;
578  p->avail_in = (uInt) rv2;
579  /* Check for terminated connection */
580  if(!rv2) { break; }
581  }
582  }
583  break;
584  }
585 # endif /* CFG_USE_ZLIB */
586  default:
587  {
588  /* Compression algorithm not supported */
589  PRINT_ERROR("cmpr_recv(): "
590  "Compression algorithm not supported");
591  break;
592  }
593  }
594  }
595  }
596 
597  return(res);
598 }
599 
600 
601 /* ========================================================================== */
602 /*! \brief Compressed data stream object constructor
603  *
604  * \param[in] alg Compression algorithm (use \c CMPR_ALG_xxx constants)
605  * \param[in] sd Socket descriptor or stream handle of undelaying protocol
606  * \param[in] tx_send Send function to underlaying protocol
607  * \param[in] rx_recv Receive function for underlaying protocol
608  *
609  * \attention
610  * The functions to access the undelaying protocol \e tx_send() and \e rx_recv()
611  * are expected to behave like \c send() and \c recv() defined by POSIX.1-2001
612  * with compatibility to the 4.2BSD implementation regarding flags).
613  *
614  * \return
615  * - Pointer to constructed object on success
616  * - \c NULL on error
617  */
618 
619 struct cmpr_stream* cmpr_stream_constructor( unsigned int alg, int sd,
620  ssize_t (*tx_send)(int, const void*, size_t, int),
621  ssize_t (*rx_recv)(int, void*, size_t, int) )
622 {
623  struct cmpr_stream* res = NULL;
624  int error = 0;
625 # if CFG_USE_ZLIB
626  int rv;
627  z_streamp p;
628 # endif /* CFG_USE_ZLIB */
629 
630  /* Allocate and initialize data stream object */
631  res = (struct cmpr_stream*) api_posix_malloc(sizeof(struct cmpr_stream));
632  if(NULL == res) { error = 1; }
633  else
634  {
635  res->alg = alg;
636  res->sd = sd;
637  res->tx_send = tx_send;
638  res->rx_recv = rx_recv;
639  res->tx_buf_in = NULL;
640  res->tx_buf_out = NULL;
641  res->rx_buf_in = NULL;
642  res->rx_buf_out = NULL;
643  res->tx = NULL;
644  res->rx = NULL;
645  }
646 
647  /* Check parameters to access underlaying protocol */
648  if(!error)
649  {
650  if(0 > sd || NULL == res->tx_send || NULL == res->rx_recv)
651  {
652  PRINT_ERROR("Invalid parameters to access underlaying protocol");
653  error = 1;
654  }
655  }
656 
657  /* Allocate data buffers */
658  if(!error)
659  {
660  res->tx_buf_in = (char*) api_posix_malloc(CMPR_BUFSIZE);
661  res->tx_buf_out = (char*) api_posix_malloc(CMPR_BUFSIZE);
662  res->rx_buf_in = (char*) api_posix_malloc(CMPR_BUFSIZE);
663  res->rx_buf_out = (char*) api_posix_malloc(CMPR_BUFSIZE);
664  if(NULL == res->tx_buf_in || NULL == res->tx_buf_out
665  || NULL == res->rx_buf_in || NULL == res->rx_buf_out)
666  {
667  PRINT_ERROR("Memory allocation for data buffers failed");
668  error = 1;
669  }
670  }
671 
672  /* Allocate and initialize algorithm specific objects */
673  if(!error)
674  {
675  switch(alg)
676  {
677 # if CFG_USE_ZLIB
678  case CMPR_ALG_DEFLATE:
679  {
680  res->tx = api_posix_malloc(sizeof(z_stream));
681  res->rx = api_posix_malloc(sizeof(z_stream));
682  if(NULL == res->tx || NULL == res->rx)
683  {
684  PRINT_ERROR("Memory allocation for zlib streams failed");
685  error = 1;
686  }
687  else
688  {
689  /* Init zlib stream for TX direction (compression) */
690  p = (z_streamp) res->tx;
691  p->zalloc = cmpr_zlib_alloc;
692  p->zfree = cmpr_zlib_free;
693  p->opaque = NULL;
694  p->next_in = (Bytef*) res->tx_buf_in;
695  p->avail_in = (uInt) 0;
696  rv = deflateInit2(p, Z_BEST_COMPRESSION, Z_DEFLATED,
698  Z_DEFAULT_STRATEGY);
699  if(Z_OK != rv) { error = 1; }
700  else
701  {
702  p->next_out = (Bytef*) res->tx_buf_out;
703  p->avail_out = (uInt) CMPR_BUFSIZE;
704 
705  /* Init zlib stream for RX direction (decompression) */
706  p = (z_streamp) res->rx;
707  p->zalloc = cmpr_zlib_alloc;
708  p->zfree = cmpr_zlib_free;
709  p->opaque = NULL;
710  p->next_in = (Bytef*) res->rx_buf_in;
711  p->avail_in = (uInt) 0;
712  rv = inflateInit2(p, CMPR_ZLIB_WINDOW_BITS);
713  if(Z_OK != rv)
714  {
715  deflateEnd(p); /* Destroy zlib stream for TX */
716  error = 1;
717  }
718  else
719  {
720  p->next_out = (Bytef*) res->rx_buf_out;
721  p->avail_out = (uInt) CMPR_BUFSIZE;
722  }
723  }
724  }
725  if(error)
726  {
727  PRINT_ERROR("Initialization of zlib streams failed");
728  }
729  break;
730  }
731 # endif /* CFG_USE_ZLIB */
732  default:
733  {
734  /* Compression algorithm not supported */
735  PRINT_ERROR("Compression algorithm not supported");
736  error = 1;
737  break;
738  }
739  }
740  }
741 
742  /* Check for error */
743  if(error)
744  {
745  if(NULL != res)
746  {
747  api_posix_free((void*) res->tx);
748  api_posix_free((void*) res->rx);
749  api_posix_free((void*) res->tx_buf_in);
750  api_posix_free((void*) res->tx_buf_out);
751  api_posix_free((void*) res->rx_buf_in);
752  api_posix_free((void*) res->rx_buf_out);
753  api_posix_free((void*) res);
754  res = NULL;
755  }
756  }
757 
758  return((void*) res);
759 }
760 
761 
762 /* ========================================================================== */
763 /*! \brief Destroy compressed data stream object allocated by compression module
764  *
765  * \param[in] stream Pointer to object
766  *
767  * \note
768  * The pointer \e p is allowed to be \c NULL and no operation is performed in
769  * this case.
770  */
771 
772 void cmpr_stream_destructor(void* stream)
773 {
774  struct cmpr_stream* s = (struct cmpr_stream*) stream;
775 # if CFG_USE_ZLIB
776  z_streamp p;
777  int error = 0;
778  int rv;
779 # endif /* CFG_USE_ZLIB */
780 
781  if(NULL != s)
782  {
783  /* Destroy algorithm specific objects */
784  switch(s->alg)
785  {
786 # if CFG_USE_ZLIB
787  case CMPR_ALG_DEFLATE:
788  {
789  /* Destory zlib stream objects */
790  p = (z_streamp) s->rx;
791  rv = inflateEnd(p);
792  if(Z_OK != rv) { error = 1; }
793  p = (z_streamp) s->tx;
794  rv = deflateEnd(p);
795  if(Z_OK != rv && Z_DATA_ERROR != rv) { error = 1; }
796  if(error) { PRINT_ERROR("Destroying zlib streams failed"); }
797  break;
798  }
799 # endif /* CFG_USE_ZLIB */
800  default:
801  {
802  /* Compression algorithm not supported */
803  PRINT_ERROR("Compression algorithm not supported");
804  break;
805  }
806  }
807  api_posix_free((void*) s->rx);
808  api_posix_free((void*) s->tx);
809 
810  /* Free data buffers */
811  api_posix_free((void*) s->rx_buf_out);
812  api_posix_free((void*) s->rx_buf_in);
813  api_posix_free((void*) s->tx_buf_out);
814  api_posix_free((void*) s->tx_buf_in);
815 
816  /* Free stream object */
817  api_posix_free(stream);
818  }
819 }
820 
821 
822 /* ========================================================================== */
823 /*! \brief Initialize compression module */
824 
825 int cmpr_init(void)
826 {
827  int res = 0;
828 # if CFG_USE_ZLIB
829  const char* ver;
830  int minor_c = 0;
831  int minor_r = 0;
832  int rv1, rv2;
833 
834  /* Check version of zlib library */
835  ver = zlibVersion();
836  printf("%s: %szlib library version: %s\n", CFG_NAME, MAIN_ERR_PREFIX, ver);
837  if(ZLIB_VERSION[0] != ver[0])
838  {
839  PRINT_ERROR("zlib library has incompatible ABI");
840  res = -1;
841  }
842  else
843  {
844  rv1 = sscanf(ZLIB_VERSION, "%*d.%d", &minor_c);
845  rv2 = sscanf(ver, "%*d.%d", &minor_r);
846  if(1 != rv1 || 1 != rv2)
847  {
848  PRINT_ERROR("Parsing zlib version string failed");
849  }
850  else if(minor_r < minor_c)
851  {
852  printf("%s: %sWarning: Compiled for a newer zlib minor version "
853  "(%s) \n", CFG_NAME, MAIN_ERR_PREFIX, ZLIB_VERSION);
854  }
855  }
856 
857  /* Print RX window size */
858  if(!res)
859  {
860  printf("%s: %sDEFLATE: Using RX window size: %d bytes\n", CFG_NAME,
862  }
863 # else /* CFG_USE_ZLIB */
864  PRINT_ERROR("Compiled without zlib support");
865 # endif /* CFG_USE_ZLIB */
866 
867  return(res);
868 }
869 
870 
871 /* ========================================================================== */
872 /*! \brief Shutdown compress module */
873 
874 void cmpr_exit(void)
875 {
876 # if CMPR_DEBUG
877  unsigned long int tx_ul = (unsigned long int) tx_u;
878  unsigned long int tx_cl = (unsigned long int) tx_c;
879  unsigned long int rx_cl = (unsigned long int) rx_c;
880  unsigned long int rx_ul = (unsigned long int) rx_u;
881  double tx_r = (double) tx_c / (double) tx_u;
882  double rx_r = (double) rx_c / (double) rx_u;
883 
884  printf("%s--- Statistics ----------------\n", MAIN_ERR_PREFIX);
885  printf("%sUncompressed TX bytes accepted: %lu\n", MAIN_ERR_PREFIX, tx_ul);
886  printf("%sCompressed TX bytes sent : %lu\n", MAIN_ERR_PREFIX, tx_cl);
887  printf("%sCompressed RX bytes received : %lu\n", MAIN_ERR_PREFIX, rx_cl);
888  printf("%sUncompressed RX bytes provided: %lu\n", MAIN_ERR_PREFIX, rx_ul);
889  if(tx_u)
890  {
891  printf("%sTX compression ratio: %.2f\n", MAIN_ERR_PREFIX, tx_r);
892  }
893  if(rx_u)
894  {
895  printf("%sRX compression ratio: %.2f\n", MAIN_ERR_PREFIX, rx_r);
896  }
897 # endif /* CMPR_DEBUG */
898 
899  return;
900 }
901 
902 
903 #endif /* !CFG_CMPR_DISABLE */
904 
905 
906 /*! @} */
907 
908 /* EOF */
CMPR_ZLIB_MEM_LEVEL
#define CMPR_ZLIB_MEM_LEVEL
Memory usage for DEFLATE algorithm.
Definition: compression.c:124
cmpr_terminate
int cmpr_terminate(void *stream)
Flush TX direction and terminate data stream.
Definition: compression.c:413
cmpr_flush
int cmpr_flush(void *stream)
Flush TX direction.
Definition: compression.c:387
cmpr_send
api_posix_ssize_t cmpr_send(void *stream, const void *buf, size_t len)
Send data.
Definition: compression.c:365
CMPR_ZLIB_WINDOW_BITS
#define CMPR_ZLIB_WINDOW_BITS
Window size for DEFLATE algorithm.
Definition: compression.c:114
cmpr_exit
void cmpr_exit(void)
Shutdown compress module.
Definition: compression.c:874
cmpr_init
int cmpr_init(void)
Initialize compression module.
Definition: compression.c:825
cmpr_stream_destructor
void cmpr_stream_destructor(void *stream)
Destroy compressed data stream object allocated by compression module.
Definition: compression.c:772
PRINT_ERROR
#define PRINT_ERROR(s)
Prepend module prefix and print error message.
Definition: main.h:19
CMPR_BUFSIZE
#define CMPR_BUFSIZE
Size of internal data buffers.
Definition: compression.c:94
MAIN_ERR_PREFIX
#define MAIN_ERR_PREFIX
Message prefix for COMPRESSION module.
Definition: compression.c:51
cmpr_stream_constructor
struct cmpr_stream * cmpr_stream_constructor(unsigned int alg, int sd, ssize_t(*tx_send)(int, const void *, size_t, int), ssize_t(*rx_recv)(int, void *, size_t, int))
Compressed data stream object constructor.
Definition: compression.c:619
CMPR_ALG_DEFLATE
#define CMPR_ALG_DEFLATE
DEFLATE according to RFC 1951.
Definition: compression.h:23
CMPR_DEBUG
#define CMPR_DEBUG
Print debug messages to stdout if nonzero.
Definition: compression.c:76
cmpr_recv
api_posix_ssize_t cmpr_recv(void *stream, void *buf, size_t len, int peek)
Receive data.
Definition: compression.c:446

Generated at 2026-01-27 using  doxygen