Home | History | Annotate | Line # | Download | only in test
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