compression.c
Go to the documentation of this file.
1 /* ========================================================================== */
2 /*! \file
3  * \brief Data compression and decompression
4  *
5  * Copyright (c) 2015-2020 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  rv = posix_malloc(len);
165  if(NULL != rv) { res = (voidpf) rv; }
166 
167  return(res);
168 }
169 
170 
171 /* ========================================================================== */
172 /* Memory manager for zlib (release)
173  *
174  * \param[in] opaque Ignored
175  * \param[in] address Address of memory block to release
176  */
177 
178 static void cmpr_zlib_free(voidpf opaque, voidpf address)
179 {
180  posix_free((void*) address);
181 
182  return;
183 }
184 
185 
186 # endif /* CFG_USE_ZLIB */
187 
188 
189 /* ========================================================================== */
190 /*! \brief Send data
191  *
192  * \param[in] stream Pointer to stream object pointer
193  * \param[in] buf Pointer to data buffer
194  * \param[in] len Number of octets to send
195  * \param[in] flush Flush TX direction (use \c COMPR_FLUSH_xxx constants)
196  *
197  * \return
198  * - Number of bytes sent
199  * - -1 on error
200  */
201 
202 static posix_ssize_t cmpr_send_i(void* stream, const void* buf, size_t len,
203  int flush)
204 {
205  struct cmpr_stream* s = (struct cmpr_stream*) stream;
206  posix_ssize_t res = -1;
207 # if CFG_USE_ZLIB
208  z_streamp p;
209  int rv;
210  posix_ssize_t rv2;
211  size_t i;
212  size_t len2;
213  int zflush;
214 # endif /* CFG_USE_ZLIB */
215 
216  /* Check stream */
217  if(NULL == stream)
218  {
219  PRINT_ERROR("cmpr_send(): Invalid pointer to stream object");
220  }
221  /* Check size */
222  else if(INT_MAX < len)
223  {
224  PRINT_ERROR("cmpr_send(): Data length too large");
225  }
226  else if(!len && CMPR_FLUSH_NO == flush)
227  {
228  /* NOP and no error */
229  res = 0;
230  }
231  else
232  {
233  res = 0;
234  /* Clamp data length to buffer size */
235  if(CMPR_BUFSIZE < len) { len = CMPR_BUFSIZE; }
236  /* Compress data */
237  switch(s->alg)
238  {
239 # if CFG_USE_ZLIB
240  case CMPR_ALG_DEFLATE:
241  {
242  p = (z_streamp) s->tx;
243  while(!res)
244  {
245  /* Check whether TX input buffer is empty */
246  if(!p->avail_in)
247  {
248  /* Yes => Feed TX buffer with uncompressed data */
249  memcpy((void*) s->tx_buf_in, buf, len);
250  p->next_in = (Bytef*) s->tx_buf_in;
251  p->avail_in = (uInt) len;
252  res = (posix_ssize_t) len;
253  }
254  /* Check whether TX output buffer is full */
255  if(p->avail_out)
256  {
257  /* No => Drive compression engine */
258  zflush = Z_NO_FLUSH;
259  if(CMPR_FLUSH_NO != flush)
260  {
261  if(CMPR_FLUSH_END != flush) { zflush = Z_PARTIAL_FLUSH; }
262  else { zflush = Z_FINISH; }
263  }
264  rv = deflate(p, zflush);
265  switch(rv)
266  {
267  case Z_OK:
268  case Z_BUF_ERROR:
269  {
270  break;
271  }
272  case Z_STREAM_END:
273  {
274  if(CMPR_FLUSH_END != flush) { res = -1; }
275  break;
276  }
277  case Z_STREAM_ERROR:
278  {
279  PRINT_ERROR("cmpr_send(): "
280  "Stream object corrupted");
281  /* No break here is intended */
282  }
283  default:
284  {
285  /* Fatal error */
286  res = -1;
287  break;
288  }
289  }
290  }
291  /* Write TX output buffer to underlaying protocol */
292  if(!res && (uInt) CMPR_BUFSIZE > p->avail_out)
293  {
294  len2 = CMPR_BUFSIZE - (size_t) p->avail_out;
295 # if CMPR_DEBUG
296  printf("%sSend %u compressed bytes\n",
297  MAIN_ERR_PREFIX, (unsigned int) len2);
298  tx_c += len2;
299 # endif /* CMPR_DEBUG */
300  i = 0;
301  while(!res && len2 > i)
302  {
303  do
304  {
305  /* Use function registered by stream constructor */
306  rv2 = (*s->tx_send)(s->sd,
307  &s->tx_buf_out[i], len2 - i, 0);
308  }
309  while( (posix_ssize_t) -1 == rv2
310  && POSIX_EINTR == posix_errno );
311  if((posix_ssize_t) -1 == rv2)
312  {
313  PRINT_ERROR("cmpr_send(): Writing data "
314  "to underlaying protocol failed");
315  res = -1;
316  break;
317  }
318  i += (size_t) rv2;
319  }
320  p->next_out = (Bytef*) s->tx_buf_out;
321  p->avail_out = (uInt) CMPR_BUFSIZE;
322  }
323  /* Check whether flush is finished */
324  if(CMPR_FLUSH_NO != flush)
325  {
326  if(!p->avail_in && (uInt) CMPR_BUFSIZE == p->avail_out)
327  {
328  /* No more data to compress and all data flushed */
329  break;
330  }
331  }
332  }
333  break;
334  }
335 # endif /* CFG_USE_ZLIB */
336  default:
337  {
338  /* Compression algorithm not supported */
339  PRINT_ERROR("cmpr_send(): "
340  "Compression algorithm not supported");
341  break;
342  }
343  }
344  }
345 
346  return(res);
347 }
348 
349 
350 /* ========================================================================== */
351 /*! \brief Send data
352  *
353  * \param[in] stream Pointer to stream object pointer
354  * \param[in] buf Pointer to data buffer
355  * \param[in] len Number of octets to send
356  *
357  * \return
358  * - Number of bytes sent
359  * - -1 on error
360  */
361 
362 posix_ssize_t cmpr_send(void* stream, const void* buf, size_t len)
363 {
364 # if CMPR_DEBUG
365  printf("%s--- TX ------------------------\n", MAIN_ERR_PREFIX);
366  printf("%sAccepted %u uncompressed bytes\n", MAIN_ERR_PREFIX,
367  (unsigned int) len);
368  tx_u += len;
369 # endif /* CMPR_DEBUG */
370  return(cmpr_send_i(stream, buf, len, CMPR_FLUSH_NO));
371 }
372 
373 
374 /* ========================================================================== */
375 /*! \brief Flush TX direction
376  *
377  * \param[in] stream Pointer to stream object pointer
378  *
379  * \return
380  * - 0 on success
381  * - -1 on error
382  */
383 
384 int cmpr_flush(void* stream)
385 {
386  int res = -1;
387  char buf = 0;
388  posix_ssize_t rv;
389 
390 # if CMPR_DEBUG
391  printf("%sFlush requested\n", MAIN_ERR_PREFIX);
392 # endif /* CMPR_DEBUG */
393  rv = cmpr_send_i(stream, (void*) &buf, (size_t) 0, CMPR_FLUSH_YES);
394  if(0 <= rv) { res = 0; }
395 
396  return(res);
397 }
398 
399 
400 /* ========================================================================== */
401 /*! \brief Flush TX direction and terminate data stream
402  *
403  * \param[in] stream Pointer to stream object pointer
404  *
405  * \return
406  * - 0 on success
407  * - -1 on error
408  */
409 
410 int cmpr_terminate(void* stream)
411 {
412  int res = -1;
413  char buf = 0;
414  posix_ssize_t rv;
415 
416 # if CMPR_DEBUG
417  printf("%sTerminate requested\n", MAIN_ERR_PREFIX);
418 # endif /* CMPR_DEBUG */
419  rv = cmpr_send_i(stream, (void*) &buf, (size_t) 0, CMPR_FLUSH_END);
420  if(0 <= rv) { res = 0; }
421 
422  return(res);
423 }
424 
425 
426 /* ========================================================================== */
427 /*! \brief Receive data
428  *
429  * \param[in] stream Pointer to stream object pointer
430  * \param[out] buf Pointer to data buffer
431  * \param[in] len Number of octets to receive
432  * \param[in] peek Data should stay available for reading if nonzero
433  *
434  * \attention
435  * A nonzero value must be used for the \e len parameter!
436  *
437  * \return
438  * - Number of bytes received
439  * - 0 if underlaying protocol lost connection
440  * - -1 on error
441  */
442 
443 posix_ssize_t cmpr_recv(void* stream, void* buf, size_t len, int peek)
444 {
445  struct cmpr_stream* s = (struct cmpr_stream*) stream;
446  posix_ssize_t res = -1;
447 # if CFG_USE_ZLIB
448  z_streamp p;
449  int rv;
450  posix_ssize_t rv2;
451  size_t len2;
452  size_t remain;
453 # endif /* CFG_USE_ZLIB */
454 
455  /* Check stream */
456  if(NULL == stream)
457  {
458  PRINT_ERROR("cmpr_recv(): Invalid pointer to stream object");
459  }
460  /* Check size */
461  else if(INT_MAX < len)
462  {
463  PRINT_ERROR("cmpr_recv(): Data length too large");
464  }
465  else if(!len)
466  {
467  PRINT_ERROR("cmpr_recv(): Zero data length not supported");
468  }
469  else
470  {
471  res = 0;
472  if(len)
473  {
474  /* Compress data */
475  switch(s->alg)
476  {
477 # if CFG_USE_ZLIB
478  case CMPR_ALG_DEFLATE:
479  {
480  p = (z_streamp) s->rx;
481  while(!res)
482  {
483  /* Check whether RX output buffer is full */
484  if(p->avail_out)
485  {
486  /* No => Drive decompression engine */
487  rv = inflate(p, Z_SYNC_FLUSH);
488  switch(rv)
489  {
490  case Z_OK:
491  case Z_BUF_ERROR:
492  {
493  break;
494  }
495  case Z_DATA_ERROR:
496  case Z_STREAM_ERROR:
497  {
498  PRINT_ERROR("cmpr_recv(): Data or"
499  "stream object corrupted");
500  /* No break here is intended */
501  }
502  case Z_NEED_DICT:
503  case Z_MEM_ERROR:
504  default:
505  {
506  /* Fatal error */
507  res = -1;
508  break;
509  }
510  }
511  }
512  /* Check whether RX output buffer contains data */
513  if(!res && (uInt) CMPR_BUFSIZE > p->avail_out)
514  {
515  /* Yes => Decompressed data in RX output buffer present */
516  len2 = CMPR_BUFSIZE - (size_t) p->avail_out;
517  if(len < len2)
518  {
519  remain = len2 - len;
520  len2 = len;
521  }
522  else { remain = 0; }
523  memcpy(buf, (void*) s->rx_buf_out, len2);
524  if(!peek)
525  {
526 # if CMPR_DEBUG
527  printf("%sProviding %u uncompressed bytes\n",
528  MAIN_ERR_PREFIX, (unsigned int) len);
529  rx_u += len2;
530 # endif /* CMPR_DEBUG */
531  /* Consume data (remove it from RX output buffer) */
532  if(remain)
533  {
534  memmove((void*) s->rx_buf_out,
535  (void*) &s->rx_buf_out[len2], remain);
536  p->next_out = (Bytef*) &s->rx_buf_out[remain];
537  p->avail_out = (uInt) CMPR_BUFSIZE - (uInt) remain;
538  }
539  else
540  {
541  p->next_out = (Bytef*) s->rx_buf_out;
542  p->avail_out = (uInt) CMPR_BUFSIZE;
543  }
544  }
545  res = (posix_ssize_t) len2;
546  }
547  /* Check whether RX input buffer is empty */
548  if(!res && !p->avail_in)
549  {
550  /* Yes => Read from underlaying proto to RX input buffer */
551  /* Do this last to avoid blocking */
552  len2 = CMPR_BUFSIZE;
553  do
554  {
555  /* Use function registered by stream constructor */
556  rv2 = (*s->rx_recv)(s->sd, s->rx_buf_in, len2, 0);
557  }
558  while( (posix_ssize_t) -1 == rv2
559  && POSIX_EINTR == posix_errno );
560  if((posix_ssize_t) -1 == rv2)
561  {
562  PRINT_ERROR("cmpr_recv(): Reading data "
563  "from underlaying protocol failed");
564  res = -1;
565  break;
566  }
567 # if CMPR_DEBUG
568  printf("%s--- RX ------------------------\n");
569  printf("%sReceived %d compressed bytes\n",
570  MAIN_ERR_PREFIX, (int) rv2);
571  rx_c += (size_t) rv2;
572 # endif /* CMPR_DEBUG */
573  p->next_in = (Bytef*) s->rx_buf_in;
574  p->avail_in = (uInt) rv2;
575  /* Check for terminated connection */
576  if(!rv2) { break; }
577  }
578  }
579  break;
580  }
581 # endif /* CFG_USE_ZLIB */
582  default:
583  {
584  /* Compression algorithm not supported */
585  PRINT_ERROR("cmpr_recv(): "
586  "Compression algorithm not supported");
587  break;
588  }
589  }
590  }
591  }
592 
593  return(res);
594 }
595 
596 
597 /* ========================================================================== */
598 /*! \brief Compressed data stream object constructor
599  *
600  * \param[in] alg Compression algorithm (use \c CMPR_ALG_xxx constants)
601  * \param[in] sd Socket descriptor or stream handle of undelaying protocol
602  * \param[in] tx_send Send function to underlaying protocol
603  * \param[in] rx_recv Receive function for underlaying protocol
604  *
605  * \attention
606  * The functions to access the undelaying protocol \e tx_send() and \e rx_recv()
607  * are expected to behave like \c send() and \c recv() defined by POSIX.1-2001
608  * with compatibility to the 4.2BSD implementation regarding flags).
609  *
610  * \return
611  * - Pointer to constructed object on success
612  * - \c NULL on error
613  */
614 
615 struct cmpr_stream* cmpr_stream_constructor( unsigned int alg, int sd,
616  ssize_t (*tx_send)(int, const void*, size_t, int),
617  ssize_t (*rx_recv)(int, void*, size_t, int) )
618 {
619  struct cmpr_stream* res = NULL;
620  int error = 0;
621 # if CFG_USE_ZLIB
622  int rv;
623  z_streamp p;
624 # endif /* CFG_USE_ZLIB */
625 
626  /* Allocate and initialize data stream object */
627  res = (struct cmpr_stream*) posix_malloc(sizeof(struct cmpr_stream));
628  if(NULL == res) { error = 1; }
629  else
630  {
631  res->alg = alg;
632  res->sd = sd;
633  res->tx_send = tx_send;
634  res->rx_recv = rx_recv;
635  res->tx_buf_in = NULL;
636  res->tx_buf_out = NULL;
637  res->rx_buf_in = NULL;
638  res->rx_buf_out = NULL;
639  res->tx = NULL;
640  res->rx = NULL;
641  }
642 
643  /* Check parameters to access underlaying protocol */
644  if(!error)
645  {
646  if(0 > sd || NULL == res->tx_send || NULL == res->rx_recv)
647  {
648  PRINT_ERROR("Invalid parameters to access underlaying protocol");
649  error = 1;
650  }
651  }
652 
653  /* Allocate data buffers */
654  if(!error)
655  {
656  res->tx_buf_in = (char*) posix_malloc(CMPR_BUFSIZE);
657  res->tx_buf_out = (char*) posix_malloc(CMPR_BUFSIZE);
658  res->rx_buf_in = (char*) posix_malloc(CMPR_BUFSIZE);
659  res->rx_buf_out = (char*) posix_malloc(CMPR_BUFSIZE);
660  if(NULL == res->tx_buf_in || NULL == res->tx_buf_out
661  || NULL == res->rx_buf_in || NULL == res->rx_buf_out)
662  {
663  PRINT_ERROR("Memory allocation for data buffers failed");
664  error = 1;
665  }
666  }
667 
668  /* Allocate and initialize algorithm specific objects */
669  if(!error)
670  {
671  switch(alg)
672  {
673 # if CFG_USE_ZLIB
674  case CMPR_ALG_DEFLATE:
675  {
676  res->tx = posix_malloc(sizeof(z_stream));
677  res->rx = posix_malloc(sizeof(z_stream));
678  if(NULL == res->tx || NULL == res->rx)
679  {
680  PRINT_ERROR("Memory allocation for zlib streams failed");
681  error = 1;
682  }
683  else
684  {
685  /* Init zlib stream for TX direction (compression) */
686  p = (z_streamp) res->tx;
687  p->zalloc = cmpr_zlib_alloc;
688  p->zfree = cmpr_zlib_free;
689  p->opaque = NULL;
690  p->next_in = (Bytef*) res->tx_buf_in;
691  p->avail_in = (uInt) 0;
692  rv = deflateInit2(p, Z_BEST_COMPRESSION, Z_DEFLATED,
694  Z_DEFAULT_STRATEGY);
695  if(Z_OK != rv) { error = 1; }
696  else
697  {
698  p->next_out = (Bytef*) res->tx_buf_out;
699  p->avail_out = (uInt) CMPR_BUFSIZE;
700 
701  /* Init zlib stream for RX direction (decompression) */
702  p = (z_streamp) res->rx;
703  p->zalloc = cmpr_zlib_alloc;
704  p->zfree = cmpr_zlib_free;
705  p->opaque = NULL;
706  p->next_in = (Bytef*) res->rx_buf_in;
707  p->avail_in = (uInt) 0;
708  rv = inflateInit2(p, CMPR_ZLIB_WINDOW_BITS);
709  if(Z_OK != rv)
710  {
711  deflateEnd(p); /* Destroy zlib stream for TX */
712  error = 1;
713  }
714  else
715  {
716  p->next_out = (Bytef*) res->rx_buf_out;
717  p->avail_out = (uInt) CMPR_BUFSIZE;
718  }
719  }
720  }
721  if(error)
722  {
723  PRINT_ERROR("Initialization of zlib streams failed");
724  }
725  break;
726  }
727 # endif /* CFG_USE_ZLIB */
728  default:
729  {
730  /* Compression algorithm not supported */
731  PRINT_ERROR("Compression algorithm not supported");
732  error = 1;
733  break;
734  }
735  }
736  }
737 
738  /* Check for error */
739  if(error)
740  {
741  if(NULL != res)
742  {
743  posix_free((void*) res->tx);
744  posix_free((void*) res->rx);
745  posix_free((void*) res->tx_buf_in);
746  posix_free((void*) res->tx_buf_out);
747  posix_free((void*) res->rx_buf_in);
748  posix_free((void*) res->rx_buf_out);
749  posix_free((void*) res);
750  res = NULL;
751  }
752  }
753 
754  return((void*) res);
755 }
756 
757 
758 /* ========================================================================== */
759 /*! \brief Destroy compressed data stream object allocated by compression module
760  *
761  * \param[in] stream Pointer to object
762  *
763  * \note
764  * The pointer \e p is allowed to be \c NULL and no operation is performed in
765  * this case.
766  */
767 
768 void cmpr_stream_destructor(void* stream)
769 {
770  struct cmpr_stream* s = (struct cmpr_stream*) stream;
771 # if CFG_USE_ZLIB
772  z_streamp p;
773  int error = 0;
774  int rv;
775 # endif /* CFG_USE_ZLIB */
776 
777  if(NULL != s)
778  {
779  /* Destroy algorithm specific objects */
780  switch(s->alg)
781  {
782 # if CFG_USE_ZLIB
783  case CMPR_ALG_DEFLATE:
784  {
785  /* Destory zlib stream objects */
786  p = (z_streamp) s->rx;
787  rv = inflateEnd(p);
788  if(Z_OK != rv) { error = 1; }
789  p = (z_streamp) s->tx;
790  rv = deflateEnd(p);
791  if(Z_OK != rv && Z_DATA_ERROR != rv) { error = 1; }
792  if(error) { PRINT_ERROR("Destroying zlib streams failed"); }
793  break;
794  }
795 # endif /* CFG_USE_ZLIB */
796  default:
797  {
798  /* Compression algorithm not supported */
799  PRINT_ERROR("Compression algorithm not supported");
800  break;
801  }
802  }
803  posix_free((void*) s->rx);
804  posix_free((void*) s->tx);
805 
806  /* Free data buffers */
807  posix_free((void*) s->rx_buf_out);
808  posix_free((void*) s->rx_buf_in);
809  posix_free((void*) s->tx_buf_out);
810  posix_free((void*) s->tx_buf_in);
811 
812  /* Free stream object */
813  posix_free(stream);
814  }
815 }
816 
817 
818 /* ========================================================================== */
819 /*! \brief Initialize compression module */
820 
821 int cmpr_init(void)
822 {
823  int res = 0;
824 # if CFG_USE_ZLIB
825  const char* ver;
826  int minor_c = 0;
827  int minor_r = 0;
828  int rv1, rv2;
829 
830  /* Check version of zlib library */
831  ver = zlibVersion();
832  printf("%s: %szlib library version: %s\n", CFG_NAME, MAIN_ERR_PREFIX, ver);
833  if(ZLIB_VERSION[0] != ver[0])
834  {
835  PRINT_ERROR("zlib library has incompatible ABI");
836  res = -1;
837  }
838  else
839  {
840  rv1 = sscanf(ZLIB_VERSION, "%*d.%d", &minor_c);
841  rv2 = sscanf(ver, "%*d.%d", &minor_r);
842  if(1 != rv1 || 1 != rv2)
843  {
844  PRINT_ERROR("Parsing zlib version string failed");
845  }
846  else if(minor_r < minor_c)
847  {
848  printf("%s: %sWarning: Compiled for a newer zlib minor version "
849  "(%s) \n", CFG_NAME, MAIN_ERR_PREFIX, ZLIB_VERSION);
850  }
851  }
852 
853  /* Print RX window size */
854  if(!res)
855  {
856  printf("%s: %sDEFLATE: Using RX window size: %d bytes\n", CFG_NAME,
858  }
859 # else /* CFG_USE_ZLIB */
860  PRINT_ERROR("Compiled without zlib support");
861 # endif /* CFG_USE_ZLIB */
862 
863  return(res);
864 }
865 
866 
867 /* ========================================================================== */
868 /*! \brief Shutdown compress module */
869 
870 void cmpr_exit(void)
871 {
872 # if CMPR_DEBUG
873  unsigned long int tx_ul = (unsigned long int) tx_u;
874  unsigned long int tx_cl = (unsigned long int) tx_c;
875  unsigned long int rx_cl = (unsigned long int) rx_c;
876  unsigned long int rx_ul = (unsigned long int) rx_u;
877  double tx_r = (double) tx_c / (double) tx_u;
878  double rx_r = (double) rx_c / (double) rx_u;
879 
880  printf("%s--- Statistics ----------------\n", MAIN_ERR_PREFIX);
881  printf("%sUncompressed TX bytes accepted: %lu\n", MAIN_ERR_PREFIX, tx_ul);
882  printf("%sCompressed TX bytes sent : %lu\n", MAIN_ERR_PREFIX, tx_cl);
883  printf("%sCompressed RX bytes received : %lu\n", MAIN_ERR_PREFIX, rx_cl);
884  printf("%sUncompressed RX bytes provided: %lu\n", MAIN_ERR_PREFIX, rx_ul);
885  if(tx_u)
886  {
887  printf("%sTX compression ratio: %.2f\n", MAIN_ERR_PREFIX, tx_r);
888  }
889  if(rx_u)
890  {
891  printf("%sRX compression ratio: %.2f\n", MAIN_ERR_PREFIX, rx_r);
892  }
893 # endif /* CMPR_DEBUG */
894 
895  return;
896 }
897 
898 
899 #endif /* !CFG_CMPR_DISABLE */
900 
901 
902 /*! @} */
903 
904 /* EOF */
cmpr_recv
posix_ssize_t cmpr_recv(void *stream, void *buf, size_t len, int peek)
Receive data.
Definition: compression.c:443
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:410
cmpr_flush
int cmpr_flush(void *stream)
Flush TX direction.
Definition: compression.c:384
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:870
cmpr_init
int cmpr_init(void)
Initialize compression module.
Definition: compression.c:821
cmpr_stream_destructor
void cmpr_stream_destructor(void *stream)
Destroy compressed data stream object allocated by compression module.
Definition: compression.c:768
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:615
CMPR_ALG_DEFLATE
#define CMPR_ALG_DEFLATE
DEFLATE according to RFC 1951.
Definition: compression.h:23
cmpr_send
posix_ssize_t cmpr_send(void *stream, const void *buf, size_t len)
Send data.
Definition: compression.c:362
CMPR_DEBUG
#define CMPR_DEBUG
Print debug messages to stdout if nonzero.
Definition: compression.c:76

Generated at 2024-04-27 using  doxygen