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)
This commit is contained in:
Willem Toorop 2016-01-12 15:52:14 +01:00
parent 39f7e87f1a
commit 4fd8d3dddd
16 changed files with 640 additions and 2247 deletions

View File

@ -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([GETDNS_ON_WINDOWS], [1], [Define this to enable Windows build.])
AC_DEFINE_UNQUOTED([STUB_NATIVE_DNSSEC], [1]) AC_DEFINE_UNQUOTED([STUB_NATIVE_DNSSEC], [1])
LIBS="$LIBS -lgdi32 -liphlpapi" LIBS="$LIBS -lgdi32 -liphlpapi"
my_with_libunbound=0
my_with_libidn=0
else
my_with_libidn=1
fi fi
if test $my_with_libidn = 1 my_with_libidn=1
then AC_ARG_WITH(libidn, AS_HELP_STRING([--with-libidn=pathname],
AC_ARG_WITH(libidn, AS_HELP_STRING([--with-libidn=pathname], [path to libidn (default: search /usr/local ..)]),
[path to libidn (default: search /usr/local ..)]), [], [withval="yes"])
[], [withval="yes"]) if test x_$withval = x_yes; then
if test x_$withval = x_yes; then for dir in /usr/local /opt/local /usr/pkg /usr/sfw; do
for dir in /usr/local /opt/local /usr/pkg /usr/sfw; do if test -f "$dir/include/idna.h"; then
if test -f "$dir/include/idna.h"; then CFLAGS="$CFLAGS -I$dir/include"
CFLAGS="$CFLAGS -I$dir/include" LDFLAGS="$LDFLAGS -L$dir/lib"
LDFLAGS="$LDFLAGS -L$dir/lib" AC_MSG_NOTICE([Found libidn in $dir])
AC_MSG_NOTICE([Found libidn in $dir]) break
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 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 else
if test x_$withval != x_no; then my_with_libidn=0
CFLAGS="$CFLAGS -I$withval/include"
LDFLAGS="$LDFLAGS -L$withval/lib"
else
my_with_libidn=0
fi
fi fi
fi fi
@ -1161,6 +1155,14 @@ const char *inet_ntop(int af, const void *src, char *dst, size_t size);
#include <openssl/ssl.h> #include <openssl/ssl.h>
#endif #endif
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#ifndef PRIu64
#define PRIu64 "llu"
#endif
#ifdef HAVE_ATTR_FORMAT #ifdef HAVE_ATTR_FORMAT
# define ATTR_FORMAT(archetype, string_index, first_to_check) \ # define ATTR_FORMAT(archetype, string_index, first_to_check) \
__attribute__ ((format (archetype, string_index, first_to_check))) __attribute__ ((format (archetype, string_index, first_to_check)))

View File

@ -149,16 +149,24 @@ depend:
# Dependencies for the examples # Dependencies for the examples
example-all-functions.lo example-all-functions.o: $(srcdir)/example-all-functions.c $(srcdir)/getdns_libevent.h \ example-all-functions.lo example-all-functions.o: $(srcdir)/example-all-functions.c $(srcdir)/getdns_libevent.h \
../../src/config.h ../../src/getdns/getdns.h \ ../../src/config.h \
$(srcdir)/../../src/getdns/getdns_ext_libevent.h ../../src/getdns/getdns_extra.h ../../src/getdns/getdns.h \
example-reverse.lo example-reverse.o: $(srcdir)/example-reverse.c $(srcdir)/getdns_libevent.h ../../src/config.h \ $(srcdir)/../../src/getdns/getdns_ext_libevent.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 ../../src/getdns/getdns_extra.h
example-simple-answers.lo example-simple-answers.o: $(srcdir)/example-simple-answers.c $(srcdir)/getdns_libevent.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 \ ../../src/config.h \
$(srcdir)/../../src/getdns/getdns_ext_libevent.h ../../src/getdns/getdns_extra.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 \ example-synchronous.lo example-synchronous.o: $(srcdir)/example-synchronous.c $(srcdir)/getdns_core_only.h \
../../src/getdns/getdns.h ../../src/getdns/getdns.h
example-tree.lo example-tree.o: $(srcdir)/example-tree.c $(srcdir)/getdns_libevent.h ../../src/config.h \ example-tree.lo example-tree.o: $(srcdir)/example-tree.c $(srcdir)/getdns_libevent.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 ../../src/getdns/getdns_extra.h

View File

@ -74,9 +74,9 @@ LIBOBJDIR=
LIBOBJS=@LIBOBJS@ LIBOBJS=@LIBOBJS@
COMPAT_OBJ=$(LIBOBJS:.o=.lo) 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 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 $(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) 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 libmini_event.lo $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) $(LDFLAGS) -rpath $(libdir) -version-info $(libversion) -no-undefined -export-symbols $(srcdir)/libgetdns.symbols $(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 test: all
@ -225,114 +225,136 @@ depend:
FORCE: FORCE:
# Dependencies for gldns, utils, the extensions and compat functions # 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 \ const-info.lo const-info.o: $(srcdir)/const-info.c getdns/getdns.h \
getdns/getdns.h $(srcdir)/const-info.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 \ context.lo context.o: $(srcdir)/context.c config.h $(srcdir)/debug.h \
$(srcdir)/gldns/wire2str.h $(srcdir)/context.h getdns/getdns.h getdns/getdns_extra.h \ $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h $(srcdir)/context.h \
getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/extension/libmini_event.h \ getdns/getdns.h \
config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h \ getdns/getdns_extra.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)/util/rbtree.h $(srcdir)/extension/default_eventloop.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h \
$(srcdir)/dnssec.h $(srcdir)/stub.h $(srcdir)/list.h $(srcdir)/dict.h $(srcdir)/pubkey-pinning.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 \
convert.lo convert.o: $(srcdir)/convert.c config.h getdns/getdns.h getdns/getdns_extra.h \ $(srcdir)/pubkey-pinning.h
getdns/getdns.h $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \ convert.lo convert.o: $(srcdir)/convert.c config.h \
$(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \ getdns/getdns.h \
$(srcdir)/types-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ getdns/getdns_extra.h $(srcdir)/util-internal.h \
$(srcdir)/gldns/wire2str.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/convert.h $(srcdir)/context.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/extension/default_eventloop.h \
dict.lo dict.o: $(srcdir)/dict.c config.h $(srcdir)/types-internal.h getdns/getdns.h \ $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/wire2str.h \
getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h $(srcdir)/util-internal.h \ $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/convert.h
$(srcdir)/context.h $(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h \ dict.lo dict.o: $(srcdir)/dict.c config.h $(srcdir)/types-internal.h \
$(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ getdns/getdns.h \
$(srcdir)/gldns/pkthdr.h $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/const-info.h $(srcdir)/gldns/wire2str.h getdns/getdns_extra.h $(srcdir)/util/rbtree.h \
dnssec.lo dnssec.o: $(srcdir)/dnssec.c config.h $(srcdir)/debug.h getdns/getdns.h $(srcdir)/context.h \ $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h $(srcdir)/rr-iter.h \
getdns/getdns_extra.h getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \ $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/const-info.h \
$(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \ $(srcdir)/gldns/wire2str.h
$(srcdir)/types-internal.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ dnssec.lo dnssec.o: $(srcdir)/dnssec.c config.h $(srcdir)/debug.h \
$(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h \ getdns/getdns.h $(srcdir)/context.h \
$(srcdir)/gldns/keyraw.h $(srcdir)/gldns/parseutil.h $(srcdir)/general.h $(srcdir)/dict.h $(srcdir)/list.h \ getdns/getdns_extra.h $(srcdir)/types-internal.h \
$(srcdir)/util/val_secalgo.h $(srcdir)/util/rbtree.h $(srcdir)/extension/default_eventloop.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h \
general.lo general.o: $(srcdir)/general.c config.h $(srcdir)/gldns/wire2str.h $(srcdir)/context.h getdns/getdns.h \ $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/gldns/str2wire.h \
getdns/getdns_extra.h getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \ $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/keyraw.h $(srcdir)/gldns/parseutil.h \
$(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \ $(srcdir)/general.h $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/util/val_secalgo.h
$(srcdir)/types-internal.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ general.lo general.o: $(srcdir)/general.c config.h $(srcdir)/general.h \
$(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/stub.h $(srcdir)/general.h getdns/getdns.h $(srcdir)/types-internal.h \
list.lo list.o: $(srcdir)/list.c $(srcdir)/types-internal.h getdns/getdns.h getdns/getdns_extra.h \ getdns/getdns_extra.h $(srcdir)/util/rbtree.h \
getdns/getdns.h $(srcdir)/util/rbtree.h $(srcdir)/util-internal.h config.h $(srcdir)/context.h \ $(srcdir)/gldns/wire2str.h $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h $(srcdir)/util-internal.h \
$(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \ $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/stub.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)/dict.h list.lo list.o: $(srcdir)/list.c $(srcdir)/types-internal.h \
pubkey-pinning.lo pubkey-pinning.o: $(srcdir)/pubkey-pinning.c config.h $(srcdir)/debug.h getdns/getdns.h \ getdns/getdns.h \
$(srcdir)/context.h getdns/getdns.h getdns/getdns_extra.h $(srcdir)/types-internal.h \ getdns/getdns_extra.h $(srcdir)/util/rbtree.h \
$(srcdir)/util/rbtree.h $(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h \ $(srcdir)/util-internal.h config.h $(srcdir)/context.h \
$(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/extension/default_eventloop.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \
request-internal.lo request-internal.o: $(srcdir)/request-internal.c config.h $(srcdir)/types-internal.h \ $(srcdir)/gldns/pkthdr.h $(srcdir)/list.h $(srcdir)/dict.h
getdns/getdns.h getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h \ pubkey-pinning.lo pubkey-pinning.o: $(srcdir)/pubkey-pinning.c config.h \
$(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/extension/libmini_event.h config.h \ $(srcdir)/debug.h getdns/getdns.h $(srcdir)/context.h \
$(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ getdns/getdns_extra.h $(srcdir)/types-internal.h \
$(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/str2wire.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 $(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 \ rr-dict.lo rr-dict.o: $(srcdir)/rr-dict.c $(srcdir)/rr-dict.h config.h \
$(srcdir)/util-internal.h $(srcdir)/context.h getdns/getdns_extra.h getdns/getdns.h \ getdns/getdns.h $(srcdir)/gldns/gbuffer.h \
$(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/extension/libmini_event.h config.h \ $(srcdir)/util-internal.h $(srcdir)/context.h \
$(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/rr-iter.h \ getdns/getdns_extra.h $(srcdir)/types-internal.h \
$(srcdir)/gldns/pkthdr.h $(srcdir)/dict.h $(srcdir)/util/rbtree.h $(srcdir)/extension/default_eventloop.h $(srcdir)/rr-iter.h $(srcdir)/gldns/pkthdr.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)/dict.h
$(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/rrdef.h rr-iter.lo rr-iter.o: $(srcdir)/rr-iter.c $(srcdir)/rr-iter.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.h $(srcdir)/rr-dict.h \
getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h $(srcdir)/gldns/gbuffer.h \ config.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \
$(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.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 \ stub.lo stub.o: $(srcdir)/stub.c config.h $(srcdir)/debug.h $(srcdir)/stub.h \
config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h \ getdns/getdns.h $(srcdir)/types-internal.h \
$(srcdir)/util-internal.h $(srcdir)/general.h $(srcdir)/pubkey-pinning.h getdns/getdns_extra.h $(srcdir)/util/rbtree.h \
sync.lo sync.o: $(srcdir)/sync.c getdns/getdns.h config.h $(srcdir)/context.h getdns/getdns_extra.h \ $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/str2wire.h \
getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/extension/libmini_event.h \ $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/context.h \
config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/general.h \ $(srcdir)/extension/default_eventloop.h $(srcdir)/util-internal.h $(srcdir)/general.h $(srcdir)/pubkey-pinning.h
$(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ sync.lo sync.o: $(srcdir)/sync.c getdns/getdns.h \
$(srcdir)/dnssec.h $(srcdir)/stub.h $(srcdir)/gldns/wire2str.h config.h $(srcdir)/context.h \
util-internal.lo util-internal.o: $(srcdir)/util-internal.c config.h getdns/getdns.h $(srcdir)/dict.h \ getdns/getdns_extra.h $(srcdir)/types-internal.h \
$(srcdir)/util/rbtree.h $(srcdir)/types-internal.h getdns/getdns_extra.h getdns/getdns.h \ $(srcdir)/util/rbtree.h $(srcdir)/extension/default_eventloop.h $(srcdir)/general.h $(srcdir)/util-internal.h \
$(srcdir)/list.h $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/extension/libmini_event.h config.h \ $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/stub.h \
$(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ $(srcdir)/gldns/wire2str.h
$(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h util-internal.lo util-internal.o: $(srcdir)/util-internal.c config.h \
version.lo version.o: version.c getdns/getdns.h $(srcdir)/dict.h $(srcdir)/util/rbtree.h \
gbuffer.lo gbuffer.o: $(srcdir)/gldns/gbuffer.c config.h $(srcdir)/gldns/gbuffer.h $(srcdir)/types-internal.h getdns/getdns_extra.h \
keyraw.lo keyraw.o: $(srcdir)/gldns/keyraw.c config.h $(srcdir)/gldns/keyraw.h $(srcdir)/gldns/rrdef.h $(srcdir)/list.h $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h $(srcdir)/rr-iter.h \
parse.lo parse.o: $(srcdir)/gldns/parse.c config.h $(srcdir)/gldns/parse.h $(srcdir)/gldns/parseutil.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 $(srcdir)/gldns/gbuffer.h
parseutil.lo parseutil.o: $(srcdir)/gldns/parseutil.c config.h $(srcdir)/gldns/parseutil.h keyraw.lo keyraw.o: $(srcdir)/gldns/keyraw.c config.h \
rrdef.lo rrdef.o: $(srcdir)/gldns/rrdef.c config.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/parseutil.h $(srcdir)/gldns/keyraw.h $(srcdir)/gldns/rrdef.h
str2wire.lo str2wire.o: $(srcdir)/gldns/str2wire.c config.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h \ parse.lo parse.o: $(srcdir)/gldns/parse.c config.h \
$(srcdir)/gldns/wire2str.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/parse.h $(srcdir)/gldns/parseutil.h $(srcdir)/gldns/parse.h $(srcdir)/gldns/parseutil.h $(srcdir)/gldns/gbuffer.h
wire2str.lo wire2str.o: $(srcdir)/gldns/wire2str.c config.h $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/str2wire.h \ parseutil.lo parseutil.o: $(srcdir)/gldns/parseutil.c config.h \
$(srcdir)/gldns/rrdef.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/parseutil.h $(srcdir)/gldns/gbuffer.h \ $(srcdir)/gldns/parseutil.h
$(srcdir)/gldns/keyraw.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 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.lo arc4random.o: $(srcdir)/compat/arc4random.c config.h \
arc4random_uniform.lo arc4random_uniform.o: $(srcdir)/compat/arc4random_uniform.c config.h $(srcdir)/compat/chacha_private.h
explicit_bzero.lo explicit_bzero.o: $(srcdir)/compat/explicit_bzero.c config.h arc4random_uniform.lo arc4random_uniform.o: $(srcdir)/compat/arc4random_uniform.c \
getentropy_linux.lo getentropy_linux.o: $(srcdir)/compat/getentropy_linux.c config.h config.h
getentropy_osx.lo getentropy_osx.o: $(srcdir)/compat/getentropy_osx.c config.h explicit_bzero.lo explicit_bzero.o: $(srcdir)/compat/explicit_bzero.c \
getentropy_solaris.lo getentropy_solaris.o: $(srcdir)/compat/getentropy_solaris.c config.h 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 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_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 inet_pton.lo inet_pton.o: $(srcdir)/compat/inet_pton.c config.h
sha512.lo sha512.o: $(srcdir)/compat/sha512.c config.h sha512.lo sha512.o: $(srcdir)/compat/sha512.c config.h
strlcpy.lo strlcpy.o: $(srcdir)/compat/strlcpy.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 \ rbtree.lo rbtree.o: $(srcdir)/util/rbtree.c config.h $(srcdir)/util/log.h \
$(srcdir)/util/fptr_wlist.h $(srcdir)/debug.h $(srcdir)/util/fptr_wlist.h $(srcdir)/util/rbtree.h
rbtree.lo rbtree.o: $(srcdir)/util/rbtree.c config.h $(srcdir)/util/log.h $(srcdir)/debug.h config.h \ val_secalgo.lo val_secalgo.o: $(srcdir)/util/val_secalgo.c config.h \
$(srcdir)/util/fptr_wlist.h $(srcdir)/util/rbtree.h $(srcdir)/util/val_secalgo.h $(srcdir)/util/log.h $(srcdir)/debug.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/keyraw.h \
val_secalgo.lo val_secalgo.o: $(srcdir)/util/val_secalgo.c config.h $(srcdir)/util/val_secalgo.h $(srcdir)/util/log.h \ $(srcdir)/gldns/gbuffer.h
$(srcdir)/debug.h config.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/keyraw.h $(srcdir)/gldns/gbuffer.h default_eventloop.lo default_eventloop.o: $(srcdir)/extension/default_eventloop.c \
winsock_event.lo winsock_event.o: $(srcdir)/util/winsock_event.c config.h $(srcdir)/extension/default_eventloop.h config.h \
libev.lo libev.o: $(srcdir)/extension/libev.c config.h $(srcdir)/types-internal.h getdns/getdns.h \ getdns/getdns.h \
getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h \ getdns/getdns_extra.h $(srcdir)/debug.h
$(srcdir)/getdns/getdns_ext_libev.h getdns/getdns_extra.h libev.lo libev.o: $(srcdir)/extension/libev.c config.h \
libevent.lo libevent.o: $(srcdir)/extension/libevent.c config.h $(srcdir)/types-internal.h \ $(srcdir)/types-internal.h getdns/getdns.h \
getdns/getdns.h getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h \ getdns/getdns_extra.h $(srcdir)/util/rbtree.h \
$(srcdir)/getdns/getdns_ext_libevent.h getdns/getdns_extra.h $(srcdir)/getdns/getdns_ext_libev.h
libmini_event.lo libmini_event.o: $(srcdir)/extension/libmini_event.c config.h $(srcdir)/debug.h config.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)/types-internal.h getdns/getdns.h \
$(srcdir)/util/rbtree.h $(srcdir)/extension/libmini_event.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h getdns/getdns_extra.h $(srcdir)/util/rbtree.h \
libuv.lo libuv.o: $(srcdir)/extension/libuv.c config.h $(srcdir)/debug.h config.h $(srcdir)/types-internal.h \ $(srcdir)/getdns/getdns_ext_libevent.h
getdns/getdns.h getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h \ libuv.lo libuv.o: $(srcdir)/extension/libuv.c config.h $(srcdir)/debug.h \
$(srcdir)/getdns/getdns_ext_libuv.h getdns/getdns_extra.h $(srcdir)/types-internal.h getdns/getdns.h \
getdns/getdns_extra.h $(srcdir)/util/rbtree.h \
$(srcdir)/getdns/getdns_ext_libuv.h

View File

@ -966,6 +966,9 @@ getdns_context_create_with_extended_memory_functions(
struct getdns_context *result = NULL; struct getdns_context *result = NULL;
mf_union mf; mf_union mf;
gldns_buffer gbuf; gldns_buffer gbuf;
#ifdef USE_WINSOCK
WORD wVersionRequested;
#endif
if (!context || !malloc || !realloc || !free) if (!context || !malloc || !realloc || !free)
return GETDNS_RETURN_INVALID_PARAMETER; return GETDNS_RETURN_INVALID_PARAMETER;
@ -979,6 +982,14 @@ getdns_context_create_with_extended_memory_functions(
if (!result) if (!result)
return GETDNS_RETURN_MEMORY_ERROR; 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->processing = 0;
result->destroying = 0; result->destroying = 0;
result->my_mf.mf_arg = userarg; 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_query_padding_blocksize = 1; /* default is to not try to pad */
result-> tls_ctx = NULL; result-> tls_ctx = NULL;
result->extension = &result->mini_event.loop; result->extension = &result->default_eventloop.loop;
if ((r = _getdns_mini_event_init(result, &result->mini_event))) _getdns_default_eventloop_init(&result->default_eventloop);
goto error;
result->fchg_resolvconf = NULL; result->fchg_resolvconf = NULL;
result->fchg_hosts = NULL; result->fchg_hosts = NULL;
@ -1198,6 +1208,9 @@ getdns_context_destroy(struct getdns_context *context)
_getdns_traverse_postorder(&context->local_hosts, _getdns_traverse_postorder(&context->local_hosts,
destroy_local_host, context); destroy_local_host, context);
#ifdef USE_WINSOCK
WSACleanup();
#endif
GETDNS_FREE(context->my_mf, context); GETDNS_FREE(context->my_mf, context);
} /* getdns_context_destroy */ } /* 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 /* 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 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* 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) if (context->outbound_requests.count)
context->extension->vmt->run_once(context->extension, 0); 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; return context->outbound_requests.count;
} }
/* process async reqs */ /* process async reqs */
getdns_return_t 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); context->extension->vmt->run_once(context->extension, 0);
return GETDNS_RETURN_GOOD; return GETDNS_RETURN_GOOD;
} }
void void
getdns_context_run(getdns_context *context) getdns_context_run(getdns_context *context)
{ {
if (context->extension == &context->mini_event.loop) { context->extension->vmt->run(context->extension);
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);
} }
typedef struct timeout_accumulator { typedef struct timeout_accumulator {
@ -2891,8 +2885,9 @@ getdns_context_detach_eventloop(struct getdns_context* context)
/* cancel all outstanding requests */ /* cancel all outstanding requests */
cancel_outstanding_requests(context, 1); cancel_outstanding_requests(context, 1);
context->extension->vmt->cleanup(context->extension); context->extension->vmt->cleanup(context->extension);
context->extension = &context->mini_event.loop; context->extension = &context->default_eventloop.loop;
return _getdns_mini_event_init(context, &context->mini_event); _getdns_default_eventloop_init(&context->default_eventloop);
return GETDNS_RETURN_GOOD;
} }
getdns_return_t getdns_return_t

View File

@ -41,7 +41,7 @@
#include "getdns/getdns_extra.h" #include "getdns/getdns_extra.h"
#include "config.h" #include "config.h"
#include "types-internal.h" #include "types-internal.h"
#include "extension/libmini_event.h" #include "extension/default_eventloop.h"
#include "util/rbtree.h" #include "util/rbtree.h"
struct getdns_dns_req; struct getdns_dns_req;
@ -245,7 +245,7 @@ struct getdns_context {
#endif #endif
/* The default extension */ /* The default extension */
_getdns_mini_event mini_event; _getdns_default_eventloop default_eventloop;
/* /*
* state data used to detect changes to the system config files * state data used to detect changes to the system config files
@ -255,6 +255,10 @@ struct getdns_context {
uint8_t trust_anchors_spc[1024]; 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 */ }; /* getdns_context */
/** internal functions **/ /** internal functions **/

View File

@ -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;
}

View File

@ -1,11 +1,10 @@
/** /*
* * \file default_eventloop.h
* \file libmini_event.h
* @brief Build in default eventloop extension that uses select. * @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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * 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 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef DEFAULT_EVENTLOOP_H_
#ifndef _GETDNS_LIBMINI_EVENT_H_ #define DEFAULT_EVENTLOOP_H_
#define _GETDNS_LIBMINI_EVENT_H_
#include "config.h" #include "config.h"
#ifndef USE_WINSOCK #include "getdns/getdns.h"
#include "util/mini_event.h" #include "getdns/getdns_extra.h"
#else
#include "util/winsock_event.h"
#endif
#include "types-internal.h"
typedef struct _getdns_mini_event { /* No more than select's capability queries can be outstanding,
getdns_eventloop loop; * The number of outstanding timeouts should be less or equal then
time_t time_secs; * the number of outstanding queries, so MAX_TIMEOUTS equal to
struct timeval time_tv; * FD_SETSIZE should be safe.
struct _getdns_event_base *base; */
size_t n_events; #define MAX_TIMEOUTS FD_SETSIZE
struct mem_funcs mf;
} _getdns_mini_event;
getdns_return_t /* Eventloop based on select */
_getdns_mini_event_init(getdns_context *context, _getdns_mini_event *mini_event); 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 void
_getdns_mini_event_destroy(_getdns_mini_event *mini_event); _getdns_default_eventloop_init(_getdns_default_eventloop *loop);
#endif
#endif /* _GETDNS_LIBMINI_EVENT_H_ */

View File

@ -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 <inttypes.h>
#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);
}

View File

@ -50,12 +50,20 @@
#include "pubkey-pinning.h" #include "pubkey-pinning.h"
#ifdef USE_WINSOCK #ifdef USE_WINSOCK
#define EINPROGRESS 112
#define EWOULDBLOCK 140
typedef u_short sa_family_t; 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 #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_OUT_OF_OPTIONS -5 /* upstream options exceeded MAXIMUM_UPSTREAM_OPTION_SPACE */
#define STUB_TLS_SETUP_ERROR -4 #define STUB_TLS_SETUP_ERROR -4
#define STUB_TCP_AGAIN -3 #define STUB_TCP_AGAIN -3
@ -402,10 +410,21 @@ tcp_connected(getdns_upstream *upstream) {
int error = 0; int error = 0;
socklen_t len = (socklen_t)sizeof(error); socklen_t len = (socklen_t)sizeof(error);
getsockopt(upstream->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &len); getsockopt(upstream->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &len);
if (error == EINPROGRESS || error == EWOULDBLOCK) #ifdef USE_WINSOCK
return STUB_TCP_AGAIN; /* try again */ if (error == WSAEINPROGRESS)
return STUB_TCP_WOULDBLOCK;
else if (error == WSAEWOULDBLOCK)
return STUB_TCP_WOULDBLOCK;
else if (error != 0) else if (error != 0)
return STUB_TCP_ERROR; 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; return 0;
} }
@ -625,7 +644,7 @@ stub_tls_timeout_cb(void *userarg)
/****************************/ /****************************/
static int 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; ssize_t read;
uint8_t *buf; 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); read = recv(fd, (void *)tcp->read_pos, tcp->to_read, 0);
if (read == -1) { if (read == -1) {
#ifdef USE_WINSOCK if (_getdns_EWOULDBLOCK)
printf("read (in tcp ) %s\n", return STUB_TCP_WOULDBLOCK;
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;
else else
return STUB_TCP_ERROR; return STUB_TCP_ERROR;
#endif
} else if (read == 0) { } else if (read == 0) {
/* Remote end closed the socket */ /* Remote end closed the socket */
/* TODO: Try to reconnect */ /* TODO: Try to reconnect */
return STUB_TCP_ERROR; return STUB_TCP_ERROR;
} else if (read> tcp->to_read) {
return STUB_TCP_ERROR;
} }
tcp->to_read -= read; tcp->to_read -= read;
tcp->read_pos += read; tcp->read_pos += read;
if ((int)tcp->to_read > 0) if (tcp->to_read > 0)
return STUB_TCP_AGAIN; return STUB_TCP_AGAIN;
read = tcp->read_pos - tcp->read_buf; 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) { if (! tcp->write_buf) {
/* No, this is an initial write. Try to send /* No, this is an initial write. Try to send
*/ */
do { do {
query_id = arc4random(); query_id = arc4random();
query_id_intptr = (intptr_t)query_id; query_id_intptr = (intptr_t)query_id;
netreq->node.key = (void *)query_id_intptr; 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. /* We have an initialized packet buffer.
* Lets see how much of it we can write * 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 */ /* 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, written = sendto(fd, netreq->query - 2, pkt_len + 2,
MSG_FASTOPEN, (struct sockaddr *)&(netreq->upstream->addr), MSG_FASTOPEN, (struct sockaddr *)&(netreq->upstream->addr),
netreq->upstream->addr_len); 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. */ just fall back to a 'normal' write. */
if (written == -1 && errno == EISCONN) if (written == -1 && errno == EISCONN)
written = write(fd, netreq->query - 2, pkt_len + 2); 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 #else
#ifdef USE_WINSOCK
written = sendto(fd, (const char *)(netreq->query - 2), written = sendto(fd, (const char *)(netreq->query - 2),
pkt_len + 2, 0, pkt_len + 2, 0,
(struct sockaddr *)&(netreq->upstream->addr), (struct sockaddr *)&(netreq->upstream->addr),
netreq->upstream->addr_len); netreq->upstream->addr_len);
#else
written = write(fd, netreq->query - 2, pkt_len + 2);
#endif #endif
if ((written == -1 && (errno == EAGAIN || if ((written == -1 && (_getdns_EWOULDBLOCK ||
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. */
_getdns_EINPROGRESS)) ||
written < pkt_len + 2) { written < pkt_len + 2) {
#endif
/* We couldn't write the whole packet. /* We couldn't write the whole packet.
* We have to return with STUB_TCP_AGAIN. * We have to return with STUB_TCP_AGAIN.
* Setup tcp to track the state. * 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->write_buf_len = pkt_len + 2;
tcp->written = written >= 0 ? written : 0; tcp->written = written >= 0 ? written : 0;
return STUB_TCP_AGAIN; return STUB_TCP_WOULDBLOCK;
} else if (written == -1) } else if (written == -1)
return STUB_TCP_ERROR; 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, written = write(fd, tcp->write_buf + tcp->written,
tcp->write_buf_len - tcp->written); tcp->write_buf_len - tcp->written);
if (written == -1) { if (written == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) if (_getdns_EWOULDBLOCK)
return STUB_TCP_AGAIN; return STUB_TCP_WOULDBLOCK;
else else
return STUB_TCP_ERROR; return STUB_TCP_ERROR;
} }
@ -1304,7 +1301,7 @@ stub_udp_read_cb(void *userarg)
* i.e. overflow * i.e. overflow
*/ */
0, NULL, NULL); 0, NULL, NULL);
if (read == -1 && (errno = EAGAIN || errno == EWOULDBLOCK)) if (read == -1 && _getdns_EWOULDBLOCK)
return; return;
if (read < GLDNS_HEADER_SIZE) if (read < GLDNS_HEADER_SIZE)
@ -1405,13 +1402,16 @@ upstream_read_cb(void *userarg)
if (tls_should_read(upstream)) if (tls_should_read(upstream))
q = stub_tls_read(upstream, &upstream->tcp, q = stub_tls_read(upstream, &upstream->tcp,
&upstream->upstreams->mf); &upstream->upstreams->mf);
else else
q = stub_tcp_read(upstream->fd, &upstream->tcp, q = stub_tcp_read(upstream->fd, &upstream->tcp,
&upstream->upstreams->mf, &upstream->event); &upstream->upstreams->mf);
switch (q) { switch (q) {
case STUB_TCP_AGAIN: case STUB_TCP_AGAIN:
/* WSA TODO: if callback is still upstream_read_cb, do it again
*/
case STUB_TCP_WOULDBLOCK:
return; return;
case STUB_TCP_ERROR: case STUB_TCP_ERROR:
@ -1463,6 +1463,10 @@ upstream_read_cb(void *userarg)
upstream_reschedule_netreq_events(upstream, netreq); upstream_reschedule_netreq_events(upstream, netreq);
_getdns_check_dns_req_complete(netreq->owner); _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) { switch (q) {
case STUB_TCP_AGAIN: case STUB_TCP_AGAIN:
/* WSA TODO: if callback is still upstream_write_cb, do it again
*/
case STUB_TCP_WOULDBLOCK:
return; return;
case STUB_TCP_ERROR: case STUB_TCP_ERROR:
@ -1553,6 +1561,8 @@ upstream_write_cb(void *userarg)
netreq_upstream_write_cb : NULL), netreq_upstream_write_cb : NULL),
stub_timeout_cb)); stub_timeout_cb));
} }
/* WSA TODO: if callback is still upstream_write_cb, do it again
*/
return; return;
} }
} }

View File

@ -46,7 +46,7 @@
#include "gldns/wire2str.h" #include "gldns/wire2str.h"
typedef struct getdns_sync_loop { typedef struct getdns_sync_loop {
_getdns_mini_event loop; _getdns_default_eventloop loop;
#ifdef HAVE_LIBUNBOUND #ifdef HAVE_LIBUNBOUND
getdns_eventloop_event ub_event; getdns_eventloop_event ub_event;
#endif #endif
@ -61,14 +61,12 @@ getdns_sync_loop_init(getdns_context *context, getdns_sync_loop *loop)
#ifdef HAVE_LIBUNBOUND #ifdef HAVE_LIBUNBOUND
getdns_eventloop *ext = &loop->loop.loop; getdns_eventloop *ext = &loop->loop.loop;
#endif #endif
getdns_return_t r;
loop->response = NULL; loop->response = NULL;
loop->to_run = 1; loop->to_run = 1;
loop->context = context; loop->context = context;
if ((r = _getdns_mini_event_init(context, &loop->loop))) _getdns_default_eventloop_init(&loop->loop);
return r;
#ifdef HAVE_LIBUNBOUND #ifdef HAVE_LIBUNBOUND
loop->ub_event.userarg = loop->context; loop->ub_event.userarg = loop->context;

View File

@ -232,21 +232,24 @@ depend:
.PHONY: clean test .PHONY: clean test
# Dependencies for the unit tests # Dependencies for the unit tests
check_getdns.lo check_getdns.o: $(srcdir)/check_getdns.c ../getdns/getdns.h $(srcdir)/check_getdns_common.h \ check_getdns.lo check_getdns.o: $(srcdir)/check_getdns.c \
../getdns/getdns_extra.h $(srcdir)/check_getdns_general.h \ ../getdns/getdns.h \
$(srcdir)/check_getdns_general_sync.h $(srcdir)/check_getdns_address.h \ $(srcdir)/check_getdns_common.h \
$(srcdir)/check_getdns_address_sync.h $(srcdir)/check_getdns_hostname.h \ ../getdns/getdns_extra.h \
$(srcdir)/check_getdns_hostname_sync.h $(srcdir)/check_getdns_context_create.h \ $(srcdir)/check_getdns_general.h $(srcdir)/check_getdns_general_sync.h \
$(srcdir)/check_getdns_context_destroy.h $(srcdir)/check_getdns_cancel_callback.h \ $(srcdir)/check_getdns_address.h $(srcdir)/check_getdns_address_sync.h \
$(srcdir)/check_getdns_list_get_length.h $(srcdir)/check_getdns_list_get_data_type.h \ $(srcdir)/check_getdns_hostname.h $(srcdir)/check_getdns_hostname_sync.h \
$(srcdir)/check_getdns_list_get_dict.h $(srcdir)/check_getdns_list_get_list.h \ $(srcdir)/check_getdns_context_create.h $(srcdir)/check_getdns_context_destroy.h \
$(srcdir)/check_getdns_list_get_int.h $(srcdir)/check_getdns_list_get_bindata.h \ $(srcdir)/check_getdns_cancel_callback.h $(srcdir)/check_getdns_list_get_length.h \
$(srcdir)/check_getdns_dict_get_names.h $(srcdir)/check_getdns_dict_get_data_type.h \ $(srcdir)/check_getdns_list_get_data_type.h $(srcdir)/check_getdns_list_get_dict.h \
$(srcdir)/check_getdns_dict_get_dict.h $(srcdir)/check_getdns_dict_get_list.h \ $(srcdir)/check_getdns_list_get_list.h $(srcdir)/check_getdns_list_get_int.h \
$(srcdir)/check_getdns_dict_get_bindata.h $(srcdir)/check_getdns_dict_get_int.h \ $(srcdir)/check_getdns_list_get_bindata.h $(srcdir)/check_getdns_dict_get_names.h \
$(srcdir)/check_getdns_dict_destroy.h $(srcdir)/check_getdns_dict_set_dict.h \ $(srcdir)/check_getdns_dict_get_data_type.h $(srcdir)/check_getdns_dict_get_dict.h \
$(srcdir)/check_getdns_dict_set_list.h $(srcdir)/check_getdns_dict_set_bindata.h \ $(srcdir)/check_getdns_dict_get_list.h $(srcdir)/check_getdns_dict_get_bindata.h \
$(srcdir)/check_getdns_dict_set_int.h $(srcdir)/check_getdns_convert_ulabel_to_alabel.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_convert_alabel_to_ulabel.h $(srcdir)/check_getdns_pretty_print_dict.h \
$(srcdir)/check_getdns_display_ip_address.h \ $(srcdir)/check_getdns_display_ip_address.h \
$(srcdir)/check_getdns_context_set_context_update_callback.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_context_set_upstream_recursive_servers.h \
$(srcdir)/check_getdns_service.h $(srcdir)/check_getdns_service_sync.h \ $(srcdir)/check_getdns_service.h $(srcdir)/check_getdns_service_sync.h \
$(srcdir)/check_getdns_transport.h $(srcdir)/check_getdns_transport.h
check_getdns_common.lo check_getdns_common.o: $(srcdir)/check_getdns_common.c ../getdns/getdns.h \ check_getdns_common.lo check_getdns_common.o: $(srcdir)/check_getdns_common.c \
../config.h $(srcdir)/check_getdns_common.h ../getdns/getdns_extra.h \ ../getdns/getdns.h \
../config.h $(srcdir)/check_getdns_common.h \
../getdns/getdns_extra.h \
$(srcdir)/check_getdns_eventloop.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 \ 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 \ $(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 \ 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 \ ../config.h \
../getdns/getdns_extra.h $(srcdir)/check_getdns_common.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 \ 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 \ ../config.h \
../getdns/getdns_extra.h $(srcdir)/check_getdns_libevent.h $(srcdir)/check_getdns_common.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 \ 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 \ ../config.h \
../getdns/getdns_extra.h $(srcdir)/check_getdns_common.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 \ 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 ../getdns/getdns_extra.h
check_getdns_transport.lo check_getdns_transport.o: $(srcdir)/check_getdns_transport.c \ 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/getdns_extra.h
getdns_query.lo getdns_query.o: $(srcdir)/getdns_query.c ../config.h $(srcdir)/../debug.h ../config.h \ getdns_query.lo getdns_query.o: $(srcdir)/getdns_query.c \
../getdns/getdns.h ../getdns/getdns_extra.h ../config.h $(srcdir)/../debug.h \
scratchpad.template.lo scratchpad.template.o: scratchpad.template.c ../getdns/getdns.h \ ../getdns/getdns.h \
../getdns/getdns_extra.h
scratchpad.template.lo scratchpad.template.o: scratchpad.template.c \
../getdns/getdns.h \
../getdns/getdns_extra.h ../getdns/getdns_extra.h
testmessages.lo testmessages.o: $(srcdir)/testmessages.c $(srcdir)/testmessages.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_dict.lo tests_dict.o: $(srcdir)/tests_dict.c $(srcdir)/testmessages.h \
tests_list.lo tests_list.o: $(srcdir)/tests_list.c $(srcdir)/testmessages.h ../getdns/getdns.h ../getdns/getdns.h
tests_namespaces.lo tests_namespaces.o: $(srcdir)/tests_namespaces.c $(srcdir)/testmessages.h ../getdns/getdns.h tests_list.lo tests_list.o: $(srcdir)/tests_list.c $(srcdir)/testmessages.h \
tests_stub_async.lo tests_stub_async.o: $(srcdir)/tests_stub_async.c ../config.h $(srcdir)/testmessages.h \ ../getdns/getdns.h
../getdns/getdns.h ../getdns/getdns_extra.h tests_namespaces.lo tests_namespaces.o: $(srcdir)/tests_namespaces.c $(srcdir)/testmessages.h \
tests_stub_sync.lo tests_stub_sync.o: $(srcdir)/tests_stub_sync.c $(srcdir)/testmessages.h ../getdns/getdns.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 ../getdns/getdns_extra.h

View File

@ -4,7 +4,7 @@
mkdir ub || true mkdir ub || true
cd ub cd ub
for f in mini_event.c mini_event.h rbtree.c rbtree.h for f in rbtree.c rbtree.h
do do
wget http://unbound.net/svn/trunk/util/$f || \ wget http://unbound.net/svn/trunk/util/$f || \
ftp http://unbound.net/svn/trunk/util/$f || continue ftp http://unbound.net/svn/trunk/util/$f || continue

View File

@ -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 <time.h>
#endif
#include <sys/time.h>
#if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK)
#include <signal.h>
#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; i<base->maxfd+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 */

View File

@ -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 */

View File

@ -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 <signal.h>
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#include <sys/time.h>
#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; i<base->max; 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; i<WSK_MAX_ITEMS; i++) {
if(waitfor[i] == x)
waitfor[i] = 0;
}
}
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->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; i<base->max; 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; i<base->max; 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; i<numwait; i++)
eventlist[i]->just_checked = 1;
//verbose(VERB_CLIENT, "winsock_event signals");
for(i=startidx; i<numwait; i++) {
if(!base->waitfor[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; i<numwait; i++) {
short bits = 0;
/* eventlist[i] fired */
/* see if eventlist[i] is still valid and just checked from
* WSAWaitForEvents */
if(!base->waitfor[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 */

View File

@ -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 */