From 4fd8d3dddd9fbf018ffc9340c7b3efc2ab4cdb3c Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Tue, 12 Jan 2016 15:52:14 +0100 Subject: [PATCH] Replace mini_event extension by default_eventloop * default_eventloop was prototyped in getdns_query and is still in there as my_eventloop * It interfaces directly with the scheduling primitives of getdns. * It can operate entirely from stack and does not have to do any memory allocations or deallocations. * Adapted configure.ac to allow libunbound to be linked with Windows (with the removal of winsock_event.c we have no symbol clashed anymore) * Added STUB_TCP_WOULDBLOCK return code in stub_resolving helper functions, to anticipate dealing with edge triggered event loops (versus level triggered). (i.e. Windows) --- configure.ac | 70 +- spec/example/Makefile.in | 24 +- src/Makefile.in | 236 ++--- src/context.c | 59 +- src/context.h | 8 +- src/extension/default_eventloop.c | 281 ++++++ .../{libmini_event.h => default_eventloop.h} | 52 +- src/extension/libmini_event.c | 238 ----- src/stub.c | 104 ++- src/sync.c | 6 +- src/test/Makefile.in | 96 +- src/util/import.sh | 2 +- src/util/mini_event.c | 394 -------- src/util/mini_event.h | 178 ---- src/util/winsock_event.c | 844 ------------------ src/util/winsock_event.h | 295 ------ 16 files changed, 640 insertions(+), 2247 deletions(-) create mode 100644 src/extension/default_eventloop.c rename src/extension/{libmini_event.h => default_eventloop.h} (65%) delete mode 100644 src/extension/libmini_event.c delete mode 100644 src/util/mini_event.c delete mode 100644 src/util/mini_event.h delete mode 100644 src/util/winsock_event.c delete mode 100644 src/util/winsock_event.h diff --git a/configure.ac b/configure.ac index 41f28349..ab0d917b 100644 --- a/configure.ac +++ b/configure.ac @@ -453,45 +453,39 @@ if test "$USE_WINSOCK" = 1; then AC_DEFINE_UNQUOTED([GETDNS_ON_WINDOWS], [1], [Define this to enable Windows build.]) AC_DEFINE_UNQUOTED([STUB_NATIVE_DNSSEC], [1]) LIBS="$LIBS -lgdi32 -liphlpapi" - my_with_libunbound=0 - my_with_libidn=0 -else - my_with_libidn=1 fi -if test $my_with_libidn = 1 -then - AC_ARG_WITH(libidn, AS_HELP_STRING([--with-libidn=pathname], - [path to libidn (default: search /usr/local ..)]), - [], [withval="yes"]) - if test x_$withval = x_yes; then - for dir in /usr/local /opt/local /usr/pkg /usr/sfw; do - if test -f "$dir/include/idna.h"; then - CFLAGS="$CFLAGS -I$dir/include" - LDFLAGS="$LDFLAGS -L$dir/lib" - AC_MSG_NOTICE([Found libidn in $dir]) - break - fi - if test -f "$dir/include/idn/idna.h"; then - CFLAGS="$CFLAGS -I$dir/include/idn" - LDFLAGS="$LDFLAGS -L$dir/lib" - AC_MSG_NOTICE([Found libidn in $dir]) - break - fi - done - if test -f "/usr/include/idn/idna.h"; then - CFLAGS="$CFLAGS -I/usr/include/idn" - #LDFLAGS="$LDFLAGS -L/usr/lib" - AC_MSG_NOTICE([Found libidn in /usr]) +my_with_libidn=1 +AC_ARG_WITH(libidn, AS_HELP_STRING([--with-libidn=pathname], + [path to libidn (default: search /usr/local ..)]), + [], [withval="yes"]) +if test x_$withval = x_yes; then + for dir in /usr/local /opt/local /usr/pkg /usr/sfw; do + if test -f "$dir/include/idna.h"; then + CFLAGS="$CFLAGS -I$dir/include" + LDFLAGS="$LDFLAGS -L$dir/lib" + AC_MSG_NOTICE([Found libidn in $dir]) + break fi + if test -f "$dir/include/idn/idna.h"; then + CFLAGS="$CFLAGS -I$dir/include/idn" + LDFLAGS="$LDFLAGS -L$dir/lib" + AC_MSG_NOTICE([Found libidn in $dir]) + break + fi + done + if test -f "/usr/include/idn/idna.h"; then + CFLAGS="$CFLAGS -I/usr/include/idn" + #LDFLAGS="$LDFLAGS -L/usr/lib" + AC_MSG_NOTICE([Found libidn in /usr]) + fi +else + if test x_$withval != x_no; then + CFLAGS="$CFLAGS -I$withval/include" + LDFLAGS="$LDFLAGS -L$withval/lib" else - if test x_$withval != x_no; then - CFLAGS="$CFLAGS -I$withval/include" - LDFLAGS="$LDFLAGS -L$withval/lib" - else - my_with_libidn=0 - fi + my_with_libidn=0 fi fi @@ -1161,6 +1155,14 @@ const char *inet_ntop(int af, const void *src, char *dst, size_t size); #include #endif +#ifdef HAVE_INTTYPES_H +#include +#endif + +#ifndef PRIu64 +#define PRIu64 "llu" +#endif + #ifdef HAVE_ATTR_FORMAT # define ATTR_FORMAT(archetype, string_index, first_to_check) \ __attribute__ ((format (archetype, string_index, first_to_check))) diff --git a/spec/example/Makefile.in b/spec/example/Makefile.in index 7bf5e016..8ff7f2d1 100644 --- a/spec/example/Makefile.in +++ b/spec/example/Makefile.in @@ -149,16 +149,24 @@ depend: # Dependencies for the examples example-all-functions.lo example-all-functions.o: $(srcdir)/example-all-functions.c $(srcdir)/getdns_libevent.h \ - ../../src/config.h ../../src/getdns/getdns.h \ - $(srcdir)/../../src/getdns/getdns_ext_libevent.h ../../src/getdns/getdns_extra.h -example-reverse.lo example-reverse.o: $(srcdir)/example-reverse.c $(srcdir)/getdns_libevent.h ../../src/config.h \ - ../../src/getdns/getdns.h $(srcdir)/../../src/getdns/getdns_ext_libevent.h \ + ../../src/config.h \ + ../../src/getdns/getdns.h \ + $(srcdir)/../../src/getdns/getdns_ext_libevent.h \ + ../../src/getdns/getdns_extra.h +example-reverse.lo example-reverse.o: $(srcdir)/example-reverse.c $(srcdir)/getdns_libevent.h \ + ../../src/config.h \ + ../../src/getdns/getdns.h \ + $(srcdir)/../../src/getdns/getdns_ext_libevent.h \ ../../src/getdns/getdns_extra.h example-simple-answers.lo example-simple-answers.o: $(srcdir)/example-simple-answers.c $(srcdir)/getdns_libevent.h \ - ../../src/config.h ../../src/getdns/getdns.h \ - $(srcdir)/../../src/getdns/getdns_ext_libevent.h ../../src/getdns/getdns_extra.h + ../../src/config.h \ + ../../src/getdns/getdns.h \ + $(srcdir)/../../src/getdns/getdns_ext_libevent.h \ + ../../src/getdns/getdns_extra.h example-synchronous.lo example-synchronous.o: $(srcdir)/example-synchronous.c $(srcdir)/getdns_core_only.h \ ../../src/getdns/getdns.h -example-tree.lo example-tree.o: $(srcdir)/example-tree.c $(srcdir)/getdns_libevent.h ../../src/config.h \ - ../../src/getdns/getdns.h $(srcdir)/../../src/getdns/getdns_ext_libevent.h \ +example-tree.lo example-tree.o: $(srcdir)/example-tree.c $(srcdir)/getdns_libevent.h \ + ../../src/config.h \ + ../../src/getdns/getdns.h \ + $(srcdir)/../../src/getdns/getdns_ext_libevent.h \ ../../src/getdns/getdns_extra.h diff --git a/src/Makefile.in b/src/Makefile.in index a20a9b18..f51a0ab4 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -74,9 +74,9 @@ LIBOBJDIR= LIBOBJS=@LIBOBJS@ COMPAT_OBJ=$(LIBOBJS:.o=.lo) -UTIL_OBJ=mini_event.lo winsock_event.lo rbtree.lo val_secalgo.lo +UTIL_OBJ=rbtree.lo val_secalgo.lo -EXTENSION_OBJ=libmini_event.lo libevent.lo libev.lo +EXTENSION_OBJ=default_eventloop.lo libevent.lo libev.lo NON_C99_OBJS=context.lo libuv.lo @@ -144,8 +144,8 @@ libgetdns_ext_ev.la: libgetdns.la libev.lo $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ libev.lo libgetdns.la $(LDFLAGS) $(EXTENSION_LIBEV_LDFLAGS) $(EXTENSION_LIBEV_EXT_LIBS) -rpath $(libdir) -version-info $(libversion) -no-undefined -export-symbols $(srcdir)/extension/libev.symbols -libgetdns.la: $(GETDNS_OBJ) version.lo context.lo libmini_event.lo $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) - $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ $(GETDNS_OBJ) version.lo context.lo libmini_event.lo $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) $(LDFLAGS) -rpath $(libdir) -version-info $(libversion) -no-undefined -export-symbols $(srcdir)/libgetdns.symbols +libgetdns.la: $(GETDNS_OBJ) version.lo context.lo default_eventloop.lo $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) + $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ $(GETDNS_OBJ) version.lo context.lo default_eventloop.lo $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) $(LDFLAGS) -rpath $(libdir) -version-info $(libversion) -no-undefined -export-symbols $(srcdir)/libgetdns.symbols test: all @@ -225,114 +225,136 @@ depend: FORCE: # Dependencies for gldns, utils, the extensions and compat functions -const-info.lo const-info.o: $(srcdir)/const-info.c getdns/getdns.h getdns/getdns_extra.h \ - getdns/getdns.h $(srcdir)/const-info.h -context.lo context.o: $(srcdir)/context.c config.h $(srcdir)/debug.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h \ - $(srcdir)/gldns/wire2str.h $(srcdir)/context.h getdns/getdns.h getdns/getdns_extra.h \ - getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/extension/libmini_event.h \ - config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h \ - $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ - $(srcdir)/dnssec.h $(srcdir)/stub.h $(srcdir)/list.h $(srcdir)/dict.h $(srcdir)/pubkey-pinning.h -convert.lo convert.o: $(srcdir)/convert.c config.h getdns/getdns.h getdns/getdns_extra.h \ - getdns/getdns.h $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \ - $(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \ - $(srcdir)/types-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ - $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/convert.h -dict.lo dict.o: $(srcdir)/dict.c config.h $(srcdir)/types-internal.h getdns/getdns.h \ - getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h $(srcdir)/util-internal.h \ - $(srcdir)/context.h $(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h \ - $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ - $(srcdir)/gldns/pkthdr.h $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/const-info.h $(srcdir)/gldns/wire2str.h -dnssec.lo dnssec.o: $(srcdir)/dnssec.c config.h $(srcdir)/debug.h getdns/getdns.h $(srcdir)/context.h \ - getdns/getdns_extra.h getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \ - $(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \ - $(srcdir)/types-internal.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ - $(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h \ - $(srcdir)/gldns/keyraw.h $(srcdir)/gldns/parseutil.h $(srcdir)/general.h $(srcdir)/dict.h $(srcdir)/list.h \ - $(srcdir)/util/val_secalgo.h -general.lo general.o: $(srcdir)/general.c config.h $(srcdir)/gldns/wire2str.h $(srcdir)/context.h getdns/getdns.h \ - getdns/getdns_extra.h getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \ - $(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \ - $(srcdir)/types-internal.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ - $(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/stub.h $(srcdir)/general.h -list.lo list.o: $(srcdir)/list.c $(srcdir)/types-internal.h getdns/getdns.h getdns/getdns_extra.h \ - getdns/getdns.h $(srcdir)/util/rbtree.h $(srcdir)/util-internal.h config.h $(srcdir)/context.h \ - $(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \ - $(srcdir)/types-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ - $(srcdir)/list.h $(srcdir)/dict.h -pubkey-pinning.lo pubkey-pinning.o: $(srcdir)/pubkey-pinning.c config.h $(srcdir)/debug.h getdns/getdns.h \ - $(srcdir)/context.h getdns/getdns.h getdns/getdns_extra.h $(srcdir)/types-internal.h \ - $(srcdir)/util/rbtree.h $(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h \ - $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h -request-internal.lo request-internal.o: $(srcdir)/request-internal.c config.h $(srcdir)/types-internal.h \ - getdns/getdns.h getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h \ - $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/extension/libmini_event.h config.h \ - $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ - $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/str2wire.h \ +const-info.lo const-info.o: $(srcdir)/const-info.c getdns/getdns.h \ + getdns/getdns_extra.h $(srcdir)/const-info.h +context.lo context.o: $(srcdir)/context.c config.h $(srcdir)/debug.h \ + $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h $(srcdir)/context.h \ + getdns/getdns.h \ + getdns/getdns_extra.h $(srcdir)/types-internal.h \ + $(srcdir)/util/rbtree.h $(srcdir)/extension/default_eventloop.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h \ + $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/stub.h $(srcdir)/list.h $(srcdir)/dict.h \ + $(srcdir)/pubkey-pinning.h +convert.lo convert.o: $(srcdir)/convert.c config.h \ + getdns/getdns.h \ + getdns/getdns_extra.h $(srcdir)/util-internal.h \ + $(srcdir)/context.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/extension/default_eventloop.h \ + $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/wire2str.h \ + $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/convert.h +dict.lo dict.o: $(srcdir)/dict.c config.h $(srcdir)/types-internal.h \ + getdns/getdns.h \ + getdns/getdns_extra.h $(srcdir)/util/rbtree.h \ + $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h $(srcdir)/rr-iter.h \ + $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/const-info.h \ + $(srcdir)/gldns/wire2str.h +dnssec.lo dnssec.o: $(srcdir)/dnssec.c config.h $(srcdir)/debug.h \ + getdns/getdns.h $(srcdir)/context.h \ + getdns/getdns_extra.h $(srcdir)/types-internal.h \ + $(srcdir)/util/rbtree.h $(srcdir)/extension/default_eventloop.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h \ + $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/gldns/str2wire.h \ + $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/keyraw.h $(srcdir)/gldns/parseutil.h \ + $(srcdir)/general.h $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/util/val_secalgo.h +general.lo general.o: $(srcdir)/general.c config.h $(srcdir)/general.h \ + getdns/getdns.h $(srcdir)/types-internal.h \ + getdns/getdns_extra.h $(srcdir)/util/rbtree.h \ + $(srcdir)/gldns/wire2str.h $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h $(srcdir)/util-internal.h \ + $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/stub.h \ + $(srcdir)/dict.h +list.lo list.o: $(srcdir)/list.c $(srcdir)/types-internal.h \ + getdns/getdns.h \ + getdns/getdns_extra.h $(srcdir)/util/rbtree.h \ + $(srcdir)/util-internal.h config.h $(srcdir)/context.h \ + $(srcdir)/extension/default_eventloop.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ + $(srcdir)/gldns/pkthdr.h $(srcdir)/list.h $(srcdir)/dict.h +pubkey-pinning.lo pubkey-pinning.o: $(srcdir)/pubkey-pinning.c config.h \ + $(srcdir)/debug.h getdns/getdns.h $(srcdir)/context.h \ + getdns/getdns_extra.h $(srcdir)/types-internal.h \ + $(srcdir)/util/rbtree.h $(srcdir)/extension/default_eventloop.h +request-internal.lo request-internal.o: $(srcdir)/request-internal.c \ + config.h $(srcdir)/types-internal.h \ + getdns/getdns.h \ + getdns/getdns_extra.h $(srcdir)/util/rbtree.h \ + $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h $(srcdir)/rr-iter.h \ + $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/str2wire.h \ $(srcdir)/gldns/rrdef.h $(srcdir)/dict.h $(srcdir)/debug.h -rr-dict.lo rr-dict.o: $(srcdir)/rr-dict.c $(srcdir)/rr-dict.h config.h getdns/getdns.h $(srcdir)/gldns/gbuffer.h \ - $(srcdir)/util-internal.h $(srcdir)/context.h getdns/getdns_extra.h getdns/getdns.h \ - $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/extension/libmini_event.h config.h \ - $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/rr-iter.h \ - $(srcdir)/gldns/pkthdr.h $(srcdir)/dict.h -rr-iter.lo rr-iter.o: $(srcdir)/rr-iter.c $(srcdir)/rr-iter.h getdns/getdns.h $(srcdir)/rr-dict.h config.h \ - $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/rrdef.h -stub.lo stub.o: $(srcdir)/stub.c config.h $(srcdir)/debug.h $(srcdir)/stub.h getdns/getdns.h $(srcdir)/types-internal.h \ - getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h $(srcdir)/gldns/gbuffer.h \ - $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h \ - $(srcdir)/gldns/wire2str.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/context.h $(srcdir)/extension/libmini_event.h \ - config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h \ - $(srcdir)/util-internal.h $(srcdir)/general.h $(srcdir)/pubkey-pinning.h -sync.lo sync.o: $(srcdir)/sync.c getdns/getdns.h config.h $(srcdir)/context.h getdns/getdns_extra.h \ - getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/extension/libmini_event.h \ - config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/general.h \ - $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ - $(srcdir)/dnssec.h $(srcdir)/stub.h $(srcdir)/gldns/wire2str.h -util-internal.lo util-internal.o: $(srcdir)/util-internal.c config.h getdns/getdns.h $(srcdir)/dict.h \ - $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h getdns/getdns_extra.h getdns/getdns.h \ - $(srcdir)/list.h $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/extension/libmini_event.h config.h \ - $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ - $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h -version.lo version.o: version.c -gbuffer.lo gbuffer.o: $(srcdir)/gldns/gbuffer.c config.h $(srcdir)/gldns/gbuffer.h -keyraw.lo keyraw.o: $(srcdir)/gldns/keyraw.c config.h $(srcdir)/gldns/keyraw.h $(srcdir)/gldns/rrdef.h -parse.lo parse.o: $(srcdir)/gldns/parse.c config.h $(srcdir)/gldns/parse.h $(srcdir)/gldns/parseutil.h \ +rr-dict.lo rr-dict.o: $(srcdir)/rr-dict.c $(srcdir)/rr-dict.h config.h \ + getdns/getdns.h $(srcdir)/gldns/gbuffer.h \ + $(srcdir)/util-internal.h $(srcdir)/context.h \ + getdns/getdns_extra.h $(srcdir)/types-internal.h \ + $(srcdir)/util/rbtree.h $(srcdir)/extension/default_eventloop.h $(srcdir)/rr-iter.h $(srcdir)/gldns/pkthdr.h \ + $(srcdir)/dict.h +rr-iter.lo rr-iter.o: $(srcdir)/rr-iter.c $(srcdir)/rr-iter.h \ + getdns/getdns.h $(srcdir)/rr-dict.h \ + config.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ + $(srcdir)/gldns/rrdef.h +stub.lo stub.o: $(srcdir)/stub.c config.h $(srcdir)/debug.h $(srcdir)/stub.h \ + getdns/getdns.h $(srcdir)/types-internal.h \ + getdns/getdns_extra.h $(srcdir)/util/rbtree.h \ + $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/str2wire.h \ + $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/context.h \ + $(srcdir)/extension/default_eventloop.h $(srcdir)/util-internal.h $(srcdir)/general.h $(srcdir)/pubkey-pinning.h +sync.lo sync.o: $(srcdir)/sync.c getdns/getdns.h \ + config.h $(srcdir)/context.h \ + getdns/getdns_extra.h $(srcdir)/types-internal.h \ + $(srcdir)/util/rbtree.h $(srcdir)/extension/default_eventloop.h $(srcdir)/general.h $(srcdir)/util-internal.h \ + $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/stub.h \ + $(srcdir)/gldns/wire2str.h +util-internal.lo util-internal.o: $(srcdir)/util-internal.c config.h \ + getdns/getdns.h $(srcdir)/dict.h $(srcdir)/util/rbtree.h \ + $(srcdir)/types-internal.h getdns/getdns_extra.h \ + $(srcdir)/list.h $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h $(srcdir)/rr-iter.h \ + $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h +gbuffer.lo gbuffer.o: $(srcdir)/gldns/gbuffer.c config.h \ $(srcdir)/gldns/gbuffer.h -parseutil.lo parseutil.o: $(srcdir)/gldns/parseutil.c config.h $(srcdir)/gldns/parseutil.h -rrdef.lo rrdef.o: $(srcdir)/gldns/rrdef.c config.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/parseutil.h -str2wire.lo str2wire.o: $(srcdir)/gldns/str2wire.c config.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h \ - $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/parse.h $(srcdir)/gldns/parseutil.h -wire2str.lo wire2str.o: $(srcdir)/gldns/wire2str.c config.h $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/str2wire.h \ - $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/parseutil.h $(srcdir)/gldns/gbuffer.h \ - $(srcdir)/gldns/keyraw.h +keyraw.lo keyraw.o: $(srcdir)/gldns/keyraw.c config.h \ + $(srcdir)/gldns/keyraw.h $(srcdir)/gldns/rrdef.h +parse.lo parse.o: $(srcdir)/gldns/parse.c config.h \ + $(srcdir)/gldns/parse.h $(srcdir)/gldns/parseutil.h $(srcdir)/gldns/gbuffer.h +parseutil.lo parseutil.o: $(srcdir)/gldns/parseutil.c config.h \ + $(srcdir)/gldns/parseutil.h +rrdef.lo rrdef.o: $(srcdir)/gldns/rrdef.c config.h \ + $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/parseutil.h +str2wire.lo str2wire.o: $(srcdir)/gldns/str2wire.c config.h \ + $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/gbuffer.h \ + $(srcdir)/gldns/parse.h $(srcdir)/gldns/parseutil.h +wire2str.lo wire2str.o: $(srcdir)/gldns/wire2str.c config.h \ + $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/pkthdr.h \ + $(srcdir)/gldns/parseutil.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/keyraw.h arc4_lock.lo arc4_lock.o: $(srcdir)/compat/arc4_lock.c config.h -arc4random.lo arc4random.o: $(srcdir)/compat/arc4random.c config.h $(srcdir)/compat/chacha_private.h -arc4random_uniform.lo arc4random_uniform.o: $(srcdir)/compat/arc4random_uniform.c config.h -explicit_bzero.lo explicit_bzero.o: $(srcdir)/compat/explicit_bzero.c config.h -getentropy_linux.lo getentropy_linux.o: $(srcdir)/compat/getentropy_linux.c config.h -getentropy_osx.lo getentropy_osx.o: $(srcdir)/compat/getentropy_osx.c config.h -getentropy_solaris.lo getentropy_solaris.o: $(srcdir)/compat/getentropy_solaris.c config.h +arc4random.lo arc4random.o: $(srcdir)/compat/arc4random.c config.h \ + $(srcdir)/compat/chacha_private.h +arc4random_uniform.lo arc4random_uniform.o: $(srcdir)/compat/arc4random_uniform.c \ + config.h +explicit_bzero.lo explicit_bzero.o: $(srcdir)/compat/explicit_bzero.c \ + config.h +getentropy_linux.lo getentropy_linux.o: $(srcdir)/compat/getentropy_linux.c \ + config.h +getentropy_osx.lo getentropy_osx.o: $(srcdir)/compat/getentropy_osx.c \ + config.h +getentropy_solaris.lo getentropy_solaris.o: $(srcdir)/compat/getentropy_solaris.c \ + config.h getentropy_win.lo getentropy_win.o: $(srcdir)/compat/getentropy_win.c inet_ntop.lo inet_ntop.o: $(srcdir)/compat/inet_ntop.c config.h inet_pton.lo inet_pton.o: $(srcdir)/compat/inet_pton.c config.h sha512.lo sha512.o: $(srcdir)/compat/sha512.c config.h strlcpy.lo strlcpy.o: $(srcdir)/compat/strlcpy.c config.h -mini_event.lo mini_event.o: $(srcdir)/util/mini_event.c config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \ - $(srcdir)/util/fptr_wlist.h -rbtree.lo rbtree.o: $(srcdir)/util/rbtree.c config.h $(srcdir)/util/log.h $(srcdir)/debug.h config.h \ - $(srcdir)/util/fptr_wlist.h $(srcdir)/util/rbtree.h -val_secalgo.lo val_secalgo.o: $(srcdir)/util/val_secalgo.c config.h $(srcdir)/util/val_secalgo.h $(srcdir)/util/log.h \ - $(srcdir)/debug.h config.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/keyraw.h $(srcdir)/gldns/gbuffer.h -winsock_event.lo winsock_event.o: $(srcdir)/util/winsock_event.c config.h -libev.lo libev.o: $(srcdir)/extension/libev.c config.h $(srcdir)/types-internal.h getdns/getdns.h \ - getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h \ - $(srcdir)/getdns/getdns_ext_libev.h getdns/getdns_extra.h -libevent.lo libevent.o: $(srcdir)/extension/libevent.c config.h $(srcdir)/types-internal.h \ - getdns/getdns.h getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h \ - $(srcdir)/getdns/getdns_ext_libevent.h getdns/getdns_extra.h -libmini_event.lo libmini_event.o: $(srcdir)/extension/libmini_event.c config.h $(srcdir)/debug.h config.h \ - $(srcdir)/types-internal.h getdns/getdns.h getdns/getdns_extra.h getdns/getdns.h \ - $(srcdir)/util/rbtree.h $(srcdir)/extension/libmini_event.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h -libuv.lo libuv.o: $(srcdir)/extension/libuv.c config.h $(srcdir)/debug.h config.h $(srcdir)/types-internal.h \ - getdns/getdns.h getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h \ - $(srcdir)/getdns/getdns_ext_libuv.h getdns/getdns_extra.h +rbtree.lo rbtree.o: $(srcdir)/util/rbtree.c config.h $(srcdir)/util/log.h \ + $(srcdir)/debug.h $(srcdir)/util/fptr_wlist.h $(srcdir)/util/rbtree.h +val_secalgo.lo val_secalgo.o: $(srcdir)/util/val_secalgo.c config.h \ + $(srcdir)/util/val_secalgo.h $(srcdir)/util/log.h $(srcdir)/debug.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/keyraw.h \ + $(srcdir)/gldns/gbuffer.h +default_eventloop.lo default_eventloop.o: $(srcdir)/extension/default_eventloop.c \ + $(srcdir)/extension/default_eventloop.h config.h \ + getdns/getdns.h \ + getdns/getdns_extra.h $(srcdir)/debug.h +libev.lo libev.o: $(srcdir)/extension/libev.c config.h \ + $(srcdir)/types-internal.h getdns/getdns.h \ + getdns/getdns_extra.h $(srcdir)/util/rbtree.h \ + $(srcdir)/getdns/getdns_ext_libev.h +libevent.lo libevent.o: $(srcdir)/extension/libevent.c config.h \ + $(srcdir)/types-internal.h getdns/getdns.h \ + getdns/getdns_extra.h $(srcdir)/util/rbtree.h \ + $(srcdir)/getdns/getdns_ext_libevent.h +libuv.lo libuv.o: $(srcdir)/extension/libuv.c config.h $(srcdir)/debug.h \ + $(srcdir)/types-internal.h getdns/getdns.h \ + getdns/getdns_extra.h $(srcdir)/util/rbtree.h \ + $(srcdir)/getdns/getdns_ext_libuv.h diff --git a/src/context.c b/src/context.c index c325d982..0dd7ec79 100644 --- a/src/context.c +++ b/src/context.c @@ -966,6 +966,9 @@ getdns_context_create_with_extended_memory_functions( struct getdns_context *result = NULL; mf_union mf; gldns_buffer gbuf; +#ifdef USE_WINSOCK + WORD wVersionRequested; +#endif if (!context || !malloc || !realloc || !free) return GETDNS_RETURN_INVALID_PARAMETER; @@ -979,6 +982,14 @@ getdns_context_create_with_extended_memory_functions( if (!result) return GETDNS_RETURN_MEMORY_ERROR; +#ifdef USE_WINSOCK + /* We need to run WSAStartup() to be able to use getaddrinfo() */ + wVersionRequested = MAKEWORD(2, 2); + if (WSAStartup(wVersionRequested, &result->wsaData)) { + r = GETDNS_RETURN_GENERIC_ERROR; + goto error; + } +#endif result->processing = 0; result->destroying = 0; result->my_mf.mf_arg = userarg; @@ -1050,9 +1061,8 @@ getdns_context_create_with_extended_memory_functions( result->tls_query_padding_blocksize = 1; /* default is to not try to pad */ result-> tls_ctx = NULL; - result->extension = &result->mini_event.loop; - if ((r = _getdns_mini_event_init(result, &result->mini_event))) - goto error; + result->extension = &result->default_eventloop.loop; + _getdns_default_eventloop_init(&result->default_eventloop); result->fchg_resolvconf = NULL; result->fchg_hosts = NULL; @@ -1198,6 +1208,9 @@ getdns_context_destroy(struct getdns_context *context) _getdns_traverse_postorder(&context->local_hosts, destroy_local_host, context); +#ifdef USE_WINSOCK + WSACleanup(); +#endif GETDNS_FREE(context->my_mf, context); } /* getdns_context_destroy */ @@ -2798,55 +2811,36 @@ _getdns_bindata_destroy(struct mem_funcs *mfs, /* TODO: Remove next_timeout argument from getdns_context_get_num_pending_requests */ -void _getdns_handle_timeouts(struct _getdns_event_base* base, struct timeval* now, - struct timeval* wait); uint32_t -getdns_context_get_num_pending_requests(struct getdns_context* context, +getdns_context_get_num_pending_requests(getdns_context* context, struct timeval* next_timeout) { - struct timeval dispose; + (void)next_timeout; - RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); + if (!context) + return GETDNS_RETURN_INVALID_PARAMETER; if (context->outbound_requests.count) context->extension->vmt->run_once(context->extension, 0); - /* TODO: Remove this when next_timeout is gone */ - if (context->extension == &context->mini_event.loop) - _getdns_handle_timeouts(context->mini_event.base, - &context->mini_event.time_tv, - next_timeout ? next_timeout : &dispose); - return context->outbound_requests.count; } /* process async reqs */ getdns_return_t -getdns_context_process_async(struct getdns_context* context) +getdns_context_process_async(getdns_context *context) { - RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); + if (!context) + return GETDNS_RETURN_INVALID_PARAMETER; -#ifdef HAVE_LIBUNBOUND - if (ub_poll(context->unbound_ctx) && ub_process(context->unbound_ctx)){ - /* need an async return code? */ - return GETDNS_RETURN_GENERIC_ERROR; - } -#endif context->extension->vmt->run_once(context->extension, 0); - return GETDNS_RETURN_GOOD; } void getdns_context_run(getdns_context *context) { - if (context->extension == &context->mini_event.loop) { - if (getdns_context_get_num_pending_requests(context, NULL) > 0 && - !getdns_context_process_async(context)) - context->extension->vmt->run(context->extension); - } - else - context->extension->vmt->run(context->extension); + context->extension->vmt->run(context->extension); } typedef struct timeout_accumulator { @@ -2891,8 +2885,9 @@ getdns_context_detach_eventloop(struct getdns_context* context) /* cancel all outstanding requests */ cancel_outstanding_requests(context, 1); context->extension->vmt->cleanup(context->extension); - context->extension = &context->mini_event.loop; - return _getdns_mini_event_init(context, &context->mini_event); + context->extension = &context->default_eventloop.loop; + _getdns_default_eventloop_init(&context->default_eventloop); + return GETDNS_RETURN_GOOD; } getdns_return_t diff --git a/src/context.h b/src/context.h index 340ac375..8547673c 100644 --- a/src/context.h +++ b/src/context.h @@ -41,7 +41,7 @@ #include "getdns/getdns_extra.h" #include "config.h" #include "types-internal.h" -#include "extension/libmini_event.h" +#include "extension/default_eventloop.h" #include "util/rbtree.h" struct getdns_dns_req; @@ -245,7 +245,7 @@ struct getdns_context { #endif /* The default extension */ - _getdns_mini_event mini_event; + _getdns_default_eventloop default_eventloop; /* * state data used to detect changes to the system config files @@ -255,6 +255,10 @@ struct getdns_context { uint8_t trust_anchors_spc[1024]; +#ifdef USE_WINSOCK + /* We need to run WSAStartup() to be able to use getaddrinfo() */ + WSADATA wsaData; +#endif }; /* getdns_context */ /** internal functions **/ diff --git a/src/extension/default_eventloop.c b/src/extension/default_eventloop.c new file mode 100644 index 00000000..d44cfb6a --- /dev/null +++ b/src/extension/default_eventloop.c @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2013, NLNet Labs, Verisign, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the names of the copyright holders nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 Verisign, Inc. 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. + */ + +#include "extension/default_eventloop.h" +#include "debug.h" + +static uint64_t get_now_plus(uint64_t amount) +{ + struct timeval tv; + uint64_t now; + + if (gettimeofday(&tv, NULL)) { + perror("gettimeofday() failed"); + exit(EXIT_FAILURE); + } + now = tv.tv_sec * 1000000 + tv.tv_usec; + + return (now + amount * 1000) >= now ? now + amount * 1000 : -1; +} + +static getdns_return_t +default_eventloop_schedule(getdns_eventloop *loop, + int fd, uint64_t timeout, getdns_eventloop_event *event) +{ + _getdns_default_eventloop *default_loop = (_getdns_default_eventloop *)loop; + size_t i; + + DEBUG_SCHED( "%s(loop: %p, fd: %d, timeout: %"PRIu64", event: %p, FD_SETSIZE: %d)\n" + , __FUNCTION__, loop, fd, timeout, event, FD_SETSIZE); + + if (!loop || !event) + return GETDNS_RETURN_INVALID_PARAMETER; + + if (fd >= FD_SETSIZE) { + DEBUG_SCHED( "ERROR: fd %d >= FD_SETSIZE: %d!\n" + , fd, FD_SETSIZE); + return GETDNS_RETURN_GENERIC_ERROR; + } + if (fd >= 0) { + if (!(event->read_cb || event->write_cb)) { + DEBUG_SCHED("ERROR: fd event without " + "read or write cb!\n"); + return GETDNS_RETURN_GENERIC_ERROR; + } +#if defined(SCHED_DEBUG) && SCHED_DEBUG + if (default_loop->fd_events[fd]) { + DEBUG_SCHED( "ERROR: Event present at fd slot: %p!\n" + , default_loop->fd_events[fd]); + } +#endif + default_loop->fd_events[fd] = event; + default_loop->fd_timeout_times[fd] = get_now_plus(timeout); + event->ev = (void *) (intptr_t) fd + 1; + + DEBUG_SCHED( "scheduled read/write at %d\n", fd); + return GETDNS_RETURN_GOOD; + } + if (!event->timeout_cb) { + DEBUG_SCHED("ERROR: fd < 0 without timeout_cb!\n"); + return GETDNS_RETURN_GENERIC_ERROR; + } + if (event->read_cb) { + DEBUG_SCHED("ERROR: timeout event with read_cb! Clearing.\n"); + event->read_cb = NULL; + } + if (event->write_cb) { + DEBUG_SCHED("ERROR: timeout event with write_cb! Clearing.\n"); + event->write_cb = NULL; + } + for (i = 0; i < MAX_TIMEOUTS; i++) { + if (default_loop->timeout_events[i] == NULL) { + default_loop->timeout_events[i] = event; + default_loop->timeout_times[i] = get_now_plus(timeout); + event->ev = (void *) (intptr_t) i + 1; + + DEBUG_SCHED( "scheduled timeout at %d\n", (int)i); + return GETDNS_RETURN_GOOD; + } + } + DEBUG_SCHED("ERROR: Out of timeout slots!\n"); + return GETDNS_RETURN_GENERIC_ERROR; +} + +static getdns_return_t +default_eventloop_clear(getdns_eventloop *loop, getdns_eventloop_event *event) +{ + _getdns_default_eventloop *default_loop = (_getdns_default_eventloop *)loop; + ssize_t i; + + if (!loop || !event) + return GETDNS_RETURN_INVALID_PARAMETER; + + DEBUG_SCHED( "%s(loop: %p, event: %p)\n", __FUNCTION__, loop, event); + + i = (intptr_t)event->ev - 1; + if (i < 0 || i > FD_SETSIZE) { + return GETDNS_RETURN_GENERIC_ERROR; + } + if (event->timeout_cb && !event->read_cb && !event->write_cb) { +#if defined(SCHED_DEBUG) && SCHED_DEBUG + if (default_loop->timeout_events[i] != event) + DEBUG_SCHED( "ERROR: Different/wrong event present at " + "timeout slot: %p!\n" + , default_loop->timeout_events[i]); +#endif + default_loop->timeout_events[i] = NULL; + } else { +#if defined(SCHED_DEBUG) && SCHED_DEBUG + if (default_loop->fd_events[i] != event) + DEBUG_SCHED( "ERROR: Different/wrong event present at " + "fd slot: %p!\n" + , default_loop->fd_events[i]); +#endif + default_loop->fd_events[i] = NULL; + } + event->ev = NULL; + return GETDNS_RETURN_GOOD; +} + +static void +default_eventloop_cleanup(getdns_eventloop *loop) +{ +} + +static void +default_read_cb(int fd, getdns_eventloop_event *event) +{ + DEBUG_SCHED( "%s(fd: %d, event: %p)\n", __FUNCTION__, fd, event); + event->read_cb(event->userarg); +} + +static void +default_write_cb(int fd, getdns_eventloop_event *event) +{ + DEBUG_SCHED( "%s(fd: %d, event: %p)\n", __FUNCTION__, fd, event); + event->write_cb(event->userarg); +} + +static void +default_timeout_cb(int fd, getdns_eventloop_event *event) +{ + DEBUG_SCHED( "%s(fd: %d, event: %p)\n", __FUNCTION__, fd, event); + event->timeout_cb(event->userarg); +} + +static void +default_eventloop_run_once(getdns_eventloop *loop, int blocking) +{ + _getdns_default_eventloop *default_loop = (_getdns_default_eventloop *)loop; + + fd_set readfds, writefds; + int fd, max_fd = -1; + uint64_t now, timeout = (uint64_t)-1; + size_t i; + struct timeval tv; + + if (!loop) + return; + + FD_ZERO(&readfds); + FD_ZERO(&writefds); + now = get_now_plus(0); + + for (i = 0; i < MAX_TIMEOUTS; i++) { + if (!default_loop->timeout_events[i]) + continue; + if (now > default_loop->timeout_times[i]) + default_timeout_cb(-1, default_loop->timeout_events[i]); + else if (default_loop->timeout_times[i] < timeout) + timeout = default_loop->timeout_times[i]; + } + for (fd = 0; fd < FD_SETSIZE; fd++) { + if (!default_loop->fd_events[fd]) + continue; + if (default_loop->fd_events[fd]->read_cb) + FD_SET(fd, &readfds); + if (default_loop->fd_events[fd]->write_cb) + FD_SET(fd, &writefds); + if (fd > max_fd) + max_fd = fd; + if (default_loop->fd_timeout_times[fd] < timeout) + timeout = default_loop->fd_timeout_times[fd]; + } + if (max_fd == -1 && timeout == (uint64_t)-1) + return; + + if (! blocking || now > timeout) { + tv.tv_sec = 0; + tv.tv_usec = 0; + } else { + tv.tv_sec = (timeout - now) / 1000000; + tv.tv_usec = (timeout - now) % 1000000; + } + if (select(max_fd + 1, &readfds, &writefds, NULL, + (timeout == ((uint64_t)-1) ? NULL : &tv)) < 0) { + perror("select() failed"); + exit(EXIT_FAILURE); + } + now = get_now_plus(0); + for (fd = 0; fd < FD_SETSIZE; fd++) { + if (default_loop->fd_events[fd] && + default_loop->fd_events[fd]->read_cb && + FD_ISSET(fd, &readfds)) + default_read_cb(fd, default_loop->fd_events[fd]); + + if (default_loop->fd_events[fd] && + default_loop->fd_events[fd]->write_cb && + FD_ISSET(fd, &writefds)) + default_write_cb(fd, default_loop->fd_events[fd]); + + if (default_loop->fd_events[fd] && + default_loop->fd_events[fd]->timeout_cb && + now > default_loop->fd_timeout_times[fd]) + default_timeout_cb(fd, default_loop->fd_events[fd]); + + i = fd; + if (default_loop->timeout_events[i] && + default_loop->timeout_events[i]->timeout_cb && + now > default_loop->timeout_times[i]) + default_timeout_cb(-1, default_loop->timeout_events[i]); + } +} + +static void +default_eventloop_run(getdns_eventloop *loop) +{ + _getdns_default_eventloop *default_loop = (_getdns_default_eventloop *)loop; + size_t i; + + if (!loop) + return; + + i = 0; + while (i < MAX_TIMEOUTS) { + if (default_loop->fd_events[i] || default_loop->timeout_events[i]) { + default_eventloop_run_once(loop, 1); + i = 0; + } else { + i++; + } + } +} + +void +_getdns_default_eventloop_init(_getdns_default_eventloop *loop) +{ + static getdns_eventloop_vmt default_eventloop_vmt = { + default_eventloop_cleanup, + default_eventloop_schedule, + default_eventloop_clear, + default_eventloop_run, + default_eventloop_run_once + }; + + (void) memset(loop, 0, sizeof(_getdns_default_eventloop)); + loop->loop.vmt = &default_eventloop_vmt; +} diff --git a/src/extension/libmini_event.h b/src/extension/default_eventloop.h similarity index 65% rename from src/extension/libmini_event.h rename to src/extension/default_eventloop.h index c3f5b19a..7f6b78f0 100644 --- a/src/extension/libmini_event.h +++ b/src/extension/default_eventloop.h @@ -1,11 +1,10 @@ -/** - * - * \file libmini_event.h +/* + * \file default_eventloop.h * @brief Build in default eventloop extension that uses select. * */ /* - * Copyright (c) 2013, NLnet Labs, Verisign, Inc. + * Copyright (c) 2013, NLNet Labs, Verisign, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,34 +29,31 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -#ifndef _GETDNS_LIBMINI_EVENT_H_ -#define _GETDNS_LIBMINI_EVENT_H_ - +#ifndef DEFAULT_EVENTLOOP_H_ +#define DEFAULT_EVENTLOOP_H_ #include "config.h" -#ifndef USE_WINSOCK -#include "util/mini_event.h" -#else -#include "util/winsock_event.h" -#endif -#include "types-internal.h" +#include "getdns/getdns.h" +#include "getdns/getdns_extra.h" -typedef struct _getdns_mini_event { - getdns_eventloop loop; - time_t time_secs; - struct timeval time_tv; - struct _getdns_event_base *base; - size_t n_events; - struct mem_funcs mf; -} _getdns_mini_event; +/* No more than select's capability queries can be outstanding, + * The number of outstanding timeouts should be less or equal then + * the number of outstanding queries, so MAX_TIMEOUTS equal to + * FD_SETSIZE should be safe. + */ +#define MAX_TIMEOUTS FD_SETSIZE -getdns_return_t -_getdns_mini_event_init(getdns_context *context, _getdns_mini_event *mini_event); +/* Eventloop based on select */ +typedef struct _getdns_default_eventloop { + getdns_eventloop loop; + getdns_eventloop_event *fd_events[FD_SETSIZE]; + uint64_t fd_timeout_times[FD_SETSIZE]; + getdns_eventloop_event *timeout_events[MAX_TIMEOUTS]; + uint64_t timeout_times[MAX_TIMEOUTS]; +} _getdns_default_eventloop; -getdns_return_t -_getdns_mini_event_create(getdns_context *ctxt, _getdns_mini_event **mini_event); void -_getdns_mini_event_destroy(_getdns_mini_event *mini_event); +_getdns_default_eventloop_init(_getdns_default_eventloop *loop); + +#endif -#endif /* _GETDNS_LIBMINI_EVENT_H_ */ diff --git a/src/extension/libmini_event.c b/src/extension/libmini_event.c deleted file mode 100644 index def10027..00000000 --- a/src/extension/libmini_event.c +++ /dev/null @@ -1,238 +0,0 @@ -/** - * - * \file libmini_event.c - * @brief Build in default eventloop extension that uses select. - * - */ - -/* - * Copyright (c) 2013, NLnet Labs, Verisign, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the names of the copyright holders nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 Verisign, Inc. 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. - */ - -#include "config.h" -#include "debug.h" -#include "types-internal.h" -#include "extension/libmini_event.h" -#if defined(SCHED_DEBUG) && SCHED_DEBUG -#include -#endif - -static void -_getdns_mini_event_cleanup(getdns_eventloop *loop) -{ - _getdns_mini_event *ext = (_getdns_mini_event *)loop; - _getdns_event_base_free(ext->base); -} - -void -_getdns_mini_event_destroy(_getdns_mini_event *ext) -{ - assert(ext); - ext->loop.vmt->cleanup(&ext->loop); - GETDNS_FREE(ext->mf, ext); -} - -void _getdns_handle_timeouts(struct _getdns_event_base* base, - struct timeval* now, struct timeval* wait); -int _getdns_handle_select(struct _getdns_event_base* base, struct timeval* wait); - -static int -_getdns_mini_event_settime(_getdns_mini_event *ext) -{ - if (gettimeofday(&ext->time_tv, NULL) < 0) - return -1; - ext->time_secs = (time_t)ext->time_tv.tv_sec; - return 0; -} - -static void -_getdns_mini_event_run(getdns_eventloop *loop) -{ - _getdns_mini_event *ext = (_getdns_mini_event *)loop; - struct timeval wait; - - if (ext->n_events == 0 || _getdns_mini_event_settime(ext) < 0) - return; - - do { - (void) _getdns_handle_timeouts(ext->base, &ext->time_tv, &wait); - - if (!ext->n_events) - break; - - if (_getdns_handle_select(ext->base, &wait)) - break; - - } while (ext->n_events); -} - -static void -_getdns_mini_event_run_once(getdns_eventloop *loop, int blocking) -{ - static struct timeval immediately = { 0, 0 }; - _getdns_mini_event *ext = (_getdns_mini_event *)loop; - struct timeval wait; - - if (blocking) { - if (_getdns_mini_event_settime(ext) < 0) - return; - _getdns_handle_timeouts(ext->base, &ext->time_tv, &wait); - if (_getdns_handle_select(ext->base, &wait) < 0) - return; - - } else if (_getdns_handle_select(ext->base, &immediately) < 0) - return; - - _getdns_handle_timeouts(ext->base, &ext->time_tv, &wait); -} - -static getdns_return_t -_getdns_mini_event_clear(getdns_eventloop *loop, getdns_eventloop_event *el_ev) -{ - getdns_return_t r = GETDNS_RETURN_GOOD; - _getdns_mini_event *ext = (_getdns_mini_event *)loop; - - assert(el_ev->ev); - DEBUG_SCHED("1. _getdns_mini_event_clear(loop: %p, el_ev: %p[userarg: %p, r: %p, w: %p, t: %p, ev: %p]); n_events: %d, times: %d\n", loop, el_ev, el_ev->userarg, el_ev->read_cb, el_ev->write_cb, el_ev->timeout_cb, el_ev->ev, (int)ext->n_events, (int)ext->base->times->count); - - if (_getdns_event_del(el_ev->ev) != 0) - r = GETDNS_RETURN_GENERIC_ERROR; - - GETDNS_FREE(ext->mf, el_ev->ev); - el_ev->ev = NULL; - - ext->n_events--; - DEBUG_SCHED("2. %d <- _getdns_mini_event_clear(loop: %p, el_ev: %p[userarg: %p, r: %p, w: %p, t: %p, ev: %p]); n_events: %d, times: %d\n", r, loop, el_ev, el_ev->userarg, el_ev->read_cb, el_ev->write_cb, el_ev->timeout_cb, el_ev->ev, (int)ext->n_events, (int)ext->base->times->count); - - return r; -} - -static void -_getdns_mini_event_callback(int fd, short bits, void *arg) -{ - getdns_eventloop_event *el_ev = (getdns_eventloop_event *)arg; - DEBUG_SCHED("1. _getdns_mini_event_callback(fd: %d, bits: %d, el_ev: %p[userarg: %p, r: %p, w: %p, t: %p, ev: %p])\n", fd, (int)bits, el_ev, el_ev->userarg, el_ev->read_cb, el_ev->write_cb, el_ev->timeout_cb, el_ev->ev); - if (bits & EV_READ) { - assert(el_ev->read_cb); - el_ev->read_cb(el_ev->userarg); - } else if (bits & EV_WRITE) { - assert(el_ev->write_cb); - el_ev->write_cb(el_ev->userarg); - } else if (bits & EV_TIMEOUT) { - assert(el_ev->timeout_cb); - el_ev->timeout_cb(el_ev->userarg); - } else - assert(ASSERT_UNREACHABLE); -} - -static getdns_return_t -_getdns_mini_event_schedule(getdns_eventloop *loop, - int fd, uint64_t timeout, getdns_eventloop_event *el_ev) -{ - _getdns_mini_event *ext = (_getdns_mini_event *)loop; - struct _getdns_event *my_ev; - struct timeval tv = { timeout / 1000, (timeout % 1000) * 1000 }; - - assert(el_ev); - assert(!(el_ev->read_cb || el_ev->write_cb) || fd >= 0); - assert( el_ev->read_cb || el_ev->write_cb || el_ev->timeout_cb); - - if (!(my_ev = GETDNS_MALLOC(ext->mf, struct _getdns_event))) - return GETDNS_RETURN_MEMORY_ERROR; - - el_ev->ev = my_ev; - DEBUG_SCHED("1. _getdns_mini_event_schedule(loop: %p, fd: %d, timeout: %"PRId64", el_ev: %p[userarg: %p, r: %p, w: %p, t: %p, ev: %p]); n_events: %d\n", loop, fd, timeout, el_ev, el_ev->userarg, el_ev->read_cb, el_ev->write_cb, el_ev->timeout_cb, el_ev->ev, (int)ext->n_events); - _getdns_event_set(my_ev, fd, ( - (el_ev->read_cb ? EV_READ|EV_PERSIST : 0) | - (el_ev->write_cb ? EV_WRITE|EV_PERSIST : 0) | - (el_ev->timeout_cb ? EV_TIMEOUT : 0)), - _getdns_mini_event_callback, el_ev); - - if (_getdns_mini_event_settime(ext)) - goto error; - - (void) _getdns_event_base_set(ext->base, my_ev); - if (_getdns_event_add(my_ev, el_ev->timeout_cb ? &tv : NULL)) - goto error; - - ext->n_events++; - DEBUG_SCHED("2. _getdns_mini_event_schedule(loop: %p, fd: %d, timeout: %"PRId64", el_ev: %p[userarg: %p, r: %p, w: %p, t: %p, ev: %p]); n_events: %d\n", loop, fd, timeout, el_ev, el_ev->userarg, el_ev->read_cb, el_ev->write_cb, el_ev->timeout_cb, el_ev->ev, (int)ext->n_events); - - return GETDNS_RETURN_GOOD; -error: - GETDNS_FREE(ext->mf, my_ev); - el_ev->ev = NULL; - - DEBUG_SCHED("3. _getdns_mini_event_schedule(loop: %p, fd: %d, timeout: %"PRId64", el_ev: %p[userarg: %p, r: %p, w: %p, t: %p, ev: %p]); n_events: %d\n", loop, fd, timeout, el_ev, el_ev->userarg, el_ev->read_cb, el_ev->write_cb, el_ev->timeout_cb, el_ev->ev, (int)ext->n_events); - return GETDNS_RETURN_GENERIC_ERROR; -} - -getdns_return_t -_getdns_mini_event_init(getdns_context *context, _getdns_mini_event *ext) -{ - static getdns_eventloop_vmt _getdns_mini_event_vmt = { - _getdns_mini_event_cleanup, - _getdns_mini_event_schedule, - _getdns_mini_event_clear, - _getdns_mini_event_run, - _getdns_mini_event_run_once - }; - - if (!context) - return GETDNS_RETURN_BAD_CONTEXT; - if (!ext) - return GETDNS_RETURN_INVALID_PARAMETER; - -#ifdef USE_WINSOCK - int r; - WSADATA wsa_data; - - if ((r = WSAStartup(MAKEWORD(2, 2), &wsa_data)) != 0) { - printf("could not init winsock. WSAStartup: %s", - wsa_strerror(r)); - return GETDNS_RETURN_GENERIC_ERROR; - } -#endif - - ext->n_events = 0; - ext->loop.vmt = &_getdns_mini_event_vmt; - ext->base = _getdns_event_init(&ext->time_secs, &ext->time_tv); - if (!ext->base) - return GETDNS_RETURN_MEMORY_ERROR; - - ext->mf = *priv_getdns_context_mf(context); - return GETDNS_RETURN_GOOD; -} - -getdns_return_t -_getdns_mini_event_create(getdns_context *context, _getdns_mini_event **ext) -{ - if (!context) return GETDNS_RETURN_BAD_CONTEXT; - if (!ext) return GETDNS_RETURN_INVALID_PARAMETER; - - *ext = GETDNS_MALLOC(*priv_getdns_context_mf(context), _getdns_mini_event); - return _getdns_mini_event_init(context, *ext); -} diff --git a/src/stub.c b/src/stub.c index 719efc97..c09e98ed 100644 --- a/src/stub.c +++ b/src/stub.c @@ -50,12 +50,20 @@ #include "pubkey-pinning.h" #ifdef USE_WINSOCK -#define EINPROGRESS 112 -#define EWOULDBLOCK 140 typedef u_short sa_family_t; -#include "util/winsock_event.h" +#define _getdns_EWOULDBLOCK (WSAGetLastError() == WSATRY_AGAIN ||\ + WSAGetLastError() == WSAEWOULDBLOCK) +#define _getdns_EINPROGRESS (WSAGetLastError() == WSAEINPROGRESS) +#else +#define _getdns_EWOULDBLOCK (errno == EAGAIN || errno == EWOULDBLOCK) +#define _getdns_EINPROGRESS (errno == EINPROGRESS) #endif +/* WSA TODO: + * STUB_TCP_WOULDBLOCK added to deal with edge triggered event loops (versus + * level triggered). See also lines containing WSA TODO below... + */ +#define STUB_TCP_WOULDBLOCK -6 #define STUB_OUT_OF_OPTIONS -5 /* upstream options exceeded MAXIMUM_UPSTREAM_OPTION_SPACE */ #define STUB_TLS_SETUP_ERROR -4 #define STUB_TCP_AGAIN -3 @@ -402,10 +410,21 @@ tcp_connected(getdns_upstream *upstream) { int error = 0; socklen_t len = (socklen_t)sizeof(error); getsockopt(upstream->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &len); - if (error == EINPROGRESS || error == EWOULDBLOCK) - return STUB_TCP_AGAIN; /* try again */ +#ifdef USE_WINSOCK + if (error == WSAEINPROGRESS) + return STUB_TCP_WOULDBLOCK; + else if (error == WSAEWOULDBLOCK) + return STUB_TCP_WOULDBLOCK; else if (error != 0) return STUB_TCP_ERROR; +#else + if (error == EINPROGRESS) + return STUB_TCP_WOULDBLOCK; + else if (error == EWOULDBLOCK || error == EAGAIN) + return STUB_TCP_WOULDBLOCK; + else if (error != 0) + return STUB_TCP_ERROR; +#endif return 0; } @@ -625,7 +644,7 @@ stub_tls_timeout_cb(void *userarg) /****************************/ static int -stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf, getdns_eventloop_event* event) +stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf) { ssize_t read; uint8_t *buf; @@ -642,33 +661,21 @@ stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf, getdns_eventl } read = recv(fd, (void *)tcp->read_pos, tcp->to_read, 0); if (read == -1) { -#ifdef USE_WINSOCK - printf("read (in tcp ) %s\n", - wsa_strerror(WSAGetLastError())); - if (WSAGetLastError() == WSAECONNRESET) - return STUB_TCP_AGAIN; - if (WSAGetLastError() == WSAEINPROGRESS) - return STUB_TCP_AGAIN; - if (WSAGetLastError() == WSAEWOULDBLOCK) { - winsock_tcp_wouldblock(event->ev, EV_READ); - return STUB_TCP_AGAIN; - } - -#else - if (errno == EAGAIN || errno == EWOULDBLOCK) - return STUB_TCP_AGAIN; + if (_getdns_EWOULDBLOCK) + return STUB_TCP_WOULDBLOCK; else return STUB_TCP_ERROR; -#endif } else if (read == 0) { /* Remote end closed the socket */ /* TODO: Try to reconnect */ return STUB_TCP_ERROR; + } else if (read> tcp->to_read) { + return STUB_TCP_ERROR; } tcp->to_read -= read; tcp->read_pos += read; - if ((int)tcp->to_read > 0) + if (tcp->to_read > 0) return STUB_TCP_AGAIN; read = tcp->read_pos - tcp->read_buf; @@ -721,7 +728,7 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq) if (! tcp->write_buf) { /* No, this is an initial write. Try to send */ - do { + do { query_id = arc4random(); query_id_intptr = (intptr_t)query_id; netreq->node.key = (void *)query_id_intptr; @@ -754,8 +761,8 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq) /* We have an initialized packet buffer. * Lets see how much of it we can write */ -#ifdef USE_TCP_FASTOPEN /* We use sendto() here which will do both a connect and send */ +#ifdef USE_TCP_FASTOPEN written = sendto(fd, netreq->query - 2, pkt_len + 2, MSG_FASTOPEN, (struct sockaddr *)&(netreq->upstream->addr), netreq->upstream->addr_len); @@ -763,29 +770,19 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq) just fall back to a 'normal' write. */ if (written == -1 && errno == EISCONN) written = write(fd, netreq->query - 2, pkt_len + 2); - - if ((written == -1 && (errno == EAGAIN || - errno == EWOULDBLOCK || - /* Add the error case where the connection is in progress which is when - a cookie is not available (e.g. when doing the first request to an - upstream). We must let the handshake complete since non-blocking. */ - errno == EINPROGRESS)) || - written < pkt_len + 2) { #else - -#ifdef USE_WINSOCK written = sendto(fd, (const char *)(netreq->query - 2), pkt_len + 2, 0, (struct sockaddr *)&(netreq->upstream->addr), netreq->upstream->addr_len); - -#else - written = write(fd, netreq->query - 2, pkt_len + 2); #endif - if ((written == -1 && (errno == EAGAIN || - errno == EWOULDBLOCK)) || + if ((written == -1 && (_getdns_EWOULDBLOCK || + /* Add the error case where the connection is in progress which is when + a cookie is not available (e.g. when doing the first request to an + upstream). We must let the handshake complete since non-blocking. */ + _getdns_EINPROGRESS)) || written < pkt_len + 2) { -#endif + /* We couldn't write the whole packet. * We have to return with STUB_TCP_AGAIN. * Setup tcp to track the state. @@ -794,7 +791,7 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq) tcp->write_buf_len = pkt_len + 2; tcp->written = written >= 0 ? written : 0; - return STUB_TCP_AGAIN; + return STUB_TCP_WOULDBLOCK; } else if (written == -1) return STUB_TCP_ERROR; @@ -809,8 +806,8 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq) written = write(fd, tcp->write_buf + tcp->written, tcp->write_buf_len - tcp->written); if (written == -1) { - if (errno == EAGAIN || errno == EWOULDBLOCK) - return STUB_TCP_AGAIN; + if (_getdns_EWOULDBLOCK) + return STUB_TCP_WOULDBLOCK; else return STUB_TCP_ERROR; } @@ -1304,7 +1301,7 @@ stub_udp_read_cb(void *userarg) * i.e. overflow */ 0, NULL, NULL); - if (read == -1 && (errno = EAGAIN || errno == EWOULDBLOCK)) + if (read == -1 && _getdns_EWOULDBLOCK) return; if (read < GLDNS_HEADER_SIZE) @@ -1405,13 +1402,16 @@ upstream_read_cb(void *userarg) if (tls_should_read(upstream)) q = stub_tls_read(upstream, &upstream->tcp, - &upstream->upstreams->mf); + &upstream->upstreams->mf); else q = stub_tcp_read(upstream->fd, &upstream->tcp, - &upstream->upstreams->mf, &upstream->event); + &upstream->upstreams->mf); switch (q) { case STUB_TCP_AGAIN: + /* WSA TODO: if callback is still upstream_read_cb, do it again + */ + case STUB_TCP_WOULDBLOCK: return; case STUB_TCP_ERROR: @@ -1463,6 +1463,10 @@ upstream_read_cb(void *userarg) upstream_reschedule_netreq_events(upstream, netreq); _getdns_check_dns_req_complete(netreq->owner); + + /* WSA TODO: if callback is still upstream_read_cb, do it again + */ + return; } } @@ -1499,6 +1503,10 @@ upstream_write_cb(void *userarg) switch (q) { case STUB_TCP_AGAIN: + /* WSA TODO: if callback is still upstream_write_cb, do it again + */ + + case STUB_TCP_WOULDBLOCK: return; case STUB_TCP_ERROR: @@ -1553,6 +1561,8 @@ upstream_write_cb(void *userarg) netreq_upstream_write_cb : NULL), stub_timeout_cb)); } + /* WSA TODO: if callback is still upstream_write_cb, do it again + */ return; } } diff --git a/src/sync.c b/src/sync.c index ae063f87..cfc43df6 100644 --- a/src/sync.c +++ b/src/sync.c @@ -46,7 +46,7 @@ #include "gldns/wire2str.h" typedef struct getdns_sync_loop { - _getdns_mini_event loop; + _getdns_default_eventloop loop; #ifdef HAVE_LIBUNBOUND getdns_eventloop_event ub_event; #endif @@ -61,14 +61,12 @@ getdns_sync_loop_init(getdns_context *context, getdns_sync_loop *loop) #ifdef HAVE_LIBUNBOUND getdns_eventloop *ext = &loop->loop.loop; #endif - getdns_return_t r; loop->response = NULL; loop->to_run = 1; loop->context = context; - if ((r = _getdns_mini_event_init(context, &loop->loop))) - return r; + _getdns_default_eventloop_init(&loop->loop); #ifdef HAVE_LIBUNBOUND loop->ub_event.userarg = loop->context; diff --git a/src/test/Makefile.in b/src/test/Makefile.in index 016b9e22..b2c6c22d 100644 --- a/src/test/Makefile.in +++ b/src/test/Makefile.in @@ -232,21 +232,24 @@ depend: .PHONY: clean test # Dependencies for the unit tests -check_getdns.lo check_getdns.o: $(srcdir)/check_getdns.c ../getdns/getdns.h $(srcdir)/check_getdns_common.h \ - ../getdns/getdns_extra.h $(srcdir)/check_getdns_general.h \ - $(srcdir)/check_getdns_general_sync.h $(srcdir)/check_getdns_address.h \ - $(srcdir)/check_getdns_address_sync.h $(srcdir)/check_getdns_hostname.h \ - $(srcdir)/check_getdns_hostname_sync.h $(srcdir)/check_getdns_context_create.h \ - $(srcdir)/check_getdns_context_destroy.h $(srcdir)/check_getdns_cancel_callback.h \ - $(srcdir)/check_getdns_list_get_length.h $(srcdir)/check_getdns_list_get_data_type.h \ - $(srcdir)/check_getdns_list_get_dict.h $(srcdir)/check_getdns_list_get_list.h \ - $(srcdir)/check_getdns_list_get_int.h $(srcdir)/check_getdns_list_get_bindata.h \ - $(srcdir)/check_getdns_dict_get_names.h $(srcdir)/check_getdns_dict_get_data_type.h \ - $(srcdir)/check_getdns_dict_get_dict.h $(srcdir)/check_getdns_dict_get_list.h \ - $(srcdir)/check_getdns_dict_get_bindata.h $(srcdir)/check_getdns_dict_get_int.h \ - $(srcdir)/check_getdns_dict_destroy.h $(srcdir)/check_getdns_dict_set_dict.h \ - $(srcdir)/check_getdns_dict_set_list.h $(srcdir)/check_getdns_dict_set_bindata.h \ - $(srcdir)/check_getdns_dict_set_int.h $(srcdir)/check_getdns_convert_ulabel_to_alabel.h \ +check_getdns.lo check_getdns.o: $(srcdir)/check_getdns.c \ + ../getdns/getdns.h \ + $(srcdir)/check_getdns_common.h \ + ../getdns/getdns_extra.h \ + $(srcdir)/check_getdns_general.h $(srcdir)/check_getdns_general_sync.h \ + $(srcdir)/check_getdns_address.h $(srcdir)/check_getdns_address_sync.h \ + $(srcdir)/check_getdns_hostname.h $(srcdir)/check_getdns_hostname_sync.h \ + $(srcdir)/check_getdns_context_create.h $(srcdir)/check_getdns_context_destroy.h \ + $(srcdir)/check_getdns_cancel_callback.h $(srcdir)/check_getdns_list_get_length.h \ + $(srcdir)/check_getdns_list_get_data_type.h $(srcdir)/check_getdns_list_get_dict.h \ + $(srcdir)/check_getdns_list_get_list.h $(srcdir)/check_getdns_list_get_int.h \ + $(srcdir)/check_getdns_list_get_bindata.h $(srcdir)/check_getdns_dict_get_names.h \ + $(srcdir)/check_getdns_dict_get_data_type.h $(srcdir)/check_getdns_dict_get_dict.h \ + $(srcdir)/check_getdns_dict_get_list.h $(srcdir)/check_getdns_dict_get_bindata.h \ + $(srcdir)/check_getdns_dict_get_int.h $(srcdir)/check_getdns_dict_destroy.h \ + $(srcdir)/check_getdns_dict_set_dict.h $(srcdir)/check_getdns_dict_set_list.h \ + $(srcdir)/check_getdns_dict_set_bindata.h $(srcdir)/check_getdns_dict_set_int.h \ + $(srcdir)/check_getdns_convert_ulabel_to_alabel.h \ $(srcdir)/check_getdns_convert_alabel_to_ulabel.h $(srcdir)/check_getdns_pretty_print_dict.h \ $(srcdir)/check_getdns_display_ip_address.h \ $(srcdir)/check_getdns_context_set_context_update_callback.h \ @@ -254,36 +257,59 @@ check_getdns.lo check_getdns.o: $(srcdir)/check_getdns.c ../getdns/getdns.h $(sr $(srcdir)/check_getdns_context_set_upstream_recursive_servers.h \ $(srcdir)/check_getdns_service.h $(srcdir)/check_getdns_service_sync.h \ $(srcdir)/check_getdns_transport.h -check_getdns_common.lo check_getdns_common.o: $(srcdir)/check_getdns_common.c ../getdns/getdns.h \ - ../config.h $(srcdir)/check_getdns_common.h ../getdns/getdns_extra.h \ +check_getdns_common.lo check_getdns_common.o: $(srcdir)/check_getdns_common.c \ + ../getdns/getdns.h \ + ../config.h $(srcdir)/check_getdns_common.h \ + ../getdns/getdns_extra.h \ $(srcdir)/check_getdns_eventloop.h check_getdns_context_set_timeout.lo check_getdns_context_set_timeout.o: $(srcdir)/check_getdns_context_set_timeout.c \ $(srcdir)/check_getdns_context_set_timeout.h $(srcdir)/check_getdns_common.h \ - ../getdns/getdns.h ../getdns/getdns_extra.h + ../getdns/getdns.h \ + ../getdns/getdns_extra.h check_getdns_libev.lo check_getdns_libev.o: $(srcdir)/check_getdns_libev.c $(srcdir)/check_getdns_eventloop.h \ - ../config.h ../getdns/getdns.h $(srcdir)/../getdns/getdns_ext_libev.h \ - ../getdns/getdns_extra.h $(srcdir)/check_getdns_common.h + ../config.h \ + ../getdns/getdns.h \ + $(srcdir)/../getdns/getdns_ext_libev.h \ + ../getdns/getdns_extra.h \ + $(srcdir)/check_getdns_common.h check_getdns_libevent.lo check_getdns_libevent.o: $(srcdir)/check_getdns_libevent.c $(srcdir)/check_getdns_eventloop.h \ - ../config.h ../getdns/getdns.h $(srcdir)/../getdns/getdns_ext_libevent.h \ - ../getdns/getdns_extra.h $(srcdir)/check_getdns_libevent.h $(srcdir)/check_getdns_common.h + ../config.h \ + ../getdns/getdns.h \ + $(srcdir)/../getdns/getdns_ext_libevent.h \ + ../getdns/getdns_extra.h \ + $(srcdir)/check_getdns_libevent.h $(srcdir)/check_getdns_common.h check_getdns_libuv.lo check_getdns_libuv.o: $(srcdir)/check_getdns_libuv.c $(srcdir)/check_getdns_eventloop.h \ - ../config.h ../getdns/getdns.h $(srcdir)/../getdns/getdns_ext_libuv.h \ - ../getdns/getdns_extra.h $(srcdir)/check_getdns_common.h + ../config.h \ + ../getdns/getdns.h \ + $(srcdir)/../getdns/getdns_ext_libuv.h \ + ../getdns/getdns_extra.h \ + $(srcdir)/check_getdns_common.h check_getdns_selectloop.lo check_getdns_selectloop.o: $(srcdir)/check_getdns_selectloop.c \ - $(srcdir)/check_getdns_eventloop.h ../config.h ../getdns/getdns.h \ + $(srcdir)/check_getdns_eventloop.h ../config.h \ + ../getdns/getdns.h \ ../getdns/getdns_extra.h check_getdns_transport.lo check_getdns_transport.o: $(srcdir)/check_getdns_transport.c \ - $(srcdir)/check_getdns_transport.h $(srcdir)/check_getdns_common.h ../getdns/getdns.h \ + $(srcdir)/check_getdns_transport.h $(srcdir)/check_getdns_common.h \ + ../getdns/getdns.h \ ../getdns/getdns_extra.h -getdns_query.lo getdns_query.o: $(srcdir)/getdns_query.c ../config.h $(srcdir)/../debug.h ../config.h \ - ../getdns/getdns.h ../getdns/getdns_extra.h -scratchpad.template.lo scratchpad.template.o: scratchpad.template.c ../getdns/getdns.h \ +getdns_query.lo getdns_query.o: $(srcdir)/getdns_query.c \ + ../config.h $(srcdir)/../debug.h \ + ../getdns/getdns.h \ + ../getdns/getdns_extra.h +scratchpad.template.lo scratchpad.template.o: scratchpad.template.c \ + ../getdns/getdns.h \ ../getdns/getdns_extra.h testmessages.lo testmessages.o: $(srcdir)/testmessages.c $(srcdir)/testmessages.h -tests_dict.lo tests_dict.o: $(srcdir)/tests_dict.c $(srcdir)/testmessages.h ../getdns/getdns.h -tests_list.lo tests_list.o: $(srcdir)/tests_list.c $(srcdir)/testmessages.h ../getdns/getdns.h -tests_namespaces.lo tests_namespaces.o: $(srcdir)/tests_namespaces.c $(srcdir)/testmessages.h ../getdns/getdns.h -tests_stub_async.lo tests_stub_async.o: $(srcdir)/tests_stub_async.c ../config.h $(srcdir)/testmessages.h \ - ../getdns/getdns.h ../getdns/getdns_extra.h -tests_stub_sync.lo tests_stub_sync.o: $(srcdir)/tests_stub_sync.c $(srcdir)/testmessages.h ../getdns/getdns.h \ +tests_dict.lo tests_dict.o: $(srcdir)/tests_dict.c $(srcdir)/testmessages.h \ + ../getdns/getdns.h +tests_list.lo tests_list.o: $(srcdir)/tests_list.c $(srcdir)/testmessages.h \ + ../getdns/getdns.h +tests_namespaces.lo tests_namespaces.o: $(srcdir)/tests_namespaces.c $(srcdir)/testmessages.h \ + ../getdns/getdns.h +tests_stub_async.lo tests_stub_async.o: $(srcdir)/tests_stub_async.c \ + ../config.h $(srcdir)/testmessages.h \ + ../getdns/getdns.h \ + ../getdns/getdns_extra.h +tests_stub_sync.lo tests_stub_sync.o: $(srcdir)/tests_stub_sync.c $(srcdir)/testmessages.h \ + ../getdns/getdns.h \ ../getdns/getdns_extra.h diff --git a/src/util/import.sh b/src/util/import.sh index 44eabe3a..08cad0af 100755 --- a/src/util/import.sh +++ b/src/util/import.sh @@ -4,7 +4,7 @@ mkdir ub || true cd ub -for f in mini_event.c mini_event.h rbtree.c rbtree.h +for f in rbtree.c rbtree.h do wget http://unbound.net/svn/trunk/util/$f || \ ftp http://unbound.net/svn/trunk/util/$f || continue diff --git a/src/util/mini_event.c b/src/util/mini_event.c deleted file mode 100644 index 1e25f8ee..00000000 --- a/src/util/mini_event.c +++ /dev/null @@ -1,394 +0,0 @@ -/* - * mini_event.c - implementation of part of libevent api, portably. - * - * Copyright (c) 2007, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 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. - * - * Neither the name of the NLNET LABS nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "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 COPYRIGHT - * HOLDER OR CONTRIBUTORS 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. - * - */ - -/** - * \file - * fake libevent implementation. Less broad in functionality, and only - * supports select(2). - */ - -#include "config.h" -#ifdef HAVE_TIME_H -#include -#endif -#include - -#if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK) -#include -#include "util/mini_event.h" -#include "util/fptr_wlist.h" - -/** compare events in tree, based on timevalue, ptr for uniqueness */ -int _getdns_mini_ev_cmp(const void* a, const void* b) -{ - const struct _getdns_event *e = (const struct _getdns_event*)a; - const struct _getdns_event *f = (const struct _getdns_event*)b; - if(e->ev_timeout.tv_sec < f->ev_timeout.tv_sec) - return -1; - if(e->ev_timeout.tv_sec > f->ev_timeout.tv_sec) - return 1; - if(e->ev_timeout.tv_usec < f->ev_timeout.tv_usec) - return -1; - if(e->ev_timeout.tv_usec > f->ev_timeout.tv_usec) - return 1; - if(e < f) - return -1; - if(e > f) - return 1; - return 0; -} - -/** set time */ -static int -settime(struct _getdns_event_base* base) -{ - if(gettimeofday(base->time_tv, NULL) < 0) { - return -1; - } -#ifndef S_SPLINT_S - *base->time_secs = (time_t)base->time_tv->tv_sec; -#endif - return 0; -} - -/** create event base */ -void *_getdns_event_init(time_t* time_secs, struct timeval* time_tv) -{ - struct _getdns_event_base* base = (struct _getdns_event_base*)malloc( - sizeof(struct _getdns_event_base)); - if(!base) - return NULL; - memset(base, 0, sizeof(*base)); - base->time_secs = time_secs; - base->time_tv = time_tv; - if(settime(base) < 0) { - _getdns_event_base_free(base); - return NULL; - } - base->times = _getdns_rbtree_create(_getdns_mini_ev_cmp); - if(!base->times) { - _getdns_event_base_free(base); - return NULL; - } - base->capfd = MAX_FDS; -#ifdef FD_SETSIZE - if((int)FD_SETSIZE < base->capfd) - base->capfd = (int)FD_SETSIZE; -#endif - base->fds = (struct _getdns_event**)calloc((size_t)base->capfd, - sizeof(struct _getdns_event*)); - if(!base->fds) { - _getdns_event_base_free(base); - return NULL; - } - base->signals = (struct _getdns_event**)calloc(MAX_SIG, sizeof(struct _getdns_event*)); - if(!base->signals) { - _getdns_event_base_free(base); - return NULL; - } -#ifndef S_SPLINT_S - FD_ZERO(&base->reads); - FD_ZERO(&base->writes); -#endif - return base; -} - -/** get version */ -const char *_getdns_event_get_version(void) -{ - return "mini-event-"PACKAGE_VERSION; -} - -/** get polling method, select */ -const char *_getdns_event_get_method(void) -{ - return "select"; -} - -/** call timeouts handlers, and return how long to wait for next one or -1 */ -void _getdns_handle_timeouts(struct _getdns_event_base* base, struct timeval* now, - struct timeval* wait) -{ - struct _getdns_event* p; -#ifndef S_SPLINT_S - wait->tv_sec = (time_t)-1; -#endif - - while((_getdns_rbnode_t*)(p = (struct _getdns_event*)_getdns_rbtree_first(base->times)) - !=RBTREE_NULL) { -#ifndef S_SPLINT_S - if(p->ev_timeout.tv_sec > now->tv_sec || - (p->ev_timeout.tv_sec==now->tv_sec && - p->ev_timeout.tv_usec > now->tv_usec)) { - /* there is a next larger timeout. wait for it */ - wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec; - if(now->tv_usec > p->ev_timeout.tv_usec) { - wait->tv_sec--; - wait->tv_usec = 1000000 - (now->tv_usec - - p->ev_timeout.tv_usec); - } else { - wait->tv_usec = p->ev_timeout.tv_usec - - now->tv_usec; - } - return; - } -#endif - /* event times out, remove it */ - (void)_getdns_rbtree_delete(base->times, p); - p->ev_events &= ~EV_TIMEOUT; - fptr_ok(fptr_whitelist_event(p->ev_callback)); - (*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg); - } -} - -/** call select and callbacks for that */ -int _getdns_handle_select(struct _getdns_event_base* base, struct timeval* wait) -{ - fd_set r, w; - int ret, i; - -#ifndef S_SPLINT_S - if(wait->tv_sec==(time_t)-1) - wait = NULL; -#endif - memmove(&r, &base->reads, sizeof(fd_set)); - memmove(&w, &base->writes, sizeof(fd_set)); - memmove(&base->ready, &base->content, sizeof(fd_set)); - - if((ret = select(base->maxfd+1, &r, &w, NULL, wait)) == -1) { - ret = errno; - if(settime(base) < 0) - return -1; - errno = ret; - if(ret == EAGAIN || ret == EINTR) - return 0; - return -1; - } - if(settime(base) < 0) - return -1; - - for(i=0; imaxfd+1; i++) { - short bits = 0; - if(!base->fds[i] || !(FD_ISSET(i, &base->ready))) { - continue; - } - if(FD_ISSET(i, &r)) { - bits |= EV_READ; - ret--; - } - if(FD_ISSET(i, &w)) { - bits |= EV_WRITE; - ret--; - } - bits &= base->fds[i]->ev_events; - if(bits) { - fptr_ok(fptr_whitelist_event( - base->fds[i]->ev_callback)); - (*base->fds[i]->ev_callback)(base->fds[i]->ev_fd, - bits, base->fds[i]->ev_arg); - if(ret==0) - break; - } - } - return 0; -} - -/** run select in a loop */ -int _getdns_event_base_dispatch(struct _getdns_event_base* base) -{ - struct timeval wait; - if(settime(base) < 0) - return -1; - while(!base->need_to_exit) - { - /* see if timeouts need handling */ - _getdns_handle_timeouts(base, base->time_tv, &wait); - if(base->need_to_exit) - return 0; - /* do select */ - if(_getdns_handle_select(base, &wait) < 0) { - if(base->need_to_exit) - return 0; - return -1; - } - } - return 0; -} - -/** exit that loop */ -int _getdns_event_base_loopexit(struct _getdns_event_base* base, - struct timeval* ATTR_UNUSED(tv)) -{ - base->need_to_exit = 1; - return 0; -} - -/* free event base, free events yourself */ -void _getdns_event_base_free(struct _getdns_event_base* base) -{ - if(!base) - return; - if(base->times) - free(base->times); - if(base->fds) - free(base->fds); - if(base->signals) - free(base->signals); - free(base); -} - -/** set content of event */ -void _getdns_event_set(struct _getdns_event* ev, int fd, short bits, - void (*cb)(int, short, void *), void* arg) -{ - ev->node.key = ev; - ev->ev_fd = fd; - ev->ev_events = bits; - ev->ev_callback = cb; - fptr_ok(fptr_whitelist_event(ev->ev_callback)); - ev->ev_arg = arg; - ev->added = 0; -} - -/* add event to a base */ -int _getdns_event_base_set(struct _getdns_event_base* base, struct _getdns_event* ev) -{ - ev->ev_base = base; - ev->added = 0; - return 0; -} - -/* add event to make it active, you may not change it with _getdns_event_set anymore */ -int _getdns_event_add(struct _getdns_event* ev, struct timeval* tv) -{ - if(ev->added) - _getdns_event_del(ev); - if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd) - return -1; - if( (ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) { - ev->ev_base->fds[ev->ev_fd] = ev; - if(ev->ev_events&EV_READ) { - FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->reads); - } - if(ev->ev_events&EV_WRITE) { - FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->writes); - } - FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->content); - FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready); - if(ev->ev_fd > ev->ev_base->maxfd) - ev->ev_base->maxfd = ev->ev_fd; - } - if(tv && (ev->ev_events&EV_TIMEOUT)) { -#ifndef S_SPLINT_S - struct timeval *now = ev->ev_base->time_tv; - ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec; - ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec; - while(ev->ev_timeout.tv_usec > 1000000) { - ev->ev_timeout.tv_usec -= 1000000; - ev->ev_timeout.tv_sec++; - } -#endif - (void)_getdns_rbtree_insert(ev->ev_base->times, &ev->node); - } - ev->added = 1; - return 0; -} - -/* remove event, you may change it again */ -int _getdns_event_del(struct _getdns_event* ev) -{ - if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd) - return -1; - if((ev->ev_events&EV_TIMEOUT)) - (void)_getdns_rbtree_delete(ev->ev_base->times, &ev->node); - if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) { - ev->ev_base->fds[ev->ev_fd] = NULL; - FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->reads); - FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->writes); - FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready); - FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->content); - } - ev->added = 0; - return 0; -} - -/** which base gets to handle signals */ -static struct _getdns_event_base* signal_base = NULL; -/** signal handler */ -static RETSIGTYPE sigh(int sig) -{ - struct _getdns_event* ev; - if(!signal_base || sig < 0 || sig >= MAX_SIG) - return; - ev = signal_base->signals[sig]; - if(!ev) - return; - fptr_ok(fptr_whitelist_event(ev->ev_callback)); - (*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg); -} - -/** install signal handler */ -int _getdns_signal_add(struct _getdns_event* ev, struct timeval* ATTR_UNUSED(tv)) -{ - if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG) - return -1; - signal_base = ev->ev_base; - ev->ev_base->signals[ev->ev_fd] = ev; - ev->added = 1; - if(signal(ev->ev_fd, sigh) == SIG_ERR) { - return -1; - } - return 0; -} - -/** remove signal handler */ -int _getdns_signal_del(struct _getdns_event* ev) -{ - if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG) - return -1; - ev->ev_base->signals[ev->ev_fd] = NULL; - ev->added = 0; - return 0; -} - -#else /* USE_MINI_EVENT */ -#ifndef USE_WINSOCK -int _getdns_mini_ev_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) -{ - return 0; -} -#endif /* not USE_WINSOCK */ -#endif /* USE_MINI_EVENT */ diff --git a/src/util/mini_event.h b/src/util/mini_event.h deleted file mode 100644 index ff675f15..00000000 --- a/src/util/mini_event.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * mini-event.h - micro implementation of libevent api, using select() only. - * - * Copyright (c) 2007, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 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. - * - * Neither the name of the NLNET LABS nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "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 COPYRIGHT - * HOLDER OR CONTRIBUTORS 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. - */ - -/** - * \file - * This file implements part of the event(3) libevent api. - * The back end is only select. Max number of fds is limited. - * Max number of signals is limited, one handler per signal only. - * And one handler per fd. - * - * Although limited to select() and a max (1024) open fds, it - * is efficient: - * o dispatch call caches fd_sets to use. - * o handler calling takes time ~ to the number of fds. - * o timeouts are stored in a redblack tree, sorted, so take log(n). - * Timeouts are only accurate to the second (no subsecond accuracy). - * To avoid cpu hogging, fractional timeouts are rounded up to a whole second. - */ - -#ifndef MINI_EVENT_H -#define MINI_EVENT_H - -#if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK) - -#ifndef HAVE_EVENT_BASE_FREE -#define HAVE_EVENT_BASE_FREE -#endif - - -/** event timeout */ -#define EV_TIMEOUT 0x01 -/** event fd readable */ -#define EV_READ 0x02 -/** event fd writable */ -#define EV_WRITE 0x04 -/** event signal */ -#define EV_SIGNAL 0x08 -/** event must persist */ -#define EV_PERSIST 0x10 - -/* needs our redblack tree */ -#include "util/rbtree.h" - -/** max number of file descriptors to support */ -#define MAX_FDS 1024 -/** max number of signals to support */ -#define MAX_SIG 32 - -/** event base */ -struct _getdns_event_base -{ - /** sorted by timeout (absolute), ptr */ - _getdns_rbtree_t* times; - /** array of 0 - maxfd of ptr to event for it */ - struct _getdns_event** fds; - /** max fd in use */ - int maxfd; - /** capacity - size of the fds array */ - int capfd; - /* fdset for read write, for fds ready, and added */ - fd_set - /** fds for reading */ - reads, - /** fds for writing */ - writes, - /** fds determined ready for use */ - ready, - /** ready plus newly added events. */ - content; - /** array of 0 - maxsig of ptr to event for it */ - struct _getdns_event** signals; - /** if we need to exit */ - int need_to_exit; - /** where to store time in seconds */ - time_t* time_secs; - /** where to store time in microseconds */ - struct timeval* time_tv; -}; - -/** - * Event structure. Has some of the event elements. - */ -struct _getdns_event { - /** node in timeout rbtree */ - _getdns_rbnode_t node; - /** is event already added */ - int added; - - /** event base it belongs to */ - struct _getdns_event_base *ev_base; - /** fd to poll or -1 for timeouts. signal number for sigs. */ - int ev_fd; - /** what events this event is interested in, see EV_.. above. */ - short ev_events; - /** timeout value */ - struct timeval ev_timeout; - - /** callback to call: fd, eventbits, userarg */ - void (*ev_callback)(int, short, void *arg); - /** callback user arg */ - void *ev_arg; -}; - -/* function prototypes (some are as they appear in event.h) */ -/** create event base */ -void *_getdns_event_init(time_t* time_secs, struct timeval* time_tv); -/** get version */ -const char *_getdns_event_get_version(void); -/** get polling method, select */ -const char *_getdns_event_get_method(void); -/** run select in a loop */ -int _getdns_event_base_dispatch(struct _getdns_event_base *); -/** exit that loop */ -int _getdns_event_base_loopexit(struct _getdns_event_base *, struct timeval *); -/** free event base. Free events yourself */ -void _getdns_event_base_free(struct _getdns_event_base *); -/** set content of event */ -void _getdns_event_set(struct _getdns_event *, int, short, void (*)(int, short, void *), void *); -/** add event to a base. You *must* call this for every event. */ -int _getdns_event_base_set(struct _getdns_event_base *, struct _getdns_event *); -/** add event to make it active. You may not change it with _getdns_event_set anymore */ -int _getdns_event_add(struct _getdns_event *, struct timeval *); -/** remove event. You may change it again */ -int _getdns_event_del(struct _getdns_event *); - -/** add a timer */ -#define _getdns_evtimer_add(ev, tv) _getdns_event_add(ev, tv) -/** remove a timer */ -#define _getdns_evtimer_del(ev) _getdns_event_del(ev) - -/* uses different implementation. Cannot mix fd/timeouts and signals inside - * the same struct _getdns_event. create several event structs for that. */ -/** install signal handler */ -int _getdns_signal_add(struct _getdns_event *, struct timeval *); -/** set signal event contents */ -#define _getdns_signal_set(ev, x, cb, arg) \ - _getdns_event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg) -/** remove signal handler */ -int _getdns_signal_del(struct _getdns_event *); - -#endif /* USE_MINI_EVENT and not USE_WINSOCK */ - -/** compare events in tree, based on timevalue, ptr for uniqueness */ -int _getdns_mini_ev_cmp(const void* a, const void* b); - -#endif /* MINI_EVENT_H */ diff --git a/src/util/winsock_event.c b/src/util/winsock_event.c deleted file mode 100644 index 2df44558..00000000 --- a/src/util/winsock_event.c +++ /dev/null @@ -1,844 +0,0 @@ -/* - * util/winsock_event.c - implementation of the getdns winsock event handler. - * - * Copyright (c) 2015, Verisign/NLnet Labs. All rights reserved. - * - * This software is open source. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 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. - * - * Neither the name of the NLNET LABS/Verisign nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "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 COPYRIGHT - * HOLDER OR CONTRIBUTORS 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. - */ -/** - * \file - * Implementation of the getdns WinSock2 API event notification handler - * for the getdns Windows port. - * Code is originally from the Unbound source for Windows. - */ - -#include "config.h" -#ifdef USE_WINSOCK // only included for Windows builds -#include -#ifdef HAVE_TIME_H -#include -#endif -#include -#include "util/winsock_event.h" -#include "util/fptr_wlist.h" - -/** -* implementation of log_err -* @param format: format string printf-style. -*/ -void -log_err(const char *format, ...) -{ - va_list args; - va_start(args, format); - fprintf(stderr, "error "); - fprintf(stderr, format, args); - va_end(args); -} - - -char* wsa_strerror(DWORD err) -{ - static char unknown[32]; - - switch (err) { - case WSA_INVALID_HANDLE: return "Specified event object handle is invalid."; - case WSA_NOT_ENOUGH_MEMORY: return "Insufficient memory available."; - case WSA_INVALID_PARAMETER: return "One or more parameters are invalid."; - case WSA_OPERATION_ABORTED: return "Overlapped operation aborted."; - case WSA_IO_INCOMPLETE: return "Overlapped I/O event object not in signaled state."; - case WSA_IO_PENDING: return "Overlapped operations will complete later."; - case WSAEINTR: return "Interrupted function call."; - case WSAEBADF: return "File handle is not valid."; - case WSAEACCES: return "Permission denied."; - case WSAEFAULT: return "Bad address."; - case WSAEINVAL: return "Invalid argument."; - case WSAEMFILE: return "Too many open files."; - case WSAEWOULDBLOCK: return "Resource temporarily unavailable."; - case WSAEINPROGRESS: return "Operation now in progress."; - case WSAEALREADY: return "Operation already in progress."; - case WSAENOTSOCK: return "Socket operation on nonsocket."; - case WSAEDESTADDRREQ: return "Destination address required."; - case WSAEMSGSIZE: return "Message too long."; - case WSAEPROTOTYPE: return "Protocol wrong type for socket."; - case WSAENOPROTOOPT: return "Bad protocol option."; - case WSAEPROTONOSUPPORT: return "Protocol not supported."; - case WSAESOCKTNOSUPPORT: return "Socket type not supported."; - case WSAEOPNOTSUPP: return "Operation not supported."; - case WSAEPFNOSUPPORT: return "Protocol family not supported."; - case WSAEAFNOSUPPORT: return "Address family not supported by protocol family."; - case WSAEADDRINUSE: return "Address already in use."; - case WSAEADDRNOTAVAIL: return "Cannot assign requested address."; - case WSAENETDOWN: return "Network is down."; - case WSAENETUNREACH: return "Network is unreachable."; - case WSAENETRESET: return "Network dropped connection on reset."; - case WSAECONNABORTED: return "Software caused connection abort."; - case WSAECONNRESET: return "Connection reset by peer."; - case WSAENOBUFS: return "No buffer space available."; - case WSAEISCONN: return "Socket is already connected."; - case WSAENOTCONN: return "Socket is not connected."; - case WSAESHUTDOWN: return "Cannot send after socket shutdown."; - case WSAETOOMANYREFS: return "Too many references."; - case WSAETIMEDOUT: return "Connection timed out."; - case WSAECONNREFUSED: return "Connection refused."; - case WSAELOOP: return "Cannot translate name."; - case WSAENAMETOOLONG: return "Name too long."; - case WSAEHOSTDOWN: return "Host is down."; - case WSAEHOSTUNREACH: return "No route to host."; - case WSAENOTEMPTY: return "Directory not empty."; - case WSAEPROCLIM: return "Too many processes."; - case WSAEUSERS: return "User quota exceeded."; - case WSAEDQUOT: return "Disk quota exceeded."; - case WSAESTALE: return "Stale file handle reference."; - case WSAEREMOTE: return "Item is remote."; - case WSASYSNOTREADY: return "Network subsystem is unavailable."; - case WSAVERNOTSUPPORTED: return "Winsock.dll version out of range."; - case WSANOTINITIALISED: return "Successful WSAStartup not yet performed."; - case WSAEDISCON: return "Graceful shutdown in progress."; - case WSAENOMORE: return "No more results."; - case WSAECANCELLED: return "Call has been canceled."; - case WSAEINVALIDPROCTABLE: return "Procedure call table is invalid."; - case WSAEINVALIDPROVIDER: return "Service provider is invalid."; - case WSAEPROVIDERFAILEDINIT: return "Service provider failed to initialize."; - case WSASYSCALLFAILURE: return "System call failure."; - case WSASERVICE_NOT_FOUND: return "Service not found."; - case WSATYPE_NOT_FOUND: return "Class type not found."; - case WSA_E_NO_MORE: return "No more results."; - case WSA_E_CANCELLED: return "Call was canceled."; - case WSAEREFUSED: return "Database query was refused."; - case WSAHOST_NOT_FOUND: return "Host not found."; - case WSATRY_AGAIN: return "Nonauthoritative host not found."; - case WSANO_RECOVERY: return "This is a nonrecoverable error."; - case WSANO_DATA: return "Valid name, no data record of requested type."; - case WSA_QOS_RECEIVERS: return "QOS receivers."; - case WSA_QOS_SENDERS: return "QOS senders."; - case WSA_QOS_NO_SENDERS: return "No QOS senders."; - case WSA_QOS_NO_RECEIVERS: return "QOS no receivers."; - case WSA_QOS_REQUEST_CONFIRMED: return "QOS request confirmed."; - case WSA_QOS_ADMISSION_FAILURE: return "QOS admission error."; - case WSA_QOS_POLICY_FAILURE: return "QOS policy failure."; - case WSA_QOS_BAD_STYLE: return "QOS bad style."; - case WSA_QOS_BAD_OBJECT: return "QOS bad object."; - case WSA_QOS_TRAFFIC_CTRL_ERROR: return "QOS traffic control error."; - case WSA_QOS_GENERIC_ERROR: return "QOS generic error."; - case WSA_QOS_ESERVICETYPE: return "QOS service type error."; - case WSA_QOS_EFLOWSPEC: return "QOS flowspec error."; - case WSA_QOS_EPROVSPECBUF: return "Invalid QOS provider buffer."; - case WSA_QOS_EFILTERSTYLE: return "Invalid QOS filter style."; - case WSA_QOS_EFILTERTYPE: return "Invalid QOS filter type."; - case WSA_QOS_EFILTERCOUNT: return "Incorrect QOS filter count."; - case WSA_QOS_EOBJLENGTH: return "Invalid QOS object length."; - case WSA_QOS_EFLOWCOUNT: return "Incorrect QOS flow count."; - /*case WSA_QOS_EUNKOWNPSOBJ: return "Unrecognized QOS object.";*/ - case WSA_QOS_EPOLICYOBJ: return "Invalid QOS policy object."; - case WSA_QOS_EFLOWDESC: return "Invalid QOS flow descriptor."; - case WSA_QOS_EPSFLOWSPEC: return "Invalid QOS provider-specific flowspec."; - case WSA_QOS_EPSFILTERSPEC: return "Invalid QOS provider-specific filterspec."; - case WSA_QOS_ESDMODEOBJ: return "Invalid QOS shape discard mode object."; - case WSA_QOS_ESHAPERATEOBJ: return "Invalid QOS shaping rate object."; - case WSA_QOS_RESERVED_PETYPE: return "Reserved policy QOS element type."; - default: - snprintf(unknown, sizeof(unknown), - "unknown WSA error code %d", (int)err); - return unknown; - } -} - -int _getdns_mini_ev_cmp(const void* a, const void* b) -{ - const struct _getdns_event *e = (const struct _getdns_event*)a; - const struct _getdns_event *f = (const struct _getdns_event*)b; - if(e->ev_timeout.tv_sec < f->ev_timeout.tv_sec) - return -1; - if(e->ev_timeout.tv_sec > f->ev_timeout.tv_sec) - return 1; - if(e->ev_timeout.tv_usec < f->ev_timeout.tv_usec) - return -1; - if(e->ev_timeout.tv_usec > f->ev_timeout.tv_usec) - return 1; - if(e < f) - return -1; - if(e > f) - return 1; - return 0; -} - -/** set time */ -static int -settime(struct _getdns_event_base* base) -{ - if(gettimeofday(base->time_tv, NULL) < 0) { - return -1; - } -#ifndef S_SPLINT_S - *base->time_secs = (time_t)base->time_tv->tv_sec; -#endif - return 0; -} - -#ifdef WINSOCK_DEBUG -/** - * Find a fd in the list of items. - * Note that not all items have a fd associated (those are -1). - * Signals are stored separately, and not searched. - * @param base: event base to look in. - * @param fd: what socket to look for. - * @return the index in the array, or -1 on failure. - */ -static int -find_fd(struct _getdns_event_base* base, int fd) -{ - int i; - for(i=0; imax; i++) { - if(base->items[i]->ev_fd == fd) - return i; - } - return -1; -} -#endif - -/** Find ptr in base array */ -static void -zero_waitfor(WSAEVENT waitfor[], WSAEVENT x) -{ - int i; - for(i=0; itime_secs = time_secs; - base->time_tv = time_tv; - if(settime(base) < 0) { - _getdns_event_base_free(base); - return NULL; - } - base->items = (struct _getdns_event**)calloc(WSK_MAX_ITEMS, - sizeof(struct _getdns_event*)); - if(!base->items) { - _getdns_event_base_free(base); - return NULL; - } - base->cap = WSK_MAX_ITEMS; - base->max = 0; - base->times = _getdns_rbtree_create(_getdns_mini_ev_cmp); - if(!base->times) { - _getdns_event_base_free(base); - return NULL; - } - base->signals = (struct _getdns_event**)calloc(MAX_SIG, - sizeof(struct _getdns_event*)); - if(!base->signals) { - _getdns_event_base_free(base); - return NULL; - } - base->tcp_stickies = 0; - base->tcp_reinvigorated = 0; - - return base; -} - -const char *_getdns_event_get_version(void) -{ - return "winsock-event-"PACKAGE_VERSION; -} - -const char *_getdns_event_get_method(void) -{ - return "WSAWaitForMultipleEvents"; -} - -/** call timeouts handlers, and return how long to wait for next one or -1 */ -void _getdns_handle_timeouts(struct _getdns_event_base* base, struct timeval* now, - struct timeval* wait) -{ - struct _getdns_event* p; -#ifndef S_SPLINT_S - wait->tv_sec = (time_t)-1; -#endif - - while((_getdns_rbnode_t*)(p = (struct _getdns_event*)_getdns_rbtree_first(base->times)) - !=RBTREE_NULL) { -#ifndef S_SPLINT_S - if(p->ev_timeout.tv_sec > now->tv_sec || - (p->ev_timeout.tv_sec==now->tv_sec && - p->ev_timeout.tv_usec > now->tv_usec)) { - /* there is a next larger timeout. wait for it */ - wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec; - if(now->tv_usec > p->ev_timeout.tv_usec) { - wait->tv_sec--; - wait->tv_usec = 1000000 - (now->tv_usec - - p->ev_timeout.tv_usec); - } else { - wait->tv_usec = p->ev_timeout.tv_usec - - now->tv_usec; - } - return; - } -#endif - /* event times out, remove it */ - (void)_getdns_rbtree_delete(base->times, p); - p->ev_events &= ~EV_TIMEOUT; - fptr_ok(fptr_whitelist_event(p->ev_callback)); - (*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg); - } -} - -/** handle is_signal events and see if signalled */ -static void _getdns_handle_signal(struct _getdns_event* ev) -{ - printf("In _getdns_handle_signal\n"); - DWORD ret; - //log_assert(ev->is_signal && ev->hEvent); - /* see if the event is signalled */ - ret = WSAWaitForMultipleEvents(1, &ev->hEvent, 0 /* any object */, - 0 /* return immediately */, 0 /* not alertable for IOcomple*/); - if(ret == WSA_WAIT_IO_COMPLETION || ret == WSA_WAIT_FAILED) { - log_err("getdns: WSAWaitForMultipleEvents(signal) failed: %s", - wsa_strerror(WSAGetLastError())); - return; - } - if(ret == WSA_WAIT_TIMEOUT) { - /* not signalled */ - return; - } - - /* reset the signal */ - if(!WSAResetEvent(ev->hEvent)) - log_err("getdns: WSAResetEvent failed: %s", - wsa_strerror(WSAGetLastError())); - /* do the callback (which may set the signal again) */ - fptr_ok(fptr_whitelist_event(ev->ev_callback)); - (*ev->ev_callback)(ev->ev_fd, ev->ev_events, ev->ev_arg); -} - -/** call select and callbacks for that */ -int _getdns_handle_select(struct _getdns_event_base* base, struct timeval* wait) -{ - DWORD timeout = 0; /* in milliseconds */ - DWORD ret; - WSANETWORKEVENTS netev; - struct _getdns_event* eventlist[WSK_MAX_ITEMS]; - int i, numwait = 0, startidx = 0; - int newstickies = 0; - struct timeval nultm; - -#ifndef S_SPLINT_S - if(wait->tv_sec==(time_t)-1) - wait = NULL; - if (wait) - // timeout = 10 + wait->tv_usec / 1000; - timeout = wait->tv_sec * 1000 + wait->tv_usec / 1000; - if(base->tcp_stickies) { - wait = &nultm; - nultm.tv_sec = 0; - nultm.tv_usec = 0; - timeout = 0; /* no waiting, we have sticky events */ - } -#endif - - /* prepare event array */ - for(i=0; imax; i++) { - if(base->items[i]->ev_fd == -1 && !base->items[i]->is_signal) - continue; /* skip timer only events */ - eventlist[numwait] = base->items[i]; - base->waitfor[numwait++] = base->items[i]->hEvent; - printf("winsock_event bmax=%d numwait=%d wait=%x " - "timeout=%d hEvent %d\n", base->max, numwait, (int)wait, - (int)timeout, (int)base->items[i]->hEvent); - if (numwait == WSK_MAX_ITEMS) - break; /* sanity check */ - } - //log_assert(numwait <= WSA_MAXIMUM_WAIT_EVENTS); - - /* do the wait */ - if(numwait == 0) { - /* WSAWaitFor.. doesn't like 0 event objects */ - if(wait) { - Sleep(timeout); - } - } - else { - //gv: do not schedule udp write - for (i = 0; imax; i++) { - if (!base->items[i]->is_tcp && base->items[i]->ev_events&EV_WRITE) { - printf("skip UDP sched\n"); - (*eventlist[i]->ev_callback)(eventlist[i]->ev_fd, - EV_WRITE & eventlist[i]->ev_events, - eventlist[i]->ev_arg); - return 0; - } - } - printf("before wait %d\n", base->items[0]->ev_events); - ret = WSAWaitForMultipleEvents(numwait, base->waitfor, - 0 /* do not wait for all, just one will do */, - wait?timeout:WSA_INFINITE, - 0); /* we are not alertable (IO completion events) */ - printf("after wait %d %d\n", (int)ret, numwait); - if(ret == WSA_WAIT_IO_COMPLETION) { - //printf("getdns: WSAWaitForMultipleEvents failed: WSA_WAIT_IO_COMPLETION"); - return -1; - } else if(ret == WSA_WAIT_FAILED) { - //printf("getdns: WSAWaitForMultipleEvents failed: %s", - // wsa_strerror(WSAGetLastError())); - return -1; - } else if(ret == WSA_WAIT_TIMEOUT) { - printf("timeout\n"); - } else - startidx = ret - WSA_WAIT_EVENT_0; - } - ////verbose(VERB_CLIENT, "winsock_event wake was_timeout=%d startidx=%d", - // was_timeout, startidx); - - /* get new time after wait */ - if(settime(base) < 0) - return -1; - - /* callbacks */ - if(base->tcp_stickies) - startidx = 0; /* process all events, some are sticky */ - for(i=startidx; ijust_checked = 1; - - //verbose(VERB_CLIENT, "winsock_event signals"); - for(i=startidx; iwaitfor[i]) - continue; /* was deleted */ - if(eventlist[i]->is_signal) { - eventlist[i]->just_checked = 0; - _getdns_handle_signal(eventlist[i]); - } - } - /* early exit - do not process network, exit quickly */ - if(base->need_to_exit) - return 0; - - //verbose(VERB_CLIENT, "winsock_event net"); - for(i=startidx; iwaitfor[i]) - continue; /* was deleted */ - if(!eventlist[i]->just_checked) - continue; /* added by other callback */ - if(eventlist[i]->is_signal) - continue; /* not a network event at all */ - eventlist[i]->just_checked = 0; - - if(WSAEnumNetworkEvents(eventlist[i]->ev_fd, - base->waitfor[i], /* reset the event handle */ - /*NULL,*/ /* do not reset the event handle */ - &netev) != 0) { - log_err("getdns: WSAEnumNetworkEvents failed: %s", - wsa_strerror(WSAGetLastError())); - return -1; - } - if((netev.lNetworkEvents & FD_READ)) { - if(netev.iErrorCode[FD_READ_BIT] != 0) - printf("FD_READ_BIT error: %s\n", - wsa_strerror(netev.iErrorCode[FD_READ_BIT])); - bits |= EV_READ; - printf("FD_READ_BIT\n"); - } - if((netev.lNetworkEvents & FD_WRITE)) { - if(netev.iErrorCode[FD_WRITE_BIT] != 0) - printf("FD_WRITE_BIT error: %s\n", - wsa_strerror(netev.iErrorCode[FD_WRITE_BIT])); - bits |= EV_WRITE; - printf("FD_WRITE_BIT\n"); - } - if((netev.lNetworkEvents & FD_CONNECT)) { - if(netev.iErrorCode[FD_CONNECT_BIT] != 0) - printf("FD_CONNECT_BIT error: %s\n", - wsa_strerror(netev.iErrorCode[FD_CONNECT_BIT])); - bits |= EV_READ; - bits |= EV_WRITE; - printf("FD_CONNECT_BIT\n"); - } - if((netev.lNetworkEvents & FD_ACCEPT)) { - if(netev.iErrorCode[FD_ACCEPT_BIT] != 0) - printf("FD_ACCEPT_BIT error: %s\n", - wsa_strerror(netev.iErrorCode[FD_ACCEPT_BIT])); - bits |= EV_READ; - printf("FD_ACCEPT_BIT\n"); - } - if((netev.lNetworkEvents & FD_CLOSE)) { - if(netev.iErrorCode[FD_CLOSE_BIT] != 0) - printf("FD_CLOSE_BIT error: %s\n", - wsa_strerror(netev.iErrorCode[FD_CLOSE_BIT])); - //g bits |= EV_READ; - //g bits |= EV_WRITE; - printf("FD_CLOSE_BIT\n"); - } - if(eventlist[i]->is_tcp && eventlist[i]->stick_events) { - - printf("winsock %d pass sticky %s%s\n", - eventlist[i]->ev_fd, - (eventlist[i]->old_events&EV_READ)?"EV_READ":"", - (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); - - bits |= eventlist[i]->old_events; - } - if(eventlist[i]->is_tcp && bits) { - eventlist[i]->old_events = bits; - eventlist[i]->stick_events = 1; - if((eventlist[i]->ev_events & bits)) { - newstickies = 1; - } - - printf("winsock %d store sticky %s%s", - eventlist[i]->ev_fd, - (eventlist[i]->old_events&EV_READ)?"EV_READ":"", - (eventlist[i]->old_events&EV_WRITE) ? "EV_WRITE" : ""); - - } - if((bits & eventlist[i]->ev_events)) { - printf( "winsock event callback %p fd=%d " - "%s%s%s%s%s ; %s%s%s\n", - eventlist[i], eventlist[i]->ev_fd, - (netev.lNetworkEvents&FD_READ)?" FD_READ":"", - (netev.lNetworkEvents&FD_WRITE)?" FD_WRITE":"", - (netev.lNetworkEvents&FD_CONNECT)? - " FD_CONNECT":"", - (netev.lNetworkEvents&FD_ACCEPT)? - " FD_ACCEPT":"", - (netev.lNetworkEvents&FD_CLOSE)?" FD_CLOSE":"", - (bits&EV_READ)?" EV_READ":"", - (bits&EV_WRITE)?" EV_WRITE":"", - (bits&EV_TIMEOUT)?" EV_TIMEOUT":""); - - fptr_ok(fptr_whitelist_event( - eventlist[i]->ev_callback)); - (*eventlist[i]->ev_callback)(eventlist[i]->ev_fd, - bits & eventlist[i]->ev_events, - eventlist[i]->ev_arg); - } - - if(eventlist[i]->is_tcp && bits) - printf( "winsock %d got sticky %s%s\n", - eventlist[i]->ev_fd, - (eventlist[i]->old_events&EV_READ)?"EV_READ":"", - (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); - - } - //verbose(VERB_CLIENT, "winsock_event net"); - if(base->tcp_reinvigorated) { - printf("winsock_event reinvigorated\n"); - base->tcp_reinvigorated = 0; - newstickies = 1; - } - base->tcp_stickies = newstickies; - //gprintf("winsock_event handle_select end\n"); - return 0; -} - -int _getdns_event_base_dispatch(struct _getdns_event_base *base) -{ - struct timeval wait; - if(settime(base) < 0) - return -1; - while(!base->need_to_exit) - { - /* see if timeouts need handling */ - _getdns_handle_timeouts(base, base->time_tv, &wait); - if(base->need_to_exit) - return 0; - /* do select */ - if(_getdns_handle_select(base, &wait) < 0) { - if(base->need_to_exit) - return 0; - return -1; - } - } - return 0; -} - -int _getdns_event_base_loopexit(struct _getdns_event_base *base, - struct timeval * ATTR_UNUSED(tv)) -{ - base->need_to_exit = 1; - return 0; -} - -void _getdns_event_base_free(struct _getdns_event_base *base) -{ - if(!base) - return; - if(base->items) - free(base->items); - if(base->times) - free(base->times); - if(base->signals) - free(base->signals); - free(base); -} - -void _getdns_event_set(struct _getdns_event *ev, int fd, short bits, - void (*cb)(int, short, void *), void *arg) -{ - ev->node.key = ev; - ev->ev_fd = fd; - ev->ev_events = bits; - ev->ev_callback = cb; - fptr_ok(fptr_whitelist_event(ev->ev_callback)); - ev->ev_arg = arg; - ev->just_checked = 0; - ev->added = 0; -} - -int _getdns_event_base_set(struct _getdns_event_base *base, struct _getdns_event *ev) -{ - ev->ev_base = base; - ev->old_events = 0; - ev->stick_events = 0; - ev->added = 0; - return 0; -} - -int _getdns_event_add(struct _getdns_event *ev, struct timeval *tv) -{ - printf( "event_add %p added=%d fd=%d tv=" ARG_LL "d %s%s%s\n", - ev, ev->added, ev->ev_fd, - (tv?(long long)tv->tv_sec*1000+(long long)tv->tv_usec/1000:-1), - (ev->ev_events&EV_READ)?" EV_READ":"", - (ev->ev_events&EV_WRITE)?" EV_WRITE":"", - (ev->ev_events&EV_TIMEOUT)?" EV_TIMEOUT":""); - - if(ev->added) - _getdns_event_del(ev); - - ev->is_tcp = 0; - ev->is_signal = 0; - ev->just_checked = 0; - - if ((ev->ev_events&(EV_READ | EV_WRITE)) && ev->ev_fd != -1) { - BOOL b = 0; - int t, l; - long events = 0; - //gprintf("\getdns_event_add %d %d\n", ev->ev_fd, events); - - if (ev->ev_base->max == ev->ev_base->cap) - return -1; - ev->idx = ev->ev_base->max++; - ev->ev_base->items[ev->idx] = ev; - - if ((ev->ev_events&EV_READ)) - events |= FD_READ; - if ((ev->ev_events&EV_WRITE)) - { - events |= FD_CONNECT; - events |= FD_WRITE; - } - - //printf("\getdns_event_add %d read = %d write = %d %d\n", ev->ev_fd, ev->ev_events&EV_READ, ev->ev_events&EV_WRITE, events); - - l = sizeof(t); - if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_TYPE, - (void*)&t, &l) != 0) - log_err("getdns: getsockopt(SO_TYPE) failed: %s", - wsa_strerror(WSAGetLastError())); - if(t == SOCK_STREAM) { - /* TCP socket */ - ev->is_tcp = 1; - events |= FD_CLOSE; - if( (ev->ev_events&EV_WRITE) ) - events |= FD_CONNECT; - l = sizeof(b); - if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_ACCEPTCONN, - (void*)&b, &l) != 0) - log_err("getdns: getsockopt(SO_ACCEPTCONN) failed: %s", - wsa_strerror(WSAGetLastError())); - if(b) /* TCP accept socket */ - events |= FD_ACCEPT; - } - ev->hEvent = WSACreateEvent(); - if(ev->hEvent == WSA_INVALID_EVENT) - log_err("getdns: WSACreateEvent failed: %s", - wsa_strerror(WSAGetLastError())); - /* automatically sets fd to nonblocking mode. - * nonblocking cannot be disabled, until wsaES(fd, NULL, 0) */ - printf("\nWSAEventSelect %d events %d hEvent %d\n", ev->ev_fd, (int)events, (int)ev->hEvent); - if (WSAEventSelect(ev->ev_fd, ev->hEvent, events) != 0) { - log_err("getdns: WSAEventSelect in getdns failed: %s", - wsa_strerror(WSAGetLastError())); - } - if(ev->is_tcp && ev->stick_events && - (ev->ev_events & ev->old_events)) { - /* go to processing the sticky event right away */ - printf("\nWSAEventSelect sticky %d events %d hEvent %d\n", ev->ev_fd, (int)events, (int)ev->hEvent); - ev->ev_base->tcp_reinvigorated = 1; - } - } - - if(tv && (ev->ev_events&EV_TIMEOUT)) { - printf("\nWSAEventSelect timeout %d hEvent %d\n", ev->ev_fd, (int)ev->hEvent); - -#ifndef S_SPLINT_S - struct timeval *now = ev->ev_base->time_tv; - ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec; - ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec; - while(ev->ev_timeout.tv_usec > 1000000) { - ev->ev_timeout.tv_usec -= 1000000; - ev->ev_timeout.tv_sec++; - } -#endif - (void)_getdns_rbtree_insert(ev->ev_base->times, &ev->node); - } - ev->added = 1; - return 0; -} - -int _getdns_event_del(struct _getdns_event *ev) -{ - //verbose(VERB_ALGO, "event_del %p added=%d fd=%d tv=" ARG_LL "d %s%s%s", - // ev, ev->added, ev->ev_fd, - // (ev->ev_events&EV_TIMEOUT)?(long long)ev->ev_timeout.tv_sec*1000+ - // (long long)ev->ev_timeout.tv_usec/1000:-1, - // (ev->ev_events&EV_READ)?" EV_READ":"", - // (ev->ev_events&EV_WRITE)?" EV_WRITE":"", - // (ev->ev_events&EV_TIMEOUT)?" EV_TIMEOUT":""); - if(!ev->added) - return 0; - //log_assert(ev->added); - if((ev->ev_events&EV_TIMEOUT)) - (void)_getdns_rbtree_delete(ev->ev_base->times, &ev->node); - if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) { - //log_assert(ev->ev_base->max > 0); - /* remove item and compact the list */ - ev->ev_base->items[ev->idx] = - ev->ev_base->items[ev->ev_base->max-1]; - ev->ev_base->items[ev->ev_base->max-1] = NULL; - ev->ev_base->max--; - if(ev->idx < ev->ev_base->max) - ev->ev_base->items[ev->idx]->idx = ev->idx; - zero_waitfor(ev->ev_base->waitfor, ev->hEvent); - - if(WSAEventSelect(ev->ev_fd, ev->hEvent, 0) != 0) - log_err("getdns: WSAEventSelect(disable) failed: %s", - wsa_strerror(WSAGetLastError())); - if(!WSACloseEvent(ev->hEvent)) - log_err("getdns: WSACloseEvent failed: %s", - wsa_strerror(WSAGetLastError())); - } - ev->just_checked = 0; - ev->added = 0; - return 0; -} - -/** which base gets to handle signals */ -static struct _getdns_event_base* signal_base = NULL; -/** signal handler */ -static RETSIGTYPE sigh(int sig) -{ - if(!signal_base || sig < 0 || sig >= MAX_SIG) - return; -} - -int _getdns_signal_add(struct _getdns_event *ev, struct timeval * ATTR_UNUSED(tv)) -{ - if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG) - return -1; - signal_base = ev->ev_base; - ev->ev_base->signals[ev->ev_fd] = ev; - ev->added = 1; - if(signal(ev->ev_fd, sigh) == SIG_ERR) { - return -1; - } - return 0; -} - -int _getdns_signal_del(struct _getdns_event *ev) -{ - if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG) - return -1; - ev->ev_base->signals[ev->ev_fd] = NULL; - ev->added = 0; - return 0; -} - -void winsock_tcp_wouldblock(struct _getdns_event* ev, int eventbits) -{ - printf("winsock: tcp wouldblock %s\n", - eventbits==EV_READ?"EV_READ":"EV_WRITE"); - ev->old_events &= (~eventbits); - if(ev->old_events == 0) - ev->stick_events = 0; - /* in case this is the last sticky event, we could - * possibly run an empty handler loop to reset the base - * tcp_stickies variable - */ -} - -int winsock_register_wsaevent(struct _getdns_event_base* base, struct _getdns_event* ev, - WSAEVENT wsaevent, void (*cb)(int, short, void*), void* arg) -{ - if(base->max == base->cap) - return 0; - memset(ev, 0, sizeof(*ev)); - ev->ev_fd = -1; - ev->ev_events = EV_READ; - ev->ev_callback = cb; - ev->ev_arg = arg; - ev->is_signal = 1; - ev->hEvent = wsaevent; - ev->added = 1; - ev->ev_base = base; - ev->idx = ev->ev_base->max++; - ev->ev_base->items[ev->idx] = ev; - return 1; -} - -void winsock_unregister_wsaevent(struct _getdns_event* ev) -{ - if(!ev || !ev->added) return; - //log_assert(ev->added && ev->ev_base->max > 0) - /* remove item and compact the list */ - ev->ev_base->items[ev->idx] = ev->ev_base->items[ev->ev_base->max-1]; - ev->ev_base->items[ev->ev_base->max-1] = NULL; - ev->ev_base->max--; - if(ev->idx < ev->ev_base->max) - ev->ev_base->items[ev->idx]->idx = ev->idx; - ev->added = 0; -} - -#else /* USE_WINSOCK */ -/** symbol so this codefile defines symbols. pleasing ranlib on OSX 10.5 */ -int winsock_unused_symbol = 1; -#endif /* USE_WINSOCK */ diff --git a/src/util/winsock_event.h b/src/util/winsock_event.h deleted file mode 100644 index e9bb5982..00000000 --- a/src/util/winsock_event.h +++ /dev/null @@ -1,295 +0,0 @@ -/* - * util/winsock_event.h - getdns event handling for winsock on windows - * extracted from Unbound source code and modified for getdns - * - * Copyright (c) 2015, NLnet Labs/Verisign. All rights reserved. - * - * This software is open source. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 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. - * - * Neither the name of the NLNET LABS or Verisign nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "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 COPYRIGHT - * HOLDER OR CONTRIBUTORS 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. - */ - -/** - * \file - * - * This file contains interface functions with the WinSock2 API on Windows. - * It uses the winsock WSAWaitForMultipleEvents interface on a number of - * sockets. - * Code is originally from the Unbound source for Windows. - * - * Note that windows can only wait for max 64 events at one time. - * - * Also, file descriptors cannot be waited for. - * - * Named pipes are not easily available (and are not usable in select() ). - * For interprocess communication, it is possible to wait for a hEvent to - * be signaled by another thread. - * - * When a socket becomes readable, then it will not be flagged as - * readable again until you have gotten WOULDBLOCK from a recv routine. - * That means the event handler must store the readability (edge notify) - * and process the incoming data until it blocks. - * The function performing recv then has to inform the event handler that - * the socket has blocked, and the event handler can mark it as such. - * Thus, this file transforms the edge notify from windows to a level notify - * that is compatible with UNIX. - * The WSAEventSelect page says that it does do level notify, as long - * as you call a recv/write/accept at least once when it is signalled. - * This last bit is not true, even though documented in server2008 api docs - * from microsoft, it does not happen at all. Instead you have to test for - * WSAEWOULDBLOCK on a tcp stream, and only then retest the socket. - * And before that remember the previous result as still valid. - * - * To stay 'fair', instead of emptying a socket completely, the event handler - * can test the other (marked as blocking) sockets for new events. - * - * Additionally, TCP accept sockets get special event support. - * - * Socket numbers are not starting small, they can be any number (say 33060). - * Therefore, bitmaps are not used, but arrays. - * - * on winsock, you must use recv() and send() for TCP reads and writes, - * not read() and write(), those work only on files. - * - * Also fseek and fseeko do not work if a FILE is not fopen-ed in binary mode. - * - * When under a high load windows gives out lots of errors, from recvfrom - * on udp sockets for example (WSAECONNRESET). Even though the udp socket - * has no connection per se. - */ - -#ifndef UTIL_WINSOCK_EVENT_H -#define UTIL_WINSOCK_EVENT_H - -// Only enabled for Windows -#ifdef USE_WINSOCK - -#ifndef HAVE_EVENT_BASE_FREE -#define HAVE_EVENT_BASE_FREE -#endif - -/* redefine the calls to different names so that there is no name - * collision with other code that uses libevent names. (that uses libunbound)*/ -#define _getdns_event_init winsockevent_init -#define event_get_version winsockevent_get_version -#define event_get_method winsockevent_get_method -#define _getdns_event_base_dispatch winsockevent_base_dispatch -#define event_base_loopexit winsockevent_base_loopexit -#define _getdns_event_base_free winsockevent_base_free -#define _getdns_event_set winsockevent_set -#define _getdns_event_base_set winsockevent_base_set -#define _getdns_event_add winsockevent_add -#define _getdns_event_del winsockevent_del -#define signal_add winsocksignal_add -#define signal_del winsocksignal_del - -/** event timeout */ -#define EV_TIMEOUT 0x01 -/** event fd readable */ -#define EV_READ 0x02 -/** event fd writable */ -#define EV_WRITE 0x04 -/** event signal */ -#define EV_SIGNAL 0x08 -/** event must persist */ -#define EV_PERSIST 0x10 - -/* needs our redblack tree */ -#include "util/rbtree.h" - -/** max number of signals to support */ -#define MAX_SIG 32 - -/** The number of items that the winsock event handler can service. - * Windows cannot handle more anyway */ -#define WSK_MAX_ITEMS 64 - -/** - * event base for winsock event handler - */ -struct _getdns_event_base -{ - /** sorted by timeout (absolute), ptr */ - _getdns_rbtree_t* times; - /** array (first part in use) of handles to work on */ - struct _getdns_event** items; - /** number of items in use in array */ - int max; - /** capacity of array, size of array in items */ - int cap; - /** array of 0 - maxsig of ptr to event for it */ - struct _getdns_event** signals; - /** if we need to exit */ - int need_to_exit; - /** where to store time in seconds */ - time_t* time_secs; - /** where to store time in microseconds */ - struct timeval* time_tv; - /** - * TCP streams have sticky events to them, these are not - * reported by the windows event system anymore, we have to - * keep reporting those events as present until wouldblock() is - * signalled by the handler back to use. - */ - int tcp_stickies; - /** - * should next cycle process reinvigorated stickies, - * these are stickies that have been stored, but due to a new - * event_add a sudden interest in the event has incepted. - */ - int tcp_reinvigorated; - /** The list of events that is currently being processed. */ - WSAEVENT waitfor[WSK_MAX_ITEMS]; - - /* fdset for read write, for fds ready, and added */ - fd_set - /** fds for reading */ - reads, - /** fds for writing */ - writes, - /** fds determined ready for use */ - ready, - /** ready plus newly added events. */ - content; -}; - -/** - * Event structure. Has some of the event elements. - */ -struct _getdns_event { - /** node in timeout rbtree */ - _getdns_rbnode_t node; - /** is event already added */ - int added; - - /** event base it belongs to */ - struct _getdns_event_base *ev_base; - /** fd to poll or -1 for timeouts. signal number for sigs. */ - int ev_fd; - /** what events this event is interested in, see EV_.. above. */ - short ev_events; - /** timeout value */ - struct timeval ev_timeout; - - /** callback to call: fd, eventbits, userarg */ - void (*ev_callback)(int, short, void *); - /** callback user arg */ - void *ev_arg; - - /* ----- nonpublic part, for winsock_event only ----- */ - /** index of this event in the items array (if added) */ - int idx; - /** the event handle to wait for new events to become ready */ - WSAEVENT hEvent; - /** true if this filedes is a TCP socket and needs special attention */ - int is_tcp; - /** remembered EV_ values */ - short old_events; - /** should remembered EV_ values be used for TCP streams. - * Reset after WOULDBLOCK is signaled using the function. */ - int stick_events; - - /** true if this event is a signaling WSAEvent by the user. - * User created and user closed WSAEvent. Only signaled/unsigneled, - * no read/write/distinctions needed. */ - int is_signal; - /** used during callbacks to see which events were just checked */ - int just_checked; -}; - -char* wsa_strerror(DWORD err); -void log_err(const char *format, ...); -/** create event base */ -void *_getdns_event_init(time_t* time_secs, struct timeval* time_tv); -/** get version */ -const char *event_get_version(void); -/** get polling method (select,epoll) */ -const char *event_get_method(void); -/** run select in a loop */ -int _getdns_event_base_dispatch(struct _getdns_event_base *); -/** exit that loop */ -int event_base_loopexit(struct _getdns_event_base *, struct timeval *); -/** free event base. Free events yourself */ -void _getdns_event_base_free(struct _getdns_event_base *); -/** set content of event */ -void _getdns_event_set(struct _getdns_event *, int, short, void (*)(int, short, void *), void *); - -/** add event to a base. You *must* call this for every event. */ -int _getdns_event_base_set(struct _getdns_event_base *, struct _getdns_event *); -/** add event to make it active. You may not change it with event_set anymore */ -int _getdns_event_add(struct _getdns_event *, struct timeval *); -/** remove event. You may change it again */ -int _getdns_event_del(struct _getdns_event *); - -#define evtimer_add(ev, tv) event_add(ev, tv) -#define evtimer_del(ev) event_del(ev) - -/* uses different implementation. Cannot mix fd/timeouts and signals inside - * the same struct event. create several event structs for that. */ -/** install signal handler */ -int signal_add(struct _getdns_event *, struct timeval *); -/** set signal event contents */ -#define signal_set(ev, x, cb, arg) \ - event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg) -/** remove signal handler */ -int signal_del(struct _getdns_event *); - -/** compare events in tree, based on timevalue, ptr for uniqueness */ -int getdns_mini_ev_cmp(const void* a, const void* b); - -/** - * Routine for windows only, where the handling layer can signal that - * a TCP stream encountered WSAEWOULDBLOCK for a stream and thus needs - * retesting the event. - * Pass if EV_READ or EV_WRITE gave wouldblock. - */ -void winsock_tcp_wouldblock(struct _getdns_event* ev, int eventbit); - -/** - * Routine for windows only. where you pass a signal WSAEvent that - * you wait for. When the event is signaled, the callback gets called. - * The callback has to WSAResetEvent to disable the signal. - * @param base: the event base. - * @param ev: the event structure for data storage - * can be passed uninitialised. - * @param wsaevent: the WSAEvent that gets signaled. - * @param cb: callback routine. - * @param arg: user argument to callback routine. - * @return false on error. - */ -int winsock_register_wsaevent(struct _getdns_event_base* base, struct _getdns_event* ev, - WSAEVENT wsaevent, void (*cb)(int, short, void*), void* arg); - -/** - * Unregister a wsaevent. User has to close the WSAEVENT itself. - * @param ev: event data storage. - */ -void winsock_unregister_wsaevent(struct _getdns_event* ev); - -#endif /* USE_WINSOCK */ -#endif /* UTIL_WINSOCK_EVENT_H */