Annotation of ircnowd/src/ngircd/conn-zip.c, Revision 1.1.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