From: Niels Provos <provos@gmail.com> Date: Wed, 30 Apr 2008 04:31:10 +0000 (+0000) Subject: provide example bufferevent filters doing compression and decompression as additional... X-Git-Tag: release-2.0.1-alpha~346 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ccb70f1bc747068e960dd721669f0298b4f7870c;p=libevent provide example bufferevent filters doing compression and decompression as additional regression test svn:r751 --- diff --git a/configure.in b/configure.in index 1b24f040..70a8e1af 100644 --- a/configure.in +++ b/configure.in @@ -39,6 +39,18 @@ AC_CHECK_LIB(resolv, inet_aton) AC_CHECK_LIB(rt, clock_gettime) AC_CHECK_LIB(nsl, inet_ntoa) +dnl Determine if we have zlib for regression tests +ZLIB_LIBS="" +ZLIB_CFLAGS="" +AC_CHECK_LIB(z, inflateEnd, + [have_zlib=yes + ZLIB_LIBS="-lz" + AC_DEFINE(HAVE_LIBZ, 1, [Define if the system has zlib])], + [have_zlib=no]) +AC_SUBST(ZLIB_LIBS) +AC_SUBST(ZLIB_CFLAGS) +AM_CONDITIONAL(ZLIB_REGRESS, [test "$have_zlib" != "no"]) + dnl Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS(fcntl.h stdarg.h inttypes.h stdint.h stddef.h poll.h signal.h unistd.h sys/epoll.h sys/time.h sys/queue.h sys/event.h sys/param.h sys/ioctl.h sys/select.h sys/devpoll.h port.h netinet/in6.h sys/socket.h sys/uio.h) diff --git a/test/Makefile.am b/test/Makefile.am index 0e254a80..6ba6c461 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -21,9 +21,12 @@ regress_SOURCES = regress.c regress.h regress_http.c regress_dns.c \ if PTHREAD_REGRESS regress_SOURCES += regress_pthread.c endif -regress_LDADD = ../libevent.la $(PTHREAD_LIBS) +if ZLIB_REGRESS +regress_SOURCES += regress_zlib.c +endif +regress_LDADD = ../libevent.la $(PTHREAD_LIBS) $(ZLIB_LIBS) regress_CFLAGS = -I$(top_srcdir) -I$(top_srcdir)/compat \ - -I$(top_srcdir)/include $(PTHREAD_CFLAGS) + -I$(top_srcdir)/include $(PTHREAD_CFLAGS) $(ZLIB_CFLAGS) bench_SOURCES = bench.c bench_LDADD = ../libevent.la bench_cascade_SOURCES = bench_cascade.c diff --git a/test/regress.c b/test/regress.c index 2aebcfbf..00dbffe9 100644 --- a/test/regress.c +++ b/test/regress.c @@ -254,13 +254,11 @@ setup_test(const char *name) exit(1); } -#ifdef HAVE_FCNTL - if (fcntl(pair[0], F_SETFL, O_NONBLOCK) == -1) + if (evutil_make_socket_nonblocking(pair[0]) == -1) fprintf(stderr, "fcntl(O_NONBLOCK)"); - if (fcntl(pair[1], F_SETFL, O_NONBLOCK) == -1) + if (evutil_make_socket_nonblocking(pair[1]) == -1) fprintf(stderr, "fcntl(O_NONBLOCK)"); -#endif test_ok = 0; called = 0; @@ -2042,6 +2040,10 @@ main (int argc, char **argv) #if defined(HAVE_PTHREADS) && !defined(DISABLE_THREAD_SUPPORT) regress_pthread(); #endif + +#if defined(HAVE_LIBZ) + regress_zlib(); +#endif http_suite(); diff --git a/test/regress.h b/test/regress.h index c5a4510a..5ac6dff9 100644 --- a/test/regress.h +++ b/test/regress.h @@ -39,7 +39,8 @@ void rpc_suite(void); void dns_suite(void); void regress_pthread(void); - +void regress_zlib(void); + #ifdef __cplusplus } #endif diff --git a/test/regress_zlib.c b/test/regress_zlib.c new file mode 100644 index 00000000..189cebe9 --- /dev/null +++ b/test/regress_zlib.c @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2008 Niels Provos <provos@citi.umich.edu> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef WIN32 +#include <winsock2.h> +#include <windows.h> +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#ifndef WIN32 +#include <sys/socket.h> +#include <sys/wait.h> +#include <sys/signal.h> +#include <unistd.h> +#include <netdb.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <zlib.h> +#include <assert.h> + +#include "evutil.h" +#include "event.h" + +void regress_zlib(void); + +static int test_ok; + +/* + * Zlib filters + */ + +static void +zlib_deflate_init(void *ctx) +{ + z_streamp p = ctx; + + memset(p, 0, sizeof(z_stream)); + assert(deflateInit(p, Z_DEFAULT_COMPRESSION) == Z_OK); +} + +static void +zlib_deflate_free(void *ctx) +{ + z_streamp p = ctx; + + assert(deflateEnd(p) == Z_OK); +} + +static void +zlib_inflate_init(void *ctx) +{ + z_streamp p = ctx; + + memset(p, 0, sizeof(z_stream)); + assert(inflateInit(p) == Z_OK); +} + +static void +zlib_inflate_free(void *ctx) +{ + z_streamp p = ctx; + + assert(inflateEnd(p) == Z_OK); +} + +/* + * The input filter is triggered only on new input read from the network. + * That means all input data needs to be consumed or the filter needs to + * initiate its own triggering via a timeout. + */ +static enum bufferevent_filter_result +zlib_input_filter(struct evbuffer *src, struct evbuffer *dst, + enum bufferevent_filter_state state, void *ctx) +{ + char tmp[4096]; + int nread, nwrite; + int res; + + z_streamp p = ctx; + + do { + /* let's do some decompression */ + p->avail_in = EVBUFFER_LENGTH(src); + p->next_in = evbuffer_pullup(src, p->avail_in); + + p->next_out = (unsigned char *)tmp; + p->avail_out = sizeof(tmp); + + /* we need to flush zlib if we got a flush */ + res = inflate(p, state == BEV_FLUSH ? + Z_FINISH : Z_NO_FLUSH); + assert(res == Z_OK || res == Z_STREAM_END); + + /* let's figure out how much was compressed */ + nread = EVBUFFER_LENGTH(src) - p->avail_in; + nwrite = sizeof(tmp) - p->avail_out; + + evbuffer_drain(src, nread); + evbuffer_add(dst, tmp, nwrite); + } while (EVBUFFER_LENGTH(src) > 0); + + test_ok++; + + return (BEV_OK); +} + +static enum bufferevent_filter_result +zlib_output_filter(struct evbuffer *src, struct evbuffer *dst, + enum bufferevent_filter_state state, void *ctx) +{ + char tmp[4096]; + int nread, nwrite; + int res; + + z_streamp p = ctx; + + do { + /* let's do some compression */ + p->avail_in = EVBUFFER_LENGTH(src); + p->next_in = evbuffer_pullup(src, p->avail_in); + + p->next_out = (unsigned char *)tmp; + p->avail_out = sizeof(tmp); + + /* we need to flush zlib if we got a flush */ + res = deflate(p, state == BEV_FLUSH ? Z_FINISH : Z_NO_FLUSH); + assert(res == Z_OK || res == Z_STREAM_END); + + /* let's figure out how much was compressed */ + nread = EVBUFFER_LENGTH(src) - p->avail_in; + nwrite = sizeof(tmp) - p->avail_out; + + evbuffer_drain(src, nread); + evbuffer_add(dst, tmp, nwrite); + } while (EVBUFFER_LENGTH(src) > 0); + + test_ok++; + + return (BEV_OK); +} + +/* + * simple bufferevent test (over transparent zlib treatment) + */ + +static void +readcb(struct bufferevent *bev, void *arg) +{ + if (EVBUFFER_LENGTH(bev->input) == 8333) { + struct evbuffer *evbuf = evbuffer_new(); + assert(evbuf != NULL); + + /* gratuitous test of bufferevent_read_buffer */ + bufferevent_read_buffer(bev, evbuf); + + bufferevent_disable(bev, EV_READ); + + if (EVBUFFER_LENGTH(evbuf) == 8333) + test_ok++; + + evbuffer_free(evbuf); + } +} + +static void +writecb(struct bufferevent *bev, void *arg) +{ + if (EVBUFFER_LENGTH(bev->output) == 0) + test_ok++; +} + +static void +errorcb(struct bufferevent *bev, short what, void *arg) +{ + test_ok = -2; +} + +static void +test_bufferevent_zlib(void) +{ + struct bufferevent *bev1, *bev2; + struct bufferevent_filter *finput, *foutput; + char buffer[8333]; + z_stream z_input, z_output; + int i, pair[2]; + + test_ok = 0; + fprintf(stdout, "Testing Zlib Filter: "); + + if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) { + fprintf(stderr, "%s: socketpair\n", __func__); + exit(1); + } + + evutil_make_socket_nonblocking(pair[0]); + evutil_make_socket_nonblocking(pair[1]); + + bev1 = bufferevent_new(pair[0], readcb, writecb, errorcb, NULL); + bev2 = bufferevent_new(pair[1], readcb, writecb, errorcb, NULL); + + /* initialize filters */ + finput = bufferevent_filter_new( + zlib_inflate_init, zlib_inflate_free, + zlib_input_filter, &z_input); + bufferevent_filter_insert(bev2, BEV_INPUT, finput); + + foutput = bufferevent_filter_new( + zlib_deflate_init, zlib_deflate_free, + zlib_output_filter, &z_output); + bufferevent_filter_insert(bev1, BEV_OUTPUT, foutput); + + bufferevent_disable(bev1, EV_READ); + bufferevent_enable(bev2, EV_READ); + + for (i = 0; i < sizeof(buffer); i++) + buffer[i] = i; + + bufferevent_write(bev1, buffer, sizeof(buffer)); + + /* we are done writing - we need to flush everything */ + bufferevent_trigger_filter(bev1, NULL, BEV_OUTPUT, BEV_FLUSH); + + event_dispatch(); + + bufferevent_free(bev1); + bufferevent_free(bev2); + + if (test_ok != 5) { + fprintf(stdout, "FAILED: \n", test_ok); + exit(1); + } + +#ifndef WIN32 + close(pair[0]); + close(pair[1]); +#else + CloseHandle((HANDLE)pair[0]); + CloseHandle((HANDLE)pair[1]); +#endif + + fprintf(stdout, "OK\n"); +} + +void +regress_zlib(void) +{ + test_bufferevent_zlib(); +}