Annotation of ircnowd/src/ngircd/conn-zip.c, Revision 1.1
1.1 ! tomglok 1: /*
! 2: * ngIRCd -- The Next Generation IRC Daemon
! 3: * Copyright (c)2001-2014 Alexander Barton (alex@barton.de) and Contributors.
! 4: *
! 5: * This program is free software; you can redistribute it and/or modify
! 6: * it under the terms of the GNU General Public License as published by
! 7: * the Free Software Foundation; either version 2 of the License, or
! 8: * (at your option) any later version.
! 9: * Please read the file COPYING, README and AUTHORS for more information.
! 10: */
! 11:
! 12: #define CONN_MODULE
! 13:
! 14: #include "portab.h"
! 15:
! 16: /**
! 17: * @file
! 18: * Connection compression using ZLIB
! 19: */
! 20:
! 21: /* Additionan debug messages related to ZIP compression: 0=off / 1=on */
! 22: #define DEBUG_ZIP 0
! 23:
! 24: #ifdef ZLIB
! 25:
! 26: #include <assert.h>
! 27: #include <string.h>
! 28: #include <zlib.h>
! 29:
! 30: #include "conn.h"
! 31: #include "conn-func.h"
! 32: #include "log.h"
! 33: #include "array.h"
! 34:
! 35: #include "conn-zip.h"
! 36:
! 37:
! 38: GLOBAL bool
! 39: Zip_InitConn( CONN_ID Idx )
! 40: {
! 41: /* initialize zlib compression on this link */
! 42:
! 43: assert( Idx > NONE );
! 44:
! 45: My_Connections[Idx].zip.in.avail_in = 0;
! 46: My_Connections[Idx].zip.in.total_in = 0;
! 47: My_Connections[Idx].zip.in.total_out = 0;
! 48: My_Connections[Idx].zip.in.zalloc = NULL;
! 49: My_Connections[Idx].zip.in.zfree = NULL;
! 50: My_Connections[Idx].zip.in.data_type = Z_ASCII;
! 51:
! 52: if (inflateInit( &My_Connections[Idx].zip.in ) != Z_OK) {
! 53: Log(LOG_ALERT, "Can't initialize compression on connection %d (zlib inflate)!", Idx);
! 54: return false;
! 55: }
! 56:
! 57: My_Connections[Idx].zip.out.total_in = 0;
! 58: My_Connections[Idx].zip.out.total_in = 0;
! 59: My_Connections[Idx].zip.out.zalloc = NULL;
! 60: My_Connections[Idx].zip.out.zfree = NULL;
! 61: My_Connections[Idx].zip.out.data_type = Z_ASCII;
! 62:
! 63: if (deflateInit( &My_Connections[Idx].zip.out, Z_DEFAULT_COMPRESSION ) != Z_OK) {
! 64: Log(LOG_ALERT, "Can't initialize compression on connection %d (zlib deflate)!", Idx);
! 65: return false;
! 66: }
! 67:
! 68: My_Connections[Idx].zip.bytes_in = My_Connections[Idx].bytes_in;
! 69: My_Connections[Idx].zip.bytes_out = My_Connections[Idx].bytes_out;
! 70:
! 71: Log(LOG_INFO, "Enabled link compression (zlib) on connection %d.", Idx);
! 72: Conn_OPTION_ADD( &My_Connections[Idx], CONN_ZIP );
! 73:
! 74: return true;
! 75: } /* Zip_InitConn */
! 76:
! 77:
! 78: /**
! 79: * Copy data to the compression buffer of a connection. We do collect
! 80: * some data there until it's full so that we can achieve better
! 81: * compression ratios.
! 82: * If the (pre-)compression buffer is full, we try to flush it ("actually
! 83: * compress some data") and to add the new (uncompressed) data afterwards.
! 84: * This function closes the connection on error.
! 85: * @param Idx Connection handle.
! 86: * @param Data Pointer to the data.
! 87: * @param Len Length of the data to add.
! 88: * @return true on success, false otherwise.
! 89: */
! 90: GLOBAL bool
! 91: Zip_Buffer( CONN_ID Idx, const char *Data, size_t Len )
! 92: {
! 93: size_t buflen;
! 94:
! 95: assert( Idx > NONE );
! 96: assert( Data != NULL );
! 97: assert( Len > 0 );
! 98:
! 99: buflen = array_bytes(&My_Connections[Idx].zip.wbuf);
! 100: if (buflen + Len >= WRITEBUFFER_SLINK_LEN) {
! 101: /* compression buffer is full, flush */
! 102: if( ! Zip_Flush( Idx )) return false;
! 103: }
! 104:
! 105: /* check again; if zip buf is still too large do not append data:
! 106: * otherwise the zip wbuf would grow too large */
! 107: buflen = array_bytes(&My_Connections[Idx].zip.wbuf);
! 108: if (buflen + Len >= WRITEBUFFER_SLINK_LEN) {
! 109: Log(LOG_ALERT, "Zip Write buffer space exhausted: %lu bytes", buflen + Len);
! 110: Conn_Close(Idx, "Zip Write buffer space exhausted", NULL, false);
! 111: return false;
! 112: }
! 113: return array_catb(&My_Connections[Idx].zip.wbuf, Data, Len);
! 114: } /* Zip_Buffer */
! 115:
! 116:
! 117: /**
! 118: * Compress data in ZIP buffer and move result to the write buffer of
! 119: * the connection.
! 120: * This function closes the connection on error.
! 121: * @param Idx Connection handle.
! 122: * @return true on success, false otherwise.
! 123: */
! 124: GLOBAL bool
! 125: Zip_Flush( CONN_ID Idx )
! 126: {
! 127: int result;
! 128: unsigned char zipbuf[WRITEBUFFER_SLINK_LEN];
! 129: int zipbuf_used = 0;
! 130: z_stream *out;
! 131:
! 132: out = &My_Connections[Idx].zip.out;
! 133:
! 134: out->avail_in = (uInt)array_bytes(&My_Connections[Idx].zip.wbuf);
! 135: if (!out->avail_in)
! 136: return true; /* nothing to do. */
! 137:
! 138: out->next_in = array_start(&My_Connections[Idx].zip.wbuf);
! 139: assert(out->next_in != NULL);
! 140:
! 141: out->next_out = zipbuf;
! 142: out->avail_out = (uInt)sizeof zipbuf;
! 143:
! 144: #if DEBUG_ZIP
! 145: Log(LOG_DEBUG, "out->avail_in %d, out->avail_out %d",
! 146: out->avail_in, out->avail_out);
! 147: #endif
! 148: result = deflate( out, Z_SYNC_FLUSH );
! 149: if(( result != Z_OK ) || ( out->avail_in > 0 ))
! 150: {
! 151: Log( LOG_ALERT, "Compression error: code %d!?", result );
! 152: Conn_Close( Idx, "Compression error!", NULL, false );
! 153: return false;
! 154: }
! 155:
! 156: if (out->avail_out <= 0) {
! 157: /* Not all data was compressed, because data became
! 158: * bigger while compressing it. */
! 159: Log(LOG_ALERT, "Compression error: buffer overflow!?");
! 160: Conn_Close(Idx, "Compression error!", NULL, false);
! 161: return false;
! 162: }
! 163:
! 164: assert(out->avail_out <= WRITEBUFFER_SLINK_LEN);
! 165:
! 166: zipbuf_used = WRITEBUFFER_SLINK_LEN - out->avail_out;
! 167: #if DEBUG_ZIP
! 168: Log(LOG_DEBUG, "zipbuf_used: %d", zipbuf_used);
! 169: #endif
! 170: if (!array_catb(&My_Connections[Idx].wbuf,
! 171: (char *)zipbuf, (size_t) zipbuf_used)) {
! 172: Log (LOG_ALERT, "Compression error: can't copy data!?");
! 173: Conn_Close(Idx, "Compression error!", NULL, false);
! 174: return false;
! 175: }
! 176:
! 177: My_Connections[Idx].bytes_out += zipbuf_used;
! 178: My_Connections[Idx].zip.bytes_out += array_bytes(&My_Connections[Idx].zip.wbuf);
! 179: array_trunc(&My_Connections[Idx].zip.wbuf);
! 180:
! 181: return true;
! 182: } /* Zip_Flush */
! 183:
! 184:
! 185: /**
! 186: * uncompress data and copy it to read buffer.
! 187: * Returns true if data has been unpacked or no
! 188: * compressed data is currently pending in the zread buffer.
! 189: * This function closes the connection on error.
! 190: * @param Idx Connection handle.
! 191: * @return true on success, false otherwise.
! 192: */
! 193: GLOBAL bool
! 194: Unzip_Buffer( CONN_ID Idx )
! 195: {
! 196: int result;
! 197: unsigned char unzipbuf[READBUFFER_LEN];
! 198: int unzipbuf_used = 0;
! 199: unsigned int z_rdatalen;
! 200: unsigned int in_len;
! 201:
! 202: z_stream *in;
! 203:
! 204: assert( Idx > NONE );
! 205:
! 206: z_rdatalen = (unsigned int)array_bytes(&My_Connections[Idx].zip.rbuf);
! 207: if (z_rdatalen == 0)
! 208: return true;
! 209:
! 210: in = &My_Connections[Idx].zip.in;
! 211:
! 212: in->next_in = array_start(&My_Connections[Idx].zip.rbuf);
! 213: assert(in->next_in != NULL);
! 214:
! 215: in->avail_in = z_rdatalen;
! 216: in->next_out = unzipbuf;
! 217: in->avail_out = (uInt)sizeof unzipbuf;
! 218:
! 219: #if DEBUG_ZIP
! 220: Log(LOG_DEBUG, "in->avail_in %d, in->avail_out %d",
! 221: in->avail_in, in->avail_out);
! 222: #endif
! 223: result = inflate( in, Z_SYNC_FLUSH );
! 224: if( result != Z_OK )
! 225: {
! 226: Log(LOG_ALERT, "Decompression error: %s (code=%d, ni=%d, ai=%d, no=%d, ao=%d)!?", in->msg, result, in->next_in, in->avail_in, in->next_out, in->avail_out);
! 227: Conn_Close(Idx, "Decompression error!", NULL, false);
! 228: return false;
! 229: }
! 230:
! 231: assert(z_rdatalen >= in->avail_in);
! 232: in_len = z_rdatalen - in->avail_in;
! 233: unzipbuf_used = READBUFFER_LEN - in->avail_out;
! 234: #if DEBUG_ZIP
! 235: Log(LOG_DEBUG, "unzipbuf_used: %d - %d = %d", READBUFFER_LEN,
! 236: in->avail_out, unzipbuf_used);
! 237: #endif
! 238: assert(unzipbuf_used <= READBUFFER_LEN);
! 239: if (!array_catb(&My_Connections[Idx].rbuf, (char*) unzipbuf,
! 240: (size_t)unzipbuf_used)) {
! 241: Log (LOG_ALERT, "Decompression error: can't copy data!?");
! 242: Conn_Close(Idx, "Decompression error!", NULL, false);
! 243: return false;
! 244: }
! 245: if( in->avail_in > 0 ) {
! 246: array_moveleft(&My_Connections[Idx].zip.rbuf, 1, in_len );
! 247: } else {
! 248: array_trunc( &My_Connections[Idx].zip.rbuf );
! 249: My_Connections[Idx].zip.bytes_in += unzipbuf_used;
! 250: }
! 251:
! 252: return true;
! 253: } /* Unzip_Buffer */
! 254:
! 255:
! 256: /**
! 257: * @param Idx Connection handle.
! 258: * @return amount of sent (compressed) bytes
! 259: */
! 260: GLOBAL long
! 261: Zip_SendBytes( CONN_ID Idx )
! 262: {
! 263: assert( Idx > NONE );
! 264: return My_Connections[Idx].zip.bytes_out;
! 265: } /* Zip_SendBytes */
! 266:
! 267:
! 268: /**
! 269: * @param Idx Connection handle.
! 270: * @return amount of received (compressed) bytes
! 271: */
! 272: GLOBAL long
! 273: Zip_RecvBytes( CONN_ID Idx )
! 274: {
! 275: assert( Idx > NONE );
! 276: return My_Connections[Idx].zip.bytes_in;
! 277: } /* Zip_RecvBytes */
! 278:
! 279:
! 280: #endif
! 281:
! 282:
! 283: /* -eof- */
CVSweb