Missing return values (Coverity ID 204).
[openssl.git] / crypto / comp / c_zlib.c
index 90ead64b7297dc192c0602307cf788dfc8dc85a2..0e503bf1772b39b00c366e55bc22bd390a0a7b02 100644 (file)
@@ -3,6 +3,7 @@
 #include <string.h>
 #include <openssl/objects.h>
 #include <openssl/comp.h>
+#include <openssl/err.h>
 
 COMP_METHOD *COMP_zlib(void );
 
@@ -23,6 +24,32 @@ static COMP_METHOD zlib_method_nozlib={
 
 #include <zlib.h>
 
+static int zlib_stateful_init(COMP_CTX *ctx);
+static void zlib_stateful_finish(COMP_CTX *ctx);
+static int zlib_stateful_compress_block(COMP_CTX *ctx, unsigned char *out,
+       unsigned int olen, unsigned char *in, unsigned int ilen);
+static int zlib_stateful_expand_block(COMP_CTX *ctx, unsigned char *out,
+       unsigned int olen, unsigned char *in, unsigned int ilen);
+
+
+/* memory allocations functions for zlib intialization */
+static void* zlib_zalloc(void* opaque, unsigned int no, unsigned int size)
+{
+       void *p;
+       
+       p=OPENSSL_malloc(no*size);
+       if (p)
+               memset(p, 0, no*size);
+       return p;
+}
+
+
+static void zlib_zfree(void* opaque, void* address)
+{
+       OPENSSL_free(address);
+}
+
+#if 0
 static int zlib_compress_block(COMP_CTX *ctx, unsigned char *out,
        unsigned int olen, unsigned char *in, unsigned int ilen);
 static int zlib_expand_block(COMP_CTX *ctx, unsigned char *out,
@@ -31,7 +58,7 @@ static int zlib_expand_block(COMP_CTX *ctx, unsigned char *out,
 static int zz_uncompress(Bytef *dest, uLongf *destLen, const Bytef *source,
        uLong sourceLen);
 
-static COMP_METHOD zlib_method={
+static COMP_METHOD zlib_stateless_method={
        NID_zlib_compression,
        LN_zlib_compression,
        NULL,
@@ -41,56 +68,187 @@ static COMP_METHOD zlib_method={
        NULL,
        NULL,
        };
+#endif
+
+static COMP_METHOD zlib_stateful_method={
+       NID_zlib_compression,
+       LN_zlib_compression,
+       zlib_stateful_init,
+       zlib_stateful_finish,
+       zlib_stateful_compress_block,
+       zlib_stateful_expand_block,
+       NULL,
+       NULL,
+       };
 
 /* 
  * When OpenSSL is built on Windows, we do not want to require that
  * the ZLIB.DLL be available in order for the OpenSSL DLLs to
  * work.  Therefore, all ZLIB routines are loaded at run time
- * and we do not link to a .LIB file.
+ * and we do not link to a .LIB file when ZLIB_SHARED is set.
  */
-#if defined(WINDOWS) || defined(WIN32)
+#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
 # include <windows.h>
-
-# define Z_CALLCONV _stcall
-# define ZLIB_SHARED
-#else
-# define Z_CALLCONV
-#endif /* !(WINDOWS || WIN32) */
+#endif /* !(OPENSSL_SYS_WINDOWS || OPENSSL_SYS_WIN32) */
 
 #ifdef ZLIB_SHARED
 #include <openssl/dso.h>
 
-/* Prototypes for built in stubs */
-static int stub_compress(Bytef *dest,uLongf *destLen,
-       const Bytef *source, uLong sourceLen);
-static int stub_inflateEnd(z_streamp strm);
-static int stub_inflate(z_streamp strm, int flush);
-static int stub_inflateInit_(z_streamp strm, const char * version,
-       int stream_size);
-
 /* Function pointers */
-typedef int Z_CALLCONV (*compress_ft)(Bytef *dest,uLongf *destLen,
+typedef int (*compress_ft)(Bytef *dest,uLongf *destLen,
        const Bytef *source, uLong sourceLen);
-typedef int Z_CALLCONV (*inflateEnd_ft)(z_streamp strm);
-typedef int Z_CALLCONV (*inflate_ft)(z_streamp strm, int flush);
-typedef int Z_CALLCONV (*inflateInit__ft)(z_streamp strm,
+typedef int (*inflateEnd_ft)(z_streamp strm);
+typedef int (*inflate_ft)(z_streamp strm, int flush);
+typedef int (*inflateInit__ft)(z_streamp strm,
        const char * version, int stream_size);
+typedef int (*deflateEnd_ft)(z_streamp strm);
+typedef int (*deflate_ft)(z_streamp strm, int flush);
+typedef int (*deflateInit__ft)(z_streamp strm, int level,
+       const char * version, int stream_size);
+typedef const char * (*zError__ft)(int err);
 static compress_ft     p_compress=NULL;
 static inflateEnd_ft   p_inflateEnd=NULL;
 static inflate_ft      p_inflate=NULL;
 static inflateInit__ft p_inflateInit_=NULL;
+static deflateEnd_ft   p_deflateEnd=NULL;
+static deflate_ft      p_deflate=NULL;
+static deflateInit__ft p_deflateInit_=NULL;
+static zError__ft      p_zError=NULL;
 
 static int zlib_loaded = 0;     /* only attempt to init func pts once */
 static DSO *zlib_dso = NULL;
 
-#define compress                stub_compress
-#define inflateEnd              stub_inflateEnd
-#define inflate                 stub_inflate
-#define inflateInit_            stub_inflateInit_
+#define compress                p_compress
+#define inflateEnd              p_inflateEnd
+#define inflate                 p_inflate
+#define inflateInit_            p_inflateInit_
+#define deflateEnd              p_deflateEnd
+#define deflate                 p_deflate
+#define deflateInit_            p_deflateInit_
+#define zError                 p_zError
 #endif /* ZLIB_SHARED */
 
+struct zlib_state
+       {
+       z_stream istream;
+       z_stream ostream;
+       };
+
+static int zlib_stateful_ex_idx = -1;
+
+static void zlib_stateful_free_ex_data(void *obj, void *item,
+       CRYPTO_EX_DATA *ad, int ind,long argl, void *argp)
+       {
+       struct zlib_state *state = (struct zlib_state *)item;
+       inflateEnd(&state->istream);
+       deflateEnd(&state->ostream);
+       OPENSSL_free(state);
+       }
+
+static int zlib_stateful_init(COMP_CTX *ctx)
+       {
+       int err;
+       struct zlib_state *state =
+               (struct zlib_state *)OPENSSL_malloc(sizeof(struct zlib_state));
+
+       if (state == NULL)
+               goto err;
+
+       state->istream.zalloc = zlib_zalloc;
+       state->istream.zfree = zlib_zfree;
+       state->istream.opaque = Z_NULL;
+       state->istream.next_in = Z_NULL;
+       state->istream.next_out = Z_NULL;
+       state->istream.avail_in = 0;
+       state->istream.avail_out = 0;
+       err = inflateInit_(&state->istream,
+               ZLIB_VERSION, sizeof(z_stream));
+       if (err != Z_OK)
+               goto err;
+
+       state->ostream.zalloc = zlib_zalloc;
+       state->ostream.zfree = zlib_zfree;
+       state->ostream.opaque = Z_NULL;
+       state->ostream.next_in = Z_NULL;
+       state->ostream.next_out = Z_NULL;
+       state->ostream.avail_in = 0;
+       state->ostream.avail_out = 0;
+       err = deflateInit_(&state->ostream,Z_DEFAULT_COMPRESSION,
+               ZLIB_VERSION, sizeof(z_stream));
+       if (err != Z_OK)
+               goto err;
+
+       CRYPTO_new_ex_data(CRYPTO_EX_INDEX_COMP,ctx,&ctx->ex_data);
+       CRYPTO_set_ex_data(&ctx->ex_data,zlib_stateful_ex_idx,state);
+       return 1;
+ err:
+       if (state) OPENSSL_free(state);
+       return 0;
+       }
+
+static void zlib_stateful_finish(COMP_CTX *ctx)
+       {
+       CRYPTO_free_ex_data(CRYPTO_EX_INDEX_COMP,ctx,&ctx->ex_data);
+       }
+
+static int zlib_stateful_compress_block(COMP_CTX *ctx, unsigned char *out,
+       unsigned int olen, unsigned char *in, unsigned int ilen)
+       {
+       int err = Z_OK;
+       struct zlib_state *state =
+               (struct zlib_state *)CRYPTO_get_ex_data(&ctx->ex_data,
+                       zlib_stateful_ex_idx);
+
+       if (state == NULL)
+               return -1;
+
+       state->ostream.next_in = in;
+       state->ostream.avail_in = ilen;
+       state->ostream.next_out = out;
+       state->ostream.avail_out = olen;
+       if (ilen > 0)
+               err = deflate(&state->ostream, Z_SYNC_FLUSH);
+       if (err != Z_OK)
+               return -1;
+#ifdef DEBUG_ZLIB
+       fprintf(stderr,"compress(%4d)->%4d %s\n",
+               ilen,olen - state->ostream.avail_out,
+               (ilen != olen - state->ostream.avail_out)?"zlib":"clear");
+#endif
+       return olen - state->ostream.avail_out;
+       }
+
+static int zlib_stateful_expand_block(COMP_CTX *ctx, unsigned char *out,
+       unsigned int olen, unsigned char *in, unsigned int ilen)
+       {
+       int err = Z_OK;
+
+       struct zlib_state *state =
+               (struct zlib_state *)CRYPTO_get_ex_data(&ctx->ex_data,
+                       zlib_stateful_ex_idx);
+
+       if (state == NULL)
+               return 0;
+
+       state->istream.next_in = in;
+       state->istream.avail_in = ilen;
+       state->istream.next_out = out;
+       state->istream.avail_out = olen;
+       if (ilen > 0)
+               err = inflate(&state->istream, Z_SYNC_FLUSH);
+       if (err != Z_OK)
+               return -1;
+#ifdef DEBUG_ZLIB
+       fprintf(stderr,"expand(%4d)->%4d %s\n",
+               ilen,olen - state->istream.avail_out,
+               (ilen != olen - state->istream.avail_out)?"zlib":"clear");
+#endif
+       return olen - state->istream.avail_out;
+       }
+
+#if 0
 static int zlib_compress_block(COMP_CTX *ctx, unsigned char *out,
-            unsigned int olen, unsigned char *in, unsigned int ilen)
+       unsigned int olen, unsigned char *in, unsigned int ilen)
        {
        unsigned long l;
        int i;
@@ -123,7 +281,7 @@ static int zlib_compress_block(COMP_CTX *ctx, unsigned char *out,
        }
 
 static int zlib_expand_block(COMP_CTX *ctx, unsigned char *out,
-            unsigned int olen, unsigned char *in, unsigned int ilen)
+       unsigned int olen, unsigned char *in, unsigned int ilen)
        {
        unsigned long l;
        int i;
@@ -165,7 +323,8 @@ static int zz_uncompress (Bytef *dest, uLongf *destLen, const Bytef *source,
     stream.zalloc = (alloc_func)0;
     stream.zfree = (free_func)0;
 
-    err = inflateInit(&stream);
+    err = inflateInit_(&stream,
+           ZLIB_VERSION, sizeof(z_stream));
     if (err != Z_OK) return err;
 
     err = inflate(&stream, Z_FINISH);
@@ -178,6 +337,7 @@ static int zz_uncompress (Bytef *dest, uLongf *destLen, const Bytef *source,
     err = inflateEnd(&stream);
     return err;
 }
+#endif
 
 #endif
 
@@ -188,8 +348,8 @@ COMP_METHOD *COMP_zlib(void)
 #ifdef ZLIB_SHARED
        if (!zlib_loaded)
                {
-#if defined(WINDOWS) || defined(WIN32)
-               zlib_dso = DSO_load(NULL, "ZLIB", NULL, 0);
+#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
+               zlib_dso = DSO_load(NULL, "ZLIB1", NULL, 0);
 #else
                zlib_dso = DSO_load(NULL, "z", NULL, 0);
 #endif
@@ -207,54 +367,436 @@ COMP_METHOD *COMP_zlib(void)
                        p_inflateInit_
                                = (inflateInit__ft) DSO_bind_func(zlib_dso,
                                        "inflateInit_");
-                       zlib_loaded++;
-                       meth = &zlib_method;
+                       p_deflateEnd
+                               = (deflateEnd_ft) DSO_bind_func(zlib_dso,
+                                       "deflateEnd");
+                       p_deflate
+                               = (deflate_ft) DSO_bind_func(zlib_dso,
+                                       "deflate");
+                       p_deflateInit_
+                               = (deflateInit__ft) DSO_bind_func(zlib_dso,
+                                       "deflateInit_");
+                       p_zError
+                               = (zError__ft) DSO_bind_func(zlib_dso,
+                                       "zError");
+
+                       if (p_compress && p_inflateEnd && p_inflate
+                               && p_inflateInit_ && p_deflateEnd
+                               && p_deflate && p_deflateInit_ && p_zError)
+                               zlib_loaded++;
                        }
                }
 
-#elif defined(ZLIB)
-       meth = &zlib_method;
+#endif
+#ifdef ZLIB_SHARED
+       if (zlib_loaded)
+#endif
+#if defined(ZLIB) || defined(ZLIB_SHARED)
+               {
+               /* init zlib_stateful_ex_idx here so that in a multi-process
+                * application it's enough to intialize openssl before forking
+                * (idx will be inherited in all the children) */
+               if (zlib_stateful_ex_idx == -1)
+                       {
+                       CRYPTO_w_lock(CRYPTO_LOCK_COMP);
+                       if (zlib_stateful_ex_idx == -1)
+                               zlib_stateful_ex_idx =
+                                       CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_COMP,
+                                               0,NULL,NULL,NULL,zlib_stateful_free_ex_data);
+                       CRYPTO_w_unlock(CRYPTO_LOCK_COMP);
+                       if (zlib_stateful_ex_idx == -1)
+                               goto err;
+                       }
+               
+               meth = &zlib_stateful_method;
+               }
+err:   
 #endif
 
        return(meth);
        }
 
+void COMP_zlib_cleanup(void)
+       {
 #ifdef ZLIB_SHARED
-/* Stubs for each function to be dynamicly loaded */
-static int 
-stub_compress(Bytef *dest,uLongf *destLen,const Bytef *source, uLong sourceLen)
+       if (zlib_dso)
+               DSO_free(zlib_dso);
+#endif
+       }
+
+#ifdef ZLIB
+
+/* Zlib based compression/decompression filter BIO */
+
+typedef struct
        {
-       if (p_compress)
-               return(p_compress(dest,destLen,source,sourceLen));
-       else
-               return(Z_MEM_ERROR);
+       unsigned char *ibuf;    /* Input buffer */
+       int ibufsize;           /* Buffer size */
+       z_stream zin;           /* Input decompress context */
+       unsigned char *obuf;    /* Output buffer */
+       int obufsize;           /* Output buffer size */
+       unsigned char *optr;    /* Position in output buffer */
+       int ocount;             /* Amount of data in output buffer */
+       int odone;              /* deflate EOF */
+       int comp_level;         /* Compression level to use */
+       z_stream zout;          /* Output compression context */
+       } BIO_ZLIB_CTX;
+
+#define ZLIB_DEFAULT_BUFSIZE 1024
+
+static int bio_zlib_new(BIO *bi);
+static int bio_zlib_free(BIO *bi);
+static int bio_zlib_read(BIO *b, char *out, int outl);
+static int bio_zlib_write(BIO *b, const char *in, int inl);
+static long bio_zlib_ctrl(BIO *b, int cmd, long num, void *ptr);
+static long bio_zlib_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp);
+
+static BIO_METHOD bio_meth_zlib = 
+       {
+       BIO_TYPE_COMP,
+       "zlib",
+       bio_zlib_write,
+       bio_zlib_read,
+       NULL,
+       NULL,
+       bio_zlib_ctrl,
+       bio_zlib_new,
+       bio_zlib_free,
+       bio_zlib_callback_ctrl
+       };
+
+BIO_METHOD *BIO_f_zlib(void)
+       {
+       return &bio_meth_zlib;
        }
 
-static int
-stub_inflateEnd(z_streamp strm)
+
+static int bio_zlib_new(BIO *bi)
        {
-       if ( p_inflateEnd )
-               return(p_inflateEnd(strm));
-       else
-               return(Z_MEM_ERROR);
+       BIO_ZLIB_CTX *ctx;
+#ifdef ZLIB_SHARED
+       (void)COMP_zlib();
+       if (!zlib_loaded)
+               {
+               COMPerr(COMP_F_BIO_ZLIB_NEW, COMP_R_ZLIB_NOT_SUPPORTED);
+               return 0;
+               }
+#endif
+       ctx = OPENSSL_malloc(sizeof(BIO_ZLIB_CTX));
+       if(!ctx)
+               {
+               COMPerr(COMP_F_BIO_ZLIB_NEW, ERR_R_MALLOC_FAILURE);
+               return 0;
+               }
+       ctx->ibuf = NULL;
+       ctx->obuf = NULL;
+       ctx->ibufsize = ZLIB_DEFAULT_BUFSIZE;
+       ctx->obufsize = ZLIB_DEFAULT_BUFSIZE;
+       ctx->zin.zalloc = Z_NULL;
+       ctx->zin.zfree = Z_NULL;
+       ctx->zin.next_in = NULL;
+       ctx->zin.avail_in = 0;
+       ctx->zin.next_out = NULL;
+       ctx->zin.avail_out = 0;
+       ctx->zout.zalloc = Z_NULL;
+       ctx->zout.zfree = Z_NULL;
+       ctx->zout.next_in = NULL;
+       ctx->zout.avail_in = 0;
+       ctx->zout.next_out = NULL;
+       ctx->zout.avail_out = 0;
+       ctx->odone = 0;
+       ctx->comp_level = Z_DEFAULT_COMPRESSION;
+       bi->init = 1;
+       bi->ptr = (char *)ctx;
+       bi->flags = 0;
+       return 1;
        }
 
-static int
-stub_inflate(z_streamp strm, int flush)
+static int bio_zlib_free(BIO *bi)
        {
-       if ( p_inflate )
-               return(p_inflate(strm,flush));
-       else
-               return(Z_MEM_ERROR);
+       BIO_ZLIB_CTX *ctx;
+       if(!bi) return 0;
+       ctx = (BIO_ZLIB_CTX *)bi->ptr;
+       if(ctx->ibuf)
+               {
+               /* Destroy decompress context */
+               inflateEnd(&ctx->zin);
+               OPENSSL_free(ctx->ibuf);
+               }
+       if(ctx->obuf)
+               {
+               /* Destroy compress context */
+               deflateEnd(&ctx->zout);
+               OPENSSL_free(ctx->obuf);
+               }
+       OPENSSL_free(ctx);
+       bi->ptr = NULL;
+       bi->init = 0;
+       bi->flags = 0;
+       return 1;
        }
 
-static int
-stub_inflateInit_(z_streamp strm, const char * version, int stream_size)
+static int bio_zlib_read(BIO *b, char *out, int outl)
        {
-       if ( p_inflateInit_ )
-               return(p_inflateInit_(strm,version,stream_size));
-       else
-               return(Z_MEM_ERROR);
+       BIO_ZLIB_CTX *ctx;
+       int ret;
+       z_stream *zin;
+       if(!out || !outl) return 0;
+       ctx = (BIO_ZLIB_CTX *)b->ptr;
+       zin = &ctx->zin;
+       BIO_clear_retry_flags(b);
+       if(!ctx->ibuf)
+               {
+               ctx->ibuf = OPENSSL_malloc(ctx->ibufsize);
+               if(!ctx->ibuf)
+                       {
+                       COMPerr(COMP_F_BIO_ZLIB_READ, ERR_R_MALLOC_FAILURE);
+                       return 0;
+                       }
+               inflateInit(zin);
+               zin->next_in = ctx->ibuf;
+               zin->avail_in = 0;
+               }
+
+       /* Copy output data directly to supplied buffer */
+       zin->next_out = (unsigned char *)out;
+       zin->avail_out = (unsigned int)outl;
+       for(;;)
+               {
+               /* Decompress while data available */
+               while(zin->avail_in)
+                       {
+                       ret = inflate(zin, 0);
+                       if((ret != Z_OK) && (ret != Z_STREAM_END))
+                               {
+                               COMPerr(COMP_F_BIO_ZLIB_READ,
+                                               COMP_R_ZLIB_INFLATE_ERROR);
+                               ERR_add_error_data(2, "zlib error:",
+                                                       zError(ret));
+                               return 0;
+                               }
+                       /* If EOF or we've read everything then return */
+                       if((ret == Z_STREAM_END) || !zin->avail_out)
+                               return outl - zin->avail_out;
+                       }
+
+               /* No data in input buffer try to read some in,
+                * if an error then return the total data read.
+                */
+               ret = BIO_read(b->next_bio, ctx->ibuf, ctx->ibufsize);
+               if(ret <= 0)
+                       {
+                       /* Total data read */
+                       int tot = outl - zin->avail_out;
+                       BIO_copy_next_retry(b);
+                       if(ret < 0) return (tot > 0) ? tot : ret;
+                       return tot;
+                       }
+               zin->avail_in = ret;
+               zin->next_in = ctx->ibuf;
+               }
        }
 
-#endif /* ZLIB_SHARED */
+static int bio_zlib_write(BIO *b, const char *in, int inl)
+       {
+       BIO_ZLIB_CTX *ctx;
+       int ret;
+       z_stream *zout;
+       if(!in || !inl) return 0;
+       ctx = (BIO_ZLIB_CTX *)b->ptr;
+       if(ctx->odone) return 0;
+       zout = &ctx->zout;
+       BIO_clear_retry_flags(b);
+       if(!ctx->obuf)
+               {
+               ctx->obuf = OPENSSL_malloc(ctx->obufsize);
+               /* Need error here */
+               if(!ctx->obuf)
+                       {
+                       COMPerr(COMP_F_BIO_ZLIB_WRITE, ERR_R_MALLOC_FAILURE);
+                       return 0;
+                       }
+               ctx->optr = ctx->obuf;
+               ctx->ocount = 0;
+               deflateInit(zout, ctx->comp_level);
+               zout->next_out = ctx->obuf;
+               zout->avail_out = ctx->obufsize;
+               }
+       /* Obtain input data directly from supplied buffer */
+       zout->next_in = (void *)in;
+       zout->avail_in = inl;
+       for(;;)
+               {
+               /* If data in output buffer write it first */
+               while(ctx->ocount) {
+                       ret = BIO_write(b->next_bio, ctx->optr, ctx->ocount);
+                       if(ret <= 0)
+                               {
+                               /* Total data written */
+                               int tot = inl - zout->avail_in;
+                               BIO_copy_next_retry(b);
+                               if(ret < 0) return (tot > 0) ? tot : ret;
+                               return tot;
+                               }
+                       ctx->optr += ret;
+                       ctx->ocount -= ret;
+               }
+
+               /* Have we consumed all supplied data? */
+               if(!zout->avail_in)
+                       return inl;
+
+               /* Compress some more */
+
+               /* Reset buffer */
+               ctx->optr = ctx->obuf;
+               zout->next_out = ctx->obuf;
+               zout->avail_out = ctx->obufsize;
+               /* Compress some more */
+               ret = deflate(zout, 0);
+               if(ret != Z_OK)
+                       {
+                       COMPerr(COMP_F_BIO_ZLIB_WRITE,
+                                               COMP_R_ZLIB_DEFLATE_ERROR);
+                       ERR_add_error_data(2, "zlib error:", zError(ret));
+                       return 0;
+                       }
+               ctx->ocount = ctx->obufsize - zout->avail_out;
+               }
+       }
+
+static int bio_zlib_flush(BIO *b)
+       {
+       BIO_ZLIB_CTX *ctx;
+       int ret;
+       z_stream *zout;
+       ctx = (BIO_ZLIB_CTX *)b->ptr;
+       /* If no data written or already flush show success */
+       if(!ctx->obuf || (ctx->odone && !ctx->ocount)) return 1;
+       zout = &ctx->zout;
+       BIO_clear_retry_flags(b);
+       /* No more input data */
+       zout->next_in = NULL;
+       zout->avail_in = 0;
+       for(;;)
+               {
+               /* If data in output buffer write it first */
+               while(ctx->ocount)
+                       {
+                       ret = BIO_write(b->next_bio, ctx->optr, ctx->ocount);
+                       if(ret <= 0)
+                               {
+                               BIO_copy_next_retry(b);
+                               return ret;
+                               }
+                       ctx->optr += ret;
+                       ctx->ocount -= ret;
+                       }
+               if(ctx->odone) return 1;
+
+               /* Compress some more */
+
+               /* Reset buffer */
+               ctx->optr = ctx->obuf;
+               zout->next_out = ctx->obuf;
+               zout->avail_out = ctx->obufsize;
+               /* Compress some more */
+               ret = deflate(zout, Z_FINISH);
+               if(ret == Z_STREAM_END) ctx->odone = 1;
+               else if(ret != Z_OK)
+                       {
+                       COMPerr(COMP_F_BIO_ZLIB_FLUSH,
+                                               COMP_R_ZLIB_DEFLATE_ERROR);
+                       ERR_add_error_data(2, "zlib error:", zError(ret));
+                       return 0;
+                       }
+               ctx->ocount = ctx->obufsize - zout->avail_out;
+               }
+       }
+
+static long bio_zlib_ctrl(BIO *b, int cmd, long num, void *ptr)
+       {
+       BIO_ZLIB_CTX *ctx;
+       int ret, *ip;
+       int ibs, obs;
+       if(!b->next_bio) return 0;
+       ctx = (BIO_ZLIB_CTX *)b->ptr;
+       switch (cmd)
+               {
+
+       case BIO_CTRL_RESET:
+               ctx->ocount = 0;
+               ctx->odone = 0;
+               ret = 1;
+               break;
+
+       case BIO_CTRL_FLUSH:
+               ret = bio_zlib_flush(b);
+               if (ret > 0)
+                       ret = BIO_flush(b->next_bio);
+               break;
+
+       case BIO_C_SET_BUFF_SIZE:
+               ibs = -1;
+               obs = -1;
+               if (ptr != NULL)
+                       {
+                       ip = ptr;
+                       if (*ip == 0)
+                               ibs = (int) num;
+                       else 
+                               obs = (int) num;
+                       }
+               else
+                       {
+                       ibs = (int)num;
+                       obs = ibs;
+                       }
+
+               if (ibs != -1)
+                       {
+                       if (ctx->ibuf)
+                               {
+                               OPENSSL_free(ctx->ibuf);
+                               ctx->ibuf = NULL;
+                               }
+                       ctx->ibufsize = ibs;
+                       }
+
+               if (obs != -1)
+                       {
+                       if (ctx->obuf)
+                               {
+                               OPENSSL_free(ctx->obuf);
+                               ctx->obuf = NULL;
+                               }
+                       ctx->obufsize = obs;
+                       }
+               ret = 1;
+               break;
+
+       case BIO_C_DO_STATE_MACHINE:
+               BIO_clear_retry_flags(b);
+               ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
+               BIO_copy_next_retry(b);
+               break;
+
+       default:
+               ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
+               break;
+
+               }
+
+       return ret;
+       }
+
+
+static long bio_zlib_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
+       {
+       if(!b->next_bio)
+               return 0;
+       return
+               BIO_callback_ctrl(b->next_bio, cmd, fp);
+       }
+
+#endif