]>
Commit | Line | Data |
---|---|---|
3bd189cb JR |
1 | /************************************************************************ |
2 | * IRC - Internet Relay Chat, ircd/s_zip.c | |
3 | * Copyright (C) 1996 Christophe Kalt | |
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 1, or (at your option) | |
8 | * any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program; if not, write to the Free Software | |
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
18 | */ | |
19 | ||
20 | #ifndef lint | |
21 | static const volatile char rcsid[] = "@(#)$Id: s_zip.c,v 1.12 2005/02/20 23:09:45 chopin Exp $"; | |
22 | #endif | |
23 | ||
24 | #include "os.h" | |
25 | #include "s_defines.h" | |
26 | #define S_ZIP_C | |
27 | #include "s_externs.h" | |
28 | #undef S_ZIP_C | |
29 | ||
30 | #ifdef ZIP_LINKS | |
31 | ||
32 | /* | |
33 | ** Important note: | |
34 | ** The provided buffers for compression *MUST* be big | |
35 | ** enough for any operation to complete. | |
36 | ** | |
37 | ** s_bsd.c current settings are that the biggest packet size is 16k | |
38 | ** (but socket buffers are set to 8k..) | |
39 | */ | |
40 | ||
41 | /* | |
42 | ** size of the buffer holding compressed data | |
43 | ** | |
44 | ** outgoing data: | |
45 | ** must be enough to hold compressed data resulting of the compression | |
46 | ** of up to ZIP_MAXIMUM bytes | |
47 | ** incoming data: | |
48 | ** must be enough to hold what was just read | |
49 | ** (cptr->zip->inbuf should never hold more than ONE compression block. | |
50 | ** The biggest block allowed for compression is ZIP_MAXIMUM bytes) | |
51 | */ | |
52 | #define ZIP_BUFFER_SIZE (MAX(ZIP_MAXIMUM, READBUF_SIZE)) | |
53 | ||
54 | /* | |
55 | ** size of the buffer where zlib puts compressed data | |
56 | ** should be enough to hold uncompressed data resulting of the | |
57 | ** uncompression of zipbuffer | |
58 | ** | |
59 | ** tests show that an average ratio is around 40%, | |
60 | ** in some very particular cases, ratio can be VERY low, BUT: | |
61 | ** | |
62 | ** s_bsd.c/read_packet() is now smart enough to detect when uncompression | |
63 | ** stopped because the buffer is too small, and calls dopacket() again | |
64 | ** to finish the work (as many times as needed). | |
65 | */ | |
66 | #define UNZIP_BUFFER_SIZE 4*ZIP_BUFFER_SIZE | |
67 | ||
68 | /* buffers */ | |
69 | static char unzipbuf[UNZIP_BUFFER_SIZE]; | |
70 | static char zipbuf[ZIP_BUFFER_SIZE]; | |
71 | ||
72 | /* | |
73 | ** zip_init | |
74 | ** Initialize compression structures for a server. | |
75 | ** If failed, zip_free() has to be called. | |
76 | */ | |
77 | int zip_init(aClient *cptr) | |
78 | { | |
79 | cptr->zip = (aZdata *) MyMalloc(sizeof(aZdata)); | |
80 | cptr->zip->outcount = 0; | |
81 | ||
82 | cptr->zip->in = (z_stream *) MyMalloc(sizeof(z_stream)); | |
83 | cptr->zip->in->avail_in = 0; | |
84 | cptr->zip->in->total_in = 0; | |
85 | cptr->zip->in->total_out = 0; | |
86 | cptr->zip->in->zalloc = (alloc_func)0; | |
87 | cptr->zip->in->zfree = (free_func)0; | |
88 | cptr->zip->in->data_type = Z_ASCII; | |
89 | if (inflateInit(cptr->zip->in) != Z_OK) | |
90 | { | |
91 | cptr->zip->out = NULL; | |
92 | return -1; | |
93 | } | |
94 | ||
95 | cptr->zip->out = (z_stream *) MyMalloc(sizeof(z_stream)); | |
96 | cptr->zip->out->total_in = 0; | |
97 | cptr->zip->out->total_out = 0; | |
98 | cptr->zip->out->zalloc = (alloc_func)0; | |
99 | cptr->zip->out->zfree = (free_func)0; | |
100 | cptr->zip->out->data_type = Z_ASCII; | |
101 | if (deflateInit(cptr->zip->out, ZIP_LEVEL) != Z_OK) | |
102 | return -1; | |
103 | ||
104 | return 0; | |
105 | } | |
106 | ||
107 | /* | |
108 | ** zip_free | |
109 | */ | |
110 | void zip_free(aClient *cptr) | |
111 | { | |
112 | cptr->flags &= ~FLAGS_ZIP; | |
113 | if (cptr->zip) | |
114 | { | |
115 | if (cptr->zip->in) | |
116 | inflateEnd(cptr->zip->in); | |
117 | MyFree(cptr->zip->in); | |
118 | if (cptr->zip->out) | |
119 | deflateEnd(cptr->zip->out); | |
120 | MyFree(cptr->zip->out); | |
121 | MyFree(cptr->zip); | |
122 | cptr->zip = NULL; | |
123 | } | |
124 | } | |
125 | ||
126 | /* | |
127 | ** unzip_packet | |
128 | ** Unzip the content of the buffer, don't worry about any leftover. | |
129 | ** | |
130 | ** will return the uncompressed buffer, length will be updated. | |
131 | ** if a fatal error occurs, length will be set to -1 | |
132 | */ | |
133 | char *unzip_packet(aClient *cptr, char *buffer, int *length) | |
134 | { | |
135 | Reg z_stream *zin = cptr->zip->in; | |
136 | int r; | |
137 | ||
138 | if (*length != 0 && zin->avail_in != 0) | |
139 | { | |
140 | sendto_flag(SCH_ERROR, | |
141 | "assertion failed in unzip_packet(): %d %d", | |
142 | *length, zin->avail_in); | |
143 | sendto_flag(SCH_ERROR, "Please report to ircd-bugs@irc.org"); | |
144 | *length = -1; | |
145 | return NULL; | |
146 | } | |
147 | if (*length) | |
148 | { | |
149 | zin->next_in = (Bytef *) buffer; | |
150 | zin->avail_in = *length; | |
151 | } | |
152 | zin->next_out = (Bytef *) unzipbuf; | |
153 | zin->avail_out = UNZIP_BUFFER_SIZE; | |
154 | switch (r = inflate(zin, Z_SYNC_FLUSH)) | |
155 | { | |
156 | case Z_OK: | |
157 | cptr->flags &= ~FLAGS_ZIPRQ; | |
158 | *length = UNZIP_BUFFER_SIZE - zin->avail_out; | |
159 | return unzipbuf; | |
160 | ||
161 | case Z_BUF_ERROR: /*no progress possible or output buffer too small*/ | |
162 | if (zin->avail_out == 0) | |
163 | { | |
164 | sendto_flag(SCH_ERROR, | |
165 | "inflate() returned Z_BUF_ERROR: %s", | |
166 | (zin->msg) ? zin->msg : "?"); | |
167 | *length = -1; | |
168 | } | |
169 | break; | |
170 | ||
171 | case Z_DATA_ERROR: /* the buffer might not be compressed.. */ | |
172 | if ((cptr->flags & FLAGS_ZIPRQ) && | |
173 | !strncmp("ERROR ", buffer, 6)) | |
174 | { | |
175 | cptr->flags &= ~(FLAGS_ZIP | FLAGS_ZIPRQ); | |
176 | /* | |
177 | * This is not sane at all. But if other server | |
178 | * has sent an error now, it is probably closing | |
179 | * the link as well. | |
180 | */ | |
181 | return buffer; | |
182 | } | |
183 | ||
184 | /* no break */ | |
185 | ||
186 | default: /* error ! */ | |
187 | /* should probably mark link as dead or something... */ | |
188 | sendto_flag(SCH_ERROR, "inflate() error(%d): %s", r, | |
189 | (zin->msg) ? zin->msg : "?"); | |
190 | *length = -1; /* report error condition */ | |
191 | break; | |
192 | } | |
193 | return NULL; | |
194 | } | |
195 | ||
196 | /* | |
197 | ** zip_buffer | |
198 | ** Zip the content of cptr->zip->outbuf and of the buffer, | |
199 | ** put anything left in cptr->zip->outbuf, update cptr->zip->outcount | |
200 | ** | |
201 | ** if flush is set, then all available data will be compressed, | |
202 | ** otherwise, compression only occurs if there's enough to compress, | |
203 | ** or if we are reaching the maximum allowed size during a connect burst. | |
204 | ** | |
205 | ** will return the uncompressed buffer, length will be updated. | |
206 | ** if a fatal error occurs, length will be set to -1 | |
207 | */ | |
208 | char *zip_buffer(aClient *cptr, char *buffer, int *length, int flush) | |
209 | { | |
210 | Reg z_stream *zout = cptr->zip->out; | |
211 | int r; | |
212 | ||
213 | if (buffer) | |
214 | { | |
215 | /* concatenate buffer in cptr->zip->outbuf */ | |
216 | bcopy(buffer, cptr->zip->outbuf + cptr->zip->outcount,*length); | |
217 | cptr->zip->outcount += *length; | |
218 | } | |
219 | *length = 0; | |
220 | ||
221 | if (!flush && ((cptr->zip->outcount < ZIP_MINIMUM) || | |
222 | ((cptr->zip->outcount < (ZIP_MAXIMUM - BUFSIZE)) && | |
223 | CBurst(cptr)))) | |
224 | return NULL; | |
225 | ||
226 | zout->next_in = cptr->zip->outbuf; | |
227 | zout->avail_in = cptr->zip->outcount; | |
228 | zout->next_out = (Bytef *) zipbuf; | |
229 | zout->avail_out = ZIP_BUFFER_SIZE; | |
230 | ||
231 | switch (r = deflate(zout, Z_SYNC_FLUSH)) | |
232 | { | |
233 | case Z_OK: | |
234 | if (zout->avail_in) | |
235 | { | |
236 | /* can this occur?? I hope not... */ | |
237 | sendto_flag(SCH_ERROR, | |
238 | "deflate() didn't process all available data!"); | |
239 | } | |
240 | cptr->zip->outcount = 0; | |
241 | *length = ZIP_BUFFER_SIZE - zout->avail_out; | |
242 | return zipbuf; | |
243 | ||
244 | default: /* error ! */ | |
245 | sendto_flag(SCH_ERROR, "deflate() error(%d): %s", r, | |
246 | (zout->msg) ? zout->msg : "?"); | |
247 | *length = -1; | |
248 | break; | |
249 | } | |
250 | return NULL; | |
251 | } | |
252 | ||
253 | #endif /* ZIP_LINKS */ | |
254 |