xref: /netbsd-src/external/bsd/ntp/dist/sntp/libevent/test/regress_zlib.c (revision eabc0478de71e4e011a5b4e0392741e01d491794)
1*eabc0478Schristos /*	$NetBSD: regress_zlib.c,v 1.7 2024/08/18 20:47:23 christos Exp $	*/
28585484eSchristos 
38585484eSchristos /*
48585484eSchristos  * Copyright (c) 2008-2012 Niels Provos and Nick Mathewson
58585484eSchristos  *
68585484eSchristos  * Redistribution and use in source and binary forms, with or without
78585484eSchristos  * modification, are permitted provided that the following conditions
88585484eSchristos  * are met:
98585484eSchristos  * 1. Redistributions of source code must retain the above copyright
108585484eSchristos  *    notice, this list of conditions and the following disclaimer.
118585484eSchristos  * 2. Redistributions in binary form must reproduce the above copyright
128585484eSchristos  *    notice, this list of conditions and the following disclaimer in the
138585484eSchristos  *    documentation and/or other materials provided with the distribution.
148585484eSchristos  * 3. The name of the author may not be used to endorse or promote products
158585484eSchristos  *    derived from this software without specific prior written permission.
168585484eSchristos  *
178585484eSchristos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
188585484eSchristos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
198585484eSchristos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
208585484eSchristos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
218585484eSchristos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
228585484eSchristos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
238585484eSchristos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
248585484eSchristos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
258585484eSchristos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
268585484eSchristos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
278585484eSchristos  */
288585484eSchristos 
298585484eSchristos /* The old tests here need assertions to work. */
308585484eSchristos #undef NDEBUG
318585484eSchristos 
328585484eSchristos #ifdef _WIN32
338585484eSchristos #include <winsock2.h>
348585484eSchristos #include <windows.h>
358585484eSchristos #endif
368585484eSchristos 
378585484eSchristos #include "event2/event-config.h"
388585484eSchristos 
398585484eSchristos #include <sys/types.h>
408585484eSchristos #ifndef _WIN32
418585484eSchristos #include <sys/socket.h>
428585484eSchristos #include <sys/wait.h>
438585484eSchristos #include <unistd.h>
448585484eSchristos #include <netdb.h>
458585484eSchristos #endif
468585484eSchristos #include <signal.h>
478585484eSchristos #include <stdio.h>
488585484eSchristos #include <stdlib.h>
498585484eSchristos #include <string.h>
508585484eSchristos 
518585484eSchristos #include <assert.h>
528585484eSchristos #include <errno.h>
538585484eSchristos 
548585484eSchristos #include "event2/util.h"
558585484eSchristos #include "event2/event.h"
568585484eSchristos #include "event2/event_compat.h"
578585484eSchristos #include "event2/buffer.h"
588585484eSchristos #include "event2/bufferevent.h"
598585484eSchristos 
608585484eSchristos #include "regress.h"
617476e6e4Schristos #include "mm-internal.h"
628585484eSchristos 
638585484eSchristos /* zlib 1.2.4 and 1.2.5 do some "clever" things with macros.  Instead of
648585484eSchristos    saying "(defined(FOO) ? FOO : 0)" they like to say "FOO-0", on the theory
658585484eSchristos    that nobody will care if the compile outputs a no-such-identifier warning.
668585484eSchristos 
678585484eSchristos    Sorry, but we like -Werror over here, so I guess we need to define these.
688585484eSchristos    I hope that zlib 1.2.6 doesn't break these too.
698585484eSchristos */
708585484eSchristos #ifndef _LARGEFILE64_SOURCE
718585484eSchristos #define _LARGEFILE64_SOURCE 0
728585484eSchristos #endif
738585484eSchristos #ifndef _LFS64_LARGEFILE
748585484eSchristos #define _LFS64_LARGEFILE 0
758585484eSchristos #endif
768585484eSchristos #ifndef _FILE_OFFSET_BITS
778585484eSchristos #define _FILE_OFFSET_BITS 0
788585484eSchristos #endif
798585484eSchristos #ifndef off64_t
808585484eSchristos #define off64_t ev_int64_t
818585484eSchristos #endif
828585484eSchristos 
838585484eSchristos #include <zlib.h>
848585484eSchristos 
858585484eSchristos static int infilter_calls;
868585484eSchristos static int outfilter_calls;
878585484eSchristos static int readcb_finished;
888585484eSchristos static int writecb_finished;
898585484eSchristos static int errorcb_invoked;
908585484eSchristos 
918585484eSchristos /*
928585484eSchristos  * Zlib filters
938585484eSchristos  */
948585484eSchristos 
958585484eSchristos static void
968585484eSchristos zlib_deflate_free(void *ctx)
978585484eSchristos {
988585484eSchristos 	z_streamp p = ctx;
998585484eSchristos 
1008585484eSchristos 	assert(deflateEnd(p) == Z_OK);
1017476e6e4Schristos 	mm_free(p);
1028585484eSchristos }
1038585484eSchristos 
1048585484eSchristos static void
1058585484eSchristos zlib_inflate_free(void *ctx)
1068585484eSchristos {
1078585484eSchristos 	z_streamp p = ctx;
1088585484eSchristos 
1098585484eSchristos 	assert(inflateEnd(p) == Z_OK);
1107476e6e4Schristos 	mm_free(p);
1118585484eSchristos }
1128585484eSchristos 
1138585484eSchristos static int
1148585484eSchristos getstate(enum bufferevent_flush_mode state)
1158585484eSchristos {
1168585484eSchristos 	switch (state) {
1178585484eSchristos 	case BEV_FINISHED:
1188585484eSchristos 		return Z_FINISH;
1198585484eSchristos 	case BEV_FLUSH:
1208585484eSchristos 		return Z_SYNC_FLUSH;
1218585484eSchristos 	case BEV_NORMAL:
1228585484eSchristos 	default:
1238585484eSchristos 		return Z_NO_FLUSH;
1248585484eSchristos 	}
1258585484eSchristos }
1268585484eSchristos 
1278585484eSchristos /*
1288585484eSchristos  * The input filter is triggered only on new input read from the network.
1298585484eSchristos  * That means all input data needs to be consumed or the filter needs to
1308585484eSchristos  * initiate its own triggering via a timeout.
1318585484eSchristos  */
1328585484eSchristos static enum bufferevent_filter_result
1338585484eSchristos zlib_input_filter(struct evbuffer *src, struct evbuffer *dst,
1348585484eSchristos     ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx)
1358585484eSchristos {
1368585484eSchristos 	struct evbuffer_iovec v_in[1];
1378585484eSchristos 	struct evbuffer_iovec v_out[1];
1388585484eSchristos 	int nread, nwrite;
1398585484eSchristos 	int res, n;
1408585484eSchristos 
1418585484eSchristos 	z_streamp p = ctx;
1428585484eSchristos 
1438585484eSchristos 	do {
1448585484eSchristos 		/* let's do some decompression */
1458585484eSchristos 		n = evbuffer_peek(src, -1, NULL, v_in, 1);
1468585484eSchristos 		if (n) {
1478585484eSchristos 			p->avail_in = v_in[0].iov_len;
148*eabc0478Schristos 			p->next_in = (unsigned char *)v_in[0].iov_base;
1498585484eSchristos 		} else {
1508585484eSchristos 			p->avail_in = 0;
1518585484eSchristos 			p->next_in = 0;
1528585484eSchristos 		}
1538585484eSchristos 
1548585484eSchristos 		evbuffer_reserve_space(dst, 4096, v_out, 1);
155*eabc0478Schristos 		p->next_out = (unsigned char *)v_out[0].iov_base;
1568585484eSchristos 		p->avail_out = v_out[0].iov_len;
1578585484eSchristos 
1588585484eSchristos 		/* we need to flush zlib if we got a flush */
1598585484eSchristos 		res = inflate(p, getstate(state));
1608585484eSchristos 
1618585484eSchristos 		/* let's figure out how much was compressed */
1628585484eSchristos 		nread = v_in[0].iov_len - p->avail_in;
1638585484eSchristos 		nwrite = v_out[0].iov_len - p->avail_out;
1648585484eSchristos 
1658585484eSchristos 		evbuffer_drain(src, nread);
1668585484eSchristos 		v_out[0].iov_len = nwrite;
1678585484eSchristos 		evbuffer_commit_space(dst, v_out, 1);
1688585484eSchristos 
1698585484eSchristos 		if (res==Z_BUF_ERROR) {
1708585484eSchristos 			/* We're out of space, or out of decodeable input.
1718585484eSchristos 			   Only if nwrite == 0 assume the latter.
1728585484eSchristos 			 */
1738585484eSchristos 			if (nwrite == 0)
1748585484eSchristos 				return BEV_NEED_MORE;
1758585484eSchristos 		} else {
1768585484eSchristos 			assert(res == Z_OK || res == Z_STREAM_END);
1778585484eSchristos 		}
1788585484eSchristos 
1798585484eSchristos 	} while (evbuffer_get_length(src) > 0);
1808585484eSchristos 
1818585484eSchristos 	++infilter_calls;
1828585484eSchristos 
1838585484eSchristos 	return (BEV_OK);
1848585484eSchristos }
1858585484eSchristos 
1868585484eSchristos static enum bufferevent_filter_result
1878585484eSchristos zlib_output_filter(struct evbuffer *src, struct evbuffer *dst,
1888585484eSchristos     ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx)
1898585484eSchristos {
1908585484eSchristos 	struct evbuffer_iovec v_in[1];
1918585484eSchristos 	struct evbuffer_iovec v_out[1];
1928585484eSchristos 	int nread, nwrite;
1938585484eSchristos 	int res, n;
1948585484eSchristos 
1958585484eSchristos 	z_streamp p = ctx;
1968585484eSchristos 
1978585484eSchristos 	do {
1988585484eSchristos 		/* let's do some compression */
1998585484eSchristos 		n = evbuffer_peek(src, -1, NULL, v_in, 1);
2008585484eSchristos 		if (n) {
2018585484eSchristos 			p->avail_in = v_in[0].iov_len;
202*eabc0478Schristos 			p->next_in = (unsigned char *)v_in[0].iov_base;
2038585484eSchristos 		} else {
2048585484eSchristos 			p->avail_in = 0;
2058585484eSchristos 			p->next_in = 0;
2068585484eSchristos 		}
2078585484eSchristos 
2088585484eSchristos 		evbuffer_reserve_space(dst, 4096, v_out, 1);
209*eabc0478Schristos 		p->next_out = (unsigned char *)v_out[0].iov_base;
2108585484eSchristos 		p->avail_out = v_out[0].iov_len;
2118585484eSchristos 
2128585484eSchristos 		/* we need to flush zlib if we got a flush */
2138585484eSchristos 		res = deflate(p, getstate(state));
2148585484eSchristos 
2158585484eSchristos 		/* let's figure out how much was decompressed */
2168585484eSchristos 		nread = v_in[0].iov_len - p->avail_in;
2178585484eSchristos 		nwrite = v_out[0].iov_len - p->avail_out;
2188585484eSchristos 
2198585484eSchristos 		evbuffer_drain(src, nread);
2208585484eSchristos 		v_out[0].iov_len = nwrite;
2218585484eSchristos 		evbuffer_commit_space(dst, v_out, 1);
2228585484eSchristos 
2238585484eSchristos 		if (res==Z_BUF_ERROR) {
2248585484eSchristos 			/* We're out of space, or out of decodeable input.
2258585484eSchristos 			   Only if nwrite == 0 assume the latter.
2268585484eSchristos 			 */
2278585484eSchristos 			if (nwrite == 0)
2288585484eSchristos 				return BEV_NEED_MORE;
2298585484eSchristos 		} else {
2308585484eSchristos 			assert(res == Z_OK || res == Z_STREAM_END);
2318585484eSchristos 		}
2328585484eSchristos 
2338585484eSchristos 	} while (evbuffer_get_length(src) > 0);
2348585484eSchristos 
2358585484eSchristos 	++outfilter_calls;
2368585484eSchristos 
2378585484eSchristos 	return (BEV_OK);
2388585484eSchristos }
2398585484eSchristos 
2408585484eSchristos /*
2418585484eSchristos  * simple bufferevent test (over transparent zlib treatment)
2428585484eSchristos  */
2438585484eSchristos 
2448585484eSchristos static void
2458585484eSchristos readcb(struct bufferevent *bev, void *arg)
2468585484eSchristos {
2478585484eSchristos 	if (evbuffer_get_length(bufferevent_get_input(bev)) == 8333) {
2488585484eSchristos 		struct evbuffer *evbuf = evbuffer_new();
2498585484eSchristos 		assert(evbuf != NULL);
2508585484eSchristos 
2518585484eSchristos 		/* gratuitous test of bufferevent_read_buffer */
2528585484eSchristos 		bufferevent_read_buffer(bev, evbuf);
2538585484eSchristos 
2548585484eSchristos 		bufferevent_disable(bev, EV_READ);
2558585484eSchristos 
2568585484eSchristos 		if (evbuffer_get_length(evbuf) == 8333) {
2578585484eSchristos 			++readcb_finished;
2588585484eSchristos 		}
2598585484eSchristos 
2608585484eSchristos 		evbuffer_free(evbuf);
2618585484eSchristos 	}
2628585484eSchristos }
2638585484eSchristos 
2648585484eSchristos static void
2658585484eSchristos writecb(struct bufferevent *bev, void *arg)
2668585484eSchristos {
2678585484eSchristos 	if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
2688585484eSchristos 		++writecb_finished;
2698585484eSchristos 	}
2708585484eSchristos }
2718585484eSchristos 
2728585484eSchristos static void
2738585484eSchristos errorcb(struct bufferevent *bev, short what, void *arg)
2748585484eSchristos {
2758585484eSchristos 	errorcb_invoked = 1;
2768585484eSchristos }
2778585484eSchristos 
2788585484eSchristos void
2798585484eSchristos test_bufferevent_zlib(void *arg)
2808585484eSchristos {
2818585484eSchristos 	struct bufferevent *bev1=NULL, *bev2=NULL;
2828585484eSchristos 	char buffer[8333];
2837476e6e4Schristos 	z_stream *z_input, *z_output;
2848585484eSchristos 	int i, r;
2858585484eSchristos 	evutil_socket_t pair[2] = {-1, -1};
2868585484eSchristos 	(void)arg;
2878585484eSchristos 
2888585484eSchristos 	infilter_calls = outfilter_calls = readcb_finished = writecb_finished
2898585484eSchristos 	    = errorcb_invoked = 0;
2908585484eSchristos 
2918585484eSchristos 	if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
2928585484eSchristos 		tt_abort_perror("socketpair");
2938585484eSchristos 	}
2948585484eSchristos 
2958585484eSchristos 	evutil_make_socket_nonblocking(pair[0]);
2968585484eSchristos 	evutil_make_socket_nonblocking(pair[1]);
2978585484eSchristos 
2988585484eSchristos 	bev1 = bufferevent_socket_new(NULL, pair[0], 0);
2998585484eSchristos 	bev2 = bufferevent_socket_new(NULL, pair[1], 0);
3008585484eSchristos 
3017476e6e4Schristos 	z_output = mm_calloc(sizeof(*z_output), 1);
3027476e6e4Schristos 	r = deflateInit(z_output, Z_DEFAULT_COMPRESSION);
3038585484eSchristos 	tt_int_op(r, ==, Z_OK);
3047476e6e4Schristos 	z_input = mm_calloc(sizeof(*z_input), 1);
3057476e6e4Schristos 	r = inflateInit(z_input);
3068585484eSchristos 	tt_int_op(r, ==, Z_OK);
3078585484eSchristos 
3088585484eSchristos 	/* initialize filters */
3098585484eSchristos 	bev1 = bufferevent_filter_new(bev1, NULL, zlib_output_filter,
3107476e6e4Schristos 	    BEV_OPT_CLOSE_ON_FREE, zlib_deflate_free, z_output);
3118585484eSchristos 	bev2 = bufferevent_filter_new(bev2, zlib_input_filter,
3127476e6e4Schristos 	    NULL, BEV_OPT_CLOSE_ON_FREE, zlib_inflate_free, z_input);
3138585484eSchristos 	bufferevent_setcb(bev1, readcb, writecb, errorcb, NULL);
3148585484eSchristos 	bufferevent_setcb(bev2, readcb, writecb, errorcb, NULL);
3158585484eSchristos 
3168585484eSchristos 	bufferevent_disable(bev1, EV_READ);
3178585484eSchristos 	bufferevent_enable(bev1, EV_WRITE);
3188585484eSchristos 
3198585484eSchristos 	bufferevent_enable(bev2, EV_READ);
3208585484eSchristos 
3218585484eSchristos 	for (i = 0; i < (int)sizeof(buffer); i++)
3228585484eSchristos 		buffer[i] = i;
3238585484eSchristos 
3248585484eSchristos 	/* break it up into multiple buffer chains */
3258585484eSchristos 	bufferevent_write(bev1, buffer, 1800);
3268585484eSchristos 	bufferevent_write(bev1, buffer + 1800, sizeof(buffer) - 1800);
3278585484eSchristos 
3288585484eSchristos 	/* we are done writing - we need to flush everything */
3298585484eSchristos 	bufferevent_flush(bev1, EV_WRITE, BEV_FINISHED);
3308585484eSchristos 
3318585484eSchristos 	event_dispatch();
3328585484eSchristos 
3338585484eSchristos 	tt_want(infilter_calls);
3348585484eSchristos 	tt_want(outfilter_calls);
3358585484eSchristos 	tt_want(readcb_finished);
3368585484eSchristos 	tt_want(writecb_finished);
3378585484eSchristos 	tt_want(!errorcb_invoked);
3388585484eSchristos 
3398585484eSchristos 	test_ok = 1;
3408585484eSchristos end:
3418585484eSchristos 	if (bev1)
3428585484eSchristos 		bufferevent_free(bev1);
3438585484eSchristos 	if (bev2)
3448585484eSchristos 		bufferevent_free(bev2);
3458585484eSchristos 
3468585484eSchristos 	if (pair[0] >= 0)
3478585484eSchristos 		evutil_closesocket(pair[0]);
3488585484eSchristos 	if (pair[1] >= 0)
3498585484eSchristos 		evutil_closesocket(pair[1]);
3508585484eSchristos }
351