LCOV - code coverage report
Current view: top level - core/compression - message_compress.c (source / functions) Hit Total Coverage
Test: tmp.CaZ6RjdVn2 Lines: 91 98 92.9 %
Date: 2015-12-10 22:15:08 Functions: 9 11 81.8 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  * Copyright 2015, Google Inc.
       4             :  * All rights reserved.
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions are
       8             :  * met:
       9             :  *
      10             :  *     * Redistributions of source code must retain the above copyright
      11             :  * notice, this list of conditions and the following disclaimer.
      12             :  *     * Redistributions in binary form must reproduce the above
      13             :  * copyright notice, this list of conditions and the following disclaimer
      14             :  * in the documentation and/or other materials provided with the
      15             :  * distribution.
      16             :  *     * Neither the name of Google Inc. nor the names of its
      17             :  * contributors may be used to endorse or promote products derived from
      18             :  * this software without specific prior written permission.
      19             :  *
      20             :  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      21             :  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      22             :  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      23             :  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
      24             :  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      25             :  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
      26             :  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      27             :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      28             :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      29             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      30             :  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      31             :  *
      32             :  */
      33             : 
      34             : #include "src/core/compression/message_compress.h"
      35             : 
      36             : #include <string.h>
      37             : 
      38             : #include <grpc/support/alloc.h>
      39             : #include <grpc/support/log.h>
      40             : 
      41             : #include <zlib.h>
      42             : 
      43             : #define OUTPUT_BLOCK_SIZE 1024
      44             : 
      45         889 : static int zlib_body(z_stream* zs, gpr_slice_buffer* input,
      46             :                      gpr_slice_buffer* output,
      47             :                      int (*flate)(z_stream* zs, int flush)) {
      48             :   int r;
      49             :   int flush;
      50             :   size_t i;
      51         889 :   gpr_slice outbuf = gpr_slice_malloc(OUTPUT_BLOCK_SIZE);
      52         889 :   const uInt uint_max = ~(uInt)0;
      53             : 
      54         889 :   GPR_ASSERT(GPR_SLICE_LENGTH(outbuf) <= uint_max);
      55         889 :   zs->avail_out = (uInt)GPR_SLICE_LENGTH(outbuf);
      56         889 :   zs->next_out = GPR_SLICE_START_PTR(outbuf);
      57         889 :   flush = Z_NO_FLUSH;
      58        6054 :   for (i = 0; i < input->count; i++) {
      59        5167 :     if (i == input->count - 1) flush = Z_FINISH;
      60        5167 :     GPR_ASSERT(GPR_SLICE_LENGTH(input->slices[i]) <= uint_max);
      61        5167 :     zs->avail_in = (uInt)GPR_SLICE_LENGTH(input->slices[i]);
      62        5167 :     zs->next_in = GPR_SLICE_START_PTR(input->slices[i]);
      63             :     do {
      64       17483 :       if (zs->avail_out == 0) {
      65       12316 :         gpr_slice_buffer_add_indexed(output, outbuf);
      66       12316 :         outbuf = gpr_slice_malloc(OUTPUT_BLOCK_SIZE);
      67       12316 :         GPR_ASSERT(GPR_SLICE_LENGTH(outbuf) <= uint_max);
      68       12316 :         zs->avail_out = (uInt)GPR_SLICE_LENGTH(outbuf);
      69       12316 :         zs->next_out = GPR_SLICE_START_PTR(outbuf);
      70             :       }
      71       17483 :       r = flate(zs, flush);
      72       17483 :       if (r == Z_STREAM_ERROR) {
      73           0 :         gpr_log(GPR_INFO, "zlib: stream error");
      74           0 :         goto error;
      75             :       }
      76       17483 :     } while (zs->avail_out == 0);
      77        5167 :     if (zs->avail_in) {
      78           2 :       gpr_log(GPR_INFO, "zlib: not all input consumed");
      79           2 :       goto error;
      80             :     }
      81             :   }
      82             : 
      83         887 :   GPR_ASSERT(outbuf.refcount);
      84         887 :   outbuf.data.refcounted.length -= zs->avail_out;
      85         887 :   gpr_slice_buffer_add_indexed(output, outbuf);
      86             : 
      87         887 :   return 1;
      88             : 
      89             : error:
      90           2 :   gpr_slice_unref(outbuf);
      91           2 :   return 0;
      92             : }
      93             : 
      94        4093 : static void *zalloc_gpr(void* opaque, unsigned int items, unsigned int size) {
      95        4093 :   return gpr_malloc(items * size);
      96             : }
      97             : 
      98        4093 : static void zfree_gpr(void* opaque, void *address) {
      99        4093 :   gpr_free(address);
     100        4093 : }
     101             : 
     102         795 : static int zlib_compress(gpr_slice_buffer* input, gpr_slice_buffer* output,
     103             :                          int gzip) {
     104             :   z_stream zs;
     105             :   int r;
     106             :   size_t i;
     107         795 :   size_t count_before = output->count;
     108         795 :   size_t length_before = output->length;
     109         795 :   memset(&zs, 0, sizeof(zs));
     110         795 :   zs.zalloc = zalloc_gpr;
     111         795 :   zs.zfree = zfree_gpr;
     112         795 :   r = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 | (gzip ? 16 : 0),
     113             :                    8, Z_DEFAULT_STRATEGY);
     114         795 :   if (r != Z_OK) {
     115           0 :     gpr_log(GPR_ERROR, "deflateInit2 returns %d", r);
     116           0 :     return 0;
     117             :   }
     118         795 :   r = zlib_body(&zs, input, output, deflate) && output->length < input->length;
     119         795 :   if (!r) {
     120        1398 :     for (i = count_before; i < output->count; i++) {
     121         699 :       gpr_slice_unref(output->slices[i]);
     122             :     }
     123         699 :     output->count = count_before;
     124         699 :     output->length = length_before;
     125             :   }
     126         795 :   deflateEnd(&zs);
     127         795 :   return r;
     128             : }
     129             : 
     130          94 : static int zlib_decompress(gpr_slice_buffer* input, gpr_slice_buffer* output,
     131             :                            int gzip) {
     132             :   z_stream zs;
     133             :   int r;
     134             :   size_t i;
     135          94 :   size_t count_before = output->count;
     136          94 :   size_t length_before = output->length;
     137          94 :   memset(&zs, 0, sizeof(zs));
     138          94 :   zs.zalloc = zalloc_gpr;
     139          94 :   zs.zfree = zfree_gpr;
     140          94 :   r = inflateInit2(&zs, 15 | (gzip ? 16 : 0));
     141          94 :   if (r != Z_OK) {
     142           0 :     gpr_log(GPR_ERROR, "inflateInit2 returns %d", r);
     143           0 :     return 0;
     144             :   }
     145          94 :   r = zlib_body(&zs, input, output, inflate);
     146          94 :   if (!r) {
     147           2 :     for (i = count_before; i < output->count; i++) {
     148           0 :       gpr_slice_unref(output->slices[i]);
     149             :     }
     150           2 :     output->count = count_before;
     151           2 :     output->length = length_before;
     152             :   }
     153          94 :   inflateEnd(&zs);
     154          94 :   return r;
     155             : }
     156             : 
     157         749 : static int copy(gpr_slice_buffer* input, gpr_slice_buffer* output) {
     158             :   size_t i;
     159     2100694 :   for (i = 0; i < input->count; i++) {
     160     2099945 :     gpr_slice_buffer_add(output, gpr_slice_ref(input->slices[i]));
     161             :   }
     162         749 :   return 1;
     163             : }
     164             : 
     165         815 : static int compress_inner(grpc_compression_algorithm algorithm,
     166             :                    gpr_slice_buffer* input, gpr_slice_buffer* output) {
     167         815 :   switch (algorithm) {
     168             :     case GRPC_COMPRESS_NONE:
     169             :       /* the fallback path always needs to be send uncompressed: we simply
     170             :          rely on that here */
     171          18 :       return 0;
     172             :     case GRPC_COMPRESS_DEFLATE:
     173          19 :       return zlib_compress(input, output, 0);
     174             :     case GRPC_COMPRESS_GZIP:
     175         776 :       return zlib_compress(input, output, 1);
     176             :     case GRPC_COMPRESS_ALGORITHMS_COUNT:
     177           1 :       break;
     178             :   }
     179           2 :   gpr_log(GPR_ERROR, "invalid compression algorithm %d", algorithm);
     180           2 :   return 0;
     181             : }
     182             : 
     183         815 : int grpc_msg_compress(grpc_compression_algorithm algorithm,
     184             :                       gpr_slice_buffer* input, gpr_slice_buffer* output) {
     185         815 :   if (!compress_inner(algorithm, input, output)) {
     186         719 :     copy(input, output);
     187         719 :     return 0;
     188             :   }
     189          96 :   return 1;
     190             : }
     191             : 
     192         126 : int grpc_msg_decompress(grpc_compression_algorithm algorithm,
     193             :                         gpr_slice_buffer* input, gpr_slice_buffer* output) {
     194         126 :   switch (algorithm) {
     195             :     case GRPC_COMPRESS_NONE:
     196          30 :       return copy(input, output);
     197             :     case GRPC_COMPRESS_DEFLATE:
     198          14 :       return zlib_decompress(input, output, 0);
     199             :     case GRPC_COMPRESS_GZIP:
     200          80 :       return zlib_decompress(input, output, 1);
     201             :     case GRPC_COMPRESS_ALGORITHMS_COUNT:
     202           1 :       break;
     203             :   }
     204           2 :   gpr_log(GPR_ERROR, "invalid compression algorithm %d", algorithm);
     205           2 :   return 0;
     206             : }

Generated by: LCOV version 1.11