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