mirror of https://github.com/getdnsapi/getdns.git
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:
parent
39f7e87f1a
commit
4fd8d3dddd
70
configure.ac
70
configure.ac
|
@ -453,45 +453,39 @@ if test "$USE_WINSOCK" = 1; then
|
|||
AC_DEFINE_UNQUOTED([GETDNS_ON_WINDOWS], [1], [Define this to enable Windows build.])
|
||||
AC_DEFINE_UNQUOTED([STUB_NATIVE_DNSSEC], [1])
|
||||
LIBS="$LIBS -lgdi32 -liphlpapi"
|
||||
my_with_libunbound=0
|
||||
my_with_libidn=0
|
||||
else
|
||||
my_with_libidn=1
|
||||
fi
|
||||
|
||||
|
||||
if test $my_with_libidn = 1
|
||||
then
|
||||
AC_ARG_WITH(libidn, AS_HELP_STRING([--with-libidn=pathname],
|
||||
[path to libidn (default: search /usr/local ..)]),
|
||||
[], [withval="yes"])
|
||||
if test x_$withval = x_yes; then
|
||||
for dir in /usr/local /opt/local /usr/pkg /usr/sfw; do
|
||||
if test -f "$dir/include/idna.h"; then
|
||||
CFLAGS="$CFLAGS -I$dir/include"
|
||||
LDFLAGS="$LDFLAGS -L$dir/lib"
|
||||
AC_MSG_NOTICE([Found libidn in $dir])
|
||||
break
|
||||
fi
|
||||
if test -f "$dir/include/idn/idna.h"; then
|
||||
CFLAGS="$CFLAGS -I$dir/include/idn"
|
||||
LDFLAGS="$LDFLAGS -L$dir/lib"
|
||||
AC_MSG_NOTICE([Found libidn in $dir])
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -f "/usr/include/idn/idna.h"; then
|
||||
CFLAGS="$CFLAGS -I/usr/include/idn"
|
||||
#LDFLAGS="$LDFLAGS -L/usr/lib"
|
||||
AC_MSG_NOTICE([Found libidn in /usr])
|
||||
my_with_libidn=1
|
||||
AC_ARG_WITH(libidn, AS_HELP_STRING([--with-libidn=pathname],
|
||||
[path to libidn (default: search /usr/local ..)]),
|
||||
[], [withval="yes"])
|
||||
if test x_$withval = x_yes; then
|
||||
for dir in /usr/local /opt/local /usr/pkg /usr/sfw; do
|
||||
if test -f "$dir/include/idna.h"; then
|
||||
CFLAGS="$CFLAGS -I$dir/include"
|
||||
LDFLAGS="$LDFLAGS -L$dir/lib"
|
||||
AC_MSG_NOTICE([Found libidn in $dir])
|
||||
break
|
||||
fi
|
||||
if test -f "$dir/include/idn/idna.h"; then
|
||||
CFLAGS="$CFLAGS -I$dir/include/idn"
|
||||
LDFLAGS="$LDFLAGS -L$dir/lib"
|
||||
AC_MSG_NOTICE([Found libidn in $dir])
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -f "/usr/include/idn/idna.h"; then
|
||||
CFLAGS="$CFLAGS -I/usr/include/idn"
|
||||
#LDFLAGS="$LDFLAGS -L/usr/lib"
|
||||
AC_MSG_NOTICE([Found libidn in /usr])
|
||||
fi
|
||||
else
|
||||
if test x_$withval != x_no; then
|
||||
CFLAGS="$CFLAGS -I$withval/include"
|
||||
LDFLAGS="$LDFLAGS -L$withval/lib"
|
||||
else
|
||||
if test x_$withval != x_no; then
|
||||
CFLAGS="$CFLAGS -I$withval/include"
|
||||
LDFLAGS="$LDFLAGS -L$withval/lib"
|
||||
else
|
||||
my_with_libidn=0
|
||||
fi
|
||||
my_with_libidn=0
|
||||
fi
|
||||
fi
|
||||
|
||||
|
@ -1161,6 +1155,14 @@ const char *inet_ntop(int af, const void *src, char *dst, size_t size);
|
|||
#include <openssl/ssl.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#ifndef PRIu64
|
||||
#define PRIu64 "llu"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ATTR_FORMAT
|
||||
# define ATTR_FORMAT(archetype, string_index, first_to_check) \
|
||||
__attribute__ ((format (archetype, string_index, first_to_check)))
|
||||
|
|
|
@ -149,16 +149,24 @@ depend:
|
|||
|
||||
# Dependencies for the examples
|
||||
example-all-functions.lo example-all-functions.o: $(srcdir)/example-all-functions.c $(srcdir)/getdns_libevent.h \
|
||||
../../src/config.h ../../src/getdns/getdns.h \
|
||||
$(srcdir)/../../src/getdns/getdns_ext_libevent.h ../../src/getdns/getdns_extra.h
|
||||
example-reverse.lo example-reverse.o: $(srcdir)/example-reverse.c $(srcdir)/getdns_libevent.h ../../src/config.h \
|
||||
../../src/getdns/getdns.h $(srcdir)/../../src/getdns/getdns_ext_libevent.h \
|
||||
../../src/config.h \
|
||||
../../src/getdns/getdns.h \
|
||||
$(srcdir)/../../src/getdns/getdns_ext_libevent.h \
|
||||
../../src/getdns/getdns_extra.h
|
||||
example-reverse.lo example-reverse.o: $(srcdir)/example-reverse.c $(srcdir)/getdns_libevent.h \
|
||||
../../src/config.h \
|
||||
../../src/getdns/getdns.h \
|
||||
$(srcdir)/../../src/getdns/getdns_ext_libevent.h \
|
||||
../../src/getdns/getdns_extra.h
|
||||
example-simple-answers.lo example-simple-answers.o: $(srcdir)/example-simple-answers.c $(srcdir)/getdns_libevent.h \
|
||||
../../src/config.h ../../src/getdns/getdns.h \
|
||||
$(srcdir)/../../src/getdns/getdns_ext_libevent.h ../../src/getdns/getdns_extra.h
|
||||
../../src/config.h \
|
||||
../../src/getdns/getdns.h \
|
||||
$(srcdir)/../../src/getdns/getdns_ext_libevent.h \
|
||||
../../src/getdns/getdns_extra.h
|
||||
example-synchronous.lo example-synchronous.o: $(srcdir)/example-synchronous.c $(srcdir)/getdns_core_only.h \
|
||||
../../src/getdns/getdns.h
|
||||
example-tree.lo example-tree.o: $(srcdir)/example-tree.c $(srcdir)/getdns_libevent.h ../../src/config.h \
|
||||
../../src/getdns/getdns.h $(srcdir)/../../src/getdns/getdns_ext_libevent.h \
|
||||
example-tree.lo example-tree.o: $(srcdir)/example-tree.c $(srcdir)/getdns_libevent.h \
|
||||
../../src/config.h \
|
||||
../../src/getdns/getdns.h \
|
||||
$(srcdir)/../../src/getdns/getdns_ext_libevent.h \
|
||||
../../src/getdns/getdns_extra.h
|
||||
|
|
236
src/Makefile.in
236
src/Makefile.in
|
@ -74,9 +74,9 @@ LIBOBJDIR=
|
|||
LIBOBJS=@LIBOBJS@
|
||||
COMPAT_OBJ=$(LIBOBJS:.o=.lo)
|
||||
|
||||
UTIL_OBJ=mini_event.lo winsock_event.lo rbtree.lo val_secalgo.lo
|
||||
UTIL_OBJ=rbtree.lo val_secalgo.lo
|
||||
|
||||
EXTENSION_OBJ=libmini_event.lo libevent.lo libev.lo
|
||||
EXTENSION_OBJ=default_eventloop.lo libevent.lo libev.lo
|
||||
|
||||
NON_C99_OBJS=context.lo libuv.lo
|
||||
|
||||
|
@ -144,8 +144,8 @@ libgetdns_ext_ev.la: libgetdns.la libev.lo
|
|||
$(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ libev.lo libgetdns.la $(LDFLAGS) $(EXTENSION_LIBEV_LDFLAGS) $(EXTENSION_LIBEV_EXT_LIBS) -rpath $(libdir) -version-info $(libversion) -no-undefined -export-symbols $(srcdir)/extension/libev.symbols
|
||||
|
||||
|
||||
libgetdns.la: $(GETDNS_OBJ) version.lo context.lo libmini_event.lo $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ)
|
||||
$(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ $(GETDNS_OBJ) version.lo context.lo libmini_event.lo $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) $(LDFLAGS) -rpath $(libdir) -version-info $(libversion) -no-undefined -export-symbols $(srcdir)/libgetdns.symbols
|
||||
libgetdns.la: $(GETDNS_OBJ) version.lo context.lo default_eventloop.lo $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ)
|
||||
$(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ $(GETDNS_OBJ) version.lo context.lo default_eventloop.lo $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) $(LDFLAGS) -rpath $(libdir) -version-info $(libversion) -no-undefined -export-symbols $(srcdir)/libgetdns.symbols
|
||||
|
||||
|
||||
test: all
|
||||
|
@ -225,114 +225,136 @@ depend:
|
|||
FORCE:
|
||||
|
||||
# Dependencies for gldns, utils, the extensions and compat functions
|
||||
const-info.lo const-info.o: $(srcdir)/const-info.c getdns/getdns.h getdns/getdns_extra.h \
|
||||
getdns/getdns.h $(srcdir)/const-info.h
|
||||
context.lo context.o: $(srcdir)/context.c config.h $(srcdir)/debug.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h \
|
||||
$(srcdir)/gldns/wire2str.h $(srcdir)/context.h getdns/getdns.h getdns/getdns_extra.h \
|
||||
getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/extension/libmini_event.h \
|
||||
config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h \
|
||||
$(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \
|
||||
$(srcdir)/dnssec.h $(srcdir)/stub.h $(srcdir)/list.h $(srcdir)/dict.h $(srcdir)/pubkey-pinning.h
|
||||
convert.lo convert.o: $(srcdir)/convert.c config.h getdns/getdns.h getdns/getdns_extra.h \
|
||||
getdns/getdns.h $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \
|
||||
$(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \
|
||||
$(srcdir)/types-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \
|
||||
$(srcdir)/gldns/wire2str.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/convert.h
|
||||
dict.lo dict.o: $(srcdir)/dict.c config.h $(srcdir)/types-internal.h getdns/getdns.h \
|
||||
getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h $(srcdir)/util-internal.h \
|
||||
$(srcdir)/context.h $(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h \
|
||||
$(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \
|
||||
$(srcdir)/gldns/pkthdr.h $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/const-info.h $(srcdir)/gldns/wire2str.h
|
||||
dnssec.lo dnssec.o: $(srcdir)/dnssec.c config.h $(srcdir)/debug.h getdns/getdns.h $(srcdir)/context.h \
|
||||
getdns/getdns_extra.h getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \
|
||||
$(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \
|
||||
$(srcdir)/types-internal.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \
|
||||
$(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h \
|
||||
$(srcdir)/gldns/keyraw.h $(srcdir)/gldns/parseutil.h $(srcdir)/general.h $(srcdir)/dict.h $(srcdir)/list.h \
|
||||
$(srcdir)/util/val_secalgo.h
|
||||
general.lo general.o: $(srcdir)/general.c config.h $(srcdir)/gldns/wire2str.h $(srcdir)/context.h getdns/getdns.h \
|
||||
getdns/getdns_extra.h getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \
|
||||
$(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \
|
||||
$(srcdir)/types-internal.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \
|
||||
$(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/stub.h $(srcdir)/general.h
|
||||
list.lo list.o: $(srcdir)/list.c $(srcdir)/types-internal.h getdns/getdns.h getdns/getdns_extra.h \
|
||||
getdns/getdns.h $(srcdir)/util/rbtree.h $(srcdir)/util-internal.h config.h $(srcdir)/context.h \
|
||||
$(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \
|
||||
$(srcdir)/types-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \
|
||||
$(srcdir)/list.h $(srcdir)/dict.h
|
||||
pubkey-pinning.lo pubkey-pinning.o: $(srcdir)/pubkey-pinning.c config.h $(srcdir)/debug.h getdns/getdns.h \
|
||||
$(srcdir)/context.h getdns/getdns.h getdns/getdns_extra.h $(srcdir)/types-internal.h \
|
||||
$(srcdir)/util/rbtree.h $(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h \
|
||||
$(srcdir)/util/rbtree.h $(srcdir)/types-internal.h
|
||||
request-internal.lo request-internal.o: $(srcdir)/request-internal.c config.h $(srcdir)/types-internal.h \
|
||||
getdns/getdns.h getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h \
|
||||
$(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/extension/libmini_event.h config.h \
|
||||
$(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \
|
||||
$(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/str2wire.h \
|
||||
const-info.lo const-info.o: $(srcdir)/const-info.c getdns/getdns.h \
|
||||
getdns/getdns_extra.h $(srcdir)/const-info.h
|
||||
context.lo context.o: $(srcdir)/context.c config.h $(srcdir)/debug.h \
|
||||
$(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h $(srcdir)/context.h \
|
||||
getdns/getdns.h \
|
||||
getdns/getdns_extra.h $(srcdir)/types-internal.h \
|
||||
$(srcdir)/util/rbtree.h $(srcdir)/extension/default_eventloop.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h \
|
||||
$(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/stub.h $(srcdir)/list.h $(srcdir)/dict.h \
|
||||
$(srcdir)/pubkey-pinning.h
|
||||
convert.lo convert.o: $(srcdir)/convert.c config.h \
|
||||
getdns/getdns.h \
|
||||
getdns/getdns_extra.h $(srcdir)/util-internal.h \
|
||||
$(srcdir)/context.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/extension/default_eventloop.h \
|
||||
$(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/wire2str.h \
|
||||
$(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/convert.h
|
||||
dict.lo dict.o: $(srcdir)/dict.c config.h $(srcdir)/types-internal.h \
|
||||
getdns/getdns.h \
|
||||
getdns/getdns_extra.h $(srcdir)/util/rbtree.h \
|
||||
$(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h $(srcdir)/rr-iter.h \
|
||||
$(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/const-info.h \
|
||||
$(srcdir)/gldns/wire2str.h
|
||||
dnssec.lo dnssec.o: $(srcdir)/dnssec.c config.h $(srcdir)/debug.h \
|
||||
getdns/getdns.h $(srcdir)/context.h \
|
||||
getdns/getdns_extra.h $(srcdir)/types-internal.h \
|
||||
$(srcdir)/util/rbtree.h $(srcdir)/extension/default_eventloop.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h \
|
||||
$(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/gldns/str2wire.h \
|
||||
$(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/keyraw.h $(srcdir)/gldns/parseutil.h \
|
||||
$(srcdir)/general.h $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/util/val_secalgo.h
|
||||
general.lo general.o: $(srcdir)/general.c config.h $(srcdir)/general.h \
|
||||
getdns/getdns.h $(srcdir)/types-internal.h \
|
||||
getdns/getdns_extra.h $(srcdir)/util/rbtree.h \
|
||||
$(srcdir)/gldns/wire2str.h $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h $(srcdir)/util-internal.h \
|
||||
$(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/stub.h \
|
||||
$(srcdir)/dict.h
|
||||
list.lo list.o: $(srcdir)/list.c $(srcdir)/types-internal.h \
|
||||
getdns/getdns.h \
|
||||
getdns/getdns_extra.h $(srcdir)/util/rbtree.h \
|
||||
$(srcdir)/util-internal.h config.h $(srcdir)/context.h \
|
||||
$(srcdir)/extension/default_eventloop.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \
|
||||
$(srcdir)/gldns/pkthdr.h $(srcdir)/list.h $(srcdir)/dict.h
|
||||
pubkey-pinning.lo pubkey-pinning.o: $(srcdir)/pubkey-pinning.c config.h \
|
||||
$(srcdir)/debug.h getdns/getdns.h $(srcdir)/context.h \
|
||||
getdns/getdns_extra.h $(srcdir)/types-internal.h \
|
||||
$(srcdir)/util/rbtree.h $(srcdir)/extension/default_eventloop.h
|
||||
request-internal.lo request-internal.o: $(srcdir)/request-internal.c \
|
||||
config.h $(srcdir)/types-internal.h \
|
||||
getdns/getdns.h \
|
||||
getdns/getdns_extra.h $(srcdir)/util/rbtree.h \
|
||||
$(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h $(srcdir)/rr-iter.h \
|
||||
$(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/str2wire.h \
|
||||
$(srcdir)/gldns/rrdef.h $(srcdir)/dict.h $(srcdir)/debug.h
|
||||
rr-dict.lo rr-dict.o: $(srcdir)/rr-dict.c $(srcdir)/rr-dict.h config.h getdns/getdns.h $(srcdir)/gldns/gbuffer.h \
|
||||
$(srcdir)/util-internal.h $(srcdir)/context.h getdns/getdns_extra.h getdns/getdns.h \
|
||||
$(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/extension/libmini_event.h config.h \
|
||||
$(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/rr-iter.h \
|
||||
$(srcdir)/gldns/pkthdr.h $(srcdir)/dict.h
|
||||
rr-iter.lo rr-iter.o: $(srcdir)/rr-iter.c $(srcdir)/rr-iter.h getdns/getdns.h $(srcdir)/rr-dict.h config.h \
|
||||
$(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/rrdef.h
|
||||
stub.lo stub.o: $(srcdir)/stub.c config.h $(srcdir)/debug.h $(srcdir)/stub.h getdns/getdns.h $(srcdir)/types-internal.h \
|
||||
getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h $(srcdir)/gldns/gbuffer.h \
|
||||
$(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h \
|
||||
$(srcdir)/gldns/wire2str.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/context.h $(srcdir)/extension/libmini_event.h \
|
||||
config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h \
|
||||
$(srcdir)/util-internal.h $(srcdir)/general.h $(srcdir)/pubkey-pinning.h
|
||||
sync.lo sync.o: $(srcdir)/sync.c getdns/getdns.h config.h $(srcdir)/context.h getdns/getdns_extra.h \
|
||||
getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/extension/libmini_event.h \
|
||||
config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/general.h \
|
||||
$(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \
|
||||
$(srcdir)/dnssec.h $(srcdir)/stub.h $(srcdir)/gldns/wire2str.h
|
||||
util-internal.lo util-internal.o: $(srcdir)/util-internal.c config.h getdns/getdns.h $(srcdir)/dict.h \
|
||||
$(srcdir)/util/rbtree.h $(srcdir)/types-internal.h getdns/getdns_extra.h getdns/getdns.h \
|
||||
$(srcdir)/list.h $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/extension/libmini_event.h config.h \
|
||||
$(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \
|
||||
$(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h
|
||||
version.lo version.o: version.c
|
||||
gbuffer.lo gbuffer.o: $(srcdir)/gldns/gbuffer.c config.h $(srcdir)/gldns/gbuffer.h
|
||||
keyraw.lo keyraw.o: $(srcdir)/gldns/keyraw.c config.h $(srcdir)/gldns/keyraw.h $(srcdir)/gldns/rrdef.h
|
||||
parse.lo parse.o: $(srcdir)/gldns/parse.c config.h $(srcdir)/gldns/parse.h $(srcdir)/gldns/parseutil.h \
|
||||
rr-dict.lo rr-dict.o: $(srcdir)/rr-dict.c $(srcdir)/rr-dict.h config.h \
|
||||
getdns/getdns.h $(srcdir)/gldns/gbuffer.h \
|
||||
$(srcdir)/util-internal.h $(srcdir)/context.h \
|
||||
getdns/getdns_extra.h $(srcdir)/types-internal.h \
|
||||
$(srcdir)/util/rbtree.h $(srcdir)/extension/default_eventloop.h $(srcdir)/rr-iter.h $(srcdir)/gldns/pkthdr.h \
|
||||
$(srcdir)/dict.h
|
||||
rr-iter.lo rr-iter.o: $(srcdir)/rr-iter.c $(srcdir)/rr-iter.h \
|
||||
getdns/getdns.h $(srcdir)/rr-dict.h \
|
||||
config.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \
|
||||
$(srcdir)/gldns/rrdef.h
|
||||
stub.lo stub.o: $(srcdir)/stub.c config.h $(srcdir)/debug.h $(srcdir)/stub.h \
|
||||
getdns/getdns.h $(srcdir)/types-internal.h \
|
||||
getdns/getdns_extra.h $(srcdir)/util/rbtree.h \
|
||||
$(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/str2wire.h \
|
||||
$(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/context.h \
|
||||
$(srcdir)/extension/default_eventloop.h $(srcdir)/util-internal.h $(srcdir)/general.h $(srcdir)/pubkey-pinning.h
|
||||
sync.lo sync.o: $(srcdir)/sync.c getdns/getdns.h \
|
||||
config.h $(srcdir)/context.h \
|
||||
getdns/getdns_extra.h $(srcdir)/types-internal.h \
|
||||
$(srcdir)/util/rbtree.h $(srcdir)/extension/default_eventloop.h $(srcdir)/general.h $(srcdir)/util-internal.h \
|
||||
$(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/stub.h \
|
||||
$(srcdir)/gldns/wire2str.h
|
||||
util-internal.lo util-internal.o: $(srcdir)/util-internal.c config.h \
|
||||
getdns/getdns.h $(srcdir)/dict.h $(srcdir)/util/rbtree.h \
|
||||
$(srcdir)/types-internal.h getdns/getdns_extra.h \
|
||||
$(srcdir)/list.h $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h $(srcdir)/rr-iter.h \
|
||||
$(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h
|
||||
gbuffer.lo gbuffer.o: $(srcdir)/gldns/gbuffer.c config.h \
|
||||
$(srcdir)/gldns/gbuffer.h
|
||||
parseutil.lo parseutil.o: $(srcdir)/gldns/parseutil.c config.h $(srcdir)/gldns/parseutil.h
|
||||
rrdef.lo rrdef.o: $(srcdir)/gldns/rrdef.c config.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/parseutil.h
|
||||
str2wire.lo str2wire.o: $(srcdir)/gldns/str2wire.c config.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h \
|
||||
$(srcdir)/gldns/wire2str.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/parse.h $(srcdir)/gldns/parseutil.h
|
||||
wire2str.lo wire2str.o: $(srcdir)/gldns/wire2str.c config.h $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/str2wire.h \
|
||||
$(srcdir)/gldns/rrdef.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/parseutil.h $(srcdir)/gldns/gbuffer.h \
|
||||
$(srcdir)/gldns/keyraw.h
|
||||
keyraw.lo keyraw.o: $(srcdir)/gldns/keyraw.c config.h \
|
||||
$(srcdir)/gldns/keyraw.h $(srcdir)/gldns/rrdef.h
|
||||
parse.lo parse.o: $(srcdir)/gldns/parse.c config.h \
|
||||
$(srcdir)/gldns/parse.h $(srcdir)/gldns/parseutil.h $(srcdir)/gldns/gbuffer.h
|
||||
parseutil.lo parseutil.o: $(srcdir)/gldns/parseutil.c config.h \
|
||||
$(srcdir)/gldns/parseutil.h
|
||||
rrdef.lo rrdef.o: $(srcdir)/gldns/rrdef.c config.h \
|
||||
$(srcdir)/gldns/rrdef.h $(srcdir)/gldns/parseutil.h
|
||||
str2wire.lo str2wire.o: $(srcdir)/gldns/str2wire.c config.h \
|
||||
$(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/gbuffer.h \
|
||||
$(srcdir)/gldns/parse.h $(srcdir)/gldns/parseutil.h
|
||||
wire2str.lo wire2str.o: $(srcdir)/gldns/wire2str.c config.h \
|
||||
$(srcdir)/gldns/wire2str.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/pkthdr.h \
|
||||
$(srcdir)/gldns/parseutil.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/keyraw.h
|
||||
arc4_lock.lo arc4_lock.o: $(srcdir)/compat/arc4_lock.c config.h
|
||||
arc4random.lo arc4random.o: $(srcdir)/compat/arc4random.c config.h $(srcdir)/compat/chacha_private.h
|
||||
arc4random_uniform.lo arc4random_uniform.o: $(srcdir)/compat/arc4random_uniform.c config.h
|
||||
explicit_bzero.lo explicit_bzero.o: $(srcdir)/compat/explicit_bzero.c config.h
|
||||
getentropy_linux.lo getentropy_linux.o: $(srcdir)/compat/getentropy_linux.c config.h
|
||||
getentropy_osx.lo getentropy_osx.o: $(srcdir)/compat/getentropy_osx.c config.h
|
||||
getentropy_solaris.lo getentropy_solaris.o: $(srcdir)/compat/getentropy_solaris.c config.h
|
||||
arc4random.lo arc4random.o: $(srcdir)/compat/arc4random.c config.h \
|
||||
$(srcdir)/compat/chacha_private.h
|
||||
arc4random_uniform.lo arc4random_uniform.o: $(srcdir)/compat/arc4random_uniform.c \
|
||||
config.h
|
||||
explicit_bzero.lo explicit_bzero.o: $(srcdir)/compat/explicit_bzero.c \
|
||||
config.h
|
||||
getentropy_linux.lo getentropy_linux.o: $(srcdir)/compat/getentropy_linux.c \
|
||||
config.h
|
||||
getentropy_osx.lo getentropy_osx.o: $(srcdir)/compat/getentropy_osx.c \
|
||||
config.h
|
||||
getentropy_solaris.lo getentropy_solaris.o: $(srcdir)/compat/getentropy_solaris.c \
|
||||
config.h
|
||||
getentropy_win.lo getentropy_win.o: $(srcdir)/compat/getentropy_win.c
|
||||
inet_ntop.lo inet_ntop.o: $(srcdir)/compat/inet_ntop.c config.h
|
||||
inet_pton.lo inet_pton.o: $(srcdir)/compat/inet_pton.c config.h
|
||||
sha512.lo sha512.o: $(srcdir)/compat/sha512.c config.h
|
||||
strlcpy.lo strlcpy.o: $(srcdir)/compat/strlcpy.c config.h
|
||||
mini_event.lo mini_event.o: $(srcdir)/util/mini_event.c config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \
|
||||
$(srcdir)/util/fptr_wlist.h
|
||||
rbtree.lo rbtree.o: $(srcdir)/util/rbtree.c config.h $(srcdir)/util/log.h $(srcdir)/debug.h config.h \
|
||||
$(srcdir)/util/fptr_wlist.h $(srcdir)/util/rbtree.h
|
||||
val_secalgo.lo val_secalgo.o: $(srcdir)/util/val_secalgo.c config.h $(srcdir)/util/val_secalgo.h $(srcdir)/util/log.h \
|
||||
$(srcdir)/debug.h config.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/keyraw.h $(srcdir)/gldns/gbuffer.h
|
||||
winsock_event.lo winsock_event.o: $(srcdir)/util/winsock_event.c config.h
|
||||
libev.lo libev.o: $(srcdir)/extension/libev.c config.h $(srcdir)/types-internal.h getdns/getdns.h \
|
||||
getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h \
|
||||
$(srcdir)/getdns/getdns_ext_libev.h getdns/getdns_extra.h
|
||||
libevent.lo libevent.o: $(srcdir)/extension/libevent.c config.h $(srcdir)/types-internal.h \
|
||||
getdns/getdns.h getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h \
|
||||
$(srcdir)/getdns/getdns_ext_libevent.h getdns/getdns_extra.h
|
||||
libmini_event.lo libmini_event.o: $(srcdir)/extension/libmini_event.c config.h $(srcdir)/debug.h config.h \
|
||||
$(srcdir)/types-internal.h getdns/getdns.h getdns/getdns_extra.h getdns/getdns.h \
|
||||
$(srcdir)/util/rbtree.h $(srcdir)/extension/libmini_event.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h
|
||||
libuv.lo libuv.o: $(srcdir)/extension/libuv.c config.h $(srcdir)/debug.h config.h $(srcdir)/types-internal.h \
|
||||
getdns/getdns.h getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h \
|
||||
$(srcdir)/getdns/getdns_ext_libuv.h getdns/getdns_extra.h
|
||||
rbtree.lo rbtree.o: $(srcdir)/util/rbtree.c config.h $(srcdir)/util/log.h \
|
||||
$(srcdir)/debug.h $(srcdir)/util/fptr_wlist.h $(srcdir)/util/rbtree.h
|
||||
val_secalgo.lo val_secalgo.o: $(srcdir)/util/val_secalgo.c config.h \
|
||||
$(srcdir)/util/val_secalgo.h $(srcdir)/util/log.h $(srcdir)/debug.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/keyraw.h \
|
||||
$(srcdir)/gldns/gbuffer.h
|
||||
default_eventloop.lo default_eventloop.o: $(srcdir)/extension/default_eventloop.c \
|
||||
$(srcdir)/extension/default_eventloop.h config.h \
|
||||
getdns/getdns.h \
|
||||
getdns/getdns_extra.h $(srcdir)/debug.h
|
||||
libev.lo libev.o: $(srcdir)/extension/libev.c config.h \
|
||||
$(srcdir)/types-internal.h getdns/getdns.h \
|
||||
getdns/getdns_extra.h $(srcdir)/util/rbtree.h \
|
||||
$(srcdir)/getdns/getdns_ext_libev.h
|
||||
libevent.lo libevent.o: $(srcdir)/extension/libevent.c config.h \
|
||||
$(srcdir)/types-internal.h getdns/getdns.h \
|
||||
getdns/getdns_extra.h $(srcdir)/util/rbtree.h \
|
||||
$(srcdir)/getdns/getdns_ext_libevent.h
|
||||
libuv.lo libuv.o: $(srcdir)/extension/libuv.c config.h $(srcdir)/debug.h \
|
||||
$(srcdir)/types-internal.h getdns/getdns.h \
|
||||
getdns/getdns_extra.h $(srcdir)/util/rbtree.h \
|
||||
$(srcdir)/getdns/getdns_ext_libuv.h
|
||||
|
|
|
@ -966,6 +966,9 @@ getdns_context_create_with_extended_memory_functions(
|
|||
struct getdns_context *result = NULL;
|
||||
mf_union mf;
|
||||
gldns_buffer gbuf;
|
||||
#ifdef USE_WINSOCK
|
||||
WORD wVersionRequested;
|
||||
#endif
|
||||
|
||||
if (!context || !malloc || !realloc || !free)
|
||||
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||
|
@ -979,6 +982,14 @@ getdns_context_create_with_extended_memory_functions(
|
|||
if (!result)
|
||||
return GETDNS_RETURN_MEMORY_ERROR;
|
||||
|
||||
#ifdef USE_WINSOCK
|
||||
/* We need to run WSAStartup() to be able to use getaddrinfo() */
|
||||
wVersionRequested = MAKEWORD(2, 2);
|
||||
if (WSAStartup(wVersionRequested, &result->wsaData)) {
|
||||
r = GETDNS_RETURN_GENERIC_ERROR;
|
||||
goto error;
|
||||
}
|
||||
#endif
|
||||
result->processing = 0;
|
||||
result->destroying = 0;
|
||||
result->my_mf.mf_arg = userarg;
|
||||
|
@ -1050,9 +1061,8 @@ getdns_context_create_with_extended_memory_functions(
|
|||
result->tls_query_padding_blocksize = 1; /* default is to not try to pad */
|
||||
result-> tls_ctx = NULL;
|
||||
|
||||
result->extension = &result->mini_event.loop;
|
||||
if ((r = _getdns_mini_event_init(result, &result->mini_event)))
|
||||
goto error;
|
||||
result->extension = &result->default_eventloop.loop;
|
||||
_getdns_default_eventloop_init(&result->default_eventloop);
|
||||
|
||||
result->fchg_resolvconf = NULL;
|
||||
result->fchg_hosts = NULL;
|
||||
|
@ -1198,6 +1208,9 @@ getdns_context_destroy(struct getdns_context *context)
|
|||
_getdns_traverse_postorder(&context->local_hosts,
|
||||
destroy_local_host, context);
|
||||
|
||||
#ifdef USE_WINSOCK
|
||||
WSACleanup();
|
||||
#endif
|
||||
GETDNS_FREE(context->my_mf, context);
|
||||
} /* getdns_context_destroy */
|
||||
|
||||
|
@ -2798,55 +2811,36 @@ _getdns_bindata_destroy(struct mem_funcs *mfs,
|
|||
|
||||
/* TODO: Remove next_timeout argument from getdns_context_get_num_pending_requests
|
||||
*/
|
||||
void _getdns_handle_timeouts(struct _getdns_event_base* base, struct timeval* now,
|
||||
struct timeval* wait);
|
||||
uint32_t
|
||||
getdns_context_get_num_pending_requests(struct getdns_context* context,
|
||||
getdns_context_get_num_pending_requests(getdns_context* context,
|
||||
struct timeval* next_timeout)
|
||||
{
|
||||
struct timeval dispose;
|
||||
(void)next_timeout;
|
||||
|
||||
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
|
||||
if (!context)
|
||||
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||
|
||||
if (context->outbound_requests.count)
|
||||
context->extension->vmt->run_once(context->extension, 0);
|
||||
|
||||
/* TODO: Remove this when next_timeout is gone */
|
||||
if (context->extension == &context->mini_event.loop)
|
||||
_getdns_handle_timeouts(context->mini_event.base,
|
||||
&context->mini_event.time_tv,
|
||||
next_timeout ? next_timeout : &dispose);
|
||||
|
||||
return context->outbound_requests.count;
|
||||
}
|
||||
|
||||
/* process async reqs */
|
||||
getdns_return_t
|
||||
getdns_context_process_async(struct getdns_context* context)
|
||||
getdns_context_process_async(getdns_context *context)
|
||||
{
|
||||
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
|
||||
if (!context)
|
||||
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||
|
||||
#ifdef HAVE_LIBUNBOUND
|
||||
if (ub_poll(context->unbound_ctx) && ub_process(context->unbound_ctx)){
|
||||
/* need an async return code? */
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
}
|
||||
#endif
|
||||
context->extension->vmt->run_once(context->extension, 0);
|
||||
|
||||
return GETDNS_RETURN_GOOD;
|
||||
}
|
||||
|
||||
void
|
||||
getdns_context_run(getdns_context *context)
|
||||
{
|
||||
if (context->extension == &context->mini_event.loop) {
|
||||
if (getdns_context_get_num_pending_requests(context, NULL) > 0 &&
|
||||
!getdns_context_process_async(context))
|
||||
context->extension->vmt->run(context->extension);
|
||||
}
|
||||
else
|
||||
context->extension->vmt->run(context->extension);
|
||||
context->extension->vmt->run(context->extension);
|
||||
}
|
||||
|
||||
typedef struct timeout_accumulator {
|
||||
|
@ -2891,8 +2885,9 @@ getdns_context_detach_eventloop(struct getdns_context* context)
|
|||
/* cancel all outstanding requests */
|
||||
cancel_outstanding_requests(context, 1);
|
||||
context->extension->vmt->cleanup(context->extension);
|
||||
context->extension = &context->mini_event.loop;
|
||||
return _getdns_mini_event_init(context, &context->mini_event);
|
||||
context->extension = &context->default_eventloop.loop;
|
||||
_getdns_default_eventloop_init(&context->default_eventloop);
|
||||
return GETDNS_RETURN_GOOD;
|
||||
}
|
||||
|
||||
getdns_return_t
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
#include "getdns/getdns_extra.h"
|
||||
#include "config.h"
|
||||
#include "types-internal.h"
|
||||
#include "extension/libmini_event.h"
|
||||
#include "extension/default_eventloop.h"
|
||||
#include "util/rbtree.h"
|
||||
|
||||
struct getdns_dns_req;
|
||||
|
@ -245,7 +245,7 @@ struct getdns_context {
|
|||
#endif
|
||||
|
||||
/* The default extension */
|
||||
_getdns_mini_event mini_event;
|
||||
_getdns_default_eventloop default_eventloop;
|
||||
|
||||
/*
|
||||
* state data used to detect changes to the system config files
|
||||
|
@ -255,6 +255,10 @@ struct getdns_context {
|
|||
|
||||
uint8_t trust_anchors_spc[1024];
|
||||
|
||||
#ifdef USE_WINSOCK
|
||||
/* We need to run WSAStartup() to be able to use getaddrinfo() */
|
||||
WSADATA wsaData;
|
||||
#endif
|
||||
}; /* getdns_context */
|
||||
|
||||
/** internal functions **/
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -1,11 +1,10 @@
|
|||
/**
|
||||
*
|
||||
* \file libmini_event.h
|
||||
/*
|
||||
* \file default_eventloop.h
|
||||
* @brief Build in default eventloop extension that uses select.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2013, NLnet Labs, Verisign, Inc.
|
||||
* Copyright (c) 2013, NLNet Labs, Verisign, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -30,34 +29,31 @@
|
|||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _GETDNS_LIBMINI_EVENT_H_
|
||||
#define _GETDNS_LIBMINI_EVENT_H_
|
||||
|
||||
#ifndef DEFAULT_EVENTLOOP_H_
|
||||
#define DEFAULT_EVENTLOOP_H_
|
||||
#include "config.h"
|
||||
#ifndef USE_WINSOCK
|
||||
#include "util/mini_event.h"
|
||||
#else
|
||||
#include "util/winsock_event.h"
|
||||
#endif
|
||||
#include "types-internal.h"
|
||||
#include "getdns/getdns.h"
|
||||
#include "getdns/getdns_extra.h"
|
||||
|
||||
typedef struct _getdns_mini_event {
|
||||
getdns_eventloop loop;
|
||||
time_t time_secs;
|
||||
struct timeval time_tv;
|
||||
struct _getdns_event_base *base;
|
||||
size_t n_events;
|
||||
struct mem_funcs mf;
|
||||
} _getdns_mini_event;
|
||||
/* No more than select's capability queries can be outstanding,
|
||||
* The number of outstanding timeouts should be less or equal then
|
||||
* the number of outstanding queries, so MAX_TIMEOUTS equal to
|
||||
* FD_SETSIZE should be safe.
|
||||
*/
|
||||
#define MAX_TIMEOUTS FD_SETSIZE
|
||||
|
||||
getdns_return_t
|
||||
_getdns_mini_event_init(getdns_context *context, _getdns_mini_event *mini_event);
|
||||
/* Eventloop based on select */
|
||||
typedef struct _getdns_default_eventloop {
|
||||
getdns_eventloop loop;
|
||||
getdns_eventloop_event *fd_events[FD_SETSIZE];
|
||||
uint64_t fd_timeout_times[FD_SETSIZE];
|
||||
getdns_eventloop_event *timeout_events[MAX_TIMEOUTS];
|
||||
uint64_t timeout_times[MAX_TIMEOUTS];
|
||||
} _getdns_default_eventloop;
|
||||
|
||||
getdns_return_t
|
||||
_getdns_mini_event_create(getdns_context *ctxt, _getdns_mini_event **mini_event);
|
||||
|
||||
void
|
||||
_getdns_mini_event_destroy(_getdns_mini_event *mini_event);
|
||||
_getdns_default_eventloop_init(_getdns_default_eventloop *loop);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _GETDNS_LIBMINI_EVENT_H_ */
|
|
@ -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);
|
||||
}
|
104
src/stub.c
104
src/stub.c
|
@ -50,12 +50,20 @@
|
|||
#include "pubkey-pinning.h"
|
||||
|
||||
#ifdef USE_WINSOCK
|
||||
#define EINPROGRESS 112
|
||||
#define EWOULDBLOCK 140
|
||||
typedef u_short sa_family_t;
|
||||
#include "util/winsock_event.h"
|
||||
#define _getdns_EWOULDBLOCK (WSAGetLastError() == WSATRY_AGAIN ||\
|
||||
WSAGetLastError() == WSAEWOULDBLOCK)
|
||||
#define _getdns_EINPROGRESS (WSAGetLastError() == WSAEINPROGRESS)
|
||||
#else
|
||||
#define _getdns_EWOULDBLOCK (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
#define _getdns_EINPROGRESS (errno == EINPROGRESS)
|
||||
#endif
|
||||
|
||||
/* WSA TODO:
|
||||
* STUB_TCP_WOULDBLOCK added to deal with edge triggered event loops (versus
|
||||
* level triggered). See also lines containing WSA TODO below...
|
||||
*/
|
||||
#define STUB_TCP_WOULDBLOCK -6
|
||||
#define STUB_OUT_OF_OPTIONS -5 /* upstream options exceeded MAXIMUM_UPSTREAM_OPTION_SPACE */
|
||||
#define STUB_TLS_SETUP_ERROR -4
|
||||
#define STUB_TCP_AGAIN -3
|
||||
|
@ -402,10 +410,21 @@ tcp_connected(getdns_upstream *upstream) {
|
|||
int error = 0;
|
||||
socklen_t len = (socklen_t)sizeof(error);
|
||||
getsockopt(upstream->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &len);
|
||||
if (error == EINPROGRESS || error == EWOULDBLOCK)
|
||||
return STUB_TCP_AGAIN; /* try again */
|
||||
#ifdef USE_WINSOCK
|
||||
if (error == WSAEINPROGRESS)
|
||||
return STUB_TCP_WOULDBLOCK;
|
||||
else if (error == WSAEWOULDBLOCK)
|
||||
return STUB_TCP_WOULDBLOCK;
|
||||
else if (error != 0)
|
||||
return STUB_TCP_ERROR;
|
||||
#else
|
||||
if (error == EINPROGRESS)
|
||||
return STUB_TCP_WOULDBLOCK;
|
||||
else if (error == EWOULDBLOCK || error == EAGAIN)
|
||||
return STUB_TCP_WOULDBLOCK;
|
||||
else if (error != 0)
|
||||
return STUB_TCP_ERROR;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -625,7 +644,7 @@ stub_tls_timeout_cb(void *userarg)
|
|||
/****************************/
|
||||
|
||||
static int
|
||||
stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf, getdns_eventloop_event* event)
|
||||
stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf)
|
||||
{
|
||||
ssize_t read;
|
||||
uint8_t *buf;
|
||||
|
@ -642,33 +661,21 @@ stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf, getdns_eventl
|
|||
}
|
||||
read = recv(fd, (void *)tcp->read_pos, tcp->to_read, 0);
|
||||
if (read == -1) {
|
||||
#ifdef USE_WINSOCK
|
||||
printf("read (in tcp ) %s\n",
|
||||
wsa_strerror(WSAGetLastError()));
|
||||
if (WSAGetLastError() == WSAECONNRESET)
|
||||
return STUB_TCP_AGAIN;
|
||||
if (WSAGetLastError() == WSAEINPROGRESS)
|
||||
return STUB_TCP_AGAIN;
|
||||
if (WSAGetLastError() == WSAEWOULDBLOCK) {
|
||||
winsock_tcp_wouldblock(event->ev, EV_READ);
|
||||
return STUB_TCP_AGAIN;
|
||||
}
|
||||
|
||||
#else
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
return STUB_TCP_AGAIN;
|
||||
if (_getdns_EWOULDBLOCK)
|
||||
return STUB_TCP_WOULDBLOCK;
|
||||
else
|
||||
return STUB_TCP_ERROR;
|
||||
#endif
|
||||
} else if (read == 0) {
|
||||
/* Remote end closed the socket */
|
||||
/* TODO: Try to reconnect */
|
||||
return STUB_TCP_ERROR;
|
||||
} else if (read> tcp->to_read) {
|
||||
return STUB_TCP_ERROR;
|
||||
}
|
||||
tcp->to_read -= read;
|
||||
tcp->read_pos += read;
|
||||
|
||||
if ((int)tcp->to_read > 0)
|
||||
if (tcp->to_read > 0)
|
||||
return STUB_TCP_AGAIN;
|
||||
|
||||
read = tcp->read_pos - tcp->read_buf;
|
||||
|
@ -721,7 +728,7 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
|
|||
if (! tcp->write_buf) {
|
||||
/* No, this is an initial write. Try to send
|
||||
*/
|
||||
do {
|
||||
do {
|
||||
query_id = arc4random();
|
||||
query_id_intptr = (intptr_t)query_id;
|
||||
netreq->node.key = (void *)query_id_intptr;
|
||||
|
@ -754,8 +761,8 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
|
|||
/* We have an initialized packet buffer.
|
||||
* Lets see how much of it we can write
|
||||
*/
|
||||
#ifdef USE_TCP_FASTOPEN
|
||||
/* We use sendto() here which will do both a connect and send */
|
||||
#ifdef USE_TCP_FASTOPEN
|
||||
written = sendto(fd, netreq->query - 2, pkt_len + 2,
|
||||
MSG_FASTOPEN, (struct sockaddr *)&(netreq->upstream->addr),
|
||||
netreq->upstream->addr_len);
|
||||
|
@ -763,29 +770,19 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
|
|||
just fall back to a 'normal' write. */
|
||||
if (written == -1 && errno == EISCONN)
|
||||
written = write(fd, netreq->query - 2, pkt_len + 2);
|
||||
|
||||
if ((written == -1 && (errno == EAGAIN ||
|
||||
errno == EWOULDBLOCK ||
|
||||
/* Add the error case where the connection is in progress which is when
|
||||
a cookie is not available (e.g. when doing the first request to an
|
||||
upstream). We must let the handshake complete since non-blocking. */
|
||||
errno == EINPROGRESS)) ||
|
||||
written < pkt_len + 2) {
|
||||
#else
|
||||
|
||||
#ifdef USE_WINSOCK
|
||||
written = sendto(fd, (const char *)(netreq->query - 2),
|
||||
pkt_len + 2, 0,
|
||||
(struct sockaddr *)&(netreq->upstream->addr),
|
||||
netreq->upstream->addr_len);
|
||||
|
||||
#else
|
||||
written = write(fd, netreq->query - 2, pkt_len + 2);
|
||||
#endif
|
||||
if ((written == -1 && (errno == EAGAIN ||
|
||||
errno == EWOULDBLOCK)) ||
|
||||
if ((written == -1 && (_getdns_EWOULDBLOCK ||
|
||||
/* Add the error case where the connection is in progress which is when
|
||||
a cookie is not available (e.g. when doing the first request to an
|
||||
upstream). We must let the handshake complete since non-blocking. */
|
||||
_getdns_EINPROGRESS)) ||
|
||||
written < pkt_len + 2) {
|
||||
#endif
|
||||
|
||||
/* We couldn't write the whole packet.
|
||||
* We have to return with STUB_TCP_AGAIN.
|
||||
* Setup tcp to track the state.
|
||||
|
@ -794,7 +791,7 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
|
|||
tcp->write_buf_len = pkt_len + 2;
|
||||
tcp->written = written >= 0 ? written : 0;
|
||||
|
||||
return STUB_TCP_AGAIN;
|
||||
return STUB_TCP_WOULDBLOCK;
|
||||
|
||||
} else if (written == -1)
|
||||
return STUB_TCP_ERROR;
|
||||
|
@ -809,8 +806,8 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
|
|||
written = write(fd, tcp->write_buf + tcp->written,
|
||||
tcp->write_buf_len - tcp->written);
|
||||
if (written == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
return STUB_TCP_AGAIN;
|
||||
if (_getdns_EWOULDBLOCK)
|
||||
return STUB_TCP_WOULDBLOCK;
|
||||
else
|
||||
return STUB_TCP_ERROR;
|
||||
}
|
||||
|
@ -1304,7 +1301,7 @@ stub_udp_read_cb(void *userarg)
|
|||
* i.e. overflow
|
||||
*/
|
||||
0, NULL, NULL);
|
||||
if (read == -1 && (errno = EAGAIN || errno == EWOULDBLOCK))
|
||||
if (read == -1 && _getdns_EWOULDBLOCK)
|
||||
return;
|
||||
|
||||
if (read < GLDNS_HEADER_SIZE)
|
||||
|
@ -1405,13 +1402,16 @@ upstream_read_cb(void *userarg)
|
|||
|
||||
if (tls_should_read(upstream))
|
||||
q = stub_tls_read(upstream, &upstream->tcp,
|
||||
&upstream->upstreams->mf);
|
||||
&upstream->upstreams->mf);
|
||||
else
|
||||
q = stub_tcp_read(upstream->fd, &upstream->tcp,
|
||||
&upstream->upstreams->mf, &upstream->event);
|
||||
&upstream->upstreams->mf);
|
||||
|
||||
switch (q) {
|
||||
case STUB_TCP_AGAIN:
|
||||
/* WSA TODO: if callback is still upstream_read_cb, do it again
|
||||
*/
|
||||
case STUB_TCP_WOULDBLOCK:
|
||||
return;
|
||||
|
||||
case STUB_TCP_ERROR:
|
||||
|
@ -1463,6 +1463,10 @@ upstream_read_cb(void *userarg)
|
|||
upstream_reschedule_netreq_events(upstream, netreq);
|
||||
|
||||
_getdns_check_dns_req_complete(netreq->owner);
|
||||
|
||||
/* WSA TODO: if callback is still upstream_read_cb, do it again
|
||||
*/
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1499,6 +1503,10 @@ upstream_write_cb(void *userarg)
|
|||
|
||||
switch (q) {
|
||||
case STUB_TCP_AGAIN:
|
||||
/* WSA TODO: if callback is still upstream_write_cb, do it again
|
||||
*/
|
||||
|
||||
case STUB_TCP_WOULDBLOCK:
|
||||
return;
|
||||
|
||||
case STUB_TCP_ERROR:
|
||||
|
@ -1553,6 +1561,8 @@ upstream_write_cb(void *userarg)
|
|||
netreq_upstream_write_cb : NULL),
|
||||
stub_timeout_cb));
|
||||
}
|
||||
/* WSA TODO: if callback is still upstream_write_cb, do it again
|
||||
*/
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
#include "gldns/wire2str.h"
|
||||
|
||||
typedef struct getdns_sync_loop {
|
||||
_getdns_mini_event loop;
|
||||
_getdns_default_eventloop loop;
|
||||
#ifdef HAVE_LIBUNBOUND
|
||||
getdns_eventloop_event ub_event;
|
||||
#endif
|
||||
|
@ -61,14 +61,12 @@ getdns_sync_loop_init(getdns_context *context, getdns_sync_loop *loop)
|
|||
#ifdef HAVE_LIBUNBOUND
|
||||
getdns_eventloop *ext = &loop->loop.loop;
|
||||
#endif
|
||||
getdns_return_t r;
|
||||
|
||||
loop->response = NULL;
|
||||
loop->to_run = 1;
|
||||
loop->context = context;
|
||||
|
||||
if ((r = _getdns_mini_event_init(context, &loop->loop)))
|
||||
return r;
|
||||
_getdns_default_eventloop_init(&loop->loop);
|
||||
|
||||
#ifdef HAVE_LIBUNBOUND
|
||||
loop->ub_event.userarg = loop->context;
|
||||
|
|
|
@ -232,21 +232,24 @@ depend:
|
|||
.PHONY: clean test
|
||||
|
||||
# Dependencies for the unit tests
|
||||
check_getdns.lo check_getdns.o: $(srcdir)/check_getdns.c ../getdns/getdns.h $(srcdir)/check_getdns_common.h \
|
||||
../getdns/getdns_extra.h $(srcdir)/check_getdns_general.h \
|
||||
$(srcdir)/check_getdns_general_sync.h $(srcdir)/check_getdns_address.h \
|
||||
$(srcdir)/check_getdns_address_sync.h $(srcdir)/check_getdns_hostname.h \
|
||||
$(srcdir)/check_getdns_hostname_sync.h $(srcdir)/check_getdns_context_create.h \
|
||||
$(srcdir)/check_getdns_context_destroy.h $(srcdir)/check_getdns_cancel_callback.h \
|
||||
$(srcdir)/check_getdns_list_get_length.h $(srcdir)/check_getdns_list_get_data_type.h \
|
||||
$(srcdir)/check_getdns_list_get_dict.h $(srcdir)/check_getdns_list_get_list.h \
|
||||
$(srcdir)/check_getdns_list_get_int.h $(srcdir)/check_getdns_list_get_bindata.h \
|
||||
$(srcdir)/check_getdns_dict_get_names.h $(srcdir)/check_getdns_dict_get_data_type.h \
|
||||
$(srcdir)/check_getdns_dict_get_dict.h $(srcdir)/check_getdns_dict_get_list.h \
|
||||
$(srcdir)/check_getdns_dict_get_bindata.h $(srcdir)/check_getdns_dict_get_int.h \
|
||||
$(srcdir)/check_getdns_dict_destroy.h $(srcdir)/check_getdns_dict_set_dict.h \
|
||||
$(srcdir)/check_getdns_dict_set_list.h $(srcdir)/check_getdns_dict_set_bindata.h \
|
||||
$(srcdir)/check_getdns_dict_set_int.h $(srcdir)/check_getdns_convert_ulabel_to_alabel.h \
|
||||
check_getdns.lo check_getdns.o: $(srcdir)/check_getdns.c \
|
||||
../getdns/getdns.h \
|
||||
$(srcdir)/check_getdns_common.h \
|
||||
../getdns/getdns_extra.h \
|
||||
$(srcdir)/check_getdns_general.h $(srcdir)/check_getdns_general_sync.h \
|
||||
$(srcdir)/check_getdns_address.h $(srcdir)/check_getdns_address_sync.h \
|
||||
$(srcdir)/check_getdns_hostname.h $(srcdir)/check_getdns_hostname_sync.h \
|
||||
$(srcdir)/check_getdns_context_create.h $(srcdir)/check_getdns_context_destroy.h \
|
||||
$(srcdir)/check_getdns_cancel_callback.h $(srcdir)/check_getdns_list_get_length.h \
|
||||
$(srcdir)/check_getdns_list_get_data_type.h $(srcdir)/check_getdns_list_get_dict.h \
|
||||
$(srcdir)/check_getdns_list_get_list.h $(srcdir)/check_getdns_list_get_int.h \
|
||||
$(srcdir)/check_getdns_list_get_bindata.h $(srcdir)/check_getdns_dict_get_names.h \
|
||||
$(srcdir)/check_getdns_dict_get_data_type.h $(srcdir)/check_getdns_dict_get_dict.h \
|
||||
$(srcdir)/check_getdns_dict_get_list.h $(srcdir)/check_getdns_dict_get_bindata.h \
|
||||
$(srcdir)/check_getdns_dict_get_int.h $(srcdir)/check_getdns_dict_destroy.h \
|
||||
$(srcdir)/check_getdns_dict_set_dict.h $(srcdir)/check_getdns_dict_set_list.h \
|
||||
$(srcdir)/check_getdns_dict_set_bindata.h $(srcdir)/check_getdns_dict_set_int.h \
|
||||
$(srcdir)/check_getdns_convert_ulabel_to_alabel.h \
|
||||
$(srcdir)/check_getdns_convert_alabel_to_ulabel.h $(srcdir)/check_getdns_pretty_print_dict.h \
|
||||
$(srcdir)/check_getdns_display_ip_address.h \
|
||||
$(srcdir)/check_getdns_context_set_context_update_callback.h \
|
||||
|
@ -254,36 +257,59 @@ check_getdns.lo check_getdns.o: $(srcdir)/check_getdns.c ../getdns/getdns.h $(sr
|
|||
$(srcdir)/check_getdns_context_set_upstream_recursive_servers.h \
|
||||
$(srcdir)/check_getdns_service.h $(srcdir)/check_getdns_service_sync.h \
|
||||
$(srcdir)/check_getdns_transport.h
|
||||
check_getdns_common.lo check_getdns_common.o: $(srcdir)/check_getdns_common.c ../getdns/getdns.h \
|
||||
../config.h $(srcdir)/check_getdns_common.h ../getdns/getdns_extra.h \
|
||||
check_getdns_common.lo check_getdns_common.o: $(srcdir)/check_getdns_common.c \
|
||||
../getdns/getdns.h \
|
||||
../config.h $(srcdir)/check_getdns_common.h \
|
||||
../getdns/getdns_extra.h \
|
||||
$(srcdir)/check_getdns_eventloop.h
|
||||
check_getdns_context_set_timeout.lo check_getdns_context_set_timeout.o: $(srcdir)/check_getdns_context_set_timeout.c \
|
||||
$(srcdir)/check_getdns_context_set_timeout.h $(srcdir)/check_getdns_common.h \
|
||||
../getdns/getdns.h ../getdns/getdns_extra.h
|
||||
../getdns/getdns.h \
|
||||
../getdns/getdns_extra.h
|
||||
check_getdns_libev.lo check_getdns_libev.o: $(srcdir)/check_getdns_libev.c $(srcdir)/check_getdns_eventloop.h \
|
||||
../config.h ../getdns/getdns.h $(srcdir)/../getdns/getdns_ext_libev.h \
|
||||
../getdns/getdns_extra.h $(srcdir)/check_getdns_common.h
|
||||
../config.h \
|
||||
../getdns/getdns.h \
|
||||
$(srcdir)/../getdns/getdns_ext_libev.h \
|
||||
../getdns/getdns_extra.h \
|
||||
$(srcdir)/check_getdns_common.h
|
||||
check_getdns_libevent.lo check_getdns_libevent.o: $(srcdir)/check_getdns_libevent.c $(srcdir)/check_getdns_eventloop.h \
|
||||
../config.h ../getdns/getdns.h $(srcdir)/../getdns/getdns_ext_libevent.h \
|
||||
../getdns/getdns_extra.h $(srcdir)/check_getdns_libevent.h $(srcdir)/check_getdns_common.h
|
||||
../config.h \
|
||||
../getdns/getdns.h \
|
||||
$(srcdir)/../getdns/getdns_ext_libevent.h \
|
||||
../getdns/getdns_extra.h \
|
||||
$(srcdir)/check_getdns_libevent.h $(srcdir)/check_getdns_common.h
|
||||
check_getdns_libuv.lo check_getdns_libuv.o: $(srcdir)/check_getdns_libuv.c $(srcdir)/check_getdns_eventloop.h \
|
||||
../config.h ../getdns/getdns.h $(srcdir)/../getdns/getdns_ext_libuv.h \
|
||||
../getdns/getdns_extra.h $(srcdir)/check_getdns_common.h
|
||||
../config.h \
|
||||
../getdns/getdns.h \
|
||||
$(srcdir)/../getdns/getdns_ext_libuv.h \
|
||||
../getdns/getdns_extra.h \
|
||||
$(srcdir)/check_getdns_common.h
|
||||
check_getdns_selectloop.lo check_getdns_selectloop.o: $(srcdir)/check_getdns_selectloop.c \
|
||||
$(srcdir)/check_getdns_eventloop.h ../config.h ../getdns/getdns.h \
|
||||
$(srcdir)/check_getdns_eventloop.h ../config.h \
|
||||
../getdns/getdns.h \
|
||||
../getdns/getdns_extra.h
|
||||
check_getdns_transport.lo check_getdns_transport.o: $(srcdir)/check_getdns_transport.c \
|
||||
$(srcdir)/check_getdns_transport.h $(srcdir)/check_getdns_common.h ../getdns/getdns.h \
|
||||
$(srcdir)/check_getdns_transport.h $(srcdir)/check_getdns_common.h \
|
||||
../getdns/getdns.h \
|
||||
../getdns/getdns_extra.h
|
||||
getdns_query.lo getdns_query.o: $(srcdir)/getdns_query.c ../config.h $(srcdir)/../debug.h ../config.h \
|
||||
../getdns/getdns.h ../getdns/getdns_extra.h
|
||||
scratchpad.template.lo scratchpad.template.o: scratchpad.template.c ../getdns/getdns.h \
|
||||
getdns_query.lo getdns_query.o: $(srcdir)/getdns_query.c \
|
||||
../config.h $(srcdir)/../debug.h \
|
||||
../getdns/getdns.h \
|
||||
../getdns/getdns_extra.h
|
||||
scratchpad.template.lo scratchpad.template.o: scratchpad.template.c \
|
||||
../getdns/getdns.h \
|
||||
../getdns/getdns_extra.h
|
||||
testmessages.lo testmessages.o: $(srcdir)/testmessages.c $(srcdir)/testmessages.h
|
||||
tests_dict.lo tests_dict.o: $(srcdir)/tests_dict.c $(srcdir)/testmessages.h ../getdns/getdns.h
|
||||
tests_list.lo tests_list.o: $(srcdir)/tests_list.c $(srcdir)/testmessages.h ../getdns/getdns.h
|
||||
tests_namespaces.lo tests_namespaces.o: $(srcdir)/tests_namespaces.c $(srcdir)/testmessages.h ../getdns/getdns.h
|
||||
tests_stub_async.lo tests_stub_async.o: $(srcdir)/tests_stub_async.c ../config.h $(srcdir)/testmessages.h \
|
||||
../getdns/getdns.h ../getdns/getdns_extra.h
|
||||
tests_stub_sync.lo tests_stub_sync.o: $(srcdir)/tests_stub_sync.c $(srcdir)/testmessages.h ../getdns/getdns.h \
|
||||
tests_dict.lo tests_dict.o: $(srcdir)/tests_dict.c $(srcdir)/testmessages.h \
|
||||
../getdns/getdns.h
|
||||
tests_list.lo tests_list.o: $(srcdir)/tests_list.c $(srcdir)/testmessages.h \
|
||||
../getdns/getdns.h
|
||||
tests_namespaces.lo tests_namespaces.o: $(srcdir)/tests_namespaces.c $(srcdir)/testmessages.h \
|
||||
../getdns/getdns.h
|
||||
tests_stub_async.lo tests_stub_async.o: $(srcdir)/tests_stub_async.c \
|
||||
../config.h $(srcdir)/testmessages.h \
|
||||
../getdns/getdns.h \
|
||||
../getdns/getdns_extra.h
|
||||
tests_stub_sync.lo tests_stub_sync.o: $(srcdir)/tests_stub_sync.c $(srcdir)/testmessages.h \
|
||||
../getdns/getdns.h \
|
||||
../getdns/getdns_extra.h
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
mkdir ub || true
|
||||
cd ub
|
||||
for f in mini_event.c mini_event.h rbtree.c rbtree.h
|
||||
for f in rbtree.c rbtree.h
|
||||
do
|
||||
wget http://unbound.net/svn/trunk/util/$f || \
|
||||
ftp http://unbound.net/svn/trunk/util/$f || continue
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
Loading…
Reference in New Issue