vtun/lfd_zlib.c

190 lines
4.2 KiB
C

/*
VTun - Virtual Tunnel over TCP/IP network.
Copyright (C) 1998-2008 Maxim Krasnyansky <max_mk@yahoo.com>
VTun has been derived from VPPP package by Maxim Krasnyansky.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
/*
* $Id: lfd_zlib.c,v 1.5.2.2 2008/01/07 22:35:38 mtbishop Exp $
*/
/* ZLIB compression module */
#include "config.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <syslog.h>
#include "vtun.h"
#include "linkfd.h"
#include "lib.h"
#ifdef HAVE_ZLIB
#include <zlib.h>
static z_stream zi, zd;
static unsigned char *zbuf;
static int zbuf_size = VTUN_FRAME_SIZE + 200;
/*
* Initialize compressor/decompressor.
* Allocate the buffer.
*/
int zlib_alloc(struct vtun_host *host)
{
int zlevel = host->zlevel ? host->zlevel : 1;
zd.zalloc = (alloc_func)0;
zd.zfree = (free_func)0;
zd.opaque = (voidpf)0;
zi.zalloc = (alloc_func)0;
zi.zfree = (free_func)0;
zi.opaque = (voidpf)0;
if( deflateInit(&zd, zlevel ) != Z_OK ){
vtun_syslog(LOG_ERR,"Can't initialize compressor");
return 1;
}
if( inflateInit(&zi) != Z_OK ){
vtun_syslog(LOG_ERR,"Can't initialize decompressor");
return 1;
}
if( !(zbuf = (void *) lfd_alloc(zbuf_size)) ){
vtun_syslog(LOG_ERR,"Can't allocate buffer for the compressor");
return 1;
}
vtun_syslog(LOG_INFO,"ZLIB compression[level %d] initialized.", zlevel);
return 0;
}
/*
* Deinitialize compressor/decompressor.
* Free the buffer.
*/
int zlib_free()
{
deflateEnd(&zd);
inflateEnd(&zi);
lfd_free(zbuf); zbuf = NULL;
return 0;
}
static int expand_zbuf(z_stream *zs, int len)
{
if( !(zbuf = lfd_realloc(zbuf,zbuf_size+len)) )
return -1;
zs->next_out = zbuf + zbuf_size;
zs->avail_out = len;
zbuf_size += len;
return 0;
}
/*
* This functions _MUST_ consume all incoming bytes in one pass,
* That's why we expand buffer dynamically.
* Practice shows that buffer will not grow larger that 16K.
*/
int zlib_comp(int len, char *in, char **out)
{
int oavail, olen = 0;
int err;
zd.next_in = (void *) in;
zd.avail_in = len;
zd.next_out = (void *) zbuf;
zd.avail_out = zbuf_size;
while(1) {
oavail = zd.avail_out;
if( (err=deflate(&zd, Z_SYNC_FLUSH)) != Z_OK ){
vtun_syslog(LOG_ERR,"Deflate error %d",err);
return -1;
}
olen += oavail - zd.avail_out;
if(!zd.avail_in)
break;
if( expand_zbuf(&zd,100) ) {
vtun_syslog( LOG_ERR, "Can't expand compression buffer");
return -1;
}
}
*out = (void *) zbuf;
return olen;
}
int zlib_decomp(int len, char *in, char **out)
{
int oavail = 0, olen = 0;
int err;
zi.next_in = (void *) in;
zi.avail_in = len;
zi.next_out = (void *) zbuf;
zi.avail_out = zbuf_size;
while(1) {
oavail = zi.avail_out;
if( (err=inflate(&zi, Z_SYNC_FLUSH)) != Z_OK ) {
vtun_syslog(LOG_ERR,"Inflate error %d len %d", err, len);
return -1;
}
olen += oavail - zi.avail_out;
if(!zi.avail_in)
break;
if( expand_zbuf(&zi,100) ) {
vtun_syslog( LOG_ERR, "Can't expand compression buffer");
return -1;
}
}
*out = (void *) zbuf;
return olen;
}
struct lfd_mod lfd_zlib = {
"ZLIB",
zlib_alloc,
zlib_comp,
NULL,
zlib_decomp,
NULL,
zlib_free,
NULL,
NULL
};
#else /* HAVE_ZLIB */
int no_zlib(struct vtun_host *host)
{
vtun_syslog(LOG_INFO, "ZLIB compression is not supported");
return -1;
}
struct lfd_mod lfd_zlib = {
"ZLIB",
no_zlib, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
#endif /* HAVE_ZLIB */