mirror of https://github.com/getdnsapi/getdns.git
Merge pull request #144 from wtoorop/devel/default_eventloop
Devel/default eventloop
This commit is contained in:
commit
4b5c61145a
137
configure.ac
137
configure.ac
|
@ -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,54 +449,44 @@ 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],
|
||||
[path to libidn (default: search /usr/local ..)]),
|
||||
[], [withval="yes"])
|
||||
if test x_$withval = x_yes; then
|
||||
for dir in /usr/local /opt/local /usr/pkg /usr/sfw; do
|
||||
if test -f "$dir/include/idna.h"; then
|
||||
CFLAGS="$CFLAGS -I$dir/include"
|
||||
LDFLAGS="$LDFLAGS -L$dir/lib"
|
||||
AC_MSG_NOTICE([Found libidn in $dir])
|
||||
break
|
||||
fi
|
||||
if test -f "$dir/include/idn/idna.h"; then
|
||||
CFLAGS="$CFLAGS -I$dir/include/idn"
|
||||
LDFLAGS="$LDFLAGS -L$dir/lib"
|
||||
AC_MSG_NOTICE([Found libidn in $dir])
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -f "/usr/include/idn/idna.h"; then
|
||||
CFLAGS="$CFLAGS -I/usr/include/idn"
|
||||
#LDFLAGS="$LDFLAGS -L/usr/lib"
|
||||
AC_MSG_NOTICE([Found libidn in /usr])
|
||||
my_with_libidn=1
|
||||
AC_ARG_WITH(libidn, AS_HELP_STRING([--with-libidn=pathname],
|
||||
[path to libidn (default: search /usr/local ..)]),
|
||||
[], [withval="yes"])
|
||||
if test x_$withval = x_yes; then
|
||||
for dir in /usr/local /opt/local /usr/pkg /usr/sfw; do
|
||||
if test -f "$dir/include/idna.h"; then
|
||||
CFLAGS="$CFLAGS -I$dir/include"
|
||||
LDFLAGS="$LDFLAGS -L$dir/lib"
|
||||
AC_MSG_NOTICE([Found libidn in $dir])
|
||||
break
|
||||
fi
|
||||
if test -f "$dir/include/idn/idna.h"; then
|
||||
CFLAGS="$CFLAGS -I$dir/include/idn"
|
||||
LDFLAGS="$LDFLAGS -L$dir/lib"
|
||||
AC_MSG_NOTICE([Found libidn in $dir])
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -f "/usr/include/idn/idna.h"; then
|
||||
CFLAGS="$CFLAGS -I/usr/include/idn"
|
||||
#LDFLAGS="$LDFLAGS -L/usr/lib"
|
||||
AC_MSG_NOTICE([Found libidn in /usr])
|
||||
fi
|
||||
else
|
||||
if test x_$withval != x_no; then
|
||||
CFLAGS="$CFLAGS -I$withval/include"
|
||||
LDFLAGS="$LDFLAGS -L$withval/lib"
|
||||
else
|
||||
if test x_$withval != x_no; then
|
||||
CFLAGS="$CFLAGS -I$withval/include"
|
||||
LDFLAGS="$LDFLAGS -L$withval/lib"
|
||||
else
|
||||
my_with_libidn=0
|
||||
fi
|
||||
my_with_libidn=0
|
||||
fi
|
||||
fi
|
||||
|
||||
|
@ -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
|
||||
])
|
||||
|
||||
|
|
|
@ -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.])])
|
||||
])
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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>
|
||||
|
|
|
@ -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:
|
||||
|
|
126
src/context.c
126
src/context.c
|
@ -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);
|
||||
context->extension->vmt->schedule(
|
||||
context->extension, ub_fd(context->unbound_ctx),
|
||||
TIMEOUT_FOREVER, &context->ub_event);
|
||||
#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);
|
||||
|
||||
context->extension->vmt->clear(
|
||||
context->extension, &context->ub_event);
|
||||
#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 */
|
||||
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
|
||||
_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);
|
||||
#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,55 +2932,36 @@ _getdns_bindata_destroy(struct mem_funcs *mfs,
|
|||
|
||||
/* TODO: Remove next_timeout argument from getdns_context_get_num_pending_requests
|
||||
*/
|
||||
void _getdns_handle_timeouts(struct _getdns_event_base* base, struct timeval* now,
|
||||
struct timeval* wait);
|
||||
uint32_t
|
||||
getdns_context_get_num_pending_requests(struct getdns_context* context,
|
||||
getdns_context_get_num_pending_requests(getdns_context* context,
|
||||
struct timeval* next_timeout)
|
||||
{
|
||||
struct timeval dispose;
|
||||
(void)next_timeout;
|
||||
|
||||
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
|
||||
if (!context)
|
||||
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||
|
||||
if (context->outbound_requests.count)
|
||||
context->extension->vmt->run_once(context->extension, 0);
|
||||
|
||||
/* TODO: Remove this when next_timeout is gone */
|
||||
if (context->extension == &context->mini_event.loop)
|
||||
_getdns_handle_timeouts(context->mini_event.base,
|
||||
&context->mini_event.time_tv,
|
||||
next_timeout ? next_timeout : &dispose);
|
||||
|
||||
return context->outbound_requests.count;
|
||||
}
|
||||
|
||||
/* process async reqs */
|
||||
getdns_return_t
|
||||
getdns_context_process_async(struct getdns_context* context)
|
||||
getdns_context_process_async(getdns_context *context)
|
||||
{
|
||||
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
|
||||
if (!context)
|
||||
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||
|
||||
#ifdef HAVE_LIBUNBOUND
|
||||
if (ub_poll(context->unbound_ctx) && ub_process(context->unbound_ctx)){
|
||||
/* need an async return code? */
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
}
|
||||
#endif
|
||||
context->extension->vmt->run_once(context->extension, 0);
|
||||
|
||||
return GETDNS_RETURN_GOOD;
|
||||
}
|
||||
|
||||
void
|
||||
getdns_context_run(getdns_context *context)
|
||||
{
|
||||
if (context->extension == &context->mini_event.loop) {
|
||||
if (getdns_context_get_num_pending_requests(context, NULL) > 0 &&
|
||||
!getdns_context_process_async(context))
|
||||
context->extension->vmt->run(context->extension);
|
||||
}
|
||||
else
|
||||
context->extension->vmt->run(context->extension);
|
||||
context->extension->vmt->run(context->extension);
|
||||
}
|
||||
|
||||
typedef struct timeout_accumulator {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 **/
|
||||
|
|
|
@ -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"); \
|
||||
|
|
59
src/dnssec.c
59
src/dnssec.c
|
@ -749,6 +749,8 @@ struct chain_head {
|
|||
|
||||
struct chain_node {
|
||||
chain_node *parent;
|
||||
|
||||
size_t lock;
|
||||
|
||||
getdns_rrset dnskey;
|
||||
getdns_network_req *dnskey_req;
|
||||
|
@ -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)
|
||||
|
|
|
@ -0,0 +1,281 @@
|
|||
/*
|
||||
* Copyright (c) 2013, NLNet Labs, Verisign, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the names of the copyright holders nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "extension/default_eventloop.h"
|
||||
#include "debug.h"
|
||||
|
||||
static uint64_t get_now_plus(uint64_t amount)
|
||||
{
|
||||
struct timeval tv;
|
||||
uint64_t now;
|
||||
|
||||
if (gettimeofday(&tv, NULL)) {
|
||||
perror("gettimeofday() failed");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
now = tv.tv_sec * 1000000 + tv.tv_usec;
|
||||
|
||||
return (now + amount * 1000) >= now ? now + amount * 1000 : -1;
|
||||
}
|
||||
|
||||
static getdns_return_t
|
||||
default_eventloop_schedule(getdns_eventloop *loop,
|
||||
int fd, uint64_t timeout, getdns_eventloop_event *event)
|
||||
{
|
||||
_getdns_default_eventloop *default_loop = (_getdns_default_eventloop *)loop;
|
||||
size_t i;
|
||||
|
||||
DEBUG_SCHED( "%s(loop: %p, fd: %d, timeout: %"PRIu64", event: %p, FD_SETSIZE: %d)\n"
|
||||
, __FUNCTION__, loop, fd, timeout, event, FD_SETSIZE);
|
||||
|
||||
if (!loop || !event)
|
||||
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||
|
||||
if (fd >= FD_SETSIZE) {
|
||||
DEBUG_SCHED( "ERROR: fd %d >= FD_SETSIZE: %d!\n"
|
||||
, fd, FD_SETSIZE);
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
}
|
||||
if (fd >= 0) {
|
||||
if (!(event->read_cb || event->write_cb)) {
|
||||
DEBUG_SCHED("ERROR: fd event without "
|
||||
"read or write cb!\n");
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
}
|
||||
#if defined(SCHED_DEBUG) && SCHED_DEBUG
|
||||
if (default_loop->fd_events[fd]) {
|
||||
DEBUG_SCHED( "ERROR: Event present at fd slot: %p!\n"
|
||||
, default_loop->fd_events[fd]);
|
||||
}
|
||||
#endif
|
||||
default_loop->fd_events[fd] = event;
|
||||
default_loop->fd_timeout_times[fd] = get_now_plus(timeout);
|
||||
event->ev = (void *) (intptr_t) fd + 1;
|
||||
|
||||
DEBUG_SCHED( "scheduled read/write at %d\n", fd);
|
||||
return GETDNS_RETURN_GOOD;
|
||||
}
|
||||
if (!event->timeout_cb) {
|
||||
DEBUG_SCHED("ERROR: fd < 0 without timeout_cb!\n");
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
}
|
||||
if (event->read_cb) {
|
||||
DEBUG_SCHED("ERROR: timeout event with read_cb! Clearing.\n");
|
||||
event->read_cb = NULL;
|
||||
}
|
||||
if (event->write_cb) {
|
||||
DEBUG_SCHED("ERROR: timeout event with write_cb! Clearing.\n");
|
||||
event->write_cb = NULL;
|
||||
}
|
||||
for (i = 0; i < MAX_TIMEOUTS; i++) {
|
||||
if (default_loop->timeout_events[i] == NULL) {
|
||||
default_loop->timeout_events[i] = event;
|
||||
default_loop->timeout_times[i] = get_now_plus(timeout);
|
||||
event->ev = (void *) (intptr_t) i + 1;
|
||||
|
||||
DEBUG_SCHED( "scheduled timeout at %d\n", (int)i);
|
||||
return GETDNS_RETURN_GOOD;
|
||||
}
|
||||
}
|
||||
DEBUG_SCHED("ERROR: Out of timeout slots!\n");
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
}
|
||||
|
||||
static getdns_return_t
|
||||
default_eventloop_clear(getdns_eventloop *loop, getdns_eventloop_event *event)
|
||||
{
|
||||
_getdns_default_eventloop *default_loop = (_getdns_default_eventloop *)loop;
|
||||
ssize_t i;
|
||||
|
||||
if (!loop || !event)
|
||||
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||
|
||||
DEBUG_SCHED( "%s(loop: %p, event: %p)\n", __FUNCTION__, loop, event);
|
||||
|
||||
i = (intptr_t)event->ev - 1;
|
||||
if (i < 0 || i > FD_SETSIZE) {
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
}
|
||||
if (event->timeout_cb && !event->read_cb && !event->write_cb) {
|
||||
#if defined(SCHED_DEBUG) && SCHED_DEBUG
|
||||
if (default_loop->timeout_events[i] != event)
|
||||
DEBUG_SCHED( "ERROR: Different/wrong event present at "
|
||||
"timeout slot: %p!\n"
|
||||
, default_loop->timeout_events[i]);
|
||||
#endif
|
||||
default_loop->timeout_events[i] = NULL;
|
||||
} else {
|
||||
#if defined(SCHED_DEBUG) && SCHED_DEBUG
|
||||
if (default_loop->fd_events[i] != event)
|
||||
DEBUG_SCHED( "ERROR: Different/wrong event present at "
|
||||
"fd slot: %p!\n"
|
||||
, default_loop->fd_events[i]);
|
||||
#endif
|
||||
default_loop->fd_events[i] = NULL;
|
||||
}
|
||||
event->ev = NULL;
|
||||
return GETDNS_RETURN_GOOD;
|
||||
}
|
||||
|
||||
static void
|
||||
default_eventloop_cleanup(getdns_eventloop *loop)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
default_read_cb(int fd, getdns_eventloop_event *event)
|
||||
{
|
||||
DEBUG_SCHED( "%s(fd: %d, event: %p)\n", __FUNCTION__, fd, event);
|
||||
event->read_cb(event->userarg);
|
||||
}
|
||||
|
||||
static void
|
||||
default_write_cb(int fd, getdns_eventloop_event *event)
|
||||
{
|
||||
DEBUG_SCHED( "%s(fd: %d, event: %p)\n", __FUNCTION__, fd, event);
|
||||
event->write_cb(event->userarg);
|
||||
}
|
||||
|
||||
static void
|
||||
default_timeout_cb(int fd, getdns_eventloop_event *event)
|
||||
{
|
||||
DEBUG_SCHED( "%s(fd: %d, event: %p)\n", __FUNCTION__, fd, event);
|
||||
event->timeout_cb(event->userarg);
|
||||
}
|
||||
|
||||
static void
|
||||
default_eventloop_run_once(getdns_eventloop *loop, int blocking)
|
||||
{
|
||||
_getdns_default_eventloop *default_loop = (_getdns_default_eventloop *)loop;
|
||||
|
||||
fd_set readfds, writefds;
|
||||
int fd, max_fd = -1;
|
||||
uint64_t now, timeout = (uint64_t)-1;
|
||||
size_t i;
|
||||
struct timeval tv;
|
||||
|
||||
if (!loop)
|
||||
return;
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_ZERO(&writefds);
|
||||
now = get_now_plus(0);
|
||||
|
||||
for (i = 0; i < MAX_TIMEOUTS; i++) {
|
||||
if (!default_loop->timeout_events[i])
|
||||
continue;
|
||||
if (now > default_loop->timeout_times[i])
|
||||
default_timeout_cb(-1, default_loop->timeout_events[i]);
|
||||
else if (default_loop->timeout_times[i] < timeout)
|
||||
timeout = default_loop->timeout_times[i];
|
||||
}
|
||||
for (fd = 0; fd < FD_SETSIZE; fd++) {
|
||||
if (!default_loop->fd_events[fd])
|
||||
continue;
|
||||
if (default_loop->fd_events[fd]->read_cb)
|
||||
FD_SET(fd, &readfds);
|
||||
if (default_loop->fd_events[fd]->write_cb)
|
||||
FD_SET(fd, &writefds);
|
||||
if (fd > max_fd)
|
||||
max_fd = fd;
|
||||
if (default_loop->fd_timeout_times[fd] < timeout)
|
||||
timeout = default_loop->fd_timeout_times[fd];
|
||||
}
|
||||
if (max_fd == -1 && timeout == (uint64_t)-1)
|
||||
return;
|
||||
|
||||
if (! blocking || now > timeout) {
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
} else {
|
||||
tv.tv_sec = (timeout - now) / 1000000;
|
||||
tv.tv_usec = (timeout - now) % 1000000;
|
||||
}
|
||||
if (select(max_fd + 1, &readfds, &writefds, NULL,
|
||||
(timeout == ((uint64_t)-1) ? NULL : &tv)) < 0) {
|
||||
perror("select() failed");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
now = get_now_plus(0);
|
||||
for (fd = 0; fd < FD_SETSIZE; fd++) {
|
||||
if (default_loop->fd_events[fd] &&
|
||||
default_loop->fd_events[fd]->read_cb &&
|
||||
FD_ISSET(fd, &readfds))
|
||||
default_read_cb(fd, default_loop->fd_events[fd]);
|
||||
|
||||
if (default_loop->fd_events[fd] &&
|
||||
default_loop->fd_events[fd]->write_cb &&
|
||||
FD_ISSET(fd, &writefds))
|
||||
default_write_cb(fd, default_loop->fd_events[fd]);
|
||||
|
||||
if (default_loop->fd_events[fd] &&
|
||||
default_loop->fd_events[fd]->timeout_cb &&
|
||||
now > default_loop->fd_timeout_times[fd])
|
||||
default_timeout_cb(fd, default_loop->fd_events[fd]);
|
||||
|
||||
i = fd;
|
||||
if (default_loop->timeout_events[i] &&
|
||||
default_loop->timeout_events[i]->timeout_cb &&
|
||||
now > default_loop->timeout_times[i])
|
||||
default_timeout_cb(-1, default_loop->timeout_events[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
default_eventloop_run(getdns_eventloop *loop)
|
||||
{
|
||||
_getdns_default_eventloop *default_loop = (_getdns_default_eventloop *)loop;
|
||||
size_t i;
|
||||
|
||||
if (!loop)
|
||||
return;
|
||||
|
||||
i = 0;
|
||||
while (i < MAX_TIMEOUTS) {
|
||||
if (default_loop->fd_events[i] || default_loop->timeout_events[i]) {
|
||||
default_eventloop_run_once(loop, 1);
|
||||
i = 0;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_getdns_default_eventloop_init(_getdns_default_eventloop *loop)
|
||||
{
|
||||
static getdns_eventloop_vmt default_eventloop_vmt = {
|
||||
default_eventloop_cleanup,
|
||||
default_eventloop_schedule,
|
||||
default_eventloop_clear,
|
||||
default_eventloop_run,
|
||||
default_eventloop_run_once
|
||||
};
|
||||
|
||||
(void) memset(loop, 0, sizeof(_getdns_default_eventloop));
|
||||
loop->loop.vmt = &default_eventloop_vmt;
|
||||
}
|
|
@ -1,11 +1,10 @@
|
|||
/**
|
||||
*
|
||||
* \file libmini_event.h
|
||||
/*
|
||||
* \file default_eventloop.h
|
||||
* @brief Build in default eventloop extension that uses select.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2013, NLnet Labs, Verisign, Inc.
|
||||
* Copyright (c) 2013, NLNet Labs, Verisign, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -30,34 +29,31 @@
|
|||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _GETDNS_LIBMINI_EVENT_H_
|
||||
#define _GETDNS_LIBMINI_EVENT_H_
|
||||
|
||||
#ifndef DEFAULT_EVENTLOOP_H_
|
||||
#define DEFAULT_EVENTLOOP_H_
|
||||
#include "config.h"
|
||||
#ifndef USE_WINSOCK
|
||||
#include "util/mini_event.h"
|
||||
#else
|
||||
#include "util/winsock_event.h"
|
||||
#endif
|
||||
#include "types-internal.h"
|
||||
#include "getdns/getdns.h"
|
||||
#include "getdns/getdns_extra.h"
|
||||
|
||||
typedef struct _getdns_mini_event {
|
||||
getdns_eventloop loop;
|
||||
time_t time_secs;
|
||||
struct timeval time_tv;
|
||||
struct _getdns_event_base *base;
|
||||
size_t n_events;
|
||||
struct mem_funcs mf;
|
||||
} _getdns_mini_event;
|
||||
/* No more than select's capability queries can be outstanding,
|
||||
* The number of outstanding timeouts should be less or equal then
|
||||
* the number of outstanding queries, so MAX_TIMEOUTS equal to
|
||||
* FD_SETSIZE should be safe.
|
||||
*/
|
||||
#define MAX_TIMEOUTS FD_SETSIZE
|
||||
|
||||
getdns_return_t
|
||||
_getdns_mini_event_init(getdns_context *context, _getdns_mini_event *mini_event);
|
||||
/* Eventloop based on select */
|
||||
typedef struct _getdns_default_eventloop {
|
||||
getdns_eventloop loop;
|
||||
getdns_eventloop_event *fd_events[FD_SETSIZE];
|
||||
uint64_t fd_timeout_times[FD_SETSIZE];
|
||||
getdns_eventloop_event *timeout_events[MAX_TIMEOUTS];
|
||||
uint64_t timeout_times[MAX_TIMEOUTS];
|
||||
} _getdns_default_eventloop;
|
||||
|
||||
getdns_return_t
|
||||
_getdns_mini_event_create(getdns_context *ctxt, _getdns_mini_event **mini_event);
|
||||
|
||||
void
|
||||
_getdns_mini_event_destroy(_getdns_mini_event *mini_event);
|
||||
_getdns_default_eventloop_init(_getdns_default_eventloop *loop);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _GETDNS_LIBMINI_EVENT_H_ */
|
|
@ -1,238 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* \file libmini_event.c
|
||||
* @brief Build in default eventloop extension that uses select.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013, NLnet Labs, Verisign, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the names of the copyright holders nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "types-internal.h"
|
||||
#include "extension/libmini_event.h"
|
||||
#if defined(SCHED_DEBUG) && SCHED_DEBUG
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
static void
|
||||
_getdns_mini_event_cleanup(getdns_eventloop *loop)
|
||||
{
|
||||
_getdns_mini_event *ext = (_getdns_mini_event *)loop;
|
||||
_getdns_event_base_free(ext->base);
|
||||
}
|
||||
|
||||
void
|
||||
_getdns_mini_event_destroy(_getdns_mini_event *ext)
|
||||
{
|
||||
assert(ext);
|
||||
ext->loop.vmt->cleanup(&ext->loop);
|
||||
GETDNS_FREE(ext->mf, ext);
|
||||
}
|
||||
|
||||
void _getdns_handle_timeouts(struct _getdns_event_base* base,
|
||||
struct timeval* now, struct timeval* wait);
|
||||
int _getdns_handle_select(struct _getdns_event_base* base, struct timeval* wait);
|
||||
|
||||
static int
|
||||
_getdns_mini_event_settime(_getdns_mini_event *ext)
|
||||
{
|
||||
if (gettimeofday(&ext->time_tv, NULL) < 0)
|
||||
return -1;
|
||||
ext->time_secs = (time_t)ext->time_tv.tv_sec;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_getdns_mini_event_run(getdns_eventloop *loop)
|
||||
{
|
||||
_getdns_mini_event *ext = (_getdns_mini_event *)loop;
|
||||
struct timeval wait;
|
||||
|
||||
if (ext->n_events == 0 || _getdns_mini_event_settime(ext) < 0)
|
||||
return;
|
||||
|
||||
do {
|
||||
(void) _getdns_handle_timeouts(ext->base, &ext->time_tv, &wait);
|
||||
|
||||
if (!ext->n_events)
|
||||
break;
|
||||
|
||||
if (_getdns_handle_select(ext->base, &wait))
|
||||
break;
|
||||
|
||||
} while (ext->n_events);
|
||||
}
|
||||
|
||||
static void
|
||||
_getdns_mini_event_run_once(getdns_eventloop *loop, int blocking)
|
||||
{
|
||||
static struct timeval immediately = { 0, 0 };
|
||||
_getdns_mini_event *ext = (_getdns_mini_event *)loop;
|
||||
struct timeval wait;
|
||||
|
||||
if (blocking) {
|
||||
if (_getdns_mini_event_settime(ext) < 0)
|
||||
return;
|
||||
_getdns_handle_timeouts(ext->base, &ext->time_tv, &wait);
|
||||
if (_getdns_handle_select(ext->base, &wait) < 0)
|
||||
return;
|
||||
|
||||
} else if (_getdns_handle_select(ext->base, &immediately) < 0)
|
||||
return;
|
||||
|
||||
_getdns_handle_timeouts(ext->base, &ext->time_tv, &wait);
|
||||
}
|
||||
|
||||
static getdns_return_t
|
||||
_getdns_mini_event_clear(getdns_eventloop *loop, getdns_eventloop_event *el_ev)
|
||||
{
|
||||
getdns_return_t r = GETDNS_RETURN_GOOD;
|
||||
_getdns_mini_event *ext = (_getdns_mini_event *)loop;
|
||||
|
||||
assert(el_ev->ev);
|
||||
DEBUG_SCHED("1. _getdns_mini_event_clear(loop: %p, el_ev: %p[userarg: %p, r: %p, w: %p, t: %p, ev: %p]); n_events: %d, times: %d\n", loop, el_ev, el_ev->userarg, el_ev->read_cb, el_ev->write_cb, el_ev->timeout_cb, el_ev->ev, (int)ext->n_events, (int)ext->base->times->count);
|
||||
|
||||
if (_getdns_event_del(el_ev->ev) != 0)
|
||||
r = GETDNS_RETURN_GENERIC_ERROR;
|
||||
|
||||
GETDNS_FREE(ext->mf, el_ev->ev);
|
||||
el_ev->ev = NULL;
|
||||
|
||||
ext->n_events--;
|
||||
DEBUG_SCHED("2. %d <- _getdns_mini_event_clear(loop: %p, el_ev: %p[userarg: %p, r: %p, w: %p, t: %p, ev: %p]); n_events: %d, times: %d\n", r, loop, el_ev, el_ev->userarg, el_ev->read_cb, el_ev->write_cb, el_ev->timeout_cb, el_ev->ev, (int)ext->n_events, (int)ext->base->times->count);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void
|
||||
_getdns_mini_event_callback(int fd, short bits, void *arg)
|
||||
{
|
||||
getdns_eventloop_event *el_ev = (getdns_eventloop_event *)arg;
|
||||
DEBUG_SCHED("1. _getdns_mini_event_callback(fd: %d, bits: %d, el_ev: %p[userarg: %p, r: %p, w: %p, t: %p, ev: %p])\n", fd, (int)bits, el_ev, el_ev->userarg, el_ev->read_cb, el_ev->write_cb, el_ev->timeout_cb, el_ev->ev);
|
||||
if (bits & EV_READ) {
|
||||
assert(el_ev->read_cb);
|
||||
el_ev->read_cb(el_ev->userarg);
|
||||
} else if (bits & EV_WRITE) {
|
||||
assert(el_ev->write_cb);
|
||||
el_ev->write_cb(el_ev->userarg);
|
||||
} else if (bits & EV_TIMEOUT) {
|
||||
assert(el_ev->timeout_cb);
|
||||
el_ev->timeout_cb(el_ev->userarg);
|
||||
} else
|
||||
assert(ASSERT_UNREACHABLE);
|
||||
}
|
||||
|
||||
static getdns_return_t
|
||||
_getdns_mini_event_schedule(getdns_eventloop *loop,
|
||||
int fd, uint64_t timeout, getdns_eventloop_event *el_ev)
|
||||
{
|
||||
_getdns_mini_event *ext = (_getdns_mini_event *)loop;
|
||||
struct _getdns_event *my_ev;
|
||||
struct timeval tv = { timeout / 1000, (timeout % 1000) * 1000 };
|
||||
|
||||
assert(el_ev);
|
||||
assert(!(el_ev->read_cb || el_ev->write_cb) || fd >= 0);
|
||||
assert( el_ev->read_cb || el_ev->write_cb || el_ev->timeout_cb);
|
||||
|
||||
if (!(my_ev = GETDNS_MALLOC(ext->mf, struct _getdns_event)))
|
||||
return GETDNS_RETURN_MEMORY_ERROR;
|
||||
|
||||
el_ev->ev = my_ev;
|
||||
DEBUG_SCHED("1. _getdns_mini_event_schedule(loop: %p, fd: %d, timeout: %"PRId64", el_ev: %p[userarg: %p, r: %p, w: %p, t: %p, ev: %p]); n_events: %d\n", loop, fd, timeout, el_ev, el_ev->userarg, el_ev->read_cb, el_ev->write_cb, el_ev->timeout_cb, el_ev->ev, (int)ext->n_events);
|
||||
_getdns_event_set(my_ev, fd, (
|
||||
(el_ev->read_cb ? EV_READ|EV_PERSIST : 0) |
|
||||
(el_ev->write_cb ? EV_WRITE|EV_PERSIST : 0) |
|
||||
(el_ev->timeout_cb ? EV_TIMEOUT : 0)),
|
||||
_getdns_mini_event_callback, el_ev);
|
||||
|
||||
if (_getdns_mini_event_settime(ext))
|
||||
goto error;
|
||||
|
||||
(void) _getdns_event_base_set(ext->base, my_ev);
|
||||
if (_getdns_event_add(my_ev, el_ev->timeout_cb ? &tv : NULL))
|
||||
goto error;
|
||||
|
||||
ext->n_events++;
|
||||
DEBUG_SCHED("2. _getdns_mini_event_schedule(loop: %p, fd: %d, timeout: %"PRId64", el_ev: %p[userarg: %p, r: %p, w: %p, t: %p, ev: %p]); n_events: %d\n", loop, fd, timeout, el_ev, el_ev->userarg, el_ev->read_cb, el_ev->write_cb, el_ev->timeout_cb, el_ev->ev, (int)ext->n_events);
|
||||
|
||||
return GETDNS_RETURN_GOOD;
|
||||
error:
|
||||
GETDNS_FREE(ext->mf, my_ev);
|
||||
el_ev->ev = NULL;
|
||||
|
||||
DEBUG_SCHED("3. _getdns_mini_event_schedule(loop: %p, fd: %d, timeout: %"PRId64", el_ev: %p[userarg: %p, r: %p, w: %p, t: %p, ev: %p]); n_events: %d\n", loop, fd, timeout, el_ev, el_ev->userarg, el_ev->read_cb, el_ev->write_cb, el_ev->timeout_cb, el_ev->ev, (int)ext->n_events);
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
}
|
||||
|
||||
getdns_return_t
|
||||
_getdns_mini_event_init(getdns_context *context, _getdns_mini_event *ext)
|
||||
{
|
||||
static getdns_eventloop_vmt _getdns_mini_event_vmt = {
|
||||
_getdns_mini_event_cleanup,
|
||||
_getdns_mini_event_schedule,
|
||||
_getdns_mini_event_clear,
|
||||
_getdns_mini_event_run,
|
||||
_getdns_mini_event_run_once
|
||||
};
|
||||
|
||||
if (!context)
|
||||
return GETDNS_RETURN_BAD_CONTEXT;
|
||||
if (!ext)
|
||||
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||
|
||||
#ifdef USE_WINSOCK
|
||||
int r;
|
||||
WSADATA wsa_data;
|
||||
|
||||
if ((r = WSAStartup(MAKEWORD(2, 2), &wsa_data)) != 0) {
|
||||
printf("could not init winsock. WSAStartup: %s",
|
||||
wsa_strerror(r));
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
ext->n_events = 0;
|
||||
ext->loop.vmt = &_getdns_mini_event_vmt;
|
||||
ext->base = _getdns_event_init(&ext->time_secs, &ext->time_tv);
|
||||
if (!ext->base)
|
||||
return GETDNS_RETURN_MEMORY_ERROR;
|
||||
|
||||
ext->mf = *priv_getdns_context_mf(context);
|
||||
return GETDNS_RETURN_GOOD;
|
||||
}
|
||||
|
||||
getdns_return_t
|
||||
_getdns_mini_event_create(getdns_context *context, _getdns_mini_event **ext)
|
||||
{
|
||||
if (!context) return GETDNS_RETURN_BAD_CONTEXT;
|
||||
if (!ext) return GETDNS_RETURN_INVALID_PARAMETER;
|
||||
|
||||
*ext = GETDNS_MALLOC(*priv_getdns_context_mf(context), _getdns_mini_event);
|
||||
return _getdns_mini_event_init(context, *ext);
|
||||
}
|
|
@ -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,10 +347,18 @@ _getdns_submit_netreq(getdns_network_req *netreq)
|
|||
dns_req->name_len, name, sizeof(name));
|
||||
|
||||
#ifdef HAVE_LIBUNBOUND
|
||||
return ub_resolve_async(dns_req->context->unbound_ctx,
|
||||
name, netreq->request_type, netreq->owner->request_class,
|
||||
netreq, ub_resolve_callback, &(netreq->unbound_id)) ?
|
||||
GETDNS_RETURN_GENERIC_ERROR : GETDNS_RETURN_GOOD;
|
||||
#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)) ?
|
||||
GETDNS_RETURN_GENERIC_ERROR : GETDNS_RETURN_GOOD;
|
||||
#else
|
||||
return GETDNS_RETURN_NOT_IMPLEMENTED;
|
||||
#endif
|
||||
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
112
src/stub.c
112
src/stub.c
|
@ -50,12 +50,20 @@
|
|||
#include "pubkey-pinning.h"
|
||||
|
||||
#ifdef USE_WINSOCK
|
||||
#define EINPROGRESS 112
|
||||
#define EWOULDBLOCK 140
|
||||
typedef u_short sa_family_t;
|
||||
#include "util/winsock_event.h"
|
||||
#define _getdns_EWOULDBLOCK (WSAGetLastError() == WSATRY_AGAIN ||\
|
||||
WSAGetLastError() == WSAEWOULDBLOCK)
|
||||
#define _getdns_EINPROGRESS (WSAGetLastError() == WSAEINPROGRESS)
|
||||
#else
|
||||
#define _getdns_EWOULDBLOCK (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
#define _getdns_EINPROGRESS (errno == EINPROGRESS)
|
||||
#endif
|
||||
|
||||
/* WSA TODO:
|
||||
* STUB_TCP_WOULDBLOCK added to deal with edge triggered event loops (versus
|
||||
* level triggered). See also lines containing WSA TODO below...
|
||||
*/
|
||||
#define STUB_TCP_WOULDBLOCK -6
|
||||
#define STUB_OUT_OF_OPTIONS -5 /* upstream options exceeded MAXIMUM_UPSTREAM_OPTION_SPACE */
|
||||
#define STUB_TLS_SETUP_ERROR -4
|
||||
#define STUB_TCP_AGAIN -3
|
||||
|
@ -384,10 +392,10 @@ 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) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
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;
|
||||
|
@ -721,7 +728,7 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
|
|||
if (! tcp->write_buf) {
|
||||
/* No, this is an initial write. Try to send
|
||||
*/
|
||||
do {
|
||||
do {
|
||||
query_id = arc4random();
|
||||
query_id_intptr = (intptr_t)query_id;
|
||||
netreq->node.key = (void *)query_id_intptr;
|
||||
|
@ -754,8 +761,8 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
|
|||
/* We have an initialized packet buffer.
|
||||
* Lets see how much of it we can write
|
||||
*/
|
||||
#ifdef USE_TCP_FASTOPEN
|
||||
/* We use sendto() here which will do both a connect and send */
|
||||
#ifdef USE_TCP_FASTOPEN
|
||||
written = sendto(fd, netreq->query - 2, pkt_len + 2,
|
||||
MSG_FASTOPEN, (struct sockaddr *)&(netreq->upstream->addr),
|
||||
netreq->upstream->addr_len);
|
||||
|
@ -763,29 +770,19 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
|
|||
just fall back to a 'normal' write. */
|
||||
if (written == -1 && errno == EISCONN)
|
||||
written = write(fd, netreq->query - 2, pkt_len + 2);
|
||||
|
||||
if ((written == -1 && (errno == EAGAIN ||
|
||||
errno == EWOULDBLOCK ||
|
||||
/* Add the error case where the connection is in progress which is when
|
||||
a cookie is not available (e.g. when doing the first request to an
|
||||
upstream). We must let the handshake complete since non-blocking. */
|
||||
errno == EINPROGRESS)) ||
|
||||
written < pkt_len + 2) {
|
||||
#else
|
||||
|
||||
#ifdef USE_WINSOCK
|
||||
written = sendto(fd, (const char *)(netreq->query - 2),
|
||||
pkt_len + 2, 0,
|
||||
(struct sockaddr *)&(netreq->upstream->addr),
|
||||
netreq->upstream->addr_len);
|
||||
|
||||
#else
|
||||
written = write(fd, netreq->query - 2, pkt_len + 2);
|
||||
#endif
|
||||
if ((written == -1 && (errno == EAGAIN ||
|
||||
errno == EWOULDBLOCK)) ||
|
||||
if ((written == -1 && (_getdns_EWOULDBLOCK ||
|
||||
/* Add the error case where the connection is in progress which is when
|
||||
a cookie is not available (e.g. when doing the first request to an
|
||||
upstream). We must let the handshake complete since non-blocking. */
|
||||
_getdns_EINPROGRESS)) ||
|
||||
written < pkt_len + 2) {
|
||||
#endif
|
||||
|
||||
/* We couldn't write the whole packet.
|
||||
* We have to return with STUB_TCP_AGAIN.
|
||||
* Setup tcp to track the state.
|
||||
|
@ -794,7 +791,7 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
|
|||
tcp->write_buf_len = pkt_len + 2;
|
||||
tcp->written = written >= 0 ? written : 0;
|
||||
|
||||
return STUB_TCP_AGAIN;
|
||||
return STUB_TCP_WOULDBLOCK;
|
||||
|
||||
} else if (written == -1)
|
||||
return STUB_TCP_ERROR;
|
||||
|
@ -809,8 +806,8 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
|
|||
written = write(fd, tcp->write_buf + tcp->written,
|
||||
tcp->write_buf_len - tcp->written);
|
||||
if (written == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
return STUB_TCP_AGAIN;
|
||||
if (_getdns_EWOULDBLOCK)
|
||||
return STUB_TCP_WOULDBLOCK;
|
||||
else
|
||||
return STUB_TCP_ERROR;
|
||||
}
|
||||
|
@ -1304,7 +1301,7 @@ stub_udp_read_cb(void *userarg)
|
|||
* i.e. overflow
|
||||
*/
|
||||
0, NULL, NULL);
|
||||
if (read == -1 && (errno = EAGAIN || errno == EWOULDBLOCK))
|
||||
if (read == -1 && _getdns_EWOULDBLOCK)
|
||||
return;
|
||||
|
||||
if (read < GLDNS_HEADER_SIZE)
|
||||
|
@ -1405,13 +1402,16 @@ upstream_read_cb(void *userarg)
|
|||
|
||||
if (tls_should_read(upstream))
|
||||
q = stub_tls_read(upstream, &upstream->tcp,
|
||||
&upstream->upstreams->mf);
|
||||
&upstream->upstreams->mf);
|
||||
else
|
||||
q = stub_tcp_read(upstream->fd, &upstream->tcp,
|
||||
&upstream->upstreams->mf, &upstream->event);
|
||||
&upstream->upstreams->mf);
|
||||
|
||||
switch (q) {
|
||||
case STUB_TCP_AGAIN:
|
||||
/* WSA TODO: if callback is still upstream_read_cb, do it again
|
||||
*/
|
||||
case STUB_TCP_WOULDBLOCK:
|
||||
return;
|
||||
|
||||
case STUB_TCP_ERROR:
|
||||
|
@ -1463,6 +1463,10 @@ upstream_read_cb(void *userarg)
|
|||
upstream_reschedule_netreq_events(upstream, netreq);
|
||||
|
||||
_getdns_check_dns_req_complete(netreq->owner);
|
||||
|
||||
/* WSA TODO: if callback is still upstream_read_cb, do it again
|
||||
*/
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1499,6 +1503,10 @@ upstream_write_cb(void *userarg)
|
|||
|
||||
switch (q) {
|
||||
case STUB_TCP_AGAIN:
|
||||
/* WSA TODO: if callback is still upstream_write_cb, do it again
|
||||
*/
|
||||
|
||||
case STUB_TCP_WOULDBLOCK:
|
||||
return;
|
||||
|
||||
case STUB_TCP_ERROR:
|
||||
|
@ -1553,6 +1561,8 @@ upstream_write_cb(void *userarg)
|
|||
netreq_upstream_write_cb : NULL),
|
||||
stub_timeout_cb));
|
||||
}
|
||||
/* WSA TODO: if callback is still upstream_write_cb, do it again
|
||||
*/
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
149
src/sync.c
149
src/sync.c
|
@ -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;
|
||||
|
||||
return ext->vmt->schedule(ext, ub_fd(context->unbound_ctx),
|
||||
TIMEOUT_FOREVER, &loop->ub_event);
|
||||
#else
|
||||
# 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, &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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
mkdir ub || true
|
||||
cd ub
|
||||
for f in mini_event.c mini_event.h rbtree.c rbtree.h
|
||||
for f in rbtree.c rbtree.h
|
||||
do
|
||||
wget http://unbound.net/svn/trunk/util/$f || \
|
||||
ftp http://unbound.net/svn/trunk/util/$f || continue
|
||||
|
|
|
@ -1,394 +0,0 @@
|
|||
/*
|
||||
* mini_event.c - implementation of part of libevent api, portably.
|
||||
*
|
||||
* Copyright (c) 2007, NLnet Labs. All rights reserved.
|
||||
*
|
||||
* This software is open source.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of the NLNET LABS nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* fake libevent implementation. Less broad in functionality, and only
|
||||
* supports select(2).
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#ifdef HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
#include <sys/time.h>
|
||||
|
||||
#if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK)
|
||||
#include <signal.h>
|
||||
#include "util/mini_event.h"
|
||||
#include "util/fptr_wlist.h"
|
||||
|
||||
/** compare events in tree, based on timevalue, ptr for uniqueness */
|
||||
int _getdns_mini_ev_cmp(const void* a, const void* b)
|
||||
{
|
||||
const struct _getdns_event *e = (const struct _getdns_event*)a;
|
||||
const struct _getdns_event *f = (const struct _getdns_event*)b;
|
||||
if(e->ev_timeout.tv_sec < f->ev_timeout.tv_sec)
|
||||
return -1;
|
||||
if(e->ev_timeout.tv_sec > f->ev_timeout.tv_sec)
|
||||
return 1;
|
||||
if(e->ev_timeout.tv_usec < f->ev_timeout.tv_usec)
|
||||
return -1;
|
||||
if(e->ev_timeout.tv_usec > f->ev_timeout.tv_usec)
|
||||
return 1;
|
||||
if(e < f)
|
||||
return -1;
|
||||
if(e > f)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** set time */
|
||||
static int
|
||||
settime(struct _getdns_event_base* base)
|
||||
{
|
||||
if(gettimeofday(base->time_tv, NULL) < 0) {
|
||||
return -1;
|
||||
}
|
||||
#ifndef S_SPLINT_S
|
||||
*base->time_secs = (time_t)base->time_tv->tv_sec;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** create event base */
|
||||
void *_getdns_event_init(time_t* time_secs, struct timeval* time_tv)
|
||||
{
|
||||
struct _getdns_event_base* base = (struct _getdns_event_base*)malloc(
|
||||
sizeof(struct _getdns_event_base));
|
||||
if(!base)
|
||||
return NULL;
|
||||
memset(base, 0, sizeof(*base));
|
||||
base->time_secs = time_secs;
|
||||
base->time_tv = time_tv;
|
||||
if(settime(base) < 0) {
|
||||
_getdns_event_base_free(base);
|
||||
return NULL;
|
||||
}
|
||||
base->times = _getdns_rbtree_create(_getdns_mini_ev_cmp);
|
||||
if(!base->times) {
|
||||
_getdns_event_base_free(base);
|
||||
return NULL;
|
||||
}
|
||||
base->capfd = MAX_FDS;
|
||||
#ifdef FD_SETSIZE
|
||||
if((int)FD_SETSIZE < base->capfd)
|
||||
base->capfd = (int)FD_SETSIZE;
|
||||
#endif
|
||||
base->fds = (struct _getdns_event**)calloc((size_t)base->capfd,
|
||||
sizeof(struct _getdns_event*));
|
||||
if(!base->fds) {
|
||||
_getdns_event_base_free(base);
|
||||
return NULL;
|
||||
}
|
||||
base->signals = (struct _getdns_event**)calloc(MAX_SIG, sizeof(struct _getdns_event*));
|
||||
if(!base->signals) {
|
||||
_getdns_event_base_free(base);
|
||||
return NULL;
|
||||
}
|
||||
#ifndef S_SPLINT_S
|
||||
FD_ZERO(&base->reads);
|
||||
FD_ZERO(&base->writes);
|
||||
#endif
|
||||
return base;
|
||||
}
|
||||
|
||||
/** get version */
|
||||
const char *_getdns_event_get_version(void)
|
||||
{
|
||||
return "mini-event-"PACKAGE_VERSION;
|
||||
}
|
||||
|
||||
/** get polling method, select */
|
||||
const char *_getdns_event_get_method(void)
|
||||
{
|
||||
return "select";
|
||||
}
|
||||
|
||||
/** call timeouts handlers, and return how long to wait for next one or -1 */
|
||||
void _getdns_handle_timeouts(struct _getdns_event_base* base, struct timeval* now,
|
||||
struct timeval* wait)
|
||||
{
|
||||
struct _getdns_event* p;
|
||||
#ifndef S_SPLINT_S
|
||||
wait->tv_sec = (time_t)-1;
|
||||
#endif
|
||||
|
||||
while((_getdns_rbnode_t*)(p = (struct _getdns_event*)_getdns_rbtree_first(base->times))
|
||||
!=RBTREE_NULL) {
|
||||
#ifndef S_SPLINT_S
|
||||
if(p->ev_timeout.tv_sec > now->tv_sec ||
|
||||
(p->ev_timeout.tv_sec==now->tv_sec &&
|
||||
p->ev_timeout.tv_usec > now->tv_usec)) {
|
||||
/* there is a next larger timeout. wait for it */
|
||||
wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec;
|
||||
if(now->tv_usec > p->ev_timeout.tv_usec) {
|
||||
wait->tv_sec--;
|
||||
wait->tv_usec = 1000000 - (now->tv_usec -
|
||||
p->ev_timeout.tv_usec);
|
||||
} else {
|
||||
wait->tv_usec = p->ev_timeout.tv_usec
|
||||
- now->tv_usec;
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
/* event times out, remove it */
|
||||
(void)_getdns_rbtree_delete(base->times, p);
|
||||
p->ev_events &= ~EV_TIMEOUT;
|
||||
fptr_ok(fptr_whitelist_event(p->ev_callback));
|
||||
(*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg);
|
||||
}
|
||||
}
|
||||
|
||||
/** call select and callbacks for that */
|
||||
int _getdns_handle_select(struct _getdns_event_base* base, struct timeval* wait)
|
||||
{
|
||||
fd_set r, w;
|
||||
int ret, i;
|
||||
|
||||
#ifndef S_SPLINT_S
|
||||
if(wait->tv_sec==(time_t)-1)
|
||||
wait = NULL;
|
||||
#endif
|
||||
memmove(&r, &base->reads, sizeof(fd_set));
|
||||
memmove(&w, &base->writes, sizeof(fd_set));
|
||||
memmove(&base->ready, &base->content, sizeof(fd_set));
|
||||
|
||||
if((ret = select(base->maxfd+1, &r, &w, NULL, wait)) == -1) {
|
||||
ret = errno;
|
||||
if(settime(base) < 0)
|
||||
return -1;
|
||||
errno = ret;
|
||||
if(ret == EAGAIN || ret == EINTR)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
if(settime(base) < 0)
|
||||
return -1;
|
||||
|
||||
for(i=0; i<base->maxfd+1; i++) {
|
||||
short bits = 0;
|
||||
if(!base->fds[i] || !(FD_ISSET(i, &base->ready))) {
|
||||
continue;
|
||||
}
|
||||
if(FD_ISSET(i, &r)) {
|
||||
bits |= EV_READ;
|
||||
ret--;
|
||||
}
|
||||
if(FD_ISSET(i, &w)) {
|
||||
bits |= EV_WRITE;
|
||||
ret--;
|
||||
}
|
||||
bits &= base->fds[i]->ev_events;
|
||||
if(bits) {
|
||||
fptr_ok(fptr_whitelist_event(
|
||||
base->fds[i]->ev_callback));
|
||||
(*base->fds[i]->ev_callback)(base->fds[i]->ev_fd,
|
||||
bits, base->fds[i]->ev_arg);
|
||||
if(ret==0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** run select in a loop */
|
||||
int _getdns_event_base_dispatch(struct _getdns_event_base* base)
|
||||
{
|
||||
struct timeval wait;
|
||||
if(settime(base) < 0)
|
||||
return -1;
|
||||
while(!base->need_to_exit)
|
||||
{
|
||||
/* see if timeouts need handling */
|
||||
_getdns_handle_timeouts(base, base->time_tv, &wait);
|
||||
if(base->need_to_exit)
|
||||
return 0;
|
||||
/* do select */
|
||||
if(_getdns_handle_select(base, &wait) < 0) {
|
||||
if(base->need_to_exit)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** exit that loop */
|
||||
int _getdns_event_base_loopexit(struct _getdns_event_base* base,
|
||||
struct timeval* ATTR_UNUSED(tv))
|
||||
{
|
||||
base->need_to_exit = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* free event base, free events yourself */
|
||||
void _getdns_event_base_free(struct _getdns_event_base* base)
|
||||
{
|
||||
if(!base)
|
||||
return;
|
||||
if(base->times)
|
||||
free(base->times);
|
||||
if(base->fds)
|
||||
free(base->fds);
|
||||
if(base->signals)
|
||||
free(base->signals);
|
||||
free(base);
|
||||
}
|
||||
|
||||
/** set content of event */
|
||||
void _getdns_event_set(struct _getdns_event* ev, int fd, short bits,
|
||||
void (*cb)(int, short, void *), void* arg)
|
||||
{
|
||||
ev->node.key = ev;
|
||||
ev->ev_fd = fd;
|
||||
ev->ev_events = bits;
|
||||
ev->ev_callback = cb;
|
||||
fptr_ok(fptr_whitelist_event(ev->ev_callback));
|
||||
ev->ev_arg = arg;
|
||||
ev->added = 0;
|
||||
}
|
||||
|
||||
/* add event to a base */
|
||||
int _getdns_event_base_set(struct _getdns_event_base* base, struct _getdns_event* ev)
|
||||
{
|
||||
ev->ev_base = base;
|
||||
ev->added = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* add event to make it active, you may not change it with _getdns_event_set anymore */
|
||||
int _getdns_event_add(struct _getdns_event* ev, struct timeval* tv)
|
||||
{
|
||||
if(ev->added)
|
||||
_getdns_event_del(ev);
|
||||
if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd)
|
||||
return -1;
|
||||
if( (ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
|
||||
ev->ev_base->fds[ev->ev_fd] = ev;
|
||||
if(ev->ev_events&EV_READ) {
|
||||
FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->reads);
|
||||
}
|
||||
if(ev->ev_events&EV_WRITE) {
|
||||
FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->writes);
|
||||
}
|
||||
FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->content);
|
||||
FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready);
|
||||
if(ev->ev_fd > ev->ev_base->maxfd)
|
||||
ev->ev_base->maxfd = ev->ev_fd;
|
||||
}
|
||||
if(tv && (ev->ev_events&EV_TIMEOUT)) {
|
||||
#ifndef S_SPLINT_S
|
||||
struct timeval *now = ev->ev_base->time_tv;
|
||||
ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec;
|
||||
ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec;
|
||||
while(ev->ev_timeout.tv_usec > 1000000) {
|
||||
ev->ev_timeout.tv_usec -= 1000000;
|
||||
ev->ev_timeout.tv_sec++;
|
||||
}
|
||||
#endif
|
||||
(void)_getdns_rbtree_insert(ev->ev_base->times, &ev->node);
|
||||
}
|
||||
ev->added = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* remove event, you may change it again */
|
||||
int _getdns_event_del(struct _getdns_event* ev)
|
||||
{
|
||||
if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd)
|
||||
return -1;
|
||||
if((ev->ev_events&EV_TIMEOUT))
|
||||
(void)_getdns_rbtree_delete(ev->ev_base->times, &ev->node);
|
||||
if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
|
||||
ev->ev_base->fds[ev->ev_fd] = NULL;
|
||||
FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->reads);
|
||||
FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->writes);
|
||||
FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready);
|
||||
FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->content);
|
||||
}
|
||||
ev->added = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** which base gets to handle signals */
|
||||
static struct _getdns_event_base* signal_base = NULL;
|
||||
/** signal handler */
|
||||
static RETSIGTYPE sigh(int sig)
|
||||
{
|
||||
struct _getdns_event* ev;
|
||||
if(!signal_base || sig < 0 || sig >= MAX_SIG)
|
||||
return;
|
||||
ev = signal_base->signals[sig];
|
||||
if(!ev)
|
||||
return;
|
||||
fptr_ok(fptr_whitelist_event(ev->ev_callback));
|
||||
(*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg);
|
||||
}
|
||||
|
||||
/** install signal handler */
|
||||
int _getdns_signal_add(struct _getdns_event* ev, struct timeval* ATTR_UNUSED(tv))
|
||||
{
|
||||
if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
|
||||
return -1;
|
||||
signal_base = ev->ev_base;
|
||||
ev->ev_base->signals[ev->ev_fd] = ev;
|
||||
ev->added = 1;
|
||||
if(signal(ev->ev_fd, sigh) == SIG_ERR) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** remove signal handler */
|
||||
int _getdns_signal_del(struct _getdns_event* ev)
|
||||
{
|
||||
if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
|
||||
return -1;
|
||||
ev->ev_base->signals[ev->ev_fd] = NULL;
|
||||
ev->added = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* USE_MINI_EVENT */
|
||||
#ifndef USE_WINSOCK
|
||||
int _getdns_mini_ev_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* not USE_WINSOCK */
|
||||
#endif /* USE_MINI_EVENT */
|
|
@ -1,178 +0,0 @@
|
|||
/*
|
||||
* mini-event.h - micro implementation of libevent api, using select() only.
|
||||
*
|
||||
* Copyright (c) 2007, NLnet Labs. All rights reserved.
|
||||
*
|
||||
* This software is open source.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of the NLNET LABS nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* This file implements part of the event(3) libevent api.
|
||||
* The back end is only select. Max number of fds is limited.
|
||||
* Max number of signals is limited, one handler per signal only.
|
||||
* And one handler per fd.
|
||||
*
|
||||
* Although limited to select() and a max (1024) open fds, it
|
||||
* is efficient:
|
||||
* o dispatch call caches fd_sets to use.
|
||||
* o handler calling takes time ~ to the number of fds.
|
||||
* o timeouts are stored in a redblack tree, sorted, so take log(n).
|
||||
* Timeouts are only accurate to the second (no subsecond accuracy).
|
||||
* To avoid cpu hogging, fractional timeouts are rounded up to a whole second.
|
||||
*/
|
||||
|
||||
#ifndef MINI_EVENT_H
|
||||
#define MINI_EVENT_H
|
||||
|
||||
#if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK)
|
||||
|
||||
#ifndef HAVE_EVENT_BASE_FREE
|
||||
#define HAVE_EVENT_BASE_FREE
|
||||
#endif
|
||||
|
||||
|
||||
/** event timeout */
|
||||
#define EV_TIMEOUT 0x01
|
||||
/** event fd readable */
|
||||
#define EV_READ 0x02
|
||||
/** event fd writable */
|
||||
#define EV_WRITE 0x04
|
||||
/** event signal */
|
||||
#define EV_SIGNAL 0x08
|
||||
/** event must persist */
|
||||
#define EV_PERSIST 0x10
|
||||
|
||||
/* needs our redblack tree */
|
||||
#include "util/rbtree.h"
|
||||
|
||||
/** max number of file descriptors to support */
|
||||
#define MAX_FDS 1024
|
||||
/** max number of signals to support */
|
||||
#define MAX_SIG 32
|
||||
|
||||
/** event base */
|
||||
struct _getdns_event_base
|
||||
{
|
||||
/** sorted by timeout (absolute), ptr */
|
||||
_getdns_rbtree_t* times;
|
||||
/** array of 0 - maxfd of ptr to event for it */
|
||||
struct _getdns_event** fds;
|
||||
/** max fd in use */
|
||||
int maxfd;
|
||||
/** capacity - size of the fds array */
|
||||
int capfd;
|
||||
/* fdset for read write, for fds ready, and added */
|
||||
fd_set
|
||||
/** fds for reading */
|
||||
reads,
|
||||
/** fds for writing */
|
||||
writes,
|
||||
/** fds determined ready for use */
|
||||
ready,
|
||||
/** ready plus newly added events. */
|
||||
content;
|
||||
/** array of 0 - maxsig of ptr to event for it */
|
||||
struct _getdns_event** signals;
|
||||
/** if we need to exit */
|
||||
int need_to_exit;
|
||||
/** where to store time in seconds */
|
||||
time_t* time_secs;
|
||||
/** where to store time in microseconds */
|
||||
struct timeval* time_tv;
|
||||
};
|
||||
|
||||
/**
|
||||
* Event structure. Has some of the event elements.
|
||||
*/
|
||||
struct _getdns_event {
|
||||
/** node in timeout rbtree */
|
||||
_getdns_rbnode_t node;
|
||||
/** is event already added */
|
||||
int added;
|
||||
|
||||
/** event base it belongs to */
|
||||
struct _getdns_event_base *ev_base;
|
||||
/** fd to poll or -1 for timeouts. signal number for sigs. */
|
||||
int ev_fd;
|
||||
/** what events this event is interested in, see EV_.. above. */
|
||||
short ev_events;
|
||||
/** timeout value */
|
||||
struct timeval ev_timeout;
|
||||
|
||||
/** callback to call: fd, eventbits, userarg */
|
||||
void (*ev_callback)(int, short, void *arg);
|
||||
/** callback user arg */
|
||||
void *ev_arg;
|
||||
};
|
||||
|
||||
/* function prototypes (some are as they appear in event.h) */
|
||||
/** create event base */
|
||||
void *_getdns_event_init(time_t* time_secs, struct timeval* time_tv);
|
||||
/** get version */
|
||||
const char *_getdns_event_get_version(void);
|
||||
/** get polling method, select */
|
||||
const char *_getdns_event_get_method(void);
|
||||
/** run select in a loop */
|
||||
int _getdns_event_base_dispatch(struct _getdns_event_base *);
|
||||
/** exit that loop */
|
||||
int _getdns_event_base_loopexit(struct _getdns_event_base *, struct timeval *);
|
||||
/** free event base. Free events yourself */
|
||||
void _getdns_event_base_free(struct _getdns_event_base *);
|
||||
/** set content of event */
|
||||
void _getdns_event_set(struct _getdns_event *, int, short, void (*)(int, short, void *), void *);
|
||||
/** add event to a base. You *must* call this for every event. */
|
||||
int _getdns_event_base_set(struct _getdns_event_base *, struct _getdns_event *);
|
||||
/** add event to make it active. You may not change it with _getdns_event_set anymore */
|
||||
int _getdns_event_add(struct _getdns_event *, struct timeval *);
|
||||
/** remove event. You may change it again */
|
||||
int _getdns_event_del(struct _getdns_event *);
|
||||
|
||||
/** add a timer */
|
||||
#define _getdns_evtimer_add(ev, tv) _getdns_event_add(ev, tv)
|
||||
/** remove a timer */
|
||||
#define _getdns_evtimer_del(ev) _getdns_event_del(ev)
|
||||
|
||||
/* uses different implementation. Cannot mix fd/timeouts and signals inside
|
||||
* the same struct _getdns_event. create several event structs for that. */
|
||||
/** install signal handler */
|
||||
int _getdns_signal_add(struct _getdns_event *, struct timeval *);
|
||||
/** set signal event contents */
|
||||
#define _getdns_signal_set(ev, x, cb, arg) \
|
||||
_getdns_event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg)
|
||||
/** remove signal handler */
|
||||
int _getdns_signal_del(struct _getdns_event *);
|
||||
|
||||
#endif /* USE_MINI_EVENT and not USE_WINSOCK */
|
||||
|
||||
/** compare events in tree, based on timevalue, ptr for uniqueness */
|
||||
int _getdns_mini_ev_cmp(const void* a, const void* b);
|
||||
|
||||
#endif /* MINI_EVENT_H */
|
|
@ -1,844 +0,0 @@
|
|||
/*
|
||||
* util/winsock_event.c - implementation of the getdns winsock event handler.
|
||||
*
|
||||
* Copyright (c) 2015, Verisign/NLnet Labs. All rights reserved.
|
||||
*
|
||||
* This software is open source.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of the NLNET LABS/Verisign nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/**
|
||||
* \file
|
||||
* Implementation of the getdns WinSock2 API event notification handler
|
||||
* for the getdns Windows port.
|
||||
* Code is originally from the Unbound source for Windows.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#ifdef USE_WINSOCK // only included for Windows builds
|
||||
#include <signal.h>
|
||||
#ifdef HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
#include <sys/time.h>
|
||||
#include "util/winsock_event.h"
|
||||
#include "util/fptr_wlist.h"
|
||||
|
||||
/**
|
||||
* implementation of log_err
|
||||
* @param format: format string printf-style.
|
||||
*/
|
||||
void
|
||||
log_err(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
fprintf(stderr, "error ");
|
||||
fprintf(stderr, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
char* wsa_strerror(DWORD err)
|
||||
{
|
||||
static char unknown[32];
|
||||
|
||||
switch (err) {
|
||||
case WSA_INVALID_HANDLE: return "Specified event object handle is invalid.";
|
||||
case WSA_NOT_ENOUGH_MEMORY: return "Insufficient memory available.";
|
||||
case WSA_INVALID_PARAMETER: return "One or more parameters are invalid.";
|
||||
case WSA_OPERATION_ABORTED: return "Overlapped operation aborted.";
|
||||
case WSA_IO_INCOMPLETE: return "Overlapped I/O event object not in signaled state.";
|
||||
case WSA_IO_PENDING: return "Overlapped operations will complete later.";
|
||||
case WSAEINTR: return "Interrupted function call.";
|
||||
case WSAEBADF: return "File handle is not valid.";
|
||||
case WSAEACCES: return "Permission denied.";
|
||||
case WSAEFAULT: return "Bad address.";
|
||||
case WSAEINVAL: return "Invalid argument.";
|
||||
case WSAEMFILE: return "Too many open files.";
|
||||
case WSAEWOULDBLOCK: return "Resource temporarily unavailable.";
|
||||
case WSAEINPROGRESS: return "Operation now in progress.";
|
||||
case WSAEALREADY: return "Operation already in progress.";
|
||||
case WSAENOTSOCK: return "Socket operation on nonsocket.";
|
||||
case WSAEDESTADDRREQ: return "Destination address required.";
|
||||
case WSAEMSGSIZE: return "Message too long.";
|
||||
case WSAEPROTOTYPE: return "Protocol wrong type for socket.";
|
||||
case WSAENOPROTOOPT: return "Bad protocol option.";
|
||||
case WSAEPROTONOSUPPORT: return "Protocol not supported.";
|
||||
case WSAESOCKTNOSUPPORT: return "Socket type not supported.";
|
||||
case WSAEOPNOTSUPP: return "Operation not supported.";
|
||||
case WSAEPFNOSUPPORT: return "Protocol family not supported.";
|
||||
case WSAEAFNOSUPPORT: return "Address family not supported by protocol family.";
|
||||
case WSAEADDRINUSE: return "Address already in use.";
|
||||
case WSAEADDRNOTAVAIL: return "Cannot assign requested address.";
|
||||
case WSAENETDOWN: return "Network is down.";
|
||||
case WSAENETUNREACH: return "Network is unreachable.";
|
||||
case WSAENETRESET: return "Network dropped connection on reset.";
|
||||
case WSAECONNABORTED: return "Software caused connection abort.";
|
||||
case WSAECONNRESET: return "Connection reset by peer.";
|
||||
case WSAENOBUFS: return "No buffer space available.";
|
||||
case WSAEISCONN: return "Socket is already connected.";
|
||||
case WSAENOTCONN: return "Socket is not connected.";
|
||||
case WSAESHUTDOWN: return "Cannot send after socket shutdown.";
|
||||
case WSAETOOMANYREFS: return "Too many references.";
|
||||
case WSAETIMEDOUT: return "Connection timed out.";
|
||||
case WSAECONNREFUSED: return "Connection refused.";
|
||||
case WSAELOOP: return "Cannot translate name.";
|
||||
case WSAENAMETOOLONG: return "Name too long.";
|
||||
case WSAEHOSTDOWN: return "Host is down.";
|
||||
case WSAEHOSTUNREACH: return "No route to host.";
|
||||
case WSAENOTEMPTY: return "Directory not empty.";
|
||||
case WSAEPROCLIM: return "Too many processes.";
|
||||
case WSAEUSERS: return "User quota exceeded.";
|
||||
case WSAEDQUOT: return "Disk quota exceeded.";
|
||||
case WSAESTALE: return "Stale file handle reference.";
|
||||
case WSAEREMOTE: return "Item is remote.";
|
||||
case WSASYSNOTREADY: return "Network subsystem is unavailable.";
|
||||
case WSAVERNOTSUPPORTED: return "Winsock.dll version out of range.";
|
||||
case WSANOTINITIALISED: return "Successful WSAStartup not yet performed.";
|
||||
case WSAEDISCON: return "Graceful shutdown in progress.";
|
||||
case WSAENOMORE: return "No more results.";
|
||||
case WSAECANCELLED: return "Call has been canceled.";
|
||||
case WSAEINVALIDPROCTABLE: return "Procedure call table is invalid.";
|
||||
case WSAEINVALIDPROVIDER: return "Service provider is invalid.";
|
||||
case WSAEPROVIDERFAILEDINIT: return "Service provider failed to initialize.";
|
||||
case WSASYSCALLFAILURE: return "System call failure.";
|
||||
case WSASERVICE_NOT_FOUND: return "Service not found.";
|
||||
case WSATYPE_NOT_FOUND: return "Class type not found.";
|
||||
case WSA_E_NO_MORE: return "No more results.";
|
||||
case WSA_E_CANCELLED: return "Call was canceled.";
|
||||
case WSAEREFUSED: return "Database query was refused.";
|
||||
case WSAHOST_NOT_FOUND: return "Host not found.";
|
||||
case WSATRY_AGAIN: return "Nonauthoritative host not found.";
|
||||
case WSANO_RECOVERY: return "This is a nonrecoverable error.";
|
||||
case WSANO_DATA: return "Valid name, no data record of requested type.";
|
||||
case WSA_QOS_RECEIVERS: return "QOS receivers.";
|
||||
case WSA_QOS_SENDERS: return "QOS senders.";
|
||||
case WSA_QOS_NO_SENDERS: return "No QOS senders.";
|
||||
case WSA_QOS_NO_RECEIVERS: return "QOS no receivers.";
|
||||
case WSA_QOS_REQUEST_CONFIRMED: return "QOS request confirmed.";
|
||||
case WSA_QOS_ADMISSION_FAILURE: return "QOS admission error.";
|
||||
case WSA_QOS_POLICY_FAILURE: return "QOS policy failure.";
|
||||
case WSA_QOS_BAD_STYLE: return "QOS bad style.";
|
||||
case WSA_QOS_BAD_OBJECT: return "QOS bad object.";
|
||||
case WSA_QOS_TRAFFIC_CTRL_ERROR: return "QOS traffic control error.";
|
||||
case WSA_QOS_GENERIC_ERROR: return "QOS generic error.";
|
||||
case WSA_QOS_ESERVICETYPE: return "QOS service type error.";
|
||||
case WSA_QOS_EFLOWSPEC: return "QOS flowspec error.";
|
||||
case WSA_QOS_EPROVSPECBUF: return "Invalid QOS provider buffer.";
|
||||
case WSA_QOS_EFILTERSTYLE: return "Invalid QOS filter style.";
|
||||
case WSA_QOS_EFILTERTYPE: return "Invalid QOS filter type.";
|
||||
case WSA_QOS_EFILTERCOUNT: return "Incorrect QOS filter count.";
|
||||
case WSA_QOS_EOBJLENGTH: return "Invalid QOS object length.";
|
||||
case WSA_QOS_EFLOWCOUNT: return "Incorrect QOS flow count.";
|
||||
/*case WSA_QOS_EUNKOWNPSOBJ: return "Unrecognized QOS object.";*/
|
||||
case WSA_QOS_EPOLICYOBJ: return "Invalid QOS policy object.";
|
||||
case WSA_QOS_EFLOWDESC: return "Invalid QOS flow descriptor.";
|
||||
case WSA_QOS_EPSFLOWSPEC: return "Invalid QOS provider-specific flowspec.";
|
||||
case WSA_QOS_EPSFILTERSPEC: return "Invalid QOS provider-specific filterspec.";
|
||||
case WSA_QOS_ESDMODEOBJ: return "Invalid QOS shape discard mode object.";
|
||||
case WSA_QOS_ESHAPERATEOBJ: return "Invalid QOS shaping rate object.";
|
||||
case WSA_QOS_RESERVED_PETYPE: return "Reserved policy QOS element type.";
|
||||
default:
|
||||
snprintf(unknown, sizeof(unknown),
|
||||
"unknown WSA error code %d", (int)err);
|
||||
return unknown;
|
||||
}
|
||||
}
|
||||
|
||||
int _getdns_mini_ev_cmp(const void* a, const void* b)
|
||||
{
|
||||
const struct _getdns_event *e = (const struct _getdns_event*)a;
|
||||
const struct _getdns_event *f = (const struct _getdns_event*)b;
|
||||
if(e->ev_timeout.tv_sec < f->ev_timeout.tv_sec)
|
||||
return -1;
|
||||
if(e->ev_timeout.tv_sec > f->ev_timeout.tv_sec)
|
||||
return 1;
|
||||
if(e->ev_timeout.tv_usec < f->ev_timeout.tv_usec)
|
||||
return -1;
|
||||
if(e->ev_timeout.tv_usec > f->ev_timeout.tv_usec)
|
||||
return 1;
|
||||
if(e < f)
|
||||
return -1;
|
||||
if(e > f)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** set time */
|
||||
static int
|
||||
settime(struct _getdns_event_base* base)
|
||||
{
|
||||
if(gettimeofday(base->time_tv, NULL) < 0) {
|
||||
return -1;
|
||||
}
|
||||
#ifndef S_SPLINT_S
|
||||
*base->time_secs = (time_t)base->time_tv->tv_sec;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WINSOCK_DEBUG
|
||||
/**
|
||||
* Find a fd in the list of items.
|
||||
* Note that not all items have a fd associated (those are -1).
|
||||
* Signals are stored separately, and not searched.
|
||||
* @param base: event base to look in.
|
||||
* @param fd: what socket to look for.
|
||||
* @return the index in the array, or -1 on failure.
|
||||
*/
|
||||
static int
|
||||
find_fd(struct _getdns_event_base* base, int fd)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<base->max; i++) {
|
||||
if(base->items[i]->ev_fd == fd)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Find ptr in base array */
|
||||
static void
|
||||
zero_waitfor(WSAEVENT waitfor[], WSAEVENT x)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<WSK_MAX_ITEMS; i++) {
|
||||
if(waitfor[i] == x)
|
||||
waitfor[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void *_getdns_event_init(time_t* time_secs, struct timeval* time_tv)
|
||||
{
|
||||
struct _getdns_event_base* base = (struct _getdns_event_base*)malloc(
|
||||
sizeof(struct _getdns_event_base));
|
||||
if(!base)
|
||||
return NULL;
|
||||
memset(base, 0, sizeof(*base));
|
||||
base->time_secs = time_secs;
|
||||
base->time_tv = time_tv;
|
||||
if(settime(base) < 0) {
|
||||
_getdns_event_base_free(base);
|
||||
return NULL;
|
||||
}
|
||||
base->items = (struct _getdns_event**)calloc(WSK_MAX_ITEMS,
|
||||
sizeof(struct _getdns_event*));
|
||||
if(!base->items) {
|
||||
_getdns_event_base_free(base);
|
||||
return NULL;
|
||||
}
|
||||
base->cap = WSK_MAX_ITEMS;
|
||||
base->max = 0;
|
||||
base->times = _getdns_rbtree_create(_getdns_mini_ev_cmp);
|
||||
if(!base->times) {
|
||||
_getdns_event_base_free(base);
|
||||
return NULL;
|
||||
}
|
||||
base->signals = (struct _getdns_event**)calloc(MAX_SIG,
|
||||
sizeof(struct _getdns_event*));
|
||||
if(!base->signals) {
|
||||
_getdns_event_base_free(base);
|
||||
return NULL;
|
||||
}
|
||||
base->tcp_stickies = 0;
|
||||
base->tcp_reinvigorated = 0;
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
const char *_getdns_event_get_version(void)
|
||||
{
|
||||
return "winsock-event-"PACKAGE_VERSION;
|
||||
}
|
||||
|
||||
const char *_getdns_event_get_method(void)
|
||||
{
|
||||
return "WSAWaitForMultipleEvents";
|
||||
}
|
||||
|
||||
/** call timeouts handlers, and return how long to wait for next one or -1 */
|
||||
void _getdns_handle_timeouts(struct _getdns_event_base* base, struct timeval* now,
|
||||
struct timeval* wait)
|
||||
{
|
||||
struct _getdns_event* p;
|
||||
#ifndef S_SPLINT_S
|
||||
wait->tv_sec = (time_t)-1;
|
||||
#endif
|
||||
|
||||
while((_getdns_rbnode_t*)(p = (struct _getdns_event*)_getdns_rbtree_first(base->times))
|
||||
!=RBTREE_NULL) {
|
||||
#ifndef S_SPLINT_S
|
||||
if(p->ev_timeout.tv_sec > now->tv_sec ||
|
||||
(p->ev_timeout.tv_sec==now->tv_sec &&
|
||||
p->ev_timeout.tv_usec > now->tv_usec)) {
|
||||
/* there is a next larger timeout. wait for it */
|
||||
wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec;
|
||||
if(now->tv_usec > p->ev_timeout.tv_usec) {
|
||||
wait->tv_sec--;
|
||||
wait->tv_usec = 1000000 - (now->tv_usec -
|
||||
p->ev_timeout.tv_usec);
|
||||
} else {
|
||||
wait->tv_usec = p->ev_timeout.tv_usec
|
||||
- now->tv_usec;
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
/* event times out, remove it */
|
||||
(void)_getdns_rbtree_delete(base->times, p);
|
||||
p->ev_events &= ~EV_TIMEOUT;
|
||||
fptr_ok(fptr_whitelist_event(p->ev_callback));
|
||||
(*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg);
|
||||
}
|
||||
}
|
||||
|
||||
/** handle is_signal events and see if signalled */
|
||||
static void _getdns_handle_signal(struct _getdns_event* ev)
|
||||
{
|
||||
printf("In _getdns_handle_signal\n");
|
||||
DWORD ret;
|
||||
//log_assert(ev->is_signal && ev->hEvent);
|
||||
/* see if the event is signalled */
|
||||
ret = WSAWaitForMultipleEvents(1, &ev->hEvent, 0 /* any object */,
|
||||
0 /* return immediately */, 0 /* not alertable for IOcomple*/);
|
||||
if(ret == WSA_WAIT_IO_COMPLETION || ret == WSA_WAIT_FAILED) {
|
||||
log_err("getdns: WSAWaitForMultipleEvents(signal) failed: %s",
|
||||
wsa_strerror(WSAGetLastError()));
|
||||
return;
|
||||
}
|
||||
if(ret == WSA_WAIT_TIMEOUT) {
|
||||
/* not signalled */
|
||||
return;
|
||||
}
|
||||
|
||||
/* reset the signal */
|
||||
if(!WSAResetEvent(ev->hEvent))
|
||||
log_err("getdns: WSAResetEvent failed: %s",
|
||||
wsa_strerror(WSAGetLastError()));
|
||||
/* do the callback (which may set the signal again) */
|
||||
fptr_ok(fptr_whitelist_event(ev->ev_callback));
|
||||
(*ev->ev_callback)(ev->ev_fd, ev->ev_events, ev->ev_arg);
|
||||
}
|
||||
|
||||
/** call select and callbacks for that */
|
||||
int _getdns_handle_select(struct _getdns_event_base* base, struct timeval* wait)
|
||||
{
|
||||
DWORD timeout = 0; /* in milliseconds */
|
||||
DWORD ret;
|
||||
WSANETWORKEVENTS netev;
|
||||
struct _getdns_event* eventlist[WSK_MAX_ITEMS];
|
||||
int i, numwait = 0, startidx = 0;
|
||||
int newstickies = 0;
|
||||
struct timeval nultm;
|
||||
|
||||
#ifndef S_SPLINT_S
|
||||
if(wait->tv_sec==(time_t)-1)
|
||||
wait = NULL;
|
||||
if (wait)
|
||||
// timeout = 10 + wait->tv_usec / 1000;
|
||||
timeout = wait->tv_sec * 1000 + wait->tv_usec / 1000;
|
||||
if(base->tcp_stickies) {
|
||||
wait = &nultm;
|
||||
nultm.tv_sec = 0;
|
||||
nultm.tv_usec = 0;
|
||||
timeout = 0; /* no waiting, we have sticky events */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* prepare event array */
|
||||
for(i=0; i<base->max; i++) {
|
||||
if(base->items[i]->ev_fd == -1 && !base->items[i]->is_signal)
|
||||
continue; /* skip timer only events */
|
||||
eventlist[numwait] = base->items[i];
|
||||
base->waitfor[numwait++] = base->items[i]->hEvent;
|
||||
printf("winsock_event bmax=%d numwait=%d wait=%x "
|
||||
"timeout=%d hEvent %d\n", base->max, numwait, (int)wait,
|
||||
(int)timeout, (int)base->items[i]->hEvent);
|
||||
if (numwait == WSK_MAX_ITEMS)
|
||||
break; /* sanity check */
|
||||
}
|
||||
//log_assert(numwait <= WSA_MAXIMUM_WAIT_EVENTS);
|
||||
|
||||
/* do the wait */
|
||||
if(numwait == 0) {
|
||||
/* WSAWaitFor.. doesn't like 0 event objects */
|
||||
if(wait) {
|
||||
Sleep(timeout);
|
||||
}
|
||||
}
|
||||
else {
|
||||
//gv: do not schedule udp write
|
||||
for (i = 0; i<base->max; i++) {
|
||||
if (!base->items[i]->is_tcp && base->items[i]->ev_events&EV_WRITE) {
|
||||
printf("skip UDP sched\n");
|
||||
(*eventlist[i]->ev_callback)(eventlist[i]->ev_fd,
|
||||
EV_WRITE & eventlist[i]->ev_events,
|
||||
eventlist[i]->ev_arg);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
printf("before wait %d\n", base->items[0]->ev_events);
|
||||
ret = WSAWaitForMultipleEvents(numwait, base->waitfor,
|
||||
0 /* do not wait for all, just one will do */,
|
||||
wait?timeout:WSA_INFINITE,
|
||||
0); /* we are not alertable (IO completion events) */
|
||||
printf("after wait %d %d\n", (int)ret, numwait);
|
||||
if(ret == WSA_WAIT_IO_COMPLETION) {
|
||||
//printf("getdns: WSAWaitForMultipleEvents failed: WSA_WAIT_IO_COMPLETION");
|
||||
return -1;
|
||||
} else if(ret == WSA_WAIT_FAILED) {
|
||||
//printf("getdns: WSAWaitForMultipleEvents failed: %s",
|
||||
// wsa_strerror(WSAGetLastError()));
|
||||
return -1;
|
||||
} else if(ret == WSA_WAIT_TIMEOUT) {
|
||||
printf("timeout\n");
|
||||
} else
|
||||
startidx = ret - WSA_WAIT_EVENT_0;
|
||||
}
|
||||
////verbose(VERB_CLIENT, "winsock_event wake was_timeout=%d startidx=%d",
|
||||
// was_timeout, startidx);
|
||||
|
||||
/* get new time after wait */
|
||||
if(settime(base) < 0)
|
||||
return -1;
|
||||
|
||||
/* callbacks */
|
||||
if(base->tcp_stickies)
|
||||
startidx = 0; /* process all events, some are sticky */
|
||||
for(i=startidx; i<numwait; i++)
|
||||
eventlist[i]->just_checked = 1;
|
||||
|
||||
//verbose(VERB_CLIENT, "winsock_event signals");
|
||||
for(i=startidx; i<numwait; i++) {
|
||||
if(!base->waitfor[i])
|
||||
continue; /* was deleted */
|
||||
if(eventlist[i]->is_signal) {
|
||||
eventlist[i]->just_checked = 0;
|
||||
_getdns_handle_signal(eventlist[i]);
|
||||
}
|
||||
}
|
||||
/* early exit - do not process network, exit quickly */
|
||||
if(base->need_to_exit)
|
||||
return 0;
|
||||
|
||||
//verbose(VERB_CLIENT, "winsock_event net");
|
||||
for(i=startidx; i<numwait; i++) {
|
||||
short bits = 0;
|
||||
/* eventlist[i] fired */
|
||||
/* see if eventlist[i] is still valid and just checked from
|
||||
* WSAWaitForEvents */
|
||||
if(!base->waitfor[i])
|
||||
continue; /* was deleted */
|
||||
if(!eventlist[i]->just_checked)
|
||||
continue; /* added by other callback */
|
||||
if(eventlist[i]->is_signal)
|
||||
continue; /* not a network event at all */
|
||||
eventlist[i]->just_checked = 0;
|
||||
|
||||
if(WSAEnumNetworkEvents(eventlist[i]->ev_fd,
|
||||
base->waitfor[i], /* reset the event handle */
|
||||
/*NULL,*/ /* do not reset the event handle */
|
||||
&netev) != 0) {
|
||||
log_err("getdns: WSAEnumNetworkEvents failed: %s",
|
||||
wsa_strerror(WSAGetLastError()));
|
||||
return -1;
|
||||
}
|
||||
if((netev.lNetworkEvents & FD_READ)) {
|
||||
if(netev.iErrorCode[FD_READ_BIT] != 0)
|
||||
printf("FD_READ_BIT error: %s\n",
|
||||
wsa_strerror(netev.iErrorCode[FD_READ_BIT]));
|
||||
bits |= EV_READ;
|
||||
printf("FD_READ_BIT\n");
|
||||
}
|
||||
if((netev.lNetworkEvents & FD_WRITE)) {
|
||||
if(netev.iErrorCode[FD_WRITE_BIT] != 0)
|
||||
printf("FD_WRITE_BIT error: %s\n",
|
||||
wsa_strerror(netev.iErrorCode[FD_WRITE_BIT]));
|
||||
bits |= EV_WRITE;
|
||||
printf("FD_WRITE_BIT\n");
|
||||
}
|
||||
if((netev.lNetworkEvents & FD_CONNECT)) {
|
||||
if(netev.iErrorCode[FD_CONNECT_BIT] != 0)
|
||||
printf("FD_CONNECT_BIT error: %s\n",
|
||||
wsa_strerror(netev.iErrorCode[FD_CONNECT_BIT]));
|
||||
bits |= EV_READ;
|
||||
bits |= EV_WRITE;
|
||||
printf("FD_CONNECT_BIT\n");
|
||||
}
|
||||
if((netev.lNetworkEvents & FD_ACCEPT)) {
|
||||
if(netev.iErrorCode[FD_ACCEPT_BIT] != 0)
|
||||
printf("FD_ACCEPT_BIT error: %s\n",
|
||||
wsa_strerror(netev.iErrorCode[FD_ACCEPT_BIT]));
|
||||
bits |= EV_READ;
|
||||
printf("FD_ACCEPT_BIT\n");
|
||||
}
|
||||
if((netev.lNetworkEvents & FD_CLOSE)) {
|
||||
if(netev.iErrorCode[FD_CLOSE_BIT] != 0)
|
||||
printf("FD_CLOSE_BIT error: %s\n",
|
||||
wsa_strerror(netev.iErrorCode[FD_CLOSE_BIT]));
|
||||
//g bits |= EV_READ;
|
||||
//g bits |= EV_WRITE;
|
||||
printf("FD_CLOSE_BIT\n");
|
||||
}
|
||||
if(eventlist[i]->is_tcp && eventlist[i]->stick_events) {
|
||||
|
||||
printf("winsock %d pass sticky %s%s\n",
|
||||
eventlist[i]->ev_fd,
|
||||
(eventlist[i]->old_events&EV_READ)?"EV_READ":"",
|
||||
(eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":"");
|
||||
|
||||
bits |= eventlist[i]->old_events;
|
||||
}
|
||||
if(eventlist[i]->is_tcp && bits) {
|
||||
eventlist[i]->old_events = bits;
|
||||
eventlist[i]->stick_events = 1;
|
||||
if((eventlist[i]->ev_events & bits)) {
|
||||
newstickies = 1;
|
||||
}
|
||||
|
||||
printf("winsock %d store sticky %s%s",
|
||||
eventlist[i]->ev_fd,
|
||||
(eventlist[i]->old_events&EV_READ)?"EV_READ":"",
|
||||
(eventlist[i]->old_events&EV_WRITE) ? "EV_WRITE" : "");
|
||||
|
||||
}
|
||||
if((bits & eventlist[i]->ev_events)) {
|
||||
printf( "winsock event callback %p fd=%d "
|
||||
"%s%s%s%s%s ; %s%s%s\n",
|
||||
eventlist[i], eventlist[i]->ev_fd,
|
||||
(netev.lNetworkEvents&FD_READ)?" FD_READ":"",
|
||||
(netev.lNetworkEvents&FD_WRITE)?" FD_WRITE":"",
|
||||
(netev.lNetworkEvents&FD_CONNECT)?
|
||||
" FD_CONNECT":"",
|
||||
(netev.lNetworkEvents&FD_ACCEPT)?
|
||||
" FD_ACCEPT":"",
|
||||
(netev.lNetworkEvents&FD_CLOSE)?" FD_CLOSE":"",
|
||||
(bits&EV_READ)?" EV_READ":"",
|
||||
(bits&EV_WRITE)?" EV_WRITE":"",
|
||||
(bits&EV_TIMEOUT)?" EV_TIMEOUT":"");
|
||||
|
||||
fptr_ok(fptr_whitelist_event(
|
||||
eventlist[i]->ev_callback));
|
||||
(*eventlist[i]->ev_callback)(eventlist[i]->ev_fd,
|
||||
bits & eventlist[i]->ev_events,
|
||||
eventlist[i]->ev_arg);
|
||||
}
|
||||
|
||||
if(eventlist[i]->is_tcp && bits)
|
||||
printf( "winsock %d got sticky %s%s\n",
|
||||
eventlist[i]->ev_fd,
|
||||
(eventlist[i]->old_events&EV_READ)?"EV_READ":"",
|
||||
(eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":"");
|
||||
|
||||
}
|
||||
//verbose(VERB_CLIENT, "winsock_event net");
|
||||
if(base->tcp_reinvigorated) {
|
||||
printf("winsock_event reinvigorated\n");
|
||||
base->tcp_reinvigorated = 0;
|
||||
newstickies = 1;
|
||||
}
|
||||
base->tcp_stickies = newstickies;
|
||||
//gprintf("winsock_event handle_select end\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _getdns_event_base_dispatch(struct _getdns_event_base *base)
|
||||
{
|
||||
struct timeval wait;
|
||||
if(settime(base) < 0)
|
||||
return -1;
|
||||
while(!base->need_to_exit)
|
||||
{
|
||||
/* see if timeouts need handling */
|
||||
_getdns_handle_timeouts(base, base->time_tv, &wait);
|
||||
if(base->need_to_exit)
|
||||
return 0;
|
||||
/* do select */
|
||||
if(_getdns_handle_select(base, &wait) < 0) {
|
||||
if(base->need_to_exit)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _getdns_event_base_loopexit(struct _getdns_event_base *base,
|
||||
struct timeval * ATTR_UNUSED(tv))
|
||||
{
|
||||
base->need_to_exit = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _getdns_event_base_free(struct _getdns_event_base *base)
|
||||
{
|
||||
if(!base)
|
||||
return;
|
||||
if(base->items)
|
||||
free(base->items);
|
||||
if(base->times)
|
||||
free(base->times);
|
||||
if(base->signals)
|
||||
free(base->signals);
|
||||
free(base);
|
||||
}
|
||||
|
||||
void _getdns_event_set(struct _getdns_event *ev, int fd, short bits,
|
||||
void (*cb)(int, short, void *), void *arg)
|
||||
{
|
||||
ev->node.key = ev;
|
||||
ev->ev_fd = fd;
|
||||
ev->ev_events = bits;
|
||||
ev->ev_callback = cb;
|
||||
fptr_ok(fptr_whitelist_event(ev->ev_callback));
|
||||
ev->ev_arg = arg;
|
||||
ev->just_checked = 0;
|
||||
ev->added = 0;
|
||||
}
|
||||
|
||||
int _getdns_event_base_set(struct _getdns_event_base *base, struct _getdns_event *ev)
|
||||
{
|
||||
ev->ev_base = base;
|
||||
ev->old_events = 0;
|
||||
ev->stick_events = 0;
|
||||
ev->added = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _getdns_event_add(struct _getdns_event *ev, struct timeval *tv)
|
||||
{
|
||||
printf( "event_add %p added=%d fd=%d tv=" ARG_LL "d %s%s%s\n",
|
||||
ev, ev->added, ev->ev_fd,
|
||||
(tv?(long long)tv->tv_sec*1000+(long long)tv->tv_usec/1000:-1),
|
||||
(ev->ev_events&EV_READ)?" EV_READ":"",
|
||||
(ev->ev_events&EV_WRITE)?" EV_WRITE":"",
|
||||
(ev->ev_events&EV_TIMEOUT)?" EV_TIMEOUT":"");
|
||||
|
||||
if(ev->added)
|
||||
_getdns_event_del(ev);
|
||||
|
||||
ev->is_tcp = 0;
|
||||
ev->is_signal = 0;
|
||||
ev->just_checked = 0;
|
||||
|
||||
if ((ev->ev_events&(EV_READ | EV_WRITE)) && ev->ev_fd != -1) {
|
||||
BOOL b = 0;
|
||||
int t, l;
|
||||
long events = 0;
|
||||
//gprintf("\getdns_event_add %d %d\n", ev->ev_fd, events);
|
||||
|
||||
if (ev->ev_base->max == ev->ev_base->cap)
|
||||
return -1;
|
||||
ev->idx = ev->ev_base->max++;
|
||||
ev->ev_base->items[ev->idx] = ev;
|
||||
|
||||
if ((ev->ev_events&EV_READ))
|
||||
events |= FD_READ;
|
||||
if ((ev->ev_events&EV_WRITE))
|
||||
{
|
||||
events |= FD_CONNECT;
|
||||
events |= FD_WRITE;
|
||||
}
|
||||
|
||||
//printf("\getdns_event_add %d read = %d write = %d %d\n", ev->ev_fd, ev->ev_events&EV_READ, ev->ev_events&EV_WRITE, events);
|
||||
|
||||
l = sizeof(t);
|
||||
if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_TYPE,
|
||||
(void*)&t, &l) != 0)
|
||||
log_err("getdns: getsockopt(SO_TYPE) failed: %s",
|
||||
wsa_strerror(WSAGetLastError()));
|
||||
if(t == SOCK_STREAM) {
|
||||
/* TCP socket */
|
||||
ev->is_tcp = 1;
|
||||
events |= FD_CLOSE;
|
||||
if( (ev->ev_events&EV_WRITE) )
|
||||
events |= FD_CONNECT;
|
||||
l = sizeof(b);
|
||||
if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_ACCEPTCONN,
|
||||
(void*)&b, &l) != 0)
|
||||
log_err("getdns: getsockopt(SO_ACCEPTCONN) failed: %s",
|
||||
wsa_strerror(WSAGetLastError()));
|
||||
if(b) /* TCP accept socket */
|
||||
events |= FD_ACCEPT;
|
||||
}
|
||||
ev->hEvent = WSACreateEvent();
|
||||
if(ev->hEvent == WSA_INVALID_EVENT)
|
||||
log_err("getdns: WSACreateEvent failed: %s",
|
||||
wsa_strerror(WSAGetLastError()));
|
||||
/* automatically sets fd to nonblocking mode.
|
||||
* nonblocking cannot be disabled, until wsaES(fd, NULL, 0) */
|
||||
printf("\nWSAEventSelect %d events %d hEvent %d\n", ev->ev_fd, (int)events, (int)ev->hEvent);
|
||||
if (WSAEventSelect(ev->ev_fd, ev->hEvent, events) != 0) {
|
||||
log_err("getdns: WSAEventSelect in getdns failed: %s",
|
||||
wsa_strerror(WSAGetLastError()));
|
||||
}
|
||||
if(ev->is_tcp && ev->stick_events &&
|
||||
(ev->ev_events & ev->old_events)) {
|
||||
/* go to processing the sticky event right away */
|
||||
printf("\nWSAEventSelect sticky %d events %d hEvent %d\n", ev->ev_fd, (int)events, (int)ev->hEvent);
|
||||
ev->ev_base->tcp_reinvigorated = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(tv && (ev->ev_events&EV_TIMEOUT)) {
|
||||
printf("\nWSAEventSelect timeout %d hEvent %d\n", ev->ev_fd, (int)ev->hEvent);
|
||||
|
||||
#ifndef S_SPLINT_S
|
||||
struct timeval *now = ev->ev_base->time_tv;
|
||||
ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec;
|
||||
ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec;
|
||||
while(ev->ev_timeout.tv_usec > 1000000) {
|
||||
ev->ev_timeout.tv_usec -= 1000000;
|
||||
ev->ev_timeout.tv_sec++;
|
||||
}
|
||||
#endif
|
||||
(void)_getdns_rbtree_insert(ev->ev_base->times, &ev->node);
|
||||
}
|
||||
ev->added = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _getdns_event_del(struct _getdns_event *ev)
|
||||
{
|
||||
//verbose(VERB_ALGO, "event_del %p added=%d fd=%d tv=" ARG_LL "d %s%s%s",
|
||||
// ev, ev->added, ev->ev_fd,
|
||||
// (ev->ev_events&EV_TIMEOUT)?(long long)ev->ev_timeout.tv_sec*1000+
|
||||
// (long long)ev->ev_timeout.tv_usec/1000:-1,
|
||||
// (ev->ev_events&EV_READ)?" EV_READ":"",
|
||||
// (ev->ev_events&EV_WRITE)?" EV_WRITE":"",
|
||||
// (ev->ev_events&EV_TIMEOUT)?" EV_TIMEOUT":"");
|
||||
if(!ev->added)
|
||||
return 0;
|
||||
//log_assert(ev->added);
|
||||
if((ev->ev_events&EV_TIMEOUT))
|
||||
(void)_getdns_rbtree_delete(ev->ev_base->times, &ev->node);
|
||||
if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
|
||||
//log_assert(ev->ev_base->max > 0);
|
||||
/* remove item and compact the list */
|
||||
ev->ev_base->items[ev->idx] =
|
||||
ev->ev_base->items[ev->ev_base->max-1];
|
||||
ev->ev_base->items[ev->ev_base->max-1] = NULL;
|
||||
ev->ev_base->max--;
|
||||
if(ev->idx < ev->ev_base->max)
|
||||
ev->ev_base->items[ev->idx]->idx = ev->idx;
|
||||
zero_waitfor(ev->ev_base->waitfor, ev->hEvent);
|
||||
|
||||
if(WSAEventSelect(ev->ev_fd, ev->hEvent, 0) != 0)
|
||||
log_err("getdns: WSAEventSelect(disable) failed: %s",
|
||||
wsa_strerror(WSAGetLastError()));
|
||||
if(!WSACloseEvent(ev->hEvent))
|
||||
log_err("getdns: WSACloseEvent failed: %s",
|
||||
wsa_strerror(WSAGetLastError()));
|
||||
}
|
||||
ev->just_checked = 0;
|
||||
ev->added = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** which base gets to handle signals */
|
||||
static struct _getdns_event_base* signal_base = NULL;
|
||||
/** signal handler */
|
||||
static RETSIGTYPE sigh(int sig)
|
||||
{
|
||||
if(!signal_base || sig < 0 || sig >= MAX_SIG)
|
||||
return;
|
||||
}
|
||||
|
||||
int _getdns_signal_add(struct _getdns_event *ev, struct timeval * ATTR_UNUSED(tv))
|
||||
{
|
||||
if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
|
||||
return -1;
|
||||
signal_base = ev->ev_base;
|
||||
ev->ev_base->signals[ev->ev_fd] = ev;
|
||||
ev->added = 1;
|
||||
if(signal(ev->ev_fd, sigh) == SIG_ERR) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _getdns_signal_del(struct _getdns_event *ev)
|
||||
{
|
||||
if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
|
||||
return -1;
|
||||
ev->ev_base->signals[ev->ev_fd] = NULL;
|
||||
ev->added = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void winsock_tcp_wouldblock(struct _getdns_event* ev, int eventbits)
|
||||
{
|
||||
printf("winsock: tcp wouldblock %s\n",
|
||||
eventbits==EV_READ?"EV_READ":"EV_WRITE");
|
||||
ev->old_events &= (~eventbits);
|
||||
if(ev->old_events == 0)
|
||||
ev->stick_events = 0;
|
||||
/* in case this is the last sticky event, we could
|
||||
* possibly run an empty handler loop to reset the base
|
||||
* tcp_stickies variable
|
||||
*/
|
||||
}
|
||||
|
||||
int winsock_register_wsaevent(struct _getdns_event_base* base, struct _getdns_event* ev,
|
||||
WSAEVENT wsaevent, void (*cb)(int, short, void*), void* arg)
|
||||
{
|
||||
if(base->max == base->cap)
|
||||
return 0;
|
||||
memset(ev, 0, sizeof(*ev));
|
||||
ev->ev_fd = -1;
|
||||
ev->ev_events = EV_READ;
|
||||
ev->ev_callback = cb;
|
||||
ev->ev_arg = arg;
|
||||
ev->is_signal = 1;
|
||||
ev->hEvent = wsaevent;
|
||||
ev->added = 1;
|
||||
ev->ev_base = base;
|
||||
ev->idx = ev->ev_base->max++;
|
||||
ev->ev_base->items[ev->idx] = ev;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void winsock_unregister_wsaevent(struct _getdns_event* ev)
|
||||
{
|
||||
if(!ev || !ev->added) return;
|
||||
//log_assert(ev->added && ev->ev_base->max > 0)
|
||||
/* remove item and compact the list */
|
||||
ev->ev_base->items[ev->idx] = ev->ev_base->items[ev->ev_base->max-1];
|
||||
ev->ev_base->items[ev->ev_base->max-1] = NULL;
|
||||
ev->ev_base->max--;
|
||||
if(ev->idx < ev->ev_base->max)
|
||||
ev->ev_base->items[ev->idx]->idx = ev->idx;
|
||||
ev->added = 0;
|
||||
}
|
||||
|
||||
#else /* USE_WINSOCK */
|
||||
/** symbol so this codefile defines symbols. pleasing ranlib on OSX 10.5 */
|
||||
int winsock_unused_symbol = 1;
|
||||
#endif /* USE_WINSOCK */
|
|
@ -1,295 +0,0 @@
|
|||
/*
|
||||
* util/winsock_event.h - getdns event handling for winsock on windows
|
||||
* extracted from Unbound source code and modified for getdns
|
||||
*
|
||||
* Copyright (c) 2015, NLnet Labs/Verisign. All rights reserved.
|
||||
*
|
||||
* This software is open source.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of the NLNET LABS or Verisign nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* This file contains interface functions with the WinSock2 API on Windows.
|
||||
* It uses the winsock WSAWaitForMultipleEvents interface on a number of
|
||||
* sockets.
|
||||
* Code is originally from the Unbound source for Windows.
|
||||
*
|
||||
* Note that windows can only wait for max 64 events at one time.
|
||||
*
|
||||
* Also, file descriptors cannot be waited for.
|
||||
*
|
||||
* Named pipes are not easily available (and are not usable in select() ).
|
||||
* For interprocess communication, it is possible to wait for a hEvent to
|
||||
* be signaled by another thread.
|
||||
*
|
||||
* When a socket becomes readable, then it will not be flagged as
|
||||
* readable again until you have gotten WOULDBLOCK from a recv routine.
|
||||
* That means the event handler must store the readability (edge notify)
|
||||
* and process the incoming data until it blocks.
|
||||
* The function performing recv then has to inform the event handler that
|
||||
* the socket has blocked, and the event handler can mark it as such.
|
||||
* Thus, this file transforms the edge notify from windows to a level notify
|
||||
* that is compatible with UNIX.
|
||||
* The WSAEventSelect page says that it does do level notify, as long
|
||||
* as you call a recv/write/accept at least once when it is signalled.
|
||||
* This last bit is not true, even though documented in server2008 api docs
|
||||
* from microsoft, it does not happen at all. Instead you have to test for
|
||||
* WSAEWOULDBLOCK on a tcp stream, and only then retest the socket.
|
||||
* And before that remember the previous result as still valid.
|
||||
*
|
||||
* To stay 'fair', instead of emptying a socket completely, the event handler
|
||||
* can test the other (marked as blocking) sockets for new events.
|
||||
*
|
||||
* Additionally, TCP accept sockets get special event support.
|
||||
*
|
||||
* Socket numbers are not starting small, they can be any number (say 33060).
|
||||
* Therefore, bitmaps are not used, but arrays.
|
||||
*
|
||||
* on winsock, you must use recv() and send() for TCP reads and writes,
|
||||
* not read() and write(), those work only on files.
|
||||
*
|
||||
* Also fseek and fseeko do not work if a FILE is not fopen-ed in binary mode.
|
||||
*
|
||||
* When under a high load windows gives out lots of errors, from recvfrom
|
||||
* on udp sockets for example (WSAECONNRESET). Even though the udp socket
|
||||
* has no connection per se.
|
||||
*/
|
||||
|
||||
#ifndef UTIL_WINSOCK_EVENT_H
|
||||
#define UTIL_WINSOCK_EVENT_H
|
||||
|
||||
// Only enabled for Windows
|
||||
#ifdef USE_WINSOCK
|
||||
|
||||
#ifndef HAVE_EVENT_BASE_FREE
|
||||
#define HAVE_EVENT_BASE_FREE
|
||||
#endif
|
||||
|
||||
/* redefine the calls to different names so that there is no name
|
||||
* collision with other code that uses libevent names. (that uses libunbound)*/
|
||||
#define _getdns_event_init winsockevent_init
|
||||
#define event_get_version winsockevent_get_version
|
||||
#define event_get_method winsockevent_get_method
|
||||
#define _getdns_event_base_dispatch winsockevent_base_dispatch
|
||||
#define event_base_loopexit winsockevent_base_loopexit
|
||||
#define _getdns_event_base_free winsockevent_base_free
|
||||
#define _getdns_event_set winsockevent_set
|
||||
#define _getdns_event_base_set winsockevent_base_set
|
||||
#define _getdns_event_add winsockevent_add
|
||||
#define _getdns_event_del winsockevent_del
|
||||
#define signal_add winsocksignal_add
|
||||
#define signal_del winsocksignal_del
|
||||
|
||||
/** event timeout */
|
||||
#define EV_TIMEOUT 0x01
|
||||
/** event fd readable */
|
||||
#define EV_READ 0x02
|
||||
/** event fd writable */
|
||||
#define EV_WRITE 0x04
|
||||
/** event signal */
|
||||
#define EV_SIGNAL 0x08
|
||||
/** event must persist */
|
||||
#define EV_PERSIST 0x10
|
||||
|
||||
/* needs our redblack tree */
|
||||
#include "util/rbtree.h"
|
||||
|
||||
/** max number of signals to support */
|
||||
#define MAX_SIG 32
|
||||
|
||||
/** The number of items that the winsock event handler can service.
|
||||
* Windows cannot handle more anyway */
|
||||
#define WSK_MAX_ITEMS 64
|
||||
|
||||
/**
|
||||
* event base for winsock event handler
|
||||
*/
|
||||
struct _getdns_event_base
|
||||
{
|
||||
/** sorted by timeout (absolute), ptr */
|
||||
_getdns_rbtree_t* times;
|
||||
/** array (first part in use) of handles to work on */
|
||||
struct _getdns_event** items;
|
||||
/** number of items in use in array */
|
||||
int max;
|
||||
/** capacity of array, size of array in items */
|
||||
int cap;
|
||||
/** array of 0 - maxsig of ptr to event for it */
|
||||
struct _getdns_event** signals;
|
||||
/** if we need to exit */
|
||||
int need_to_exit;
|
||||
/** where to store time in seconds */
|
||||
time_t* time_secs;
|
||||
/** where to store time in microseconds */
|
||||
struct timeval* time_tv;
|
||||
/**
|
||||
* TCP streams have sticky events to them, these are not
|
||||
* reported by the windows event system anymore, we have to
|
||||
* keep reporting those events as present until wouldblock() is
|
||||
* signalled by the handler back to use.
|
||||
*/
|
||||
int tcp_stickies;
|
||||
/**
|
||||
* should next cycle process reinvigorated stickies,
|
||||
* these are stickies that have been stored, but due to a new
|
||||
* event_add a sudden interest in the event has incepted.
|
||||
*/
|
||||
int tcp_reinvigorated;
|
||||
/** The list of events that is currently being processed. */
|
||||
WSAEVENT waitfor[WSK_MAX_ITEMS];
|
||||
|
||||
/* fdset for read write, for fds ready, and added */
|
||||
fd_set
|
||||
/** fds for reading */
|
||||
reads,
|
||||
/** fds for writing */
|
||||
writes,
|
||||
/** fds determined ready for use */
|
||||
ready,
|
||||
/** ready plus newly added events. */
|
||||
content;
|
||||
};
|
||||
|
||||
/**
|
||||
* Event structure. Has some of the event elements.
|
||||
*/
|
||||
struct _getdns_event {
|
||||
/** node in timeout rbtree */
|
||||
_getdns_rbnode_t node;
|
||||
/** is event already added */
|
||||
int added;
|
||||
|
||||
/** event base it belongs to */
|
||||
struct _getdns_event_base *ev_base;
|
||||
/** fd to poll or -1 for timeouts. signal number for sigs. */
|
||||
int ev_fd;
|
||||
/** what events this event is interested in, see EV_.. above. */
|
||||
short ev_events;
|
||||
/** timeout value */
|
||||
struct timeval ev_timeout;
|
||||
|
||||
/** callback to call: fd, eventbits, userarg */
|
||||
void (*ev_callback)(int, short, void *);
|
||||
/** callback user arg */
|
||||
void *ev_arg;
|
||||
|
||||
/* ----- nonpublic part, for winsock_event only ----- */
|
||||
/** index of this event in the items array (if added) */
|
||||
int idx;
|
||||
/** the event handle to wait for new events to become ready */
|
||||
WSAEVENT hEvent;
|
||||
/** true if this filedes is a TCP socket and needs special attention */
|
||||
int is_tcp;
|
||||
/** remembered EV_ values */
|
||||
short old_events;
|
||||
/** should remembered EV_ values be used for TCP streams.
|
||||
* Reset after WOULDBLOCK is signaled using the function. */
|
||||
int stick_events;
|
||||
|
||||
/** true if this event is a signaling WSAEvent by the user.
|
||||
* User created and user closed WSAEvent. Only signaled/unsigneled,
|
||||
* no read/write/distinctions needed. */
|
||||
int is_signal;
|
||||
/** used during callbacks to see which events were just checked */
|
||||
int just_checked;
|
||||
};
|
||||
|
||||
char* wsa_strerror(DWORD err);
|
||||
void log_err(const char *format, ...);
|
||||
/** create event base */
|
||||
void *_getdns_event_init(time_t* time_secs, struct timeval* time_tv);
|
||||
/** get version */
|
||||
const char *event_get_version(void);
|
||||
/** get polling method (select,epoll) */
|
||||
const char *event_get_method(void);
|
||||
/** run select in a loop */
|
||||
int _getdns_event_base_dispatch(struct _getdns_event_base *);
|
||||
/** exit that loop */
|
||||
int event_base_loopexit(struct _getdns_event_base *, struct timeval *);
|
||||
/** free event base. Free events yourself */
|
||||
void _getdns_event_base_free(struct _getdns_event_base *);
|
||||
/** set content of event */
|
||||
void _getdns_event_set(struct _getdns_event *, int, short, void (*)(int, short, void *), void *);
|
||||
|
||||
/** add event to a base. You *must* call this for every event. */
|
||||
int _getdns_event_base_set(struct _getdns_event_base *, struct _getdns_event *);
|
||||
/** add event to make it active. You may not change it with event_set anymore */
|
||||
int _getdns_event_add(struct _getdns_event *, struct timeval *);
|
||||
/** remove event. You may change it again */
|
||||
int _getdns_event_del(struct _getdns_event *);
|
||||
|
||||
#define evtimer_add(ev, tv) event_add(ev, tv)
|
||||
#define evtimer_del(ev) event_del(ev)
|
||||
|
||||
/* uses different implementation. Cannot mix fd/timeouts and signals inside
|
||||
* the same struct event. create several event structs for that. */
|
||||
/** install signal handler */
|
||||
int signal_add(struct _getdns_event *, struct timeval *);
|
||||
/** set signal event contents */
|
||||
#define signal_set(ev, x, cb, arg) \
|
||||
event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg)
|
||||
/** remove signal handler */
|
||||
int signal_del(struct _getdns_event *);
|
||||
|
||||
/** compare events in tree, based on timevalue, ptr for uniqueness */
|
||||
int getdns_mini_ev_cmp(const void* a, const void* b);
|
||||
|
||||
/**
|
||||
* Routine for windows only, where the handling layer can signal that
|
||||
* a TCP stream encountered WSAEWOULDBLOCK for a stream and thus needs
|
||||
* retesting the event.
|
||||
* Pass if EV_READ or EV_WRITE gave wouldblock.
|
||||
*/
|
||||
void winsock_tcp_wouldblock(struct _getdns_event* ev, int eventbit);
|
||||
|
||||
/**
|
||||
* Routine for windows only. where you pass a signal WSAEvent that
|
||||
* you wait for. When the event is signaled, the callback gets called.
|
||||
* The callback has to WSAResetEvent to disable the signal.
|
||||
* @param base: the event base.
|
||||
* @param ev: the event structure for data storage
|
||||
* can be passed uninitialised.
|
||||
* @param wsaevent: the WSAEvent that gets signaled.
|
||||
* @param cb: callback routine.
|
||||
* @param arg: user argument to callback routine.
|
||||
* @return false on error.
|
||||
*/
|
||||
int winsock_register_wsaevent(struct _getdns_event_base* base, struct _getdns_event* ev,
|
||||
WSAEVENT wsaevent, void (*cb)(int, short, void*), void* arg);
|
||||
|
||||
/**
|
||||
* Unregister a wsaevent. User has to close the WSAEVENT itself.
|
||||
* @param ev: event data storage.
|
||||
*/
|
||||
void winsock_unregister_wsaevent(struct _getdns_event* ev);
|
||||
|
||||
#endif /* USE_WINSOCK */
|
||||
#endif /* UTIL_WINSOCK_EVENT_H */
|
Loading…
Reference in New Issue