From 2d58ed465c341921d00352961a925b50d9b57a93 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 22 Nov 2015 22:38:13 -0500 Subject: [PATCH 01/11] Changes for Windows, Fix configure.ac to take in a winsock option to configure and generafigure, add ifdef's to stub out windows code for other platforms. --- README.md | 25 +- configure.ac | 57 +- src/Makefile.in | 36 +- src/compat/arc4random.c | 40 +- src/compat/getentropy_linux.c | 4 + src/context.c | 167 +++- src/convert.c | 4 +- src/dict.c | 3 + src/extension/libmini_event.c | 11 + src/extension/libmini_event.h | 4 + src/samplewin/Makefile.in | 150 ++++ src/samplewin/getdns_query.c | 1524 +++++++++++++++++++++++++++++++++ src/stub.c | 14 + src/util/winsock_event.c | 872 +++++++++++++++++++ src/util/winsock_event.h | 294 +++++++ 15 files changed, 3147 insertions(+), 58 deletions(-) create mode 100644 src/samplewin/Makefile.in create mode 100644 src/samplewin/getdns_query.c create mode 100644 src/util/winsock_event.c create mode 100644 src/util/winsock_event.h diff --git a/README.md b/README.md index dbd72731..ec28e45c 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ The goals of this implementation of the getdns API are: * Provide an open source implementation, in C, of the formally described getdns API by getdns API team at * Initial support for FreeBSD, OSX, Linux (CentOS/RHEL, Ubuntu) via functional "configure" script +* Initial support for Windows 8.1 * Initial support to include the Android platform * Include examples and tests as part of the build * Document code using doxygen @@ -84,6 +85,7 @@ Building/External Dependencies ============================== External dependencies are linked outside the getdns API build tree (we rely on configure to find them). We would like to keep the dependency tree short. +Please refer to section for building on Windows for separate dependency and build instructions. * [libunbound from NLnet Labs](https://unbound.net/) version 1.4.16 or later. * [libidn from the FSF](https://www.gnu.org/software/libidn/) version 1. @@ -112,6 +114,8 @@ The implementation works with a variety of event loops, each built as a separate * [libuv](https://github.com/joyent/libuv) * [libev](http://software.schmorp.de/pkg/libev.html) +NOTE: The current Windows implementation does not support the above. + ## Regression Tests A suite of regression tests are included with the library, if you make changes or just @@ -119,6 +123,8 @@ want to sanity check things on your system take a look at src/test. You will ne to install [libcheck](http://check.sourceforge.net/) and [libldns from NLnet Labs](https://nlnetlabs.nl/projects/ldns/) version 1.6.17 or later. Both libraries are also available from many of the package repositories for the more popular operating systems. +NOTE: The current Windows implementation does not support the above. + ## DNSSEC For the library to be DNSSEC capable, it needs to know the root trust anchor. @@ -167,8 +173,9 @@ The primary platforms targeted are Linux and FreeBSD, other platform are support * RHEL/CentOS 6.4 * OSX 10.8 * Ubuntu 14.04 +* Microsoft Windows 8.1 (initial support for DNSSEC but no TLS provided for version 0.5.1) -We intend to add MS-Windows, Android and other platforms to the releases as we have time to port it. +We intend to add Android and other platforms to the releases as we have time to port it. ##Platform Specific Build Reports @@ -233,6 +240,22 @@ Note that in order to compile the examples, the `--with-libevent` switch is requ As of the 0.2.0 release, when installing via Homebrew, the trust anchor is expected to be located at `$(brew --prefix)/etc/getdns-root.key`. Additionally, the OpenSSL library installed by Homebrew is linked against. Note that the Homebrew OpenSSL installation clones the Keychain certificates to the default OpenSSL location so TLS certificate authentication should work out of the box. + +### Microsoft Windows 8.1 + +The windows version of getdns currently only is supported in stub only mode. + +To configure: + ./configure --enable-use-winsock --enable-stub-only --with-trust-anchor="c:\\\MinGW\\\msys\\\1.0\\\etc\\\unbound\\\getdns-root.key" + + The trust anchor is also installed by unbound on c:\program Files (X86)\unbound\root.key and can be referenced from there + or anywhere else that the user chooses to configure it. + + After configuring, do a 'make' and 'make install' to build getdns for Windows. + + There is a sample, getdns_query.exe which can be built in src/samplewin using 'make' + + Contributors ============ * Theogene Bucuti diff --git a/configure.ac b/configure.ac index 7422f67c..a59974f8 100644 --- a/configure.ac +++ b/configure.ac @@ -429,9 +429,30 @@ case "$enable_stub_only" in ;; esac + + # search to set include and library paths right # find libidn my_with_libidn=1 + +AC_MSG_NOTICE([Checking if building on Windows]) +AC_ARG_ENABLE(use-winsock, AC_HELP_STRING([--enable-use-winsock], [Enable building on Microsoft Windows using mingw])) +case "$enable_use_winsock" in + yes) + AC_MSG_NOTICE([ Building on Windows ... YES! ]) + AC_DEFINE_UNQUOTED([USE_WINSOCK], [1], [Define this to enable Windows build.]) + AC_DEFINE_UNQUOTED([GETDNS_ON_WINDOWS], [1], [Define this to enable Windows build.]) + AC_DEFINE_UNQUOTED([HAVE_WINSOCK2_H], [1], [Define this to enable Windows build.]) + AC_DEFINE_UNQUOTED([HAVE_WS2TCPIP_H], [1], [Define this to enable Windows build.]) + AC_DEFINE_UNQUOTED([STUB_NATIVE_DNSSEC], [1], [Define this to enable Windows build.]) + my_with_libunbound=0 + my_with_libidn=0 + ;; + no|*) + AC_MSG_NOTICE([ Building on Windows ... YES! ]) + ;; +esac + AC_ARG_WITH(libidn, AS_HELP_STRING([--with-libidn=pathname], [path to libidn (default: search /usr/local ..)]), [], [withval="yes"]) @@ -985,6 +1006,35 @@ esac AC_SUBST(C99COMPATFLAGS) AH_BOTTOM([ + +/* the version of the windows API enabled */ +#undef WINVER +#undef _WIN32_WINNT +#define WINVER 0x0600 // 0x0502 +#define _WIN32_WINNT 0x0600 // 0x0502 +#ifdef HAVE_WINSOCK2_H +#include +#include +#endif + +#ifdef HAVE_WS2TCPIP_H +#include +#endif + +#ifndef USE_WINSOCK +#define ARG_LL "%ll" +#else +#define ARG_LL "%I64" +#endif + +/* detect if we need to cast to unsigned int for FD_SET to avoid warnings */ +#ifdef HAVE_WINSOCK2_H +#define FD_SET_T (u_int) +#else +#define FD_SET_T +#endif + + #include #include #include @@ -1094,13 +1144,6 @@ unsigned char *SHA512(void* data, unsigned int data_len, unsigned char *digest); # define ATTR_UNUSED(x) x #endif /* !HAVE_ATTR_UNUSED */ -/* detect if we need to cast to unsigned int for FD_SET to avoid warnings */ -#ifdef HAVE_WINSOCK2_H -#define FD_SET_T (u_int) -#else -#define FD_SET_T -#endif - #ifdef TIME_WITH_SYS_TIME # include # include diff --git a/src/Makefile.in b/src/Makefile.in index d6d90054..1a9d29d6 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -74,7 +74,7 @@ LIBOBJDIR= LIBOBJS=@LIBOBJS@ COMPAT_OBJ=$(LIBOBJS:.o=.lo) -UTIL_OBJ=mini_event.lo rbtree.lo val_secalgo.lo +UTIL_OBJ=mini_event.lo winsock_event.lo rbtree.lo val_secalgo.lo EXTENSION_OBJ=libmini_event.lo libevent.lo libev.lo @@ -229,63 +229,63 @@ const-info.lo const-info.o: $(srcdir)/const-info.c getdns/getdns.h getdns/getdns context.lo context.o: $(srcdir)/context.c config.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 \ + config.h $(srcdir)/util/mini_event.h $(srcdir)/util/winsock_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h \ $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ $(srcdir)/dnssec.h $(srcdir)/stub.h $(srcdir)/list.h 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)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h $(srcdir)/util/winsock_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 dict.lo dict.o: $(srcdir)/dict.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)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h $(srcdir)/util/winsock_event.h $(srcdir)/util/rbtree.h \ $(srcdir)/types-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/const-info.h $(srcdir)/gldns/wire2str.h dnssec.lo dnssec.o: $(srcdir)/dnssec.c 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)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h $(srcdir)/util/winsock_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)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h $(srcdir)/util/winsock_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 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)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h $(srcdir)/util/winsock_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 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)/util/mini_event.h $(srcdir)/util/winsock_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 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)/util/winsock_event.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/rr-iter.h \ $(srcdir)/gldns/pkthdr.h $(srcdir)/dict.h rr-iter.lo rr-iter.o: $(srcdir)/rr-iter.c $(srcdir)/rr-iter.h getdns/getdns.h $(srcdir)/rr-dict.h config.h \ $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/rrdef.h stub.lo stub.o: $(srcdir)/stub.c config.h $(srcdir)/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)/rr-iter.h \ - $(srcdir)/rr-dict.h $(srcdir)/context.h $(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h \ + $(srcdir)/rr-dict.h $(srcdir)/context.h $(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h $(srcdir)/util/winsock_event.h \ $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/util-internal.h $(srcdir)/general.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 \ + config.h $(srcdir)/util/mini_event.h $(srcdir)/util/winsock_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/general.h \ $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ $(srcdir)/dnssec.h $(srcdir)/stub.h $(srcdir)/gldns/wire2str.h util-internal.lo util-internal.o: $(srcdir)/util-internal.c 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 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)/util/winsock_event.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h version.lo version.o: version.c gbuffer.lo gbuffer.o: $(srcdir)/gldns/gbuffer.c config.h $(srcdir)/gldns/gbuffer.h @@ -309,17 +309,19 @@ getentropy_solaris.lo getentropy_solaris.o: $(srcdir)/compat/getentropy_solaris. getentropy_win.lo getentropy_win.o: $(srcdir)/compat/getentropy_win.c 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 \ +winsock_event.lo winsock_event.o: $(srcdir)/util/winsock_event.c config.h $(srcdir)/util/winsock_event.h $(srcdir)/util/rbtree.h \ + $(srcdir)/util/fptr_wlist.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)/util-internal.h config.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 \ - $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ + $(srcdir)/util/winsock_event.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)/util/fptr_wlist.h val_secalgo.lo val_secalgo.o: $(srcdir)/util/val_secalgo.c config.h $(srcdir)/util/val_secalgo.h $(srcdir)/util/log.h \ $(srcdir)/util-internal.h config.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 \ - $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ + $(srcdir)/util/winsock_event.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/keyraw.h \ $(srcdir)/gldns/gbuffer.h libev.lo libev.o: $(srcdir)/extension/libev.c $(srcdir)/getdns/getdns_ext_libev.h getdns/getdns.h \ @@ -329,7 +331,7 @@ libevent.lo libevent.o: $(srcdir)/extension/libevent.c $(srcdir)/getdns/getdns_e getdns/getdns.h getdns/getdns_extra.h $(srcdir)/types-internal.h getdns/getdns.h \ getdns/getdns_extra.h $(srcdir)/util/rbtree.h config.h libmini_event.lo libmini_event.o: $(srcdir)/extension/libmini_event.c $(srcdir)/extension/libmini_event.h \ - config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h \ + config.h $(srcdir)/util/winsock_event.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h \ getdns/getdns.h getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h \ $(srcdir)/context.h config.h $(srcdir)/types-internal.h $(srcdir)/extension/libmini_event.h \ $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ @@ -337,5 +339,5 @@ libmini_event.lo libmini_event.o: $(srcdir)/extension/libmini_event.c $(srcdir)/ libuv.lo libuv.o: $(srcdir)/extension/libuv.c config.h $(srcdir)/getdns/getdns_ext_libuv.h \ getdns/getdns.h getdns/getdns_extra.h $(srcdir)/util-internal.h config.h $(srcdir)/context.h \ getdns/getdns.h getdns/getdns_extra.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \ - $(srcdir)/extension/libmini_event.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \ + $(srcdir)/extension/libmini_event.h $(srcdir)/util/winsock_event.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 diff --git a/src/compat/arc4random.c b/src/compat/arc4random.c index 27a626b7..890699cd 100644 --- a/src/compat/arc4random.c +++ b/src/compat/arc4random.c @@ -33,8 +33,42 @@ #include #include #include -#ifndef UB_ON_WINDOWS +#ifndef GETDNS_ON_WINDOWS #include +#else +#include +#include + +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 @@ -73,7 +107,7 @@ _rs_init(u_char *buf, size_t n) return; if (rs == NULL) { -#ifndef UB_ON_WINDOWS +#ifndef GETDNS_ON_WINDOWS if ((rs = mmap(NULL, sizeof(*rs), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) abort(); @@ -88,7 +122,7 @@ _rs_init(u_char *buf, size_t n) #endif } if (rsx == NULL) { -#ifndef UB_ON_WINDOWS +#ifndef GETDNS_ON_WINDOWS if ((rsx = mmap(NULL, sizeof(*rsx), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) abort(); diff --git a/src/compat/getentropy_linux.c b/src/compat/getentropy_linux.c index 76f0f9df..6c642a96 100644 --- a/src/compat/getentropy_linux.c +++ b/src/compat/getentropy_linux.c @@ -16,7 +16,10 @@ * 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 @@ -538,3 +541,4 @@ getentropy_fallback(void *buf, size_t len) errno = EIO; return -1; } +#endif \ No newline at end of file diff --git a/src/context.c b/src/context.c index a623cec5..5076a14a 100644 --- a/src/context.c +++ b/src/context.c @@ -34,17 +34,27 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "config.h" + +#ifndef USE_WINSOCK #include +#include +#include +#else +#include +#include +typedef unsigned short in_port_t; +#endif + +#include #include #include #include -#include -#include + #include -#include #include -#include "config.h" + #include "gldns/str2wire.h" #include "gldns/wire2str.h" #include "context.h" @@ -356,7 +366,11 @@ create_local_hosts(getdns_context *context) int start_of_line = 1; getdns_dict *address = NULL; +#ifdef USE_WINSOCK + in = fopen("c:\\WINDOWS\\system32\\drivers\\etc\\hosts", "r"); +#else in = fopen("/etc/hosts", "r"); +#endif while (fgets(pos, (int)(sizeof(buf) - (pos - buf)), in)) { pos = buf; /* Break out of for to read more */ @@ -751,6 +765,95 @@ set_os_defaults(struct getdns_context *context) return GETDNS_RETURN_GOOD; } /* set_os_defaults */ +#ifdef USE_WINSOCK +static getdns_return_t +set_os_defaults_windows(struct getdns_context *context) +{ + FILE *in; + char line[1024], domain[1024]; + char *parse, *token, prev_ch; + size_t upstreams_limit = 10, length; + struct getdns_bindata bindata; + struct addrinfo hints; + struct addrinfo *result; + getdns_upstream *upstream; + int s; + + if (context->fchg_resolvconf == NULL) { + context->fchg_resolvconf = + GETDNS_MALLOC(context->my_mf, struct filechg); + if (context->fchg_resolvconf == NULL) + return GETDNS_RETURN_MEMORY_ERROR; + context->fchg_resolvconf->fn = "InvalidOnWindows"; + context->fchg_resolvconf->prevstat = NULL; + context->fchg_resolvconf->changes = GETDNS_FCHG_NOCHANGES; + context->fchg_resolvconf->errors = GETDNS_FCHG_NOERROR; + } + _getdns_filechg_check(context, context->fchg_resolvconf); + + context->suffix = getdns_list_create_with_context(context); + context->upstreams = upstreams_create(context, upstreams_limit); + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_socktype = 0; /* Datagram socket */ + hints.ai_flags = AI_NUMERICHOST; /* No reverse name lookups */ + hints.ai_protocol = 0; /* Any protocol */ + hints.ai_canonname = NULL; + hints.ai_addr = NULL; + hints.ai_next = NULL; + + //g + FIXED_INFO *info; + ULONG buflen = sizeof(*info); + IP_ADDR_STRING *ptr; + + info = (FIXED_INFO *)malloc(sizeof(FIXED_INFO)); + if (info == NULL) + return GETDNS_RETURN_GENERIC_ERROR; + + if (GetNetworkParams(info, &buflen) == ERROR_BUFFER_OVERFLOW) { + free(info); + info = (FIXED_INFO *)malloc(buflen); + if (info == NULL) + return GETDNS_RETURN_GENERIC_ERROR; + } + + if (GetNetworkParams(info, &buflen) == NO_ERROR) { + int retval = 0; + ptr = &(info->DnsServerList); + *domain = 0; + while (ptr) { + for (size_t i = 0; i < GETDNS_UPSTREAM_TRANSPORTS; i++) { + char *port_str = getdns_port_str_array[i]; + if ((s = getaddrinfo(ptr->IpAddress.String, port_str, &hints, &result))) + continue; + if (!result) + continue; + + upstream = &context->upstreams-> + upstreams[context->upstreams->count++]; + upstream_init(upstream, context->upstreams, result); + upstream->transport = getdns_upstream_transports[i]; + freeaddrinfo(result); + } + ptr = ptr->Next; + + } + free(info); + } + + + (void)getdns_list_get_length(context->suffix, &length); + if (length == 0 && *domain != 0) { + bindata.data = (uint8_t *)domain; + bindata.size = strlen(domain) + 1; + (void)getdns_list_set_bindata(context->suffix, 0, &bindata); + } + return GETDNS_RETURN_GOOD; +} /* set_os_defaults_windows */ +#endif + /* compare of transaction ids in DESCENDING order so that 0 comes last */ @@ -891,8 +994,14 @@ getdns_context_create_with_extended_memory_functions( result->fchg_resolvconf = NULL; result->fchg_hosts = NULL; + //g resolv.conf does not exist on Windows, handle differently +#ifndef USE_WINSOCK if (set_from_os && (r = set_os_defaults(result))) goto error; +#else + if (set_from_os && (r = set_os_defaults_windows(result))) + goto error; +#endif result->dnssec_allowed_skew = 0; result->edns_maximum_udp_payload_size = -1; @@ -1686,7 +1795,7 @@ getdns_context_set_dnssec_allowed_skew(struct getdns_context *context, */ getdns_return_t getdns_context_set_upstream_recursive_servers(struct getdns_context *context, - struct getdns_list *upstream_list) +struct getdns_list *upstream_list) { getdns_return_t r; size_t count = 0; @@ -1703,16 +1812,16 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context, return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; } memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ - hints.ai_socktype = 0; /* Datagram socket */ - hints.ai_flags = AI_NUMERICHOST; /* No reverse name lookups */ - hints.ai_protocol = 0; /* Any protocol */ + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_socktype = 0; /* Datagram socket */ + hints.ai_flags = AI_NUMERICHOST; /* No reverse name lookups */ + hints.ai_protocol = 0; /* Any protocol */ hints.ai_canonname = NULL; - hints.ai_addr = NULL; - hints.ai_next = NULL; + hints.ai_addr = NULL; + hints.ai_next = NULL; upstreams = upstreams_create( - context, count * GETDNS_UPSTREAM_TRANSPORTS); + context, count * GETDNS_UPSTREAM_TRANSPORTS); for (i = 0; i < count; i++) { getdns_dict *dict; getdns_bindata *address_type; @@ -1727,7 +1836,7 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context, goto error; if ((r = getdns_dict_get_bindata( - dict, "address_type",&address_type))) + dict, "address_type", &address_type))) goto error; if (address_type->size < 4) goto invalid_parameter; @@ -1738,24 +1847,24 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context, else goto invalid_parameter; if ((r = getdns_dict_get_bindata( - dict, "address_data", &address_data))) + dict, "address_data", &address_data))) goto error; if ((addr.ss_family == AF_INET && - address_data->size != 4) || - (addr.ss_family == AF_INET6 && - address_data->size != 16)) + address_data->size != 4) || + (addr.ss_family == AF_INET6 && + address_data->size != 16)) goto invalid_parameter; if (inet_ntop(addr.ss_family, address_data->data, - addrstr, 1024) == NULL) + addrstr, 1024) == NULL) goto invalid_parameter; if (getdns_dict_get_bindata(dict, "scope_id", &scope_id) == - GETDNS_RETURN_GOOD) { + GETDNS_RETURN_GOOD) { if (strlen(addrstr) + scope_id->size > 1022) goto invalid_parameter; eos = &addrstr[strlen(addrstr)]; *eos++ = '%'; - (void) memcpy(eos, scope_id->data, scope_id->size); + (void)memcpy(eos, scope_id->data, scope_id->size); eos[scope_id->size] = 0; } @@ -1768,10 +1877,10 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context, continue; if (getdns_upstream_transports[j] != GETDNS_TRANSPORT_TLS) - (void) getdns_dict_get_int(dict, "port", &port); + (void)getdns_dict_get_int(dict, "port", &port); else - (void) getdns_dict_get_int(dict, "tls_port", &port); - (void) snprintf(portstr, 1024, "%d", (int)port); + (void)getdns_dict_get_int(dict, "tls_port", &port); + (void)snprintf(portstr, 1024, "%d", (int)port); if (getaddrinfo(addrstr, portstr, &hints, &ai)) goto invalid_parameter; @@ -1787,12 +1896,12 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context, upstream_init(upstream, upstreams, ai); upstream->transport = getdns_upstream_transports[j]; if (getdns_upstream_transports[j] == GETDNS_TRANSPORT_TLS || - getdns_upstream_transports[j] == GETDNS_TRANSPORT_STARTTLS) { + getdns_upstream_transports[j] == GETDNS_TRANSPORT_STARTTLS) { if ((r = getdns_dict_get_bindata( dict, "tls_auth_name", &tls_auth_name)) == GETDNS_RETURN_GOOD) { /*TODO: VALIDATE THIS STRING!*/ memcpy(upstream->tls_auth_name, - (char *)tls_auth_name->data, + (char *)tls_auth_name->data, tls_auth_name->size); upstream->tls_auth_name[tls_auth_name->size] = '\0'; } @@ -1813,8 +1922,7 @@ invalid_parameter: error: _getdns_upstreams_dereference(upstreams); return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; -} /* getdns_context_set_upstream_recursive_servers */ - +} static void set_ub_edns_maximum_udp_payload_size(struct getdns_context* context, @@ -2249,8 +2357,9 @@ _getdns_context_prepare_for_resolution(struct getdns_context *context, #ifdef HAVE_TLS_v1_2 /* Create client context, use TLS v1.2 only for now */ context->tls_ctx = SSL_CTX_new(TLSv1_2_client_method()); - if(context->tls_ctx == NULL) - return GETDNS_RETURN_BAD_CONTEXT; + if (context->tls_ctx == NULL) + printf("ERROR! Bad TLS context!"); + //g return GETDNS_RETURN_BAD_CONTEXT; /* Be strict and only use the cipher suites recommended in RFC7525 Unless we later fallback to opportunistic. */ const char* const PREFERRED_CIPHERS = "EECDH+aRSA+AESGCM:EECDH+aECDSA+AESGCM:EDH+aRSA+AESGCM"; diff --git a/src/convert.c b/src/convert.c index 082fe7db..0958a55c 100644 --- a/src/convert.c +++ b/src/convert.c @@ -34,9 +34,11 @@ #include #include -#include #include #include "config.h" +#ifndef USE_WINSOCK +#include +#endif #ifdef HAVE_LIBIDN #include #include diff --git a/src/dict.c b/src/dict.c index 822d5deb..b544ccb7 100644 --- a/src/dict.c +++ b/src/dict.c @@ -35,10 +35,13 @@ */ #include +#include "config.h" +#ifndef USE_WINSOCK #include #include #include #include +#endif #include "types-internal.h" #include "util-internal.h" diff --git a/src/extension/libmini_event.c b/src/extension/libmini_event.c index 266f73ef..d62fc89e 100644 --- a/src/extension/libmini_event.c +++ b/src/extension/libmini_event.c @@ -205,6 +205,17 @@ _getdns_mini_event_init(getdns_context *context, _getdns_mini_event *ext) 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); diff --git a/src/extension/libmini_event.h b/src/extension/libmini_event.h index 70b2cc53..c3f5b19a 100644 --- a/src/extension/libmini_event.h +++ b/src/extension/libmini_event.h @@ -35,7 +35,11 @@ #define _GETDNS_LIBMINI_EVENT_H_ #include "config.h" +#ifndef USE_WINSOCK #include "util/mini_event.h" +#else +#include "util/winsock_event.h" +#endif #include "types-internal.h" typedef struct _getdns_mini_event { diff --git a/src/samplewin/Makefile.in b/src/samplewin/Makefile.in new file mode 100644 index 00000000..90a2d327 --- /dev/null +++ b/src/samplewin/Makefile.in @@ -0,0 +1,150 @@ +# +# @configure_input@ +# +# Copyright (c) 2013, Verisign, Inc., NLNet Labs +# 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. + +package = @PACKAGE_NAME@ +version = @PACKAGE_VERSION@ +tarname = @PACKAGE_TARNAME@ +distdir = $(tarname)-$(version) + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +INSTALL = @INSTALL@ +LIBTOOL = ../../libtool + +srcdir = @srcdir@ + +have_libevent = @have_libevent@ +have_libuv = @have_libuv@ +have_libev = @have_libev@ +NOLIBCHECK = @NOLIBCHECK@ +NOLIBLDNS = @NOLIBLDNS@ + +EXTENSION_LIBEVENT_EXT_LIBS=@EXTENSION_LIBEVENT_EXT_LIBS@ +EXTENSION_LIBEVENT_LDFLAGS=@EXTENSION_LIBEVENT_LDFLAGS@ +EXTENSION_LIBUV_EXT_LIBS=@EXTENSION_LIBUV_EXT_LIBS@ +EXTENSION_LIBUV_LDFLAGS=@EXTENSION_LIBUV_LDFLAGS@ +EXTENSION_LIBEV_EXT_LIBS=@EXTENSION_LIBEV_EXT_LIBS@ +EXTENSION_LIBEV_LDFLAGS=@EXTENSION_LIBEV_LDFLAGS@ + +CHECK_GETDNS=@CHECK_GETDNS@ +CHECK_UV_PROG=@CHECK_UV_PROG@ +CHECK_EVENT_PROG=@CHECK_EVENT_PROG@ +CHECK_EV_PROG=@CHECK_EV_PROG@ + +CC=@CC@ +CFLAGS=-I$(srcdir)/.. -I$(srcdir) -I.. $(cflags) @CFLAGS@ -I/usr/local/ssl/include +LDFLAGS=-L.. @LDFLAGS@ -L/usr/local/ssl/lib -L/usr/local/lib/ +LDLIBS=../libgetdns.la @LIBS@ -lldns -lssl -lcrypto -lgdi32 -lws2_32 -liphlpapi +CHECK_LIBS=@CHECK_LIBS@ +CHECK_CFLAGS=@CHECK_CFLAGS@ +LDNS_LIBS=@LDNS_LIBS@ +LDNS_CFLAGS=@LDNS_CFLAGS@ +LDNS_LDFLAGS=@LDNS_LDFLAGS@ + +CHECK_OBJS=check_getdns_common.lo check_getdns_context_set_timeout.lo \ + check_getdns.lo check_getdns_transport.lo + +ALL_OBJS=$(CHECK_OBJS) getdns_query.lo + +PROGRAMS=getdns_query + +.SUFFIXES: .c .o .a .lo .h + +.c.o: + $(CC) $(CFLAGS) -c $< -o $@ + +.c.lo: + $(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) -c $< -o $@ + +default: all + +all: $(PROGRAMS) + +$(ALL_OBJS): + $(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) $(LDNS_CFLAGS) -c $(srcdir)/$(@:.lo=.c) -o $@ + +getdns_query: getdns_query.lo + $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ getdns_query.lo $(LDFLAGS) $(LDLIBS) + + + +clean: + rm -f *.o *.lo $(PROGRAMS) scratchpad + rm -rf .libs + rm -f check_getdns.log + + +$(distdir): FORCE + mkdir -p $(distdir)/src + cp configure.ac $(distdir) + cp configure $(distdir) + cp Makefile.in $(distdir) + cp src/Makefile.in $(distdir)/src + +distcheck: $(distdir).tar.gz + gzip -cd $(distdir).tar.gz | tar xvf - + cd $(distdir) && ./configure + cd $(distdir) && $(MAKE) all + cd $(distdir) && $(MAKE) check + cd $(distdir) && $(MAKE) DESTDIR=$${PWD}/_inst install + cd $(distdir) && $(MAKE) DESTDIR=$${PWD}/_inst uninstall + @remaining="`find $${PWD}/$(distdir)/_inst -type f | wc -l`"; \ + if test "$${remaining}" -ne 0; then + echo "@@@ $${remaining} file(s) remaining in stage directory!"; \ + exit 1; \ + fi + cd $(distdir) && $(MAKE) clean + rm -rf $(distdir) + @echo "*** Package $(distdir).tar.gz is ready for distribution" + +Makefile: $(srcdir)/Makefile.in ../../config.status + cd ../.. && ./config.status src/test/Makefile + +configure.status: configure + cd ../.. && ./config.status --recheck + +depend: + (cd $(srcdir) ; awk 'BEGIN{P=1}{if(P)print}/^# Dependencies/{P=0}' Makefile.in > Makefile.in.new ) + (cd $(srcdir) ; gcc -MM -I. -I.. *.c | \ + sed -e 's? \([a-z_-]*\)\.\([ch]\)? $$(srcdir)/\1.\2?g' \ + -e 's? \$$(srcdir)/config\.h? ../config.h?g' \ + -e 's? $$(srcdir)/\.\./getdns/getdns_extra\.h? ../getdns/getdns_extra.h?g' \ + -e 's? \.\./getdns/getdns_ext_libevent\.h? $$(srcdir)/../getdns/getdns_ext_libevent.h?g' \ + -e 's? \.\./getdns/getdns_ext_libev\.h? $$(srcdir)/../getdns/getdns_ext_libev.h?g' \ + -e 's? \.\./getdns/getdns_ext_libuv\.h? $$(srcdir)/../getdns/getdns_ext_libuv.h?g' \ + -e 's!\(.*\)\.o[ :]*!\1.lo \1.o: !g' >> Makefile.in.new ) + (cd $(srcdir) ; diff Makefile.in.new Makefile.in && rm Makefile.in.new \ + || mv Makefile.in.new Makefile.in ) + + + +.PHONY: clean + +getdns_query.lo getdns_query.o: $(srcdir)/getdns_query.c ../config.h ../getdns/getdns.h \ + ../getdns/getdns_extra.h \ No newline at end of file diff --git a/src/samplewin/getdns_query.c b/src/samplewin/getdns_query.c new file mode 100644 index 00000000..b2319ad8 --- /dev/null +++ b/src/samplewin/getdns_query.c @@ -0,0 +1,1524 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include "util-internal.h" + +#define MAX_TIMEOUTS FD_SETSIZE + +/* Eventloop based on select */ +typedef struct my_eventloop { + getdns_eventloop base; + 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]; +} my_eventloop; + +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; +} + +getdns_return_t +my_eventloop_schedule(getdns_eventloop *loop, + int fd, uint64_t timeout, getdns_eventloop_event *event) +{ + my_eventloop *my_loop = (my_eventloop *)loop; + size_t i; + + 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); + + my_loop->fd_events[fd] = event; + my_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; + } + + assert(event->timeout_cb && !event->read_cb && !event->write_cb); + + for (i = 0; i < MAX_TIMEOUTS; i++) { + if (my_loop->timeout_events[i] == NULL) { + my_loop->timeout_events[i] = event; + my_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; + } + } + return GETDNS_RETURN_GENERIC_ERROR; +} + +getdns_return_t +my_eventloop_clear(getdns_eventloop *loop, getdns_eventloop_event *event) +{ + my_eventloop *my_loop = (my_eventloop *)loop; + size_t i; + + assert(loop); + assert(event); + + DEBUG_SCHED( "%s(loop: %p, event: %p)\n", __FUNCTION__, loop, event); + + i = (intptr_t)event->ev - 1; + assert(i >= 0 && i < FD_SETSIZE); + + if (event->timeout_cb && !event->read_cb && !event->write_cb) { + assert(my_loop->timeout_events[i] == event); + my_loop->timeout_events[i] = NULL; + } else { + assert(my_loop->fd_events[i] == event); + my_loop->fd_events[i] = NULL; + } + event->ev = NULL; + return GETDNS_RETURN_GOOD; +} + +void my_eventloop_cleanup(getdns_eventloop *loop) +{ +} + +void my_read_cb(int fd, getdns_eventloop_event *event) +{ + DEBUG_SCHED( "%s(fd: %d, event: %p)\n", __FUNCTION__, fd, event); + event->read_cb(event->userarg); +} + +void my_write_cb(int fd, getdns_eventloop_event *event) +{ + DEBUG_SCHED( "%s(fd: %d, event: %p)\n", __FUNCTION__, fd, event); + event->write_cb(event->userarg); +} + +void my_timeout_cb(int fd, getdns_eventloop_event *event) +{ + DEBUG_SCHED( "%s(fd: %d, event: %p)\n", __FUNCTION__, fd, event); + event->timeout_cb(event->userarg); +} + +void my_eventloop_run_once(getdns_eventloop *loop, int blocking) +{ + my_eventloop *my_loop = (my_eventloop *)loop; + + fd_set readfds, writefds; + int fd, max_fd = -1; + uint64_t now, timeout = (uint64_t)-1; + size_t i; + struct timeval tv; + + assert(loop); + + FD_ZERO(&readfds); + FD_ZERO(&writefds); + now = get_now_plus(0); + + for (i = 0; i < MAX_TIMEOUTS; i++) { + if (!my_loop->timeout_events[i]) + continue; + if (now > my_loop->timeout_times[i]) + my_timeout_cb(-1, my_loop->timeout_events[i]); + else if (my_loop->timeout_times[i] < timeout) + timeout = my_loop->timeout_times[i]; + } + for (fd = 0; fd < FD_SETSIZE; fd++) { + if (!my_loop->fd_events[fd]) + continue; + if (my_loop->fd_events[fd]->read_cb) + FD_SET(fd, &readfds); + if (my_loop->fd_events[fd]->write_cb) + FD_SET(fd, &writefds); + if (fd > max_fd) + max_fd = fd; + if (my_loop->fd_timeout_times[fd] < timeout) + timeout = my_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, &tv) < 0) { + perror("select() failed"); + exit(EXIT_FAILURE); + } + now = get_now_plus(0); + for (fd = 0; fd < FD_SETSIZE; fd++) { + if (my_loop->fd_events[fd] && + my_loop->fd_events[fd]->read_cb && + FD_ISSET(fd, &readfds)) + my_read_cb(fd, my_loop->fd_events[fd]); + + if (my_loop->fd_events[fd] && + my_loop->fd_events[fd]->write_cb && + FD_ISSET(fd, &writefds)) + my_write_cb(fd, my_loop->fd_events[fd]); + + if (my_loop->fd_events[fd] && + my_loop->fd_events[fd]->timeout_cb && + now > my_loop->fd_timeout_times[fd]) + my_timeout_cb(fd, my_loop->fd_events[fd]); + + i = fd; + if (my_loop->timeout_events[i] && + my_loop->timeout_events[i]->timeout_cb && + now > my_loop->timeout_times[i]) + my_timeout_cb(-1, my_loop->timeout_events[i]); + } +} + +void my_eventloop_run(getdns_eventloop *loop) +{ + my_eventloop *my_loop = (my_eventloop *)loop; + size_t i; + + assert(loop); + + i = 0; + while (i < MAX_TIMEOUTS) { + if (my_loop->fd_events[i] || my_loop->timeout_events[i]) { + my_eventloop_run_once(loop, 1); + i = 0; + } else { + i++; + } + } +} + +void my_eventloop_init(my_eventloop *loop) +{ + static getdns_eventloop_vmt my_eventloop_vmt = { + my_eventloop_cleanup, + my_eventloop_schedule, + my_eventloop_clear, + my_eventloop_run, + my_eventloop_run_once + }; + + (void) memset(loop, 0, sizeof(my_eventloop)); + loop->base.vmt = &my_eventloop_vmt; +} + +static int quiet = 0; +static int batch_mode = 0; +static char *query_file = NULL; +static int json = 0; +static char *the_root = "."; +static char *name; +static getdns_context *context; +static getdns_dict *extensions; +static uint16_t request_type = GETDNS_RRTYPE_NS; +static int timeout, edns0_size, padding_blocksize; +static int async = 0, interactive = 0; +static enum { GENERAL, ADDRESS, HOSTNAME, SERVICE } calltype = GENERAL; + +int get_rrtype(const char *t); + +getdns_dict * +ipaddr_dict(getdns_context *context, char *ipstr) +{ + getdns_dict *r = getdns_dict_create_with_context(context); + char *s = strchr(ipstr, '%'), *scope_id_str = ""; + char *p = strchr(ipstr, '@'), *portstr = ""; + char *t = strchr(ipstr, '#'), *tls_portstr = ""; + char *n = strchr(ipstr, '~'), *tls_namestr = ""; + uint8_t buf[sizeof(struct in6_addr)]; + getdns_bindata addr; + + addr.data = buf; + + if (!r) return NULL; + if (s) { + *s = 0; + scope_id_str = s + 1; + } + if (p) { + *p = 0; + portstr = p + 1; + } + if (t) { + *t = 0; + tls_portstr = t + 1; + } + if (n) { + *n = 0; + tls_namestr = n + 1; + } + if (strchr(ipstr, ':')) { + getdns_dict_util_set_string(r, "address_type", "IPv6"); + addr.size = 16; + if (inet_pton(AF_INET6, ipstr, buf) <= 0) { + getdns_dict_destroy(r); + return NULL; + } + } else { + getdns_dict_util_set_string(r, "address_type", "IPv4"); + addr.size = 4; + if (inet_pton(AF_INET, ipstr, buf) <= 0) { + getdns_dict_destroy(r); + return NULL; + } + } + getdns_dict_set_bindata(r, "address_data", &addr); + if (*portstr) + getdns_dict_set_int(r, "port", (int32_t)atoi(portstr)); + if (*tls_portstr) + getdns_dict_set_int(r, "tls_port", (int32_t)atoi(tls_portstr)); + if (*tls_namestr) { + getdns_dict_util_set_string(r, "tls_auth_name", tls_namestr); + } + if (*scope_id_str) + getdns_dict_util_set_string(r, "scope_id", scope_id_str); + + return r; +} + +static getdns_return_t +fill_transport_list(getdns_context *context, char *transport_list_str, + getdns_transport_list_t *transports, size_t *transport_count) +{ + size_t max_transports = *transport_count; + *transport_count = 0; + for ( size_t i = 0 + ; i < max_transports && i < strlen(transport_list_str) + ; i++, (*transport_count)++) { + switch(*(transport_list_str + i)) { + case 'U': + transports[i] = GETDNS_TRANSPORT_UDP; + break; + case 'T': + transports[i] = GETDNS_TRANSPORT_TCP; + break; + case 'L': + transports[i] = GETDNS_TRANSPORT_TLS; + break; + case 'S': + transports[i] = GETDNS_TRANSPORT_STARTTLS; + break; + default: + fprintf(stderr, "Unrecognised transport '%c' in string %s\n", + *(transport_list_str + i), transport_list_str); + return GETDNS_RETURN_GENERIC_ERROR; + } + } + return GETDNS_RETURN_GOOD; +} + +void +print_usage(FILE *out, const char *progname) +{ + fprintf(out, "usage: %s [@] [+extension] [] []\n", + progname); + fprintf(out, "options:\n"); + fprintf(out, "\t-a\tPerform asynchronous resolution " + "(default = synchronous)\n"); + fprintf(out, "\t-A\taddress lookup ( is ignored)\n"); + fprintf(out, "\t-B\tBatch mode. Schedule all messages before processing responses.\n"); + fprintf(out, "\t-b \tSet edns0 max_udp_payload size\n"); + fprintf(out, "\t-c\tSend Client Subnet privacy request\n"); + fprintf(out, "\t-D\tSet edns0 do bit\n"); + fprintf(out, "\t-d\tclear edns0 do bit\n"); + fprintf(out, "\t-e \tSet idle timeout in miliseconds\n"); + fprintf(out, "\t-F \tread the queries from the specified file\n"); + fprintf(out, "\t-G\tgeneral lookup\n"); + fprintf(out, "\t-H\thostname lookup. ( must be an IP address; is ignored)\n"); + fprintf(out, "\t-h\tPrint this help\n"); + fprintf(out, "\t-i\tPrint api information\n"); + fprintf(out, "\t-I\tInteractive mode (> 1 queries on same context)\n"); + fprintf(out, "\t-j\tOutput json response dict\n"); + fprintf(out, "\t-J\tPretty print json response dict\n"); + fprintf(out, "\t-k\tPrint root trust anchors\n"); + fprintf(out, "\t-n\tSet TLS authentication mode to NONE (default)\n"); + fprintf(out, "\t-m\tSet TLS authentication mode to HOSTNAME\n"); + fprintf(out, "\t-p\tPretty print response dict\n"); + fprintf(out, "\t-P \tPad TLS queries to a multiple of blocksize\n"); + fprintf(out, "\t-r\tSet recursing resolution type\n"); + fprintf(out, "\t-q\tQuiet mode - don't print response\n"); + fprintf(out, "\t-s\tSet stub resolution type (default = recursing)\n"); + fprintf(out, "\t-S\tservice lookup ( is ignored)\n"); + fprintf(out, "\t-t \tSet timeout in miliseconds\n"); + fprintf(out, "\t-T\tSet transport to TCP only\n"); + fprintf(out, "\t-O\tSet transport to TCP only keep connections open\n"); + fprintf(out, "\t-L\tSet transport to TLS only keep connections open\n"); + fprintf(out, "\t-E\tSet transport to TLS with TCP fallback only keep connections open\n"); + fprintf(out, "\t-R\tSet transport to STARTTLS with TCP fallback only keep connections open\n"); + fprintf(out, "\t-u\tSet transport to UDP with TCP fallback\n"); + fprintf(out, "\t-U\tSet transport to UDP only\n"); + fprintf(out, "\t-l \tSet transport list. List can contain 1 of each of the characters\n"); + fprintf(out, "\t\t\t U T L S for UDP, TCP, TLS or STARTTLS e.g 'UT' or 'LST' \n"); + +} + +static getdns_return_t validate_chain(getdns_dict *response) +{ + getdns_return_t r; + getdns_list *validation_chain; + getdns_list *replies_tree; + getdns_dict *reply; + getdns_list *to_validate; + getdns_list *trust_anchor; + size_t i; + int s; + + if (!(to_validate = getdns_list_create())) + return GETDNS_RETURN_MEMORY_ERROR; + + trust_anchor = getdns_root_trust_anchor(NULL); + + if ((r = getdns_dict_get_list( + response, "validation_chain", &validation_chain))) + goto error; + + if ((r = getdns_dict_get_list( + response, "replies_tree", &replies_tree))) + goto error; + + fprintf(stdout, "replies_tree dnssec_status: "); + switch ((s = getdns_validate_dnssec( + replies_tree, validation_chain, trust_anchor))) { + + case GETDNS_DNSSEC_SECURE: + fprintf(stdout, "GETDNS_DNSSEC_SECURE\n"); + break; + case GETDNS_DNSSEC_BOGUS: + fprintf(stdout, "GETDNS_DNSSEC_BOGUS\n"); + break; + case GETDNS_DNSSEC_INDETERMINATE: + fprintf(stdout, "GETDNS_DNSSEC_INDETERMINATE\n"); + break; + case GETDNS_DNSSEC_INSECURE: + fprintf(stdout, "GETDNS_DNSSEC_INSECURE\n"); + break; + case GETDNS_DNSSEC_NOT_PERFORMED: + fprintf(stdout, "GETDNS_DNSSEC_NOT_PERFORMED\n"); + break; + default: + fprintf(stdout, "%d\n", (int)s); + } + + i = 0; + while (!(r = getdns_list_get_dict(replies_tree, i++, &reply))) { + + if ((r = getdns_list_set_dict(to_validate, 0, reply))) + goto error; + + fprintf( stdout + , "reply %zu, dnssec_status: ", i); + switch ((s = getdns_validate_dnssec( + to_validate, validation_chain, trust_anchor))) { + + case GETDNS_DNSSEC_SECURE: + fprintf(stdout, "GETDNS_DNSSEC_SECURE\n"); + break; + case GETDNS_DNSSEC_BOGUS: + fprintf(stdout, "GETDNS_DNSSEC_BOGUS\n"); + break; + case GETDNS_DNSSEC_INDETERMINATE: + fprintf(stdout, "GETDNS_DNSSEC_INDETERMINATE\n"); + break; + case GETDNS_DNSSEC_INSECURE: + fprintf(stdout, "GETDNS_DNSSEC_INSECURE\n"); + break; + case GETDNS_DNSSEC_NOT_PERFORMED: + fprintf(stdout, "GETDNS_DNSSEC_NOT_PERFORMED\n"); + break; + default: + fprintf(stdout, "%d\n", (int)s); + } + } + if (r == GETDNS_RETURN_NO_SUCH_LIST_ITEM) + r = GETDNS_RETURN_GOOD; +error: + getdns_list_destroy(trust_anchor); + getdns_list_destroy(to_validate); + + return GETDNS_RETURN_GOOD; +} + +void callback(getdns_context *context, getdns_callback_type_t callback_type, + getdns_dict *response, void *userarg, getdns_transaction_t trans_id) +{ + char *response_str; + + /* This is a callback with data */; + if (response && !quiet && (response_str = json ? + getdns_print_json_dict(response, json == 1) + : getdns_pretty_print_dict(response))) { + + fprintf(stdout, "ASYNC response:\n%s\n", response_str); + validate_chain(response); + free(response_str); + } + + if (callback_type == GETDNS_CALLBACK_COMPLETE) { + fprintf(stdout, + "Response code was: GOOD. Status was: Callback with ID %llu was successfull.\n", + (unsigned long long)trans_id); + + } else if (callback_type == GETDNS_CALLBACK_CANCEL) + fprintf(stderr, + "An error occurred: The callback with ID %llu was cancelled. Exiting.\n", + (unsigned long long)trans_id); + else { + fprintf(stderr, + "An error occurred: The callback got a callback_type of %d. Exiting.\n", + callback_type); + fprintf(stderr, + "Error : '%s'\n", + getdns_get_errorstr_by_id(callback_type)); + } + getdns_dict_destroy(response); + response = NULL; +} + +#define CONTINUE ((getdns_return_t)-2) +#define CONTINUE_ERROR ((getdns_return_t)-3) + +static getdns_return_t set_cookie(getdns_dict *exts, char *cookie) +{ + uint8_t data[40]; + size_t i; + getdns_return_t r = GETDNS_RETURN_GENERIC_ERROR; + getdns_bindata bindata; + + getdns_dict *opt_parameters = getdns_dict_create(); + getdns_list *options = getdns_list_create(); + getdns_dict *option = getdns_dict_create(); + + if (*cookie == '=') + cookie++; + + for (i = 0; i < 40 && *cookie; i++) { + if (*cookie >= '0' && *cookie <= '9') + data[i] = (uint8_t)(*cookie - '0') << 4; + else if (*cookie >= 'a' && *cookie <= 'f') + data[i] = (uint8_t)(*cookie - 'a' + 10) << 4; + else if (*cookie >= 'A' && *cookie <= 'F') + data[i] = (uint8_t)(*cookie - 'A' + 10) << 4; + else + goto done; + cookie++; + if (*cookie >= '0' && *cookie <= '9') + data[i] |= (uint8_t)(*cookie - '0'); + else if (*cookie >= 'a' && *cookie <= 'f') + data[i] |= (uint8_t)(*cookie - 'a' + 10); + else if (*cookie >= 'A' && *cookie <= 'F') + data[i] |= (uint8_t)(*cookie - 'A' + 10); + else + goto done; + cookie++;; + } + bindata.data = data; + bindata.size = i; + if ((r = getdns_dict_set_int(option, "option_code", 10))) + goto done; + if ((r = getdns_dict_set_bindata(option, "option_data", &bindata))) + goto done; + if ((r = getdns_list_set_dict(options, 0, option))) + goto done; + if ((r = getdns_dict_set_list(opt_parameters, "options", options))) + goto done; + r = getdns_dict_set_dict(exts, "add_opt_parameters", opt_parameters); +done: + getdns_dict_destroy(option); + getdns_list_destroy(options); + getdns_dict_destroy(opt_parameters); + return r; +} + +getdns_return_t parse_args(int argc, char **argv) +{ + getdns_return_t r = GETDNS_RETURN_GOOD; + size_t i; + char *arg, *c, *endptr; + int t, print_api_info = 0, print_trust_anchors = 0; + getdns_list *upstream_list = NULL; + getdns_list *tas = NULL; + size_t upstream_count = 0; + + for (i = 1; i < argc; i++) { + arg = argv[i]; + if ((t = get_rrtype(arg)) >= 0) { + request_type = t; + continue; + + } else if (arg[0] == '+') { + if (arg[1] == 's' && arg[2] == 'i' && arg[3] == 't' && + (arg[4] == '=' || arg[4] == '\0')) { + if ((r = set_cookie(extensions, arg+4))) { + fprintf(stderr, "Could not set cookie:" + " %d", r); + break; + } + } else if (arg[1] == '0') { + /* Unset all existing extensions*/ + getdns_dict_destroy(extensions); + extensions = getdns_dict_create(); + break; + } 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); + break; + } + continue; + + } else if (arg[0] == '@') { + getdns_dict *upstream = ipaddr_dict(context, arg + 1); + if (upstream) { + if (!upstream_list && + !(upstream_list = + getdns_list_create_with_context(context))){ + fprintf(stderr, "Could not create upstream list\n"); + return GETDNS_RETURN_MEMORY_ERROR; + } + getdns_list_set_dict(upstream_list, + upstream_count++, upstream); + } + continue; + } else if (arg[0] != '-') { + name = arg; + continue; + } + for (c = arg+1; *c; c++) { + switch (*c) { + case 'a': + async = 1; + break; + case 'A': + calltype = ADDRESS; + break; + case 'b': + if (c[1] != 0 || ++i >= argc || !*argv[i]) { + fprintf(stderr, "max_udp_payload_size " + "expected after -b\n"); + return GETDNS_RETURN_GENERIC_ERROR; + } + edns0_size = strtol(argv[i], &endptr, 10); + if (*endptr || edns0_size < 0) { + fprintf(stderr, "positive " + "numeric max_udp_payload_size " + "expected after -b\n"); + return GETDNS_RETURN_GENERIC_ERROR; + } + getdns_context_set_edns_maximum_udp_payload_size( + context, (uint16_t) edns0_size); + goto next; + case 'c': + if (getdns_context_set_edns_client_subnet_private(context, 1)) + return GETDNS_RETURN_GENERIC_ERROR; + break; + case 'D': + (void) getdns_context_set_edns_do_bit(context, 1); + break; + case 'd': + (void) getdns_context_set_edns_do_bit(context, 0); + break; + case 'F': + if (c[1] != 0 || ++i >= argc || !*argv[i]) { + fprintf(stderr, "file name expected " + "after -F\n"); + return GETDNS_RETURN_GENERIC_ERROR; + } + query_file = argv[i]; + interactive = 1; + break; + case 'G': + calltype = GENERAL; + break; + case 'H': + calltype = HOSTNAME; + break; + case 'h': + print_usage(stdout, argv[0]); + return CONTINUE; + case 'i': + print_api_info = 1; + break; + case 'I': + interactive = 1; + break; + case 'j': + json = 2; + break; + case 'J': + json = 1; + break; + case 'k': + print_trust_anchors = 1; + break; + case 'n': + getdns_context_set_tls_authentication(context, + GETDNS_AUTHENTICATION_NONE); + break; + case 'm': + getdns_context_set_tls_authentication(context, + GETDNS_AUTHENTICATION_HOSTNAME); + break; + case 'P': + if (c[1] != 0 || ++i >= argc || !*argv[i]) { + fprintf(stderr, "tls_query_padding_blocksize " + "expected after -P\n"); + return GETDNS_RETURN_GENERIC_ERROR; + } + padding_blocksize = strtol(argv[i], &endptr, 10); + if (*endptr || padding_blocksize < 0) { + fprintf(stderr, "non-negative " + "numeric padding blocksize expected " + "after -P\n"); + return GETDNS_RETURN_GENERIC_ERROR; + } + if (getdns_context_set_tls_query_padding_blocksize( + context, padding_blocksize)) + return GETDNS_RETURN_GENERIC_ERROR; + goto next; + case 'p': + json = 0; + case 'q': + quiet = 1; + break; + case 'r': + getdns_context_set_resolution_type( + context, + GETDNS_RESOLUTION_RECURSING); + break; + case 's': + getdns_context_set_resolution_type( + context, GETDNS_RESOLUTION_STUB); + break; + case 'S': + calltype = SERVICE; + break; + case 't': + if (c[1] != 0 || ++i >= argc || !*argv[i]) { + fprintf(stderr, "timeout expected " + "after -t\n"); + return GETDNS_RETURN_GENERIC_ERROR; + } + timeout = strtol(argv[i], &endptr, 10); + if (*endptr || timeout < 0) { + fprintf(stderr, "positive " + "numeric timeout expected " + "after -t\n"); + return GETDNS_RETURN_GENERIC_ERROR; + } + getdns_context_set_timeout( + context, timeout); + goto next; + case 'e': + if (c[1] != 0 || ++i >= argc || !*argv[i]) { + fprintf(stderr, "idle timeout expected " + "after -t\n"); + return GETDNS_RETURN_GENERIC_ERROR; + } + timeout = strtol(argv[i], &endptr, 10); + if (*endptr || timeout < 0) { + fprintf(stderr, "positive " + "numeric idle timeout expected " + "after -t\n"); + return GETDNS_RETURN_GENERIC_ERROR; + } + getdns_context_set_idle_timeout( + context, timeout); + goto next; + case 'T': + getdns_context_set_dns_transport(context, + GETDNS_TRANSPORT_TCP_ONLY); + break; + case 'O': + getdns_context_set_dns_transport(context, + GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN); + break; + case 'L': + getdns_context_set_dns_transport(context, + GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN); + break; + case 'E': + getdns_context_set_dns_transport(context, + GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN); + break; + case 'R': + getdns_context_set_dns_transport(context, + GETDNS_TRANSPORT_STARTTLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN); + break; + case 'u': + getdns_context_set_dns_transport(context, + GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP); + break; + case 'U': + getdns_context_set_dns_transport(context, + GETDNS_TRANSPORT_UDP_ONLY); + break; + case 'l': + if (c[1] != 0 || ++i >= argc || !*argv[i]) { + fprintf(stderr, "transport list expected " + "after -l\n"); + return GETDNS_RETURN_GENERIC_ERROR; + } + getdns_transport_list_t transports[10]; + size_t transport_count = sizeof(transports); + if ((r = fill_transport_list(context, argv[i], transports, &transport_count)) || + (r = getdns_context_set_dns_transport_list(context, + transport_count, transports))){ + fprintf(stderr, "Could not set transports\n"); + return r; + } + break; + case 'B': + batch_mode = 1; + break; + + + default: + fprintf(stderr, "Unknown option " + "\"%c\"\n", *c); + for (i = 0; i < argc; i++) + fprintf(stderr, "%d: \"%s\"\n", (int)i, argv[i]); + return GETDNS_RETURN_GENERIC_ERROR; + } + } +next: ; + } + if (r) + return r; + if (upstream_count && + (r = getdns_context_set_upstream_recursive_servers( + context, upstream_list))) { + fprintf(stderr, "Error setting upstream recursive servers\n"); + } + if (print_api_info) { + fprintf(stdout, "%s\n", getdns_pretty_print_dict( + getdns_context_get_api_information(context))); + return CONTINUE; + } + if (print_trust_anchors) { + if ((tas = getdns_root_trust_anchor(NULL))) { + fprintf(stdout, "%s\n", getdns_pretty_print_list(tas)); + return CONTINUE; + } else + return CONTINUE_ERROR; + } + return r; +} + +getdns_return_t do_the_call(void) +{ + getdns_return_t r; + getdns_dict *address = NULL; + getdns_dict *response = NULL; + char *response_str; + uint32_t status; + + if (calltype == HOSTNAME && + !(address = ipaddr_dict(context, name))) { + fprintf(stderr, "Could not convert \"%s\" " + "to an IP address", name); + return GETDNS_RETURN_GOOD; + } + if (async) { + switch (calltype) { + case GENERAL: + r = getdns_general(context, name, request_type, + extensions, &response, NULL, callback); + break; + case ADDRESS: + r = getdns_address(context, name, + extensions, &response, NULL, callback); + break; + case HOSTNAME: + r = getdns_hostname(context, address, + extensions, &response, NULL, callback); + break; + case SERVICE: + r = getdns_service(context, name, + extensions, &response, NULL, callback); + break; + default: + r = GETDNS_RETURN_GENERIC_ERROR; + break; + } + 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, + getdns_get_errorstr_by_id(r)); + } else { + switch (calltype) { + case GENERAL: + r = getdns_general_sync(context, name, + request_type, extensions, &response); + break; + case ADDRESS: + r = getdns_address_sync(context, name, + extensions, &response); + break; + case HOSTNAME: + r = getdns_hostname_sync(context, address, + extensions, &response); + break; + case SERVICE: + r = getdns_service_sync(context, name, + extensions, &response); + break; + default: + r = GETDNS_RETURN_GENERIC_ERROR; + break; + } + if (r != GETDNS_RETURN_GOOD) { + fprintf(stderr, "An error occurred: %d '%s'\n", r, + getdns_get_errorstr_by_id(r)); + return r; + } + if (response && !quiet) { + if ((response_str = json ? + getdns_print_json_dict(response, json == 1) + : getdns_pretty_print_dict(response))) { + + fprintf( stdout, "SYNC response:\n%s\n" + , response_str); + validate_chain(response); + free(response_str); + } else { + r = GETDNS_RETURN_MEMORY_ERROR; + fprintf( stderr + , "Could not print response\n"); + } + } + getdns_dict_get_int(response, "status", &status); + fprintf(stdout, "Response code was: GOOD. Status was: %s\n", + getdns_get_errorstr_by_id(status)); + if (response) + getdns_dict_destroy(response); + } + return r; +} + +my_eventloop my_loop; +FILE *fp; + +void read_line_cb(void *userarg) +{ + getdns_eventloop_event *read_line_ev = userarg; + getdns_return_t r; + + char line[1024], *token, *linev[256]; + int linec; + + if (!fgets(line, 1024, fp) || !*line) { + if (query_file) + fprintf(stdout,"End of file."); + my_eventloop_clear(&my_loop.base, read_line_ev); + return; + } + if (query_file) + fprintf(stdout,"Found query: %s", line); + + linev[0] = __FILE__; + linec = 1; + if (!(token = strtok(line, " \t\f\n\r"))) { + if (! query_file) { + printf("> "); + fflush(stdout); + } + return; + } + if (*token == '#') { + fprintf(stdout,"Result: Skipping comment\n"); + if (! query_file) { + printf("> "); + fflush(stdout); + } + return; + } + do linev[linec++] = token; + while (linec < 256 && (token = strtok(NULL, " \t\f\n\r"))); + + if (((r = parse_args(linec, linev)) || (r = do_the_call())) && + (r != CONTINUE && r != CONTINUE_ERROR)) + my_eventloop_clear(&my_loop.base, read_line_ev); + + else if (! query_file) { + printf("> "); + fflush(stdout); + } +} + +int +main(int argc, char **argv) +{ + getdns_return_t r; + + name = the_root; + if ((r = getdns_context_create(&context, 1))) { + fprintf(stderr, "Create context failed: %d\n", 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(); + if (! extensions) { + fprintf(stderr, "Could not create extensions dict\n"); + r = GETDNS_RETURN_MEMORY_ERROR; + goto done_destroy_context; + } + if ((r = parse_args(argc, argv))) + goto done_destroy_context; + + if (query_file) { + fp = fopen(query_file, "rt"); + if (fp == NULL) { + fprintf(stderr, "Could not open query file: %s\n", query_file); + goto done_destroy_context; + } + } else + fp = stdin; + + /* 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 (!query_file) { + printf("> "); + fflush(stdout); + } + my_eventloop_run(&my_loop.base); + } + else + r = do_the_call(); + + if ((r == GETDNS_RETURN_GOOD && batch_mode)) + getdns_context_run(context); + + /* Clean up */ + getdns_dict_destroy(extensions); +done_destroy_context: + getdns_context_destroy(context); + + if (fp) + fclose(fp); + + if (r == CONTINUE) + return 0; + else if (r == CONTINUE_ERROR) + return 1; + fprintf(stdout, "\nAll done.\n"); + return r; +} + +int get_rrtype(const char *t) { + char *endptr; + int r; + + switch (t[0]) { + case 'A': + case 'a': switch (t[1]) { + case '\0': return GETDNS_RRTYPE_A; + case '6': if (t[2] == '\0') return GETDNS_RRTYPE_A6; + return -1; + case 'A': + case 'a': /* before "AA", final "AA" (GETDNS_RRTYPE_AAAA) */ + if ((t[2]|0x20) == 'a' && (t[3]|0x20) == 'a' && t[4] == '\0') + return GETDNS_RRTYPE_AAAA; + return -1; + case 'F': + case 'f': /* before "AF", final "SDB" (GETDNS_RRTYPE_AFSDB) */ + if ((t[2]|0x20) == 's' && (t[3]|0x20) == 'd' && (t[4]|0x20) == 'b' && t[5] == '\0') + return GETDNS_RRTYPE_AFSDB; + return -1; + case 'P': + case 'p': /* before "AP", final "L" (GETDNS_RRTYPE_APL) */ + if ((t[2]|0x20) == 'l' && t[3] == '\0') + return GETDNS_RRTYPE_APL; + return -1; + case 'T': + case 't': /* before "AT", final "MA" (GETDNS_RRTYPE_ATMA) */ + if ((t[2]|0x20) == 'm' && (t[3]|0x20) == 'a' && t[4] == '\0') + return GETDNS_RRTYPE_ATMA; + return -1; + case 'X': + case 'x': /* before "AX", final "FR" (GETDNS_RRTYPE_AXFR) */ + if ((t[2]|0x20) == 'f' && (t[3]|0x20) == 'r' && t[4] == '\0') + return GETDNS_RRTYPE_AXFR; + return -1; + default : return -1; + }; + case 'C': + case 'c': switch (t[1]) { + case 'A': + case 'a': /* before "CA", final "A" (GETDNS_RRTYPE_CAA) */ + if ((t[2]|0x20) == 'a' && t[3] == '\0') + return GETDNS_RRTYPE_CAA; + return -1; + case 'D': + case 'd': switch (t[2]) { + case 'N': + case 'n': /* before "CDN", final "SKEY" (GETDNS_RRTYPE_CDNSKEY) */ + if ((t[3]|0x20) == 's' && (t[4]|0x20) == 'k' && (t[5]|0x20) == 'e' && (t[6]|0x20) == 'y' && t[7] == '\0') + return GETDNS_RRTYPE_CDNSKEY; + return -1; + case 'S': + case 's': if (t[3] == '\0') return GETDNS_RRTYPE_CDS; + return -1; + default : return -1; + }; + case 'E': + case 'e': /* before "CE", final "RT" (GETDNS_RRTYPE_CERT) */ + if ((t[2]|0x20) == 'r' && (t[3]|0x20) == 't' && t[4] == '\0') + return GETDNS_RRTYPE_CERT; + return -1; + case 'N': + case 'n': /* before "CN", final "AME" (GETDNS_RRTYPE_CNAME) */ + if ((t[2]|0x20) == 'a' && (t[3]|0x20) == 'm' && (t[4]|0x20) == 'e' && t[5] == '\0') + return GETDNS_RRTYPE_CNAME; + return -1; + case 'S': + case 's': /* before "CS", final "YNC" (GETDNS_RRTYPE_CSYNC) */ + if ((t[2]|0x20) == 'y' && (t[3]|0x20) == 'n' && (t[4]|0x20) == 'c' && t[5] == '\0') + return GETDNS_RRTYPE_CSYNC; + return -1; + + default : return -1; + }; + case 'D': + case 'd': switch (t[1]) { + case 'H': + case 'h': /* before "DH", final "CID" (GETDNS_RRTYPE_DHCID) */ + if ((t[2]|0x20) == 'c' && (t[3]|0x20) == 'i' && (t[4]|0x20) == 'd' && t[5] == '\0') + return GETDNS_RRTYPE_DHCID; + return -1; + case 'L': + case 'l': /* before "DL", final "V" (GETDNS_RRTYPE_DLV) */ + if ((t[2]|0x20) == 'v' && t[3] == '\0') + return GETDNS_RRTYPE_DLV; + return -1; + case 'N': + case 'n': switch (t[2]) { + case 'A': + case 'a': /* before "DNA", final "ME" (GETDNS_RRTYPE_DNAME) */ + if ((t[3]|0x20) == 'm' && (t[4]|0x20) == 'e' && t[5] == '\0') + return GETDNS_RRTYPE_DNAME; + return -1; + case 'S': + case 's': /* before "DNS", final "KEY" (GETDNS_RRTYPE_DNSKEY) */ + if ((t[3]|0x20) == 'k' && (t[4]|0x20) == 'e' && (t[5]|0x20) == 'y' && t[6] == '\0') + return GETDNS_RRTYPE_DNSKEY; + return -1; + default : return -1; + }; + case 'S': + case 's': if (t[2] == '\0') return GETDNS_RRTYPE_DS; + return -1; + default : return -1; + }; + case 'E': + case 'e': switch (t[1]) { + case 'I': + case 'i': /* before "EI", final "D" (GETDNS_RRTYPE_EID) */ + if ((t[2]|0x20) == 'd' && t[3] == '\0') + return GETDNS_RRTYPE_EID; + return -1; + case 'U': + case 'u': /* before "EU", next "I" */ + if ((t[2]|0x20) != 'i') + return -1; + switch (t[3]) { + case '4': /* before "EUI4", final "8" (GETDNS_RRTYPE_EUI48) */ + if (t[4] == '8' && t[5] == '\0') + return GETDNS_RRTYPE_EUI48; + return -1; + case '6': /* before "EUI6", final "4" (GETDNS_RRTYPE_EUI64) */ + if (t[4] == '4' && t[5] == '\0') + return GETDNS_RRTYPE_EUI64; + return -1; + default : return -1; + }; + default : return -1; + }; + case 'G': + case 'g': switch (t[1]) { + case 'I': + case 'i': /* before "GI", final "D" (GETDNS_RRTYPE_GID) */ + if ((t[2]|0x20) == 'd' && t[3] == '\0') + return GETDNS_RRTYPE_GID; + return -1; + case 'P': + case 'p': /* before "GP", final "OS" (GETDNS_RRTYPE_GPOS) */ + if ((t[2]|0x20) == 'o' && (t[3]|0x20) == 's' && t[4] == '\0') + return GETDNS_RRTYPE_GPOS; + return -1; + default : return -1; + }; + case 'H': + case 'h': /* before "H", next "I" */ + if ((t[1]|0x20) != 'i') + return -1; + switch (t[2]) { + case 'N': + case 'n': /* before "HIN", final "FO" (GETDNS_RRTYPE_HINFO) */ + if ((t[3]|0x20) == 'f' && (t[4]|0x20) == 'o' && t[5] == '\0') + return GETDNS_RRTYPE_HINFO; + return -1; + case 'P': + case 'p': if (t[3] == '\0') return GETDNS_RRTYPE_HIP; + return -1; + default : return -1; + }; + case 'I': + case 'i': switch (t[1]) { + case 'P': + case 'p': /* before "IP", final "SECKEY" (GETDNS_RRTYPE_IPSECKEY) */ + if ((t[2]|0x20) == 's' && (t[3]|0x20) == 'e' && (t[4]|0x20) == 'c' && (t[5]|0x20) == 'k' && (t[6]|0x20) == 'e' && (t[7]|0x20) == 'y' && t[8] == '\0') + return GETDNS_RRTYPE_IPSECKEY; + return -1; + case 'S': + case 's': /* before "IS", final "DN" (GETDNS_RRTYPE_ISDN) */ + if ((t[2]|0x20) == 'd' && (t[3]|0x20) == 'n' && t[4] == '\0') + return GETDNS_RRTYPE_ISDN; + return -1; + case 'X': + case 'x': /* before "IX", final "FR" (GETDNS_RRTYPE_IXFR) */ + if ((t[2]|0x20) == 'f' && (t[3]|0x20) == 'r' && t[4] == '\0') + return GETDNS_RRTYPE_IXFR; + return -1; + default : return -1; + }; + case 'K': + case 'k': switch (t[1]) { + case 'E': + case 'e': /* before "KE", final "Y" (GETDNS_RRTYPE_KEY) */ + if ((t[2]|0x20) == 'y' && t[3] == '\0') + return GETDNS_RRTYPE_KEY; + return -1; + case 'X': + case 'x': if (t[2] == '\0') return GETDNS_RRTYPE_KX; + return -1; + default : return -1; + }; + case 'L': + case 'l': switch (t[1]) { + case '3': /* before "L3", final "2" (GETDNS_RRTYPE_L32) */ + if (t[2] == '2' && t[3] == '\0') + return GETDNS_RRTYPE_L32; + return -1; + case '6': /* before "L6", final "4" (GETDNS_RRTYPE_L64) */ + if (t[2] == '4' && t[3] == '\0') + return GETDNS_RRTYPE_L64; + return -1; + case 'O': + case 'o': /* before "LO", final "C" (GETDNS_RRTYPE_LOC) */ + if ((t[2]|0x20) == 'c' && t[3] == '\0') + return GETDNS_RRTYPE_LOC; + return -1; + case 'P': + case 'p': if (t[2] == '\0') return GETDNS_RRTYPE_LP; + return -1; + default : return -1; + }; + case 'M': + case 'm': switch (t[1]) { + case 'A': + case 'a': /* before "MA", next "IL" */ + if ((t[2]|0x20) != 'i' && (t[3]|0x20) != 'l') + return -1; + switch (t[4]) { + case 'A': + case 'a': if (t[5] == '\0') return GETDNS_RRTYPE_MAILA; + return -1; + case 'B': + case 'b': if (t[5] == '\0') return GETDNS_RRTYPE_MAILB; + return -1; + default : return -1; + }; + case 'B': + case 'b': if (t[2] == '\0') return GETDNS_RRTYPE_MB; + return -1; + case 'D': + case 'd': if (t[2] == '\0') return GETDNS_RRTYPE_MD; + return -1; + case 'F': + case 'f': if (t[2] == '\0') return GETDNS_RRTYPE_MF; + return -1; + case 'G': + case 'g': if (t[2] == '\0') return GETDNS_RRTYPE_MG; + return -1; + case 'I': + case 'i': /* before "MI", final "NFO" (GETDNS_RRTYPE_MINFO) */ + if ((t[2]|0x20) == 'n' && (t[3]|0x20) == 'f' && (t[4]|0x20) == 'o' && t[5] == '\0') + return GETDNS_RRTYPE_MINFO; + return -1; + case 'R': + case 'r': if (t[2] == '\0') return GETDNS_RRTYPE_MR; + return -1; + case 'X': + case 'x': if (t[2] == '\0') return GETDNS_RRTYPE_MX; + return -1; + default : return -1; + }; + case 'N': + case 'n': switch (t[1]) { + case 'A': + case 'a': /* before "NA", final "PTR" (GETDNS_RRTYPE_NAPTR) */ + if ((t[2]|0x20) == 'p' && (t[3]|0x20) == 't' && (t[4]|0x20) == 'r' && t[5] == '\0') + return GETDNS_RRTYPE_NAPTR; + return -1; + case 'I': + case 'i': switch (t[2]) { + case 'D': + case 'd': if (t[3] == '\0') return GETDNS_RRTYPE_NID; + return -1; + case 'M': + case 'm': /* before "NIM", final "LOC" (GETDNS_RRTYPE_NIMLOC) */ + if ((t[3]|0x20) == 'l' && (t[4]|0x20) == 'o' && (t[5]|0x20) == 'c' && t[6] == '\0') + return GETDNS_RRTYPE_NIMLOC; + return -1; + case 'N': + case 'n': /* before "NIN", final "FO" (GETDNS_RRTYPE_NINFO) */ + if ((t[3]|0x20) == 'f' && (t[4]|0x20) == 'o' && t[5] == '\0') + return GETDNS_RRTYPE_NINFO; + return -1; + default : return -1; + }; + case 'S': + case 's': switch (t[2]) { + case '\0': return GETDNS_RRTYPE_NS; + case 'A': + case 'a': /* before "NSA", final "P" (GETDNS_RRTYPE_NSAP) */ + if ((t[3]|0x20) == 'p' && t[4] == '\0') + return GETDNS_RRTYPE_NSAP; + return -1; + case 'E': + case 'e': /* before "NSE", final "C3PARAM" (GETDNS_RRTYPE_NSEC3PARAM) */ + if ((t[3]|0x20) == 'c' && t[4] == '3' && (t[5]|0x20) == 'p' && (t[6]|0x20) == 'a' && (t[7]|0x20) == 'r' && (t[8]|0x20) == 'a' && (t[9]|0x20) == 'm' && t[10] == '\0') + return GETDNS_RRTYPE_NSEC3PARAM; + return -1; + default : return -1; + }; + case 'U': + case 'u': /* before "NU", final "LL" (GETDNS_RRTYPE_NULL) */ + if ((t[2]|0x20) == 'l' && (t[3]|0x20) == 'l' && t[4] == '\0') + return GETDNS_RRTYPE_NULL; + return -1; + case 'X': + case 'x': /* before "NX", final "T" (GETDNS_RRTYPE_NXT) */ + if ((t[2]|0x20) == 't' && t[3] == '\0') + return GETDNS_RRTYPE_NXT; + return -1; + default : return -1; + }; + case 'O': + case 'o': /* before "O", next "P" */ + if ((t[1]|0x20) != 'p') + return -1; + switch (t[2]) { + case 'E': + case 'e': /* before "OPE", final "NPGPKEY" (GETDNS_RRTYPE_OPENPGPKEY) */ + if ((t[3]|0x20) == 'n' && (t[4]|0x20) == 'p' && (t[5]|0x20) == 'g' && (t[6]|0x20) == 'p' && (t[7]|0x20) == 'k' && (t[8]|0x20) == 'e' && (t[9]|0x20) == 'y' && t[10] == '\0') + return GETDNS_RRTYPE_OPENPGPKEY; + return -1; + case 'T': + case 't': if (t[3] == '\0') return GETDNS_RRTYPE_OPT; + return -1; + default : return -1; + }; + case 'P': + case 'p': switch (t[1]) { + case 'T': + case 't': /* before "PT", final "R" (GETDNS_RRTYPE_PTR) */ + if ((t[2]|0x20) == 'r' && t[3] == '\0') + return GETDNS_RRTYPE_PTR; + return -1; + case 'X': + case 'x': if (t[2] == '\0') return GETDNS_RRTYPE_PX; + return -1; + default : return -1; + }; + case 'R': + case 'r': switch (t[1]) { + case 'K': + case 'k': /* before "RK", final "EY" (GETDNS_RRTYPE_RKEY) */ + if ((t[2]|0x20) == 'e' && (t[3]|0x20) == 'y' && t[4] == '\0') + return GETDNS_RRTYPE_RKEY; + return -1; + case 'P': + case 'p': if (t[2] == '\0') return GETDNS_RRTYPE_RP; + return -1; + case 'R': + case 'r': /* before "RR", final "SIG" (GETDNS_RRTYPE_RRSIG) */ + if ((t[2]|0x20) == 's' && (t[3]|0x20) == 'i' && (t[4]|0x20) == 'g' && t[5] == '\0') + return GETDNS_RRTYPE_RRSIG; + return -1; + case 'T': + case 't': if (t[2] == '\0') return GETDNS_RRTYPE_RT; + return -1; + default : return -1; + }; + case 'S': + case 's': switch (t[1]) { + case 'I': + case 'i': switch (t[2]) { + case 'G': + case 'g': if (t[3] == '\0') return GETDNS_RRTYPE_SIG; + return -1; + case 'N': + case 'n': /* before "SIN", final "K" (GETDNS_RRTYPE_SINK) */ + if ((t[3]|0x20) == 'k' && t[4] == '\0') + return GETDNS_RRTYPE_SINK; + return -1; + default : return -1; + }; + case 'O': + case 'o': /* before "SO", final "A" (GETDNS_RRTYPE_SOA) */ + if ((t[2]|0x20) == 'a' && t[3] == '\0') + return GETDNS_RRTYPE_SOA; + return -1; + case 'P': + case 'p': /* before "SP", final "F" (GETDNS_RRTYPE_SPF) */ + if ((t[2]|0x20) == 'f' && t[3] == '\0') + return GETDNS_RRTYPE_SPF; + return -1; + case 'R': + case 'r': /* before "SR", final "V" (GETDNS_RRTYPE_SRV) */ + if ((t[2]|0x20) == 'v' && t[3] == '\0') + return GETDNS_RRTYPE_SRV; + return -1; + case 'S': + case 's': /* before "SS", final "HFP" (GETDNS_RRTYPE_SSHFP) */ + if ((t[2]|0x20) == 'h' && (t[3]|0x20) == 'f' && (t[4]|0x20) == 'p' && t[5] == '\0') + return GETDNS_RRTYPE_SSHFP; + return -1; + default : return -1; + }; + case 'T': + case 't': switch (t[1]) { + case 'A': + case 'a': /* before "TA", final "LINK" (GETDNS_RRTYPE_TALINK) */ + if ((t[2]|0x20) == 'l' && (t[3]|0x20) == 'i' && (t[4]|0x20) == 'n' && (t[5]|0x20) == 'k' && t[6] == '\0') + return GETDNS_RRTYPE_TALINK; + return -1; + case 'K': + case 'k': /* before "TK", final "EY" (GETDNS_RRTYPE_TKEY) */ + if ((t[2]|0x20) == 'e' && (t[3]|0x20) == 'y' && t[4] == '\0') + return GETDNS_RRTYPE_TKEY; + return -1; + case 'L': + case 'l': /* before "TL", final "SA" (GETDNS_RRTYPE_TLSA) */ + if ((t[2]|0x20) == 's' && (t[3]|0x20) == 'a' && t[4] == '\0') + return GETDNS_RRTYPE_TLSA; + return -1; + case 'S': + case 's': /* before "TS", final "IG" (GETDNS_RRTYPE_TSIG) */ + if ((t[2]|0x20) == 'i' && (t[3]|0x20) == 'g' && t[4] == '\0') + return GETDNS_RRTYPE_TSIG; + return -1; + case 'X': + case 'x': /* before "TX", final "T" (GETDNS_RRTYPE_TXT) */ + if ((t[2]|0x20) == 't' && t[3] == '\0') + return GETDNS_RRTYPE_TXT; + return -1; + case 'Y': + case 'y': /* before "TY", then "PE" followed by a number */ + if ((t[2]|0x20) == 'p' && (t[3]|0x20) == 'e' && t[4] != '\0') { + r = (int) strtol(t + 4, &endptr, 10); + if (*endptr == '\0') return r; + } + return -1; + default : return -1; + }; + case 'U': + case 'u': switch (t[1]) { + case 'I': + case 'i': switch (t[2]) { + case 'D': + case 'd': if (t[3] == '\0') return GETDNS_RRTYPE_UID; + return -1; + case 'N': + case 'n': /* before "UIN", final "FO" (GETDNS_RRTYPE_UINFO) */ + if ((t[3]|0x20) == 'f' && (t[4]|0x20) == 'o' && t[5] == '\0') + return GETDNS_RRTYPE_UINFO; + return -1; + default : return -1; + }; + case 'N': + case 'n': /* before "UN", final "SPEC" (GETDNS_RRTYPE_UNSPEC) */ + if ((t[2]|0x20) == 's' && (t[3]|0x20) == 'p' && (t[4]|0x20) == 'e' && (t[5]|0x20) == 'c' && t[6] == '\0') + return GETDNS_RRTYPE_UNSPEC; + return -1; + case 'R': + case 'r': /* before "UR", final "I" (GETDNS_RRTYPE_URI) */ + if ((t[2]|0x20) == 'i' && t[3] == '\0') + return GETDNS_RRTYPE_URI; + return -1; + default : return -1; + }; + case 'W': + case 'w': /* before "W", final "KS" (GETDNS_RRTYPE_WKS) */ + if ((t[1]|0x20) == 'k' && (t[2]|0x20) == 's' && t[3] == '\0') + return GETDNS_RRTYPE_WKS; + return -1; + case 'X': + case 'x': /* before "X", final "25" (GETDNS_RRTYPE_X25) */ + if (t[1] == '2' && t[2] == '5' && t[3] == '\0') + return GETDNS_RRTYPE_X25; + return -1; + default : return -1; + }; +} + diff --git a/src/stub.c b/src/stub.c index c0c254cc..8072d5da 100644 --- a/src/stub.c +++ b/src/stub.c @@ -46,6 +46,12 @@ #include "util-internal.h" #include "general.h" +#ifdef USE_WINSOCK +#define EINPROGRESS 112 +#define EWOULDBLOCK 140 +typedef u_short sa_family_t; +#endif + #define STUB_OUT_OF_OPTIONS -5 /* upstream options exceeded MAXIMUM_UPSTREAM_OPTION_SPACE */ #define STUB_TLS_SETUP_ERROR -4 #define STUB_TCP_AGAIN -3 @@ -741,8 +747,16 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq) upstream). We must let the handshake complete since non-blocking. */ errno == EINPROGRESS)) || written < pkt_len + 2) { +#else + +#ifdef USE_WINSOCK + written = sendto(fd, 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)) || written < pkt_len + 2) { diff --git a/src/util/winsock_event.c b/src/util/winsock_event.c new file mode 100644 index 00000000..f29c9f32 --- /dev/null +++ b/src/util/winsock_event.c @@ -0,0 +1,872 @@ +/* + * 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. + */ + +#include "config.h" +#ifdef USE_WINSOCK +#include +#ifdef HAVE_TIME_H +#include +#endif +#include +#include "util/winsock_event.h" +#include "util/fptr_wlist.h" + +/** +* implementation of log_err +* @param format: format string printf-style. +*/ +void +log_err(const char *format, ...) +{ + va_list args; + va_start(args, format); + fprintf(stderr, "error", 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 UNBOUND_DEBUG +/** + * Find a fd in the list of items. + * Note that not all items have a fd associated (those are -1). + * Signals are stored separately, and not searched. + * @param base: event base to look in. + * @param fd: what socket to look for. + * @return the index in the array, or -1 on failure. + */ +static int +find_fd(struct _getdns_event_base* base, int fd) +{ + int i; + for(i=0; imax; i++) { + if(base->items[i]->ev_fd == fd) + return i; + } + return -1; +} +#endif + +/** Find ptr in base array */ +static void +zero_waitfor(WSAEVENT waitfor[], WSAEVENT x) +{ + int i; + for(i=0; itime_secs = time_secs; + base->time_tv = time_tv; + if(settime(base) < 0) { + _getdns_event_base_free(base); + return NULL; + } + base->items = (struct _getdns_event**)calloc(WSK_MAX_ITEMS, + sizeof(struct _getdns_event*)); + if(!base->items) { + _getdns_event_base_free(base); + return NULL; + } + base->cap = WSK_MAX_ITEMS; + base->max = 0; + base->times = _getdns_rbtree_create(_getdns_mini_ev_cmp); + if(!base->times) { + _getdns_event_base_free(base); + return NULL; + } + base->signals = (struct _getdns_event**)calloc(MAX_SIG, sizeof(struct _getdns_event*)); + if(!base->signals) { + _getdns_event_base_free(base); + return NULL; + } + base->tcp_stickies = 0; + base->tcp_reinvigorated = 0; + //verbose(VERB_CLIENT, "winsock_event inited"); + return base; +} + +const char *_getdns_event_get_version(void) +{ + return "winsock-event-"PACKAGE_VERSION; +} + +const char *_getdns_event_get_method(void) +{ + return "WSAWaitForMultipleEvents"; +} + +//gowri remove static +/** 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 + //verbose(VERB_CLIENT, "winsock_event handle_timeouts"); + + 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; + } + //verbose(VERB_CLIENT, "winsock_event wait=" ARG_LL "d.%6.6d", + // (long long)wait->tv_sec, (int)wait->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); + } + //verbose(VERB_CLIENT, "winsock_event wait=(-1)"); +} + +/** 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, was_timeout = 0; + int newstickies = 0; + struct timeval nultm; + +#ifndef S_SPLINT_S + if(wait->tv_sec==(time_t)-1) + wait = NULL; + if (wait) + // timeout = 10 + wait->tv_usec / 1000; + timeout = wait->tv_sec * 1000 + wait->tv_usec / 1000; + if(base->tcp_stickies) { + wait = &nultm; + nultm.tv_sec = 0; + nultm.tv_usec = 0; + timeout = 0; /* no waiting, we have sticky events */ + } +#endif + + /* prepare event array */ + for(i=0; imax; i++) { + if(base->items[i]->ev_fd == -1 && !base->items[i]->is_signal) + continue; /* skip timer only events */ + eventlist[numwait] = base->items[i]; + base->waitfor[numwait++] = base->items[i]->hEvent; + printf("winsock_event bmax=%d numwait=%d wait=%x " + "timeout=%d hEvent %d\n", base->max, numwait, (int)wait, (int)timeout, 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); + } + was_timeout = 1; + } + else { + //gv: do not schedule udp write + for (i = 0; imax; i++) { + if (!base->items[i]->is_tcp && base->items[i]->ev_events&EV_WRITE) { + //gprintf("skip UDP sched\n"); + (*eventlist[i]->ev_callback)(eventlist[i]->ev_fd, + EV_WRITE & eventlist[i]->ev_events, + eventlist[i]->ev_arg); + return 0; + } + } + //gprintf("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) */ + //gprintf("after wait %d %d\n", 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"); + was_timeout = 1; + } else + startidx = ret - WSA_WAIT_EVENT_0; + } + ////verbose(VERB_CLIENT, "winsock_event wake was_timeout=%d startidx=%d", + // was_timeout, startidx); + + /* get new time after wait */ + if(settime(base) < 0) + return -1; + + /* callbacks */ + if(base->tcp_stickies) + startidx = 0; /* process all events, some are sticky */ + for(i=startidx; ijust_checked = 1; + + //verbose(VERB_CLIENT, "winsock_event signals"); + for(i=startidx; iwaitfor[i]) + continue; /* was deleted */ + if(eventlist[i]->is_signal) { + eventlist[i]->just_checked = 0; + _getdns_handle_signal(eventlist[i]); + } + } + /* early exit - do not process network, exit quickly */ + if(base->need_to_exit) + return 0; + + //verbose(VERB_CLIENT, "winsock_event net"); + for(i=startidx; iwaitfor[i]) + continue; /* was deleted */ + if(!eventlist[i]->just_checked) + continue; /* added by other callback */ + if(eventlist[i]->is_signal) + continue; /* not a network event at all */ + eventlist[i]->just_checked = 0; + + if(WSAEnumNetworkEvents(eventlist[i]->ev_fd, + base->waitfor[i], /* reset the event handle */ + /*NULL,*/ /* do not reset the event handle */ + &netev) != 0) { + log_err("getdns: WSAEnumNetworkEvents failed: %s", + wsa_strerror(WSAGetLastError())); + return -1; + } + if((netev.lNetworkEvents & FD_READ)) { + if(netev.iErrorCode[FD_READ_BIT] != 0) + printf("FD_READ_BIT error: %s\n", + wsa_strerror(netev.iErrorCode[FD_READ_BIT])); + bits |= EV_READ; + printf("FD_READ_BIT\n"); + } + if((netev.lNetworkEvents & FD_WRITE)) { + if(netev.iErrorCode[FD_WRITE_BIT] != 0) + printf("FD_WRITE_BIT error: %s\n", + wsa_strerror(netev.iErrorCode[FD_WRITE_BIT])); + bits |= EV_WRITE; + printf("FD_WRITE_BIT\n"); + } + if((netev.lNetworkEvents & FD_CONNECT)) { + if(netev.iErrorCode[FD_CONNECT_BIT] != 0) + printf("FD_CONNECT_BIT error: %s\n", + wsa_strerror(netev.iErrorCode[FD_CONNECT_BIT])); + bits |= EV_READ; + bits |= EV_WRITE; + printf("FD_CONNECT_BIT\n"); + } + if((netev.lNetworkEvents & FD_ACCEPT)) { + if(netev.iErrorCode[FD_ACCEPT_BIT] != 0) + printf("FD_ACCEPT_BIT error: %s\n", + wsa_strerror(netev.iErrorCode[FD_ACCEPT_BIT])); + bits |= EV_READ; + printf("FD_ACCEPT_BIT\n"); + } + if((netev.lNetworkEvents & FD_CLOSE)) { + if(netev.iErrorCode[FD_CLOSE_BIT] != 0) + printf("FD_CLOSE_BIT error: %s\n", + wsa_strerror(netev.iErrorCode[FD_CLOSE_BIT])); + //g bits |= EV_READ; + //g bits |= EV_WRITE; + printf("FD_CLOSE_BIT\n"); + } + if(eventlist[i]->is_tcp && eventlist[i]->stick_events) { + /* + printf("winsock %d pass sticky %s%s\n", + eventlist[i]->ev_fd, + (eventlist[i]->old_events&EV_READ)?"EV_READ":"", + (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); + */ + bits |= eventlist[i]->old_events; + } + if(eventlist[i]->is_tcp && bits) { + eventlist[i]->old_events = bits; + eventlist[i]->stick_events = 1; + if((eventlist[i]->ev_events & bits)) { + newstickies = 1; + } + /* + printf("winsock %d store sticky %s%s", + eventlist[i]->ev_fd, + (eventlist[i]->old_events&EV_READ)?"EV_READ":"", + (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); + */ + } + if((bits & eventlist[i]->ev_events)) { + printf( "winsock event callback %p fd=%d " + "%s%s%s%s%s ; %s%s%s\n", + eventlist[i], eventlist[i]->ev_fd, + (netev.lNetworkEvents&FD_READ)?" FD_READ":"", + (netev.lNetworkEvents&FD_WRITE)?" FD_WRITE":"", + (netev.lNetworkEvents&FD_CONNECT)? + " FD_CONNECT":"", + (netev.lNetworkEvents&FD_ACCEPT)? + " FD_ACCEPT":"", + (netev.lNetworkEvents&FD_CLOSE)?" FD_CLOSE":"", + (bits&EV_READ)?" EV_READ":"", + (bits&EV_WRITE)?" EV_WRITE":"", + (bits&EV_TIMEOUT)?" EV_TIMEOUT":""); + + fptr_ok(fptr_whitelist_event( + eventlist[i]->ev_callback)); + (*eventlist[i]->ev_callback)(eventlist[i]->ev_fd, + bits & eventlist[i]->ev_events, + eventlist[i]->ev_arg); + } + /* + if(eventlist[i]->is_tcp && bits) + printf( "winsock %d got sticky %s%s\n", + eventlist[i]->ev_fd, + (eventlist[i]->old_events&EV_READ)?"EV_READ":"", + (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); + */ + } + //verbose(VERB_CLIENT, "winsock_event net"); + if(base->tcp_reinvigorated) { + printf("winsock_event reinvigorated\n"); + base->tcp_reinvigorated = 0; + newstickies = 1; + } + base->tcp_stickies = newstickies; + //gprintf("winsock_event handle_select end\n"); + return 0; +} + +int _getdns_event_base_dispatch(struct _getdns_event_base *base) +{ + struct timeval wait; + if(settime(base) < 0) + return -1; + while(!base->need_to_exit) + { + /* see if timeouts need handling */ + _getdns_handle_timeouts(base, base->time_tv, &wait); + if(base->need_to_exit) + return 0; + /* do select */ + if(_getdns_handle_select(base, &wait) < 0) { + if(base->need_to_exit) + return 0; + return -1; + } + } + return 0; +} + +int _getdns_event_base_loopexit(struct _getdns_event_base *base, + struct timeval * ATTR_UNUSED(tv)) +{ + //verbose(VERB_CLIENT, "winsock_event loopexit"); + base->need_to_exit = 1; + return 0; +} + +void _getdns_event_base_free(struct _getdns_event_base *base) +{ + //verbose(VERB_CLIENT, "winsock_event event_base_free"); + 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; +} + +/** +* Find a fd in the list of items. +* Note that not all items have a fd associated (those are -1). +* Signals are stored separately, and not searched. +* @param base: event base to look in. +* @param fd: what socket to look for. +* @return the index in the array, or -1 on failure. +*/ +static int +find_fd(struct _getdns_event_base* base, int fd) +{ + int i; + for (i = 0; imax; i++) { + if (base->items[i]->ev_fd == fd) + return i; + } + return -1; +} + +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, events, ev->hEvent); + //gg if (WSAEventSelect(ev->ev_fd, ev->hEvent, FD_ACCEPT | FD_CONNECT | FD_READ | FD_CLOSE | FD_WRITE) != 0) { + //if (WSAEventSelect(ev->ev_fd, ev->hEvent,FD_READ | FD_WRITE) != 0) { + 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 */ + ev->ev_base->tcp_reinvigorated = 1; + } + } + + 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; +} + +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) +{ + struct getdns_event* ev; + if(!signal_base || sig < 0 || sig >= MAX_SIG) + return; + ev = signal_base->signals[sig]; + if(!ev) + return; + //g fptr_ok(fptr_whitelist_event(ev->ev_callback)); + //g (*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg); +} + +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) +{ + //verbose(VERB_ALGO, "winsock: tcp wouldblock %s", + //eventbits==EV_READ?"EV_READ":"EV_WRITE"); + ev->old_events &= (~eventbits); + if(ev->old_events == 0) + ev->stick_events = 0; + /* in case this is the last sticky event, we could + * possibly run an empty handler loop to reset the base + * tcp_stickies variable + */ +} + +int winsock_register_wsaevent(struct _getdns_event_base* base, struct _getdns_event* ev, + WSAEVENT wsaevent, void (*cb)(int, short, void*), void* arg) +{ + if(base->max == base->cap) + return 0; + memset(ev, 0, sizeof(*ev)); + ev->ev_fd = -1; + ev->ev_events = EV_READ; + ev->ev_callback = cb; + ev->ev_arg = arg; + ev->is_signal = 1; + ev->hEvent = wsaevent; + ev->added = 1; + ev->ev_base = base; + ev->idx = ev->ev_base->max++; + ev->ev_base->items[ev->idx] = ev; + return 1; +} + +void winsock_unregister_wsaevent(struct _getdns_event* ev) +{ + if(!ev || !ev->added) return; + //log_assert(ev->added && ev->ev_base->max > 0) + /* remove item and compact the list */ + ev->ev_base->items[ev->idx] = ev->ev_base->items[ev->ev_base->max-1]; + ev->ev_base->items[ev->ev_base->max-1] = NULL; + ev->ev_base->max--; + if(ev->idx < ev->ev_base->max) + ev->ev_base->items[ev->idx]->idx = ev->idx; + ev->added = 0; +} + +#else /* USE_WINSOCK */ +/** symbol so this codefile defines symbols. pleasing ranlib on OSX 10.5 */ +int winsock_unused_symbol = 1; +#endif /* USE_WINSOCK */ diff --git a/src/util/winsock_event.h b/src/util/winsock_event.h new file mode 100644 index 00000000..595116b2 --- /dev/null +++ b/src/util/winsock_event.h @@ -0,0 +1,294 @@ +/* + * 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. + * + * 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 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 event_set winsockevent_set +#define event_base_set winsockevent_base_set +#define 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 *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 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 event_base_free(struct _getdns_event_base *); +/** set content of event */ +void 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 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 event_add(struct _getdns_event *, struct timeval *); +/** remove event. You may change it again */ +int 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. + */ +static 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. + */ +static 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. + */ +static void winsock_unregister_wsaevent(struct _getdns_event* ev); + +#endif /* USE_WINSOCK */ +#endif /* UTIL_WINSOCK_EVENT_H */ From 22a8550caa95ea9da0bd1563c55a37a7050ae15c Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 4 Dec 2015 16:12:43 -0500 Subject: [PATCH 02/11] Bug fix in get_os_defaults, clean up code in winsock_event, add code to handle event handling differences in Winsock2 --- src/context.c | 24 +- src/stub.c | 47 +- src/util/winsock_event.c | 1162 +++++++++++++++++++------------------- src/util/winsock_event.h | 157 ++--- 4 files changed, 704 insertions(+), 686 deletions(-) diff --git a/src/context.c b/src/context.c index 5076a14a..83ae9c82 100644 --- a/src/context.c +++ b/src/context.c @@ -803,10 +803,9 @@ set_os_defaults_windows(struct getdns_context *context) hints.ai_addr = NULL; hints.ai_next = NULL; - //g FIXED_INFO *info; ULONG buflen = sizeof(*info); - IP_ADDR_STRING *ptr; + IP_ADDR_STRING *ptr = 0; info = (FIXED_INFO *)malloc(sizeof(FIXED_INFO)); if (info == NULL) @@ -821,7 +820,7 @@ set_os_defaults_windows(struct getdns_context *context) if (GetNetworkParams(info, &buflen) == NO_ERROR) { int retval = 0; - ptr = &(info->DnsServerList); + ptr = info->DnsServerList.Next; *domain = 0; while (ptr) { for (size_t i = 0; i < GETDNS_UPSTREAM_TRANSPORTS; i++) { @@ -843,7 +842,6 @@ set_os_defaults_windows(struct getdns_context *context) free(info); } - (void)getdns_list_get_length(context->suffix, &length); if (length == 0 && *domain != 0) { bindata.data = (uint8_t *)domain; @@ -994,7 +992,7 @@ getdns_context_create_with_extended_memory_functions( result->fchg_resolvconf = NULL; result->fchg_hosts = NULL; - //g resolv.conf does not exist on Windows, handle differently + // resolv.conf does not exist on Windows, handle differently #ifndef USE_WINSOCK if (set_from_os && (r = set_os_defaults(result))) goto error; @@ -2358,18 +2356,24 @@ _getdns_context_prepare_for_resolution(struct getdns_context *context, /* Create client context, use TLS v1.2 only for now */ context->tls_ctx = SSL_CTX_new(TLSv1_2_client_method()); if (context->tls_ctx == NULL) - printf("ERROR! Bad TLS context!"); - //g return GETDNS_RETURN_BAD_CONTEXT; +#ifndef USE_WINSOCK + return GETDNS_RETURN_BAD_CONTEXT; +#else + printf("Warning! Bad TLS context, check openssl version on Windows!\n");; +#endif /* Be strict and only use the cipher suites recommended in RFC7525 Unless we later fallback to opportunistic. */ const char* const PREFERRED_CIPHERS = "EECDH+aRSA+AESGCM:EECDH+aECDSA+AESGCM:EDH+aRSA+AESGCM"; - if (!SSL_CTX_set_cipher_list(context->tls_ctx, PREFERRED_CIPHERS)) + if (!SSL_CTX_set_cipher_list(context->tls_ctx, PREFERRED_CIPHERS)) { return GETDNS_RETURN_BAD_CONTEXT; - if (!SSL_CTX_set_default_verify_paths(context->tls_ctx)) + } + if (!SSL_CTX_set_default_verify_paths(context->tls_ctx)) { return GETDNS_RETURN_BAD_CONTEXT; + } #else - if (tls_only_is_in_transports_list(context) == 1) + if (tls_only_is_in_transports_list(context) == 1) { return GETDNS_RETURN_BAD_CONTEXT; + } /* A null tls_ctx will make TLS fail and fallback to the other transports will kick-in.*/ #endif diff --git a/src/stub.c b/src/stub.c index 8072d5da..96265c87 100644 --- a/src/stub.c +++ b/src/stub.c @@ -50,6 +50,7 @@ #define EINPROGRESS 112 #define EWOULDBLOCK 140 typedef u_short sa_family_t; +#include "util/winsock_event.h" #endif #define STUB_OUT_OF_OPTIONS -5 /* upstream options exceeded MAXIMUM_UPSTREAM_OPTION_SPACE */ @@ -623,7 +624,7 @@ stub_tls_timeout_cb(void *userarg) /****************************/ static int -stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf) +stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf, getdns_eventloop_event* event) { ssize_t read; uint8_t *buf; @@ -640,10 +641,24 @@ stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf) } read = recv(fd, 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_READ); + return STUB_TCP_AGAIN; + } + +#else if (errno == EAGAIN || errno == EWOULDBLOCK) return STUB_TCP_AGAIN; else return STUB_TCP_ERROR; +#endif } else if (read == 0) { /* Remote end closed the socket */ /* TODO: Try to reconnect */ @@ -747,19 +762,19 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq) upstream). We must let the handshake complete since non-blocking. */ errno == EINPROGRESS)) || written < pkt_len + 2) { -#else - -#ifdef USE_WINSOCK - written = sendto(fd, 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)) || - written < pkt_len + 2) { +#else + +#ifdef USE_WINSOCK + written = sendto(fd, 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)) || + written < pkt_len + 2) { #endif /* We couldn't write the whole packet. * We have to return with STUB_TCP_AGAIN. @@ -1359,7 +1374,7 @@ stub_tcp_read_cb(void *userarg) int q; switch ((q = stub_tcp_read(netreq->fd, &netreq->tcp, - &dnsreq->context->mf))) { + &dnsreq->context->mf, &netreq->event))) { case STUB_TCP_AGAIN: return; @@ -1437,7 +1452,7 @@ upstream_read_cb(void *userarg) &upstream->upstreams->mf); else q = stub_tcp_read(upstream->fd, &upstream->tcp, - &upstream->upstreams->mf); + &upstream->upstreams->mf, &netreq->event); switch (q) { case STUB_TCP_AGAIN: diff --git a/src/util/winsock_event.c b/src/util/winsock_event.c index f29c9f32..9bb78cf9 100644 --- a/src/util/winsock_event.c +++ b/src/util/winsock_event.c @@ -36,10 +36,11 @@ * \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 +#ifdef USE_WINSOCK // only included for Windows builds #include #ifdef HAVE_TIME_H #include @@ -55,117 +56,118 @@ void log_err(const char *format, ...) { - va_list args; - va_start(args, format); - fprintf(stderr, "error", format, args); - va_end(args); + va_list args; + va_start(args, format); + fprintf(stderr, "error", format, args); + va_end(args); } + char* wsa_strerror(DWORD err) { - static char unknown[32]; + 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; - } + 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) @@ -184,7 +186,7 @@ int _getdns_mini_ev_cmp(const void* a, const void* b) return -1; if(e > f) return 1; - return 0; + return 0; } /** set time */ @@ -200,7 +202,7 @@ settime(struct _getdns_event_base* base) return 0; } -#ifdef UNBOUND_DEBUG +#ifdef WINSOCK_DEBUG /** * Find a fd in the list of items. * Note that not all items have a fd associated (those are -1). @@ -212,12 +214,12 @@ settime(struct _getdns_event_base* base) static int find_fd(struct _getdns_event_base* base, int fd) { - int i; - for(i=0; imax; i++) { - if(base->items[i]->ev_fd == fd) - return i; - } - return -1; + int i; + for(i=0; imax; i++) { + if(base->items[i]->ev_fd == fd) + return i; + } + return -1; } #endif @@ -225,61 +227,61 @@ find_fd(struct _getdns_event_base* base, int fd) static void zero_waitfor(WSAEVENT waitfor[], WSAEVENT x) { - int i; - for(i=0; itime_secs = time_secs; - base->time_tv = time_tv; - if(settime(base) < 0) { + 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->items = (struct _getdns_event**)calloc(WSK_MAX_ITEMS, - sizeof(struct _getdns_event*)); - if(!base->items) { - _getdns_event_base_free(base); + } + 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->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; - //verbose(VERB_CLIENT, "winsock_event inited"); - return base; + } + base->tcp_stickies = 0; + base->tcp_reinvigorated = 0; + + return base; } const char *_getdns_event_get_version(void) { - return "winsock-event-"PACKAGE_VERSION; + return "winsock-event-"PACKAGE_VERSION; } const char *_getdns_event_get_method(void) { - return "WSAWaitForMultipleEvents"; + return "WSAWaitForMultipleEvents"; } - -//gowri remove static + /** 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) @@ -288,352 +290,347 @@ void _getdns_handle_timeouts(struct _getdns_event_base* base, struct timeval* no #ifndef S_SPLINT_S wait->tv_sec = (time_t)-1; #endif - //verbose(VERB_CLIENT, "winsock_event handle_timeouts"); - while((_getdns_rbnode_t*)(p = (struct _getdns_event*)_getdns_rbtree_first(base->times)) + 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 || + 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; - } - //verbose(VERB_CLIENT, "winsock_event wait=" ARG_LL "d.%6.6d", - // (long long)wait->tv_sec, (int)wait->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); + /* 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; } - //verbose(VERB_CLIENT, "winsock_event wait=(-1)"); + 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; - } + 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); + /* 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, was_timeout = 0; - int newstickies = 0; - struct timeval nultm; + DWORD timeout = 0; /* in milliseconds */ + DWORD ret; + WSANETWORKEVENTS netev; + struct _getdns_event* eventlist[WSK_MAX_ITEMS]; + int i, numwait = 0, startidx = 0, was_timeout = 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 */ - } + if(wait->tv_sec==(time_t)-1) + wait = NULL; + if (wait) + // timeout = 10 + wait->tv_usec / 1000; + timeout = wait->tv_sec * 1000 + wait->tv_usec / 1000; + if(base->tcp_stickies) { + wait = &nultm; + nultm.tv_sec = 0; + nultm.tv_usec = 0; + timeout = 0; /* no waiting, we have sticky events */ + } #endif - /* prepare event array */ - for(i=0; imax; i++) { - if(base->items[i]->ev_fd == -1 && !base->items[i]->is_signal) - continue; /* skip timer only events */ - eventlist[numwait] = base->items[i]; - base->waitfor[numwait++] = base->items[i]->hEvent; - printf("winsock_event bmax=%d numwait=%d wait=%x " - "timeout=%d hEvent %d\n", base->max, numwait, (int)wait, (int)timeout, base->items[i]->hEvent); - if (numwait == WSK_MAX_ITEMS) - break; /* sanity check */ - } - //log_assert(numwait <= WSA_MAXIMUM_WAIT_EVENTS); + /* prepare event array */ + for(i=0; imax; i++) { + if(base->items[i]->ev_fd == -1 && !base->items[i]->is_signal) + continue; /* skip timer only events */ + eventlist[numwait] = base->items[i]; + base->waitfor[numwait++] = base->items[i]->hEvent; + printf("winsock_event bmax=%d numwait=%d wait=%x " + "timeout=%d hEvent %d\n", base->max, numwait, (int)wait, + (int)timeout, 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); - } - was_timeout = 1; - } - else { - //gv: do not schedule udp write - for (i = 0; imax; i++) { - if (!base->items[i]->is_tcp && base->items[i]->ev_events&EV_WRITE) { - //gprintf("skip UDP sched\n"); - (*eventlist[i]->ev_callback)(eventlist[i]->ev_fd, - EV_WRITE & eventlist[i]->ev_events, - eventlist[i]->ev_arg); - return 0; - } - } - //gprintf("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) */ - //gprintf("after wait %d %d\n", 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"); - was_timeout = 1; - } else - startidx = ret - WSA_WAIT_EVENT_0; - } - ////verbose(VERB_CLIENT, "winsock_event wake was_timeout=%d startidx=%d", - // was_timeout, startidx); + /* do the wait */ + if(numwait == 0) { + /* WSAWaitFor.. doesn't like 0 event objects */ + if(wait) { + Sleep(timeout); + } + was_timeout = 1; + } + else { + //gv: do not schedule udp write + for (i = 0; imax; i++) { + if (!base->items[i]->is_tcp && base->items[i]->ev_events&EV_WRITE) { + printf("skip UDP sched\n"); + (*eventlist[i]->ev_callback)(eventlist[i]->ev_fd, + EV_WRITE & eventlist[i]->ev_events, + eventlist[i]->ev_arg); + return 0; + } + } + printf("before wait %d\n", base->items[0]->ev_events); + ret = WSAWaitForMultipleEvents(numwait, base->waitfor, + 0 /* do not wait for all, just one will do */, + wait?timeout:WSA_INFINITE, + 0); /* we are not alertable (IO completion events) */ + printf("after wait %d %d\n", 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"); + was_timeout = 1; + } 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 */ + /* get new time after wait */ if(settime(base) < 0) return -1; - /* callbacks */ - if(base->tcp_stickies) - startidx = 0; /* process all events, some are sticky */ - for(i=startidx; ijust_checked = 1; + /* callbacks */ + if(base->tcp_stickies) + startidx = 0; /* process all events, some are sticky */ + for(i=startidx; ijust_checked = 1; - //verbose(VERB_CLIENT, "winsock_event signals"); - for(i=startidx; iwaitfor[i]) - continue; /* was deleted */ - if(eventlist[i]->is_signal) { - eventlist[i]->just_checked = 0; - _getdns_handle_signal(eventlist[i]); - } - } - /* early exit - do not process network, exit quickly */ - if(base->need_to_exit) - return 0; + //verbose(VERB_CLIENT, "winsock_event signals"); + for(i=startidx; iwaitfor[i]) + continue; /* was deleted */ + if(eventlist[i]->is_signal) { + eventlist[i]->just_checked = 0; + _getdns_handle_signal(eventlist[i]); + } + } + /* early exit - do not process network, exit quickly */ + if(base->need_to_exit) + return 0; - //verbose(VERB_CLIENT, "winsock_event net"); - for(i=startidx; iwaitfor[i]) - continue; /* was deleted */ - if(!eventlist[i]->just_checked) - continue; /* added by other callback */ - if(eventlist[i]->is_signal) - continue; /* not a network event at all */ - eventlist[i]->just_checked = 0; + //verbose(VERB_CLIENT, "winsock_event net"); + for(i=startidx; iwaitfor[i]) + continue; /* was deleted */ + if(!eventlist[i]->just_checked) + continue; /* added by other callback */ + if(eventlist[i]->is_signal) + continue; /* not a network event at all */ + eventlist[i]->just_checked = 0; - if(WSAEnumNetworkEvents(eventlist[i]->ev_fd, - base->waitfor[i], /* reset the event handle */ - /*NULL,*/ /* do not reset the event handle */ - &netev) != 0) { - log_err("getdns: WSAEnumNetworkEvents failed: %s", - wsa_strerror(WSAGetLastError())); - return -1; - } - if((netev.lNetworkEvents & FD_READ)) { - if(netev.iErrorCode[FD_READ_BIT] != 0) - printf("FD_READ_BIT error: %s\n", - wsa_strerror(netev.iErrorCode[FD_READ_BIT])); - bits |= EV_READ; - printf("FD_READ_BIT\n"); - } - if((netev.lNetworkEvents & FD_WRITE)) { - if(netev.iErrorCode[FD_WRITE_BIT] != 0) - printf("FD_WRITE_BIT error: %s\n", - wsa_strerror(netev.iErrorCode[FD_WRITE_BIT])); - bits |= EV_WRITE; - printf("FD_WRITE_BIT\n"); - } - if((netev.lNetworkEvents & FD_CONNECT)) { - if(netev.iErrorCode[FD_CONNECT_BIT] != 0) - printf("FD_CONNECT_BIT error: %s\n", - wsa_strerror(netev.iErrorCode[FD_CONNECT_BIT])); - bits |= EV_READ; - bits |= EV_WRITE; - printf("FD_CONNECT_BIT\n"); - } - if((netev.lNetworkEvents & FD_ACCEPT)) { - if(netev.iErrorCode[FD_ACCEPT_BIT] != 0) - printf("FD_ACCEPT_BIT error: %s\n", - wsa_strerror(netev.iErrorCode[FD_ACCEPT_BIT])); - bits |= EV_READ; - printf("FD_ACCEPT_BIT\n"); - } - if((netev.lNetworkEvents & FD_CLOSE)) { - if(netev.iErrorCode[FD_CLOSE_BIT] != 0) - printf("FD_CLOSE_BIT error: %s\n", - wsa_strerror(netev.iErrorCode[FD_CLOSE_BIT])); - //g bits |= EV_READ; - //g bits |= EV_WRITE; - printf("FD_CLOSE_BIT\n"); - } - if(eventlist[i]->is_tcp && eventlist[i]->stick_events) { - /* - printf("winsock %d pass sticky %s%s\n", - eventlist[i]->ev_fd, - (eventlist[i]->old_events&EV_READ)?"EV_READ":"", - (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); - */ - bits |= eventlist[i]->old_events; - } - if(eventlist[i]->is_tcp && bits) { - eventlist[i]->old_events = bits; - eventlist[i]->stick_events = 1; - if((eventlist[i]->ev_events & bits)) { - newstickies = 1; - } - /* - printf("winsock %d store sticky %s%s", - eventlist[i]->ev_fd, - (eventlist[i]->old_events&EV_READ)?"EV_READ":"", - (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); - */ - } - if((bits & eventlist[i]->ev_events)) { - printf( "winsock event callback %p fd=%d " - "%s%s%s%s%s ; %s%s%s\n", - eventlist[i], eventlist[i]->ev_fd, - (netev.lNetworkEvents&FD_READ)?" FD_READ":"", - (netev.lNetworkEvents&FD_WRITE)?" FD_WRITE":"", - (netev.lNetworkEvents&FD_CONNECT)? - " FD_CONNECT":"", - (netev.lNetworkEvents&FD_ACCEPT)? - " FD_ACCEPT":"", - (netev.lNetworkEvents&FD_CLOSE)?" FD_CLOSE":"", - (bits&EV_READ)?" EV_READ":"", - (bits&EV_WRITE)?" EV_WRITE":"", - (bits&EV_TIMEOUT)?" EV_TIMEOUT":""); - - fptr_ok(fptr_whitelist_event( - eventlist[i]->ev_callback)); - (*eventlist[i]->ev_callback)(eventlist[i]->ev_fd, - bits & eventlist[i]->ev_events, - eventlist[i]->ev_arg); - } - /* - if(eventlist[i]->is_tcp && bits) - printf( "winsock %d got sticky %s%s\n", - eventlist[i]->ev_fd, - (eventlist[i]->old_events&EV_READ)?"EV_READ":"", - (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); - */ - } - //verbose(VERB_CLIENT, "winsock_event net"); - if(base->tcp_reinvigorated) { - printf("winsock_event reinvigorated\n"); - base->tcp_reinvigorated = 0; - newstickies = 1; - } - base->tcp_stickies = newstickies; - //gprintf("winsock_event handle_select end\n"); - return 0; + 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); + 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; - /* do select */ - if(_getdns_handle_select(base, &wait) < 0) { - if(base->need_to_exit) - return 0; - return -1; - } + return 0; + return -1; } - return 0; + } + return 0; } int _getdns_event_base_loopexit(struct _getdns_event_base *base, - struct timeval * ATTR_UNUSED(tv)) + struct timeval * ATTR_UNUSED(tv)) { - //verbose(VERB_CLIENT, "winsock_event loopexit"); - base->need_to_exit = 1; - return 0; + base->need_to_exit = 1; + return 0; } void _getdns_event_base_free(struct _getdns_event_base *base) { - //verbose(VERB_CLIENT, "winsock_event event_base_free"); - if(!base) + if(!base) return; - if(base->items) - free(base->items); - if(base->times) - free(base->times); - if(base->signals) - free(base->signals); - free(base); + 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) + 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; + 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; + ev->ev_base = base; + ev->old_events = 0; + ev->stick_events = 0; + ev->added = 0; + return 0; } /** @@ -647,91 +644,92 @@ int _getdns_event_base_set(struct _getdns_event_base *base, struct _getdns_event static int find_fd(struct _getdns_event_base* base, int fd) { - int i; - for (i = 0; imax; i++) { - if (base->items[i]->ev_fd == fd) - return i; - } - return -1; + int i; + for (i = 0; imax; i++) { + if (base->items[i]->ev_fd == fd) + return i; + } + return -1; } 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":""); - + 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; + 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_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_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; - } + 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); + //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, events, ev->hEvent); - //gg if (WSAEventSelect(ev->ev_fd, ev->hEvent, FD_ACCEPT | FD_CONNECT | FD_READ | FD_CLOSE | FD_WRITE) != 0) { - //if (WSAEventSelect(ev->ev_fd, ev->hEvent,FD_READ | FD_WRITE) != 0) { - 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 */ - ev->ev_base->tcp_reinvigorated = 1; - } - } + 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, events, 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, events, 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, ev->hEvent); - 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; @@ -744,42 +742,42 @@ int _getdns_event_add(struct _getdns_event *ev, struct timeval *tv) (void)_getdns_rbtree_insert(ev->ev_base->times, &ev->node); } ev->added = 1; - return 0; + 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); + //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); + //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; + 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; } @@ -796,7 +794,7 @@ static RETSIGTYPE sigh(int sig) if(!ev) return; //g fptr_ok(fptr_whitelist_event(ev->ev_callback)); - //g (*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg); + //g (*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg); } int _getdns_signal_add(struct _getdns_event *ev, struct timeval * ATTR_UNUSED(tv)) @@ -823,47 +821,47 @@ int _getdns_signal_del(struct _getdns_event *ev) void winsock_tcp_wouldblock(struct _getdns_event* ev, int eventbits) { - //verbose(VERB_ALGO, "winsock: tcp wouldblock %s", - //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 - */ + 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) + 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; + 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; + 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 */ diff --git a/src/util/winsock_event.h b/src/util/winsock_event.h index 595116b2..6083cfc5 100644 --- a/src/util/winsock_event.h +++ b/src/util/winsock_event.h @@ -40,6 +40,7 @@ * 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. * @@ -133,92 +134,92 @@ */ 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]; + /** 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; + /* 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; + /** 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; + /** 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; + /** 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; + /* ----- 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; + /** 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); @@ -267,7 +268,7 @@ int getdns_mini_ev_cmp(const void* a, const void* b); * retesting the event. * Pass if EV_READ or EV_WRITE gave wouldblock. */ -static void winsock_tcp_wouldblock(struct _getdns_event* ev, int eventbit); +void winsock_tcp_wouldblock(struct _getdns_event* ev, int eventbit); /** * Routine for windows only. where you pass a signal WSAEvent that @@ -275,14 +276,14 @@ static void winsock_tcp_wouldblock(struct _getdns_event* ev, int eventbit); * 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. + * 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. */ static int winsock_register_wsaevent(struct _getdns_event_base* base, struct _getdns_event* ev, - WSAEVENT wsaevent, void (*cb)(int, short, void*), void* arg); + WSAEVENT wsaevent, void (*cb)(int, short, void*), void* arg); /** * Unregister a wsaevent. User has to close the WSAEVENT itself. From e582f0f23e1b6c0ae72f092d28165401d6e0b7d3 Mon Sep 17 00:00:00 2001 From: gmadkat Date: Fri, 4 Dec 2015 16:23:05 -0500 Subject: [PATCH 03/11] Update README.md --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ec28e45c..e69078ef 100644 --- a/README.md +++ b/README.md @@ -243,7 +243,16 @@ As of the 0.2.0 release, when installing via Homebrew, the trust anchor is expec ### Microsoft Windows 8.1 -The windows version of getdns currently only is supported in stub only mode. +Build tested using Mingw(3.21.0) and Msys 1.0 (http://www.mingw.org/) on Windows 8.1 + +Dependencies: +The following dependencies are built from source on Mingw +openssl1.0.2a +libexpat +ldns (dependency to be removed soon) +libidn + +The windows version of getdns currently only is supported in the stub only mode. To configure: ./configure --enable-use-winsock --enable-stub-only --with-trust-anchor="c:\\\MinGW\\\msys\\\1.0\\\etc\\\unbound\\\getdns-root.key" From 0d6d8116bcce4672afe520652ff00c332dc95b7c Mon Sep 17 00:00:00 2001 From: gmadkat Date: Fri, 4 Dec 2015 17:01:10 -0500 Subject: [PATCH 04/11] Update README.md --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e69078ef..8e2e64a7 100644 --- a/README.md +++ b/README.md @@ -243,6 +243,8 @@ As of the 0.2.0 release, when installing via Homebrew, the trust anchor is expec ### Microsoft Windows 8.1 +This section has some Windows specific build instructions. + Build tested using Mingw(3.21.0) and Msys 1.0 (http://www.mingw.org/) on Windows 8.1 Dependencies: @@ -263,7 +265,12 @@ To configure: After configuring, do a 'make' and 'make install' to build getdns for Windows. There is a sample, getdns_query.exe which can be built in src/samplewin using 'make' - + + Example test queries: + ./getdns_query.exe -s gmadkat.com A @64.6.64.6 +return_call_debugging (UDP) + ./getdns_query.exe -s gmadkat.com A @64.6.64.6 -T +return_call_debugging (TCP) + ./getdns_query.exe -s gmadkat.com A -l L @185.49.141.37 +return_call_debugging (TLS without authentication) + ./getdns_query.exe -s www.huque.com A +dnssec_return_status +return_call_debugging (DNSSEC) Contributors ============ From a2e15a169d4cb8df04fbe0b9ccdff13cb0789369 Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Thu, 17 Dec 2015 12:37:33 +0100 Subject: [PATCH 05/11] Revert syntactic/style changes So actual changes aren't obfuscated --- configure.ac | 2 -- src/context.c | 56 +++++++++++++++++++++++++-------------------------- src/stub.c | 54 ++++++++++++++++++++++++------------------------- 3 files changed, 54 insertions(+), 58 deletions(-) diff --git a/configure.ac b/configure.ac index a59974f8..9bc9c366 100644 --- a/configure.ac +++ b/configure.ac @@ -429,8 +429,6 @@ case "$enable_stub_only" in ;; esac - - # search to set include and library paths right # find libidn my_with_libidn=1 diff --git a/src/context.c b/src/context.c index 83ae9c82..b39bb002 100644 --- a/src/context.c +++ b/src/context.c @@ -1793,7 +1793,7 @@ getdns_context_set_dnssec_allowed_skew(struct getdns_context *context, */ getdns_return_t getdns_context_set_upstream_recursive_servers(struct getdns_context *context, -struct getdns_list *upstream_list) + struct getdns_list *upstream_list) { getdns_return_t r; size_t count = 0; @@ -1810,16 +1810,16 @@ struct getdns_list *upstream_list) return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; } memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ - hints.ai_socktype = 0; /* Datagram socket */ - hints.ai_flags = AI_NUMERICHOST; /* No reverse name lookups */ - hints.ai_protocol = 0; /* Any protocol */ + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_socktype = 0; /* Datagram socket */ + hints.ai_flags = AI_NUMERICHOST; /* No reverse name lookups */ + hints.ai_protocol = 0; /* Any protocol */ hints.ai_canonname = NULL; - hints.ai_addr = NULL; - hints.ai_next = NULL; + hints.ai_addr = NULL; + hints.ai_next = NULL; upstreams = upstreams_create( - context, count * GETDNS_UPSTREAM_TRANSPORTS); + context, count * GETDNS_UPSTREAM_TRANSPORTS); for (i = 0; i < count; i++) { getdns_dict *dict; getdns_bindata *address_type; @@ -1834,7 +1834,7 @@ struct getdns_list *upstream_list) goto error; if ((r = getdns_dict_get_bindata( - dict, "address_type", &address_type))) + dict, "address_type",&address_type))) goto error; if (address_type->size < 4) goto invalid_parameter; @@ -1845,24 +1845,24 @@ struct getdns_list *upstream_list) else goto invalid_parameter; if ((r = getdns_dict_get_bindata( - dict, "address_data", &address_data))) + dict, "address_data", &address_data))) goto error; if ((addr.ss_family == AF_INET && - address_data->size != 4) || - (addr.ss_family == AF_INET6 && - address_data->size != 16)) + address_data->size != 4) || + (addr.ss_family == AF_INET6 && + address_data->size != 16)) goto invalid_parameter; if (inet_ntop(addr.ss_family, address_data->data, - addrstr, 1024) == NULL) + addrstr, 1024) == NULL) goto invalid_parameter; if (getdns_dict_get_bindata(dict, "scope_id", &scope_id) == - GETDNS_RETURN_GOOD) { + GETDNS_RETURN_GOOD) { if (strlen(addrstr) + scope_id->size > 1022) goto invalid_parameter; eos = &addrstr[strlen(addrstr)]; *eos++ = '%'; - (void)memcpy(eos, scope_id->data, scope_id->size); + (void) memcpy(eos, scope_id->data, scope_id->size); eos[scope_id->size] = 0; } @@ -1875,10 +1875,10 @@ struct getdns_list *upstream_list) continue; if (getdns_upstream_transports[j] != GETDNS_TRANSPORT_TLS) - (void)getdns_dict_get_int(dict, "port", &port); + (void) getdns_dict_get_int(dict, "port", &port); else - (void)getdns_dict_get_int(dict, "tls_port", &port); - (void)snprintf(portstr, 1024, "%d", (int)port); + (void) getdns_dict_get_int(dict, "tls_port", &port); + (void) snprintf(portstr, 1024, "%d", (int)port); if (getaddrinfo(addrstr, portstr, &hints, &ai)) goto invalid_parameter; @@ -1894,12 +1894,12 @@ struct getdns_list *upstream_list) upstream_init(upstream, upstreams, ai); upstream->transport = getdns_upstream_transports[j]; if (getdns_upstream_transports[j] == GETDNS_TRANSPORT_TLS || - getdns_upstream_transports[j] == GETDNS_TRANSPORT_STARTTLS) { + getdns_upstream_transports[j] == GETDNS_TRANSPORT_STARTTLS) { if ((r = getdns_dict_get_bindata( dict, "tls_auth_name", &tls_auth_name)) == GETDNS_RETURN_GOOD) { /*TODO: VALIDATE THIS STRING!*/ memcpy(upstream->tls_auth_name, - (char *)tls_auth_name->data, + (char *)tls_auth_name->data, tls_auth_name->size); upstream->tls_auth_name[tls_auth_name->size] = '\0'; } @@ -1920,7 +1920,8 @@ invalid_parameter: error: _getdns_upstreams_dereference(upstreams); return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; -} +} /* getdns_context_set_upstream_recursive_servers */ + static void set_ub_edns_maximum_udp_payload_size(struct getdns_context* context, @@ -2355,7 +2356,7 @@ _getdns_context_prepare_for_resolution(struct getdns_context *context, #ifdef HAVE_TLS_v1_2 /* Create client context, use TLS v1.2 only for now */ context->tls_ctx = SSL_CTX_new(TLSv1_2_client_method()); - if (context->tls_ctx == NULL) + if(context->tls_ctx == NULL) #ifndef USE_WINSOCK return GETDNS_RETURN_BAD_CONTEXT; #else @@ -2364,16 +2365,13 @@ _getdns_context_prepare_for_resolution(struct getdns_context *context, /* Be strict and only use the cipher suites recommended in RFC7525 Unless we later fallback to opportunistic. */ const char* const PREFERRED_CIPHERS = "EECDH+aRSA+AESGCM:EECDH+aECDSA+AESGCM:EDH+aRSA+AESGCM"; - if (!SSL_CTX_set_cipher_list(context->tls_ctx, PREFERRED_CIPHERS)) { + if (!SSL_CTX_set_cipher_list(context->tls_ctx, PREFERRED_CIPHERS)) return GETDNS_RETURN_BAD_CONTEXT; - } - if (!SSL_CTX_set_default_verify_paths(context->tls_ctx)) { + if (!SSL_CTX_set_default_verify_paths(context->tls_ctx)) return GETDNS_RETURN_BAD_CONTEXT; - } #else - if (tls_only_is_in_transports_list(context) == 1) { + if (tls_only_is_in_transports_list(context) == 1) return GETDNS_RETURN_BAD_CONTEXT; - } /* A null tls_ctx will make TLS fail and fallback to the other transports will kick-in.*/ #endif diff --git a/src/stub.c b/src/stub.c index 96265c87..2e0ee664 100644 --- a/src/stub.c +++ b/src/stub.c @@ -641,18 +641,18 @@ stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf, getdns_eventl } read = recv(fd, 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_READ); - return STUB_TCP_AGAIN; - } - +#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_READ); + return STUB_TCP_AGAIN; + } + #else if (errno == EAGAIN || errno == EWOULDBLOCK) return STUB_TCP_AGAIN; @@ -762,19 +762,19 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq) upstream). We must let the handshake complete since non-blocking. */ errno == EINPROGRESS)) || written < pkt_len + 2) { -#else - -#ifdef USE_WINSOCK - written = sendto(fd, 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)) || - written < pkt_len + 2) { +#else + +#ifdef USE_WINSOCK + written = sendto(fd, 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)) || + written < pkt_len + 2) { #endif /* We couldn't write the whole packet. * We have to return with STUB_TCP_AGAIN. @@ -1374,7 +1374,7 @@ stub_tcp_read_cb(void *userarg) int q; switch ((q = stub_tcp_read(netreq->fd, &netreq->tcp, - &dnsreq->context->mf, &netreq->event))) { + &dnsreq->context->mf))) { case STUB_TCP_AGAIN: return; @@ -1452,7 +1452,7 @@ upstream_read_cb(void *userarg) &upstream->upstreams->mf); else q = stub_tcp_read(upstream->fd, &upstream->tcp, - &upstream->upstreams->mf, &netreq->event); + &upstream->upstreams->mf); switch (q) { case STUB_TCP_AGAIN: From b839b97ac2de28739575803505c6427792dce184 Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Thu, 17 Dec 2015 13:07:39 +0100 Subject: [PATCH 06/11] Oops... reverted syntax/style to agressively --- src/stub.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/stub.c b/src/stub.c index 2e0ee664..9d81df7d 100644 --- a/src/stub.c +++ b/src/stub.c @@ -624,7 +624,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, getdns_eventloop_event* qweroiuyqwer) { ssize_t read; uint8_t *buf; @@ -1374,7 +1374,7 @@ stub_tcp_read_cb(void *userarg) int q; switch ((q = stub_tcp_read(netreq->fd, &netreq->tcp, - &dnsreq->context->mf))) { + &dnsreq->context->mf, &netreq->event))) { case STUB_TCP_AGAIN: return; @@ -1452,7 +1452,7 @@ upstream_read_cb(void *userarg) &upstream->upstreams->mf); else q = stub_tcp_read(upstream->fd, &upstream->tcp, - &upstream->upstreams->mf); + &upstream->upstreams->mf, &netreq->event); switch (q) { case STUB_TCP_AGAIN: From d3d2dbc1d30bbbed9ec8af79780311216baec17c Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Thu, 17 Dec 2015 15:36:43 +0100 Subject: [PATCH 07/11] inet_ntop and inet_pton from compat --- configure.ac | 2 + src/compat/inet_ntop.c | 218 ++++++++++++++++++++++++++++++++++++++ src/compat/inet_pton.c | 230 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 450 insertions(+) create mode 100644 src/compat/inet_ntop.c create mode 100644 src/compat/inet_pton.c diff --git a/configure.ac b/configure.ac index 9bc9c366..59ce2736 100644 --- a/configure.ac +++ b/configure.ac @@ -947,6 +947,8 @@ if test $ac_cv_c_unused_attribute = yes; then AC_DEFINE(HAVE_ATTR_UNUSED, 1, [Whether the C compiler accepts the "unused" attribute]) fi AC_CHECK_DECLS([strlcpy,arc4random,arc4random_uniform]) +AC_REPLACE_FUNCS(inet_pton) +AC_REPLACE_FUNCS(inet_ntop) AC_REPLACE_FUNCS(strlcpy) AC_REPLACE_FUNCS(arc4random) AC_REPLACE_FUNCS(arc4random_uniform) diff --git a/src/compat/inet_ntop.c b/src/compat/inet_ntop.c new file mode 100644 index 00000000..bd418ae7 --- /dev/null +++ b/src/compat/inet_ntop.c @@ -0,0 +1,218 @@ +/* From openssh 4.3p2 compat/inet_ntop.c */ +/* Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* OPENBSD ORIGINAL: lib/libc/net/inet_ntop.c */ + +#include + +#ifndef HAVE_INET_NTOP + +#include +#include +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#include +#include +#include + +#ifndef IN6ADDRSZ +#define IN6ADDRSZ 16 /* IPv6 T_AAAA */ +#endif + +#ifndef INT16SZ +#define INT16SZ 2 /* for systems without 16-bit ints */ +#endif + +/* + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. + */ + +static const char *inet_ntop4(const u_char *src, char *dst, size_t size); +static const char *inet_ntop6(const u_char *src, char *dst, size_t size); + +/* char * + * inet_ntop(af, src, dst, size) + * convert a network format address to presentation format. + * return: + * pointer to presentation format address (`dst'), or NULL (see errno). + * author: + * Paul Vixie, 1996. + */ +const char * +inet_ntop(int af, const void *src, char *dst, size_t size) +{ + switch (af) { + case AF_INET: + return (inet_ntop4(src, dst, size)); + case AF_INET6: + return (inet_ntop6(src, dst, size)); + default: +#ifdef EAFNOSUPPORT + errno = EAFNOSUPPORT; +#else + errno = ENOSYS; +#endif + return (NULL); + } + /* NOTREACHED */ +} + +/* const char * + * inet_ntop4(src, dst, size) + * format an IPv4 address, more or less like inet_ntoa() + * return: + * `dst' (as a const) + * notes: + * (1) uses no statics + * (2) takes a u_char* not an in_addr as input + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop4(const u_char *src, char *dst, size_t size) +{ + static const char fmt[] = "%u.%u.%u.%u"; + char tmp[sizeof "255.255.255.255"]; + int l; + + l = snprintf(tmp, size, fmt, src[0], src[1], src[2], src[3]); + if (l <= 0 || l >= (int)size) { + errno = ENOSPC; + return (NULL); + } + strlcpy(dst, tmp, size); + return (dst); +} + +/* const char * + * inet_ntop6(src, dst, size) + * convert IPv6 binary address into presentation (printable) format + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop6(const u_char *src, char *dst, size_t size) +{ + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"]; + char *tp, *ep; + struct { int base, len; } best, cur; + u_int words[IN6ADDRSZ / INT16SZ]; + int i; + int advance; + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, '\0', sizeof words); + for (i = 0; i < IN6ADDRSZ; i++) + words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); + best.base = -1; + best.len = 0; + cur.base = -1; + cur.len = 0; + for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { + if (words[i] == 0) { + if (cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } else { + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + } + if (best.base != -1 && best.len < 2) + best.base = -1; + + /* + * Format the result. + */ + tp = tmp; + ep = tmp + sizeof(tmp); + for (i = 0; i < (IN6ADDRSZ / INT16SZ) && tp < ep; i++) { + /* Are we inside the best run of 0x00's? */ + if (best.base != -1 && i >= best.base && + i < (best.base + best.len)) { + if (i == best.base) { + if (tp + 1 >= ep) + return (NULL); + *tp++ = ':'; + } + continue; + } + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) { + if (tp + 1 >= ep) + return (NULL); + *tp++ = ':'; + } + /* Is this address an encapsulated IPv4? */ + if (i == 6 && best.base == 0 && + (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { + if (!inet_ntop4(src+12, tp, (size_t)(ep - tp))) + return (NULL); + tp += strlen(tp); + break; + } + advance = snprintf(tp, ep - tp, "%x", words[i]); + if (advance <= 0 || advance >= ep - tp) + return (NULL); + tp += advance; + } + /* Was it a trailing run of 0x00's? */ + if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) { + if (tp + 1 >= ep) + return (NULL); + *tp++ = ':'; + } + if (tp + 1 >= ep) + return (NULL); + *tp++ = '\0'; + + /* + * Check for overflow, copy, and we're done. + */ + if ((size_t)(tp - tmp) > size) { + errno = ENOSPC; + return (NULL); + } + strlcpy(dst, tmp, size); + return (dst); +} + +#endif /* !HAVE_INET_NTOP */ diff --git a/src/compat/inet_pton.c b/src/compat/inet_pton.c new file mode 100644 index 00000000..15780d0b --- /dev/null +++ b/src/compat/inet_pton.c @@ -0,0 +1,230 @@ +/* $KAME: inet_pton.c,v 1.5 2001/08/20 02:32:40 itojun Exp $ */ + +/* Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#include + +#include +#include +#include + +/* + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. + */ + +static int inet_pton4 (const char *src, uint8_t *dst); +static int inet_pton6 (const char *src, uint8_t *dst); + +/* + * + * The definitions we might miss. + * + */ +#ifndef NS_INT16SZ +#define NS_INT16SZ 2 +#endif + +#ifndef NS_IN6ADDRSZ +#define NS_IN6ADDRSZ 16 +#endif + +#ifndef NS_INADDRSZ +#define NS_INADDRSZ 4 +#endif + +/* int + * inet_pton(af, src, dst) + * convert from presentation format (which usually means ASCII printable) + * to network format (which is usually some kind of binary format). + * return: + * 1 if the address was valid for the specified address family + * 0 if the address wasn't valid (`dst' is untouched in this case) + * -1 if some other error occurred (`dst' is untouched in this case, too) + * author: + * Paul Vixie, 1996. + */ +int +inet_pton(af, src, dst) + int af; + const char *src; + void *dst; +{ + switch (af) { + case AF_INET: + return (inet_pton4(src, dst)); + case AF_INET6: + return (inet_pton6(src, dst)); + default: +#ifdef EAFNOSUPPORT + errno = EAFNOSUPPORT; +#else + errno = ENOSYS; +#endif + return (-1); + } + /* NOTREACHED */ +} + +/* int + * inet_pton4(src, dst) + * like inet_aton() but without all the hexadecimal and shorthand. + * return: + * 1 if `src' is a valid dotted quad, else 0. + * notice: + * does not touch `dst' unless it's returning 1. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton4(src, dst) + const char *src; + uint8_t *dst; +{ + static const char digits[] = "0123456789"; + int saw_digit, octets, ch; + uint8_t tmp[NS_INADDRSZ], *tp; + + saw_digit = 0; + octets = 0; + *(tp = tmp) = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr(digits, ch)) != NULL) { + uint32_t new = *tp * 10 + (pch - digits); + + if (new > 255) + return (0); + *tp = new; + if (! saw_digit) { + if (++octets > 4) + return (0); + saw_digit = 1; + } + } else if (ch == '.' && saw_digit) { + if (octets == 4) + return (0); + *++tp = 0; + saw_digit = 0; + } else + return (0); + } + if (octets < 4) + return (0); + + memcpy(dst, tmp, NS_INADDRSZ); + return (1); +} + +/* int + * inet_pton6(src, dst) + * convert presentation level address to network order binary form. + * return: + * 1 if `src' is a valid [RFC1884 2.2] address, else 0. + * notice: + * (1) does not touch `dst' unless it's returning 1. + * (2) :: in a full address is silently ignored. + * credit: + * inspired by Mark Andrews. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton6(src, dst) + const char *src; + uint8_t *dst; +{ + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + uint8_t tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, saw_xdigit; + uint32_t val; + + memset((tp = tmp), '\0', NS_IN6ADDRSZ); + endp = tp + NS_IN6ADDRSZ; + colonp = NULL; + /* Leading :: requires some special handling. */ + if (*src == ':') + if (*++src != ':') + return (0); + curtok = src; + saw_xdigit = 0; + val = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) + pch = strchr((xdigits = xdigits_u), ch); + if (pch != NULL) { + val <<= 4; + val |= (pch - xdigits); + if (val > 0xffff) + return (0); + saw_xdigit = 1; + continue; + } + if (ch == ':') { + curtok = src; + if (!saw_xdigit) { + if (colonp) + return (0); + colonp = tp; + continue; + } + if (tp + NS_INT16SZ > endp) + return (0); + *tp++ = (uint8_t) (val >> 8) & 0xff; + *tp++ = (uint8_t) val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && + inet_pton4(curtok, tp) > 0) { + tp += NS_INADDRSZ; + saw_xdigit = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + return (0); + } + if (saw_xdigit) { + if (tp + NS_INT16SZ > endp) + return (0); + *tp++ = (uint8_t) (val >> 8) & 0xff; + *tp++ = (uint8_t) val & 0xff; + } + if (colonp != NULL) { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = tp - colonp; + int i; + + for (i = 1; i <= n; i++) { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) + return (0); + memcpy(dst, tmp, NS_IN6ADDRSZ); + return (1); +} From 5a65d2b6938a7dd7238133e0c95e13ae6d64bb1b Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Thu, 17 Dec 2015 15:46:31 +0100 Subject: [PATCH 08/11] Look further then you nose Willem! --- src/stub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stub.c b/src/stub.c index 9d81df7d..4191fe41 100644 --- a/src/stub.c +++ b/src/stub.c @@ -624,7 +624,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* qweroiuyqwer) +stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf, getdns_eventloop_event* event) { ssize_t read; uint8_t *buf; From 8da3775e22c9e95e5846d24c4f73abf6abc1e8e5 Mon Sep 17 00:00:00 2001 From: gmadkat Date: Thu, 17 Dec 2015 21:13:40 -0500 Subject: [PATCH 09/11] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 8e2e64a7..8b6143dd 100644 --- a/README.md +++ b/README.md @@ -250,8 +250,6 @@ Build tested using Mingw(3.21.0) and Msys 1.0 (http://www.mingw.org/) on Windows Dependencies: The following dependencies are built from source on Mingw openssl1.0.2a -libexpat -ldns (dependency to be removed soon) libidn The windows version of getdns currently only is supported in the stub only mode. From 7c766e528467b7c6ce5812a428f5778d00980162 Mon Sep 17 00:00:00 2001 From: gmadkat Date: Fri, 18 Dec 2015 10:40:12 -0500 Subject: [PATCH 10/11] Update configure.ac --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 59ce2736..333ecff2 100644 --- a/configure.ac +++ b/configure.ac @@ -434,7 +434,7 @@ esac my_with_libidn=1 AC_MSG_NOTICE([Checking if building on Windows]) -AC_ARG_ENABLE(use-winsock, AC_HELP_STRING([--enable-use-winsock], [Enable building on Microsoft Windows using mingw])) +AC_ARG_ENABLE(use-winsock, AC_HELP_STRING([--enable-use-winsock], [Enable building for Microsoft Windows using mingw])) case "$enable_use_winsock" in yes) AC_MSG_NOTICE([ Building on Windows ... YES! ]) From 9d3905459e23bca666e0dec0aa3390f05e38950c Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Thu, 24 Dec 2015 14:41:50 +0100 Subject: [PATCH 11/11] Miscellaneous fixes to compile on windows Also without warnings. --- Makefile.in | 1 + README.md | 12 +- configure.ac | 102 +-- m4/acx_getaddrinfo.m4 | 81 ++ src/context.c | 170 ++-- src/general.c | 82 +- src/samplewin/Makefile.in | 150 ---- src/samplewin/getdns_query.c | 1524 ---------------------------------- src/stub.c | 18 +- src/test/getdns_query.c | 12 +- src/util/winsock_event.c | 42 +- src/util/winsock_event.h | 26 +- 12 files changed, 301 insertions(+), 1919 deletions(-) create mode 100644 m4/acx_getaddrinfo.m4 delete mode 100644 src/samplewin/Makefile.in delete mode 100644 src/samplewin/getdns_query.c diff --git a/Makefile.in b/Makefile.in index 5f10efca..9e7fb66a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -193,6 +193,7 @@ $(distdir): cp $(srcdir)/install-sh $(distdir) cp $(srcdir)/config.sub $(distdir) cp $(srcdir)/config.guess $(distdir) + cp $(srcdir)/getdns.pc.in $(distdir) cp libtool $(distdir) cp $(srcdir)/ltmain.sh $(distdir) cp $(srcdir)/m4/*.m4 $(distdir)/m4 diff --git a/README.md b/README.md index 8b6143dd..5b9cabd0 100644 --- a/README.md +++ b/README.md @@ -255,20 +255,18 @@ libidn The windows version of getdns currently only is supported in the stub only mode. To configure: - ./configure --enable-use-winsock --enable-stub-only --with-trust-anchor="c:\\\MinGW\\\msys\\\1.0\\\etc\\\unbound\\\getdns-root.key" + ./configure --enable-stub-only --with-trust-anchor="c:\\\MinGW\\\msys\\\1.0\\\etc\\\unbound\\\getdns-root.key" --with-ssl=/c/OpenSSL --with-getdns_query The trust anchor is also installed by unbound on c:\program Files (X86)\unbound\root.key and can be referenced from there or anywhere else that the user chooses to configure it. After configuring, do a 'make' and 'make install' to build getdns for Windows. - There is a sample, getdns_query.exe which can be built in src/samplewin using 'make' - Example test queries: - ./getdns_query.exe -s gmadkat.com A @64.6.64.6 +return_call_debugging (UDP) - ./getdns_query.exe -s gmadkat.com A @64.6.64.6 -T +return_call_debugging (TCP) - ./getdns_query.exe -s gmadkat.com A -l L @185.49.141.37 +return_call_debugging (TLS without authentication) - ./getdns_query.exe -s www.huque.com A +dnssec_return_status +return_call_debugging (DNSSEC) + ./getdns_query.exe -s gmadkat.com A @64.6.64.6 +return_call_reporting (UDP) + ./getdns_query.exe -s gmadkat.com A @64.6.64.6 -T +return_call_reporting (TCP) + ./getdns_query.exe -s gmadkat.com A -l L @185.49.141.37 +return_call_reporting (TLS without authentication) + ./getdns_query.exe -s www.huque.com A +dnssec_return_status +return_call_reporting (DNSSEC) Contributors ============ diff --git a/configure.ac b/configure.ac index 43696eac..417c3361 100644 --- a/configure.ac +++ b/configure.ac @@ -32,6 +32,7 @@ AC_PREREQ([2.56]) AC_CONFIG_MACRO_DIRS([m4]) sinclude(./m4/acx_openssl.m4) +sinclude(./m4/acx_getaddrinfo.m4) sinclude(./m4/ax_check_compile_flag.m4) sinclude(./m4/pkg.m4) @@ -444,56 +445,53 @@ case "$enable_stub_only" in esac # search to set include and library paths right -# find libidn -my_with_libidn=1 - -AC_MSG_NOTICE([Checking if building on Windows]) -AC_ARG_ENABLE(use-winsock, AC_HELP_STRING([--enable-use-winsock], [Enable building for Microsoft Windows using mingw])) -case "$enable_use_winsock" in - yes) - AC_MSG_NOTICE([ Building on Windows ... YES! ]) - AC_DEFINE_UNQUOTED([USE_WINSOCK], [1], [Define this to enable Windows build.]) - AC_DEFINE_UNQUOTED([GETDNS_ON_WINDOWS], [1], [Define this to enable Windows build.]) - AC_DEFINE_UNQUOTED([HAVE_WINSOCK2_H], [1], [Define this to enable Windows build.]) - AC_DEFINE_UNQUOTED([HAVE_WS2TCPIP_H], [1], [Define this to enable Windows build.]) - AC_DEFINE_UNQUOTED([STUB_NATIVE_DNSSEC], [1], [Define this to enable Windows build.]) - my_with_libunbound=0 - my_with_libidn=0 - ;; - no|*) - AC_MSG_NOTICE([ Building on Windows ... YES! ]) - ;; -esac - -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 +# 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 - if test x_$withval != x_no; then - CFLAGS="$CFLAGS -I$withval/include" - LDFLAGS="$LDFLAGS -L$withval/lib" + 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]) + fi else - my_with_libidn=0 + if test x_$withval != x_no; then + CFLAGS="$CFLAGS -I$withval/include" + LDFLAGS="$LDFLAGS -L$withval/lib" + else + my_with_libidn=0 + fi fi fi @@ -1105,6 +1103,14 @@ void SHA512_Final(uint8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*); unsigned char *SHA512(void* data, unsigned int data_len, unsigned char *digest); #endif /* COMPAT_SHA512 */ +#ifndef HAVE_INET_PTON +int inet_pton(int af, const char* src, void* dst); +#endif /* HAVE_INET_PTON */ + +#ifndef HAVE_INET_NTOP +const char *inet_ntop(int af, const void *src, char *dst, size_t size); +#endif + #ifdef __cplusplus } #endif diff --git a/m4/acx_getaddrinfo.m4 b/m4/acx_getaddrinfo.m4 new file mode 100644 index 00000000..e88e1ddd --- /dev/null +++ b/m4/acx_getaddrinfo.m4 @@ -0,0 +1,81 @@ +# Taken from acx_nlnetlabs.m4 - common macros for configure checks +# Copyright 2009, Wouter Wijngaards, NLnet Labs. +# BSD licensed. +# + +dnl Check getaddrinfo. +dnl Works on linux, solaris, bsd and windows(links winsock). +dnl defines HAVE_GETADDRINFO, USE_WINSOCK. +AC_DEFUN([ACX_CHECK_GETADDRINFO_WITH_INCLUDES], +[AC_REQUIRE([AC_PROG_CC]) +AC_MSG_CHECKING(for getaddrinfo) +ac_cv_func_getaddrinfo=no +AC_LINK_IFELSE( +[AC_LANG_SOURCE([[ +#ifdef __cplusplus +extern "C" +{ +#endif +char* getaddrinfo(); +char* (*f) () = getaddrinfo; +#ifdef __cplusplus +} +#endif +int main() { + ; + return 0; +} +]])], +dnl this case on linux, solaris, bsd +[ac_cv_func_getaddrinfo="yes" +dnl see if on windows +if test "$ac_cv_header_windows_h" = "yes"; then + AC_DEFINE(USE_WINSOCK, 1, [Whether the windows socket API is used]) + USE_WINSOCK="1" + LIBS="$LIBS -lws2_32" +fi +], +dnl no quick getaddrinfo, try mingw32 and winsock2 library. +ORIGLIBS="$LIBS" +LIBS="$LIBS -lws2_32" +AC_LINK_IFELSE( +[AC_LANG_PROGRAM( +[ +#define _WIN32_WINNT 0x0501 +#ifdef HAVE_WINDOWS_H +#include +#endif +#ifdef HAVE_WINSOCK_H +#include +#endif +#ifdef HAVE_WINSOCK2_H +#include +#endif +#include +#ifdef HAVE_WS2TCPIP_H +#include +#endif +], +[ + (void)getaddrinfo(NULL, NULL, NULL, NULL); +] +)], +[ +ac_cv_func_getaddrinfo="yes" +dnl already: LIBS="$LIBS -lws2_32" +AC_DEFINE(USE_WINSOCK, 1, [Whether the windows socket API is used]) +USE_WINSOCK="1" +], +[ +ac_cv_func_getaddrinfo="no" +LIBS="$ORIGLIBS" +]) +) + +AC_MSG_RESULT($ac_cv_func_getaddrinfo) +if test $ac_cv_func_getaddrinfo = yes; then + AC_DEFINE(HAVE_GETADDRINFO, 1, [Whether getaddrinfo is available]) +fi +])dnl Endof AC_CHECK_GETADDRINFO_WITH_INCLUDES + +dnl End of file diff --git a/src/context.c b/src/context.c index 85af776d..89858323 100644 --- a/src/context.c +++ b/src/context.c @@ -106,7 +106,6 @@ getdns_port_str_array[] = { /* Private functions */ static getdns_return_t create_default_namespaces(struct getdns_context *context); static getdns_return_t create_default_dns_transports(struct getdns_context *context); -static getdns_return_t set_os_defaults(struct getdns_context *); static int transaction_id_cmp(const void *, const void *); static void dispatch_updated(struct getdns_context *, uint16_t); static void cancel_dns_req(getdns_dns_req *); @@ -705,6 +704,89 @@ upstream_init(getdns_upstream *upstream, net_req_query_id_cmp); } +#ifdef USE_WINSOCK +static getdns_return_t +set_os_defaults_windows(struct getdns_context *context) +{ + char domain[1024]; + size_t upstreams_limit = 10, length; + struct getdns_bindata bindata; + struct addrinfo hints; + struct addrinfo *result; + getdns_upstream *upstream; + int s; + + if (context->fchg_resolvconf == NULL) { + context->fchg_resolvconf = + GETDNS_MALLOC(context->my_mf, struct filechg); + if (context->fchg_resolvconf == NULL) + return GETDNS_RETURN_MEMORY_ERROR; + context->fchg_resolvconf->fn = "InvalidOnWindows"; + context->fchg_resolvconf->prevstat = NULL; + context->fchg_resolvconf->changes = GETDNS_FCHG_NOCHANGES; + context->fchg_resolvconf->errors = GETDNS_FCHG_NOERROR; + } + _getdns_filechg_check(context, context->fchg_resolvconf); + + context->suffix = getdns_list_create_with_context(context); + context->upstreams = upstreams_create(context, upstreams_limit); + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_socktype = 0; /* Datagram socket */ + hints.ai_flags = AI_NUMERICHOST; /* No reverse name lookups */ + hints.ai_protocol = 0; /* Any protocol */ + hints.ai_canonname = NULL; + hints.ai_addr = NULL; + hints.ai_next = NULL; + + FIXED_INFO *info; + ULONG buflen = sizeof(*info); + IP_ADDR_STRING *ptr = 0; + + info = (FIXED_INFO *)malloc(sizeof(FIXED_INFO)); + if (info == NULL) + return GETDNS_RETURN_GENERIC_ERROR; + + if (GetNetworkParams(info, &buflen) == ERROR_BUFFER_OVERFLOW) { + free(info); + info = (FIXED_INFO *)malloc(buflen); + if (info == NULL) + return GETDNS_RETURN_GENERIC_ERROR; + } + + if (GetNetworkParams(info, &buflen) == NO_ERROR) { + ptr = info->DnsServerList.Next; + *domain = 0; + while (ptr) { + for (size_t i = 0; i < GETDNS_UPSTREAM_TRANSPORTS; i++) { + char *port_str = getdns_port_str_array[i]; + if ((s = getaddrinfo(ptr->IpAddress.String, port_str, &hints, &result))) + continue; + if (!result) + continue; + + upstream = &context->upstreams-> + upstreams[context->upstreams->count++]; + upstream_init(upstream, context->upstreams, result); + upstream->transport = getdns_upstream_transports[i]; + freeaddrinfo(result); + } + ptr = ptr->Next; + + } + free(info); + } + + (void)getdns_list_get_length(context->suffix, &length); + if (length == 0 && *domain != 0) { + bindata.data = (uint8_t *)domain; + bindata.size = strlen(domain) + 1; + (void)getdns_list_set_bindata(context->suffix, 0, &bindata); + } + return GETDNS_RETURN_GOOD; +} /* set_os_defaults_windows */ +#else static getdns_return_t set_os_defaults(struct getdns_context *context) { @@ -816,92 +898,6 @@ set_os_defaults(struct getdns_context *context) _getdns_list_append_string(context->suffix, domain); return GETDNS_RETURN_GOOD; } /* set_os_defaults */ - -#ifdef USE_WINSOCK -static getdns_return_t -set_os_defaults_windows(struct getdns_context *context) -{ - FILE *in; - char line[1024], domain[1024]; - char *parse, *token, prev_ch; - size_t upstreams_limit = 10, length; - struct getdns_bindata bindata; - struct addrinfo hints; - struct addrinfo *result; - getdns_upstream *upstream; - int s; - - if (context->fchg_resolvconf == NULL) { - context->fchg_resolvconf = - GETDNS_MALLOC(context->my_mf, struct filechg); - if (context->fchg_resolvconf == NULL) - return GETDNS_RETURN_MEMORY_ERROR; - context->fchg_resolvconf->fn = "InvalidOnWindows"; - context->fchg_resolvconf->prevstat = NULL; - context->fchg_resolvconf->changes = GETDNS_FCHG_NOCHANGES; - context->fchg_resolvconf->errors = GETDNS_FCHG_NOERROR; - } - _getdns_filechg_check(context, context->fchg_resolvconf); - - context->suffix = getdns_list_create_with_context(context); - context->upstreams = upstreams_create(context, upstreams_limit); - - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ - hints.ai_socktype = 0; /* Datagram socket */ - hints.ai_flags = AI_NUMERICHOST; /* No reverse name lookups */ - hints.ai_protocol = 0; /* Any protocol */ - hints.ai_canonname = NULL; - hints.ai_addr = NULL; - hints.ai_next = NULL; - - FIXED_INFO *info; - ULONG buflen = sizeof(*info); - IP_ADDR_STRING *ptr = 0; - - info = (FIXED_INFO *)malloc(sizeof(FIXED_INFO)); - if (info == NULL) - return GETDNS_RETURN_GENERIC_ERROR; - - if (GetNetworkParams(info, &buflen) == ERROR_BUFFER_OVERFLOW) { - free(info); - info = (FIXED_INFO *)malloc(buflen); - if (info == NULL) - return GETDNS_RETURN_GENERIC_ERROR; - } - - if (GetNetworkParams(info, &buflen) == NO_ERROR) { - int retval = 0; - ptr = info->DnsServerList.Next; - *domain = 0; - while (ptr) { - for (size_t i = 0; i < GETDNS_UPSTREAM_TRANSPORTS; i++) { - char *port_str = getdns_port_str_array[i]; - if ((s = getaddrinfo(ptr->IpAddress.String, port_str, &hints, &result))) - continue; - if (!result) - continue; - - upstream = &context->upstreams-> - upstreams[context->upstreams->count++]; - upstream_init(upstream, context->upstreams, result); - upstream->transport = getdns_upstream_transports[i]; - freeaddrinfo(result); - } - ptr = ptr->Next; - - } - free(info); - } - - (void)getdns_list_get_length(context->suffix, &length); - if (length == 0 && *domain != 0) { - bindata.data = (uint8_t *)domain; - bindata.size = strlen(domain) + 1; - (void)getdns_list_set_bindata(context->suffix, 0, &bindata); - } - return GETDNS_RETURN_GOOD; -} /* set_os_defaults_windows */ #endif /* compare of transaction ids in DESCENDING order diff --git a/src/general.c b/src/general.c index c73a2e9e..9ac63f46 100644 --- a/src/general.c +++ b/src/general.c @@ -346,50 +346,50 @@ _getdns_hostname_loop(getdns_context *context, getdns_eventloop *loop, switch (address_data->size) { case 4: (void)snprintf(name, sizeof(name), - "%hhu.%hhu.%hhu.%hhu.in-addr.arpa.", - ((uint8_t *)address_data->data)[3], - ((uint8_t *)address_data->data)[2], - ((uint8_t *)address_data->data)[1], - ((uint8_t *)address_data->data)[0]); + "%d.%d.%d.%d.in-addr.arpa.", + (int)((uint8_t *)address_data->data)[3], + (int)((uint8_t *)address_data->data)[2], + (int)((uint8_t *)address_data->data)[1], + (int)((uint8_t *)address_data->data)[0]); break; case 16: (void)snprintf(name, sizeof(name), - "%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx." - "%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx." - "%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx." - "%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.ip6.arpa.", - (uint8_t)(((uint8_t *)address_data->data)[15] & 0x0F), - (uint8_t)(((uint8_t *)address_data->data)[15] >> 4), - (uint8_t)(((uint8_t *)address_data->data)[14] & 0x0F), - (uint8_t)(((uint8_t *)address_data->data)[14] >> 4), - (uint8_t)(((uint8_t *)address_data->data)[13] & 0x0F), - (uint8_t)(((uint8_t *)address_data->data)[13] >> 4), - (uint8_t)(((uint8_t *)address_data->data)[12] & 0x0F), - (uint8_t)(((uint8_t *)address_data->data)[12] >> 4), - (uint8_t)(((uint8_t *)address_data->data)[11] & 0x0F), - (uint8_t)(((uint8_t *)address_data->data)[11] >> 4), - (uint8_t)(((uint8_t *)address_data->data)[10] & 0x0F), - (uint8_t)(((uint8_t *)address_data->data)[10] >> 4), - (uint8_t)(((uint8_t *)address_data->data)[9] & 0x0F), - (uint8_t)(((uint8_t *)address_data->data)[9] >> 4), - (uint8_t)(((uint8_t *)address_data->data)[8] & 0x0F), - (uint8_t)(((uint8_t *)address_data->data)[8] >> 4), - (uint8_t)(((uint8_t *)address_data->data)[7] & 0x0F), - (uint8_t)(((uint8_t *)address_data->data)[7] >> 4), - (uint8_t)(((uint8_t *)address_data->data)[6] & 0x0F), - (uint8_t)(((uint8_t *)address_data->data)[6] >> 4), - (uint8_t)(((uint8_t *)address_data->data)[5] & 0x0F), - (uint8_t)(((uint8_t *)address_data->data)[5] >> 4), - (uint8_t)(((uint8_t *)address_data->data)[4] & 0x0F), - (uint8_t)(((uint8_t *)address_data->data)[4] >> 4), - (uint8_t)(((uint8_t *)address_data->data)[3] & 0x0F), - (uint8_t)(((uint8_t *)address_data->data)[3] >> 4), - (uint8_t)(((uint8_t *)address_data->data)[2] & 0x0F), - (uint8_t)(((uint8_t *)address_data->data)[2] >> 4), - (uint8_t)(((uint8_t *)address_data->data)[1] & 0x0F), - (uint8_t)(((uint8_t *)address_data->data)[1] >> 4), - (uint8_t)(((uint8_t *)address_data->data)[0] & 0x0F), - (uint8_t)(((uint8_t *)address_data->data)[0] >> 4)); + "%x.%x.%x.%x.%x.%x.%x.%x." + "%x.%x.%x.%x.%x.%x.%x.%x." + "%x.%x.%x.%x.%x.%x.%x.%x." + "%x.%x.%x.%x.%x.%x.%x.%x.ip6.arpa.", + (int)(((uint8_t *)address_data->data)[15] & 0x0F), + (int)(((uint8_t *)address_data->data)[15] >> 4), + (int)(((uint8_t *)address_data->data)[14] & 0x0F), + (int)(((uint8_t *)address_data->data)[14] >> 4), + (int)(((uint8_t *)address_data->data)[13] & 0x0F), + (int)(((uint8_t *)address_data->data)[13] >> 4), + (int)(((uint8_t *)address_data->data)[12] & 0x0F), + (int)(((uint8_t *)address_data->data)[12] >> 4), + (int)(((uint8_t *)address_data->data)[11] & 0x0F), + (int)(((uint8_t *)address_data->data)[11] >> 4), + (int)(((uint8_t *)address_data->data)[10] & 0x0F), + (int)(((uint8_t *)address_data->data)[10] >> 4), + (int)(((uint8_t *)address_data->data)[9] & 0x0F), + (int)(((uint8_t *)address_data->data)[9] >> 4), + (int)(((uint8_t *)address_data->data)[8] & 0x0F), + (int)(((uint8_t *)address_data->data)[8] >> 4), + (int)(((uint8_t *)address_data->data)[7] & 0x0F), + (int)(((uint8_t *)address_data->data)[7] >> 4), + (int)(((uint8_t *)address_data->data)[6] & 0x0F), + (int)(((uint8_t *)address_data->data)[6] >> 4), + (int)(((uint8_t *)address_data->data)[5] & 0x0F), + (int)(((uint8_t *)address_data->data)[5] >> 4), + (int)(((uint8_t *)address_data->data)[4] & 0x0F), + (int)(((uint8_t *)address_data->data)[4] >> 4), + (int)(((uint8_t *)address_data->data)[3] & 0x0F), + (int)(((uint8_t *)address_data->data)[3] >> 4), + (int)(((uint8_t *)address_data->data)[2] & 0x0F), + (int)(((uint8_t *)address_data->data)[2] >> 4), + (int)(((uint8_t *)address_data->data)[1] & 0x0F), + (int)(((uint8_t *)address_data->data)[1] >> 4), + (int)(((uint8_t *)address_data->data)[0] & 0x0F), + (int)(((uint8_t *)address_data->data)[0] >> 4)); break; default: return GETDNS_RETURN_INVALID_PARAMETER; diff --git a/src/samplewin/Makefile.in b/src/samplewin/Makefile.in deleted file mode 100644 index 90a2d327..00000000 --- a/src/samplewin/Makefile.in +++ /dev/null @@ -1,150 +0,0 @@ -# -# @configure_input@ -# -# Copyright (c) 2013, Verisign, Inc., NLNet Labs -# 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. - -package = @PACKAGE_NAME@ -version = @PACKAGE_VERSION@ -tarname = @PACKAGE_TARNAME@ -distdir = $(tarname)-$(version) - -prefix = @prefix@ -exec_prefix = @exec_prefix@ -bindir = @bindir@ -INSTALL = @INSTALL@ -LIBTOOL = ../../libtool - -srcdir = @srcdir@ - -have_libevent = @have_libevent@ -have_libuv = @have_libuv@ -have_libev = @have_libev@ -NOLIBCHECK = @NOLIBCHECK@ -NOLIBLDNS = @NOLIBLDNS@ - -EXTENSION_LIBEVENT_EXT_LIBS=@EXTENSION_LIBEVENT_EXT_LIBS@ -EXTENSION_LIBEVENT_LDFLAGS=@EXTENSION_LIBEVENT_LDFLAGS@ -EXTENSION_LIBUV_EXT_LIBS=@EXTENSION_LIBUV_EXT_LIBS@ -EXTENSION_LIBUV_LDFLAGS=@EXTENSION_LIBUV_LDFLAGS@ -EXTENSION_LIBEV_EXT_LIBS=@EXTENSION_LIBEV_EXT_LIBS@ -EXTENSION_LIBEV_LDFLAGS=@EXTENSION_LIBEV_LDFLAGS@ - -CHECK_GETDNS=@CHECK_GETDNS@ -CHECK_UV_PROG=@CHECK_UV_PROG@ -CHECK_EVENT_PROG=@CHECK_EVENT_PROG@ -CHECK_EV_PROG=@CHECK_EV_PROG@ - -CC=@CC@ -CFLAGS=-I$(srcdir)/.. -I$(srcdir) -I.. $(cflags) @CFLAGS@ -I/usr/local/ssl/include -LDFLAGS=-L.. @LDFLAGS@ -L/usr/local/ssl/lib -L/usr/local/lib/ -LDLIBS=../libgetdns.la @LIBS@ -lldns -lssl -lcrypto -lgdi32 -lws2_32 -liphlpapi -CHECK_LIBS=@CHECK_LIBS@ -CHECK_CFLAGS=@CHECK_CFLAGS@ -LDNS_LIBS=@LDNS_LIBS@ -LDNS_CFLAGS=@LDNS_CFLAGS@ -LDNS_LDFLAGS=@LDNS_LDFLAGS@ - -CHECK_OBJS=check_getdns_common.lo check_getdns_context_set_timeout.lo \ - check_getdns.lo check_getdns_transport.lo - -ALL_OBJS=$(CHECK_OBJS) getdns_query.lo - -PROGRAMS=getdns_query - -.SUFFIXES: .c .o .a .lo .h - -.c.o: - $(CC) $(CFLAGS) -c $< -o $@ - -.c.lo: - $(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) -c $< -o $@ - -default: all - -all: $(PROGRAMS) - -$(ALL_OBJS): - $(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) $(LDNS_CFLAGS) -c $(srcdir)/$(@:.lo=.c) -o $@ - -getdns_query: getdns_query.lo - $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ getdns_query.lo $(LDFLAGS) $(LDLIBS) - - - -clean: - rm -f *.o *.lo $(PROGRAMS) scratchpad - rm -rf .libs - rm -f check_getdns.log - - -$(distdir): FORCE - mkdir -p $(distdir)/src - cp configure.ac $(distdir) - cp configure $(distdir) - cp Makefile.in $(distdir) - cp src/Makefile.in $(distdir)/src - -distcheck: $(distdir).tar.gz - gzip -cd $(distdir).tar.gz | tar xvf - - cd $(distdir) && ./configure - cd $(distdir) && $(MAKE) all - cd $(distdir) && $(MAKE) check - cd $(distdir) && $(MAKE) DESTDIR=$${PWD}/_inst install - cd $(distdir) && $(MAKE) DESTDIR=$${PWD}/_inst uninstall - @remaining="`find $${PWD}/$(distdir)/_inst -type f | wc -l`"; \ - if test "$${remaining}" -ne 0; then - echo "@@@ $${remaining} file(s) remaining in stage directory!"; \ - exit 1; \ - fi - cd $(distdir) && $(MAKE) clean - rm -rf $(distdir) - @echo "*** Package $(distdir).tar.gz is ready for distribution" - -Makefile: $(srcdir)/Makefile.in ../../config.status - cd ../.. && ./config.status src/test/Makefile - -configure.status: configure - cd ../.. && ./config.status --recheck - -depend: - (cd $(srcdir) ; awk 'BEGIN{P=1}{if(P)print}/^# Dependencies/{P=0}' Makefile.in > Makefile.in.new ) - (cd $(srcdir) ; gcc -MM -I. -I.. *.c | \ - sed -e 's? \([a-z_-]*\)\.\([ch]\)? $$(srcdir)/\1.\2?g' \ - -e 's? \$$(srcdir)/config\.h? ../config.h?g' \ - -e 's? $$(srcdir)/\.\./getdns/getdns_extra\.h? ../getdns/getdns_extra.h?g' \ - -e 's? \.\./getdns/getdns_ext_libevent\.h? $$(srcdir)/../getdns/getdns_ext_libevent.h?g' \ - -e 's? \.\./getdns/getdns_ext_libev\.h? $$(srcdir)/../getdns/getdns_ext_libev.h?g' \ - -e 's? \.\./getdns/getdns_ext_libuv\.h? $$(srcdir)/../getdns/getdns_ext_libuv.h?g' \ - -e 's!\(.*\)\.o[ :]*!\1.lo \1.o: !g' >> Makefile.in.new ) - (cd $(srcdir) ; diff Makefile.in.new Makefile.in && rm Makefile.in.new \ - || mv Makefile.in.new Makefile.in ) - - - -.PHONY: clean - -getdns_query.lo getdns_query.o: $(srcdir)/getdns_query.c ../config.h ../getdns/getdns.h \ - ../getdns/getdns_extra.h \ No newline at end of file diff --git a/src/samplewin/getdns_query.c b/src/samplewin/getdns_query.c deleted file mode 100644 index b2319ad8..00000000 --- a/src/samplewin/getdns_query.c +++ /dev/null @@ -1,1524 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include "util-internal.h" - -#define MAX_TIMEOUTS FD_SETSIZE - -/* Eventloop based on select */ -typedef struct my_eventloop { - getdns_eventloop base; - 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]; -} my_eventloop; - -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; -} - -getdns_return_t -my_eventloop_schedule(getdns_eventloop *loop, - int fd, uint64_t timeout, getdns_eventloop_event *event) -{ - my_eventloop *my_loop = (my_eventloop *)loop; - size_t i; - - 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); - - my_loop->fd_events[fd] = event; - my_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; - } - - assert(event->timeout_cb && !event->read_cb && !event->write_cb); - - for (i = 0; i < MAX_TIMEOUTS; i++) { - if (my_loop->timeout_events[i] == NULL) { - my_loop->timeout_events[i] = event; - my_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; - } - } - return GETDNS_RETURN_GENERIC_ERROR; -} - -getdns_return_t -my_eventloop_clear(getdns_eventloop *loop, getdns_eventloop_event *event) -{ - my_eventloop *my_loop = (my_eventloop *)loop; - size_t i; - - assert(loop); - assert(event); - - DEBUG_SCHED( "%s(loop: %p, event: %p)\n", __FUNCTION__, loop, event); - - i = (intptr_t)event->ev - 1; - assert(i >= 0 && i < FD_SETSIZE); - - if (event->timeout_cb && !event->read_cb && !event->write_cb) { - assert(my_loop->timeout_events[i] == event); - my_loop->timeout_events[i] = NULL; - } else { - assert(my_loop->fd_events[i] == event); - my_loop->fd_events[i] = NULL; - } - event->ev = NULL; - return GETDNS_RETURN_GOOD; -} - -void my_eventloop_cleanup(getdns_eventloop *loop) -{ -} - -void my_read_cb(int fd, getdns_eventloop_event *event) -{ - DEBUG_SCHED( "%s(fd: %d, event: %p)\n", __FUNCTION__, fd, event); - event->read_cb(event->userarg); -} - -void my_write_cb(int fd, getdns_eventloop_event *event) -{ - DEBUG_SCHED( "%s(fd: %d, event: %p)\n", __FUNCTION__, fd, event); - event->write_cb(event->userarg); -} - -void my_timeout_cb(int fd, getdns_eventloop_event *event) -{ - DEBUG_SCHED( "%s(fd: %d, event: %p)\n", __FUNCTION__, fd, event); - event->timeout_cb(event->userarg); -} - -void my_eventloop_run_once(getdns_eventloop *loop, int blocking) -{ - my_eventloop *my_loop = (my_eventloop *)loop; - - fd_set readfds, writefds; - int fd, max_fd = -1; - uint64_t now, timeout = (uint64_t)-1; - size_t i; - struct timeval tv; - - assert(loop); - - FD_ZERO(&readfds); - FD_ZERO(&writefds); - now = get_now_plus(0); - - for (i = 0; i < MAX_TIMEOUTS; i++) { - if (!my_loop->timeout_events[i]) - continue; - if (now > my_loop->timeout_times[i]) - my_timeout_cb(-1, my_loop->timeout_events[i]); - else if (my_loop->timeout_times[i] < timeout) - timeout = my_loop->timeout_times[i]; - } - for (fd = 0; fd < FD_SETSIZE; fd++) { - if (!my_loop->fd_events[fd]) - continue; - if (my_loop->fd_events[fd]->read_cb) - FD_SET(fd, &readfds); - if (my_loop->fd_events[fd]->write_cb) - FD_SET(fd, &writefds); - if (fd > max_fd) - max_fd = fd; - if (my_loop->fd_timeout_times[fd] < timeout) - timeout = my_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, &tv) < 0) { - perror("select() failed"); - exit(EXIT_FAILURE); - } - now = get_now_plus(0); - for (fd = 0; fd < FD_SETSIZE; fd++) { - if (my_loop->fd_events[fd] && - my_loop->fd_events[fd]->read_cb && - FD_ISSET(fd, &readfds)) - my_read_cb(fd, my_loop->fd_events[fd]); - - if (my_loop->fd_events[fd] && - my_loop->fd_events[fd]->write_cb && - FD_ISSET(fd, &writefds)) - my_write_cb(fd, my_loop->fd_events[fd]); - - if (my_loop->fd_events[fd] && - my_loop->fd_events[fd]->timeout_cb && - now > my_loop->fd_timeout_times[fd]) - my_timeout_cb(fd, my_loop->fd_events[fd]); - - i = fd; - if (my_loop->timeout_events[i] && - my_loop->timeout_events[i]->timeout_cb && - now > my_loop->timeout_times[i]) - my_timeout_cb(-1, my_loop->timeout_events[i]); - } -} - -void my_eventloop_run(getdns_eventloop *loop) -{ - my_eventloop *my_loop = (my_eventloop *)loop; - size_t i; - - assert(loop); - - i = 0; - while (i < MAX_TIMEOUTS) { - if (my_loop->fd_events[i] || my_loop->timeout_events[i]) { - my_eventloop_run_once(loop, 1); - i = 0; - } else { - i++; - } - } -} - -void my_eventloop_init(my_eventloop *loop) -{ - static getdns_eventloop_vmt my_eventloop_vmt = { - my_eventloop_cleanup, - my_eventloop_schedule, - my_eventloop_clear, - my_eventloop_run, - my_eventloop_run_once - }; - - (void) memset(loop, 0, sizeof(my_eventloop)); - loop->base.vmt = &my_eventloop_vmt; -} - -static int quiet = 0; -static int batch_mode = 0; -static char *query_file = NULL; -static int json = 0; -static char *the_root = "."; -static char *name; -static getdns_context *context; -static getdns_dict *extensions; -static uint16_t request_type = GETDNS_RRTYPE_NS; -static int timeout, edns0_size, padding_blocksize; -static int async = 0, interactive = 0; -static enum { GENERAL, ADDRESS, HOSTNAME, SERVICE } calltype = GENERAL; - -int get_rrtype(const char *t); - -getdns_dict * -ipaddr_dict(getdns_context *context, char *ipstr) -{ - getdns_dict *r = getdns_dict_create_with_context(context); - char *s = strchr(ipstr, '%'), *scope_id_str = ""; - char *p = strchr(ipstr, '@'), *portstr = ""; - char *t = strchr(ipstr, '#'), *tls_portstr = ""; - char *n = strchr(ipstr, '~'), *tls_namestr = ""; - uint8_t buf[sizeof(struct in6_addr)]; - getdns_bindata addr; - - addr.data = buf; - - if (!r) return NULL; - if (s) { - *s = 0; - scope_id_str = s + 1; - } - if (p) { - *p = 0; - portstr = p + 1; - } - if (t) { - *t = 0; - tls_portstr = t + 1; - } - if (n) { - *n = 0; - tls_namestr = n + 1; - } - if (strchr(ipstr, ':')) { - getdns_dict_util_set_string(r, "address_type", "IPv6"); - addr.size = 16; - if (inet_pton(AF_INET6, ipstr, buf) <= 0) { - getdns_dict_destroy(r); - return NULL; - } - } else { - getdns_dict_util_set_string(r, "address_type", "IPv4"); - addr.size = 4; - if (inet_pton(AF_INET, ipstr, buf) <= 0) { - getdns_dict_destroy(r); - return NULL; - } - } - getdns_dict_set_bindata(r, "address_data", &addr); - if (*portstr) - getdns_dict_set_int(r, "port", (int32_t)atoi(portstr)); - if (*tls_portstr) - getdns_dict_set_int(r, "tls_port", (int32_t)atoi(tls_portstr)); - if (*tls_namestr) { - getdns_dict_util_set_string(r, "tls_auth_name", tls_namestr); - } - if (*scope_id_str) - getdns_dict_util_set_string(r, "scope_id", scope_id_str); - - return r; -} - -static getdns_return_t -fill_transport_list(getdns_context *context, char *transport_list_str, - getdns_transport_list_t *transports, size_t *transport_count) -{ - size_t max_transports = *transport_count; - *transport_count = 0; - for ( size_t i = 0 - ; i < max_transports && i < strlen(transport_list_str) - ; i++, (*transport_count)++) { - switch(*(transport_list_str + i)) { - case 'U': - transports[i] = GETDNS_TRANSPORT_UDP; - break; - case 'T': - transports[i] = GETDNS_TRANSPORT_TCP; - break; - case 'L': - transports[i] = GETDNS_TRANSPORT_TLS; - break; - case 'S': - transports[i] = GETDNS_TRANSPORT_STARTTLS; - break; - default: - fprintf(stderr, "Unrecognised transport '%c' in string %s\n", - *(transport_list_str + i), transport_list_str); - return GETDNS_RETURN_GENERIC_ERROR; - } - } - return GETDNS_RETURN_GOOD; -} - -void -print_usage(FILE *out, const char *progname) -{ - fprintf(out, "usage: %s [@] [+extension] [] []\n", - progname); - fprintf(out, "options:\n"); - fprintf(out, "\t-a\tPerform asynchronous resolution " - "(default = synchronous)\n"); - fprintf(out, "\t-A\taddress lookup ( is ignored)\n"); - fprintf(out, "\t-B\tBatch mode. Schedule all messages before processing responses.\n"); - fprintf(out, "\t-b \tSet edns0 max_udp_payload size\n"); - fprintf(out, "\t-c\tSend Client Subnet privacy request\n"); - fprintf(out, "\t-D\tSet edns0 do bit\n"); - fprintf(out, "\t-d\tclear edns0 do bit\n"); - fprintf(out, "\t-e \tSet idle timeout in miliseconds\n"); - fprintf(out, "\t-F \tread the queries from the specified file\n"); - fprintf(out, "\t-G\tgeneral lookup\n"); - fprintf(out, "\t-H\thostname lookup. ( must be an IP address; is ignored)\n"); - fprintf(out, "\t-h\tPrint this help\n"); - fprintf(out, "\t-i\tPrint api information\n"); - fprintf(out, "\t-I\tInteractive mode (> 1 queries on same context)\n"); - fprintf(out, "\t-j\tOutput json response dict\n"); - fprintf(out, "\t-J\tPretty print json response dict\n"); - fprintf(out, "\t-k\tPrint root trust anchors\n"); - fprintf(out, "\t-n\tSet TLS authentication mode to NONE (default)\n"); - fprintf(out, "\t-m\tSet TLS authentication mode to HOSTNAME\n"); - fprintf(out, "\t-p\tPretty print response dict\n"); - fprintf(out, "\t-P \tPad TLS queries to a multiple of blocksize\n"); - fprintf(out, "\t-r\tSet recursing resolution type\n"); - fprintf(out, "\t-q\tQuiet mode - don't print response\n"); - fprintf(out, "\t-s\tSet stub resolution type (default = recursing)\n"); - fprintf(out, "\t-S\tservice lookup ( is ignored)\n"); - fprintf(out, "\t-t \tSet timeout in miliseconds\n"); - fprintf(out, "\t-T\tSet transport to TCP only\n"); - fprintf(out, "\t-O\tSet transport to TCP only keep connections open\n"); - fprintf(out, "\t-L\tSet transport to TLS only keep connections open\n"); - fprintf(out, "\t-E\tSet transport to TLS with TCP fallback only keep connections open\n"); - fprintf(out, "\t-R\tSet transport to STARTTLS with TCP fallback only keep connections open\n"); - fprintf(out, "\t-u\tSet transport to UDP with TCP fallback\n"); - fprintf(out, "\t-U\tSet transport to UDP only\n"); - fprintf(out, "\t-l \tSet transport list. List can contain 1 of each of the characters\n"); - fprintf(out, "\t\t\t U T L S for UDP, TCP, TLS or STARTTLS e.g 'UT' or 'LST' \n"); - -} - -static getdns_return_t validate_chain(getdns_dict *response) -{ - getdns_return_t r; - getdns_list *validation_chain; - getdns_list *replies_tree; - getdns_dict *reply; - getdns_list *to_validate; - getdns_list *trust_anchor; - size_t i; - int s; - - if (!(to_validate = getdns_list_create())) - return GETDNS_RETURN_MEMORY_ERROR; - - trust_anchor = getdns_root_trust_anchor(NULL); - - if ((r = getdns_dict_get_list( - response, "validation_chain", &validation_chain))) - goto error; - - if ((r = getdns_dict_get_list( - response, "replies_tree", &replies_tree))) - goto error; - - fprintf(stdout, "replies_tree dnssec_status: "); - switch ((s = getdns_validate_dnssec( - replies_tree, validation_chain, trust_anchor))) { - - case GETDNS_DNSSEC_SECURE: - fprintf(stdout, "GETDNS_DNSSEC_SECURE\n"); - break; - case GETDNS_DNSSEC_BOGUS: - fprintf(stdout, "GETDNS_DNSSEC_BOGUS\n"); - break; - case GETDNS_DNSSEC_INDETERMINATE: - fprintf(stdout, "GETDNS_DNSSEC_INDETERMINATE\n"); - break; - case GETDNS_DNSSEC_INSECURE: - fprintf(stdout, "GETDNS_DNSSEC_INSECURE\n"); - break; - case GETDNS_DNSSEC_NOT_PERFORMED: - fprintf(stdout, "GETDNS_DNSSEC_NOT_PERFORMED\n"); - break; - default: - fprintf(stdout, "%d\n", (int)s); - } - - i = 0; - while (!(r = getdns_list_get_dict(replies_tree, i++, &reply))) { - - if ((r = getdns_list_set_dict(to_validate, 0, reply))) - goto error; - - fprintf( stdout - , "reply %zu, dnssec_status: ", i); - switch ((s = getdns_validate_dnssec( - to_validate, validation_chain, trust_anchor))) { - - case GETDNS_DNSSEC_SECURE: - fprintf(stdout, "GETDNS_DNSSEC_SECURE\n"); - break; - case GETDNS_DNSSEC_BOGUS: - fprintf(stdout, "GETDNS_DNSSEC_BOGUS\n"); - break; - case GETDNS_DNSSEC_INDETERMINATE: - fprintf(stdout, "GETDNS_DNSSEC_INDETERMINATE\n"); - break; - case GETDNS_DNSSEC_INSECURE: - fprintf(stdout, "GETDNS_DNSSEC_INSECURE\n"); - break; - case GETDNS_DNSSEC_NOT_PERFORMED: - fprintf(stdout, "GETDNS_DNSSEC_NOT_PERFORMED\n"); - break; - default: - fprintf(stdout, "%d\n", (int)s); - } - } - if (r == GETDNS_RETURN_NO_SUCH_LIST_ITEM) - r = GETDNS_RETURN_GOOD; -error: - getdns_list_destroy(trust_anchor); - getdns_list_destroy(to_validate); - - return GETDNS_RETURN_GOOD; -} - -void callback(getdns_context *context, getdns_callback_type_t callback_type, - getdns_dict *response, void *userarg, getdns_transaction_t trans_id) -{ - char *response_str; - - /* This is a callback with data */; - if (response && !quiet && (response_str = json ? - getdns_print_json_dict(response, json == 1) - : getdns_pretty_print_dict(response))) { - - fprintf(stdout, "ASYNC response:\n%s\n", response_str); - validate_chain(response); - free(response_str); - } - - if (callback_type == GETDNS_CALLBACK_COMPLETE) { - fprintf(stdout, - "Response code was: GOOD. Status was: Callback with ID %llu was successfull.\n", - (unsigned long long)trans_id); - - } else if (callback_type == GETDNS_CALLBACK_CANCEL) - fprintf(stderr, - "An error occurred: The callback with ID %llu was cancelled. Exiting.\n", - (unsigned long long)trans_id); - else { - fprintf(stderr, - "An error occurred: The callback got a callback_type of %d. Exiting.\n", - callback_type); - fprintf(stderr, - "Error : '%s'\n", - getdns_get_errorstr_by_id(callback_type)); - } - getdns_dict_destroy(response); - response = NULL; -} - -#define CONTINUE ((getdns_return_t)-2) -#define CONTINUE_ERROR ((getdns_return_t)-3) - -static getdns_return_t set_cookie(getdns_dict *exts, char *cookie) -{ - uint8_t data[40]; - size_t i; - getdns_return_t r = GETDNS_RETURN_GENERIC_ERROR; - getdns_bindata bindata; - - getdns_dict *opt_parameters = getdns_dict_create(); - getdns_list *options = getdns_list_create(); - getdns_dict *option = getdns_dict_create(); - - if (*cookie == '=') - cookie++; - - for (i = 0; i < 40 && *cookie; i++) { - if (*cookie >= '0' && *cookie <= '9') - data[i] = (uint8_t)(*cookie - '0') << 4; - else if (*cookie >= 'a' && *cookie <= 'f') - data[i] = (uint8_t)(*cookie - 'a' + 10) << 4; - else if (*cookie >= 'A' && *cookie <= 'F') - data[i] = (uint8_t)(*cookie - 'A' + 10) << 4; - else - goto done; - cookie++; - if (*cookie >= '0' && *cookie <= '9') - data[i] |= (uint8_t)(*cookie - '0'); - else if (*cookie >= 'a' && *cookie <= 'f') - data[i] |= (uint8_t)(*cookie - 'a' + 10); - else if (*cookie >= 'A' && *cookie <= 'F') - data[i] |= (uint8_t)(*cookie - 'A' + 10); - else - goto done; - cookie++;; - } - bindata.data = data; - bindata.size = i; - if ((r = getdns_dict_set_int(option, "option_code", 10))) - goto done; - if ((r = getdns_dict_set_bindata(option, "option_data", &bindata))) - goto done; - if ((r = getdns_list_set_dict(options, 0, option))) - goto done; - if ((r = getdns_dict_set_list(opt_parameters, "options", options))) - goto done; - r = getdns_dict_set_dict(exts, "add_opt_parameters", opt_parameters); -done: - getdns_dict_destroy(option); - getdns_list_destroy(options); - getdns_dict_destroy(opt_parameters); - return r; -} - -getdns_return_t parse_args(int argc, char **argv) -{ - getdns_return_t r = GETDNS_RETURN_GOOD; - size_t i; - char *arg, *c, *endptr; - int t, print_api_info = 0, print_trust_anchors = 0; - getdns_list *upstream_list = NULL; - getdns_list *tas = NULL; - size_t upstream_count = 0; - - for (i = 1; i < argc; i++) { - arg = argv[i]; - if ((t = get_rrtype(arg)) >= 0) { - request_type = t; - continue; - - } else if (arg[0] == '+') { - if (arg[1] == 's' && arg[2] == 'i' && arg[3] == 't' && - (arg[4] == '=' || arg[4] == '\0')) { - if ((r = set_cookie(extensions, arg+4))) { - fprintf(stderr, "Could not set cookie:" - " %d", r); - break; - } - } else if (arg[1] == '0') { - /* Unset all existing extensions*/ - getdns_dict_destroy(extensions); - extensions = getdns_dict_create(); - break; - } 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); - break; - } - continue; - - } else if (arg[0] == '@') { - getdns_dict *upstream = ipaddr_dict(context, arg + 1); - if (upstream) { - if (!upstream_list && - !(upstream_list = - getdns_list_create_with_context(context))){ - fprintf(stderr, "Could not create upstream list\n"); - return GETDNS_RETURN_MEMORY_ERROR; - } - getdns_list_set_dict(upstream_list, - upstream_count++, upstream); - } - continue; - } else if (arg[0] != '-') { - name = arg; - continue; - } - for (c = arg+1; *c; c++) { - switch (*c) { - case 'a': - async = 1; - break; - case 'A': - calltype = ADDRESS; - break; - case 'b': - if (c[1] != 0 || ++i >= argc || !*argv[i]) { - fprintf(stderr, "max_udp_payload_size " - "expected after -b\n"); - return GETDNS_RETURN_GENERIC_ERROR; - } - edns0_size = strtol(argv[i], &endptr, 10); - if (*endptr || edns0_size < 0) { - fprintf(stderr, "positive " - "numeric max_udp_payload_size " - "expected after -b\n"); - return GETDNS_RETURN_GENERIC_ERROR; - } - getdns_context_set_edns_maximum_udp_payload_size( - context, (uint16_t) edns0_size); - goto next; - case 'c': - if (getdns_context_set_edns_client_subnet_private(context, 1)) - return GETDNS_RETURN_GENERIC_ERROR; - break; - case 'D': - (void) getdns_context_set_edns_do_bit(context, 1); - break; - case 'd': - (void) getdns_context_set_edns_do_bit(context, 0); - break; - case 'F': - if (c[1] != 0 || ++i >= argc || !*argv[i]) { - fprintf(stderr, "file name expected " - "after -F\n"); - return GETDNS_RETURN_GENERIC_ERROR; - } - query_file = argv[i]; - interactive = 1; - break; - case 'G': - calltype = GENERAL; - break; - case 'H': - calltype = HOSTNAME; - break; - case 'h': - print_usage(stdout, argv[0]); - return CONTINUE; - case 'i': - print_api_info = 1; - break; - case 'I': - interactive = 1; - break; - case 'j': - json = 2; - break; - case 'J': - json = 1; - break; - case 'k': - print_trust_anchors = 1; - break; - case 'n': - getdns_context_set_tls_authentication(context, - GETDNS_AUTHENTICATION_NONE); - break; - case 'm': - getdns_context_set_tls_authentication(context, - GETDNS_AUTHENTICATION_HOSTNAME); - break; - case 'P': - if (c[1] != 0 || ++i >= argc || !*argv[i]) { - fprintf(stderr, "tls_query_padding_blocksize " - "expected after -P\n"); - return GETDNS_RETURN_GENERIC_ERROR; - } - padding_blocksize = strtol(argv[i], &endptr, 10); - if (*endptr || padding_blocksize < 0) { - fprintf(stderr, "non-negative " - "numeric padding blocksize expected " - "after -P\n"); - return GETDNS_RETURN_GENERIC_ERROR; - } - if (getdns_context_set_tls_query_padding_blocksize( - context, padding_blocksize)) - return GETDNS_RETURN_GENERIC_ERROR; - goto next; - case 'p': - json = 0; - case 'q': - quiet = 1; - break; - case 'r': - getdns_context_set_resolution_type( - context, - GETDNS_RESOLUTION_RECURSING); - break; - case 's': - getdns_context_set_resolution_type( - context, GETDNS_RESOLUTION_STUB); - break; - case 'S': - calltype = SERVICE; - break; - case 't': - if (c[1] != 0 || ++i >= argc || !*argv[i]) { - fprintf(stderr, "timeout expected " - "after -t\n"); - return GETDNS_RETURN_GENERIC_ERROR; - } - timeout = strtol(argv[i], &endptr, 10); - if (*endptr || timeout < 0) { - fprintf(stderr, "positive " - "numeric timeout expected " - "after -t\n"); - return GETDNS_RETURN_GENERIC_ERROR; - } - getdns_context_set_timeout( - context, timeout); - goto next; - case 'e': - if (c[1] != 0 || ++i >= argc || !*argv[i]) { - fprintf(stderr, "idle timeout expected " - "after -t\n"); - return GETDNS_RETURN_GENERIC_ERROR; - } - timeout = strtol(argv[i], &endptr, 10); - if (*endptr || timeout < 0) { - fprintf(stderr, "positive " - "numeric idle timeout expected " - "after -t\n"); - return GETDNS_RETURN_GENERIC_ERROR; - } - getdns_context_set_idle_timeout( - context, timeout); - goto next; - case 'T': - getdns_context_set_dns_transport(context, - GETDNS_TRANSPORT_TCP_ONLY); - break; - case 'O': - getdns_context_set_dns_transport(context, - GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN); - break; - case 'L': - getdns_context_set_dns_transport(context, - GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN); - break; - case 'E': - getdns_context_set_dns_transport(context, - GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN); - break; - case 'R': - getdns_context_set_dns_transport(context, - GETDNS_TRANSPORT_STARTTLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN); - break; - case 'u': - getdns_context_set_dns_transport(context, - GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP); - break; - case 'U': - getdns_context_set_dns_transport(context, - GETDNS_TRANSPORT_UDP_ONLY); - break; - case 'l': - if (c[1] != 0 || ++i >= argc || !*argv[i]) { - fprintf(stderr, "transport list expected " - "after -l\n"); - return GETDNS_RETURN_GENERIC_ERROR; - } - getdns_transport_list_t transports[10]; - size_t transport_count = sizeof(transports); - if ((r = fill_transport_list(context, argv[i], transports, &transport_count)) || - (r = getdns_context_set_dns_transport_list(context, - transport_count, transports))){ - fprintf(stderr, "Could not set transports\n"); - return r; - } - break; - case 'B': - batch_mode = 1; - break; - - - default: - fprintf(stderr, "Unknown option " - "\"%c\"\n", *c); - for (i = 0; i < argc; i++) - fprintf(stderr, "%d: \"%s\"\n", (int)i, argv[i]); - return GETDNS_RETURN_GENERIC_ERROR; - } - } -next: ; - } - if (r) - return r; - if (upstream_count && - (r = getdns_context_set_upstream_recursive_servers( - context, upstream_list))) { - fprintf(stderr, "Error setting upstream recursive servers\n"); - } - if (print_api_info) { - fprintf(stdout, "%s\n", getdns_pretty_print_dict( - getdns_context_get_api_information(context))); - return CONTINUE; - } - if (print_trust_anchors) { - if ((tas = getdns_root_trust_anchor(NULL))) { - fprintf(stdout, "%s\n", getdns_pretty_print_list(tas)); - return CONTINUE; - } else - return CONTINUE_ERROR; - } - return r; -} - -getdns_return_t do_the_call(void) -{ - getdns_return_t r; - getdns_dict *address = NULL; - getdns_dict *response = NULL; - char *response_str; - uint32_t status; - - if (calltype == HOSTNAME && - !(address = ipaddr_dict(context, name))) { - fprintf(stderr, "Could not convert \"%s\" " - "to an IP address", name); - return GETDNS_RETURN_GOOD; - } - if (async) { - switch (calltype) { - case GENERAL: - r = getdns_general(context, name, request_type, - extensions, &response, NULL, callback); - break; - case ADDRESS: - r = getdns_address(context, name, - extensions, &response, NULL, callback); - break; - case HOSTNAME: - r = getdns_hostname(context, address, - extensions, &response, NULL, callback); - break; - case SERVICE: - r = getdns_service(context, name, - extensions, &response, NULL, callback); - break; - default: - r = GETDNS_RETURN_GENERIC_ERROR; - break; - } - 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, - getdns_get_errorstr_by_id(r)); - } else { - switch (calltype) { - case GENERAL: - r = getdns_general_sync(context, name, - request_type, extensions, &response); - break; - case ADDRESS: - r = getdns_address_sync(context, name, - extensions, &response); - break; - case HOSTNAME: - r = getdns_hostname_sync(context, address, - extensions, &response); - break; - case SERVICE: - r = getdns_service_sync(context, name, - extensions, &response); - break; - default: - r = GETDNS_RETURN_GENERIC_ERROR; - break; - } - if (r != GETDNS_RETURN_GOOD) { - fprintf(stderr, "An error occurred: %d '%s'\n", r, - getdns_get_errorstr_by_id(r)); - return r; - } - if (response && !quiet) { - if ((response_str = json ? - getdns_print_json_dict(response, json == 1) - : getdns_pretty_print_dict(response))) { - - fprintf( stdout, "SYNC response:\n%s\n" - , response_str); - validate_chain(response); - free(response_str); - } else { - r = GETDNS_RETURN_MEMORY_ERROR; - fprintf( stderr - , "Could not print response\n"); - } - } - getdns_dict_get_int(response, "status", &status); - fprintf(stdout, "Response code was: GOOD. Status was: %s\n", - getdns_get_errorstr_by_id(status)); - if (response) - getdns_dict_destroy(response); - } - return r; -} - -my_eventloop my_loop; -FILE *fp; - -void read_line_cb(void *userarg) -{ - getdns_eventloop_event *read_line_ev = userarg; - getdns_return_t r; - - char line[1024], *token, *linev[256]; - int linec; - - if (!fgets(line, 1024, fp) || !*line) { - if (query_file) - fprintf(stdout,"End of file."); - my_eventloop_clear(&my_loop.base, read_line_ev); - return; - } - if (query_file) - fprintf(stdout,"Found query: %s", line); - - linev[0] = __FILE__; - linec = 1; - if (!(token = strtok(line, " \t\f\n\r"))) { - if (! query_file) { - printf("> "); - fflush(stdout); - } - return; - } - if (*token == '#') { - fprintf(stdout,"Result: Skipping comment\n"); - if (! query_file) { - printf("> "); - fflush(stdout); - } - return; - } - do linev[linec++] = token; - while (linec < 256 && (token = strtok(NULL, " \t\f\n\r"))); - - if (((r = parse_args(linec, linev)) || (r = do_the_call())) && - (r != CONTINUE && r != CONTINUE_ERROR)) - my_eventloop_clear(&my_loop.base, read_line_ev); - - else if (! query_file) { - printf("> "); - fflush(stdout); - } -} - -int -main(int argc, char **argv) -{ - getdns_return_t r; - - name = the_root; - if ((r = getdns_context_create(&context, 1))) { - fprintf(stderr, "Create context failed: %d\n", 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(); - if (! extensions) { - fprintf(stderr, "Could not create extensions dict\n"); - r = GETDNS_RETURN_MEMORY_ERROR; - goto done_destroy_context; - } - if ((r = parse_args(argc, argv))) - goto done_destroy_context; - - if (query_file) { - fp = fopen(query_file, "rt"); - if (fp == NULL) { - fprintf(stderr, "Could not open query file: %s\n", query_file); - goto done_destroy_context; - } - } else - fp = stdin; - - /* 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 (!query_file) { - printf("> "); - fflush(stdout); - } - my_eventloop_run(&my_loop.base); - } - else - r = do_the_call(); - - if ((r == GETDNS_RETURN_GOOD && batch_mode)) - getdns_context_run(context); - - /* Clean up */ - getdns_dict_destroy(extensions); -done_destroy_context: - getdns_context_destroy(context); - - if (fp) - fclose(fp); - - if (r == CONTINUE) - return 0; - else if (r == CONTINUE_ERROR) - return 1; - fprintf(stdout, "\nAll done.\n"); - return r; -} - -int get_rrtype(const char *t) { - char *endptr; - int r; - - switch (t[0]) { - case 'A': - case 'a': switch (t[1]) { - case '\0': return GETDNS_RRTYPE_A; - case '6': if (t[2] == '\0') return GETDNS_RRTYPE_A6; - return -1; - case 'A': - case 'a': /* before "AA", final "AA" (GETDNS_RRTYPE_AAAA) */ - if ((t[2]|0x20) == 'a' && (t[3]|0x20) == 'a' && t[4] == '\0') - return GETDNS_RRTYPE_AAAA; - return -1; - case 'F': - case 'f': /* before "AF", final "SDB" (GETDNS_RRTYPE_AFSDB) */ - if ((t[2]|0x20) == 's' && (t[3]|0x20) == 'd' && (t[4]|0x20) == 'b' && t[5] == '\0') - return GETDNS_RRTYPE_AFSDB; - return -1; - case 'P': - case 'p': /* before "AP", final "L" (GETDNS_RRTYPE_APL) */ - if ((t[2]|0x20) == 'l' && t[3] == '\0') - return GETDNS_RRTYPE_APL; - return -1; - case 'T': - case 't': /* before "AT", final "MA" (GETDNS_RRTYPE_ATMA) */ - if ((t[2]|0x20) == 'm' && (t[3]|0x20) == 'a' && t[4] == '\0') - return GETDNS_RRTYPE_ATMA; - return -1; - case 'X': - case 'x': /* before "AX", final "FR" (GETDNS_RRTYPE_AXFR) */ - if ((t[2]|0x20) == 'f' && (t[3]|0x20) == 'r' && t[4] == '\0') - return GETDNS_RRTYPE_AXFR; - return -1; - default : return -1; - }; - case 'C': - case 'c': switch (t[1]) { - case 'A': - case 'a': /* before "CA", final "A" (GETDNS_RRTYPE_CAA) */ - if ((t[2]|0x20) == 'a' && t[3] == '\0') - return GETDNS_RRTYPE_CAA; - return -1; - case 'D': - case 'd': switch (t[2]) { - case 'N': - case 'n': /* before "CDN", final "SKEY" (GETDNS_RRTYPE_CDNSKEY) */ - if ((t[3]|0x20) == 's' && (t[4]|0x20) == 'k' && (t[5]|0x20) == 'e' && (t[6]|0x20) == 'y' && t[7] == '\0') - return GETDNS_RRTYPE_CDNSKEY; - return -1; - case 'S': - case 's': if (t[3] == '\0') return GETDNS_RRTYPE_CDS; - return -1; - default : return -1; - }; - case 'E': - case 'e': /* before "CE", final "RT" (GETDNS_RRTYPE_CERT) */ - if ((t[2]|0x20) == 'r' && (t[3]|0x20) == 't' && t[4] == '\0') - return GETDNS_RRTYPE_CERT; - return -1; - case 'N': - case 'n': /* before "CN", final "AME" (GETDNS_RRTYPE_CNAME) */ - if ((t[2]|0x20) == 'a' && (t[3]|0x20) == 'm' && (t[4]|0x20) == 'e' && t[5] == '\0') - return GETDNS_RRTYPE_CNAME; - return -1; - case 'S': - case 's': /* before "CS", final "YNC" (GETDNS_RRTYPE_CSYNC) */ - if ((t[2]|0x20) == 'y' && (t[3]|0x20) == 'n' && (t[4]|0x20) == 'c' && t[5] == '\0') - return GETDNS_RRTYPE_CSYNC; - return -1; - - default : return -1; - }; - case 'D': - case 'd': switch (t[1]) { - case 'H': - case 'h': /* before "DH", final "CID" (GETDNS_RRTYPE_DHCID) */ - if ((t[2]|0x20) == 'c' && (t[3]|0x20) == 'i' && (t[4]|0x20) == 'd' && t[5] == '\0') - return GETDNS_RRTYPE_DHCID; - return -1; - case 'L': - case 'l': /* before "DL", final "V" (GETDNS_RRTYPE_DLV) */ - if ((t[2]|0x20) == 'v' && t[3] == '\0') - return GETDNS_RRTYPE_DLV; - return -1; - case 'N': - case 'n': switch (t[2]) { - case 'A': - case 'a': /* before "DNA", final "ME" (GETDNS_RRTYPE_DNAME) */ - if ((t[3]|0x20) == 'm' && (t[4]|0x20) == 'e' && t[5] == '\0') - return GETDNS_RRTYPE_DNAME; - return -1; - case 'S': - case 's': /* before "DNS", final "KEY" (GETDNS_RRTYPE_DNSKEY) */ - if ((t[3]|0x20) == 'k' && (t[4]|0x20) == 'e' && (t[5]|0x20) == 'y' && t[6] == '\0') - return GETDNS_RRTYPE_DNSKEY; - return -1; - default : return -1; - }; - case 'S': - case 's': if (t[2] == '\0') return GETDNS_RRTYPE_DS; - return -1; - default : return -1; - }; - case 'E': - case 'e': switch (t[1]) { - case 'I': - case 'i': /* before "EI", final "D" (GETDNS_RRTYPE_EID) */ - if ((t[2]|0x20) == 'd' && t[3] == '\0') - return GETDNS_RRTYPE_EID; - return -1; - case 'U': - case 'u': /* before "EU", next "I" */ - if ((t[2]|0x20) != 'i') - return -1; - switch (t[3]) { - case '4': /* before "EUI4", final "8" (GETDNS_RRTYPE_EUI48) */ - if (t[4] == '8' && t[5] == '\0') - return GETDNS_RRTYPE_EUI48; - return -1; - case '6': /* before "EUI6", final "4" (GETDNS_RRTYPE_EUI64) */ - if (t[4] == '4' && t[5] == '\0') - return GETDNS_RRTYPE_EUI64; - return -1; - default : return -1; - }; - default : return -1; - }; - case 'G': - case 'g': switch (t[1]) { - case 'I': - case 'i': /* before "GI", final "D" (GETDNS_RRTYPE_GID) */ - if ((t[2]|0x20) == 'd' && t[3] == '\0') - return GETDNS_RRTYPE_GID; - return -1; - case 'P': - case 'p': /* before "GP", final "OS" (GETDNS_RRTYPE_GPOS) */ - if ((t[2]|0x20) == 'o' && (t[3]|0x20) == 's' && t[4] == '\0') - return GETDNS_RRTYPE_GPOS; - return -1; - default : return -1; - }; - case 'H': - case 'h': /* before "H", next "I" */ - if ((t[1]|0x20) != 'i') - return -1; - switch (t[2]) { - case 'N': - case 'n': /* before "HIN", final "FO" (GETDNS_RRTYPE_HINFO) */ - if ((t[3]|0x20) == 'f' && (t[4]|0x20) == 'o' && t[5] == '\0') - return GETDNS_RRTYPE_HINFO; - return -1; - case 'P': - case 'p': if (t[3] == '\0') return GETDNS_RRTYPE_HIP; - return -1; - default : return -1; - }; - case 'I': - case 'i': switch (t[1]) { - case 'P': - case 'p': /* before "IP", final "SECKEY" (GETDNS_RRTYPE_IPSECKEY) */ - if ((t[2]|0x20) == 's' && (t[3]|0x20) == 'e' && (t[4]|0x20) == 'c' && (t[5]|0x20) == 'k' && (t[6]|0x20) == 'e' && (t[7]|0x20) == 'y' && t[8] == '\0') - return GETDNS_RRTYPE_IPSECKEY; - return -1; - case 'S': - case 's': /* before "IS", final "DN" (GETDNS_RRTYPE_ISDN) */ - if ((t[2]|0x20) == 'd' && (t[3]|0x20) == 'n' && t[4] == '\0') - return GETDNS_RRTYPE_ISDN; - return -1; - case 'X': - case 'x': /* before "IX", final "FR" (GETDNS_RRTYPE_IXFR) */ - if ((t[2]|0x20) == 'f' && (t[3]|0x20) == 'r' && t[4] == '\0') - return GETDNS_RRTYPE_IXFR; - return -1; - default : return -1; - }; - case 'K': - case 'k': switch (t[1]) { - case 'E': - case 'e': /* before "KE", final "Y" (GETDNS_RRTYPE_KEY) */ - if ((t[2]|0x20) == 'y' && t[3] == '\0') - return GETDNS_RRTYPE_KEY; - return -1; - case 'X': - case 'x': if (t[2] == '\0') return GETDNS_RRTYPE_KX; - return -1; - default : return -1; - }; - case 'L': - case 'l': switch (t[1]) { - case '3': /* before "L3", final "2" (GETDNS_RRTYPE_L32) */ - if (t[2] == '2' && t[3] == '\0') - return GETDNS_RRTYPE_L32; - return -1; - case '6': /* before "L6", final "4" (GETDNS_RRTYPE_L64) */ - if (t[2] == '4' && t[3] == '\0') - return GETDNS_RRTYPE_L64; - return -1; - case 'O': - case 'o': /* before "LO", final "C" (GETDNS_RRTYPE_LOC) */ - if ((t[2]|0x20) == 'c' && t[3] == '\0') - return GETDNS_RRTYPE_LOC; - return -1; - case 'P': - case 'p': if (t[2] == '\0') return GETDNS_RRTYPE_LP; - return -1; - default : return -1; - }; - case 'M': - case 'm': switch (t[1]) { - case 'A': - case 'a': /* before "MA", next "IL" */ - if ((t[2]|0x20) != 'i' && (t[3]|0x20) != 'l') - return -1; - switch (t[4]) { - case 'A': - case 'a': if (t[5] == '\0') return GETDNS_RRTYPE_MAILA; - return -1; - case 'B': - case 'b': if (t[5] == '\0') return GETDNS_RRTYPE_MAILB; - return -1; - default : return -1; - }; - case 'B': - case 'b': if (t[2] == '\0') return GETDNS_RRTYPE_MB; - return -1; - case 'D': - case 'd': if (t[2] == '\0') return GETDNS_RRTYPE_MD; - return -1; - case 'F': - case 'f': if (t[2] == '\0') return GETDNS_RRTYPE_MF; - return -1; - case 'G': - case 'g': if (t[2] == '\0') return GETDNS_RRTYPE_MG; - return -1; - case 'I': - case 'i': /* before "MI", final "NFO" (GETDNS_RRTYPE_MINFO) */ - if ((t[2]|0x20) == 'n' && (t[3]|0x20) == 'f' && (t[4]|0x20) == 'o' && t[5] == '\0') - return GETDNS_RRTYPE_MINFO; - return -1; - case 'R': - case 'r': if (t[2] == '\0') return GETDNS_RRTYPE_MR; - return -1; - case 'X': - case 'x': if (t[2] == '\0') return GETDNS_RRTYPE_MX; - return -1; - default : return -1; - }; - case 'N': - case 'n': switch (t[1]) { - case 'A': - case 'a': /* before "NA", final "PTR" (GETDNS_RRTYPE_NAPTR) */ - if ((t[2]|0x20) == 'p' && (t[3]|0x20) == 't' && (t[4]|0x20) == 'r' && t[5] == '\0') - return GETDNS_RRTYPE_NAPTR; - return -1; - case 'I': - case 'i': switch (t[2]) { - case 'D': - case 'd': if (t[3] == '\0') return GETDNS_RRTYPE_NID; - return -1; - case 'M': - case 'm': /* before "NIM", final "LOC" (GETDNS_RRTYPE_NIMLOC) */ - if ((t[3]|0x20) == 'l' && (t[4]|0x20) == 'o' && (t[5]|0x20) == 'c' && t[6] == '\0') - return GETDNS_RRTYPE_NIMLOC; - return -1; - case 'N': - case 'n': /* before "NIN", final "FO" (GETDNS_RRTYPE_NINFO) */ - if ((t[3]|0x20) == 'f' && (t[4]|0x20) == 'o' && t[5] == '\0') - return GETDNS_RRTYPE_NINFO; - return -1; - default : return -1; - }; - case 'S': - case 's': switch (t[2]) { - case '\0': return GETDNS_RRTYPE_NS; - case 'A': - case 'a': /* before "NSA", final "P" (GETDNS_RRTYPE_NSAP) */ - if ((t[3]|0x20) == 'p' && t[4] == '\0') - return GETDNS_RRTYPE_NSAP; - return -1; - case 'E': - case 'e': /* before "NSE", final "C3PARAM" (GETDNS_RRTYPE_NSEC3PARAM) */ - if ((t[3]|0x20) == 'c' && t[4] == '3' && (t[5]|0x20) == 'p' && (t[6]|0x20) == 'a' && (t[7]|0x20) == 'r' && (t[8]|0x20) == 'a' && (t[9]|0x20) == 'm' && t[10] == '\0') - return GETDNS_RRTYPE_NSEC3PARAM; - return -1; - default : return -1; - }; - case 'U': - case 'u': /* before "NU", final "LL" (GETDNS_RRTYPE_NULL) */ - if ((t[2]|0x20) == 'l' && (t[3]|0x20) == 'l' && t[4] == '\0') - return GETDNS_RRTYPE_NULL; - return -1; - case 'X': - case 'x': /* before "NX", final "T" (GETDNS_RRTYPE_NXT) */ - if ((t[2]|0x20) == 't' && t[3] == '\0') - return GETDNS_RRTYPE_NXT; - return -1; - default : return -1; - }; - case 'O': - case 'o': /* before "O", next "P" */ - if ((t[1]|0x20) != 'p') - return -1; - switch (t[2]) { - case 'E': - case 'e': /* before "OPE", final "NPGPKEY" (GETDNS_RRTYPE_OPENPGPKEY) */ - if ((t[3]|0x20) == 'n' && (t[4]|0x20) == 'p' && (t[5]|0x20) == 'g' && (t[6]|0x20) == 'p' && (t[7]|0x20) == 'k' && (t[8]|0x20) == 'e' && (t[9]|0x20) == 'y' && t[10] == '\0') - return GETDNS_RRTYPE_OPENPGPKEY; - return -1; - case 'T': - case 't': if (t[3] == '\0') return GETDNS_RRTYPE_OPT; - return -1; - default : return -1; - }; - case 'P': - case 'p': switch (t[1]) { - case 'T': - case 't': /* before "PT", final "R" (GETDNS_RRTYPE_PTR) */ - if ((t[2]|0x20) == 'r' && t[3] == '\0') - return GETDNS_RRTYPE_PTR; - return -1; - case 'X': - case 'x': if (t[2] == '\0') return GETDNS_RRTYPE_PX; - return -1; - default : return -1; - }; - case 'R': - case 'r': switch (t[1]) { - case 'K': - case 'k': /* before "RK", final "EY" (GETDNS_RRTYPE_RKEY) */ - if ((t[2]|0x20) == 'e' && (t[3]|0x20) == 'y' && t[4] == '\0') - return GETDNS_RRTYPE_RKEY; - return -1; - case 'P': - case 'p': if (t[2] == '\0') return GETDNS_RRTYPE_RP; - return -1; - case 'R': - case 'r': /* before "RR", final "SIG" (GETDNS_RRTYPE_RRSIG) */ - if ((t[2]|0x20) == 's' && (t[3]|0x20) == 'i' && (t[4]|0x20) == 'g' && t[5] == '\0') - return GETDNS_RRTYPE_RRSIG; - return -1; - case 'T': - case 't': if (t[2] == '\0') return GETDNS_RRTYPE_RT; - return -1; - default : return -1; - }; - case 'S': - case 's': switch (t[1]) { - case 'I': - case 'i': switch (t[2]) { - case 'G': - case 'g': if (t[3] == '\0') return GETDNS_RRTYPE_SIG; - return -1; - case 'N': - case 'n': /* before "SIN", final "K" (GETDNS_RRTYPE_SINK) */ - if ((t[3]|0x20) == 'k' && t[4] == '\0') - return GETDNS_RRTYPE_SINK; - return -1; - default : return -1; - }; - case 'O': - case 'o': /* before "SO", final "A" (GETDNS_RRTYPE_SOA) */ - if ((t[2]|0x20) == 'a' && t[3] == '\0') - return GETDNS_RRTYPE_SOA; - return -1; - case 'P': - case 'p': /* before "SP", final "F" (GETDNS_RRTYPE_SPF) */ - if ((t[2]|0x20) == 'f' && t[3] == '\0') - return GETDNS_RRTYPE_SPF; - return -1; - case 'R': - case 'r': /* before "SR", final "V" (GETDNS_RRTYPE_SRV) */ - if ((t[2]|0x20) == 'v' && t[3] == '\0') - return GETDNS_RRTYPE_SRV; - return -1; - case 'S': - case 's': /* before "SS", final "HFP" (GETDNS_RRTYPE_SSHFP) */ - if ((t[2]|0x20) == 'h' && (t[3]|0x20) == 'f' && (t[4]|0x20) == 'p' && t[5] == '\0') - return GETDNS_RRTYPE_SSHFP; - return -1; - default : return -1; - }; - case 'T': - case 't': switch (t[1]) { - case 'A': - case 'a': /* before "TA", final "LINK" (GETDNS_RRTYPE_TALINK) */ - if ((t[2]|0x20) == 'l' && (t[3]|0x20) == 'i' && (t[4]|0x20) == 'n' && (t[5]|0x20) == 'k' && t[6] == '\0') - return GETDNS_RRTYPE_TALINK; - return -1; - case 'K': - case 'k': /* before "TK", final "EY" (GETDNS_RRTYPE_TKEY) */ - if ((t[2]|0x20) == 'e' && (t[3]|0x20) == 'y' && t[4] == '\0') - return GETDNS_RRTYPE_TKEY; - return -1; - case 'L': - case 'l': /* before "TL", final "SA" (GETDNS_RRTYPE_TLSA) */ - if ((t[2]|0x20) == 's' && (t[3]|0x20) == 'a' && t[4] == '\0') - return GETDNS_RRTYPE_TLSA; - return -1; - case 'S': - case 's': /* before "TS", final "IG" (GETDNS_RRTYPE_TSIG) */ - if ((t[2]|0x20) == 'i' && (t[3]|0x20) == 'g' && t[4] == '\0') - return GETDNS_RRTYPE_TSIG; - return -1; - case 'X': - case 'x': /* before "TX", final "T" (GETDNS_RRTYPE_TXT) */ - if ((t[2]|0x20) == 't' && t[3] == '\0') - return GETDNS_RRTYPE_TXT; - return -1; - case 'Y': - case 'y': /* before "TY", then "PE" followed by a number */ - if ((t[2]|0x20) == 'p' && (t[3]|0x20) == 'e' && t[4] != '\0') { - r = (int) strtol(t + 4, &endptr, 10); - if (*endptr == '\0') return r; - } - return -1; - default : return -1; - }; - case 'U': - case 'u': switch (t[1]) { - case 'I': - case 'i': switch (t[2]) { - case 'D': - case 'd': if (t[3] == '\0') return GETDNS_RRTYPE_UID; - return -1; - case 'N': - case 'n': /* before "UIN", final "FO" (GETDNS_RRTYPE_UINFO) */ - if ((t[3]|0x20) == 'f' && (t[4]|0x20) == 'o' && t[5] == '\0') - return GETDNS_RRTYPE_UINFO; - return -1; - default : return -1; - }; - case 'N': - case 'n': /* before "UN", final "SPEC" (GETDNS_RRTYPE_UNSPEC) */ - if ((t[2]|0x20) == 's' && (t[3]|0x20) == 'p' && (t[4]|0x20) == 'e' && (t[5]|0x20) == 'c' && t[6] == '\0') - return GETDNS_RRTYPE_UNSPEC; - return -1; - case 'R': - case 'r': /* before "UR", final "I" (GETDNS_RRTYPE_URI) */ - if ((t[2]|0x20) == 'i' && t[3] == '\0') - return GETDNS_RRTYPE_URI; - return -1; - default : return -1; - }; - case 'W': - case 'w': /* before "W", final "KS" (GETDNS_RRTYPE_WKS) */ - if ((t[1]|0x20) == 'k' && (t[2]|0x20) == 's' && t[3] == '\0') - return GETDNS_RRTYPE_WKS; - return -1; - case 'X': - case 'x': /* before "X", final "25" (GETDNS_RRTYPE_X25) */ - if (t[1] == '2' && t[2] == '5' && t[3] == '\0') - return GETDNS_RRTYPE_X25; - return -1; - default : return -1; - }; -} - diff --git a/src/stub.c b/src/stub.c index 3b8de972..e0d55148 100644 --- a/src/stub.c +++ b/src/stub.c @@ -639,7 +639,7 @@ stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf, getdns_eventl tcp->read_pos = tcp->read_buf; tcp->to_read = 2; /* Packet size */ } - read = recv(fd, tcp->read_pos, tcp->to_read, 0); + read = recv(fd, (void *)tcp->read_pos, tcp->to_read, 0); if (read == -1) { #ifdef USE_WINSOCK printf("read (in tcp ) %s\n", @@ -649,7 +649,7 @@ stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf, getdns_eventl if (WSAGetLastError() == WSAEINPROGRESS) return STUB_TCP_AGAIN; if (WSAGetLastError() == WSAEWOULDBLOCK) { - winsock_tcp_wouldblock(event, EV_READ); + winsock_tcp_wouldblock(event->ev, EV_READ); return STUB_TCP_AGAIN; } @@ -773,9 +773,10 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq) #else #ifdef USE_WINSOCK - written = sendto(fd, netreq->query - 2, pkt_len + 2, - 0, (struct sockaddr *)&(netreq->upstream->addr), - netreq->upstream->addr_len); + 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); @@ -1283,7 +1284,7 @@ stub_udp_read_cb(void *userarg) GETDNS_CLEAR_EVENT(dnsreq->loop, &netreq->event); - read = recvfrom(netreq->fd, netreq->response, + read = recvfrom(netreq->fd, (void *)netreq->response, netreq->max_udp_payload_size + 1, /* If read == max_udp_payload_size * then all is good. If read == * max_udp_payload_size + 1, then @@ -1363,7 +1364,8 @@ stub_udp_write_cb(void *userarg) return; /* too many upstream options */ } pkt_len = _getdns_network_req_add_tsig(netreq); - if ((ssize_t)pkt_len != sendto(netreq->fd, netreq->query, pkt_len, 0, + if ((ssize_t)pkt_len != sendto( + netreq->fd, (const void *)netreq->query, pkt_len, 0, (struct sockaddr *)&netreq->upstream->addr, netreq->upstream->addr_len)) { close(netreq->fd); @@ -1394,7 +1396,7 @@ upstream_read_cb(void *userarg) &upstream->upstreams->mf); else q = stub_tcp_read(upstream->fd, &upstream->tcp, - &upstream->upstreams->mf, &netreq->event); + &upstream->upstreams->mf, &upstream->event); switch (q) { case STUB_TCP_AGAIN: diff --git a/src/test/getdns_query.c b/src/test/getdns_query.c index 2d00c985..862b9c68 100644 --- a/src/test/getdns_query.c +++ b/src/test/getdns_query.c @@ -549,8 +549,7 @@ static getdns_return_t validate_chain(getdns_dict *response) if ((r = getdns_list_set_dict(to_validate, 0, reply))) goto error; - fprintf( stdout - , "reply %zu, dnssec_status: ", i); + printf("reply %u, dnssec_status: ", (unsigned)i); switch ((s = getdns_validate_dnssec( to_validate, validation_chain, trust_anchor))) { @@ -598,14 +597,13 @@ void callback(getdns_context *context, getdns_callback_type_t callback_type, } if (callback_type == GETDNS_CALLBACK_COMPLETE) { - fprintf(stdout, - "Response code was: GOOD. Status was: Callback with ID %llu was successfull.\n", - (unsigned long long)trans_id); + printf("Response code was: GOOD. Status was: Callback with ID %"PRIu64" was successfull.\n", + trans_id); } else if (callback_type == GETDNS_CALLBACK_CANCEL) fprintf(stderr, - "An error occurred: The callback with ID %llu was cancelled. Exiting.\n", - (unsigned long long)trans_id); + "An error occurred: The callback with ID %"PRIu64" was cancelled. Exiting.\n", + trans_id); else { fprintf(stderr, "An error occurred: The callback got a callback_type of %d. Exiting.\n", diff --git a/src/util/winsock_event.c b/src/util/winsock_event.c index 9bb78cf9..2df44558 100644 --- a/src/util/winsock_event.c +++ b/src/util/winsock_event.c @@ -58,7 +58,8 @@ log_err(const char *format, ...) { va_list args; va_start(args, format); - fprintf(stderr, "error", format, args); + fprintf(stderr, "error "); + fprintf(stderr, format, args); va_end(args); } @@ -353,7 +354,7 @@ int _getdns_handle_select(struct _getdns_event_base* base, struct timeval* wait) DWORD ret; WSANETWORKEVENTS netev; struct _getdns_event* eventlist[WSK_MAX_ITEMS]; - int i, numwait = 0, startidx = 0, was_timeout = 0; + int i, numwait = 0, startidx = 0; int newstickies = 0; struct timeval nultm; @@ -379,7 +380,7 @@ int _getdns_handle_select(struct _getdns_event_base* base, struct timeval* wait) 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, base->items[i]->hEvent); + (int)timeout, (int)base->items[i]->hEvent); if (numwait == WSK_MAX_ITEMS) break; /* sanity check */ } @@ -391,7 +392,6 @@ int _getdns_handle_select(struct _getdns_event_base* base, struct timeval* wait) if(wait) { Sleep(timeout); } - was_timeout = 1; } else { //gv: do not schedule udp write @@ -409,7 +409,7 @@ int _getdns_handle_select(struct _getdns_event_base* base, struct timeval* wait) 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", ret, numwait); + 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; @@ -419,7 +419,6 @@ int _getdns_handle_select(struct _getdns_event_base* base, struct timeval* wait) return -1; } else if(ret == WSA_WAIT_TIMEOUT) { printf("timeout\n"); - was_timeout = 1; } else startidx = ret - WSA_WAIT_EVENT_0; } @@ -633,25 +632,6 @@ int _getdns_event_base_set(struct _getdns_event_base *base, struct _getdns_event return 0; } -/** -* Find a fd in the list of items. -* Note that not all items have a fd associated (those are -1). -* Signals are stored separately, and not searched. -* @param base: event base to look in. -* @param fd: what socket to look for. -* @return the index in the array, or -1 on failure. -*/ -static int -find_fd(struct _getdns_event_base* base, int fd) -{ - int i; - for (i = 0; imax; i++) { - if (base->items[i]->ev_fd == fd) - return i; - } - return -1; -} - 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", @@ -714,7 +694,7 @@ int _getdns_event_add(struct _getdns_event *ev, struct timeval *tv) 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, events, ev->hEvent); + 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())); @@ -722,13 +702,13 @@ int _getdns_event_add(struct _getdns_event *ev, struct timeval *tv) 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, events, ev->hEvent); + 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, ev->hEvent); + 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; @@ -787,14 +767,8 @@ 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; - //g fptr_ok(fptr_whitelist_event(ev->ev_callback)); - //g (*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg); } int _getdns_signal_add(struct _getdns_event *ev, struct timeval * ATTR_UNUSED(tv)) diff --git a/src/util/winsock_event.h b/src/util/winsock_event.h index 6083cfc5..e9bb5982 100644 --- a/src/util/winsock_event.h +++ b/src/util/winsock_event.h @@ -95,15 +95,15 @@ /* redefine the calls to different names so that there is no name * collision with other code that uses libevent names. (that uses libunbound)*/ -#define event_init winsockevent_init +#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 event_set winsockevent_set -#define event_base_set winsockevent_base_set -#define event_add winsockevent_add +#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 @@ -225,26 +225,26 @@ struct _getdns_event { char* wsa_strerror(DWORD err); void log_err(const char *format, ...); /** create event base */ -void *event_init(time_t* time_secs, struct timeval* time_tv); +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 event_base_dispatch(struct _getdns_event_base *); +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 event_base_free(struct _getdns_event_base *); +void _getdns_event_base_free(struct _getdns_event_base *); /** set content of event */ -void event_set(struct _getdns_event *, int, short, void (*)(int, short, void *), void *); +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 event_base_set(struct _getdns_event_base *, struct _getdns_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 event_add(struct _getdns_event *, struct timeval *); +int _getdns_event_add(struct _getdns_event *, struct timeval *); /** remove event. You may change it again */ -int event_del(struct _getdns_event *); +int _getdns_event_del(struct _getdns_event *); #define evtimer_add(ev, tv) event_add(ev, tv) #define evtimer_del(ev) event_del(ev) @@ -282,14 +282,14 @@ void winsock_tcp_wouldblock(struct _getdns_event* ev, int eventbit); * @param arg: user argument to callback routine. * @return false on error. */ -static int winsock_register_wsaevent(struct _getdns_event_base* base, struct _getdns_event* ev, +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. */ -static void winsock_unregister_wsaevent(struct _getdns_event* ev); +void winsock_unregister_wsaevent(struct _getdns_event* ev); #endif /* USE_WINSOCK */ #endif /* UTIL_WINSOCK_EVENT_H */