regress_zlib.c revision 1.1.1.1.6.1 1 /* $NetBSD: regress_zlib.c,v 1.1.1.1.6.1 2014/12/24 00:05:26 riz Exp $ */
2
3 /*
4 * Copyright (c) 2008-2012 Niels Provos and Nick Mathewson
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /* The old tests here need assertions to work. */
30 #undef NDEBUG
31
32 #ifdef _WIN32
33 #include <winsock2.h>
34 #include <windows.h>
35 #endif
36
37 #include "event2/event-config.h"
38
39 #include <sys/types.h>
40 #ifndef _WIN32
41 #include <sys/socket.h>
42 #include <sys/wait.h>
43 #include <unistd.h>
44 #include <netdb.h>
45 #endif
46 #include <signal.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50
51 #include <assert.h>
52 #include <errno.h>
53
54 #include "event2/util.h"
55 #include "event2/event.h"
56 #include "event2/event_compat.h"
57 #include "event2/buffer.h"
58 #include "event2/bufferevent.h"
59
60 #include "regress.h"
61
62 /* zlib 1.2.4 and 1.2.5 do some "clever" things with macros. Instead of
63 saying "(defined(FOO) ? FOO : 0)" they like to say "FOO-0", on the theory
64 that nobody will care if the compile outputs a no-such-identifier warning.
65
66 Sorry, but we like -Werror over here, so I guess we need to define these.
67 I hope that zlib 1.2.6 doesn't break these too.
68 */
69 #ifndef _LARGEFILE64_SOURCE
70 #define _LARGEFILE64_SOURCE 0
71 #endif
72 #ifndef _LFS64_LARGEFILE
73 #define _LFS64_LARGEFILE 0
74 #endif
75 #ifndef _FILE_OFFSET_BITS
76 #define _FILE_OFFSET_BITS 0
77 #endif
78 #ifndef off64_t
79 #define off64_t ev_int64_t
80 #endif
81
82 #include <zlib.h>
83
84 static int infilter_calls;
85 static int outfilter_calls;
86 static int readcb_finished;
87 static int writecb_finished;
88 static int errorcb_invoked;
89
90 /*
91 * Zlib filters
92 */
93
94 static void
95 zlib_deflate_free(void *ctx)
96 {
97 z_streamp p = ctx;
98
99 assert(deflateEnd(p) == Z_OK);
100 }
101
102 static void
103 zlib_inflate_free(void *ctx)
104 {
105 z_streamp p = ctx;
106
107 assert(inflateEnd(p) == Z_OK);
108 }
109
110 static int
111 getstate(enum bufferevent_flush_mode state)
112 {
113 switch (state) {
114 case BEV_FINISHED:
115 return Z_FINISH;
116 case BEV_FLUSH:
117 return Z_SYNC_FLUSH;
118 case BEV_NORMAL:
119 default:
120 return Z_NO_FLUSH;
121 }
122 }
123
124 /*
125 * The input filter is triggered only on new input read from the network.
126 * That means all input data needs to be consumed or the filter needs to
127 * initiate its own triggering via a timeout.
128 */
129 static enum bufferevent_filter_result
130 zlib_input_filter(struct evbuffer *src, struct evbuffer *dst,
131 ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx)
132 {
133 struct evbuffer_iovec v_in[1];
134 struct evbuffer_iovec v_out[1];
135 int nread, nwrite;
136 int res, n;
137
138 z_streamp p = ctx;
139
140 do {
141 /* let's do some decompression */
142 n = evbuffer_peek(src, -1, NULL, v_in, 1);
143 if (n) {
144 p->avail_in = v_in[0].iov_len;
145 p->next_in = v_in[0].iov_base;
146 } else {
147 p->avail_in = 0;
148 p->next_in = 0;
149 }
150
151 evbuffer_reserve_space(dst, 4096, v_out, 1);
152 p->next_out = v_out[0].iov_base;
153 p->avail_out = v_out[0].iov_len;
154
155 /* we need to flush zlib if we got a flush */
156 res = inflate(p, getstate(state));
157
158 /* let's figure out how much was compressed */
159 nread = v_in[0].iov_len - p->avail_in;
160 nwrite = v_out[0].iov_len - p->avail_out;
161
162 evbuffer_drain(src, nread);
163 v_out[0].iov_len = nwrite;
164 evbuffer_commit_space(dst, v_out, 1);
165
166 if (res==Z_BUF_ERROR) {
167 /* We're out of space, or out of decodeable input.
168 Only if nwrite == 0 assume the latter.
169 */
170 if (nwrite == 0)
171 return BEV_NEED_MORE;
172 } else {
173 assert(res == Z_OK || res == Z_STREAM_END);
174 }
175
176 } while (evbuffer_get_length(src) > 0);
177
178 ++infilter_calls;
179
180 return (BEV_OK);
181 }
182
183 static enum bufferevent_filter_result
184 zlib_output_filter(struct evbuffer *src, struct evbuffer *dst,
185 ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx)
186 {
187 struct evbuffer_iovec v_in[1];
188 struct evbuffer_iovec v_out[1];
189 int nread, nwrite;
190 int res, n;
191
192 z_streamp p = ctx;
193
194 do {
195 /* let's do some compression */
196 n = evbuffer_peek(src, -1, NULL, v_in, 1);
197 if (n) {
198 p->avail_in = v_in[0].iov_len;
199 p->next_in = v_in[0].iov_base;
200 } else {
201 p->avail_in = 0;
202 p->next_in = 0;
203 }
204
205 evbuffer_reserve_space(dst, 4096, v_out, 1);
206 p->next_out = v_out[0].iov_base;
207 p->avail_out = v_out[0].iov_len;
208
209 /* we need to flush zlib if we got a flush */
210 res = deflate(p, getstate(state));
211
212 /* let's figure out how much was decompressed */
213 nread = v_in[0].iov_len - p->avail_in;
214 nwrite = v_out[0].iov_len - p->avail_out;
215
216 evbuffer_drain(src, nread);
217 v_out[0].iov_len = nwrite;
218 evbuffer_commit_space(dst, v_out, 1);
219
220 if (res==Z_BUF_ERROR) {
221 /* We're out of space, or out of decodeable input.
222 Only if nwrite == 0 assume the latter.
223 */
224 if (nwrite == 0)
225 return BEV_NEED_MORE;
226 } else {
227 assert(res == Z_OK || res == Z_STREAM_END);
228 }
229
230 } while (evbuffer_get_length(src) > 0);
231
232 ++outfilter_calls;
233
234 return (BEV_OK);
235 }
236
237 /*
238 * simple bufferevent test (over transparent zlib treatment)
239 */
240
241 static void
242 readcb(struct bufferevent *bev, void *arg)
243 {
244 if (evbuffer_get_length(bufferevent_get_input(bev)) == 8333) {
245 struct evbuffer *evbuf = evbuffer_new();
246 assert(evbuf != NULL);
247
248 /* gratuitous test of bufferevent_read_buffer */
249 bufferevent_read_buffer(bev, evbuf);
250
251 bufferevent_disable(bev, EV_READ);
252
253 if (evbuffer_get_length(evbuf) == 8333) {
254 ++readcb_finished;
255 }
256
257 evbuffer_free(evbuf);
258 }
259 }
260
261 static void
262 writecb(struct bufferevent *bev, void *arg)
263 {
264 if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
265 ++writecb_finished;
266 }
267 }
268
269 static void
270 errorcb(struct bufferevent *bev, short what, void *arg)
271 {
272 errorcb_invoked = 1;
273 }
274
275 void
276 test_bufferevent_zlib(void *arg)
277 {
278 struct bufferevent *bev1=NULL, *bev2=NULL;
279 char buffer[8333];
280 z_stream z_input, z_output;
281 int i, r;
282 evutil_socket_t pair[2] = {-1, -1};
283 (void)arg;
284
285 infilter_calls = outfilter_calls = readcb_finished = writecb_finished
286 = errorcb_invoked = 0;
287
288 if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
289 tt_abort_perror("socketpair");
290 }
291
292 evutil_make_socket_nonblocking(pair[0]);
293 evutil_make_socket_nonblocking(pair[1]);
294
295 bev1 = bufferevent_socket_new(NULL, pair[0], 0);
296 bev2 = bufferevent_socket_new(NULL, pair[1], 0);
297
298 memset(&z_output, 0, sizeof(z_output));
299 r = deflateInit(&z_output, Z_DEFAULT_COMPRESSION);
300 tt_int_op(r, ==, Z_OK);
301 memset(&z_input, 0, sizeof(z_input));
302 r = inflateInit(&z_input);
303 tt_int_op(r, ==, Z_OK);
304
305 /* initialize filters */
306 bev1 = bufferevent_filter_new(bev1, NULL, zlib_output_filter,
307 BEV_OPT_CLOSE_ON_FREE, zlib_deflate_free, &z_output);
308 bev2 = bufferevent_filter_new(bev2, zlib_input_filter,
309 NULL, BEV_OPT_CLOSE_ON_FREE, zlib_inflate_free, &z_input);
310 bufferevent_setcb(bev1, readcb, writecb, errorcb, NULL);
311 bufferevent_setcb(bev2, readcb, writecb, errorcb, NULL);
312
313 bufferevent_disable(bev1, EV_READ);
314 bufferevent_enable(bev1, EV_WRITE);
315
316 bufferevent_enable(bev2, EV_READ);
317
318 for (i = 0; i < (int)sizeof(buffer); i++)
319 buffer[i] = i;
320
321 /* break it up into multiple buffer chains */
322 bufferevent_write(bev1, buffer, 1800);
323 bufferevent_write(bev1, buffer + 1800, sizeof(buffer) - 1800);
324
325 /* we are done writing - we need to flush everything */
326 bufferevent_flush(bev1, EV_WRITE, BEV_FINISHED);
327
328 event_dispatch();
329
330 tt_want(infilter_calls);
331 tt_want(outfilter_calls);
332 tt_want(readcb_finished);
333 tt_want(writecb_finished);
334 tt_want(!errorcb_invoked);
335
336 test_ok = 1;
337 end:
338 if (bev1)
339 bufferevent_free(bev1);
340 if (bev2)
341 bufferevent_free(bev2);
342
343 if (pair[0] >= 0)
344 evutil_closesocket(pair[0]);
345 if (pair[1] >= 0)
346 evutil_closesocket(pair[1]);
347 }
348