fixed_c_zlib.h

Go to the documentation of this file.
00001 /* $Id$
00002  * 
00003  * This file contains modified zlib compression functions
00004  * originally part of crypto/comp/c_zlib.c from the openssl library 
00005  * (version 0.9.8a).
00006  * It's distributed under the same license as OpenSSL.
00007  *
00008  * Copyright (c) 1998-2005 The OpenSSL Project.  All rights reserved.
00009  */
00010 /*
00011  * The changes are: 
00012  *   - proper zalloc and zfree initialization for the zlib compression
00013  *     methods (use OPENSSL_malloc & OPENSSL_free to construct zalloc/zfree)
00014  *   - zlib_stateful_ex_idx is now a macro, a pointer to int is alloc'ed now
00015  *    on init and zlib_stateful_ex_idx is now the contents of this pointer 
00016  *    (deref). This allows using compression from different processes (if 
00017  *    the OPENSSL_malloc's are initialized previously to a shared mem. using
00018  *    version).
00019  *  -- andrei
00020  */
00030 #ifdef TLS_FIX_ZLIB_COMPRESSION
00031 
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <openssl/objects.h>
00036 #include <openssl/comp.h>
00037 #include <openssl/err.h>
00038 
00039 #include <zlib.h>
00040 
00041 
00042 /* alloc functions for zlib initialization */
00043 static void* comp_calloc(void* foo, unsigned int no, unsigned int size)
00044 {
00045         void *p;
00046         
00047         p=OPENSSL_malloc(no*size);
00048         if (p)
00049                 memset(p, 0, no*size);
00050         return p;
00051 }
00052 
00053 
00054 /* alloc functions for zlib initialization */
00055 static void comp_free(void* foo, void* p)
00056 {
00057         OPENSSL_free(p);
00058 }
00059 
00060 
00061 static int zlib_stateful_init(COMP_CTX *ctx);
00062 static void zlib_stateful_finish(COMP_CTX *ctx);
00063 static int zlib_stateful_compress_block(COMP_CTX *ctx, unsigned char *out,
00064         unsigned int olen, unsigned char *in, unsigned int ilen);
00065 static int zlib_stateful_expand_block(COMP_CTX *ctx, unsigned char *out,
00066         unsigned int olen, unsigned char *in, unsigned int ilen);
00067 
00068 
00069 static COMP_METHOD zlib_method={
00070         NID_zlib_compression,
00071         LN_zlib_compression,
00072         zlib_stateful_init,
00073         zlib_stateful_finish,
00074         zlib_stateful_compress_block,
00075         zlib_stateful_expand_block,
00076         NULL,
00077         NULL,
00078         };
00079 
00080 
00081 struct zlib_state
00082         {
00083         z_stream istream;
00084         z_stream ostream;
00085         };
00086 
00087 static int* pzlib_stateful_ex_idx = 0; 
00088 #define zlib_stateful_ex_idx (*pzlib_stateful_ex_idx)
00089 
00090 static void zlib_stateful_free_ex_data(void *obj, void *item,
00091         CRYPTO_EX_DATA *ad, int ind,long argl, void *argp);
00092 
00093 int fixed_c_zlib_init()
00094 {
00095         if (pzlib_stateful_ex_idx==0){
00096                 if ((pzlib_stateful_ex_idx=OPENSSL_malloc(sizeof(int)))!=0){
00097                         /* good side effect: it makes sure the ex_data hash
00098                          * in crypto/ex_data.c is created before fork
00099                          * (else each process would have its own copy :-( ) */
00100                         CRYPTO_w_lock(CRYPTO_LOCK_COMP);
00101                         zlib_stateful_ex_idx =
00102                                 CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_COMP,
00103                                         0,NULL,NULL,NULL,zlib_stateful_free_ex_data);
00104                         CRYPTO_w_unlock(CRYPTO_LOCK_COMP);
00105                         return 0;
00106                 } else return -1;
00107         }
00108         return -1;
00109 }
00110 
00111 
00112 
00113 static void zlib_stateful_free_ex_data(void *obj, void *item,
00114         CRYPTO_EX_DATA *ad, int ind,long argl, void *argp)
00115         {
00116         struct zlib_state *state = (struct zlib_state *)item;
00117         if (state)
00118                 {
00119                         inflateEnd(&state->istream);
00120                         deflateEnd(&state->ostream);
00121                         OPENSSL_free(state);
00122                 }
00123         else LOG(L_CRIT, "WARNING: zlib_stateful_free_ex(%p, %p, %p, %d, %ld, %p)" ": cannot free, null item/state\n", obj, item, ad, ind, argl, argp);
00124         }
00125 
00126 static int zlib_stateful_init(COMP_CTX *ctx)
00127         {
00128         int err;
00129         struct zlib_state *state =
00130                 (struct zlib_state *)OPENSSL_malloc(sizeof(struct zlib_state));
00131         int inflate_init, deflate_init;
00132 
00133         if (state == NULL)
00134                 goto err;
00135         inflate_init=0;
00136         deflate_init=0;
00137 
00138         state->istream.zalloc = comp_calloc;
00139         state->istream.zfree = comp_free;
00140         state->istream.opaque = Z_NULL;
00141         state->istream.next_in = Z_NULL;
00142         state->istream.next_out = Z_NULL;
00143         state->istream.avail_in = 0;
00144         state->istream.avail_out = 0;
00145         err = inflateInit_(&state->istream,
00146                 ZLIB_VERSION, sizeof(z_stream));
00147         if (err != Z_OK)
00148                 goto err;
00149         inflate_init=1;
00150 
00151         state->ostream.zalloc = comp_calloc;
00152         state->ostream.zfree = comp_free;
00153         state->ostream.opaque = Z_NULL;
00154         state->ostream.next_in = Z_NULL;
00155         state->ostream.next_out = Z_NULL;
00156         state->ostream.avail_in = 0;
00157         state->ostream.avail_out = 0;
00158         err = deflateInit_(&state->ostream,Z_DEFAULT_COMPRESSION,
00159                 ZLIB_VERSION, sizeof(z_stream));
00160         if (err != Z_OK)
00161                 goto err;
00162         deflate_init=1;
00163 
00164         if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_COMP,ctx,&ctx->ex_data))
00165                 goto err;
00166         if (zlib_stateful_ex_idx == -1)
00167                 {
00168                 CRYPTO_w_lock(CRYPTO_LOCK_COMP);
00169                 if (zlib_stateful_ex_idx == -1)
00170                         zlib_stateful_ex_idx =
00171                                 CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_COMP,
00172                                         0,NULL,NULL,NULL,zlib_stateful_free_ex_data);
00173                 CRYPTO_w_unlock(CRYPTO_LOCK_COMP);
00174                 if (zlib_stateful_ex_idx == -1)
00175                         goto err_ex_data;
00176                 }
00177         if (!CRYPTO_set_ex_data(&ctx->ex_data,zlib_stateful_ex_idx,state))
00178                 goto err_ex_data;
00179         return 1;
00180 err_ex_data:
00181         CRYPTO_free_ex_data(CRYPTO_EX_INDEX_COMP,ctx,&ctx->ex_data);
00182 err:
00183         if (state){
00184                 /* ctx->ex_data freed from outside */
00185                 if (inflate_init)
00186                                 inflateEnd(&state->istream);
00187                 if (deflate_init)
00188                                 deflateEnd(&state->ostream);
00189                 OPENSSL_free(state);
00190         }
00191         return 0;
00192         }
00193 
00194 static void zlib_stateful_finish(COMP_CTX *ctx)
00195         {
00196         CRYPTO_free_ex_data(CRYPTO_EX_INDEX_COMP,ctx,&ctx->ex_data);
00197         }
00198 
00199 static int zlib_stateful_compress_block(COMP_CTX *ctx, unsigned char *out,
00200         unsigned int olen, unsigned char *in, unsigned int ilen)
00201         {
00202         int err = Z_OK;
00203         struct zlib_state *state =
00204                 (struct zlib_state *)CRYPTO_get_ex_data(&ctx->ex_data,
00205                         zlib_stateful_ex_idx);
00206 
00207         if (state == NULL)
00208                 return -1;
00209 
00210         state->ostream.next_in = in;
00211         state->ostream.avail_in = ilen;
00212         state->ostream.next_out = out;
00213         state->ostream.avail_out = olen;
00214         if (ilen > 0)
00215                 err = deflate(&state->ostream, Z_SYNC_FLUSH);
00216         if (err != Z_OK)
00217                 return -1;
00218 #ifdef DEBUG_ZLIB
00219         fprintf(stderr,"compress(%4d)->%4d %s\n",
00220                 ilen,olen - state->ostream.avail_out,
00221                 (ilen != olen - state->ostream.avail_out)?"zlib":"clear");
00222 #endif
00223         return olen - state->ostream.avail_out;
00224         }
00225 
00226 static int zlib_stateful_expand_block(COMP_CTX *ctx, unsigned char *out,
00227         unsigned int olen, unsigned char *in, unsigned int ilen)
00228         {
00229         int err = Z_OK;
00230 
00231         struct zlib_state *state =
00232                 (struct zlib_state *)CRYPTO_get_ex_data(&ctx->ex_data,
00233                         zlib_stateful_ex_idx);
00234 
00235         if (state == NULL)
00236                 return 0;
00237 
00238         state->istream.next_in = in;
00239         state->istream.avail_in = ilen;
00240         state->istream.next_out = out;
00241         state->istream.avail_out = olen;
00242         if (ilen > 0)
00243                 err = inflate(&state->istream, Z_SYNC_FLUSH);
00244         if (err != Z_OK)
00245                 return -1;
00246 #ifdef DEBUG_ZLIB
00247         fprintf(stderr,"expand(%4d)->%4d %s\n",
00248                 ilen,olen - state->istream.avail_out,
00249                 (ilen != olen - state->istream.avail_out)?"zlib":"clear");
00250 #endif
00251         return olen - state->istream.avail_out;
00252         }
00253 
00254 #endif /* TLS_FIX_ZLIB_COMPRESSION */