Merge in stock unbound

This commit is contained in:
Neel Goyal 2014-02-03 17:46:58 -05:00
commit 07dcd6cc0e
26 changed files with 981 additions and 515 deletions

View File

@ -18,7 +18,7 @@ VPATH = @srcdir@
default:
cd src && $(MAKE) $@
all : default
all : default
install: all
cd src && $(MAKE) $@
@ -28,7 +28,7 @@ uninstall:
cd src && $(MAKE) $@
cd doc && $(MAKE) $@
doc:
doc:
cd doc && $(MAKE) $@
example:
@ -37,6 +37,9 @@ example:
test:
cd src && $(MAKE) $@
example:
cd src && $(MAKE) $@
clean:
cd src && $(MAKE) $@
cd doc && $(MAKE) $@
@ -53,7 +56,7 @@ $(distdir).tar.gz: $(distdir)
tar chof - $(distdir) | gzip -9 -c > $@
rm -rf $(distdir)
$(distdir):
$(distdir):
mkdir -p $(distdir)/src
mkdir -p $(distdir)/src/getdns
mkdir -p $(distdir)/src/test
@ -68,6 +71,7 @@ $(distdir):
cp $(srcdir)/ltmain.sh $(distdir)
cp $(srcdir)/src/*.in $(distdir)/src
cp $(srcdir)/src/*.[ch] $(distdir)/src
cp $(srcdir)/src/extension/*.[ch] $(distdir)/src/extension
cp $(srcdir)/src/getdns/*.in $(distdir)/src/getdns
cp $(srcdir)/src/getdns/*.h $(distdir)/src/getdns
cp $(srcdir)/src/test/Makefile.in $(distdir)/src/test
@ -98,7 +102,7 @@ distcheck: $(distdir).tar.gz
Makefile: Makefile.in config.status
./config.status $@
configure.status: configure
./config.status --recheck

220
configure vendored
View File

@ -2,7 +2,7 @@
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for getdns 0.1.0.
#
# Report bugs to <melinda.shore@nomountain.net>.
# Report bugs to <stub-resolver@verisignlabs.com>.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@ -275,7 +275,7 @@ fi
$as_echo "$0: be upgraded to zsh 4.3.4 or later."
else
$as_echo "$0: Please tell bug-autoconf@gnu.org and
$0: melinda.shore@nomountain.net about your system,
$0: stub-resolver@verisignlabs.com about your system,
$0: including any error possibly output before this
$0: message. Then install a modern shell, or manually run
$0: the script under such a shell if you do have one."
@ -592,7 +592,7 @@ PACKAGE_NAME='getdns'
PACKAGE_TARNAME='getdns'
PACKAGE_VERSION='0.1.0'
PACKAGE_STRING='getdns 0.1.0'
PACKAGE_BUGREPORT='melinda.shore@nomountain.net'
PACKAGE_BUGREPORT='stub-resolver@verisignlabs.com'
PACKAGE_URL=''
ac_unique_file="src/getdns/getdns.h"
@ -634,6 +634,7 @@ ac_includes_default="\
ac_subst_vars='LTLIBOBJS
LIBOBJS
have_libevent
DOXYGEN
INSTALL_DATA
INSTALL_SCRIPT
@ -1386,7 +1387,7 @@ Some influential environment variables:
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
Report bugs to <melinda.shore@nomountain.net>.
Report bugs to <stub-resolver@verisignlabs.com>.
_ACEOF
ac_status=$?
fi
@ -10853,127 +10854,8 @@ fi
# Checks for libraries.
found_all_libs=1
{ $as_echo "$as_me:${as_lineno-$LINENO}: Checking for dependencies libevent, ldns" >&5
$as_echo "$as_me: Checking for dependencies libevent, ldns" >&6;}
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing event_loop" >&5
$as_echo_n "checking for library containing event_loop... " >&6; }
if ${ac_cv_search_event_loop+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char event_loop ();
int
main ()
{
return event_loop ();
;
return 0;
}
_ACEOF
for ac_lib in '' event_core event; do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_search_event_loop=$ac_res
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
if ${ac_cv_search_event_loop+:} false; then :
break
fi
done
if ${ac_cv_search_event_loop+:} false; then :
else
ac_cv_search_event_loop=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_event_loop" >&5
$as_echo "$ac_cv_search_event_loop" >&6; }
ac_res=$ac_cv_search_event_loop
if test "$ac_res" != no; then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
else
ac_cv_search_event_loop=''
LDFLAGS="$LDFLAGS -L/usr/local/lib/event"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing event_loop" >&5
$as_echo_n "checking for library containing event_loop... " >&6; }
if ${ac_cv_search_event_loop+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char event_loop ();
int
main ()
{
return event_loop ();
;
return 0;
}
_ACEOF
for ac_lib in '' event_core event; do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_search_event_loop=$ac_res
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
if ${ac_cv_search_event_loop+:} false; then :
break
fi
done
if ${ac_cv_search_event_loop+:} false; then :
else
ac_cv_search_event_loop=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_event_loop" >&5
$as_echo "$ac_cv_search_event_loop" >&6; }
ac_res=$ac_cv_search_event_loop
if test "$ac_res" != no; then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
else
found_all_libs=0
fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: Checking for dependencies ldns" >&5
$as_echo "$as_me: Checking for dependencies ldns" >&6;}
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldns_dname_new_frm_str in -lldns" >&5
$as_echo_n "checking for ldns_dname_new_frm_str in -lldns... " >&6; }
if ${ac_cv_lib_ldns_ldns_dname_new_frm_str+:} false; then :
@ -11079,9 +10961,9 @@ fi
found_libunbound=1
{ $as_echo "$as_me:${as_lineno-$LINENO}: Checking for dependency libunbound" >&5
$as_echo "$as_me: Checking for dependency libunbound" >&6;}
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ub_ctx_set_event in -lunbound" >&5
$as_echo_n "checking for ub_ctx_set_event in -lunbound... " >&6; }
if ${ac_cv_lib_unbound_ub_ctx_set_event+:} false; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ub_fd in -lunbound" >&5
$as_echo_n "checking for ub_fd in -lunbound... " >&6; }
if ${ac_cv_lib_unbound_ub_fd+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@ -11095,27 +10977,27 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
#ifdef __cplusplus
extern "C"
#endif
char ub_ctx_set_event ();
char ub_fd ();
int
main ()
{
return ub_ctx_set_event ();
return ub_fd ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_lib_unbound_ub_ctx_set_event=yes
ac_cv_lib_unbound_ub_fd=yes
else
ac_cv_lib_unbound_ub_ctx_set_event=no
ac_cv_lib_unbound_ub_fd=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_unbound_ub_ctx_set_event" >&5
$as_echo "$ac_cv_lib_unbound_ub_ctx_set_event" >&6; }
if test "x$ac_cv_lib_unbound_ub_ctx_set_event" = xyes; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_unbound_ub_fd" >&5
$as_echo "$ac_cv_lib_unbound_ub_fd" >&6; }
if test "x$ac_cv_lib_unbound_ub_fd" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_LIBUNBOUND 1
_ACEOF
@ -11128,7 +11010,7 @@ fi
if test $found_libunbound == 0
then
as_fn_error $? "libunbound is missing or does not incude event code, you may need to patch your libunbound sources and rebuild. See the getdns build instructions" "$LINENO" 5
as_fn_error $? "libunbound is missing." "$LINENO" 5
fi
for ac_prog in doxygen
@ -11261,7 +11143,64 @@ _ACEOF
esac
for ac_func in event_base_new event_base_free
have_libevent=1
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing event_loop" >&5
$as_echo_n "checking for library containing event_loop... " >&6; }
if ${ac_cv_search_event_loop+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char event_loop ();
int
main ()
{
return event_loop ();
;
return 0;
}
_ACEOF
for ac_lib in '' event_core event; do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_search_event_loop=$ac_res
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
if ${ac_cv_search_event_loop+:} false; then :
break
fi
done
if ${ac_cv_search_event_loop+:} false; then :
else
ac_cv_search_event_loop=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_event_loop" >&5
$as_echo "$ac_cv_search_event_loop" >&6; }
ac_res=$ac_cv_search_event_loop
if test "$ac_res" != no; then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
$as_echo "#define HAVE_LIBEVENT 1" >>confdefs.h
for ac_func in event_base_new event_base_free
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@ -11274,6 +11213,11 @@ fi
done
else
have_libevent=0
fi
ac_config_files="$ac_config_files Makefile src/Makefile src/getdns/Makefile src/example/Makefile src/test/Makefile doc/Makefile"
@ -11849,7 +11793,7 @@ $config_headers
Configuration commands:
$config_commands
Report bugs to <melinda.shore@nomountain.net>."
Report bugs to <stub-resolver@verisignlabs.com>."
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1

View File

@ -6,7 +6,7 @@
#
AC_PREREQ([2.56])
AC_INIT([getdns], [0.1.0], [melinda.shore@nomountain.net])
AC_INIT([getdns], [0.1.0], [stub-resolver@verisignlabs.com])
AC_CONFIG_SRCDIR([src/getdns/getdns.h])
# AM_INIT_AUTOMAKE
# LT_INIT
@ -128,12 +128,7 @@ fi
# Checks for libraries.
found_all_libs=1
AC_MSG_NOTICE([Checking for dependencies libevent, ldns])
AC_SEARCH_LIBS([event_loop], [event_core event], [], [
ac_cv_search_event_loop=''
LDFLAGS="$LDFLAGS -L/usr/local/lib/event"
AC_SEARCH_LIBS([event_loop], [event_core event], [], [found_all_libs=0])
])
AC_MSG_NOTICE([Checking for dependencies ldns])
AC_CHECK_LIB([ldns], [ldns_dname_new_frm_str], [], [found_all_libs=0])
AC_CHECK_LIB([idn], [idna_to_ascii_8z], [], [found_all_libs=0])
@ -142,14 +137,14 @@ then
AC_MSG_ERROR([One more dependencies is missing])
fi
# break out libunbound from other libraries since we are currently using a
# break out libunbound from other libraries since we are currently using a
# patch to the sources
found_libunbound=1
AC_MSG_NOTICE([Checking for dependency libunbound])
AC_CHECK_LIB([unbound], [ub_ctx_set_event], [], [found_libunbound=0])
AC_CHECK_LIB([unbound], [ub_fd], [], [found_libunbound=0])
if test $found_libunbound == 0
then
AC_MSG_ERROR([libunbound is missing or does not incude event code, you may need to patch your libunbound sources and rebuild. See the getdns build instructions])
AC_MSG_ERROR([libunbound is missing.])
fi
AC_CHECK_PROGS([DOXYGEN], [doxygen])
@ -167,16 +162,22 @@ AC_TYPE_UINT32_T
AC_TYPE_UINT64_T
AC_TYPE_UINT8_T
AC_CHECK_FUNCS([event_base_new event_base_free])
AH_BOTTOM([
#ifndef HAVE_EVENT_BASE_FREE
#define event_base_free(x) /* nop */
#endif
#ifndef HAVE_EVENT_BASE_NEW
#define event_base_new event_init
#endif
])
have_libevent=1
AC_SEARCH_LIBS([event_loop],
[event_core event],
[AC_DEFINE([HAVE_LIBEVENT], [1], [Define to 1 to enable the libevent extension])]
[AC_CHECK_FUNCS([event_base_new event_base_free])]
[AH_BOTTOM([
#ifndef HAVE_EVENT_BASE_FREE
#define event_base_free(x) /* nop */
#endif
#ifndef HAVE_EVENT_BASE_NEW
#define event_base_new event_init
#endif
])],
[have_libevent=0])
AC_SUBST(have_libevent)
AC_CONFIG_FILES([Makefile src/Makefile src/getdns/Makefile src/example/Makefile src/test/Makefile doc/Makefile])
if [ test -n "$DOXYGEN" ]
then AC_CONFIG_FILES([src/Doxyfile])

View File

@ -20,6 +20,7 @@ exec_prefix = @exec_prefix@
bindir = @bindir@
libdir = @libdir@
includedir = @includedir@
have_libevent = @have_libevent@
# datarootdir is here to please some checkers
datarootdir=@datarootdir@
INSTALL = @INSTALL@
@ -35,6 +36,10 @@ GETDNS_OBJ=sync.lo context.lo list.lo dict.lo convert.lo general.lo \
hostname.lo service.lo request-internal.lo validate_dnssec.lo \
util-internal.lo getdns_error.lo rr-dict.lo validation-chain.lo
ifeq ($(have_libevent),1)
GETDNS_OBJ += extension/libevent.lo
endif
.SUFFIXES: .c .o .a .lo .h
.c.o:
@ -54,24 +59,31 @@ install: libgetdns.la
$(INSTALL) -m 755 -d $(DESTDIR)$(includedir)
$(INSTALL) -m 755 -d $(DESTDIR)$(includedir)/getdns
$(INSTALL) -m 644 $(srcdir)/getdns/getdns.h $(DESTDIR)$(includedir)/getdns/getdns.h
ifeq ($(have_libevent),1)
$(INSTALL) -m 644 $(srcdir)/getdns/getdns_ext_libevent.h $(DESTDIR)$(includedir)/getdns/
endif
$(INSTALL) -m 755 -d $(DESTDIR)$(libdir)
$(LIBTOOL) --mode=install cp libgetdns.la $(DESTDIR)$(libdir)
$(LIBTOOL) --mode=finish $(DESTDIR)$(libdir)
uninstall:
rm -f $(DESTDIR)$(includedir)/getdns/getdns.h
rm -rf $(DESTDIR)$(includedir)/getdns
$(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/libgetdns.la
libgetdns.la: $(GETDNS_OBJ)
$(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ $(GETDNS_OBJ) $(LDFLAGS) -rpath $(libdir) -version-info $(libversion) -no-undefined
test: libgetdns.la
test:
cd test && $(MAKE) $@
example:
cd example && $(MAKE) $@
clean:
cd test && $(MAKE) $@
cd example && $(MAKE) $@
rm -f *.o *.lo $(PROGRAMS) libgetdns.la
rm -f *.o *.lo extension/*.lo $(PROGRAMS) libgetdns.la
rm -rf .libs
distclean : clean

View File

@ -15,6 +15,9 @@
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 to enable the libevent extension */
#undef HAVE_LIBEVENT
/* Define to 1 if you have the `idn' library (-lidn). */
#undef HAVE_LIBIDN
@ -111,10 +114,10 @@
#undef uint8_t
#ifndef HAVE_EVENT_BASE_FREE
#define event_base_free(x) /* nop */
#endif
#ifndef HAVE_EVENT_BASE_NEW
#define event_base_new event_init
#endif
#ifndef HAVE_EVENT_BASE_FREE
#define event_base_free(x) /* nop */
#endif
#ifndef HAVE_EVENT_BASE_NEW
#define event_base_new event_init
#endif

View File

@ -35,17 +35,12 @@
*/
#include "config.h"
#ifdef HAVE_EVENT2_EVENT_H
# include <event2/event.h>
#else
# include <event.h>
#endif
#include <arpa/inet.h>
#include <ldns/ldns.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unbound-event.h>
#include <sys/time.h>
#include <unbound.h>
#include "context.h"
@ -64,11 +59,13 @@ static struct getdns_list *create_from_ldns_list(struct getdns_context *,
ldns_rdf **, size_t);
static getdns_return_t set_os_defaults(struct getdns_context *);
static int transaction_id_cmp(const void *, const void *);
static int timeout_cmp(const void *, const void *);
static void set_ub_string_opt(struct getdns_context *, char *, char *);
static void set_ub_number_opt(struct getdns_context *, char *, uint16_t);
static inline void clear_resolution_type_set_flag(struct getdns_context *, uint16_t);
static void dispatch_updated(struct getdns_context *, uint16_t);
static void cancel_dns_req(getdns_dns_req *);
static void cancel_outstanding_requests(struct getdns_context*, int);
/* Stuff to make it compile pedantically */
#define UNUSED_PARAM(x) ((void)(x))
@ -218,6 +215,9 @@ set_os_defaults(struct getdns_context *context)
return GETDNS_RETURN_GOOD;
} /* set_os_defaults */
/* compare of transaction ids in DESCENDING order
so that 0 comes last
*/
static int
transaction_id_cmp(const void *id1, const void *id2)
{
@ -234,7 +234,7 @@ transaction_id_cmp(const void *id1, const void *id2)
*((const getdns_transaction_t *) id2);
if (t1 == t2) {
return 0;
} else if (t1 < t2) {
} else if (t1 > t2) {
return -1;
} else {
return 1;
@ -242,6 +242,33 @@ transaction_id_cmp(const void *id1, const void *id2)
}
}
static int timeout_cmp(const void *to1, const void *to2) {
if (to1 == NULL && to2 == NULL) {
return 0;
} else if (to1 == NULL && to2 != NULL) {
return 1;
} else if (to1 != NULL && to2 == NULL) {
return -1;
} else {
const getdns_timeout_data_t* t1 = (const getdns_timeout_data_t*) to1;
const getdns_timeout_data_t* t2 = (const getdns_timeout_data_t*) to2;
if (t1->timeout_time.tv_sec < t2->timeout_time.tv_sec) {
return -1;
} else if (t1->timeout_time.tv_sec > t2->timeout_time.tv_sec) {
return 1;
} else {
/* compare usec.. */
if (t1->timeout_time.tv_usec < t2->timeout_time.tv_usec) {
return -1;
} else if (t1->timeout_time.tv_usec > t2->timeout_time.tv_usec) {
return 1;
} else {
return transaction_id_cmp(&t1->transaction_id, &t2->transaction_id);
}
}
}
}
/*
* getdns_context_create
*
@ -283,11 +310,7 @@ getdns_context_create_with_extended_memory_functions(
result->mf.mf.ext.realloc = realloc;
result->mf.mf.ext.free = free;
result->event_base_sync = event_base_new();
result->unbound_sync = ub_ctx_create_event(result->event_base_sync);
/* create the async one also so options are kept up to date */
result->unbound_async = ub_ctx_create_event(result->event_base_sync);
result->event_base_async = NULL;
result->unbound_ctx = ub_ctx_create();
result->resolution_type_set = 0;
@ -309,6 +332,11 @@ getdns_context_create_with_extended_memory_functions(
result->edns_version = 0;
result->edns_do_bit = 0;
result->extension = NULL;
result->extension_data = NULL;
result->timeouts_by_time = ldns_rbtree_create(timeout_cmp);
result->timeouts_by_id = ldns_rbtree_create(transaction_id_cmp);
if (set_from_os) {
if (GETDNS_RETURN_GOOD != set_os_defaults(result)) {
getdns_context_destroy(result);
@ -377,18 +405,19 @@ getdns_context_destroy(struct getdns_context *context)
if (context->namespaces)
GETDNS_FREE(context->my_mf, context->namespaces);
cancel_outstanding_requests(context, 0);
getdns_list_destroy(context->dns_root_servers);
getdns_list_destroy(context->suffix);
getdns_list_destroy(context->dnssec_trust_anchors);
getdns_list_destroy(context->upstream_list);
/* destroy the ub context */
ub_ctx_delete(context->unbound_async);
ub_ctx_delete(context->unbound_sync);
event_base_free(context->event_base_sync);
ub_ctx_delete(context->unbound_ctx);
ldns_rbtree_free(context->outbound_requests);
ldns_rbtree_free(context->timeouts_by_id);
ldns_rbtree_free(context->timeouts_by_time);
GETDNS_FREE(context->my_mf, context);
return;
@ -415,8 +444,7 @@ getdns_context_set_context_update_callback(struct getdns_context *context,
static void
set_ub_string_opt(struct getdns_context *ctx, char *opt, char *value)
{
ub_ctx_set_option(ctx->unbound_sync, opt, value);
ub_ctx_set_option(ctx->unbound_async, opt, value);
ub_ctx_set_option(ctx->unbound_ctx, opt, value);
}
static void
@ -891,27 +919,6 @@ getdns_context_set_memory_functions(struct getdns_context *context,
context, MF_PLAIN, mf.ext.malloc, mf.ext.realloc, mf.ext.free);
} /* getdns_context_set_memory_functions*/
/*
* getdns_extension_set_libevent_base
*
*/
getdns_return_t
getdns_extension_set_libevent_base(struct getdns_context *context,
struct event_base * this_event_base)
{
RETURN_IF_NULL(context, GETDNS_RETURN_BAD_CONTEXT);
if (this_event_base) {
ub_ctx_set_event(context->unbound_async, this_event_base);
context->event_base_async = this_event_base;
} else {
ub_ctx_set_event(context->unbound_async,
context->event_base_sync);
context->event_base_async = NULL;
}
return GETDNS_RETURN_GOOD;
} /* getdns_extension_set_libevent_base */
/* cancel the request */
static void
cancel_dns_req(getdns_dns_req * req)
@ -921,7 +928,7 @@ cancel_dns_req(getdns_dns_req * req)
if (netreq->state == NET_REQ_IN_FLIGHT) {
/* for ev based ub, this should always prevent
* the callback from firing */
ub_cancel(req->unbound, netreq->unbound_id);
ub_cancel(req->context->unbound_ctx, netreq->unbound_id);
netreq->state = NET_REQ_CANCELED;
} else if (netreq->state == NET_REQ_NOT_SENT) {
netreq->state = NET_REQ_CANCELED;
@ -1071,19 +1078,15 @@ getdns_context_prepare_for_resolution(struct getdns_context *context)
return GETDNS_RETURN_BAD_CONTEXT;
}
/* set upstreams */
ub_setup_stub(context->unbound_async, context->upstream_list,
upstream_len);
ub_setup_stub(context->unbound_sync, context->upstream_list,
ub_setup_stub(context->unbound_ctx, context->upstream_list,
upstream_len);
/* use /etc/hosts */
ub_ctx_hosts(context->unbound_sync, NULL);
ub_ctx_hosts(context->unbound_async, NULL);
ub_ctx_hosts(context->unbound_ctx, NULL);
} else if (context->resolution_type == GETDNS_CONTEXT_RECURSING) {
/* set recursive */
/* TODO: use the root servers via root hints file */
ub_ctx_set_fwd(context->unbound_async, NULL);
ub_ctx_set_fwd(context->unbound_sync, NULL);
ub_ctx_set_fwd(context->unbound_ctx, NULL);
} else {
/* bogus? */
@ -1129,48 +1132,271 @@ getdns_context_clear_outbound_request(getdns_dns_req * req)
return GETDNS_RETURN_GOOD;
}
char *
getdns_strdup(const struct mem_funcs *mfs, const char *s)
{
size_t sz = strlen(s) + 1;
char *r = GETDNS_XMALLOC(*mfs, char, sz);
if (r)
return memcpy(r, s, sz);
else
return NULL;
size_t sz = strlen(s) + 1;
char *r = GETDNS_XMALLOC(*mfs, char, sz);
if (r)
return memcpy(r, s, sz);
else
return NULL;
}
struct getdns_bindata *
getdns_bindata_copy(struct mem_funcs *mfs,
const struct getdns_bindata *src)
{
struct getdns_bindata *dst;
struct getdns_bindata *dst;
if (!src)
return NULL;
if (!src)
return NULL;
dst = GETDNS_MALLOC(*mfs, struct getdns_bindata);
if (!dst)
return NULL;
dst = GETDNS_MALLOC(*mfs, struct getdns_bindata);
if (!dst)
return NULL;
dst->size = src->size;
dst->data = GETDNS_XMALLOC(*mfs, uint8_t, src->size);
if (!dst->data) {
GETDNS_FREE(*mfs, dst);
return NULL;
}
(void) memcpy(dst->data, src->data, src->size);
return dst;
dst->size = src->size;
dst->data = GETDNS_XMALLOC(*mfs, uint8_t, src->size);
if (!dst->data) {
GETDNS_FREE(*mfs, dst);
return NULL;
}
(void) memcpy(dst->data, src->data, src->size);
return dst;
}
void
getdns_bindata_destroy(struct mem_funcs *mfs,
struct getdns_bindata *bindata)
{
if (!bindata)
return;
GETDNS_FREE(*mfs, bindata->data);
GETDNS_FREE(*mfs, bindata);
if (!bindata)
return;
GETDNS_FREE(*mfs, bindata->data);
GETDNS_FREE(*mfs, bindata);
}
/* get the fd */
int getdns_context_fd(struct getdns_context* context) {
RETURN_IF_NULL(context, -1);
return ub_fd(context->unbound_ctx);
}
int
getdns_context_get_num_pending_requests(struct getdns_context* context,
struct timeval* next_timeout) {
RETURN_IF_NULL(context, GETDNS_RETURN_BAD_CONTEXT);
int r = context->outbound_requests->count;
if (r > 0) {
if (!context->extension && next_timeout) {
/* get the first timeout */
ldns_rbnode_t* first = ldns_rbtree_first(context->timeouts_by_time);
if (first) {
getdns_timeout_data_t* timeout_data = (getdns_timeout_data_t*) first->data;
*next_timeout = (timeout_data->timeout_time);
}
}
}
return r;
}
/* process async reqs */
getdns_return_t getdns_context_process_async(struct getdns_context* context) {
RETURN_IF_NULL(context, GETDNS_RETURN_BAD_CONTEXT);
if (ub_poll(context->unbound_ctx)) {
if (ub_process(context->unbound_ctx) != 0) {
/* need an async return code? */
return GETDNS_RETURN_GENERIC_ERROR;
}
}
if (context->extension != NULL) {
/* no need to process timeouts since it is delegated
* to the extension */
return GETDNS_RETURN_GOOD;
}
getdns_timeout_data_t key;
/* set to 0 so it is the last timeout if we have
* two with the same time */
key.transaction_id = 0;
if (gettimeofday(&key.timeout_time, NULL) != 0) {
return GETDNS_RETURN_GENERIC_ERROR;
}
ldns_rbnode_t* next_timeout = ldns_rbtree_first(context->timeouts_by_time);
while (next_timeout) {
getdns_timeout_data_t* timeout_data = (getdns_timeout_data_t*) next_timeout->data;
if (timeout_cmp(timeout_data, &key) > 0) {
/* no more timeouts need to be fired. */
break;
}
/* get the next_timeout */
next_timeout = ldns_rbtree_next(next_timeout);
/* delete the node */
/* timeout data is freed in the clear_timeout */
ldns_rbnode_t* to_del = ldns_rbtree_delete(context->timeouts_by_time, timeout_data);
if (to_del) {
/* should always exist .. */
GETDNS_FREE(context->my_mf, to_del);
}
/* fire the timeout */
timeout_data->callback(timeout_data->userarg);
}
return GETDNS_RETURN_GOOD;
}
typedef struct timeout_accumulator {
getdns_transaction_t* ids;
int idx;
} timeout_accumulator;
static void
accumulate_outstanding_transactions(ldns_rbnode_t* node, void* arg) {
timeout_accumulator* acc = (timeout_accumulator*) arg;
acc->ids[acc->idx] = *((getdns_transaction_t*) node->key);
acc->idx++;
}
static void
cancel_outstanding_requests(struct getdns_context* context, int fire_callback) {
if (context->outbound_requests->count > 0) {
timeout_accumulator acc;
int i;
acc.idx = 0;
acc.ids = GETDNS_XMALLOC(context->my_mf, getdns_transaction_t, context->outbound_requests->count);
ldns_traverse_postorder(context->outbound_requests, accumulate_outstanding_transactions, &acc);
for (i = 0; i < acc.idx; ++i) {
getdns_context_cancel_request(context, acc.ids[i], fire_callback);
}
}
}
getdns_return_t
getdns_extension_detach_eventloop(struct getdns_context* context)
{
RETURN_IF_NULL(context, GETDNS_RETURN_BAD_CONTEXT);
getdns_return_t r = GETDNS_RETURN_GOOD;
if (context->extension) {
/* cancel all outstanding requests */
cancel_outstanding_requests(context, 1);
r = context->extension->cleanup_data(context, context->extension_data);
if (r != GETDNS_RETURN_GOOD) {
return r;
}
context->extension = NULL;
context->extension_data = NULL;
}
return r;
}
getdns_return_t
getdns_extension_set_eventloop(struct getdns_context* context,
getdns_eventloop_extension* extension, void* extension_data)
{
RETURN_IF_NULL(context, GETDNS_RETURN_BAD_CONTEXT);
RETURN_IF_NULL(extension, GETDNS_RETURN_INVALID_PARAMETER);
getdns_return_t r = getdns_extension_detach_eventloop(context);
if (r != GETDNS_RETURN_GOOD) {
return r;
}
context->extension = extension;
context->extension_data = extension_data;
return GETDNS_RETURN_GOOD;
}
getdns_return_t
getdns_context_schedule_timeout(struct getdns_context* context,
getdns_transaction_t id, uint16_t timeout, getdns_timeout_callback callback,
void* userarg) {
RETURN_IF_NULL(context, GETDNS_RETURN_BAD_CONTEXT);
RETURN_IF_NULL(callback, GETDNS_RETURN_INVALID_PARAMETER);
getdns_return_t result;
/* create a timeout */
getdns_timeout_data_t* timeout_data = GETDNS_MALLOC(context->my_mf, getdns_timeout_data_t);
if (!timeout_data) {
return GETDNS_RETURN_GENERIC_ERROR;
}
timeout_data->context = context;
timeout_data->transaction_id = id;
timeout_data->callback = callback;
timeout_data->userarg = userarg;
timeout_data->extension_timer = NULL;
/* insert into transaction tree */
ldns_rbnode_t *node = GETDNS_MALLOC(context->my_mf, ldns_rbnode_t);
if (!node) {
GETDNS_FREE(context->my_mf, timeout_data);
return GETDNS_RETURN_GENERIC_ERROR;
}
node->key = &(timeout_data->transaction_id);
node->data = timeout_data;
node->left = NULL;
node->right = NULL;
if (!ldns_rbtree_insert(context->timeouts_by_id, node)) {
/* free the node */
GETDNS_FREE(context->my_mf, timeout_data);
GETDNS_FREE(context->my_mf, node);
return GETDNS_RETURN_GENERIC_ERROR;
}
if (context->extension) {
result = context->extension->schedule_timeout(context, context->extension_data,
timeout, timeout_data, &(timeout_data->extension_timer));
} else {
result = GETDNS_RETURN_GENERIC_ERROR;
if (gettimeofday(&timeout_data->timeout_time, NULL) == 0) {
/* increment */
uint16_t num_secs = timeout / 1000;
/* timeout is in millis */
timeout_data->timeout_time.tv_sec += num_secs;
ldns_rbnode_t* id_node = GETDNS_MALLOC(context->my_mf, ldns_rbnode_t);
if (id_node) {
id_node->key = timeout_data;
id_node->data = timeout_data;
id_node->left = NULL;
id_node->right = NULL;
if (!ldns_rbtree_insert(context->timeouts_by_time, id_node)) {
GETDNS_FREE(context->my_mf, id_node);
} else {
result = GETDNS_RETURN_GOOD;
}
}
}
}
if (result != GETDNS_RETURN_GOOD) {
GETDNS_FREE(context->my_mf, timeout_data);
GETDNS_FREE(context->my_mf, node);
}
return result;
}
getdns_return_t
getdns_context_clear_timeout(struct getdns_context* context,
getdns_transaction_t id) {
RETURN_IF_NULL(context, GETDNS_RETURN_BAD_CONTEXT);
/* find the timeout_data by id */
ldns_rbnode_t* node = ldns_rbtree_delete(context->timeouts_by_id, &id);
if (!node) {
return GETDNS_RETURN_UNKNOWN_TRANSACTION;
}
getdns_timeout_data_t* timeout_data = (getdns_timeout_data_t*) node->data;
GETDNS_FREE(context->my_mf, node);
if (context->extension) {
context->extension->clear_timeout(context, context->extension,
timeout_data->extension_timer);
} else {
/* make sure it is removed from the timeout node */
ldns_rbnode_t* to_del = ldns_rbtree_delete(context->timeouts_by_time, timeout_data);
if (to_del) {
GETDNS_FREE(context->my_mf, to_del);
}
}
GETDNS_FREE(context->my_mf, timeout_data);
return GETDNS_RETURN_GOOD;
}
/* context.c */

View File

@ -40,7 +40,6 @@
#include <getdns/getdns.h>
#include "types-internal.h"
struct event_base;
struct getdns_dns_req;
struct ldns_rbtree_t;
struct ub_ctx;
@ -70,15 +69,9 @@ struct getdns_context {
struct mem_funcs mf;
struct mem_funcs my_mf;
/* Event loop for sync requests */
struct event_base *event_base_sync;
/* Event loop for async requests */
struct event_base *event_base_async;
/* The underlying unbound contexts that do
* the real work */
struct ub_ctx *unbound_sync;
struct ub_ctx *unbound_async;
struct ub_ctx *unbound_ctx;
/* which resolution type the contexts are configured for
* 0 means nothing set
@ -89,6 +82,26 @@ struct getdns_context {
* outbound requests -> transaction to getdns_dns_req
*/
struct ldns_rbtree_t *outbound_requests;
/*
* Event loop extension functions
* These structs are static and should never be freed
* since they are just a collection of function pointers
*/
getdns_eventloop_extension* extension;
/*
* Extension data that will be freed by the functions
* in the extension struct
*/
void* extension_data;
/*
* Timeout info one tree to manage timeout data
* keyed by transaction id. Second to manage by
* timeout time (ascending)
*/
struct ldns_rbtree_t *timeouts_by_id;
struct ldns_rbtree_t *timeouts_by_time;
};
/** internal functions **/
@ -118,4 +131,20 @@ void getdns_bindata_destroy(
struct mem_funcs *mfs,
struct getdns_bindata *bindata);
/* extension stuff */
getdns_return_t getdns_extension_set_eventloop(struct getdns_context* context,
getdns_eventloop_extension* extension, void* extension_data);
getdns_return_t
getdns_extension_detach_eventloop(struct getdns_context* context);
/* timeout scheduling */
getdns_return_t getdns_context_schedule_timeout(struct getdns_context* context,
getdns_transaction_t id, uint16_t timeout, getdns_timeout_callback callback,
void* userarg);
getdns_return_t getdns_context_clear_timeout(struct getdns_context* context,
getdns_transaction_t id);
#endif /* _GETDNS_CONTEXT_H_ */

View File

@ -17,7 +17,7 @@ VPATH = @srcdir@
CC=gcc
CFLAGS=@CFLAGS@ -Wall -I$(srcdir)/ -I$(srcdir)/../ -I/usr/local/include -std=c99
LDFLAGS=@LDFLAGS@ -L. -L.. -L/usr/local/lib
LDFLAGS=@LDFLAGS@ -L. -L.. -L$(srcdir)/../ -L/usr/local/lib
LDLIBS=-lgetdns @LIBS@
PROGRAMS=example-all-functions example-simple-answers example-tree example-synchronous example-reverse

View File

@ -1,5 +1,5 @@
#include <getdns/getdns.h>
#include "config.h"
#include <getdns/getdns_ext_libevent.h>
#ifdef HAVE_EVENT2_EVENT_H
#include <event2/event.h>
#else

162
src/extension/libevent.c Normal file
View File

@ -0,0 +1,162 @@
/**
* \file
* \brief Public interfaces to getdns, include in your application to use getdns API.
*
* This source was taken from the original pseudo-implementation by
* Paul Hoffman.
*/
/*
* Copyright (c) 2013, NLNet Labs, Versign, 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 name of the <organization> 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 <getdns/getdns_ext_libevent.h>
#include "config.h"
#include "context.h"
#include <sys/time.h>
#ifdef HAVE_EVENT2_EVENT_H
# include <event2/event.h>
#else
# include <event.h>
# define evutil_socket_t int
# define event_free free
# define evtimer_new(b, cb, arg) event_new((b), -1, 0, (cb), (arg))
#endif
#define RETURN_IF_NULL(ptr, code) if(ptr == NULL) return code;
#ifndef HAVE_EVENT2_EVENT_H
static struct event *
event_new(struct event_base *b, evutil_socket_t fd, short ev, void* cb, void *arg)
{
struct event* e = (struct event*)calloc(1, sizeof(struct event));
if(!e) return NULL;
event_set(e, fd, ev, cb, arg);
event_base_set(b, e);
return e;
}
#endif /* no event2 */
/* extension info */
struct event_data {
struct event* event;
struct event_base* event_base;
};
/* lib event callbacks */
static void
getdns_libevent_cb(evutil_socket_t fd, short what, void *userarg) {
struct getdns_context* context = (struct getdns_context*) userarg;
getdns_context_process_async(context);
}
static void
getdns_libevent_timeout_cb(evutil_socket_t fd, short what, void* userarg) {
getdns_timeout_data_t* timeout_data = (getdns_timeout_data_t*) userarg;
timeout_data->callback(timeout_data->userarg);
}
/* getdns extension functions */
static getdns_return_t
getdns_libevent_cleanup(struct getdns_context* context, void* data) {
struct event_data *edata = (struct event_data*) data;
event_del(edata->event);
event_free(edata->event);
free(edata);
return GETDNS_RETURN_GOOD;
}
static getdns_return_t
getdns_libevent_schedule_timeout(struct getdns_context* context,
void* eventloop_data, uint16_t timeout,
getdns_timeout_data_t* timeout_data,
void** eventloop_timer) {
struct timeval tv;
struct event* ev = NULL;
struct event_data* ev_data = (struct event_data*) eventloop_data;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
ev = evtimer_new(ev_data->event_base, getdns_libevent_timeout_cb, timeout_data);
evtimer_add(ev, &tv);
*eventloop_timer = ev;
return GETDNS_RETURN_GOOD;
}
static getdns_return_t
getdns_libevent_clear_timeout(struct getdns_context* context,
void* eventloop_data, void** eventloop_timer) {
struct event* ev = (struct event*) eventloop_timer;
event_del(ev);
event_free(ev);
return GETDNS_RETURN_GOOD;
}
static getdns_eventloop_extension LIBEVENT_EXT = {
getdns_libevent_cleanup,
getdns_libevent_schedule_timeout,
getdns_libevent_clear_timeout
};
/*
* getdns_extension_set_libevent_base
*
*/
getdns_return_t
getdns_extension_set_libevent_base(struct getdns_context *context,
struct event_base * this_event_base)
{
RETURN_IF_NULL(context, GETDNS_RETURN_BAD_CONTEXT);
RETURN_IF_NULL(this_event_base, GETDNS_RETURN_INVALID_PARAMETER);
/* TODO: cleanup current extension base */
getdns_return_t r = getdns_extension_detach_eventloop(context);
if (r != GETDNS_RETURN_GOOD) {
return r;
}
int fd = getdns_context_fd(context);
struct event* getdns_event = event_new(this_event_base, fd, EV_READ | EV_PERSIST, getdns_libevent_cb, context);
if (!getdns_event) {
return GETDNS_RETURN_GENERIC_ERROR;
}
event_add(getdns_event, NULL);
/* TODO: use context functs? */
struct event_data* ev_data = (struct event_data*) malloc(sizeof(struct event_data));
if (!ev_data) {
/* cleanup */
event_del(getdns_event);
event_free(getdns_event);
return GETDNS_RETURN_GENERIC_ERROR;
}
ev_data->event = getdns_event;
ev_data->event_base = this_event_base;
return getdns_extension_set_eventloop(context, &LIBEVENT_EXT, ev_data);
} /* getdns_extension_set_libevent_base */

View File

@ -35,17 +35,8 @@
*/
#include "config.h"
#ifdef HAVE_EVENT2_EVENT_H
# include <event2/event.h>
#else
# include <event.h>
# define evutil_socket_t int
# define event_free free
# define evtimer_new(b, cb, arg) event_new((b), -1, 0, (cb), (arg))
#endif
#include <string.h>
#include <unbound.h>
#include <unbound-event.h>
#include <ldns/ldns.h>
#include "context.h"
#include "types-internal.h"
@ -57,11 +48,9 @@
#define UNUSED_PARAM(x) ((void)(x))
/* declarations */
static void ub_resolve_callback(void *arg, int err, void* result,
int packet_len, int sec, char *bogus);
static void ub_resolve_timeout(evutil_socket_t fd, short what, void *arg);
static void ub_local_resolve_timeout(evutil_socket_t fd, short what,
void *arg);
static void ub_resolve_callback(void* mydata, int err, struct ub_result* result);
static void ub_resolve_timeout(void *arg);
static void ub_local_resolve_timeout(void *arg);
static void handle_network_request_error(getdns_network_req * netreq, int err);
static void handle_dns_request_complete(getdns_dns_req * dns_req);
@ -71,27 +60,12 @@ typedef struct netreq_cb_data
{
getdns_network_req *netreq;
int err;
void *result;
int packet_len;
int sec;
char *bogus;
struct ub_result* ub_res;
} netreq_cb_data;
#ifndef HAVE_EVENT2_EVENT_H
static struct event *
event_new(struct event_base *b, evutil_socket_t fd, short ev, void* cb, void *arg)
{
struct event* e = (struct event*)calloc(1, sizeof(struct event));
if(!e) return NULL;
event_set(e, fd, ev, cb, arg);
event_base_set(b, e);
return e;
}
#endif /* no event2 */
/* cancel, cleanup and send timeout to callback */
static void
ub_resolve_timeout(evutil_socket_t fd, short what, void *arg)
ub_resolve_timeout(void *arg)
{
getdns_dns_req *dns_req = (getdns_dns_req *) arg;
struct getdns_context *context = dns_req->context;
@ -109,7 +83,7 @@ ub_resolve_timeout(evutil_socket_t fd, short what, void *arg)
}
static void
ub_local_resolve_timeout(evutil_socket_t fd, short what, void *arg)
ub_local_resolve_timeout(void *arg)
{
netreq_cb_data *cb_data = (netreq_cb_data *) arg;
@ -117,18 +91,15 @@ ub_local_resolve_timeout(evutil_socket_t fd, short what, void *arg)
* invalid after calling ub_resolve_callback
*/
getdns_dns_req *dnsreq = cb_data->netreq->owner;
event_free(dnsreq->local_cb_timer);
dnsreq->local_cb_timer = NULL;
/* clear the timeout */
getdns_context_clear_timeout(dnsreq->context, dnsreq->local_timeout_id);
dnsreq->local_timeout_id = 0;
/* just call ub_resolve_callback */
ub_resolve_callback(cb_data->netreq, cb_data->err, cb_data->result,
cb_data->packet_len, cb_data->sec, cb_data->bogus);
ub_resolve_callback(cb_data->netreq, cb_data->err, cb_data->ub_res);
/* cleanup the state */
free(cb_data->result);
if (cb_data->bogus) {
free(cb_data->bogus);
}
free(cb_data);
}
@ -176,7 +147,7 @@ static int
submit_network_request(getdns_network_req * netreq)
{
getdns_dns_req *dns_req = netreq->owner;
int r = ub_resolve_event(dns_req->unbound,
int r = ub_resolve_async(dns_req->context->unbound_ctx,
dns_req->name,
netreq->request_type,
netreq->request_class,
@ -188,10 +159,15 @@ submit_network_request(getdns_network_req * netreq)
}
static void
ub_resolve_callback(void *arg, int err, void *result, int packet_len,
int sec, char *bogus)
ub_resolve_callback(void* arg, int err, struct ub_result* ub_res)
// ub_resolve_callback(void *arg, int err, ldns_buffer * result, int sec,
// char *bogus)
{
getdns_network_req *netreq = (getdns_network_req *) arg;
getdns_network_req *netreq = (getdns_network_req *) arg;
if (err != 0) {
handle_network_request_error(netreq, err);
return;
}
/* if netreq->state == NET_REQ_NOT_SENT here, that implies
* that ub called us back immediately - probably from a local file.
* This most likely means that getdns_general has not returned
@ -201,72 +177,49 @@ ub_resolve_callback(void *arg, int err, void *result, int packet_len,
* we can make this less hacky, but it gets interesting when multiple
* netreqs need to be issued and some resolve immediately vs. not.
*/
struct timeval tv;
getdns_dns_req *dnsreq = netreq->owner;
netreq_cb_data *cb_data =
(netreq_cb_data *) malloc(sizeof(netreq_cb_data));
getdns_dns_req *dnsreq = netreq->owner;
netreq_cb_data *cb_data =
(netreq_cb_data *) malloc(sizeof(netreq_cb_data));
cb_data->netreq = netreq;
cb_data->err = err;
cb_data->ub_res = ub_res;
cb_data->netreq = netreq;
cb_data->err = err;
cb_data->sec = sec;
cb_data->result = NULL;
cb_data->bogus = NULL; /* unused but here in case we need it */
if (result) {
cb_data->result = (uint8_t *) malloc(packet_len);
if (!cb_data->result) {
cb_data->err = GETDNS_RETURN_GENERIC_ERROR;
} else {
/* copy */
(void) memcpy(
cb_data->result, result, packet_len);
}
}
/* schedule the timeout */
dnsreq->local_cb_timer =
evtimer_new(dnsreq->ev_base, ub_local_resolve_timeout,
cb_data);
tv.tv_sec = 0;
/* half ms */
tv.tv_usec = 500;
evtimer_add(dnsreq->local_cb_timer, &tv);
dnsreq->local_timeout_id = ldns_get_random();
getdns_context_schedule_timeout(dnsreq->context,
dnsreq->local_timeout_id, 1, ub_local_resolve_timeout, cb_data);
return;
}
netreq->state = NET_REQ_FINISHED;
if (err) {
handle_network_request_error(netreq, err);
} else {
/* parse */
ldns_status r =
ldns_wire2pkt(&(netreq->result), result, packet_len);
if (r != LDNS_STATUS_OK) {
handle_network_request_error(netreq, r);
/* parse */
/* TODO: optimize */
getdns_return_t r = getdns_apply_network_result(netreq, ub_res);
ub_resolve_free(ub_res);
if (r != GETDNS_RETURN_GOOD) {
handle_network_request_error(netreq, err);
} else {
/* is this the last request */
if (!netreq->next) {
/* finished */
handle_dns_request_complete(netreq->owner);
} else {
/* is this the last request */
if (!netreq->next) {
/* finished */
handle_dns_request_complete(netreq->owner);
} else {
/* not finished - update to next request and ship it */
getdns_dns_req *dns_req = netreq->owner;
dns_req->current_req = netreq->next;
submit_network_request(netreq->next);
}
/* not finished - update to next request and ship it */
getdns_dns_req *dns_req = netreq->owner;
dns_req->current_req = netreq->next;
submit_network_request(netreq->next);
}
}
}
getdns_return_t
getdns_general_ub(struct ub_ctx *unbound,
struct event_base *ev_base,
struct getdns_context *context,
getdns_general_ub(struct getdns_context *context,
const char *name,
uint16_t request_type,
struct getdns_dict *extensions,
void *userarg,
getdns_transaction_t * transaction_id, getdns_callback_t callbackfn)
getdns_transaction_t * transaction_id,
getdns_callback_t callbackfn)
{
/* timeout */
struct timeval tv;
getdns_return_t gr;
int r;
@ -281,7 +234,6 @@ getdns_general_ub(struct ub_ctx *unbound,
/* request state */
getdns_dns_req *req = dns_req_new(context,
unbound,
name,
request_type,
extensions);
@ -299,11 +251,11 @@ getdns_general_ub(struct ub_ctx *unbound,
getdns_context_track_outbound_request(req);
/* assign a timeout */
req->ev_base = ev_base;
req->timeout = evtimer_new(ev_base, ub_resolve_timeout, req);
tv.tv_sec = context->timeout / 1000;
tv.tv_usec = (context->timeout % 1000) * 1000;
evtimer_add(req->timeout, &tv);
// req->ev_base = ev_base;
// req->timeout = evtimer_new(ev_base, ub_resolve_timeout, req);
/* schedule the timeout */
getdns_context_schedule_timeout(context, req->trans_id,
context->timeout, ub_resolve_timeout, req);
/* issue the first network req */
@ -331,7 +283,7 @@ getdns_general(struct getdns_context *context,
{
int extcheck = GETDNS_RETURN_GOOD;
if (!context || !context->event_base_async) {
if (!context) {
/* Can't do async without an event loop
* or callback
*/
@ -352,9 +304,7 @@ getdns_general(struct getdns_context *context,
if (extcheck != GETDNS_RETURN_GOOD)
return extcheck;
return getdns_general_ub(context->unbound_async,
context->event_base_async,
context,
return getdns_general_ub(context,
name, request_type, extensions, userarg, transaction_id, callback);
} /* getdns_general */

View File

@ -9,7 +9,7 @@
/*
* Copyright (c) 2013, Versign, 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
@ -40,13 +40,8 @@
/* private inner helper used by sync and async */
struct ub_ctx;
struct event_base;
getdns_return_t
getdns_general_ub(struct ub_ctx *unbound,
struct event_base *ev_base,
struct getdns_context *context,
getdns_general_ub(struct getdns_context *context,
const char *name,
uint16_t request_type,
struct getdns_dict *extensions,

View File

@ -43,8 +43,6 @@
extern "C" {
#endif
struct event_base;
#define GETDNS_COMPILATION_COMMENT The API implementation should fill in something here, such as a compilation version string and date, and change it each time the API is compiled.
/**
@ -797,19 +795,12 @@ char *getdns_pretty_print_dict(const struct getdns_dict *some_dict);
char *getdns_display_ip_address(const struct getdns_bindata
*bindata_of_ipv4_or_ipv6_address);
/*
getdns_return_t getdns_context_set_context_update_callback(
struct getdns_context *context,
void (*value) (struct getdns_context *context, uint16_t changed_item)
);
*/
getdns_return_t
getdns_context_set_context_update_callback(
struct getdns_context * context,
void (*value)(struct getdns_context *context, uint16_t changed_item)
);
getdns_return_t
getdns_context_set_resolution_type(struct getdns_context *context, uint16_t value);
@ -881,11 +872,14 @@ getdns_context_set_extended_memory_functions(struct getdns_context *context,
void (*free) (void *userarg, void *ptr)
);
/* Extension - refactor to abstract async evt loop */
/* For libevent, which we are using for these examples */
getdns_return_t
getdns_extension_set_libevent_base(struct getdns_context *context,
struct event_base *this_event_base);
/* Async support */
struct timeval;
int getdns_context_get_num_pending_requests(struct getdns_context* context, struct timeval* next_timeout);
/* get the fd */
int getdns_context_fd(struct getdns_context* context);
/* process async reqs */
getdns_return_t getdns_context_process_async(struct getdns_context* context);
#ifdef __cplusplus
}

View File

@ -0,0 +1,55 @@
/**
* \file
* \brief Public interfaces to getdns, include in your application to use getdns API.
*
* This source was taken from the original pseudo-implementation by
* Paul Hoffman.
*/
/*
* Copyright (c) 2013, NLNet Labs, Versign, 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 name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GETDNS_EXT_LIBEVENT_H
#define GETDNS_EXT_LIBEVENT_H
#ifdef __cplusplus
extern "C" {
#endif
#include <getdns/getdns.h>
struct event_base;
/* For libevent, which we are using for these examples */
getdns_return_t
getdns_extension_set_libevent_base(struct getdns_context *context,
struct event_base *this_event_base);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -9,7 +9,7 @@
/*
* Copyright (c) 2013, Versign, 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
@ -34,15 +34,8 @@
*/
#include "config.h"
#ifdef HAVE_EVENT2_EVENT_H
# include <event2/event.h>
#else
# include <event.h>
# define event_free free
#endif
#include "types-internal.h"
#include "util-internal.h"
#include <unbound.h>
void
network_req_free(getdns_network_req * net_req)
@ -103,16 +96,11 @@ dns_req_free(getdns_dns_req * req)
net_req = next;
}
/* cleanup timeout */
if (req->timeout) {
event_del(req->timeout);
event_free(req->timeout);
}
if (req->local_timeout_id != 0) {
getdns_context_clear_timeout(context, req->local_timeout_id);
}
if (req->local_cb_timer) {
event_del(req->local_cb_timer);
event_free(req->local_cb_timer);
}
getdns_context_clear_timeout(context, req->trans_id);
/* free strduped name */
free(req->name);
@ -123,7 +111,6 @@ dns_req_free(getdns_dns_req * req)
/* create a new dns req to be submitted */
getdns_dns_req *
dns_req_new(struct getdns_context *context,
struct ub_ctx *unbound,
const char *name, uint16_t request_type, struct getdns_dict *extensions)
{
@ -139,20 +126,17 @@ dns_req_new(struct getdns_context *context,
result->name = strdup(name);
result->context = context;
result->unbound = unbound;
result->canceled = 0;
result->current_req = NULL;
result->first_req = NULL;
result->trans_id = ldns_get_random();
result->timeout = NULL;
result->local_cb_timer = NULL;
result->ev_base = NULL;
getdns_dict_copy(extensions, &result->extensions);
/* will be set by caller */
result->user_pointer = NULL;
result->user_callback = NULL;
result->local_timeout_id = 0;
/* create the requests */
req = network_req_new(result,

View File

@ -34,13 +34,8 @@
*/
#include "config.h"
#ifdef HAVE_EVENT2_EVENT_H
# include <event2/event.h>
#else
# include <event.h>
#endif
#include <getdns/getdns.h>
#include <unbound-event.h>
#include <unbound.h>
#include "context.h"
#include "general.h"
#include "types-internal.h"
@ -51,14 +46,28 @@
#define UNUSED_PARAM(x) ((void)(x))
#define RETURN_IF_NULL(ptr, code) if(ptr == NULL) return code;
static void
sync_callback_func(struct getdns_context *context,
uint16_t callback_type,
struct getdns_dict *response,
void *userarg, getdns_transaction_t transaction_id)
{
*((struct getdns_dict **) userarg) = response;
getdns_return_t submit_request_sync(getdns_dns_req* req) {
struct ub_result* ub_res = NULL;
getdns_return_t gr = GETDNS_RETURN_GOOD;
getdns_network_req *netreq = req->first_req;
while (netreq) {
int r = ub_resolve(req->context->unbound_ctx,
req->name,
netreq->request_type,
netreq->request_class,
&ub_res);
if (r != 0) {
return GETDNS_RETURN_GENERIC_ERROR;
}
gr = getdns_apply_network_result(netreq, ub_res);
ub_resolve_free(ub_res);
ub_res = NULL;
if (gr != GETDNS_RETURN_GOOD) {
return gr;
}
netreq = netreq->next;
}
return gr;
}
getdns_return_t
@ -78,12 +87,22 @@ getdns_general_sync(struct getdns_context *context,
}
response_status = validate_extensions(extensions);
if (response_status == GETDNS_RETURN_GOOD) {
response_status = getdns_general_ub(context->unbound_sync,
context->event_base_sync,
context, name, request_type,
extensions, (void *) response, NULL, sync_callback_func);
event_base_dispatch(context->event_base_sync);
/* for each netreq we call ub_ctx_resolve */
/* request state */
getdns_dns_req *req = dns_req_new(context,
name,
request_type,
extensions);
if (!req) {
return GETDNS_RETURN_GENERIC_ERROR;
}
response_status = submit_request_sync(req);
if (response_status != GETDNS_RETURN_GOOD) {
dns_req_free(req);
return response_status;
}
*response = create_getdns_response(req);
dns_req_free(req);
}
return response_status;
}

View File

@ -17,7 +17,7 @@ VPATH = @srcdir@
CC=gcc
CFLAGS=@CFLAGS@ -Wall -I$(srcdir)/ -I$(srcdir)/../ -I/usr/local/include -std=c99 $(cflags)
LDFLAGS=@LDFLAGS@ -L. -L.. -L/usr/local/lib
LDFLAGS=@LDFLAGS@ -L. -L.. -L$(srcdir)/../ -L/usr/local/lib
LDLIBS=-lgetdns @LIBS@ -lcheck
PROGRAMS=tests_dict tests_list tests_stub_async tests_stub_sync check_getdns tests_dnssec
@ -45,7 +45,7 @@ tests_stub_sync: tests_stub_sync.o
check_getdns_common: check_getdns_common.o
$(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ check_getdns_common.o
check_getdns: check_getdns.o check_getdns_common.o
check_getdns: check_getdns.o check_getdns_common.o
$(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ check_getdns.o check_getdns_common.o
tests_dnssec: tests_dnssec.o testmessages.o

View File

@ -42,9 +42,12 @@
int
main (void)
main (int argc, char** argv)
{
int number_failed;
if (argc > 1) {
event_loop_type = atoi(argv[1]);
}
SRunner *sr ;
Suite *getdns_general_suite(void);

View File

@ -5,12 +5,16 @@
#include <inttypes.h>
#include <check.h>
#include <getdns/getdns.h>
#include <getdns/getdns_ext_libevent.h>
#include "check_getdns_common.h"
#include <unistd.h>
#include <sys/time.h>
int callback_called = 0;
int callback_completed = 0;
int callback_canceled = 0;
uint16_t expected_changed_item = 0;
int event_loop_type = 0;
/*
* extract_response extracts all of the various information
@ -20,25 +24,25 @@ void extract_response(struct getdns_dict *response, struct extracted_response *e
{
ck_assert_msg(response != NULL, "Response should not be NULL");
ASSERT_RC(getdns_dict_get_int(response, "answer_type", &ex_response->top_answer_type),
ASSERT_RC(getdns_dict_get_int(response, "answer_type", &ex_response->top_answer_type),
GETDNS_RETURN_GOOD, "Failed to extract \"top answer_type\"");
ASSERT_RC(getdns_dict_get_bindata(response, "canonical_name", &ex_response->top_canonical_name),
ASSERT_RC(getdns_dict_get_bindata(response, "canonical_name", &ex_response->top_canonical_name),
GETDNS_RETURN_GOOD, "Failed to extract \"top canonical_name\"");
ASSERT_RC(getdns_dict_get_list(response, "just_address_answers", &ex_response->just_address_answers),
ASSERT_RC(getdns_dict_get_list(response, "just_address_answers", &ex_response->just_address_answers),
GETDNS_RETURN_GOOD, "Failed to extract \"just_address_answers\"");
ck_assert_msg(ex_response->just_address_answers != NULL, "just_address_answers should not be NULL");
ASSERT_RC(getdns_dict_get_list(response, "replies_full", &ex_response->replies_full),
ASSERT_RC(getdns_dict_get_list(response, "replies_full", &ex_response->replies_full),
GETDNS_RETURN_GOOD, "Failed to extract \"replies_full\"");
ck_assert_msg(ex_response->replies_full != NULL, "replies_full should not be NULL");
ASSERT_RC(getdns_dict_get_list(response, "replies_tree", &ex_response->replies_tree),
ASSERT_RC(getdns_dict_get_list(response, "replies_tree", &ex_response->replies_tree),
GETDNS_RETURN_GOOD, "Failed to extract \"replies_tree\"");
ck_assert_msg(ex_response->replies_tree != NULL, "replies_tree should not be NULL");
ASSERT_RC(getdns_list_get_dict(ex_response->replies_tree, 0, &ex_response->replies_tree_sub_dict),
ASSERT_RC(getdns_list_get_dict(ex_response->replies_tree, 0, &ex_response->replies_tree_sub_dict),
GETDNS_RETURN_GOOD, "Failed to extract \"replies_tree[0]\"");
ck_assert_msg(ex_response->replies_tree_sub_dict != NULL, "replies_tree[0] dict should not be NULL");
@ -46,29 +50,29 @@ void extract_response(struct getdns_dict *response, struct extracted_response *e
GETDNS_RETURN_GOOD, "Failed to extract \"additional\"");
ck_assert_msg(ex_response->additional != NULL, "additional should not be NULL");
ASSERT_RC(getdns_dict_get_list(ex_response->replies_tree_sub_dict, "answer", &ex_response->answer),
ASSERT_RC(getdns_dict_get_list(ex_response->replies_tree_sub_dict, "answer", &ex_response->answer),
GETDNS_RETURN_GOOD, "Failed to extract \"answer\"");
ck_assert_msg(ex_response->answer != NULL, "answer should not be NULL");
ASSERT_RC(getdns_dict_get_int(ex_response->replies_tree_sub_dict, "answer_type", &ex_response->answer_type),
ASSERT_RC(getdns_dict_get_int(ex_response->replies_tree_sub_dict, "answer_type", &ex_response->answer_type),
GETDNS_RETURN_GOOD, "Failed to extract \"answer_type\"");
ASSERT_RC(getdns_dict_get_list(ex_response->replies_tree_sub_dict, "authority", &ex_response->authority),
ASSERT_RC(getdns_dict_get_list(ex_response->replies_tree_sub_dict, "authority", &ex_response->authority),
GETDNS_RETURN_GOOD, "Failed to extract \"authority\"");
ck_assert_msg(ex_response->authority != NULL, "authority should not be NULL");
ASSERT_RC(getdns_dict_get_bindata(ex_response->replies_tree_sub_dict, "canonical_name", &ex_response->canonical_name),
ASSERT_RC(getdns_dict_get_bindata(ex_response->replies_tree_sub_dict, "canonical_name", &ex_response->canonical_name),
GETDNS_RETURN_GOOD, "Failed to extract \"canonical_name\"");
ASSERT_RC(getdns_dict_get_dict(ex_response->replies_tree_sub_dict, "header", &ex_response->header),
ASSERT_RC(getdns_dict_get_dict(ex_response->replies_tree_sub_dict, "header", &ex_response->header),
GETDNS_RETURN_GOOD, "Failed to extract \"header\"");
ck_assert_msg(ex_response->header != NULL, "header should not be NULL");
ASSERT_RC(getdns_dict_get_dict(ex_response->replies_tree_sub_dict, "question", &ex_response->question),
ASSERT_RC(getdns_dict_get_dict(ex_response->replies_tree_sub_dict, "question", &ex_response->question),
GETDNS_RETURN_GOOD, "Failed to extract \"question\"");
ck_assert_msg(ex_response->question != NULL, "question should not be NULL");
ASSERT_RC(getdns_dict_get_int(response, "status", &ex_response->status),
ASSERT_RC(getdns_dict_get_int(response, "status", &ex_response->status),
GETDNS_RETURN_GOOD, "Failed to extract \"status\"");
}
@ -87,17 +91,17 @@ void assert_noerror(struct extracted_response *ex_response)
/*
* assert_nodata asserts that ancount in the header and the
* of the answer section (list) are both zero.
*/
*/
void assert_nodata(struct extracted_response *ex_response)
{
uint32_t ancount;
size_t length;
ASSERT_RC(getdns_dict_get_int(ex_response->header, "ancount", &ancount),
ASSERT_RC(getdns_dict_get_int(ex_response->header, "ancount", &ancount),
GETDNS_RETURN_GOOD, "Failed to extract \"ancount\"");
ck_assert_msg(ancount == 0, "Expected ancount == 0, got %d", ancount);
ASSERT_RC(getdns_list_get_length(ex_response->answer, &length),
ASSERT_RC(getdns_list_get_length(ex_response->answer, &length),
GETDNS_RETURN_GOOD, "Failed to extract \"answer\" length");
ck_assert_msg(length == 0, "Expected \"answer\" length == 0, got %d", length);
}
@ -110,7 +114,7 @@ void assert_nodata(struct extracted_response *ex_response)
*/
void assert_address_in_answer(struct extracted_response *ex_response, int a, int aaaa)
{
uint32_t ancount;
uint32_t ancount;
size_t length;
struct getdns_dict *rr_dict;
uint32_t type;
@ -127,9 +131,9 @@ void assert_address_in_answer(struct extracted_response *ex_response, int a, int
for(i = 0; i < length; i++)
{
ASSERT_RC(getdns_list_get_dict(ex_response->answer, i, &rr_dict),
ASSERT_RC(getdns_list_get_dict(ex_response->answer, i, &rr_dict),
GETDNS_RETURN_GOOD, "Failed to extract \"answer\" record");
ASSERT_RC(getdns_dict_get_int(rr_dict, "type", &type),
ASSERT_RC(getdns_dict_get_int(rr_dict, "type", &type),
GETDNS_RETURN_GOOD, "Failed to extract \"type\" from answer record");
switch (type)
{
@ -244,8 +248,8 @@ void callbackfn(struct getdns_context *context,
/*
* If userarg is NULL, either a negative test case
* erroneously reached the query state, or the value
* in userarg (verification function) was somehow
* erroneously reached the query state, or the value
* in userarg (verification function) was somehow
* lost in transit.
*/
ck_assert_msg(userarg != NULL, "Callback called with NULL userarg");
@ -282,8 +286,38 @@ void callbackfn(struct getdns_context *context,
void update_callbackfn(struct getdns_context *context,
uint16_t changed_item)
{
ck_assert_msg(changed_item == expected_changed_item,
ck_assert_msg(changed_item == expected_changed_item,
"Expected changed_item == %d, got %d",
changed_item, expected_changed_item);
}
void run_event_loop(struct getdns_context* context, struct event_base* base) {
if (event_loop_type == 0) {
while (getdns_context_get_num_pending_requests(context, NULL) > 0) {
event_base_loop(base, EVLOOP_ONCE);
}
} else if (event_loop_type == 1) {
struct timeval tv;
while (getdns_context_get_num_pending_requests(context, &tv) > 0) {
int fd = getdns_context_fd(context);
fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(fd, &read_fds);
select(fd + 1, &read_fds, NULL, NULL, &tv);
getdns_context_process_async(context);
}
}
}
struct event_base* create_event_base(struct getdns_context* context) {
if (event_loop_type == 0) {
struct event_base* result = event_base_new();
ck_assert_msg(result != NULL, "Event base creation failed");
ASSERT_RC(getdns_extension_set_libevent_base(context, result),
GETDNS_RETURN_GOOD,
"Return code from getdns_extension_set_libevent_base()");
return result;
}
return NULL;
}

View File

@ -1,6 +1,8 @@
#ifndef _check_getdns_common_h_
#define _check_getdns_common_h_
#include "check_getdns_libevent.h"
#define TRUE 1
#define FALSE 0
#define MAXLEN 200
@ -9,7 +11,8 @@
extern int callback_completed;
extern int callback_canceled;
extern uint16_t expected_changed_item;
extern int event_loop_type;
struct extracted_response {
uint32_t top_answer_type;
struct getdns_bindata *top_canonical_name;
@ -26,7 +29,7 @@
struct getdns_dict *question;
uint32_t status;
};
/*
* The ASSERT_RC macro is used to assert
* whether the return code from the last
@ -42,12 +45,12 @@
"%s: expecting %s: %d, but received: %d: %s", \
prefix, #expected_rc, expected_rc, evaluated_rc, error_string); \
}
/*
* The CONTEXT_CREATE macro is used to
* The CONTEXT_CREATE macro is used to
* create a context and assert the proper
* return code is returned.
*/
* return code is returned.
*/
#define CONTEXT_CREATE(set_from_os) \
ASSERT_RC(getdns_context_create(&context, set_from_os), \
GETDNS_RETURN_GOOD, \
@ -60,24 +63,19 @@
#define CONTEXT_DESTROY getdns_context_destroy(context);
/*
* The EVENT_BASE_CREATE macro is used to
* create an event base and put it in the
* context.
*/
#define EVENT_BASE_CREATE \
event_base = event_base_new(); \
ck_assert_msg(event_base != NULL, "Event base creation failed"); \
ASSERT_RC(getdns_extension_set_libevent_base(context, event_base), \
GETDNS_RETURN_GOOD, \
"Return code from getdns_extension_set_libevent_base()");
* The EVENT_BASE_CREATE macro is used to
* create an event base and put it in the
* context.
*/
#define EVENT_BASE_CREATE event_base = create_event_base(context);
/*
* The RUN_EVENT_LOOP macro calls the event loop.
*/
#define RUN_EVENT_LOOP event_base_dispatch(event_base);
#define RUN_EVENT_LOOP run_event_loop(context, event_base);
/*
* The LIST_CREATE macro simply creates a
* The LIST_CREATE macro simply creates a
* list and verifies the returned pointer
* is not NULL.
*/
@ -92,7 +90,7 @@
#define LIST_DESTROY(list) getdns_list_destroy(list);
/*
* The DICT_CREATE macro simply creates a
* The DICT_CREATE macro simply creates a
* dict and verifies the returned pointer
* is not NULL.
*/
@ -105,8 +103,8 @@
* The DICT_DESTROY macro destroys a dict.
*/
#define DICT_DESTROY(dict) getdns_dict_destroy(dict);
/*
/*
* The process_response macro declares the
* variables needed to house the response and
* calls the function that extracts it.
@ -116,14 +114,14 @@
extract_response(response, &ex_response);
//
// FUNCTION DECLARATIONS
//
// FUNCTION DECLARATIONS
//
/*
* extract_response extracts all of the various information
* a test may want to look at from the response.
*/
void extract_response(struct getdns_dict *response, struct extracted_response *ex_response);
void extract_response(struct getdns_dict *response, struct extracted_response *ex_response);
/*
* assert_noerror asserts that the rcode is 0.
@ -137,10 +135,10 @@
void assert_nodata(struct extracted_response *ex_response);
/*
* assert_address_records_in_answer asserts that ancount in
* the header * is >= 1, ancount is equal to the length
* of "answer", and that all of * the records in the
* answer section are A and/or AAAA resource records based
* assert_address_records_in_answer asserts that ancount in
* the header * is >= 1, ancount is equal to the length
* of "answer", and that all of * the records in the
* answer section are A and/or AAAA resource records based
* on the value of the a/aaaa arguments.
*/
void assert_address_in_answer(struct extracted_response *ex_response, int a, int aaaa);
@ -169,17 +167,22 @@
* be called for positive tests and will verify the
* response that is returned.
*/
void callbackfn(struct getdns_context *context,
void callbackfn(struct getdns_context *context,
uint16_t callback_type,
struct getdns_dict *response,
struct getdns_dict *response,
void *userarg,
getdns_transaction_t transaction_id);
/*
* update_callbackfn is the callback function given to
* getdns_context_set_context_update_callback tests.
* update_callbackfn is the callback function given to
* getdns_context_set_context_update_callback tests.
*/
void update_callbackfn(struct getdns_context *context,
void update_callbackfn(struct getdns_context *context,
uint16_t changed_item);
/* run the event loop */
void run_event_loop(struct getdns_context *context, struct event_base* event_base);
struct event_base* create_event_base(struct getdns_context* context);
#endif

View File

@ -44,6 +44,7 @@
#include <string.h>
#include "testmessages.h"
#include <getdns/getdns.h>
#include <getdns/getdns_ext_libevent.h>
/* Set up the callback function, which will also do the processing of the results */
void

View File

@ -43,6 +43,8 @@
#include <string.h>
#include "testmessages.h"
#include <getdns/getdns.h>
#include <getdns/getdns_ext_libevent.h>
#include <sys/time.h>
/* Set up the callback function, which will also do the processing of the results */
void
@ -90,8 +92,12 @@ main(int argc, char** argv)
getdns_context_destroy(this_context);
return (GETDNS_RETURN_GENERIC_ERROR);
}
(void) getdns_extension_set_libevent_base(this_context,
this_event_base);
if (getdns_extension_set_libevent_base(this_context,
this_event_base) != GETDNS_RETURN_GOOD) {
fprintf(stderr, "Setting event base failed.");
getdns_context_destroy(this_context);
return (GETDNS_RETURN_GENERIC_ERROR);
}
/* Set up the getdns call */
const char *this_name = argc > 1 ? argv[1] : "www.google.com";
char *this_userarg = "somestring"; // Could add things here to help identify this call
@ -117,7 +123,10 @@ main(int argc, char** argv)
// }
else {
/* Call the event loop */
event_base_dispatch(this_event_base);
event_base_loop(this_event_base, EVLOOP_ONCE);
while (getdns_context_get_num_pending_requests(this_context, NULL) > 0) {
event_base_loop(this_event_base, EVLOOP_ONCE);
}
// TODO: check the return value above
}
/* Clean up */

View File

@ -9,7 +9,7 @@
/*
* Copyright (c) 2013, Versign, 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
@ -100,9 +100,6 @@ struct getdns_context;
/* declarations */
struct getdns_dns_req;
struct getdns_network_req;
struct ub_ctx;
struct event;
struct event_base;
typedef enum network_req_state_enum
{
@ -165,21 +162,9 @@ typedef struct getdns_dns_req
/* first request in list */
struct getdns_network_req *first_req;
/* request timeout event */
struct event *timeout;
/* local callback timer */
struct event *local_cb_timer;
/* event base this req is scheduled on */
struct event_base *ev_base;
/* context that owns the request */
struct getdns_context *context;
/* ub_ctx issuing the request */
struct ub_ctx *unbound;
/* request extensions */
struct getdns_dict *extensions;
@ -190,6 +175,9 @@ typedef struct getdns_dns_req
/* the transaction id */
getdns_transaction_t trans_id;
/* local timeout id */
getdns_transaction_t local_timeout_id;
} getdns_dns_req;
#define MF_PLAIN ((void *)&plain_mem_funcs_user_arg)
@ -247,11 +235,40 @@ getdns_network_req *network_req_new(getdns_dns_req * owner,
/* dns request utils */
getdns_dns_req *dns_req_new(struct getdns_context *context,
struct ub_ctx *unbound,
const char *name, uint16_t request_type, struct getdns_dict *extensions);
void dns_req_free(getdns_dns_req * req);
/* extensions */
typedef void (*getdns_timeout_callback) (void* userarg);
/* context timeout data */
typedef struct getdns_timeout_data {
getdns_transaction_t transaction_id;
struct timeval timeout_time;
getdns_timeout_callback callback;
void* userarg;
void* extension_timer;
struct getdns_context* context;
} getdns_timeout_data_t;
typedef getdns_return_t (*getdns_eventloop_cleanup_t)(struct getdns_context* context, void* eventloop_data);
typedef getdns_return_t (*getdns_eventloop_schedule_timeout_t)(struct getdns_context* context,
void* eventloop_data, uint16_t timeout,
getdns_timeout_data_t* timeout_data,
void** eventloop_timer);
typedef getdns_return_t (*getdns_eventloop_clear_timeout_t)(struct getdns_context* context,
void* eventloop_data, void** eventloop_timer);
typedef struct getdns_eventloop_extension {
getdns_eventloop_cleanup_t cleanup_data;
getdns_eventloop_schedule_timeout_t schedule_timeout;
getdns_eventloop_clear_timeout_t clear_timeout;
} getdns_eventloop_extension;
#endif
/* types-internal.h */

View File

@ -41,6 +41,7 @@
#include "list.h"
#include "util-internal.h"
#include "types-internal.h"
#include <unbound.h>
#include "rr-dict.h"
/**
@ -571,6 +572,22 @@ validate_extensions(struct getdns_dict * extensions)
return GETDNS_RETURN_GOOD;
} /* validate_extensions */
getdns_return_t
getdns_apply_network_result(getdns_network_req* netreq,
struct ub_result* ub_res) {
ldns_buffer *result = ldns_buffer_new(ub_res->answer_len);
if (!result) {
return GETDNS_RETURN_GENERIC_ERROR;
}
ldns_status r =
ldns_wire2pkt(&(netreq->result), ub_res->answer_packet, ub_res->answer_len);
if (r != LDNS_STATUS_OK) {
return GETDNS_RETURN_GENERIC_ERROR;
}
return GETDNS_RETURN_GOOD;
}
getdns_return_t
validate_dname(const char* dname) {
int len;

View File

@ -41,6 +41,10 @@
#include <ldns/ldns.h>
#include "context.h"
struct ub_result;
struct getdns_network_req;
getdns_return_t getdns_apply_network_result(getdns_network_req* netreq, struct ub_result* result);
#define GETDNS_MAX_DNAME_LEN 255
#define GETDNS_MAX_LABEL_LEN 63

View File

@ -110,24 +110,23 @@ static void callback_on_complete_chain(struct validation_chain *chain)
static void
ub_chain_response_callback(void *arg, int err, void *result, int packet_len,
int sec, char *bogus)
ub_chain_response_callback(void *arg, int err, struct ub_result* ub_res)
{
struct chain_response *response = (struct chain_response *) arg;
ldns_status r;
ldns_pkt *p;
ldns_rr_list *answer;
ldns_rr_list *keys;
size_t i;
ldns_status r;
ldns_pkt *p;
ldns_rr_list *answer;
ldns_rr_list *keys;
size_t i;
response->err = err;
response->sec = sec;
response->bogus = bogus;
response->err = err;
response->sec = ub_res ? ub_res->secure : 0;
response->bogus = ub_res ? ub_res->why_bogus : NULL;
if (result == NULL)
goto done;
if (ub_res == NULL)
goto done;
r = ldns_wire2pkt(&p, (uint8_t *)result, (size_t)packet_len);
r = ldns_wire2pkt(&p, ub_res->answer_packet, ub_res->answer_len);
if (r != LDNS_STATUS_OK) {
if (err == 0)
response->err = r;
@ -165,6 +164,7 @@ ub_chain_response_callback(void *arg, int err, void *result, int packet_len,
ldns_rr_list_free(keys);
ldns_pkt_free(p);
ub_resolve_free(ub_res);
done: if (response->err == 0 && response->result == NULL)
response->err = -1;
@ -202,14 +202,14 @@ static void launch_chain_link_lookup(struct validation_chain *chain, char *name)
ldns_rbtree_insert(&(chain->root), (ldns_rbnode_t *)link);
chain->lock++;
r = ub_resolve_event(chain->dns_req->unbound,
r = ub_resolve_async(chain->dns_req->context->unbound_ctx,
name, LDNS_RR_TYPE_DNSKEY, LDNS_RR_CLASS_IN, &link->DNSKEY,
ub_chain_response_callback, &link->DNSKEY.unbound_id);
if (r != 0)
link->DNSKEY.err = r;
if (name[0] != '.' || name[1] != '\0') {
r = ub_resolve_event(chain->dns_req->unbound,
r = ub_resolve_async(chain->dns_req->context->unbound_ctx,
name, LDNS_RR_TYPE_DS, LDNS_RR_CLASS_IN, &link->DS,
ub_chain_response_callback, &link->DS.unbound_id);
if (r != 0)