Merge pull request #144 from wtoorop/devel/default_eventloop

Devel/default eventloop
This commit is contained in:
Melinda Shore 2016-03-14 20:02:57 -08:00
commit 4b5c61145a
32 changed files with 1368 additions and 2395 deletions

View File

@ -201,6 +201,11 @@ case "$enable_native_stub_dnssec" in
;;
esac
# search to set include and library paths right
# find libidn (no libidn on windows though)
AC_CHECK_HEADERS([windows.h winsock.h stdio.h winsock2.h ws2tcpip.h],,, [AC_INCLUDES_DEFAULT])
ACX_CHECK_GETADDRINFO_WITH_INCLUDES
USE_NSS="no"
# openssl
if test $USE_NSS = "no"; then
@ -444,28 +449,19 @@ case "$enable_stub_only" in
;;
esac
# search to set include and library paths right
# find libidn (no libidn on windows though)
AC_CHECK_HEADERS([windows.h winsock.h stdio.h winsock2.h ws2tcpip.h],,, [AC_INCLUDES_DEFAULT])
ACX_CHECK_GETADDRINFO_WITH_INCLUDES
if test "$USE_WINSOCK" = 1; then
AC_MSG_NOTICE([ Building on Windows ... YES! ])
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],
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
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"
@ -485,14 +481,13 @@ then
#LDFLAGS="$LDFLAGS -L/usr/lib"
AC_MSG_NOTICE([Found libidn in /usr])
fi
else
else
if test x_$withval != x_no; then
CFLAGS="$CFLAGS -I$withval/include"
LDFLAGS="$LDFLAGS -L$withval/lib"
else
my_with_libidn=0
fi
fi
fi
if test $my_with_libunbound = 1
@ -531,8 +526,15 @@ fi
if test $my_with_libunbound = 1
then
AC_CHECK_HEADERS([unbound-event.h],,, [AC_INCLUDES_DEFAULT])
AC_MSG_NOTICE([Checking for dependency libunbound])
AC_CHECK_LIB([unbound], [ub_fd], [], [found_all_libs=0])
AC_CHECK_LIB([unbound], [ub_fd], [
AC_DEFINE_UNQUOTED([HAVE_LIBUNBOUND], [1], [Define to 1 if you have the `unbound' library (-lunbound).])
LIBS="-lunbound $LIBS"
AC_CHECK_FUNC([ub_ctx_create_ub_event], [
AC_DEFINE_UNQUOTED([HAVE_UNBOUND_EVENT_API], [1], [Define this when libunbound is compiled with the --enable-event-api option.])
])
], [found_all_libs=0])
fi
if test $found_all_libs = 0
@ -1019,14 +1021,37 @@ AC_SUBST(C99COMPATFLAGS)
AH_BOTTOM([
#ifdef GETDNS_ON_WINDOWS
/* On windows it is allowed to increase the FD_SETSIZE
* (and nescessary to make our custom eventloop work)
* See: https://support.microsoft.com/en-us/kb/111855
*/
#define FD_SETSIZE 1024
#define PRIsz "%Iu"
#else
#define PRIsz "%zu"
#endif
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#ifdef HAVE_BSD_STRING_H
#include <bsd/string.h>
#endif
/* the version of the windows API enabled */
#undef WINVER
#undef _WIN32_WINNT
#ifndef WINVER
#define WINVER 0x0600 // 0x0502
#endif
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0600 // 0x0502
#endif
#ifdef HAVE_WINSOCK2_H
#include <winsock2.h>
#include<BaseTsd.h>
#endif
#ifdef HAVE_WS2TCPIP_H
@ -1047,15 +1072,6 @@ AH_BOTTOM([
#endif
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#ifdef HAVE_BSD_STRING_H
#include <bsd/string.h>
#endif
#ifdef __cplusplus
extern "C" {
@ -1147,6 +1163,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)))
@ -1176,7 +1200,16 @@ const char *inet_ntop(int af, const void *src, char *dst, size_t size);
#endif
#ifdef HAVE_LIBUNBOUND
#include <unbound.h>
# include <unbound.h>
# ifdef HAVE_UNBOUND_EVENT_H
# include <unbound-event.h>
# else
struct ub_event_base;
struct ub_ctx* ub_ctx_create_ub_event(struct ub_event_base* base);
typedef void (*ub_event_callback_t)(void*, int, void*, int, int, char*);
int ub_resolve_event(struct ub_ctx* ctx, const char* name, int rrtype,
int rrclass, void* mydata, ub_event_callback_t callback, int* async_id);
# endif
#endif
])

View File

@ -48,8 +48,8 @@ AC_DEFUN([ACX_SSL_CHECKS], [
fi
AC_MSG_CHECKING([for HMAC_CTX_init in -lcrypto])
LIBS="$LIBS -lssl -lcrypto"
LIBSSL_LIBS="$LIBSSL_LIBS -lssl -lcrypto"
LIBS="-lssl -lcrypto $LIBS"
LIBSSL_LIBS="-lssl -lcrypto $LIBSSL_LIBS"
AC_TRY_LINK(, [
int HMAC_CTX_init(void);
(void)HMAC_CTX_init();
@ -101,11 +101,11 @@ AC_CHECK_HEADERS([openssl/err.h],,, [AC_INCLUDES_DEFAULT])
AC_CHECK_HEADERS([openssl/rand.h],,, [AC_INCLUDES_DEFAULT])
dnl TLS v1.2 requires OpenSSL 1.0.1
AC_CHECK_LIB(ssl, TLSv1_2_client_method,AC_DEFINE([HAVE_TLS_v1_2], [1],
AC_CHECK_FUNC(TLSv1_2_client_method,AC_DEFINE([HAVE_TLS_v1_2], [1],
[Define if you have libssl with tls 1.2]),[AC_MSG_WARN([Cannot find TLSv1_2_client_method in libssl library. TLS will not be available.])])
dnl Native OpenSSL hostname verification requires OpenSSL 1.0.2
AC_CHECK_LIB(ssl, SSL_CTX_get0_param,AC_DEFINE([HAVE_SSL_HN_AUTH], [1],
AC_CHECK_FUNC(SSL_CTX_get0_param,AC_DEFINE([HAVE_SSL_HN_AUTH], [1],
[Define if you have libssl with host name verification]),[AC_MSG_WARN([Cannot find SSL_CTX_get0_param in libssl library. TLS hostname verification will not be available.])])
])

View File

@ -65,7 +65,7 @@ C99COMPATFLAGS=@C99COMPATFLAGS@
GETDNS_OBJ=const-info.lo convert.lo dict.lo dnssec.lo general.lo \
list.lo request-internal.lo pubkey-pinning.lo rr-dict.lo \
rr-iter.lo stub.lo sync.lo util-internal.lo
rr-iter.lo stub.lo sync.lo ub_loop.lo util-internal.lo
GLDNS_OBJ=keyraw.lo gbuffer.lo wire2str.lo parse.lo parseutil.lo rrdef.lo \
str2wire.lo
@ -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
@ -229,70 +229,66 @@ const-info.lo const-info.o: $(srcdir)/const-info.c getdns/getdns.h getdns/getdns
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 \
getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \
$(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h $(srcdir)/ub_loop.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
$(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h $(srcdir)/ub_loop.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
$(srcdir)/context.h $(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h \
$(srcdir)/ub_loop.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
$(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h $(srcdir)/ub_loop.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 getdns/getdns.h $(srcdir)/util/rbtree.h $(srcdir)/gldns/wire2str.h \
$(srcdir)/context.h $(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h \
$(srcdir)/ub_loop.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 \
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
$(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h $(srcdir)/ub_loop.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
$(srcdir)/util/rbtree.h $(srcdir)/extension/default_eventloop.h config.h \
getdns/getdns_extra.h $(srcdir)/ub_loop.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 \
$(srcdir)/gldns/rrdef.h $(srcdir)/dict.h $(srcdir)/debug.h
$(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h config.h \
getdns/getdns_extra.h $(srcdir)/ub_loop.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
$(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/extension/default_eventloop.h config.h \
getdns/getdns_extra.h $(srcdir)/ub_loop.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)/gldns/wire2str.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/context.h \
$(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h $(srcdir)/ub_loop.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
sync.lo sync.o: $(srcdir)/sync.c config.h getdns/getdns.h getdns/getdns_extra.h \
getdns/getdns.h
ub_loop.lo ub_loop.o: $(srcdir)/ub_loop.c $(srcdir)/ub_loop.h config.h getdns/getdns.h \
getdns/getdns_extra.h getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.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
$(srcdir)/list.h $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h config.h \
getdns/getdns_extra.h $(srcdir)/ub_loop.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
@ -317,22 +313,19 @@ 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
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 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

View File

@ -26,7 +26,9 @@
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@ -35,40 +37,6 @@
#include <sys/time.h>
#ifndef GETDNS_ON_WINDOWS
#include <sys/mman.h>
#else
#include <wincrypt.h>
#include <process.h>
int getentropy(void *buf, size_t len);
/*
* On Windows, CryptGenRandom is supposed to be a well-seeded
* cryptographically strong random number generator.
*/
int
getentropy(void *buf, size_t len)
{
HCRYPTPROV provider;
if (len > 256) {
errno = EIO;
return -1;
}
if (CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT) == 0)
goto fail;
if (CryptGenRandom(provider, len, buf) == 0) {
CryptReleaseContext(provider, 0);
goto fail;
}
CryptReleaseContext(provider, 0);
return (0);
fail:
errno = EIO;
return (-1);
}
#endif
#define KEYSTREAM_ONLY

View File

@ -16,10 +16,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "config.h"
#ifndef GETDNS_ON_WINDOWS
/*
#define _POSIX_C_SOURCE 199309L
@ -49,7 +46,12 @@
#include <errno.h>
#include <unistd.h>
#include <time.h>
#if defined(HAVE_SSL)
#include <openssl/sha.h>
#elif defined(HAVE_NETTLE)
#include <nettle/sha.h>
#endif
#include <linux/types.h>
#include <linux/random.h>
@ -70,9 +72,21 @@
HD(b); \
} while (0)
#if defined(HAVE_SSL)
#define CRYPTO_SHA512_CTX SHA512_CTX
#define CRYPTO_SHA512_INIT(x) SHA512_Init(x)
#define CRYPTO_SHA512_FINAL(r, c) SHA512_Final(r, c)
#define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l)))
#define HD(x) (SHA512_Update(&ctx, (char *)&(x), sizeof (x)))
#define HF(x) (SHA512_Update(&ctx, (char *)&(x), sizeof (void*)))
#elif defined(HAVE_NETTLE)
#define CRYPTO_SHA512_CTX struct sha512_ctx
#define CRYPTO_SHA512_INIT(x) sha512_init(x)
#define CRYPTO_SHA512_FINAL(r, c) sha512_digest(c, SHA512_DIGEST_SIZE, r)
#define HR(x, l) (sha512_update(&ctx, (l), (uint8_t *)(x)))
#define HD(x) (sha512_update(&ctx, sizeof (x), (uint8_t *)&(x)))
#define HF(x) (sha512_update(&ctx, sizeof (void*), (uint8_t *)&(x)))
#endif
int getentropy(void *buf, size_t len);
@ -125,7 +139,7 @@ getentropy(void *buf, size_t len)
* Try to use sysctl CTL_KERN, KERN_RANDOM, RANDOM_UUID.
* sysctl is a failsafe API, so it guarantees a result. This
* should work inside a chroot, or when file descriptors are
* exhuasted.
* exhausted.
*
* However this can fail if the Linux kernel removes support
* for sysctl. Starting in 2007, there have been efforts to
@ -340,7 +354,7 @@ getentropy_fallback(void *buf, size_t len)
struct rusage ru;
sigset_t sigset;
struct stat st;
SHA512_CTX ctx;
CRYPTO_SHA512_CTX ctx;
static pid_t lastpid;
pid_t pid;
size_t i, ii, m;
@ -357,7 +371,7 @@ getentropy_fallback(void *buf, size_t len)
}
for (i = 0; i < len; ) {
int j;
SHA512_Init(&ctx);
CRYPTO_SHA512_INIT(&ctx);
for (j = 0; j < repeat; j++) {
HX((e = gettimeofday(&tv, NULL)) == -1, tv);
if (e != -1) {
@ -529,7 +543,7 @@ getentropy_fallback(void *buf, size_t len)
# endif
#endif /* HAVE_GETAUXVAL */
SHA512_Final(results, &ctx);
CRYPTO_SHA512_FINAL(results, &ctx);
memcpy((char*)buf + i, results, min(sizeof(results), len - i));
i += min(sizeof(results), len - i);
}
@ -541,4 +555,3 @@ getentropy_fallback(void *buf, size_t len)
errno = EIO;
return -1;
}
#endif

View File

@ -30,7 +30,9 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <stdlib.h>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#include <stdio.h>
#include <termios.h>
#include <fcntl.h>
@ -39,10 +41,14 @@
#include <errno.h>
#include <unistd.h>
#include <time.h>
#ifdef HAVE_SYS_SHA2_H
#include <sys/sha2.h>
#define SHA512_Init SHA512Init
#define SHA512_Update SHA512Update
#define SHA512_Final SHA512Final
#else
#include "openssl/sha.h"
#endif
#include <sys/vfs.h>
#include <sys/statfs.h>

View File

@ -70,7 +70,7 @@ unsigned char *SHA512(void *data, unsigned int data_len, unsigned char *digest);
* Please make sure that your system defines BYTE_ORDER. If your
* architecture is little-endian, make sure it also defines
* LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are
* equivilent.
* equivalent.
*
* If your system does not define the above, then you can do so by
* hand like this:

View File

@ -63,6 +63,9 @@ typedef unsigned short in_port_t;
#include <ctype.h>
#include "config.h"
#ifdef HAVE_LIBUNBOUND
#include <unbound.h>
#endif
#include "debug.h"
#include "gldns/str2wire.h"
#include "gldns/wire2str.h"
@ -1056,6 +1059,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;
@ -1069,6 +1075,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;
@ -1103,7 +1117,7 @@ getdns_context_create_with_extended_memory_functions(
result->follow_redirects = GETDNS_REDIRECTS_FOLLOW;
result->dns_root_servers = NULL;
result->root_servers_fn[0] = 0;
result->append_name = GETDNS_APPEND_NAME_ALWAYS;
result->append_name = GETDNS_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE;
result->suffixes = no_suffixes;
result->suffixes_len = sizeof(no_suffixes);
@ -1140,9 +1154,9 @@ 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);
_getdns_default_eventloop_init(&result->sync_eventloop);
result->fchg_resolvconf = NULL;
result->fchg_hosts = NULL;
@ -1247,13 +1261,13 @@ getdns_context_destroy(struct getdns_context *context)
*/
_getdns_upstreams_dereference(context->upstreams);
context->sync_eventloop.loop.vmt->cleanup(&context->sync_eventloop.loop);
context->extension->vmt->cleanup(context->extension);
#ifdef HAVE_LIBUNBOUND
if (context->unbound_ctx)
ub_ctx_delete(context->unbound_ctx);
#endif
context->extension->vmt->cleanup(context->extension);
if (context->namespaces)
GETDNS_FREE(context->my_mf, context->namespaces);
@ -1288,6 +1302,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 */
@ -1357,17 +1374,27 @@ getdns_context_request_count_changed(getdns_context *context)
DEBUG_SCHED("gc_request_count_changed "
"-> ub schedule(el_ev = %p, el_ev->ev = %p)\n",
&context->ub_event, context->ub_event.ev);
#ifndef USE_WINSOCK
#ifdef HAVE_UNBOUND_EVENT_API
if (!_getdns_ub_loop_enabled(&context->ub_loop))
#endif
context->extension->vmt->schedule(
context->extension, ub_fd(context->unbound_ctx),
TIMEOUT_FOREVER, &context->ub_event);
#endif
}
else if (context->ub_event.ev) /* Only test if count == 0! */ {
DEBUG_SCHED("gc_request_count_changed "
"-> ub clear(el_ev = %p, el_ev->ev = %p)\n",
&context->ub_event, context->ub_event.ev);
#ifndef USE_WINSOCK
#ifdef HAVE_UNBOUND_EVENT_API
if (!_getdns_ub_loop_enabled(&context->ub_loop))
#endif
context->extension->vmt->clear(
context->extension, &context->ub_event);
#endif
}
}
@ -1397,12 +1424,23 @@ rebuild_ub_ctx(struct getdns_context* context) {
context->unbound_ctx = NULL;
}
/* setup */
#ifdef HAVE_UNBOUND_EVENT_API
_getdns_ub_loop_init(&context->ub_loop, &context->mf, context->extension);
if (_getdns_ub_loop_enabled(&context->ub_loop)) {
context->unbound_ctx = ub_ctx_create_ub_event(&context->ub_loop.super);
} else {
#endif
context->unbound_ctx = ub_ctx_create();
(void) ub_ctx_async(context->unbound_ctx, 1);
context->unbound_ta_set = 0;
if (!context->unbound_ctx) {
return GETDNS_RETURN_MEMORY_ERROR;
#ifdef HAVE_UNBOUND_EVENT_API
}
#endif
context->unbound_ta_set = 0;
if (!context->unbound_ctx)
return GETDNS_RETURN_MEMORY_ERROR;
ub_ctx_set_option(context->unbound_ctx,
"target-fetch-policy:", "0 0 0 0 0");
set_ub_dnssec_allowed_skew(context,
context->dnssec_allowed_skew);
set_ub_edns_maximum_udp_payload_size(context,
@ -1851,15 +1889,15 @@ getdns_context_set_dns_root_servers(
else if (addr_bd->size == 16 &&
inet_ntop(AF_INET6, addr_bd->data, dst, sizeof(dst)))
fprintf(fh, ". NS %zu.root-servers.getdnsapi.net.\n"
"%zu.root-servers.getdnsapi.net. AAAA %s\n",
fprintf(fh,". NS "PRIsz".root-servers.getdnsapi.net.\n"
PRIsz".root-servers.getdnsapi.net. AAAA %s\n",
i, i, dst);
else if (addr_bd->size == 4 &&
inet_ntop(AF_INET, addr_bd->data, dst, sizeof(dst)))
fprintf(fh, ". NS %zu.root-servers.getdnsapi.net.\n"
"%zu.root-servers.getdnsapi.net. A %s\n",
fprintf(fh,". NS "PRIsz".root-servers.getdnsapi.net.\n"
PRIsz".root-servers.getdnsapi.net. A %s\n",
i, i, dst);
}
fclose(fh);
@ -2894,54 +2932,35 @@ _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);
}
@ -2987,8 +3006,13 @@ 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);
#ifdef HAVE_UNBOUND_EVENT_API
if (_getdns_ub_loop_enabled(&context->ub_loop))
context->ub_loop.extension = context->extension;
#endif
return GETDNS_RETURN_GOOD;
}
getdns_return_t
@ -3002,6 +3026,10 @@ getdns_context_set_eventloop(getdns_context* context, getdns_eventloop* loop)
context->extension->vmt->cleanup(context->extension);
}
context->extension = loop;
#ifdef HAVE_UNBOUND_EVENT_API
if (_getdns_ub_loop_enabled(&context->ub_loop))
context->ub_loop.extension = loop;
#endif
return GETDNS_RETURN_GOOD;
}

View File

@ -41,8 +41,9 @@
#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"
#include "ub_loop.h"
struct getdns_dns_req;
struct ub_ctx;
@ -220,8 +221,10 @@ struct getdns_context {
/* The underlying contexts that do the real work */
struct ub_ctx *unbound_ctx;
int unbound_ta_set;
#ifdef HAVE_UNBOUND_EVENT_API
_getdns_ub_loop ub_loop;
#endif
#endif
/* A tree to hold local host information*/
_getdns_rbtree_t local_hosts;
@ -245,7 +248,8 @@ struct getdns_context {
#endif
/* The default extension */
_getdns_mini_event mini_event;
_getdns_default_eventloop default_eventloop;
_getdns_default_eventloop sync_eventloop;
/*
* state data used to detect changes to the system config files
@ -255,6 +259,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 **/

View File

@ -44,7 +44,7 @@
\
gettimeofday(&tv, NULL); \
gmtime_r(&tv.tv_sec, &tm); \
strftime(buf, 10, "%T", &tm); \
strftime(buf, 10, "%H:%M:%S", &tm); \
fprintf(stderr, "[%s.%.6d] ", buf, (int)tv.tv_usec); \
fprintf(stderr, __VA_ARGS__); \
} while (0)
@ -56,7 +56,7 @@
\
gettimeofday(&tv, NULL); \
gmtime_r(&tv.tv_sec, &tm); \
strftime(buf, 10, "%T", &tm); \
strftime(buf, 10, "%H:%M:%S", &tm); \
fprintf(stderr, "[%s.%.6d] ", buf, (int)tv.tv_usec); \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, "\n"); \

View File

@ -750,6 +750,8 @@ struct chain_head {
struct chain_node {
chain_node *parent;
size_t lock;
getdns_rrset dnskey;
getdns_network_req *dnskey_req;
int dnskey_signer;
@ -839,7 +841,7 @@ static chain_head *add_rrset2val_chain(struct mem_funcs *mf,
dname_len = *labels - last_label[-1] + 1;
head_sz = (sizeof(chain_head) + dname_len + 7) / 8 * 8;
node_count = last_label - labels - max_labels;
DEBUG_SEC( "%zu labels in common. %zu labels to allocate\n"
DEBUG_SEC( PRIsz" labels in common. "PRIsz" labels to allocate\n"
, max_labels, node_count);
if (! (region = GETDNS_XMALLOC(*mf, uint8_t, head_sz +
@ -878,6 +880,7 @@ static chain_head *add_rrset2val_chain(struct mem_funcs *mf,
; node_count
; node_count--, node = node->parent =&node[1], dname += *dname + 1) {
node->lock = 0;
node->ds.name = dname;
node->dnskey.name = dname;
node->ds.rr_class = head->rrset.rr_class;
@ -1135,7 +1138,6 @@ static void val_chain_sched_soa_node(chain_node *node)
{
getdns_context *context;
getdns_eventloop *loop;
getdns_dns_req *dnsreq;
char name[1024];
context = node->chains->netreq->owner->context;
@ -1147,12 +1149,15 @@ static void val_chain_sched_soa_node(chain_node *node)
DEBUG_SEC("schedule SOA lookup for %s\n", name);
node->lock++;
if (! node->soa_req &&
! _getdns_general_loop(context, loop, name, GETDNS_RRTYPE_SOA,
CD_extension(node->chains->netreq->owner), node, &dnsreq, NULL,
val_chain_node_soa_cb))
_getdns_general_loop(context, loop, name, GETDNS_RRTYPE_SOA,
CD_extension(node->chains->netreq->owner), node, &node->soa_req,
NULL, val_chain_node_soa_cb))
node->soa_req = dnsreq->netreqs[0];
node->soa_req = NULL;
node->lock--;
}
/* A SOA lookup is scheduled as a last resort. No signatures were found and
@ -1183,7 +1188,6 @@ static void val_chain_sched_node(chain_node *node)
{
getdns_context *context;
getdns_eventloop *loop;
getdns_dns_req *dnsreq;
char name[1024];
context = node->chains->netreq->owner->context;
@ -1195,19 +1199,22 @@ static void val_chain_sched_node(chain_node *node)
DEBUG_SEC("schedule DS & DNSKEY lookup for %s\n", name);
node->lock++;
if (! node->dnskey_req /* not scheduled */ &&
! _getdns_general_loop(context, loop, name, GETDNS_RRTYPE_DNSKEY,
_getdns_general_loop(context, loop, name, GETDNS_RRTYPE_DNSKEY,
CD_extension(node->chains->netreq->owner),
node, &dnsreq, NULL, val_chain_node_cb))
node, &node->dnskey_req, NULL, val_chain_node_cb))
node->dnskey_req = dnsreq->netreqs[0];
node->dnskey_req = NULL;
if (! node->ds_req && node->parent /* not root */ &&
! _getdns_general_loop(context, loop, name, GETDNS_RRTYPE_DS,
_getdns_general_loop(context, loop, name, GETDNS_RRTYPE_DS,
CD_extension(node->chains->netreq->owner),
node, &dnsreq, NULL, val_chain_node_cb))
node, &node->ds_req, NULL, val_chain_node_cb))
node->ds_req = dnsreq->netreqs[0];
node->ds_req = NULL;
node->lock--;
}
static void val_chain_sched(chain_head *head, const uint8_t *dname)
@ -1228,7 +1235,6 @@ static void val_chain_sched_ds_node(chain_node *node)
{
getdns_context *context;
getdns_eventloop *loop;
getdns_dns_req *ds_req;
char name[1024];
context = node->chains->netreq->owner->context;
@ -1241,12 +1247,15 @@ static void val_chain_sched_ds_node(chain_node *node)
DEBUG_SEC("schedule DS lookup for %s\n", name);
node->lock++;
if (! node->ds_req && node->parent /* not root */ &&
! _getdns_general_loop(context, loop, name, GETDNS_RRTYPE_DS,
_getdns_general_loop(context, loop, name, GETDNS_RRTYPE_DS,
CD_extension(node->chains->netreq->owner),
node, &ds_req, NULL, val_chain_node_cb))
node, &node->ds_req, NULL, val_chain_node_cb))
node->ds_req = ds_req->netreqs[0];
node->ds_req = NULL;
node->lock--;
}
static void val_chain_sched_ds(chain_head *head, const uint8_t *dname)
@ -1627,7 +1636,7 @@ static int _getdns_verify_rrsig(struct mem_funcs *mf,
/* More space needed for val_rrset */
val_rrset = GETDNS_XMALLOC(*mf, _getdns_rr_iter, n_rrs);
}
DEBUG_SEC( "sizes: %zu rrs, %zu bytes for validation buffer\n"
DEBUG_SEC( "sizes: "PRIsz" rrs, "PRIsz" bytes for validation buffer\n"
, n_rrs, valbuf_sz);
qsort(val_rrset, n_rrs, sizeof(_getdns_rr_iter), _rr_iter_rdata_cmp);
@ -1686,7 +1695,7 @@ static int _getdns_verify_rrsig(struct mem_funcs *mf,
gldns_buffer_write_u16_at(&valbuf, pos,
(uint16_t)(gldns_buffer_position(&valbuf) - pos - 2));
}
DEBUG_SEC( "written to valbuf: %zu bytes\n"
DEBUG_SEC( "written to valbuf: "PRIsz" bytes\n"
, gldns_buffer_position(&valbuf));
assert(gldns_buffer_position(&valbuf) <= valbuf_sz);
@ -2107,7 +2116,7 @@ static int ds_authenticates_keys(struct mem_funcs *mf,
if (digest_buf != digest_buf_spc)
GETDNS_FREE(*mf, digest_buf);
DEBUG_SEC("HASH length mismatch %zu != %zu\n",
DEBUG_SEC("HASH length mismatch "PRIsz" != "PRIsz"\n",
digest_len, ds->rr_i.nxt - ds->rr_i.rr_type-14);
continue;
}
@ -2130,7 +2139,7 @@ static int ds_authenticates_keys(struct mem_funcs *mf,
max_supported_result = SIGNATURE_VERIFIED | keytag;
}
}
DEBUG_SEC("valid_dsses: %zu, supported_dsses: %zu\n",
DEBUG_SEC("valid_dsses: "PRIsz", supported_dsses: "PRIsz"\n",
valid_dsses, supported_dsses);
if (valid_dsses && !supported_dsses)
return NO_SUPPORTED_ALGORITHMS;
@ -2998,6 +3007,8 @@ static size_t count_outstanding_requests(chain_head *head)
; node
; node = node->parent) {
count += node->lock;
if (node->dnskey_req &&
node->dnskey_req->state != NET_REQ_FINISHED &&
node->dnskey_req->state != NET_REQ_CANCELED)
@ -3135,7 +3146,7 @@ static void check_chain_complete(chain_head *chain)
rrset_iter tas_iter;
if ((o = count_outstanding_requests(chain)) > 0) {
DEBUG_SEC("%zu outstanding requests\n", o);
DEBUG_SEC(PRIsz" outstanding requests\n", o);
return;
}
DEBUG_SEC("Chain done!\n");
@ -3406,7 +3417,7 @@ getdns_validate_dnssec2(getdns_list *records_to_validate,
for (i = 0; !getdns_list_get_dict(records_to_validate,i,&reply); i++) {
DEBUG_SEC("REPLY %zu, r: %d\n", i, r);
DEBUG_SEC("REPLY "PRIsz", r: %d\n", i, r);
if (to_val != to_val_buf)
GETDNS_FREE(*mf, to_val);
to_val_len = sizeof(to_val_buf);
@ -3433,7 +3444,7 @@ getdns_validate_dnssec2(getdns_list *records_to_validate,
break;
}
}
DEBUG_SEC("REPLY %zu, r: %d\n", i, r);
DEBUG_SEC("REPLY "PRIsz", r: %d\n", i, r);
exit_free_to_val:
if (to_val != to_val_buf)

View File

@ -0,0 +1,281 @@
/*
* Copyright (c) 2013, NLNet Labs, Verisign, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the names of the copyright holders nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "extension/default_eventloop.h"
#include "debug.h"
static uint64_t get_now_plus(uint64_t amount)
{
struct timeval tv;
uint64_t now;
if (gettimeofday(&tv, NULL)) {
perror("gettimeofday() failed");
exit(EXIT_FAILURE);
}
now = tv.tv_sec * 1000000 + tv.tv_usec;
return (now + amount * 1000) >= now ? now + amount * 1000 : -1;
}
static getdns_return_t
default_eventloop_schedule(getdns_eventloop *loop,
int fd, uint64_t timeout, getdns_eventloop_event *event)
{
_getdns_default_eventloop *default_loop = (_getdns_default_eventloop *)loop;
size_t i;
DEBUG_SCHED( "%s(loop: %p, fd: %d, timeout: %"PRIu64", event: %p, FD_SETSIZE: %d)\n"
, __FUNCTION__, loop, fd, timeout, event, FD_SETSIZE);
if (!loop || !event)
return GETDNS_RETURN_INVALID_PARAMETER;
if (fd >= FD_SETSIZE) {
DEBUG_SCHED( "ERROR: fd %d >= FD_SETSIZE: %d!\n"
, fd, FD_SETSIZE);
return GETDNS_RETURN_GENERIC_ERROR;
}
if (fd >= 0) {
if (!(event->read_cb || event->write_cb)) {
DEBUG_SCHED("ERROR: fd event without "
"read or write cb!\n");
return GETDNS_RETURN_GENERIC_ERROR;
}
#if defined(SCHED_DEBUG) && SCHED_DEBUG
if (default_loop->fd_events[fd]) {
DEBUG_SCHED( "ERROR: Event present at fd slot: %p!\n"
, default_loop->fd_events[fd]);
}
#endif
default_loop->fd_events[fd] = event;
default_loop->fd_timeout_times[fd] = get_now_plus(timeout);
event->ev = (void *) (intptr_t) fd + 1;
DEBUG_SCHED( "scheduled read/write at %d\n", fd);
return GETDNS_RETURN_GOOD;
}
if (!event->timeout_cb) {
DEBUG_SCHED("ERROR: fd < 0 without timeout_cb!\n");
return GETDNS_RETURN_GENERIC_ERROR;
}
if (event->read_cb) {
DEBUG_SCHED("ERROR: timeout event with read_cb! Clearing.\n");
event->read_cb = NULL;
}
if (event->write_cb) {
DEBUG_SCHED("ERROR: timeout event with write_cb! Clearing.\n");
event->write_cb = NULL;
}
for (i = 0; i < MAX_TIMEOUTS; i++) {
if (default_loop->timeout_events[i] == NULL) {
default_loop->timeout_events[i] = event;
default_loop->timeout_times[i] = get_now_plus(timeout);
event->ev = (void *) (intptr_t) i + 1;
DEBUG_SCHED( "scheduled timeout at %d\n", (int)i);
return GETDNS_RETURN_GOOD;
}
}
DEBUG_SCHED("ERROR: Out of timeout slots!\n");
return GETDNS_RETURN_GENERIC_ERROR;
}
static getdns_return_t
default_eventloop_clear(getdns_eventloop *loop, getdns_eventloop_event *event)
{
_getdns_default_eventloop *default_loop = (_getdns_default_eventloop *)loop;
ssize_t i;
if (!loop || !event)
return GETDNS_RETURN_INVALID_PARAMETER;
DEBUG_SCHED( "%s(loop: %p, event: %p)\n", __FUNCTION__, loop, event);
i = (intptr_t)event->ev - 1;
if (i < 0 || i > FD_SETSIZE) {
return GETDNS_RETURN_GENERIC_ERROR;
}
if (event->timeout_cb && !event->read_cb && !event->write_cb) {
#if defined(SCHED_DEBUG) && SCHED_DEBUG
if (default_loop->timeout_events[i] != event)
DEBUG_SCHED( "ERROR: Different/wrong event present at "
"timeout slot: %p!\n"
, default_loop->timeout_events[i]);
#endif
default_loop->timeout_events[i] = NULL;
} else {
#if defined(SCHED_DEBUG) && SCHED_DEBUG
if (default_loop->fd_events[i] != event)
DEBUG_SCHED( "ERROR: Different/wrong event present at "
"fd slot: %p!\n"
, default_loop->fd_events[i]);
#endif
default_loop->fd_events[i] = NULL;
}
event->ev = NULL;
return GETDNS_RETURN_GOOD;
}
static void
default_eventloop_cleanup(getdns_eventloop *loop)
{
}
static void
default_read_cb(int fd, getdns_eventloop_event *event)
{
DEBUG_SCHED( "%s(fd: %d, event: %p)\n", __FUNCTION__, fd, event);
event->read_cb(event->userarg);
}
static void
default_write_cb(int fd, getdns_eventloop_event *event)
{
DEBUG_SCHED( "%s(fd: %d, event: %p)\n", __FUNCTION__, fd, event);
event->write_cb(event->userarg);
}
static void
default_timeout_cb(int fd, getdns_eventloop_event *event)
{
DEBUG_SCHED( "%s(fd: %d, event: %p)\n", __FUNCTION__, fd, event);
event->timeout_cb(event->userarg);
}
static void
default_eventloop_run_once(getdns_eventloop *loop, int blocking)
{
_getdns_default_eventloop *default_loop = (_getdns_default_eventloop *)loop;
fd_set readfds, writefds;
int fd, max_fd = -1;
uint64_t now, timeout = (uint64_t)-1;
size_t i;
struct timeval tv;
if (!loop)
return;
FD_ZERO(&readfds);
FD_ZERO(&writefds);
now = get_now_plus(0);
for (i = 0; i < MAX_TIMEOUTS; i++) {
if (!default_loop->timeout_events[i])
continue;
if (now > default_loop->timeout_times[i])
default_timeout_cb(-1, default_loop->timeout_events[i]);
else if (default_loop->timeout_times[i] < timeout)
timeout = default_loop->timeout_times[i];
}
for (fd = 0; fd < FD_SETSIZE; fd++) {
if (!default_loop->fd_events[fd])
continue;
if (default_loop->fd_events[fd]->read_cb)
FD_SET(fd, &readfds);
if (default_loop->fd_events[fd]->write_cb)
FD_SET(fd, &writefds);
if (fd > max_fd)
max_fd = fd;
if (default_loop->fd_timeout_times[fd] < timeout)
timeout = default_loop->fd_timeout_times[fd];
}
if (max_fd == -1 && timeout == (uint64_t)-1)
return;
if (! blocking || now > timeout) {
tv.tv_sec = 0;
tv.tv_usec = 0;
} else {
tv.tv_sec = (timeout - now) / 1000000;
tv.tv_usec = (timeout - now) % 1000000;
}
if (select(max_fd + 1, &readfds, &writefds, NULL,
(timeout == ((uint64_t)-1) ? NULL : &tv)) < 0) {
perror("select() failed");
exit(EXIT_FAILURE);
}
now = get_now_plus(0);
for (fd = 0; fd < FD_SETSIZE; fd++) {
if (default_loop->fd_events[fd] &&
default_loop->fd_events[fd]->read_cb &&
FD_ISSET(fd, &readfds))
default_read_cb(fd, default_loop->fd_events[fd]);
if (default_loop->fd_events[fd] &&
default_loop->fd_events[fd]->write_cb &&
FD_ISSET(fd, &writefds))
default_write_cb(fd, default_loop->fd_events[fd]);
if (default_loop->fd_events[fd] &&
default_loop->fd_events[fd]->timeout_cb &&
now > default_loop->fd_timeout_times[fd])
default_timeout_cb(fd, default_loop->fd_events[fd]);
i = fd;
if (default_loop->timeout_events[i] &&
default_loop->timeout_events[i]->timeout_cb &&
now > default_loop->timeout_times[i])
default_timeout_cb(-1, default_loop->timeout_events[i]);
}
}
static void
default_eventloop_run(getdns_eventloop *loop)
{
_getdns_default_eventloop *default_loop = (_getdns_default_eventloop *)loop;
size_t i;
if (!loop)
return;
i = 0;
while (i < MAX_TIMEOUTS) {
if (default_loop->fd_events[i] || default_loop->timeout_events[i]) {
default_eventloop_run_once(loop, 1);
i = 0;
} else {
i++;
}
}
}
void
_getdns_default_eventloop_init(_getdns_default_eventloop *loop)
{
static getdns_eventloop_vmt default_eventloop_vmt = {
default_eventloop_cleanup,
default_eventloop_schedule,
default_eventloop_clear,
default_eventloop_run,
default_eventloop_run_once
};
(void) memset(loop, 0, sizeof(_getdns_default_eventloop));
loop->loop.vmt = &default_eventloop_vmt;
}

View File

@ -1,11 +1,10 @@
/**
*
* \file 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 {
/* 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
/* Eventloop based on select */
typedef struct _getdns_default_eventloop {
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;
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_init(getdns_context *context, _getdns_mini_event *mini_event);
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_ */

View File

@ -1,238 +0,0 @@
/**
*
* \file libmini_event.c
* @brief Build in default eventloop extension that uses select.
*
*/
/*
* Copyright (c) 2013, NLnet Labs, Verisign, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the names of the copyright holders nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "debug.h"
#include "types-internal.h"
#include "extension/libmini_event.h"
#if defined(SCHED_DEBUG) && SCHED_DEBUG
#include <inttypes.h>
#endif
static void
_getdns_mini_event_cleanup(getdns_eventloop *loop)
{
_getdns_mini_event *ext = (_getdns_mini_event *)loop;
_getdns_event_base_free(ext->base);
}
void
_getdns_mini_event_destroy(_getdns_mini_event *ext)
{
assert(ext);
ext->loop.vmt->cleanup(&ext->loop);
GETDNS_FREE(ext->mf, ext);
}
void _getdns_handle_timeouts(struct _getdns_event_base* base,
struct timeval* now, struct timeval* wait);
int _getdns_handle_select(struct _getdns_event_base* base, struct timeval* wait);
static int
_getdns_mini_event_settime(_getdns_mini_event *ext)
{
if (gettimeofday(&ext->time_tv, NULL) < 0)
return -1;
ext->time_secs = (time_t)ext->time_tv.tv_sec;
return 0;
}
static void
_getdns_mini_event_run(getdns_eventloop *loop)
{
_getdns_mini_event *ext = (_getdns_mini_event *)loop;
struct timeval wait;
if (ext->n_events == 0 || _getdns_mini_event_settime(ext) < 0)
return;
do {
(void) _getdns_handle_timeouts(ext->base, &ext->time_tv, &wait);
if (!ext->n_events)
break;
if (_getdns_handle_select(ext->base, &wait))
break;
} while (ext->n_events);
}
static void
_getdns_mini_event_run_once(getdns_eventloop *loop, int blocking)
{
static struct timeval immediately = { 0, 0 };
_getdns_mini_event *ext = (_getdns_mini_event *)loop;
struct timeval wait;
if (blocking) {
if (_getdns_mini_event_settime(ext) < 0)
return;
_getdns_handle_timeouts(ext->base, &ext->time_tv, &wait);
if (_getdns_handle_select(ext->base, &wait) < 0)
return;
} else if (_getdns_handle_select(ext->base, &immediately) < 0)
return;
_getdns_handle_timeouts(ext->base, &ext->time_tv, &wait);
}
static getdns_return_t
_getdns_mini_event_clear(getdns_eventloop *loop, getdns_eventloop_event *el_ev)
{
getdns_return_t r = GETDNS_RETURN_GOOD;
_getdns_mini_event *ext = (_getdns_mini_event *)loop;
assert(el_ev->ev);
DEBUG_SCHED("1. _getdns_mini_event_clear(loop: %p, el_ev: %p[userarg: %p, r: %p, w: %p, t: %p, ev: %p]); n_events: %d, times: %d\n", loop, el_ev, el_ev->userarg, el_ev->read_cb, el_ev->write_cb, el_ev->timeout_cb, el_ev->ev, (int)ext->n_events, (int)ext->base->times->count);
if (_getdns_event_del(el_ev->ev) != 0)
r = GETDNS_RETURN_GENERIC_ERROR;
GETDNS_FREE(ext->mf, el_ev->ev);
el_ev->ev = NULL;
ext->n_events--;
DEBUG_SCHED("2. %d <- _getdns_mini_event_clear(loop: %p, el_ev: %p[userarg: %p, r: %p, w: %p, t: %p, ev: %p]); n_events: %d, times: %d\n", r, loop, el_ev, el_ev->userarg, el_ev->read_cb, el_ev->write_cb, el_ev->timeout_cb, el_ev->ev, (int)ext->n_events, (int)ext->base->times->count);
return r;
}
static void
_getdns_mini_event_callback(int fd, short bits, void *arg)
{
getdns_eventloop_event *el_ev = (getdns_eventloop_event *)arg;
DEBUG_SCHED("1. _getdns_mini_event_callback(fd: %d, bits: %d, el_ev: %p[userarg: %p, r: %p, w: %p, t: %p, ev: %p])\n", fd, (int)bits, el_ev, el_ev->userarg, el_ev->read_cb, el_ev->write_cb, el_ev->timeout_cb, el_ev->ev);
if (bits & EV_READ) {
assert(el_ev->read_cb);
el_ev->read_cb(el_ev->userarg);
} else if (bits & EV_WRITE) {
assert(el_ev->write_cb);
el_ev->write_cb(el_ev->userarg);
} else if (bits & EV_TIMEOUT) {
assert(el_ev->timeout_cb);
el_ev->timeout_cb(el_ev->userarg);
} else
assert(ASSERT_UNREACHABLE);
}
static getdns_return_t
_getdns_mini_event_schedule(getdns_eventloop *loop,
int fd, uint64_t timeout, getdns_eventloop_event *el_ev)
{
_getdns_mini_event *ext = (_getdns_mini_event *)loop;
struct _getdns_event *my_ev;
struct timeval tv = { timeout / 1000, (timeout % 1000) * 1000 };
assert(el_ev);
assert(!(el_ev->read_cb || el_ev->write_cb) || fd >= 0);
assert( el_ev->read_cb || el_ev->write_cb || el_ev->timeout_cb);
if (!(my_ev = GETDNS_MALLOC(ext->mf, struct _getdns_event)))
return GETDNS_RETURN_MEMORY_ERROR;
el_ev->ev = my_ev;
DEBUG_SCHED("1. _getdns_mini_event_schedule(loop: %p, fd: %d, timeout: %"PRId64", el_ev: %p[userarg: %p, r: %p, w: %p, t: %p, ev: %p]); n_events: %d\n", loop, fd, timeout, el_ev, el_ev->userarg, el_ev->read_cb, el_ev->write_cb, el_ev->timeout_cb, el_ev->ev, (int)ext->n_events);
_getdns_event_set(my_ev, fd, (
(el_ev->read_cb ? EV_READ|EV_PERSIST : 0) |
(el_ev->write_cb ? EV_WRITE|EV_PERSIST : 0) |
(el_ev->timeout_cb ? EV_TIMEOUT : 0)),
_getdns_mini_event_callback, el_ev);
if (_getdns_mini_event_settime(ext))
goto error;
(void) _getdns_event_base_set(ext->base, my_ev);
if (_getdns_event_add(my_ev, el_ev->timeout_cb ? &tv : NULL))
goto error;
ext->n_events++;
DEBUG_SCHED("2. _getdns_mini_event_schedule(loop: %p, fd: %d, timeout: %"PRId64", el_ev: %p[userarg: %p, r: %p, w: %p, t: %p, ev: %p]); n_events: %d\n", loop, fd, timeout, el_ev, el_ev->userarg, el_ev->read_cb, el_ev->write_cb, el_ev->timeout_cb, el_ev->ev, (int)ext->n_events);
return GETDNS_RETURN_GOOD;
error:
GETDNS_FREE(ext->mf, my_ev);
el_ev->ev = NULL;
DEBUG_SCHED("3. _getdns_mini_event_schedule(loop: %p, fd: %d, timeout: %"PRId64", el_ev: %p[userarg: %p, r: %p, w: %p, t: %p, ev: %p]); n_events: %d\n", loop, fd, timeout, el_ev, el_ev->userarg, el_ev->read_cb, el_ev->write_cb, el_ev->timeout_cb, el_ev->ev, (int)ext->n_events);
return GETDNS_RETURN_GENERIC_ERROR;
}
getdns_return_t
_getdns_mini_event_init(getdns_context *context, _getdns_mini_event *ext)
{
static getdns_eventloop_vmt _getdns_mini_event_vmt = {
_getdns_mini_event_cleanup,
_getdns_mini_event_schedule,
_getdns_mini_event_clear,
_getdns_mini_event_run,
_getdns_mini_event_run_once
};
if (!context)
return GETDNS_RETURN_BAD_CONTEXT;
if (!ext)
return GETDNS_RETURN_INVALID_PARAMETER;
#ifdef USE_WINSOCK
int r;
WSADATA wsa_data;
if ((r = WSAStartup(MAKEWORD(2, 2), &wsa_data)) != 0) {
printf("could not init winsock. WSAStartup: %s",
wsa_strerror(r));
return GETDNS_RETURN_GENERIC_ERROR;
}
#endif
ext->n_events = 0;
ext->loop.vmt = &_getdns_mini_event_vmt;
ext->base = _getdns_event_init(&ext->time_secs, &ext->time_tv);
if (!ext->base)
return GETDNS_RETURN_MEMORY_ERROR;
ext->mf = *priv_getdns_context_mf(context);
return GETDNS_RETURN_GOOD;
}
getdns_return_t
_getdns_mini_event_create(getdns_context *context, _getdns_mini_event **ext)
{
if (!context) return GETDNS_RETURN_BAD_CONTEXT;
if (!ext) return GETDNS_RETURN_INVALID_PARAMETER;
*ext = GETDNS_MALLOC(*priv_getdns_context_mf(context), _getdns_mini_event);
return _getdns_mini_event_init(context, *ext);
}

View File

@ -39,6 +39,12 @@
#include <string.h>
#include "config.h"
#include "general.h"
#ifdef HAVE_LIBUNBOUND
#include <unbound.h>
#endif
#ifdef HAVE_UNBOUND_EVENT_API
#include "ub_loop.h"
#endif
#include "gldns/wire2str.h"
#include "context.h"
#include "types-internal.h"
@ -256,6 +262,26 @@ _getdns_check_dns_req_complete(getdns_dns_req *dns_req)
}
#ifdef HAVE_LIBUNBOUND
#ifdef HAVE_UNBOUND_EVENT_API
static void
ub_resolve_event_callback(void* arg, int rcode, void *pkt, int pkt_len,
int sec, char* why_bogus)
{
getdns_network_req *netreq = (getdns_network_req *) arg;
getdns_dns_req *dns_req = netreq->owner;
netreq->state = NET_REQ_FINISHED;
/* parse */
if (getdns_apply_network_result(
netreq, rcode, pkt, pkt_len, sec, why_bogus)) {
_getdns_call_user_callback(dns_req, NULL);
return;
}
_getdns_check_dns_req_complete(dns_req);
} /* ub_resolve_event_callback */
#endif
static void
ub_resolve_callback(void* arg, int err, struct ub_result* ub_res)
{
@ -268,7 +294,9 @@ ub_resolve_callback(void* arg, int err, struct ub_result* ub_res)
return;
}
/* parse */
if (getdns_apply_network_result(netreq, ub_res)) {
if (getdns_apply_network_result(netreq, ub_res->rcode,
ub_res->answer_packet, ub_res->answer_len,
(ub_res->secure ? 2 : ub_res->bogus ? 1 : 0), ub_res->why_bogus)) {
ub_resolve_free(ub_res);
_getdns_call_user_callback(dns_req, NULL);
return;
@ -319,6 +347,14 @@ _getdns_submit_netreq(getdns_network_req *netreq)
dns_req->name_len, name, sizeof(name));
#ifdef HAVE_LIBUNBOUND
#ifdef HAVE_UNBOUND_EVENT_API
if (_getdns_ub_loop_enabled(&dns_req->context->ub_loop))
return ub_resolve_event(dns_req->context->unbound_ctx,
name, netreq->request_type, netreq->owner->request_class,
netreq, ub_resolve_event_callback, &(netreq->unbound_id)) ?
GETDNS_RETURN_GENERIC_ERROR : GETDNS_RETURN_GOOD;
else
#endif
return ub_resolve_async(dns_req->context->unbound_ctx,
name, netreq->request_type, netreq->owner->request_class,
netreq, ub_resolve_callback, &(netreq->unbound_id)) ?
@ -412,7 +448,7 @@ validate_extensions(struct getdns_dict * extensions)
static getdns_return_t
getdns_general_ns(getdns_context *context, getdns_eventloop *loop,
const char *name, uint16_t request_type, getdns_dict *extensions,
void *userarg, getdns_dns_req **dnsreq_p,
void *userarg, getdns_network_req **return_netreq_p,
getdns_callback_t callbackfn, internal_cb_t internal_cb, int usenamespaces)
{
getdns_return_t r = GETDNS_RETURN_GOOD;
@ -443,8 +479,8 @@ getdns_general_ns(getdns_context *context, getdns_eventloop *loop,
req->user_callback = callbackfn;
req->internal_cb = internal_cb;
if (dnsreq_p)
*dnsreq_p = req;
if (return_netreq_p)
*return_netreq_p = req->netreqs[0];
_getdns_context_track_outbound_request(req);
@ -493,12 +529,12 @@ getdns_general_ns(getdns_context *context, getdns_eventloop *loop,
getdns_return_t
_getdns_general_loop(getdns_context *context, getdns_eventloop *loop,
const char *name, uint16_t request_type, getdns_dict *extensions,
void *userarg, getdns_dns_req **dnsreq_p,
void *userarg, getdns_network_req **netreq_p,
getdns_callback_t callback, internal_cb_t internal_cb)
{
return getdns_general_ns(context, loop,
name, request_type, extensions,
userarg, dnsreq_p, callback, internal_cb, 0);
userarg, netreq_p, callback, internal_cb, 0);
} /* getdns_general_loop */
@ -510,7 +546,7 @@ _getdns_address_loop(getdns_context *context, getdns_eventloop *loop,
getdns_dict *my_extensions = extensions;
getdns_return_t r;
uint32_t value;
getdns_dns_req *dnsreq = NULL;
getdns_network_req *netreq = NULL;
if (!my_extensions) {
if (!(my_extensions=getdns_dict_create_with_context(context)))
@ -526,9 +562,9 @@ _getdns_address_loop(getdns_context *context, getdns_eventloop *loop,
r = getdns_general_ns(context, loop,
name, GETDNS_RRTYPE_AAAA, my_extensions,
userarg, &dnsreq, callback, NULL, 1);
if (dnsreq && transaction_id)
*transaction_id = dnsreq->trans_id;
userarg, &netreq, callback, NULL, 1);
if (netreq && transaction_id)
*transaction_id = netreq->owner->trans_id;
if (my_extensions != extensions)
getdns_dict_destroy(my_extensions);
@ -546,7 +582,7 @@ _getdns_hostname_loop(getdns_context *context, getdns_eventloop *loop,
uint16_t req_type;
char name[1024];
getdns_return_t retval;
getdns_dns_req *dnsreq = NULL;
getdns_network_req *netreq= NULL;
if ((retval =
getdns_dict_get_bindata(address, "address_data",
@ -620,9 +656,9 @@ _getdns_hostname_loop(getdns_context *context, getdns_eventloop *loop,
return GETDNS_RETURN_INVALID_PARAMETER;
}
retval = _getdns_general_loop(context, loop, name, req_type,
extensions, userarg, &dnsreq, callback, NULL);
if (dnsreq && transaction_id)
*transaction_id = dnsreq->trans_id;
extensions, userarg, &netreq, callback, NULL);
if (netreq && transaction_id)
*transaction_id = netreq->owner->trans_id;
return retval;
} /* getdns_hostname_loop */
@ -632,11 +668,11 @@ _getdns_service_loop(getdns_context *context, getdns_eventloop *loop,
getdns_transaction_t * transaction_id, getdns_callback_t callback)
{
getdns_return_t r;
getdns_dns_req *dnsreq = NULL;
getdns_network_req *netreq = NULL;
r = getdns_general_ns(context, loop, name, GETDNS_RRTYPE_SRV,
extensions, userarg, &dnsreq, callback, NULL, 1);
if (dnsreq && transaction_id)
*transaction_id = dnsreq->trans_id;
extensions, userarg, &netreq, callback, NULL, 1);
if (netreq && transaction_id)
*transaction_id = netreq->owner->trans_id;
return r;
} /* getdns_service_loop */
@ -650,14 +686,14 @@ getdns_general(getdns_context *context,
getdns_callback_t callback)
{
getdns_return_t r;
getdns_dns_req *dnsreq = NULL;
getdns_network_req *netreq = NULL;
if (!context) return GETDNS_RETURN_INVALID_PARAMETER;
r = _getdns_general_loop(context, context->extension,
name, request_type, extensions,
userarg, &dnsreq, callback, NULL);
if (dnsreq && transaction_id)
*transaction_id = dnsreq->trans_id;
userarg, &netreq, callback, NULL);
if (netreq && transaction_id)
*transaction_id = netreq->owner->trans_id;
return r;
} /* getdns_general */

View File

@ -50,7 +50,7 @@ getdns_return_t _getdns_submit_netreq(getdns_network_req *netreq);
getdns_return_t
_getdns_general_loop(getdns_context *context, getdns_eventloop *loop,
const char *name, uint16_t request_type, getdns_dict *extensions,
void *userarg, getdns_dns_req **dnsreq,
void *userarg, getdns_network_req **netreq_p,
getdns_callback_t callbackfn, internal_cb_t internal_cb);
getdns_return_t

View File

@ -120,8 +120,8 @@ gldns_buffer_printf(gldns_buffer *buffer, const char *format, ...)
remaining = gldns_buffer_remaining(buffer);
va_start(args, format);
written = vsnprintf((char *) gldns_buffer_current(buffer), remaining,
format, args);
written = _gldns_vsnprintf((char*)gldns_buffer_current(buffer),
remaining, format, args);
va_end(args);
if (written == -1) {
buffer->_status_err = 1;
@ -132,7 +132,8 @@ gldns_buffer_printf(gldns_buffer *buffer, const char *format, ...)
return -1;
}
va_start(args, format);
written = vsnprintf((char *) gldns_buffer_current(buffer),
written = _gldns_vsnprintf(
(char *) gldns_buffer_current(buffer),
gldns_buffer_remaining(buffer), format, args);
va_end(args);
if (written == -1) {

View File

@ -27,6 +27,21 @@ extern "C" {
# endif
#endif
#ifndef USE_WINSOCK
#define _gldns_vsnprintf vsnprintf
#else
/* Unlike Linux and BSD, vsnprintf on Windows returns -1 on overflow.
* Here it is redefined to always return the amount printed
* if enough space had been available.
*/
INLINE int
_gldns_vsnprintf(char *str, size_t size, const char *format, va_list ap)
{
int r = vsnprintf(str, size, format, ap);
return r == -1 ? _vscprintf(format, ap) : r;
}
#endif
/*
* Copy data allowing for unaligned accesses in network byte order
* (big endian).

View File

@ -278,7 +278,7 @@ int gldns_wire2str_dname_buf(uint8_t* d, size_t dlen, char* s, size_t slen)
int gldns_str_vprint(char** str, size_t* slen, const char* format, va_list args)
{
int w = vsnprintf(*str, *slen, format, args);
int w = _gldns_vsnprintf(*str, *slen, format, args);
if(w < 0) {
/* error in printout */
return 0;

View File

@ -415,13 +415,13 @@ _getdns_verify_pinset_match(const sha256_pin_t *pinset,
/* digest the cert with sha256 */
len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x), NULL);
if (len > sizeof(raw)) {
DEBUG_STUB("--- %s: pubkey %d is larger than %ld octets\n",
DEBUG_STUB("--- %s: pubkey %d is larger than "PRIsz" octets\n",
__FUNCTION__, i, sizeof(raw));
continue;
}
i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x), &next);
if (next - raw != len) {
DEBUG_STUB("--- %s: pubkey %d claimed it needed %d octets, really needed %ld\n",
DEBUG_STUB("--- %s: pubkey %d claimed it needed %d octets, really needed "PRIsz"\n",
__FUNCTION__, i, len, next - raw);
continue;
}
@ -430,7 +430,7 @@ _getdns_verify_pinset_match(const sha256_pin_t *pinset,
/* compare it */
for (p = pinset; p; p = p->next)
if (0 == memcmp(buf, p->pin, sizeof(p->pin))) {
DEBUG_STUB("--- %s: pubkey %d matched pin %p (%ld)!\n",
DEBUG_STUB("--- %s: pubkey %d matched pin %p ("PRIsz")!\n",
__FUNCTION__, i, p, sizeof(p->pin));
return GETDNS_RETURN_GOOD;
} else

View File

@ -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
@ -384,11 +392,11 @@ tcp_connect(getdns_upstream *upstream, getdns_transport_list_t transport)
#endif
if (connect(fd, (struct sockaddr *)&upstream->addr,
upstream->addr_len) == -1) {
if (errno != EINPROGRESS) {
if (_getdns_EINPROGRESS || _getdns_EWOULDBLOCK)
return fd;
close(fd);
return -1;
}
}
return fd;
}
@ -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;
@ -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)
@ -1408,10 +1405,13 @@ upstream_read_cb(void *userarg)
&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;
}
}

View File

@ -45,101 +45,108 @@
#include "stub.h"
#include "gldns/wire2str.h"
typedef struct getdns_sync_loop {
_getdns_mini_event loop;
typedef struct getdns_sync_data {
#ifdef HAVE_LIBUNBOUND
getdns_eventloop_event ub_event;
#endif
getdns_context *context;
int to_run;
getdns_dict *response;
} getdns_sync_loop;
} getdns_sync_data;
static getdns_return_t
getdns_sync_loop_init(getdns_context *context, getdns_sync_loop *loop)
getdns_sync_data_init(getdns_context *context, getdns_sync_data *data)
{
#ifdef HAVE_LIBUNBOUND
getdns_eventloop *ext = &loop->loop.loop;
getdns_eventloop *ext = &context->sync_eventloop.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;
data->context = context;
data->to_run = 1;
data->response = NULL;
#ifdef HAVE_LIBUNBOUND
loop->ub_event.userarg = loop->context;
loop->ub_event.read_cb = _getdns_context_ub_read_cb;
loop->ub_event.write_cb = NULL;
loop->ub_event.timeout_cb = NULL;
loop->ub_event.ev = NULL;
# ifndef USE_WINSOCK
data->ub_event.userarg = data->context;
data->ub_event.read_cb = _getdns_context_ub_read_cb;
data->ub_event.write_cb = NULL;
data->ub_event.timeout_cb = NULL;
data->ub_event.ev = NULL;
# endif
# ifdef HAVE_UNBOUND_EVENT_API
if (_getdns_ub_loop_enabled(&context->ub_loop)) {
context->ub_loop.extension = ext;
} else
# endif
# ifndef USE_WINSOCK
return ext->vmt->schedule(ext, ub_fd(context->unbound_ctx),
TIMEOUT_FOREVER, &loop->ub_event);
#else
TIMEOUT_FOREVER, &data->ub_event);
# else
/* No sync full recursion requests on windows without
* UNBOUND_EVENT_API because ub_fd() doesn't work on windows.
*/
; /* pass */
# endif
#endif
return GETDNS_RETURN_GOOD;
}
static void
getdns_sync_data_cleanup(getdns_sync_data *data)
{
#if defined(HAVE_LIBUNBOUND) && !defined(USE_WINSOCK)
# ifdef HAVE_UNBOUND_EVENT_API
if (_getdns_ub_loop_enabled(&data->context->ub_loop)) {
data->context->ub_loop.extension = data->context->extension;
} else
# endif
data->context->sync_eventloop.loop.vmt->clear(
&data->context->sync_eventloop.loop, &data->ub_event);
#endif
}
static void
getdns_sync_loop_cleanup(getdns_sync_loop *loop)
getdns_sync_loop_run(getdns_sync_data *data)
{
getdns_eventloop *ext = &loop->loop.loop;
#ifdef HAVE_LIBUNBOUND
ext->vmt->clear(ext, &loop->ub_event);
#endif
ext->vmt->cleanup(ext);
}
static void
getdns_sync_loop_run(getdns_sync_loop *loop)
{
getdns_eventloop *ext = &loop->loop.loop;
while (loop->to_run)
ext->vmt->run_once(ext, 1);
getdns_sync_loop_cleanup(loop);
while (data->to_run)
data->context->sync_eventloop.loop.vmt->run_once(
&data->context->sync_eventloop.loop, 1);
}
static void
getdns_sync_cb(getdns_context *context, getdns_callback_type_t callback_type,
getdns_dict *response, void *userarg, getdns_transaction_t transaction_id)
{
getdns_sync_loop *loop = (getdns_sync_loop *)userarg;
getdns_sync_data *data = (getdns_sync_data *)userarg;
assert(loop);
assert(data);
loop->response = response;
loop->to_run = 0;
data->response = response;
data->to_run = 0;
}
getdns_return_t
getdns_general_sync(getdns_context *context, const char *name,
uint16_t request_type, getdns_dict *extensions, getdns_dict **response)
{
getdns_sync_loop loop;
getdns_sync_data data;
getdns_return_t r;
if (!context || !name || !response)
return GETDNS_RETURN_INVALID_PARAMETER;
if ((r = getdns_sync_loop_init(context, &loop)))
if ((r = getdns_sync_data_init(context, &data)))
return r;
if ((r = _getdns_general_loop(context, &loop.loop.loop, name,
request_type, extensions, &loop, NULL, getdns_sync_cb, NULL))) {
if ((r = _getdns_general_loop(context, &context->sync_eventloop.loop,
name, request_type, extensions, &data, NULL, getdns_sync_cb, NULL))) {
getdns_sync_loop_cleanup(&loop);
getdns_sync_data_cleanup(&data);
return r;
}
getdns_sync_loop_run(&loop);
getdns_sync_loop_run(&data);
return (*response = loop.response) ?
return (*response = data.response) ?
GETDNS_RETURN_GOOD : GETDNS_RETURN_GENERIC_ERROR;
}
@ -147,24 +154,24 @@ getdns_return_t
getdns_address_sync(getdns_context *context, const char *name,
getdns_dict *extensions, getdns_dict **response)
{
getdns_sync_loop loop;
getdns_sync_data data;
getdns_return_t r;
if (!context || !name || !response)
return GETDNS_RETURN_INVALID_PARAMETER;
if ((r = getdns_sync_loop_init(context, &loop)))
if ((r = getdns_sync_data_init(context, &data)))
return r;
if ((r = _getdns_address_loop(context, &loop.loop.loop, name,
extensions, &loop, NULL, getdns_sync_cb))) {
if ((r = _getdns_address_loop(context, &context->sync_eventloop.loop,
name, extensions, &data, NULL, getdns_sync_cb))) {
getdns_sync_loop_cleanup(&loop);
getdns_sync_data_cleanup(&data);
return r;
}
getdns_sync_loop_run(&loop);
getdns_sync_loop_run(&data);
return (*response = loop.response) ?
return (*response = data.response) ?
GETDNS_RETURN_GOOD : GETDNS_RETURN_GENERIC_ERROR;
}
@ -172,24 +179,24 @@ getdns_return_t
getdns_hostname_sync(getdns_context *context, getdns_dict *address,
getdns_dict *extensions, getdns_dict **response)
{
getdns_sync_loop loop;
getdns_sync_data data;
getdns_return_t r;
if (!context || !address || !response)
return GETDNS_RETURN_INVALID_PARAMETER;
if ((r = getdns_sync_loop_init(context, &loop)))
if ((r = getdns_sync_data_init(context, &data)))
return r;
if ((r = _getdns_hostname_loop(context, &loop.loop.loop, address,
extensions, &loop, NULL, getdns_sync_cb))) {
if ((r = _getdns_hostname_loop(context, &context->sync_eventloop.loop,
address, extensions, &data, NULL, getdns_sync_cb))) {
getdns_sync_loop_cleanup(&loop);
getdns_sync_data_cleanup(&data);
return r;
}
getdns_sync_loop_run(&loop);
getdns_sync_loop_run(&data);
return (*response = loop.response) ?
return (*response = data.response) ?
GETDNS_RETURN_GOOD : GETDNS_RETURN_GENERIC_ERROR;
}
@ -197,24 +204,24 @@ getdns_return_t
getdns_service_sync(getdns_context *context, const char *name,
getdns_dict *extensions, getdns_dict **response)
{
getdns_sync_loop loop;
getdns_sync_data data;
getdns_return_t r;
if (!context || !name || !response)
return GETDNS_RETURN_INVALID_PARAMETER;
if ((r = getdns_sync_loop_init(context, &loop)))
if ((r = getdns_sync_data_init(context, &data)))
return r;
if ((r = _getdns_service_loop(context, &loop.loop.loop, name,
extensions, &loop, NULL, getdns_sync_cb))) {
if ((r = _getdns_service_loop(context, &context->sync_eventloop.loop,
name, extensions, &data, NULL, getdns_sync_cb))) {
getdns_sync_loop_cleanup(&loop);
getdns_sync_data_cleanup(&data);
return r;
}
getdns_sync_loop_run(&loop);
getdns_sync_loop_run(&data);
return (*response = loop.response) ?
return (*response = data.response) ?
GETDNS_RETURN_GOOD : GETDNS_RETURN_GENERIC_ERROR;
}

View File

@ -68,12 +68,13 @@ my_eventloop_schedule(getdns_eventloop *loop,
my_eventloop *my_loop = (my_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);
assert(loop);
assert(event);
assert(fd < FD_SETSIZE);
DEBUG_SCHED( "%s(loop: %p, fd: %d, timeout: %"PRIu64", event: %p)\n"
, __FUNCTION__, loop, fd, timeout, event);
if (fd >= 0 && (event->read_cb || event->write_cb)) {
assert(my_loop->fd_events[fd] == NULL);
@ -587,7 +588,7 @@ static getdns_return_t validate_chain(getdns_dict *response)
if ((r = getdns_list_set_dict(to_validate, 0, reply)))
goto error;
printf("reply %u, dnssec_status: ", (unsigned)i);
printf("reply "PRIsz", dnssec_status: ", i);
switch ((s = getdns_validate_dnssec(
to_validate, validation_chain, trust_anchor))) {
@ -645,7 +646,7 @@ void callback(getdns_context *context, getdns_callback_type_t callback_type,
else {
fprintf(stderr,
"An error occurred: The callback got a callback_type of %d. Exiting.\n",
callback_type);
(int)callback_type);
fprintf(stderr,
"Error : '%s'\n",
getdns_get_errorstr_by_id(callback_type));
@ -736,7 +737,7 @@ getdns_return_t parse_args(int argc, char **argv)
(arg[4] == '=' || arg[4] == '\0')) {
if ((r = set_cookie(extensions, arg+4))) {
fprintf(stderr, "Could not set cookie:"
" %d", r);
" %d", (int)r);
break;
}
} else if (strncmp(arg+1, "specify_class=", 14) == 0) {
@ -776,7 +777,7 @@ getdns_return_t parse_args(int argc, char **argv)
} else if ((r = getdns_dict_set_int(extensions, arg+1,
GETDNS_EXTENSION_TRUE))) {
fprintf(stderr, "Could not set extension "
"\"%s\": %d\n", argv[i], r);
"\"%s\": %d\n", argv[i], (int)r);
break;
}
continue;
@ -911,7 +912,7 @@ getdns_return_t parse_args(int argc, char **argv)
if (r = getdns_list_set_dict(pubkey_pinset, pincount++,
pubkey_pin), r) {
fprintf(stderr, "Failed to add pin to pinset (error %d: %s)\n",
r, getdns_get_errorstr_by_id(r));
(int)r, getdns_get_errorstr_by_id(r));
getdns_dict_destroy(pubkey_pin);
pubkey_pin = NULL;
return GETDNS_RETURN_GENERIC_ERROR;
@ -1121,11 +1122,11 @@ next: ;
/* apply the accumulated pubkey pinset to all upstreams: */
for (i = 0; i < upstream_count; i++) {
if (r = getdns_list_get_dict(upstream_list, i, &upstream), r) {
fprintf(stderr, "Failed to get upstream %lu when adding pinset\n", (long unsigned int)i);
fprintf(stderr, "Failed to get upstream "PRIsz" when adding pinset\n", i);
return r;
}
if (r = getdns_dict_set_list(upstream, "tls_pubkey_pinset", pubkey_pinset), r) {
fprintf(stderr, "Failed to set pubkey pinset on upstream %lu\n", (long unsigned int)i);
fprintf(stderr, "Failed to set pubkey pinset on upstream "PRIsz"\n", i);
return r;
}
}
@ -1190,7 +1191,7 @@ getdns_return_t do_the_call(void)
if (r == GETDNS_RETURN_GOOD && !batch_mode)
getdns_context_run(context);
if (r != GETDNS_RETURN_GOOD)
fprintf(stderr, "An error occurred: %d '%s'\n", r,
fprintf(stderr, "An error occurred: %d '%s'\n", (int)r,
getdns_get_errorstr_by_id(r));
} else {
switch (calltype) {
@ -1215,7 +1216,7 @@ getdns_return_t do_the_call(void)
break;
}
if (r != GETDNS_RETURN_GOOD) {
fprintf(stderr, "An error occurred: %d '%s'\n", r,
fprintf(stderr, "An error occurred: %d '%s'\n", (int)r,
getdns_get_errorstr_by_id(r));
return r;
}
@ -1300,12 +1301,10 @@ main(int argc, char **argv)
name = the_root;
if ((r = getdns_context_create(&context, 1))) {
fprintf(stderr, "Create context failed: %d\n", r);
fprintf(stderr, "Create context failed: %d\n", (int)r);
return r;
}
my_eventloop_init(&my_loop);
if ((r = getdns_context_set_eventloop(context, &my_loop.base)))
goto done_destroy_context;
if ((r = getdns_context_set_use_threads(context, 1)))
goto done_destroy_context;
extensions = getdns_dict_create();
@ -1328,10 +1327,14 @@ main(int argc, char **argv)
/* Make the call */
if (interactive) {
getdns_eventloop_event read_line_ev = {
&read_line_ev, read_line_cb, NULL, NULL, NULL };
(void) my_eventloop_schedule(
&my_loop.base, fileno(fp), -1, &read_line_ev);
if ((r = getdns_context_set_eventloop(context, &my_loop.base)))
goto done_destroy_context;
if (!query_file) {
printf("> ");
fflush(stdout);

445
src/ub_loop.c Normal file
View File

@ -0,0 +1,445 @@
/**
*
* \file ub_loop.c
* @brief Interface to the unbound pluggable event API
*
* These routines are not intended to be used by applications calling into
* the library.
*
*/
/*
* 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 "ub_loop.h"
#ifdef HAVE_UNBOUND_EVENT_API
#define UB_EVENT_API_MAGIC 0x44d74d78
#ifndef HAVE_UNBOUND_EVENT_H
/** event timeout */
#define UB_EV_TIMEOUT 0x01
/** event fd readable */
#define UB_EV_READ 0x02
/** event fd writable */
#define UB_EV_WRITE 0x04
/** event signal */
#define UB_EV_SIGNAL 0x08
/** event must persist */
#define UB_EV_PERSIST 0x10
struct ub_event_base_vmt {
void (*free)(struct ub_event_base*);
int (*dispatch)(struct ub_event_base*);
int (*loopexit)(struct ub_event_base*, struct timeval*);
struct ub_event* (*new_event)(struct ub_event_base*,
int fd, short bits, void (*cb)(int, short, void*), void* arg);
struct ub_event* (*new_signal)(struct ub_event_base*, int fd,
void (*cb)(int, short, void*), void* arg);
struct ub_event* (*winsock_register_wsaevent)(struct ub_event_base*,
void* wsaevent, void (*cb)(int, short, void*), void* arg);
};
struct ub_event_vmt {
void (*add_bits)(struct ub_event*, short);
void (*del_bits)(struct ub_event*, short);
void (*set_fd)(struct ub_event*, int);
void (*free)(struct ub_event*);
int (*add)(struct ub_event*, struct timeval*);
int (*del)(struct ub_event*);
int (*add_timer)(struct ub_event*, struct ub_event_base*,
void (*cb)(int, short, void*), void* arg, struct timeval*);
int (*del_timer)(struct ub_event*);
int (*add_signal)(struct ub_event*, struct timeval*);
int (*del_signal)(struct ub_event*);
void (*winsock_unregister_wsaevent)(struct ub_event* ev);
void (*winsock_tcp_wouldblock)(struct ub_event*, int eventbit);
};
struct ub_event {
unsigned long magic;
struct ub_event_vmt* vmt;
};
#endif
typedef struct my_event {
struct ub_event super;
/** event in the getdns event loop */
getdns_eventloop_event gev;
/** is event already added */
int added;
/** event loop it belongs to */
_getdns_ub_loop *loop;
/** fd to poll or -1 for timeouts. signal number for sigs. */
int fd;
/** what events this event is interested in, see EV_.. above. */
short bits;
/** timeout value */
uint64_t timeout;
/** callback to call: fd, eventbits, userarg */
void (*cb)(int, short, void *arg);
/** callback user arg */
void *arg;
#ifdef USE_WINSOCK
int is_tcp;
int read_wouldblock;
int write_wouldblock;
#endif
int *active;
} my_event;
#define AS_UB_LOOP(x) \
(((union {struct ub_event_base* a; _getdns_ub_loop* b;})x).b)
#define AS_MY_EVENT(x) \
(((union {struct ub_event* a; my_event* b;})x).b)
static void my_event_base_free(struct ub_event_base* base)
{
/* We don't allocate our event base, so no need to free */
(void)base;
return;
}
static int my_event_base_dispatch(struct ub_event_base* base)
{
(void)base;
/* We run the event loop extension for which this ub_event_base is an
* interface ourselfs, so no need to let libunbound call dispatch.
*/
return -1;
}
static int my_event_base_loopexit(struct ub_event_base* base, struct timeval* tv)
{
(void)tv;
/* Not sure when this will be called. But it is of no influence as we
* run the event loop ourself.
*/
AS_UB_LOOP(base)->running = 0;
return 0;
}
#define CLEAR_MY_EVENT(ev) \
do { (ev)->loop->extension->vmt->clear((ev)->loop->extension, \
&(ev)->gev); (ev)->added = 0; if ((ev)->active) { \
*(ev)->active = 0; (ev)->active = NULL; }} while(0)
static getdns_return_t schedule_my_event(my_event *ev)
{
getdns_return_t r;
if (ev->gev.read_cb || ev->gev.write_cb || ev->gev.write_cb) {
if ((r = ev->loop->extension->vmt->schedule(
ev->loop->extension, ev->fd, ev->timeout, &ev->gev)))
return r;
ev->added = 1;
}
return GETDNS_RETURN_GOOD;
}
static void read_cb(void *userarg)
{
struct my_event *ev = (struct my_event *)userarg;
int active = 1;
ev->active = &active;
#ifdef USE_WINSOCK
if (ev->is_tcp) {
ev->read_wouldblock = 0;
do {
(*ev->cb)(ev->fd, UB_EV_READ, ev->arg);
} while (active && !ev->read_wouldblock && (ev->bits & UB_EV_PERSIST));
} else
(*ev->cb)(ev->fd, UB_EV_READ, ev->arg);
#else
(*ev->cb)(ev->fd, UB_EV_READ, ev->arg);
#endif
if (active) {
ev->active = NULL;
if ((ev->bits & UB_EV_PERSIST) == 0)
CLEAR_MY_EVENT(ev);
}
}
static void write_cb(void *userarg)
{
struct my_event *ev = (struct my_event *)userarg;
int active = 1;
ev->active = &active;
#ifdef USE_WINSOCK
if (ev->is_tcp) {
ev->write_wouldblock = 0;
do {
(*ev->cb)(ev->fd, UB_EV_WRITE, ev->arg);
} while (active && !ev->write_wouldblock && (ev->bits & UB_EV_PERSIST));
} else
(*ev->cb)(ev->fd, UB_EV_WRITE, ev->arg);
#else
(*ev->cb)(ev->fd, UB_EV_WRITE, ev->arg);
#endif
if (active) {
ev->active = NULL;
if ((ev->bits & UB_EV_PERSIST) == 0)
CLEAR_MY_EVENT(ev);
}
}
static void timeout_cb(void *userarg)
{
struct my_event *ev = (struct my_event *)userarg;
int active = 1;
ev->active = &active;
(*ev->cb)(ev->fd, UB_EV_TIMEOUT, ev->arg);
if (active) {
ev->active = NULL;
if ((ev->bits & UB_EV_PERSIST) == 0)
CLEAR_MY_EVENT(ev);
}
}
static getdns_return_t set_gev_callbacks(my_event* ev, short bits)
{
int added = ev->added;
if (ev->bits != bits) {
if (added)
CLEAR_MY_EVENT(ev);
ev->gev.read_cb = bits & UB_EV_READ ? read_cb : NULL;
ev->gev.write_cb = bits & UB_EV_WRITE ? write_cb : NULL;
ev->gev.timeout_cb = bits & UB_EV_TIMEOUT ? timeout_cb : NULL;
ev->bits = bits;
if (added)
return schedule_my_event(ev);
}
return GETDNS_RETURN_GOOD;
}
static void my_event_add_bits(struct ub_event* ev, short bits)
{
(void) set_gev_callbacks(AS_MY_EVENT(ev), AS_MY_EVENT(ev)->bits | bits);
}
static void my_event_del_bits(struct ub_event* ev, short bits)
{
(void) set_gev_callbacks(AS_MY_EVENT(ev), AS_MY_EVENT(ev)->bits & ~bits);
}
static void my_event_set_fd(struct ub_event* ub_ev, int fd)
{
my_event *ev = AS_MY_EVENT(ub_ev);
if (ev->fd != fd) {
if (ev->added) {
CLEAR_MY_EVENT(ev);
ev->fd = fd;
(void) schedule_my_event(ev);
} else
ev->fd = fd;
}
}
static void my_event_free(struct ub_event* ev)
{
GETDNS_FREE(AS_MY_EVENT(ev)->loop->mf, ev);
}
static int my_event_del(struct ub_event* ev)
{
if (AS_MY_EVENT(ev)->added)
CLEAR_MY_EVENT(AS_MY_EVENT(ev));
return 0;
}
static int my_event_add(struct ub_event* ub_ev, struct timeval* tv)
{
my_event *ev = AS_MY_EVENT(ub_ev);
#ifdef USE_WINSOCK
int t, l = sizeof(t);
#endif
if (ev->added)
my_event_del(&ev->super);
if (tv && (ev->bits & UB_EV_TIMEOUT) != 0)
ev->timeout = (tv->tv_sec * 1000) + (tv->tv_usec / 1000);
#ifdef USE_WINSOCK
if ((ev->bits & (UB_EV_READ|UB_EV_WRITE)) && ev->fd != -1 &&
getsockopt(ev->fd, SOL_SOCKET, SO_TYPE, (void *)&t, &l) == 0 &&
t == SOCK_STREAM) {
ev->is_tcp = 1;
ev->read_wouldblock = 0;
ev->write_wouldblock = 0;
} else
ev->is_tcp = 0;
#endif
if (schedule_my_event(AS_MY_EVENT(ev)))
return -1;
return 0;
}
static int my_timer_add(struct ub_event* ub_ev, struct ub_event_base* base,
void (*cb)(int, short, void*), void* arg, struct timeval* tv)
{
my_event *ev = AS_MY_EVENT(ub_ev);
if (!base || !cb || !tv || AS_UB_LOOP(base) != ev->loop)
return -1;
if (ev->added)
CLEAR_MY_EVENT(ev);
ev->cb = cb;
ev->arg = arg;
return my_event_add(ub_ev, tv);
}
static int my_timer_del(struct ub_event* ev)
{
return my_event_del(ev);
}
static int my_signal_add(struct ub_event* ub_ev, struct timeval* tv)
{
/* Only unbound daaemon workers use signals */
return -1;
}
static int my_signal_del(struct ub_event* ub_ev)
{
/* Only unbound daaemon workers use signals */
return -1;
}
static void my_winsock_unregister_wsaevent(struct ub_event* ev)
{
/* wsa events don't get registered with libunbound */
(void)ev;
}
static void my_winsock_tcp_wouldblock(struct ub_event* ev, int bits)
{
#ifndef USE_WINSOCK
(void)ev; (void)bits;
#else
if (bits & UB_EV_READ)
AS_MY_EVENT(ev)->read_wouldblock = 1;
if (bits & UB_EV_WRITE)
AS_MY_EVENT(ev)->write_wouldblock = 1;
#endif
}
static struct ub_event* my_event_new(struct ub_event_base* base, int fd,
short bits, void (*cb)(int, short, void*), void* arg)
{
static struct ub_event_vmt vmt = {
my_event_add_bits,
my_event_del_bits,
my_event_set_fd,
my_event_free,
my_event_add,
my_event_del,
my_timer_add,
my_timer_del,
my_signal_add,
my_signal_del,
my_winsock_unregister_wsaevent,
my_winsock_tcp_wouldblock
};
my_event *ev;
if (!base || !cb)
return NULL;
ev = GETDNS_MALLOC(AS_UB_LOOP(base)->mf, my_event);
ev->super.magic = UB_EVENT_API_MAGIC;
ev->super.vmt = &vmt;
ev->loop = AS_UB_LOOP(base);
ev->added = 0;
ev->fd = fd;
ev->bits = bits;
ev->timeout = (uint64_t)-1;
ev->cb = cb;
ev->arg = arg;
#ifdef USE_WINSOCK
ev->is_tcp = 0;
ev->read_wouldblock = 0;
ev->write_wouldblock = 0;
#endif
ev->active = NULL;
ev->gev.userarg = ev;
ev->gev.read_cb = bits & UB_EV_READ ? read_cb : NULL;
ev->gev.write_cb = bits & UB_EV_WRITE ? write_cb : NULL;
ev->gev.timeout_cb = bits & UB_EV_TIMEOUT ? timeout_cb : NULL;
return &ev->super;
}
static struct ub_event* my_signal_new(struct ub_event_base* base, int fd,
void (*cb)(int, short, void*), void* arg)
{
/* Not applicable, because in unbound used in the daemon only */
(void)base; (void)fd; (void)cb; (void)arg;
return NULL;
}
static struct ub_event* my_winsock_register_wsaevent(struct ub_event_base *b,
void* wsaevent, void (*cb)(int, short, void*), void* arg)
{
/* Not applicable, because in unbound used for tubes only */
(void)b; (void)wsaevent; (void)cb; (void)arg;
return NULL;
}
void _getdns_ub_loop_init(_getdns_ub_loop *loop, struct mem_funcs *mf, getdns_eventloop *extension)
{
static struct ub_event_base_vmt vmt = {
my_event_base_free,
my_event_base_dispatch,
my_event_base_loopexit,
my_event_new,
my_signal_new,
my_winsock_register_wsaevent
};
loop->super.magic = UB_EVENT_API_MAGIC;
loop->super.vmt = &vmt;
loop->mf = *mf;
loop->extension = extension;
loop->running = 1;
}
#endif
/* ub_loop.c */

73
src/ub_loop.h Normal file
View File

@ -0,0 +1,73 @@
/**
*
* \file ub_loop.h
* /brief Interface for the pluggable unbound event API
*
*/
/*
* Copyright (c) 2015, 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.
*/
#ifndef UB_LOOP_H
#define UB_LOOP_H
#include "config.h"
#ifdef HAVE_UNBOUND_EVENT_API
#include "getdns/getdns.h"
#include "getdns/getdns_extra.h"
#include "types-internal.h"
#ifdef HAVE_UNBOUND_EVENT_H
#include <unbound-event.h>
#else
struct ub_event_base_vmt;
struct ub_event_base {
unsigned long magic;
struct ub_event_base_vmt* vmt;
};
struct ub_event_base;
struct ub_ctx* ub_ctx_create_ub_event(struct ub_event_base* base);
typedef void (*ub_event_callback_t)(void*, int, void*, int, int, char*);
int ub_resolve_event(struct ub_ctx* ctx, const char* name, int rrtype,
int rrclass, void* mydata, ub_event_callback_t callback, int* async_id);
#endif
typedef struct _getdns_ub_loop {
struct ub_event_base super;
struct mem_funcs mf;
getdns_eventloop *extension;
int running;
} _getdns_ub_loop;
void _getdns_ub_loop_init(_getdns_ub_loop *loop, struct mem_funcs *mf, getdns_eventloop *extension);
inline static int _getdns_ub_loop_enabled(_getdns_ub_loop *loop)
{ return loop->super.vmt ? 1 : 0; }
#endif /* HAVE_UNBOUND_EVENT_API */
#endif
/* ub_loop.h */

View File

@ -271,7 +271,7 @@ _getdns_rr_iter2rr_dict(struct mem_funcs *mf, _getdns_rr_iter *i)
} else if (rdf->rdd_pos->type == GETDNS_RDF_SPECIAL)
val_type = wf_special;
else
assert(0);
assert(((val_type = wf_int), 0));
if (! rdf->rdd_repeat) {
switch (val_type) {
@ -1020,30 +1020,24 @@ error_free_result:
#ifdef HAVE_LIBUNBOUND
getdns_return_t
getdns_apply_network_result(getdns_network_req* netreq,
struct ub_result* ub_res)
int rcode, void *pkt, int pkt_len, int sec, char* why_bogus)
{
if (ub_res->bogus)
netreq->dnssec_status = GETDNS_DNSSEC_BOGUS;
else if (ub_res->secure)
netreq->dnssec_status = GETDNS_DNSSEC_SECURE;
else if (netreq->owner->context->trust_anchors)
netreq->dnssec_status = GETDNS_DNSSEC_INSECURE;
netreq->dnssec_status = sec == 0 ? GETDNS_DNSSEC_INSECURE
: sec == 2 ? GETDNS_DNSSEC_SECURE
: GETDNS_DNSSEC_BOGUS;
if (ub_res == NULL) /* Timeout */
return GETDNS_RETURN_GOOD;
if (ub_res->answer_packet) {
if (netreq->max_udp_payload_size < ub_res->answer_len)
if (pkt) {
if (netreq->max_udp_payload_size < pkt_len)
netreq->response = GETDNS_XMALLOC(
netreq->owner->context->mf,
uint8_t, ub_res->answer_len
uint8_t, pkt_len
);
(void) memcpy(netreq->response, ub_res->answer_packet,
(netreq->response_len = ub_res->answer_len));
(void) memcpy(netreq->response, pkt,
(netreq->response_len = pkt_len));
return GETDNS_RETURN_GOOD;
}
if (ub_res->rcode == GETDNS_RCODE_SERVFAIL) {
if (rcode == GETDNS_RCODE_SERVFAIL) {
/* Likely to be caused by timeout from a synchronous
* lookup. Don't forge a packet.
*/
@ -1064,7 +1058,7 @@ getdns_apply_network_result(getdns_network_req* netreq,
GLDNS_QR_SET(netreq->response);
GLDNS_RD_SET(netreq->response);
GLDNS_RA_SET(netreq->response);
GLDNS_RCODE_SET(netreq->response, ub_res->rcode);
GLDNS_RCODE_SET(netreq->response, rcode);
(void) memcpy( netreq->response + GLDNS_HEADER_SIZE
, netreq->owner->name, netreq->owner->name_len);

View File

@ -56,7 +56,8 @@
struct ub_result;
struct getdns_network_req;
getdns_return_t getdns_apply_network_result(getdns_network_req* netreq, struct ub_result* result);
getdns_return_t getdns_apply_network_result(getdns_network_req* netreq,
int rcode, void *pkt, int pkt_len, int sec, char* why_bogus);
#define GETDNS_MAX_DNAME_LEN 255
#define GETDNS_MAX_LABEL_LEN 63

View File

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

View File

@ -1,394 +0,0 @@
/*
* mini_event.c - implementation of part of libevent api, portably.
*
* Copyright (c) 2007, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* \file
* fake libevent implementation. Less broad in functionality, and only
* supports select(2).
*/
#include "config.h"
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#include <sys/time.h>
#if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK)
#include <signal.h>
#include "util/mini_event.h"
#include "util/fptr_wlist.h"
/** compare events in tree, based on timevalue, ptr for uniqueness */
int _getdns_mini_ev_cmp(const void* a, const void* b)
{
const struct _getdns_event *e = (const struct _getdns_event*)a;
const struct _getdns_event *f = (const struct _getdns_event*)b;
if(e->ev_timeout.tv_sec < f->ev_timeout.tv_sec)
return -1;
if(e->ev_timeout.tv_sec > f->ev_timeout.tv_sec)
return 1;
if(e->ev_timeout.tv_usec < f->ev_timeout.tv_usec)
return -1;
if(e->ev_timeout.tv_usec > f->ev_timeout.tv_usec)
return 1;
if(e < f)
return -1;
if(e > f)
return 1;
return 0;
}
/** set time */
static int
settime(struct _getdns_event_base* base)
{
if(gettimeofday(base->time_tv, NULL) < 0) {
return -1;
}
#ifndef S_SPLINT_S
*base->time_secs = (time_t)base->time_tv->tv_sec;
#endif
return 0;
}
/** create event base */
void *_getdns_event_init(time_t* time_secs, struct timeval* time_tv)
{
struct _getdns_event_base* base = (struct _getdns_event_base*)malloc(
sizeof(struct _getdns_event_base));
if(!base)
return NULL;
memset(base, 0, sizeof(*base));
base->time_secs = time_secs;
base->time_tv = time_tv;
if(settime(base) < 0) {
_getdns_event_base_free(base);
return NULL;
}
base->times = _getdns_rbtree_create(_getdns_mini_ev_cmp);
if(!base->times) {
_getdns_event_base_free(base);
return NULL;
}
base->capfd = MAX_FDS;
#ifdef FD_SETSIZE
if((int)FD_SETSIZE < base->capfd)
base->capfd = (int)FD_SETSIZE;
#endif
base->fds = (struct _getdns_event**)calloc((size_t)base->capfd,
sizeof(struct _getdns_event*));
if(!base->fds) {
_getdns_event_base_free(base);
return NULL;
}
base->signals = (struct _getdns_event**)calloc(MAX_SIG, sizeof(struct _getdns_event*));
if(!base->signals) {
_getdns_event_base_free(base);
return NULL;
}
#ifndef S_SPLINT_S
FD_ZERO(&base->reads);
FD_ZERO(&base->writes);
#endif
return base;
}
/** get version */
const char *_getdns_event_get_version(void)
{
return "mini-event-"PACKAGE_VERSION;
}
/** get polling method, select */
const char *_getdns_event_get_method(void)
{
return "select";
}
/** call timeouts handlers, and return how long to wait for next one or -1 */
void _getdns_handle_timeouts(struct _getdns_event_base* base, struct timeval* now,
struct timeval* wait)
{
struct _getdns_event* p;
#ifndef S_SPLINT_S
wait->tv_sec = (time_t)-1;
#endif
while((_getdns_rbnode_t*)(p = (struct _getdns_event*)_getdns_rbtree_first(base->times))
!=RBTREE_NULL) {
#ifndef S_SPLINT_S
if(p->ev_timeout.tv_sec > now->tv_sec ||
(p->ev_timeout.tv_sec==now->tv_sec &&
p->ev_timeout.tv_usec > now->tv_usec)) {
/* there is a next larger timeout. wait for it */
wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec;
if(now->tv_usec > p->ev_timeout.tv_usec) {
wait->tv_sec--;
wait->tv_usec = 1000000 - (now->tv_usec -
p->ev_timeout.tv_usec);
} else {
wait->tv_usec = p->ev_timeout.tv_usec
- now->tv_usec;
}
return;
}
#endif
/* event times out, remove it */
(void)_getdns_rbtree_delete(base->times, p);
p->ev_events &= ~EV_TIMEOUT;
fptr_ok(fptr_whitelist_event(p->ev_callback));
(*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg);
}
}
/** call select and callbacks for that */
int _getdns_handle_select(struct _getdns_event_base* base, struct timeval* wait)
{
fd_set r, w;
int ret, i;
#ifndef S_SPLINT_S
if(wait->tv_sec==(time_t)-1)
wait = NULL;
#endif
memmove(&r, &base->reads, sizeof(fd_set));
memmove(&w, &base->writes, sizeof(fd_set));
memmove(&base->ready, &base->content, sizeof(fd_set));
if((ret = select(base->maxfd+1, &r, &w, NULL, wait)) == -1) {
ret = errno;
if(settime(base) < 0)
return -1;
errno = ret;
if(ret == EAGAIN || ret == EINTR)
return 0;
return -1;
}
if(settime(base) < 0)
return -1;
for(i=0; i<base->maxfd+1; i++) {
short bits = 0;
if(!base->fds[i] || !(FD_ISSET(i, &base->ready))) {
continue;
}
if(FD_ISSET(i, &r)) {
bits |= EV_READ;
ret--;
}
if(FD_ISSET(i, &w)) {
bits |= EV_WRITE;
ret--;
}
bits &= base->fds[i]->ev_events;
if(bits) {
fptr_ok(fptr_whitelist_event(
base->fds[i]->ev_callback));
(*base->fds[i]->ev_callback)(base->fds[i]->ev_fd,
bits, base->fds[i]->ev_arg);
if(ret==0)
break;
}
}
return 0;
}
/** run select in a loop */
int _getdns_event_base_dispatch(struct _getdns_event_base* base)
{
struct timeval wait;
if(settime(base) < 0)
return -1;
while(!base->need_to_exit)
{
/* see if timeouts need handling */
_getdns_handle_timeouts(base, base->time_tv, &wait);
if(base->need_to_exit)
return 0;
/* do select */
if(_getdns_handle_select(base, &wait) < 0) {
if(base->need_to_exit)
return 0;
return -1;
}
}
return 0;
}
/** exit that loop */
int _getdns_event_base_loopexit(struct _getdns_event_base* base,
struct timeval* ATTR_UNUSED(tv))
{
base->need_to_exit = 1;
return 0;
}
/* free event base, free events yourself */
void _getdns_event_base_free(struct _getdns_event_base* base)
{
if(!base)
return;
if(base->times)
free(base->times);
if(base->fds)
free(base->fds);
if(base->signals)
free(base->signals);
free(base);
}
/** set content of event */
void _getdns_event_set(struct _getdns_event* ev, int fd, short bits,
void (*cb)(int, short, void *), void* arg)
{
ev->node.key = ev;
ev->ev_fd = fd;
ev->ev_events = bits;
ev->ev_callback = cb;
fptr_ok(fptr_whitelist_event(ev->ev_callback));
ev->ev_arg = arg;
ev->added = 0;
}
/* add event to a base */
int _getdns_event_base_set(struct _getdns_event_base* base, struct _getdns_event* ev)
{
ev->ev_base = base;
ev->added = 0;
return 0;
}
/* add event to make it active, you may not change it with _getdns_event_set anymore */
int _getdns_event_add(struct _getdns_event* ev, struct timeval* tv)
{
if(ev->added)
_getdns_event_del(ev);
if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd)
return -1;
if( (ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
ev->ev_base->fds[ev->ev_fd] = ev;
if(ev->ev_events&EV_READ) {
FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->reads);
}
if(ev->ev_events&EV_WRITE) {
FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->writes);
}
FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->content);
FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready);
if(ev->ev_fd > ev->ev_base->maxfd)
ev->ev_base->maxfd = ev->ev_fd;
}
if(tv && (ev->ev_events&EV_TIMEOUT)) {
#ifndef S_SPLINT_S
struct timeval *now = ev->ev_base->time_tv;
ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec;
ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec;
while(ev->ev_timeout.tv_usec > 1000000) {
ev->ev_timeout.tv_usec -= 1000000;
ev->ev_timeout.tv_sec++;
}
#endif
(void)_getdns_rbtree_insert(ev->ev_base->times, &ev->node);
}
ev->added = 1;
return 0;
}
/* remove event, you may change it again */
int _getdns_event_del(struct _getdns_event* ev)
{
if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd)
return -1;
if((ev->ev_events&EV_TIMEOUT))
(void)_getdns_rbtree_delete(ev->ev_base->times, &ev->node);
if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
ev->ev_base->fds[ev->ev_fd] = NULL;
FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->reads);
FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->writes);
FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready);
FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->content);
}
ev->added = 0;
return 0;
}
/** which base gets to handle signals */
static struct _getdns_event_base* signal_base = NULL;
/** signal handler */
static RETSIGTYPE sigh(int sig)
{
struct _getdns_event* ev;
if(!signal_base || sig < 0 || sig >= MAX_SIG)
return;
ev = signal_base->signals[sig];
if(!ev)
return;
fptr_ok(fptr_whitelist_event(ev->ev_callback));
(*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg);
}
/** install signal handler */
int _getdns_signal_add(struct _getdns_event* ev, struct timeval* ATTR_UNUSED(tv))
{
if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
return -1;
signal_base = ev->ev_base;
ev->ev_base->signals[ev->ev_fd] = ev;
ev->added = 1;
if(signal(ev->ev_fd, sigh) == SIG_ERR) {
return -1;
}
return 0;
}
/** remove signal handler */
int _getdns_signal_del(struct _getdns_event* ev)
{
if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
return -1;
ev->ev_base->signals[ev->ev_fd] = NULL;
ev->added = 0;
return 0;
}
#else /* USE_MINI_EVENT */
#ifndef USE_WINSOCK
int _getdns_mini_ev_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
{
return 0;
}
#endif /* not USE_WINSOCK */
#endif /* USE_MINI_EVENT */

View File

@ -1,178 +0,0 @@
/*
* mini-event.h - micro implementation of libevent api, using select() only.
*
* Copyright (c) 2007, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
* This file implements part of the event(3) libevent api.
* The back end is only select. Max number of fds is limited.
* Max number of signals is limited, one handler per signal only.
* And one handler per fd.
*
* Although limited to select() and a max (1024) open fds, it
* is efficient:
* o dispatch call caches fd_sets to use.
* o handler calling takes time ~ to the number of fds.
* o timeouts are stored in a redblack tree, sorted, so take log(n).
* Timeouts are only accurate to the second (no subsecond accuracy).
* To avoid cpu hogging, fractional timeouts are rounded up to a whole second.
*/
#ifndef MINI_EVENT_H
#define MINI_EVENT_H
#if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK)
#ifndef HAVE_EVENT_BASE_FREE
#define HAVE_EVENT_BASE_FREE
#endif
/** event timeout */
#define EV_TIMEOUT 0x01
/** event fd readable */
#define EV_READ 0x02
/** event fd writable */
#define EV_WRITE 0x04
/** event signal */
#define EV_SIGNAL 0x08
/** event must persist */
#define EV_PERSIST 0x10
/* needs our redblack tree */
#include "util/rbtree.h"
/** max number of file descriptors to support */
#define MAX_FDS 1024
/** max number of signals to support */
#define MAX_SIG 32
/** event base */
struct _getdns_event_base
{
/** sorted by timeout (absolute), ptr */
_getdns_rbtree_t* times;
/** array of 0 - maxfd of ptr to event for it */
struct _getdns_event** fds;
/** max fd in use */
int maxfd;
/** capacity - size of the fds array */
int capfd;
/* fdset for read write, for fds ready, and added */
fd_set
/** fds for reading */
reads,
/** fds for writing */
writes,
/** fds determined ready for use */
ready,
/** ready plus newly added events. */
content;
/** array of 0 - maxsig of ptr to event for it */
struct _getdns_event** signals;
/** if we need to exit */
int need_to_exit;
/** where to store time in seconds */
time_t* time_secs;
/** where to store time in microseconds */
struct timeval* time_tv;
};
/**
* Event structure. Has some of the event elements.
*/
struct _getdns_event {
/** node in timeout rbtree */
_getdns_rbnode_t node;
/** is event already added */
int added;
/** event base it belongs to */
struct _getdns_event_base *ev_base;
/** fd to poll or -1 for timeouts. signal number for sigs. */
int ev_fd;
/** what events this event is interested in, see EV_.. above. */
short ev_events;
/** timeout value */
struct timeval ev_timeout;
/** callback to call: fd, eventbits, userarg */
void (*ev_callback)(int, short, void *arg);
/** callback user arg */
void *ev_arg;
};
/* function prototypes (some are as they appear in event.h) */
/** create event base */
void *_getdns_event_init(time_t* time_secs, struct timeval* time_tv);
/** get version */
const char *_getdns_event_get_version(void);
/** get polling method, select */
const char *_getdns_event_get_method(void);
/** run select in a loop */
int _getdns_event_base_dispatch(struct _getdns_event_base *);
/** exit that loop */
int _getdns_event_base_loopexit(struct _getdns_event_base *, struct timeval *);
/** free event base. Free events yourself */
void _getdns_event_base_free(struct _getdns_event_base *);
/** set content of event */
void _getdns_event_set(struct _getdns_event *, int, short, void (*)(int, short, void *), void *);
/** add event to a base. You *must* call this for every event. */
int _getdns_event_base_set(struct _getdns_event_base *, struct _getdns_event *);
/** add event to make it active. You may not change it with _getdns_event_set anymore */
int _getdns_event_add(struct _getdns_event *, struct timeval *);
/** remove event. You may change it again */
int _getdns_event_del(struct _getdns_event *);
/** add a timer */
#define _getdns_evtimer_add(ev, tv) _getdns_event_add(ev, tv)
/** remove a timer */
#define _getdns_evtimer_del(ev) _getdns_event_del(ev)
/* uses different implementation. Cannot mix fd/timeouts and signals inside
* the same struct _getdns_event. create several event structs for that. */
/** install signal handler */
int _getdns_signal_add(struct _getdns_event *, struct timeval *);
/** set signal event contents */
#define _getdns_signal_set(ev, x, cb, arg) \
_getdns_event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg)
/** remove signal handler */
int _getdns_signal_del(struct _getdns_event *);
#endif /* USE_MINI_EVENT and not USE_WINSOCK */
/** compare events in tree, based on timevalue, ptr for uniqueness */
int _getdns_mini_ev_cmp(const void* a, const void* b);
#endif /* MINI_EVENT_H */

View File

@ -1,844 +0,0 @@
/*
* util/winsock_event.c - implementation of the getdns winsock event handler.
*
* Copyright (c) 2015, Verisign/NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS/Verisign nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
* Implementation of the getdns WinSock2 API event notification handler
* for the getdns Windows port.
* Code is originally from the Unbound source for Windows.
*/
#include "config.h"
#ifdef USE_WINSOCK // only included for Windows builds
#include <signal.h>
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#include <sys/time.h>
#include "util/winsock_event.h"
#include "util/fptr_wlist.h"
/**
* implementation of log_err
* @param format: format string printf-style.
*/
void
log_err(const char *format, ...)
{
va_list args;
va_start(args, format);
fprintf(stderr, "error ");
fprintf(stderr, format, args);
va_end(args);
}
char* wsa_strerror(DWORD err)
{
static char unknown[32];
switch (err) {
case WSA_INVALID_HANDLE: return "Specified event object handle is invalid.";
case WSA_NOT_ENOUGH_MEMORY: return "Insufficient memory available.";
case WSA_INVALID_PARAMETER: return "One or more parameters are invalid.";
case WSA_OPERATION_ABORTED: return "Overlapped operation aborted.";
case WSA_IO_INCOMPLETE: return "Overlapped I/O event object not in signaled state.";
case WSA_IO_PENDING: return "Overlapped operations will complete later.";
case WSAEINTR: return "Interrupted function call.";
case WSAEBADF: return "File handle is not valid.";
case WSAEACCES: return "Permission denied.";
case WSAEFAULT: return "Bad address.";
case WSAEINVAL: return "Invalid argument.";
case WSAEMFILE: return "Too many open files.";
case WSAEWOULDBLOCK: return "Resource temporarily unavailable.";
case WSAEINPROGRESS: return "Operation now in progress.";
case WSAEALREADY: return "Operation already in progress.";
case WSAENOTSOCK: return "Socket operation on nonsocket.";
case WSAEDESTADDRREQ: return "Destination address required.";
case WSAEMSGSIZE: return "Message too long.";
case WSAEPROTOTYPE: return "Protocol wrong type for socket.";
case WSAENOPROTOOPT: return "Bad protocol option.";
case WSAEPROTONOSUPPORT: return "Protocol not supported.";
case WSAESOCKTNOSUPPORT: return "Socket type not supported.";
case WSAEOPNOTSUPP: return "Operation not supported.";
case WSAEPFNOSUPPORT: return "Protocol family not supported.";
case WSAEAFNOSUPPORT: return "Address family not supported by protocol family.";
case WSAEADDRINUSE: return "Address already in use.";
case WSAEADDRNOTAVAIL: return "Cannot assign requested address.";
case WSAENETDOWN: return "Network is down.";
case WSAENETUNREACH: return "Network is unreachable.";
case WSAENETRESET: return "Network dropped connection on reset.";
case WSAECONNABORTED: return "Software caused connection abort.";
case WSAECONNRESET: return "Connection reset by peer.";
case WSAENOBUFS: return "No buffer space available.";
case WSAEISCONN: return "Socket is already connected.";
case WSAENOTCONN: return "Socket is not connected.";
case WSAESHUTDOWN: return "Cannot send after socket shutdown.";
case WSAETOOMANYREFS: return "Too many references.";
case WSAETIMEDOUT: return "Connection timed out.";
case WSAECONNREFUSED: return "Connection refused.";
case WSAELOOP: return "Cannot translate name.";
case WSAENAMETOOLONG: return "Name too long.";
case WSAEHOSTDOWN: return "Host is down.";
case WSAEHOSTUNREACH: return "No route to host.";
case WSAENOTEMPTY: return "Directory not empty.";
case WSAEPROCLIM: return "Too many processes.";
case WSAEUSERS: return "User quota exceeded.";
case WSAEDQUOT: return "Disk quota exceeded.";
case WSAESTALE: return "Stale file handle reference.";
case WSAEREMOTE: return "Item is remote.";
case WSASYSNOTREADY: return "Network subsystem is unavailable.";
case WSAVERNOTSUPPORTED: return "Winsock.dll version out of range.";
case WSANOTINITIALISED: return "Successful WSAStartup not yet performed.";
case WSAEDISCON: return "Graceful shutdown in progress.";
case WSAENOMORE: return "No more results.";
case WSAECANCELLED: return "Call has been canceled.";
case WSAEINVALIDPROCTABLE: return "Procedure call table is invalid.";
case WSAEINVALIDPROVIDER: return "Service provider is invalid.";
case WSAEPROVIDERFAILEDINIT: return "Service provider failed to initialize.";
case WSASYSCALLFAILURE: return "System call failure.";
case WSASERVICE_NOT_FOUND: return "Service not found.";
case WSATYPE_NOT_FOUND: return "Class type not found.";
case WSA_E_NO_MORE: return "No more results.";
case WSA_E_CANCELLED: return "Call was canceled.";
case WSAEREFUSED: return "Database query was refused.";
case WSAHOST_NOT_FOUND: return "Host not found.";
case WSATRY_AGAIN: return "Nonauthoritative host not found.";
case WSANO_RECOVERY: return "This is a nonrecoverable error.";
case WSANO_DATA: return "Valid name, no data record of requested type.";
case WSA_QOS_RECEIVERS: return "QOS receivers.";
case WSA_QOS_SENDERS: return "QOS senders.";
case WSA_QOS_NO_SENDERS: return "No QOS senders.";
case WSA_QOS_NO_RECEIVERS: return "QOS no receivers.";
case WSA_QOS_REQUEST_CONFIRMED: return "QOS request confirmed.";
case WSA_QOS_ADMISSION_FAILURE: return "QOS admission error.";
case WSA_QOS_POLICY_FAILURE: return "QOS policy failure.";
case WSA_QOS_BAD_STYLE: return "QOS bad style.";
case WSA_QOS_BAD_OBJECT: return "QOS bad object.";
case WSA_QOS_TRAFFIC_CTRL_ERROR: return "QOS traffic control error.";
case WSA_QOS_GENERIC_ERROR: return "QOS generic error.";
case WSA_QOS_ESERVICETYPE: return "QOS service type error.";
case WSA_QOS_EFLOWSPEC: return "QOS flowspec error.";
case WSA_QOS_EPROVSPECBUF: return "Invalid QOS provider buffer.";
case WSA_QOS_EFILTERSTYLE: return "Invalid QOS filter style.";
case WSA_QOS_EFILTERTYPE: return "Invalid QOS filter type.";
case WSA_QOS_EFILTERCOUNT: return "Incorrect QOS filter count.";
case WSA_QOS_EOBJLENGTH: return "Invalid QOS object length.";
case WSA_QOS_EFLOWCOUNT: return "Incorrect QOS flow count.";
/*case WSA_QOS_EUNKOWNPSOBJ: return "Unrecognized QOS object.";*/
case WSA_QOS_EPOLICYOBJ: return "Invalid QOS policy object.";
case WSA_QOS_EFLOWDESC: return "Invalid QOS flow descriptor.";
case WSA_QOS_EPSFLOWSPEC: return "Invalid QOS provider-specific flowspec.";
case WSA_QOS_EPSFILTERSPEC: return "Invalid QOS provider-specific filterspec.";
case WSA_QOS_ESDMODEOBJ: return "Invalid QOS shape discard mode object.";
case WSA_QOS_ESHAPERATEOBJ: return "Invalid QOS shaping rate object.";
case WSA_QOS_RESERVED_PETYPE: return "Reserved policy QOS element type.";
default:
snprintf(unknown, sizeof(unknown),
"unknown WSA error code %d", (int)err);
return unknown;
}
}
int _getdns_mini_ev_cmp(const void* a, const void* b)
{
const struct _getdns_event *e = (const struct _getdns_event*)a;
const struct _getdns_event *f = (const struct _getdns_event*)b;
if(e->ev_timeout.tv_sec < f->ev_timeout.tv_sec)
return -1;
if(e->ev_timeout.tv_sec > f->ev_timeout.tv_sec)
return 1;
if(e->ev_timeout.tv_usec < f->ev_timeout.tv_usec)
return -1;
if(e->ev_timeout.tv_usec > f->ev_timeout.tv_usec)
return 1;
if(e < f)
return -1;
if(e > f)
return 1;
return 0;
}
/** set time */
static int
settime(struct _getdns_event_base* base)
{
if(gettimeofday(base->time_tv, NULL) < 0) {
return -1;
}
#ifndef S_SPLINT_S
*base->time_secs = (time_t)base->time_tv->tv_sec;
#endif
return 0;
}
#ifdef WINSOCK_DEBUG
/**
* Find a fd in the list of items.
* Note that not all items have a fd associated (those are -1).
* Signals are stored separately, and not searched.
* @param base: event base to look in.
* @param fd: what socket to look for.
* @return the index in the array, or -1 on failure.
*/
static int
find_fd(struct _getdns_event_base* base, int fd)
{
int i;
for(i=0; i<base->max; i++) {
if(base->items[i]->ev_fd == fd)
return i;
}
return -1;
}
#endif
/** Find ptr in base array */
static void
zero_waitfor(WSAEVENT waitfor[], WSAEVENT x)
{
int i;
for(i=0; i<WSK_MAX_ITEMS; i++) {
if(waitfor[i] == x)
waitfor[i] = 0;
}
}
void *_getdns_event_init(time_t* time_secs, struct timeval* time_tv)
{
struct _getdns_event_base* base = (struct _getdns_event_base*)malloc(
sizeof(struct _getdns_event_base));
if(!base)
return NULL;
memset(base, 0, sizeof(*base));
base->time_secs = time_secs;
base->time_tv = time_tv;
if(settime(base) < 0) {
_getdns_event_base_free(base);
return NULL;
}
base->items = (struct _getdns_event**)calloc(WSK_MAX_ITEMS,
sizeof(struct _getdns_event*));
if(!base->items) {
_getdns_event_base_free(base);
return NULL;
}
base->cap = WSK_MAX_ITEMS;
base->max = 0;
base->times = _getdns_rbtree_create(_getdns_mini_ev_cmp);
if(!base->times) {
_getdns_event_base_free(base);
return NULL;
}
base->signals = (struct _getdns_event**)calloc(MAX_SIG,
sizeof(struct _getdns_event*));
if(!base->signals) {
_getdns_event_base_free(base);
return NULL;
}
base->tcp_stickies = 0;
base->tcp_reinvigorated = 0;
return base;
}
const char *_getdns_event_get_version(void)
{
return "winsock-event-"PACKAGE_VERSION;
}
const char *_getdns_event_get_method(void)
{
return "WSAWaitForMultipleEvents";
}
/** call timeouts handlers, and return how long to wait for next one or -1 */
void _getdns_handle_timeouts(struct _getdns_event_base* base, struct timeval* now,
struct timeval* wait)
{
struct _getdns_event* p;
#ifndef S_SPLINT_S
wait->tv_sec = (time_t)-1;
#endif
while((_getdns_rbnode_t*)(p = (struct _getdns_event*)_getdns_rbtree_first(base->times))
!=RBTREE_NULL) {
#ifndef S_SPLINT_S
if(p->ev_timeout.tv_sec > now->tv_sec ||
(p->ev_timeout.tv_sec==now->tv_sec &&
p->ev_timeout.tv_usec > now->tv_usec)) {
/* there is a next larger timeout. wait for it */
wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec;
if(now->tv_usec > p->ev_timeout.tv_usec) {
wait->tv_sec--;
wait->tv_usec = 1000000 - (now->tv_usec -
p->ev_timeout.tv_usec);
} else {
wait->tv_usec = p->ev_timeout.tv_usec
- now->tv_usec;
}
return;
}
#endif
/* event times out, remove it */
(void)_getdns_rbtree_delete(base->times, p);
p->ev_events &= ~EV_TIMEOUT;
fptr_ok(fptr_whitelist_event(p->ev_callback));
(*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg);
}
}
/** handle is_signal events and see if signalled */
static void _getdns_handle_signal(struct _getdns_event* ev)
{
printf("In _getdns_handle_signal\n");
DWORD ret;
//log_assert(ev->is_signal && ev->hEvent);
/* see if the event is signalled */
ret = WSAWaitForMultipleEvents(1, &ev->hEvent, 0 /* any object */,
0 /* return immediately */, 0 /* not alertable for IOcomple*/);
if(ret == WSA_WAIT_IO_COMPLETION || ret == WSA_WAIT_FAILED) {
log_err("getdns: WSAWaitForMultipleEvents(signal) failed: %s",
wsa_strerror(WSAGetLastError()));
return;
}
if(ret == WSA_WAIT_TIMEOUT) {
/* not signalled */
return;
}
/* reset the signal */
if(!WSAResetEvent(ev->hEvent))
log_err("getdns: WSAResetEvent failed: %s",
wsa_strerror(WSAGetLastError()));
/* do the callback (which may set the signal again) */
fptr_ok(fptr_whitelist_event(ev->ev_callback));
(*ev->ev_callback)(ev->ev_fd, ev->ev_events, ev->ev_arg);
}
/** call select and callbacks for that */
int _getdns_handle_select(struct _getdns_event_base* base, struct timeval* wait)
{
DWORD timeout = 0; /* in milliseconds */
DWORD ret;
WSANETWORKEVENTS netev;
struct _getdns_event* eventlist[WSK_MAX_ITEMS];
int i, numwait = 0, startidx = 0;
int newstickies = 0;
struct timeval nultm;
#ifndef S_SPLINT_S
if(wait->tv_sec==(time_t)-1)
wait = NULL;
if (wait)
// timeout = 10 + wait->tv_usec / 1000;
timeout = wait->tv_sec * 1000 + wait->tv_usec / 1000;
if(base->tcp_stickies) {
wait = &nultm;
nultm.tv_sec = 0;
nultm.tv_usec = 0;
timeout = 0; /* no waiting, we have sticky events */
}
#endif
/* prepare event array */
for(i=0; i<base->max; i++) {
if(base->items[i]->ev_fd == -1 && !base->items[i]->is_signal)
continue; /* skip timer only events */
eventlist[numwait] = base->items[i];
base->waitfor[numwait++] = base->items[i]->hEvent;
printf("winsock_event bmax=%d numwait=%d wait=%x "
"timeout=%d hEvent %d\n", base->max, numwait, (int)wait,
(int)timeout, (int)base->items[i]->hEvent);
if (numwait == WSK_MAX_ITEMS)
break; /* sanity check */
}
//log_assert(numwait <= WSA_MAXIMUM_WAIT_EVENTS);
/* do the wait */
if(numwait == 0) {
/* WSAWaitFor.. doesn't like 0 event objects */
if(wait) {
Sleep(timeout);
}
}
else {
//gv: do not schedule udp write
for (i = 0; i<base->max; i++) {
if (!base->items[i]->is_tcp && base->items[i]->ev_events&EV_WRITE) {
printf("skip UDP sched\n");
(*eventlist[i]->ev_callback)(eventlist[i]->ev_fd,
EV_WRITE & eventlist[i]->ev_events,
eventlist[i]->ev_arg);
return 0;
}
}
printf("before wait %d\n", base->items[0]->ev_events);
ret = WSAWaitForMultipleEvents(numwait, base->waitfor,
0 /* do not wait for all, just one will do */,
wait?timeout:WSA_INFINITE,
0); /* we are not alertable (IO completion events) */
printf("after wait %d %d\n", (int)ret, numwait);
if(ret == WSA_WAIT_IO_COMPLETION) {
//printf("getdns: WSAWaitForMultipleEvents failed: WSA_WAIT_IO_COMPLETION");
return -1;
} else if(ret == WSA_WAIT_FAILED) {
//printf("getdns: WSAWaitForMultipleEvents failed: %s",
// wsa_strerror(WSAGetLastError()));
return -1;
} else if(ret == WSA_WAIT_TIMEOUT) {
printf("timeout\n");
} else
startidx = ret - WSA_WAIT_EVENT_0;
}
////verbose(VERB_CLIENT, "winsock_event wake was_timeout=%d startidx=%d",
// was_timeout, startidx);
/* get new time after wait */
if(settime(base) < 0)
return -1;
/* callbacks */
if(base->tcp_stickies)
startidx = 0; /* process all events, some are sticky */
for(i=startidx; i<numwait; i++)
eventlist[i]->just_checked = 1;
//verbose(VERB_CLIENT, "winsock_event signals");
for(i=startidx; i<numwait; i++) {
if(!base->waitfor[i])
continue; /* was deleted */
if(eventlist[i]->is_signal) {
eventlist[i]->just_checked = 0;
_getdns_handle_signal(eventlist[i]);
}
}
/* early exit - do not process network, exit quickly */
if(base->need_to_exit)
return 0;
//verbose(VERB_CLIENT, "winsock_event net");
for(i=startidx; i<numwait; i++) {
short bits = 0;
/* eventlist[i] fired */
/* see if eventlist[i] is still valid and just checked from
* WSAWaitForEvents */
if(!base->waitfor[i])
continue; /* was deleted */
if(!eventlist[i]->just_checked)
continue; /* added by other callback */
if(eventlist[i]->is_signal)
continue; /* not a network event at all */
eventlist[i]->just_checked = 0;
if(WSAEnumNetworkEvents(eventlist[i]->ev_fd,
base->waitfor[i], /* reset the event handle */
/*NULL,*/ /* do not reset the event handle */
&netev) != 0) {
log_err("getdns: WSAEnumNetworkEvents failed: %s",
wsa_strerror(WSAGetLastError()));
return -1;
}
if((netev.lNetworkEvents & FD_READ)) {
if(netev.iErrorCode[FD_READ_BIT] != 0)
printf("FD_READ_BIT error: %s\n",
wsa_strerror(netev.iErrorCode[FD_READ_BIT]));
bits |= EV_READ;
printf("FD_READ_BIT\n");
}
if((netev.lNetworkEvents & FD_WRITE)) {
if(netev.iErrorCode[FD_WRITE_BIT] != 0)
printf("FD_WRITE_BIT error: %s\n",
wsa_strerror(netev.iErrorCode[FD_WRITE_BIT]));
bits |= EV_WRITE;
printf("FD_WRITE_BIT\n");
}
if((netev.lNetworkEvents & FD_CONNECT)) {
if(netev.iErrorCode[FD_CONNECT_BIT] != 0)
printf("FD_CONNECT_BIT error: %s\n",
wsa_strerror(netev.iErrorCode[FD_CONNECT_BIT]));
bits |= EV_READ;
bits |= EV_WRITE;
printf("FD_CONNECT_BIT\n");
}
if((netev.lNetworkEvents & FD_ACCEPT)) {
if(netev.iErrorCode[FD_ACCEPT_BIT] != 0)
printf("FD_ACCEPT_BIT error: %s\n",
wsa_strerror(netev.iErrorCode[FD_ACCEPT_BIT]));
bits |= EV_READ;
printf("FD_ACCEPT_BIT\n");
}
if((netev.lNetworkEvents & FD_CLOSE)) {
if(netev.iErrorCode[FD_CLOSE_BIT] != 0)
printf("FD_CLOSE_BIT error: %s\n",
wsa_strerror(netev.iErrorCode[FD_CLOSE_BIT]));
//g bits |= EV_READ;
//g bits |= EV_WRITE;
printf("FD_CLOSE_BIT\n");
}
if(eventlist[i]->is_tcp && eventlist[i]->stick_events) {
printf("winsock %d pass sticky %s%s\n",
eventlist[i]->ev_fd,
(eventlist[i]->old_events&EV_READ)?"EV_READ":"",
(eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":"");
bits |= eventlist[i]->old_events;
}
if(eventlist[i]->is_tcp && bits) {
eventlist[i]->old_events = bits;
eventlist[i]->stick_events = 1;
if((eventlist[i]->ev_events & bits)) {
newstickies = 1;
}
printf("winsock %d store sticky %s%s",
eventlist[i]->ev_fd,
(eventlist[i]->old_events&EV_READ)?"EV_READ":"",
(eventlist[i]->old_events&EV_WRITE) ? "EV_WRITE" : "");
}
if((bits & eventlist[i]->ev_events)) {
printf( "winsock event callback %p fd=%d "
"%s%s%s%s%s ; %s%s%s\n",
eventlist[i], eventlist[i]->ev_fd,
(netev.lNetworkEvents&FD_READ)?" FD_READ":"",
(netev.lNetworkEvents&FD_WRITE)?" FD_WRITE":"",
(netev.lNetworkEvents&FD_CONNECT)?
" FD_CONNECT":"",
(netev.lNetworkEvents&FD_ACCEPT)?
" FD_ACCEPT":"",
(netev.lNetworkEvents&FD_CLOSE)?" FD_CLOSE":"",
(bits&EV_READ)?" EV_READ":"",
(bits&EV_WRITE)?" EV_WRITE":"",
(bits&EV_TIMEOUT)?" EV_TIMEOUT":"");
fptr_ok(fptr_whitelist_event(
eventlist[i]->ev_callback));
(*eventlist[i]->ev_callback)(eventlist[i]->ev_fd,
bits & eventlist[i]->ev_events,
eventlist[i]->ev_arg);
}
if(eventlist[i]->is_tcp && bits)
printf( "winsock %d got sticky %s%s\n",
eventlist[i]->ev_fd,
(eventlist[i]->old_events&EV_READ)?"EV_READ":"",
(eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":"");
}
//verbose(VERB_CLIENT, "winsock_event net");
if(base->tcp_reinvigorated) {
printf("winsock_event reinvigorated\n");
base->tcp_reinvigorated = 0;
newstickies = 1;
}
base->tcp_stickies = newstickies;
//gprintf("winsock_event handle_select end\n");
return 0;
}
int _getdns_event_base_dispatch(struct _getdns_event_base *base)
{
struct timeval wait;
if(settime(base) < 0)
return -1;
while(!base->need_to_exit)
{
/* see if timeouts need handling */
_getdns_handle_timeouts(base, base->time_tv, &wait);
if(base->need_to_exit)
return 0;
/* do select */
if(_getdns_handle_select(base, &wait) < 0) {
if(base->need_to_exit)
return 0;
return -1;
}
}
return 0;
}
int _getdns_event_base_loopexit(struct _getdns_event_base *base,
struct timeval * ATTR_UNUSED(tv))
{
base->need_to_exit = 1;
return 0;
}
void _getdns_event_base_free(struct _getdns_event_base *base)
{
if(!base)
return;
if(base->items)
free(base->items);
if(base->times)
free(base->times);
if(base->signals)
free(base->signals);
free(base);
}
void _getdns_event_set(struct _getdns_event *ev, int fd, short bits,
void (*cb)(int, short, void *), void *arg)
{
ev->node.key = ev;
ev->ev_fd = fd;
ev->ev_events = bits;
ev->ev_callback = cb;
fptr_ok(fptr_whitelist_event(ev->ev_callback));
ev->ev_arg = arg;
ev->just_checked = 0;
ev->added = 0;
}
int _getdns_event_base_set(struct _getdns_event_base *base, struct _getdns_event *ev)
{
ev->ev_base = base;
ev->old_events = 0;
ev->stick_events = 0;
ev->added = 0;
return 0;
}
int _getdns_event_add(struct _getdns_event *ev, struct timeval *tv)
{
printf( "event_add %p added=%d fd=%d tv=" ARG_LL "d %s%s%s\n",
ev, ev->added, ev->ev_fd,
(tv?(long long)tv->tv_sec*1000+(long long)tv->tv_usec/1000:-1),
(ev->ev_events&EV_READ)?" EV_READ":"",
(ev->ev_events&EV_WRITE)?" EV_WRITE":"",
(ev->ev_events&EV_TIMEOUT)?" EV_TIMEOUT":"");
if(ev->added)
_getdns_event_del(ev);
ev->is_tcp = 0;
ev->is_signal = 0;
ev->just_checked = 0;
if ((ev->ev_events&(EV_READ | EV_WRITE)) && ev->ev_fd != -1) {
BOOL b = 0;
int t, l;
long events = 0;
//gprintf("\getdns_event_add %d %d\n", ev->ev_fd, events);
if (ev->ev_base->max == ev->ev_base->cap)
return -1;
ev->idx = ev->ev_base->max++;
ev->ev_base->items[ev->idx] = ev;
if ((ev->ev_events&EV_READ))
events |= FD_READ;
if ((ev->ev_events&EV_WRITE))
{
events |= FD_CONNECT;
events |= FD_WRITE;
}
//printf("\getdns_event_add %d read = %d write = %d %d\n", ev->ev_fd, ev->ev_events&EV_READ, ev->ev_events&EV_WRITE, events);
l = sizeof(t);
if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_TYPE,
(void*)&t, &l) != 0)
log_err("getdns: getsockopt(SO_TYPE) failed: %s",
wsa_strerror(WSAGetLastError()));
if(t == SOCK_STREAM) {
/* TCP socket */
ev->is_tcp = 1;
events |= FD_CLOSE;
if( (ev->ev_events&EV_WRITE) )
events |= FD_CONNECT;
l = sizeof(b);
if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_ACCEPTCONN,
(void*)&b, &l) != 0)
log_err("getdns: getsockopt(SO_ACCEPTCONN) failed: %s",
wsa_strerror(WSAGetLastError()));
if(b) /* TCP accept socket */
events |= FD_ACCEPT;
}
ev->hEvent = WSACreateEvent();
if(ev->hEvent == WSA_INVALID_EVENT)
log_err("getdns: WSACreateEvent failed: %s",
wsa_strerror(WSAGetLastError()));
/* automatically sets fd to nonblocking mode.
* nonblocking cannot be disabled, until wsaES(fd, NULL, 0) */
printf("\nWSAEventSelect %d events %d hEvent %d\n", ev->ev_fd, (int)events, (int)ev->hEvent);
if (WSAEventSelect(ev->ev_fd, ev->hEvent, events) != 0) {
log_err("getdns: WSAEventSelect in getdns failed: %s",
wsa_strerror(WSAGetLastError()));
}
if(ev->is_tcp && ev->stick_events &&
(ev->ev_events & ev->old_events)) {
/* go to processing the sticky event right away */
printf("\nWSAEventSelect sticky %d events %d hEvent %d\n", ev->ev_fd, (int)events, (int)ev->hEvent);
ev->ev_base->tcp_reinvigorated = 1;
}
}
if(tv && (ev->ev_events&EV_TIMEOUT)) {
printf("\nWSAEventSelect timeout %d hEvent %d\n", ev->ev_fd, (int)ev->hEvent);
#ifndef S_SPLINT_S
struct timeval *now = ev->ev_base->time_tv;
ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec;
ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec;
while(ev->ev_timeout.tv_usec > 1000000) {
ev->ev_timeout.tv_usec -= 1000000;
ev->ev_timeout.tv_sec++;
}
#endif
(void)_getdns_rbtree_insert(ev->ev_base->times, &ev->node);
}
ev->added = 1;
return 0;
}
int _getdns_event_del(struct _getdns_event *ev)
{
//verbose(VERB_ALGO, "event_del %p added=%d fd=%d tv=" ARG_LL "d %s%s%s",
// ev, ev->added, ev->ev_fd,
// (ev->ev_events&EV_TIMEOUT)?(long long)ev->ev_timeout.tv_sec*1000+
// (long long)ev->ev_timeout.tv_usec/1000:-1,
// (ev->ev_events&EV_READ)?" EV_READ":"",
// (ev->ev_events&EV_WRITE)?" EV_WRITE":"",
// (ev->ev_events&EV_TIMEOUT)?" EV_TIMEOUT":"");
if(!ev->added)
return 0;
//log_assert(ev->added);
if((ev->ev_events&EV_TIMEOUT))
(void)_getdns_rbtree_delete(ev->ev_base->times, &ev->node);
if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
//log_assert(ev->ev_base->max > 0);
/* remove item and compact the list */
ev->ev_base->items[ev->idx] =
ev->ev_base->items[ev->ev_base->max-1];
ev->ev_base->items[ev->ev_base->max-1] = NULL;
ev->ev_base->max--;
if(ev->idx < ev->ev_base->max)
ev->ev_base->items[ev->idx]->idx = ev->idx;
zero_waitfor(ev->ev_base->waitfor, ev->hEvent);
if(WSAEventSelect(ev->ev_fd, ev->hEvent, 0) != 0)
log_err("getdns: WSAEventSelect(disable) failed: %s",
wsa_strerror(WSAGetLastError()));
if(!WSACloseEvent(ev->hEvent))
log_err("getdns: WSACloseEvent failed: %s",
wsa_strerror(WSAGetLastError()));
}
ev->just_checked = 0;
ev->added = 0;
return 0;
}
/** which base gets to handle signals */
static struct _getdns_event_base* signal_base = NULL;
/** signal handler */
static RETSIGTYPE sigh(int sig)
{
if(!signal_base || sig < 0 || sig >= MAX_SIG)
return;
}
int _getdns_signal_add(struct _getdns_event *ev, struct timeval * ATTR_UNUSED(tv))
{
if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
return -1;
signal_base = ev->ev_base;
ev->ev_base->signals[ev->ev_fd] = ev;
ev->added = 1;
if(signal(ev->ev_fd, sigh) == SIG_ERR) {
return -1;
}
return 0;
}
int _getdns_signal_del(struct _getdns_event *ev)
{
if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
return -1;
ev->ev_base->signals[ev->ev_fd] = NULL;
ev->added = 0;
return 0;
}
void winsock_tcp_wouldblock(struct _getdns_event* ev, int eventbits)
{
printf("winsock: tcp wouldblock %s\n",
eventbits==EV_READ?"EV_READ":"EV_WRITE");
ev->old_events &= (~eventbits);
if(ev->old_events == 0)
ev->stick_events = 0;
/* in case this is the last sticky event, we could
* possibly run an empty handler loop to reset the base
* tcp_stickies variable
*/
}
int winsock_register_wsaevent(struct _getdns_event_base* base, struct _getdns_event* ev,
WSAEVENT wsaevent, void (*cb)(int, short, void*), void* arg)
{
if(base->max == base->cap)
return 0;
memset(ev, 0, sizeof(*ev));
ev->ev_fd = -1;
ev->ev_events = EV_READ;
ev->ev_callback = cb;
ev->ev_arg = arg;
ev->is_signal = 1;
ev->hEvent = wsaevent;
ev->added = 1;
ev->ev_base = base;
ev->idx = ev->ev_base->max++;
ev->ev_base->items[ev->idx] = ev;
return 1;
}
void winsock_unregister_wsaevent(struct _getdns_event* ev)
{
if(!ev || !ev->added) return;
//log_assert(ev->added && ev->ev_base->max > 0)
/* remove item and compact the list */
ev->ev_base->items[ev->idx] = ev->ev_base->items[ev->ev_base->max-1];
ev->ev_base->items[ev->ev_base->max-1] = NULL;
ev->ev_base->max--;
if(ev->idx < ev->ev_base->max)
ev->ev_base->items[ev->idx]->idx = ev->idx;
ev->added = 0;
}
#else /* USE_WINSOCK */
/** symbol so this codefile defines symbols. pleasing ranlib on OSX 10.5 */
int winsock_unused_symbol = 1;
#endif /* USE_WINSOCK */

View File

@ -1,295 +0,0 @@
/*
* util/winsock_event.h - getdns event handling for winsock on windows
* extracted from Unbound source code and modified for getdns
*
* Copyright (c) 2015, NLnet Labs/Verisign. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS or Verisign nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* This file contains interface functions with the WinSock2 API on Windows.
* It uses the winsock WSAWaitForMultipleEvents interface on a number of
* sockets.
* Code is originally from the Unbound source for Windows.
*
* Note that windows can only wait for max 64 events at one time.
*
* Also, file descriptors cannot be waited for.
*
* Named pipes are not easily available (and are not usable in select() ).
* For interprocess communication, it is possible to wait for a hEvent to
* be signaled by another thread.
*
* When a socket becomes readable, then it will not be flagged as
* readable again until you have gotten WOULDBLOCK from a recv routine.
* That means the event handler must store the readability (edge notify)
* and process the incoming data until it blocks.
* The function performing recv then has to inform the event handler that
* the socket has blocked, and the event handler can mark it as such.
* Thus, this file transforms the edge notify from windows to a level notify
* that is compatible with UNIX.
* The WSAEventSelect page says that it does do level notify, as long
* as you call a recv/write/accept at least once when it is signalled.
* This last bit is not true, even though documented in server2008 api docs
* from microsoft, it does not happen at all. Instead you have to test for
* WSAEWOULDBLOCK on a tcp stream, and only then retest the socket.
* And before that remember the previous result as still valid.
*
* To stay 'fair', instead of emptying a socket completely, the event handler
* can test the other (marked as blocking) sockets for new events.
*
* Additionally, TCP accept sockets get special event support.
*
* Socket numbers are not starting small, they can be any number (say 33060).
* Therefore, bitmaps are not used, but arrays.
*
* on winsock, you must use recv() and send() for TCP reads and writes,
* not read() and write(), those work only on files.
*
* Also fseek and fseeko do not work if a FILE is not fopen-ed in binary mode.
*
* When under a high load windows gives out lots of errors, from recvfrom
* on udp sockets for example (WSAECONNRESET). Even though the udp socket
* has no connection per se.
*/
#ifndef UTIL_WINSOCK_EVENT_H
#define UTIL_WINSOCK_EVENT_H
// Only enabled for Windows
#ifdef USE_WINSOCK
#ifndef HAVE_EVENT_BASE_FREE
#define HAVE_EVENT_BASE_FREE
#endif
/* redefine the calls to different names so that there is no name
* collision with other code that uses libevent names. (that uses libunbound)*/
#define _getdns_event_init winsockevent_init
#define event_get_version winsockevent_get_version
#define event_get_method winsockevent_get_method
#define _getdns_event_base_dispatch winsockevent_base_dispatch
#define event_base_loopexit winsockevent_base_loopexit
#define _getdns_event_base_free winsockevent_base_free
#define _getdns_event_set winsockevent_set
#define _getdns_event_base_set winsockevent_base_set
#define _getdns_event_add winsockevent_add
#define _getdns_event_del winsockevent_del
#define signal_add winsocksignal_add
#define signal_del winsocksignal_del
/** event timeout */
#define EV_TIMEOUT 0x01
/** event fd readable */
#define EV_READ 0x02
/** event fd writable */
#define EV_WRITE 0x04
/** event signal */
#define EV_SIGNAL 0x08
/** event must persist */
#define EV_PERSIST 0x10
/* needs our redblack tree */
#include "util/rbtree.h"
/** max number of signals to support */
#define MAX_SIG 32
/** The number of items that the winsock event handler can service.
* Windows cannot handle more anyway */
#define WSK_MAX_ITEMS 64
/**
* event base for winsock event handler
*/
struct _getdns_event_base
{
/** sorted by timeout (absolute), ptr */
_getdns_rbtree_t* times;
/** array (first part in use) of handles to work on */
struct _getdns_event** items;
/** number of items in use in array */
int max;
/** capacity of array, size of array in items */
int cap;
/** array of 0 - maxsig of ptr to event for it */
struct _getdns_event** signals;
/** if we need to exit */
int need_to_exit;
/** where to store time in seconds */
time_t* time_secs;
/** where to store time in microseconds */
struct timeval* time_tv;
/**
* TCP streams have sticky events to them, these are not
* reported by the windows event system anymore, we have to
* keep reporting those events as present until wouldblock() is
* signalled by the handler back to use.
*/
int tcp_stickies;
/**
* should next cycle process reinvigorated stickies,
* these are stickies that have been stored, but due to a new
* event_add a sudden interest in the event has incepted.
*/
int tcp_reinvigorated;
/** The list of events that is currently being processed. */
WSAEVENT waitfor[WSK_MAX_ITEMS];
/* fdset for read write, for fds ready, and added */
fd_set
/** fds for reading */
reads,
/** fds for writing */
writes,
/** fds determined ready for use */
ready,
/** ready plus newly added events. */
content;
};
/**
* Event structure. Has some of the event elements.
*/
struct _getdns_event {
/** node in timeout rbtree */
_getdns_rbnode_t node;
/** is event already added */
int added;
/** event base it belongs to */
struct _getdns_event_base *ev_base;
/** fd to poll or -1 for timeouts. signal number for sigs. */
int ev_fd;
/** what events this event is interested in, see EV_.. above. */
short ev_events;
/** timeout value */
struct timeval ev_timeout;
/** callback to call: fd, eventbits, userarg */
void (*ev_callback)(int, short, void *);
/** callback user arg */
void *ev_arg;
/* ----- nonpublic part, for winsock_event only ----- */
/** index of this event in the items array (if added) */
int idx;
/** the event handle to wait for new events to become ready */
WSAEVENT hEvent;
/** true if this filedes is a TCP socket and needs special attention */
int is_tcp;
/** remembered EV_ values */
short old_events;
/** should remembered EV_ values be used for TCP streams.
* Reset after WOULDBLOCK is signaled using the function. */
int stick_events;
/** true if this event is a signaling WSAEvent by the user.
* User created and user closed WSAEvent. Only signaled/unsigneled,
* no read/write/distinctions needed. */
int is_signal;
/** used during callbacks to see which events were just checked */
int just_checked;
};
char* wsa_strerror(DWORD err);
void log_err(const char *format, ...);
/** create event base */
void *_getdns_event_init(time_t* time_secs, struct timeval* time_tv);
/** get version */
const char *event_get_version(void);
/** get polling method (select,epoll) */
const char *event_get_method(void);
/** run select in a loop */
int _getdns_event_base_dispatch(struct _getdns_event_base *);
/** exit that loop */
int event_base_loopexit(struct _getdns_event_base *, struct timeval *);
/** free event base. Free events yourself */
void _getdns_event_base_free(struct _getdns_event_base *);
/** set content of event */
void _getdns_event_set(struct _getdns_event *, int, short, void (*)(int, short, void *), void *);
/** add event to a base. You *must* call this for every event. */
int _getdns_event_base_set(struct _getdns_event_base *, struct _getdns_event *);
/** add event to make it active. You may not change it with event_set anymore */
int _getdns_event_add(struct _getdns_event *, struct timeval *);
/** remove event. You may change it again */
int _getdns_event_del(struct _getdns_event *);
#define evtimer_add(ev, tv) event_add(ev, tv)
#define evtimer_del(ev) event_del(ev)
/* uses different implementation. Cannot mix fd/timeouts and signals inside
* the same struct event. create several event structs for that. */
/** install signal handler */
int signal_add(struct _getdns_event *, struct timeval *);
/** set signal event contents */
#define signal_set(ev, x, cb, arg) \
event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg)
/** remove signal handler */
int signal_del(struct _getdns_event *);
/** compare events in tree, based on timevalue, ptr for uniqueness */
int getdns_mini_ev_cmp(const void* a, const void* b);
/**
* Routine for windows only, where the handling layer can signal that
* a TCP stream encountered WSAEWOULDBLOCK for a stream and thus needs
* retesting the event.
* Pass if EV_READ or EV_WRITE gave wouldblock.
*/
void winsock_tcp_wouldblock(struct _getdns_event* ev, int eventbit);
/**
* Routine for windows only. where you pass a signal WSAEvent that
* you wait for. When the event is signaled, the callback gets called.
* The callback has to WSAResetEvent to disable the signal.
* @param base: the event base.
* @param ev: the event structure for data storage
* can be passed uninitialised.
* @param wsaevent: the WSAEvent that gets signaled.
* @param cb: callback routine.
* @param arg: user argument to callback routine.
* @return false on error.
*/
int winsock_register_wsaevent(struct _getdns_event_base* base, struct _getdns_event* ev,
WSAEVENT wsaevent, void (*cb)(int, short, void*), void* arg);
/**
* Unregister a wsaevent. User has to close the WSAEVENT itself.
* @param ev: event data storage.
*/
void winsock_unregister_wsaevent(struct _getdns_event* ev);
#endif /* USE_WINSOCK */
#endif /* UTIL_WINSOCK_EVENT_H */