mirror of https://github.com/getdnsapi/getdns.git
Import mini_event & rbtree from unbound
This commit is contained in:
parent
4daa944e9e
commit
17e5262acc
|
@ -11700,6 +11700,44 @@ $as_echo "#define HAVE_ATTR_FORMAT 1" >>confdefs.h
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler (${CC-cc}) accepts the \"unused\" attribute" >&5
|
||||||
|
$as_echo_n "checking whether the C compiler (${CC-cc}) accepts the \"unused\" attribute... " >&6; }
|
||||||
|
if ${ac_cv_c_unused_attribute+:} false; then :
|
||||||
|
$as_echo_n "(cached) " >&6
|
||||||
|
else
|
||||||
|
ac_cv_c_unused_attribute=no
|
||||||
|
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||||
|
/* end confdefs.h. */
|
||||||
|
#include <stdio.h>
|
||||||
|
void f (char *u __attribute__((unused)));
|
||||||
|
|
||||||
|
int
|
||||||
|
main ()
|
||||||
|
{
|
||||||
|
|
||||||
|
f ("x");
|
||||||
|
|
||||||
|
;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_ACEOF
|
||||||
|
if ac_fn_c_try_compile "$LINENO"; then :
|
||||||
|
ac_cv_c_unused_attribute="yes"
|
||||||
|
else
|
||||||
|
ac_cv_c_unused_attribute="no"
|
||||||
|
fi
|
||||||
|
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_unused_attribute" >&5
|
||||||
|
$as_echo "$ac_cv_c_unused_attribute" >&6; }
|
||||||
|
if test $ac_cv_c_unused_attribute = yes; then
|
||||||
|
|
||||||
|
$as_echo "#define HAVE_ATTR_UNUSED 1" >>confdefs.h
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
ac_fn_c_check_func "$LINENO" "strlcpy" "ac_cv_func_strlcpy"
|
ac_fn_c_check_func "$LINENO" "strlcpy" "ac_cv_func_strlcpy"
|
||||||
if test "x$ac_cv_func_strlcpy" = xyes; then :
|
if test "x$ac_cv_func_strlcpy" = xyes; then :
|
||||||
$as_echo "#define HAVE_STRLCPY 1" >>confdefs.h
|
$as_echo "#define HAVE_STRLCPY 1" >>confdefs.h
|
||||||
|
@ -11716,6 +11754,44 @@ fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$as_echo "#define USE_MINI_EVENT 1" >>confdefs.h
|
||||||
|
|
||||||
|
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5
|
||||||
|
$as_echo_n "checking return type of signal handlers... " >&6; }
|
||||||
|
if ${ac_cv_type_signal+:} false; then :
|
||||||
|
$as_echo_n "(cached) " >&6
|
||||||
|
else
|
||||||
|
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||||
|
/* end confdefs.h. */
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main ()
|
||||||
|
{
|
||||||
|
return *(signal (0, 0)) (0) == 1;
|
||||||
|
;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_ACEOF
|
||||||
|
if ac_fn_c_try_compile "$LINENO"; then :
|
||||||
|
ac_cv_type_signal=int
|
||||||
|
else
|
||||||
|
ac_cv_type_signal=void
|
||||||
|
fi
|
||||||
|
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||||
|
fi
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_signal" >&5
|
||||||
|
$as_echo "$ac_cv_type_signal" >&6; }
|
||||||
|
|
||||||
|
cat >>confdefs.h <<_ACEOF
|
||||||
|
#define RETSIGTYPE $ac_cv_type_signal
|
||||||
|
_ACEOF
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
38
configure.ac
38
configure.ac
|
@ -404,8 +404,29 @@ if test $ac_cv_c_format_attribute = yes; then
|
||||||
AC_DEFINE(HAVE_ATTR_FORMAT, 1, [Whether the C compiler accepts the "format" attribute])
|
AC_DEFINE(HAVE_ATTR_FORMAT, 1, [Whether the C compiler accepts the "format" attribute])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
AC_MSG_CHECKING(whether the C compiler (${CC-cc}) accepts the "unused" attribute)
|
||||||
|
AC_CACHE_VAL(ac_cv_c_unused_attribute,
|
||||||
|
[ac_cv_c_unused_attribute=no
|
||||||
|
AC_TRY_COMPILE(
|
||||||
|
[#include <stdio.h>
|
||||||
|
void f (char *u __attribute__((unused)));
|
||||||
|
], [
|
||||||
|
f ("x");
|
||||||
|
],
|
||||||
|
[ac_cv_c_unused_attribute="yes"],
|
||||||
|
[ac_cv_c_unused_attribute="no"])
|
||||||
|
])
|
||||||
|
AC_MSG_RESULT($ac_cv_c_unused_attribute)
|
||||||
|
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_REPLACE_FUNCS(strlcpy)
|
AC_REPLACE_FUNCS(strlcpy)
|
||||||
|
|
||||||
|
AC_DEFINE(USE_MINI_EVENT, 1, [Needed for sync stub resolver functions])
|
||||||
|
|
||||||
|
AC_TYPE_SIGNAL
|
||||||
|
|
||||||
AH_BOTTOM([
|
AH_BOTTOM([
|
||||||
/** Use on-board gldns */
|
/** Use on-board gldns */
|
||||||
|
|
||||||
|
@ -445,6 +466,23 @@ AH_BOTTOM([
|
||||||
# define ATTR_FORMAT(archetype, string_index, first_to_check) /* empty */
|
# define ATTR_FORMAT(archetype, string_index, first_to_check) /* empty */
|
||||||
#endif /* !HAVE_ATTR_FORMAT */
|
#endif /* !HAVE_ATTR_FORMAT */
|
||||||
|
|
||||||
|
#if defined(DOXYGEN)
|
||||||
|
# define ATTR_UNUSED(x) x
|
||||||
|
#elif defined(__cplusplus)
|
||||||
|
# define ATTR_UNUSED(x)
|
||||||
|
#elif defined(HAVE_ATTR_UNUSED)
|
||||||
|
# define ATTR_UNUSED(x) x __attribute__((unused))
|
||||||
|
#else /* !HAVE_ATTR_UNUSED */
|
||||||
|
# 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
|
#ifdef TIME_WITH_SYS_TIME
|
||||||
# include <sys/time.h>
|
# include <sys/time.h>
|
||||||
# include <time.h>
|
# include <time.h>
|
||||||
|
|
|
@ -87,6 +87,8 @@ LIBOBJDIR=
|
||||||
LIBOBJS=@LIBOBJS@
|
LIBOBJS=@LIBOBJS@
|
||||||
COMPAT_OBJ=$(LIBOBJS:.o=.lo)
|
COMPAT_OBJ=$(LIBOBJS:.o=.lo)
|
||||||
|
|
||||||
|
UTIL_OBJ=mini_event.lo rbtree.lo
|
||||||
|
|
||||||
.SUFFIXES: .c .o .a .lo .h
|
.SUFFIXES: .c .o .a .lo .h
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
|
@ -95,7 +97,7 @@ COMPAT_OBJ=$(LIBOBJS:.o=.lo)
|
||||||
.c.lo:
|
.c.lo:
|
||||||
$(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) -c $< -o $@
|
$(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
$(GLDNS_OBJ) $(COMPAT_OBJ):
|
$(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ):
|
||||||
@:
|
@:
|
||||||
$(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) -c $< -o $@
|
$(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
@ -134,8 +136,8 @@ libgetdns_ext_ev.la: libgetdns.la extension/libev.lo
|
||||||
$(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ extension/libev.lo ./.libs/libgetdns.la $(EXTENSION_LIBEV_LDFLAGS) $(EXTENSION_LIBEV_EXT_LIBS) -rpath $(libdir) -version-info $(libversion) -no-undefined -export-symbols $(srcdir)/extension/libev.symbols
|
$(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ extension/libev.lo ./.libs/libgetdns.la $(EXTENSION_LIBEV_LDFLAGS) $(EXTENSION_LIBEV_EXT_LIBS) -rpath $(libdir) -version-info $(libversion) -no-undefined -export-symbols $(srcdir)/extension/libev.symbols
|
||||||
|
|
||||||
|
|
||||||
libgetdns.la: $(GETDNS_OBJ) $(GLDNS_OBJ) $(COMPAT_OBJ)
|
libgetdns.la: $(GETDNS_OBJ) $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ)
|
||||||
$(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ $(GETDNS_OBJ) $(GLDNS_OBJ) $(COMPAT_OBJ) $(LDFLAGS) -rpath $(libdir) -version-info $(libversion) -no-undefined -export-symbols $(srcdir)/libgetdns.symbols
|
$(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ $(GETDNS_OBJ) $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) $(LDFLAGS) -rpath $(libdir) -version-info $(libversion) -no-undefined -export-symbols $(srcdir)/libgetdns.symbols
|
||||||
|
|
||||||
|
|
||||||
test: FORCE
|
test: FORCE
|
||||||
|
@ -191,9 +193,10 @@ configure.status: configure
|
||||||
|
|
||||||
depend:
|
depend:
|
||||||
(cd $(srcdir) ; awk 'BEGIN{P=1}{if(P)print}/^# Dependencies/{P=0}' Makefile.in > Makefile.in.new )
|
(cd $(srcdir) ; awk 'BEGIN{P=1}{if(P)print}/^# Dependencies/{P=0}' Makefile.in > Makefile.in.new )
|
||||||
(cd $(srcdir) ; gcc -MM -I. gldns/*.c compat/*.c | \
|
(cd $(srcdir) ; gcc -MM -I. gldns/*.c compat/*.c util/*.c | \
|
||||||
sed -e 's?gldns/?$$(srcdir)/gldns/?g' \
|
sed -e 's?gldns/?$$(srcdir)/gldns/?g' \
|
||||||
-e 's?compat/?$$(srcdir)/compat/?g' \
|
-e 's?compat/?$$(srcdir)/compat/?g' \
|
||||||
|
-e 's?util/?$$(srcdir)/util/?g' \
|
||||||
-e 's!\(.*\)\.o[ :]*!\1.lo \1.o: !g' >> Makefile.in.new )
|
-e 's!\(.*\)\.o[ :]*!\1.lo \1.o: !g' >> Makefile.in.new )
|
||||||
(cd $(srcdir) ; diff Makefile.in.new Makefile.in && rm Makefile.in.new \
|
(cd $(srcdir) ; diff Makefile.in.new Makefile.in && rm Makefile.in.new \
|
||||||
|| mv Makefile.in.new Makefile.in )
|
|| mv Makefile.in.new Makefile.in )
|
||||||
|
@ -214,3 +217,7 @@ wire2str.lo wire2str.o: $(srcdir)/gldns/wire2str.c config.h $(srcdir)/gldns/wire
|
||||||
$(srcdir)/gldns/rrdef.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/parseutil.h $(srcdir)/gldns/gbuffer.h \
|
$(srcdir)/gldns/rrdef.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/parseutil.h $(srcdir)/gldns/gbuffer.h \
|
||||||
$(srcdir)/gldns/keyraw.h
|
$(srcdir)/gldns/keyraw.h
|
||||||
strlcpy.lo strlcpy.o: $(srcdir)/compat/strlcpy.c config.h
|
strlcpy.lo strlcpy.o: $(srcdir)/compat/strlcpy.c config.h
|
||||||
|
mini_event.lo mini_event.o: $(srcdir)/util/mini_event.c config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \
|
||||||
|
$(srcdir)/util/fptr_wlist.h
|
||||||
|
rbtree.lo rbtree.o: $(srcdir)/util/rbtree.c config.h $(srcdir)/util/log.h $(srcdir)/util/fptr_wlist.h \
|
||||||
|
$(srcdir)/util/rbtree.h
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
/* Whether the C compiler accepts the "format" attribute */
|
/* Whether the C compiler accepts the "format" attribute */
|
||||||
#undef HAVE_ATTR_FORMAT
|
#undef HAVE_ATTR_FORMAT
|
||||||
|
|
||||||
|
/* Whether the C compiler accepts the "unused" attribute */
|
||||||
|
#undef HAVE_ATTR_UNUSED
|
||||||
|
|
||||||
/* Define to 1 if you have the <bsd/string.h> header file. */
|
/* Define to 1 if you have the <bsd/string.h> header file. */
|
||||||
#undef HAVE_BSD_STRING_H
|
#undef HAVE_BSD_STRING_H
|
||||||
|
|
||||||
|
@ -106,6 +109,9 @@
|
||||||
/* Define to the version of this package. */
|
/* Define to the version of this package. */
|
||||||
#undef PACKAGE_VERSION
|
#undef PACKAGE_VERSION
|
||||||
|
|
||||||
|
/* Define as the return type of signal handlers (`int' or `void'). */
|
||||||
|
#undef RETSIGTYPE
|
||||||
|
|
||||||
/* Define to 1 if you have the ANSI C header files. */
|
/* Define to 1 if you have the ANSI C header files. */
|
||||||
#undef STDC_HEADERS
|
#undef STDC_HEADERS
|
||||||
|
|
||||||
|
@ -115,6 +121,9 @@
|
||||||
/* Default trust anchor file */
|
/* Default trust anchor file */
|
||||||
#undef TRUST_ANCHOR_FILE
|
#undef TRUST_ANCHOR_FILE
|
||||||
|
|
||||||
|
/* Needed for sync stub resolver functions */
|
||||||
|
#undef USE_MINI_EVENT
|
||||||
|
|
||||||
/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
|
/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
|
||||||
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
|
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
|
||||||
#define below would cause a syntax error. */
|
#define below would cause a syntax error. */
|
||||||
|
@ -188,6 +197,23 @@
|
||||||
# define ATTR_FORMAT(archetype, string_index, first_to_check) /* empty */
|
# define ATTR_FORMAT(archetype, string_index, first_to_check) /* empty */
|
||||||
#endif /* !HAVE_ATTR_FORMAT */
|
#endif /* !HAVE_ATTR_FORMAT */
|
||||||
|
|
||||||
|
#if defined(DOXYGEN)
|
||||||
|
# define ATTR_UNUSED(x) x
|
||||||
|
#elif defined(__cplusplus)
|
||||||
|
# define ATTR_UNUSED(x)
|
||||||
|
#elif defined(HAVE_ATTR_UNUSED)
|
||||||
|
# define ATTR_UNUSED(x) x __attribute__((unused))
|
||||||
|
#else /* !HAVE_ATTR_UNUSED */
|
||||||
|
# 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
|
#ifdef TIME_WITH_SYS_TIME
|
||||||
# include <sys/time.h>
|
# include <sys/time.h>
|
||||||
# include <time.h>
|
# include <time.h>
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* /brief dummy prototypes for function pointer whitelisting
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UTIL_FPTR_WLIST_H
|
||||||
|
#define UTIL_FPTR_WLIST_H
|
||||||
|
|
||||||
|
#define fptr_ok(x)
|
||||||
|
#define fptr_whitelist_event(x)
|
||||||
|
#define fptr_whitelist_rbtree_cmp(x)
|
||||||
|
|
||||||
|
#endif /* UTIL_FPTR_WLIST_H */
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Meant to be run from this directory
|
||||||
|
|
||||||
|
mkdir ub || true
|
||||||
|
cd ub
|
||||||
|
for f in mini_event.c mini_event.h rbtree.c rbtree.h
|
||||||
|
do
|
||||||
|
wget http://unbound.net/svn/trunk/util/$f
|
||||||
|
sed -e 's/event_/getdns_event_/g' -e 's/signal_add/getdns_signal_add/g' -e 's/signal_del/getdns_signal_del/g' -e 's/struct event/struct getdns_event/g' -e 's/mini_ev_cmp/getdns_mini_ev_cmp/g' -e 's/#include "rbtree\.h"/#include "util\/rbtree.h"/g' -e 's/rbnode_/getdns_rbnode_/g' -e 's/rbtree_/getdns_rbtree_/g' -e 's/#include "fptr_wlist\.h"/#include "util\/fptr_wlist.h"/g' -e 's/#include "log\.h"/#include "util\/log.h"/g' $f > ../$f
|
||||||
|
done
|
||||||
|
cd ..
|
||||||
|
rm -r ub
|
|
@ -0,0 +1,40 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* /brief dummy prototypes for logging a la unbound
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UTIL_LOG_H
|
||||||
|
#define UTIL_LOG_H
|
||||||
|
|
||||||
|
#define log_assert(x)
|
||||||
|
|
||||||
|
#endif /* UTIL_LOG_H */
|
||||||
|
|
|
@ -0,0 +1,394 @@
|
||||||
|
/*
|
||||||
|
* mini_event.c - implementation of part of libevent api, portably.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, NLnet Labs. All rights reserved.
|
||||||
|
*
|
||||||
|
* This software is open source.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the NLNET LABS nor the names of its contributors may
|
||||||
|
* be used to endorse or promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* fake libevent implementation. Less broad in functionality, and only
|
||||||
|
* supports select(2).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#ifdef HAVE_TIME_H
|
||||||
|
#include <time.h>
|
||||||
|
#endif
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
#if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK)
|
||||||
|
#include <signal.h>
|
||||||
|
#include "util/mini_event.h"
|
||||||
|
#include "util/fptr_wlist.h"
|
||||||
|
|
||||||
|
/** compare events in tree, based on timevalue, ptr for uniqueness */
|
||||||
|
int getdns_mini_ev_cmp(const void* a, const void* b)
|
||||||
|
{
|
||||||
|
const struct getdns_event *e = (const struct getdns_event*)a;
|
||||||
|
const struct getdns_event *f = (const struct getdns_event*)b;
|
||||||
|
if(e->ev_timeout.tv_sec < f->ev_timeout.tv_sec)
|
||||||
|
return -1;
|
||||||
|
if(e->ev_timeout.tv_sec > f->ev_timeout.tv_sec)
|
||||||
|
return 1;
|
||||||
|
if(e->ev_timeout.tv_usec < f->ev_timeout.tv_usec)
|
||||||
|
return -1;
|
||||||
|
if(e->ev_timeout.tv_usec > f->ev_timeout.tv_usec)
|
||||||
|
return 1;
|
||||||
|
if(e < f)
|
||||||
|
return -1;
|
||||||
|
if(e > f)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** set time */
|
||||||
|
static int
|
||||||
|
settime(struct getdns_event_base* base)
|
||||||
|
{
|
||||||
|
if(gettimeofday(base->time_tv, NULL) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#ifndef S_SPLINT_S
|
||||||
|
*base->time_secs = (time_t)base->time_tv->tv_sec;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** create event base */
|
||||||
|
void *getdns_event_init(time_t* time_secs, struct timeval* time_tv)
|
||||||
|
{
|
||||||
|
struct getdns_event_base* base = (struct getdns_event_base*)malloc(
|
||||||
|
sizeof(struct getdns_event_base));
|
||||||
|
if(!base)
|
||||||
|
return NULL;
|
||||||
|
memset(base, 0, sizeof(*base));
|
||||||
|
base->time_secs = time_secs;
|
||||||
|
base->time_tv = time_tv;
|
||||||
|
if(settime(base) < 0) {
|
||||||
|
getdns_event_base_free(base);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
base->times = getdns_rbtree_create(getdns_mini_ev_cmp);
|
||||||
|
if(!base->times) {
|
||||||
|
getdns_event_base_free(base);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
base->capfd = MAX_FDS;
|
||||||
|
#ifdef FD_SETSIZE
|
||||||
|
if((int)FD_SETSIZE < base->capfd)
|
||||||
|
base->capfd = (int)FD_SETSIZE;
|
||||||
|
#endif
|
||||||
|
base->fds = (struct getdns_event**)calloc((size_t)base->capfd,
|
||||||
|
sizeof(struct getdns_event*));
|
||||||
|
if(!base->fds) {
|
||||||
|
getdns_event_base_free(base);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
base->signals = (struct getdns_event**)calloc(MAX_SIG, sizeof(struct getdns_event*));
|
||||||
|
if(!base->signals) {
|
||||||
|
getdns_event_base_free(base);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#ifndef S_SPLINT_S
|
||||||
|
FD_ZERO(&base->reads);
|
||||||
|
FD_ZERO(&base->writes);
|
||||||
|
#endif
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** get version */
|
||||||
|
const char *getdns_event_get_version(void)
|
||||||
|
{
|
||||||
|
return "mini-event-"PACKAGE_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** get polling method, select */
|
||||||
|
const char *getdns_event_get_method(void)
|
||||||
|
{
|
||||||
|
return "select";
|
||||||
|
}
|
||||||
|
|
||||||
|
/** call timeouts handlers, and return how long to wait for next one or -1 */
|
||||||
|
static void handle_timeouts(struct getdns_event_base* base, struct timeval* now,
|
||||||
|
struct timeval* wait)
|
||||||
|
{
|
||||||
|
struct getdns_event* p;
|
||||||
|
#ifndef S_SPLINT_S
|
||||||
|
wait->tv_sec = (time_t)-1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
while((getdns_rbnode_t*)(p = (struct getdns_event*)getdns_rbtree_first(base->times))
|
||||||
|
!=RBTREE_NULL) {
|
||||||
|
#ifndef S_SPLINT_S
|
||||||
|
if(p->ev_timeout.tv_sec > now->tv_sec ||
|
||||||
|
(p->ev_timeout.tv_sec==now->tv_sec &&
|
||||||
|
p->ev_timeout.tv_usec > now->tv_usec)) {
|
||||||
|
/* there is a next larger timeout. wait for it */
|
||||||
|
wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec;
|
||||||
|
if(now->tv_usec > p->ev_timeout.tv_usec) {
|
||||||
|
wait->tv_sec--;
|
||||||
|
wait->tv_usec = 1000000 - (now->tv_usec -
|
||||||
|
p->ev_timeout.tv_usec);
|
||||||
|
} else {
|
||||||
|
wait->tv_usec = p->ev_timeout.tv_usec
|
||||||
|
- now->tv_usec;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/* event times out, remove it */
|
||||||
|
(void)getdns_rbtree_delete(base->times, p);
|
||||||
|
p->ev_events &= ~EV_TIMEOUT;
|
||||||
|
fptr_ok(fptr_whitelist_event(p->ev_callback));
|
||||||
|
(*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** call select and callbacks for that */
|
||||||
|
static int handle_select(struct getdns_event_base* base, struct timeval* wait)
|
||||||
|
{
|
||||||
|
fd_set r, w;
|
||||||
|
int ret, i;
|
||||||
|
|
||||||
|
#ifndef S_SPLINT_S
|
||||||
|
if(wait->tv_sec==(time_t)-1)
|
||||||
|
wait = NULL;
|
||||||
|
#endif
|
||||||
|
memmove(&r, &base->reads, sizeof(fd_set));
|
||||||
|
memmove(&w, &base->writes, sizeof(fd_set));
|
||||||
|
memmove(&base->ready, &base->content, sizeof(fd_set));
|
||||||
|
|
||||||
|
if((ret = select(base->maxfd+1, &r, &w, NULL, wait)) == -1) {
|
||||||
|
ret = errno;
|
||||||
|
if(settime(base) < 0)
|
||||||
|
return -1;
|
||||||
|
errno = ret;
|
||||||
|
if(ret == EAGAIN || ret == EINTR)
|
||||||
|
return 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(settime(base) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for(i=0; i<base->maxfd+1; i++) {
|
||||||
|
short bits = 0;
|
||||||
|
if(!base->fds[i] || !(FD_ISSET(i, &base->ready))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(FD_ISSET(i, &r)) {
|
||||||
|
bits |= EV_READ;
|
||||||
|
ret--;
|
||||||
|
}
|
||||||
|
if(FD_ISSET(i, &w)) {
|
||||||
|
bits |= EV_WRITE;
|
||||||
|
ret--;
|
||||||
|
}
|
||||||
|
bits &= base->fds[i]->ev_events;
|
||||||
|
if(bits) {
|
||||||
|
fptr_ok(fptr_whitelist_event(
|
||||||
|
base->fds[i]->ev_callback));
|
||||||
|
(*base->fds[i]->ev_callback)(base->fds[i]->ev_fd,
|
||||||
|
bits, base->fds[i]->ev_arg);
|
||||||
|
if(ret==0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** run select in a loop */
|
||||||
|
int getdns_event_base_dispatch(struct getdns_event_base* base)
|
||||||
|
{
|
||||||
|
struct timeval wait;
|
||||||
|
if(settime(base) < 0)
|
||||||
|
return -1;
|
||||||
|
while(!base->need_to_exit)
|
||||||
|
{
|
||||||
|
/* see if timeouts need handling */
|
||||||
|
handle_timeouts(base, base->time_tv, &wait);
|
||||||
|
if(base->need_to_exit)
|
||||||
|
return 0;
|
||||||
|
/* do select */
|
||||||
|
if(handle_select(base, &wait) < 0) {
|
||||||
|
if(base->need_to_exit)
|
||||||
|
return 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** exit that loop */
|
||||||
|
int getdns_event_base_loopexit(struct getdns_event_base* base,
|
||||||
|
struct timeval* ATTR_UNUSED(tv))
|
||||||
|
{
|
||||||
|
base->need_to_exit = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free event base, free events yourself */
|
||||||
|
void getdns_event_base_free(struct getdns_event_base* base)
|
||||||
|
{
|
||||||
|
if(!base)
|
||||||
|
return;
|
||||||
|
if(base->times)
|
||||||
|
free(base->times);
|
||||||
|
if(base->fds)
|
||||||
|
free(base->fds);
|
||||||
|
if(base->signals)
|
||||||
|
free(base->signals);
|
||||||
|
free(base);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** set content of event */
|
||||||
|
void getdns_event_set(struct getdns_event* ev, int fd, short bits,
|
||||||
|
void (*cb)(int, short, void *), void* arg)
|
||||||
|
{
|
||||||
|
ev->node.key = ev;
|
||||||
|
ev->ev_fd = fd;
|
||||||
|
ev->ev_events = bits;
|
||||||
|
ev->ev_callback = cb;
|
||||||
|
fptr_ok(fptr_whitelist_event(ev->ev_callback));
|
||||||
|
ev->ev_arg = arg;
|
||||||
|
ev->added = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add event to a base */
|
||||||
|
int getdns_event_base_set(struct getdns_event_base* base, struct getdns_event* ev)
|
||||||
|
{
|
||||||
|
ev->ev_base = base;
|
||||||
|
ev->added = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add event to make it active, you may not change it with getdns_event_set anymore */
|
||||||
|
int getdns_event_add(struct getdns_event* ev, struct timeval* tv)
|
||||||
|
{
|
||||||
|
if(ev->added)
|
||||||
|
getdns_event_del(ev);
|
||||||
|
if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd)
|
||||||
|
return -1;
|
||||||
|
if( (ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
|
||||||
|
ev->ev_base->fds[ev->ev_fd] = ev;
|
||||||
|
if(ev->ev_events&EV_READ) {
|
||||||
|
FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->reads);
|
||||||
|
}
|
||||||
|
if(ev->ev_events&EV_WRITE) {
|
||||||
|
FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->writes);
|
||||||
|
}
|
||||||
|
FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->content);
|
||||||
|
FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready);
|
||||||
|
if(ev->ev_fd > ev->ev_base->maxfd)
|
||||||
|
ev->ev_base->maxfd = ev->ev_fd;
|
||||||
|
}
|
||||||
|
if(tv && (ev->ev_events&EV_TIMEOUT)) {
|
||||||
|
#ifndef S_SPLINT_S
|
||||||
|
struct timeval *now = ev->ev_base->time_tv;
|
||||||
|
ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec;
|
||||||
|
ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec;
|
||||||
|
while(ev->ev_timeout.tv_usec > 1000000) {
|
||||||
|
ev->ev_timeout.tv_usec -= 1000000;
|
||||||
|
ev->ev_timeout.tv_sec++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
(void)getdns_rbtree_insert(ev->ev_base->times, &ev->node);
|
||||||
|
}
|
||||||
|
ev->added = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove event, you may change it again */
|
||||||
|
int getdns_event_del(struct getdns_event* ev)
|
||||||
|
{
|
||||||
|
if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd)
|
||||||
|
return -1;
|
||||||
|
if((ev->ev_events&EV_TIMEOUT))
|
||||||
|
(void)getdns_rbtree_delete(ev->ev_base->times, &ev->node);
|
||||||
|
if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
|
||||||
|
ev->ev_base->fds[ev->ev_fd] = NULL;
|
||||||
|
FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->reads);
|
||||||
|
FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->writes);
|
||||||
|
FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready);
|
||||||
|
FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->content);
|
||||||
|
}
|
||||||
|
ev->added = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** which base gets to handle signals */
|
||||||
|
static struct getdns_event_base* signal_base = NULL;
|
||||||
|
/** signal handler */
|
||||||
|
static RETSIGTYPE sigh(int sig)
|
||||||
|
{
|
||||||
|
struct getdns_event* ev;
|
||||||
|
if(!signal_base || sig < 0 || sig >= MAX_SIG)
|
||||||
|
return;
|
||||||
|
ev = signal_base->signals[sig];
|
||||||
|
if(!ev)
|
||||||
|
return;
|
||||||
|
fptr_ok(fptr_whitelist_event(ev->ev_callback));
|
||||||
|
(*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** install signal handler */
|
||||||
|
int getdns_signal_add(struct getdns_event* ev, struct timeval* ATTR_UNUSED(tv))
|
||||||
|
{
|
||||||
|
if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
|
||||||
|
return -1;
|
||||||
|
signal_base = ev->ev_base;
|
||||||
|
ev->ev_base->signals[ev->ev_fd] = ev;
|
||||||
|
ev->added = 1;
|
||||||
|
if(signal(ev->ev_fd, sigh) == SIG_ERR) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** remove signal handler */
|
||||||
|
int getdns_signal_del(struct getdns_event* ev)
|
||||||
|
{
|
||||||
|
if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
|
||||||
|
return -1;
|
||||||
|
ev->ev_base->signals[ev->ev_fd] = NULL;
|
||||||
|
ev->added = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* USE_MINI_EVENT */
|
||||||
|
#ifndef USE_WINSOCK
|
||||||
|
int getdns_mini_ev_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* not USE_WINSOCK */
|
||||||
|
#endif /* USE_MINI_EVENT */
|
|
@ -0,0 +1,177 @@
|
||||||
|
/*
|
||||||
|
* mini-event.h - micro implementation of libevent api, using select() only.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, NLnet Labs. All rights reserved.
|
||||||
|
*
|
||||||
|
* This software is open source.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the NLNET LABS nor the names of its contributors may
|
||||||
|
* be used to endorse or promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* This file implements part of the event(3) libevent api.
|
||||||
|
* The back end is only select. Max number of fds is limited.
|
||||||
|
* Max number of signals is limited, one handler per signal only.
|
||||||
|
* And one handler per fd.
|
||||||
|
*
|
||||||
|
* Although limited to select() and a max (1024) open fds, it
|
||||||
|
* is efficient:
|
||||||
|
* o dispatch call caches fd_sets to use.
|
||||||
|
* o handler calling takes time ~ to the number of fds.
|
||||||
|
* o timeouts are stored in a redblack tree, sorted, so take log(n).
|
||||||
|
* Timeouts are only accurate to the second (no subsecond accuracy).
|
||||||
|
* To avoid cpu hogging, fractional timeouts are rounded up to a whole second.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MINI_EVENT_H
|
||||||
|
#define MINI_EVENT_H
|
||||||
|
|
||||||
|
#if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK)
|
||||||
|
|
||||||
|
#ifndef HAVE_EVENT_BASE_FREE
|
||||||
|
#define HAVE_EVENT_BASE_FREE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** event timeout */
|
||||||
|
#define EV_TIMEOUT 0x01
|
||||||
|
/** event fd readable */
|
||||||
|
#define EV_READ 0x02
|
||||||
|
/** event fd writable */
|
||||||
|
#define EV_WRITE 0x04
|
||||||
|
/** event signal */
|
||||||
|
#define EV_SIGNAL 0x08
|
||||||
|
/** event must persist */
|
||||||
|
#define EV_PERSIST 0x10
|
||||||
|
|
||||||
|
/* needs our redblack tree */
|
||||||
|
#include "util/rbtree.h"
|
||||||
|
|
||||||
|
/** max number of file descriptors to support */
|
||||||
|
#define MAX_FDS 1024
|
||||||
|
/** max number of signals to support */
|
||||||
|
#define MAX_SIG 32
|
||||||
|
|
||||||
|
/** event base */
|
||||||
|
struct getdns_event_base
|
||||||
|
{
|
||||||
|
/** sorted by timeout (absolute), ptr */
|
||||||
|
getdns_rbtree_t* times;
|
||||||
|
/** array of 0 - maxfd of ptr to event for it */
|
||||||
|
struct getdns_event** fds;
|
||||||
|
/** max fd in use */
|
||||||
|
int maxfd;
|
||||||
|
/** capacity - size of the fds array */
|
||||||
|
int capfd;
|
||||||
|
/* fdset for read write, for fds ready, and added */
|
||||||
|
fd_set
|
||||||
|
/** fds for reading */
|
||||||
|
reads,
|
||||||
|
/** fds for writing */
|
||||||
|
writes,
|
||||||
|
/** fds determined ready for use */
|
||||||
|
ready,
|
||||||
|
/** ready plus newly added events. */
|
||||||
|
content;
|
||||||
|
/** array of 0 - maxsig of ptr to event for it */
|
||||||
|
struct getdns_event** signals;
|
||||||
|
/** if we need to exit */
|
||||||
|
int need_to_exit;
|
||||||
|
/** where to store time in seconds */
|
||||||
|
time_t* time_secs;
|
||||||
|
/** where to store time in microseconds */
|
||||||
|
struct timeval* time_tv;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event structure. Has some of the event elements.
|
||||||
|
*/
|
||||||
|
struct getdns_event {
|
||||||
|
/** node in timeout rbtree */
|
||||||
|
getdns_rbnode_t node;
|
||||||
|
/** is event already added */
|
||||||
|
int added;
|
||||||
|
|
||||||
|
/** event base it belongs to */
|
||||||
|
struct getdns_event_base *ev_base;
|
||||||
|
/** fd to poll or -1 for timeouts. signal number for sigs. */
|
||||||
|
int ev_fd;
|
||||||
|
/** what events this event is interested in, see EV_.. above. */
|
||||||
|
short ev_events;
|
||||||
|
/** timeout value */
|
||||||
|
struct timeval ev_timeout;
|
||||||
|
|
||||||
|
/** callback to call: fd, eventbits, userarg */
|
||||||
|
void (*ev_callback)(int, short, void *arg);
|
||||||
|
/** callback user arg */
|
||||||
|
void *ev_arg;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* function prototypes (some are as they appear in event.h) */
|
||||||
|
/** create event base */
|
||||||
|
void *getdns_event_init(time_t* time_secs, struct timeval* time_tv);
|
||||||
|
/** get version */
|
||||||
|
const char *getdns_event_get_version(void);
|
||||||
|
/** get polling method, select */
|
||||||
|
const char *getdns_event_get_method(void);
|
||||||
|
/** run select in a loop */
|
||||||
|
int getdns_event_base_dispatch(struct getdns_event_base *);
|
||||||
|
/** exit that loop */
|
||||||
|
int getdns_event_base_loopexit(struct getdns_event_base *, struct timeval *);
|
||||||
|
/** free event base. Free events yourself */
|
||||||
|
void getdns_event_base_free(struct getdns_event_base *);
|
||||||
|
/** set content of event */
|
||||||
|
void getdns_event_set(struct getdns_event *, int, short, void (*)(int, short, void *), void *);
|
||||||
|
/** add event to a base. You *must* call this for every event. */
|
||||||
|
int getdns_event_base_set(struct getdns_event_base *, struct getdns_event *);
|
||||||
|
/** add event to make it active. You may not change it with getdns_event_set anymore */
|
||||||
|
int getdns_event_add(struct getdns_event *, struct timeval *);
|
||||||
|
/** remove event. You may change it again */
|
||||||
|
int getdns_event_del(struct getdns_event *);
|
||||||
|
|
||||||
|
/** add a timer */
|
||||||
|
#define evtimer_add(ev, tv) getdns_event_add(ev, tv)
|
||||||
|
/** remove a timer */
|
||||||
|
#define evtimer_del(ev) getdns_event_del(ev)
|
||||||
|
|
||||||
|
/* uses different implementation. Cannot mix fd/timeouts and signals inside
|
||||||
|
* the same struct getdns_event. create several event structs for that. */
|
||||||
|
/** install signal handler */
|
||||||
|
int getdns_signal_add(struct getdns_event *, struct timeval *);
|
||||||
|
/** set signal event contents */
|
||||||
|
#define signal_set(ev, x, cb, arg) \
|
||||||
|
getdns_event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg)
|
||||||
|
/** remove signal handler */
|
||||||
|
int getdns_signal_del(struct getdns_event *);
|
||||||
|
|
||||||
|
#endif /* USE_MINI_EVENT and not USE_WINSOCK */
|
||||||
|
|
||||||
|
/** compare events in tree, based on timevalue, ptr for uniqueness */
|
||||||
|
int getdns_mini_ev_cmp(const void* a, const void* b);
|
||||||
|
|
||||||
|
#endif /* MINI_EVENT_H */
|
|
@ -0,0 +1,620 @@
|
||||||
|
/*
|
||||||
|
* rbtree.c -- generic red black tree
|
||||||
|
*
|
||||||
|
* Copyright (c) 2001-2007, NLnet Labs. All rights reserved.
|
||||||
|
*
|
||||||
|
* This software is open source.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the NLNET LABS nor the names of its contributors may
|
||||||
|
* be used to endorse or promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Implementation of a redblack tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "util/log.h"
|
||||||
|
#include "util/fptr_wlist.h"
|
||||||
|
#include "util/rbtree.h"
|
||||||
|
|
||||||
|
/** Node colour black */
|
||||||
|
#define BLACK 0
|
||||||
|
/** Node colour red */
|
||||||
|
#define RED 1
|
||||||
|
|
||||||
|
/** the NULL node, global alloc */
|
||||||
|
getdns_rbnode_t getdns_rbtree_null_node = {
|
||||||
|
RBTREE_NULL, /* Parent. */
|
||||||
|
RBTREE_NULL, /* Left. */
|
||||||
|
RBTREE_NULL, /* Right. */
|
||||||
|
NULL, /* Key. */
|
||||||
|
BLACK /* Color. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/** rotate subtree left (to preserve redblack property) */
|
||||||
|
static void getdns_rbtree_rotate_left(getdns_rbtree_t *rbtree, getdns_rbnode_t *node);
|
||||||
|
/** rotate subtree right (to preserve redblack property) */
|
||||||
|
static void getdns_rbtree_rotate_right(getdns_rbtree_t *rbtree, getdns_rbnode_t *node);
|
||||||
|
/** Fixup node colours when insert happened */
|
||||||
|
static void getdns_rbtree_insert_fixup(getdns_rbtree_t *rbtree, getdns_rbnode_t *node);
|
||||||
|
/** Fixup node colours when delete happened */
|
||||||
|
static void getdns_rbtree_delete_fixup(getdns_rbtree_t* rbtree, getdns_rbnode_t* child, getdns_rbnode_t* child_parent);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Creates a new red black tree, intializes and returns a pointer to it.
|
||||||
|
*
|
||||||
|
* Return NULL on failure.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
getdns_rbtree_t *
|
||||||
|
getdns_rbtree_create (int (*cmpf)(const void *, const void *))
|
||||||
|
{
|
||||||
|
getdns_rbtree_t *rbtree;
|
||||||
|
|
||||||
|
/* Allocate memory for it */
|
||||||
|
rbtree = (getdns_rbtree_t *) malloc(sizeof(getdns_rbtree_t));
|
||||||
|
if (!rbtree) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize it */
|
||||||
|
getdns_rbtree_init(rbtree, cmpf);
|
||||||
|
|
||||||
|
return rbtree;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
getdns_rbtree_init(getdns_rbtree_t *rbtree, int (*cmpf)(const void *, const void *))
|
||||||
|
{
|
||||||
|
/* Initialize it */
|
||||||
|
rbtree->root = RBTREE_NULL;
|
||||||
|
rbtree->count = 0;
|
||||||
|
rbtree->cmp = cmpf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Rotates the node to the left.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
getdns_rbtree_rotate_left(getdns_rbtree_t *rbtree, getdns_rbnode_t *node)
|
||||||
|
{
|
||||||
|
getdns_rbnode_t *right = node->right;
|
||||||
|
node->right = right->left;
|
||||||
|
if (right->left != RBTREE_NULL)
|
||||||
|
right->left->parent = node;
|
||||||
|
|
||||||
|
right->parent = node->parent;
|
||||||
|
|
||||||
|
if (node->parent != RBTREE_NULL) {
|
||||||
|
if (node == node->parent->left) {
|
||||||
|
node->parent->left = right;
|
||||||
|
} else {
|
||||||
|
node->parent->right = right;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rbtree->root = right;
|
||||||
|
}
|
||||||
|
right->left = node;
|
||||||
|
node->parent = right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Rotates the node to the right.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
getdns_rbtree_rotate_right(getdns_rbtree_t *rbtree, getdns_rbnode_t *node)
|
||||||
|
{
|
||||||
|
getdns_rbnode_t *left = node->left;
|
||||||
|
node->left = left->right;
|
||||||
|
if (left->right != RBTREE_NULL)
|
||||||
|
left->right->parent = node;
|
||||||
|
|
||||||
|
left->parent = node->parent;
|
||||||
|
|
||||||
|
if (node->parent != RBTREE_NULL) {
|
||||||
|
if (node == node->parent->right) {
|
||||||
|
node->parent->right = left;
|
||||||
|
} else {
|
||||||
|
node->parent->left = left;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rbtree->root = left;
|
||||||
|
}
|
||||||
|
left->right = node;
|
||||||
|
node->parent = left;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
getdns_rbtree_insert_fixup(getdns_rbtree_t *rbtree, getdns_rbnode_t *node)
|
||||||
|
{
|
||||||
|
getdns_rbnode_t *uncle;
|
||||||
|
|
||||||
|
/* While not at the root and need fixing... */
|
||||||
|
while (node != rbtree->root && node->parent->color == RED) {
|
||||||
|
/* If our parent is left child of our grandparent... */
|
||||||
|
if (node->parent == node->parent->parent->left) {
|
||||||
|
uncle = node->parent->parent->right;
|
||||||
|
|
||||||
|
/* If our uncle is red... */
|
||||||
|
if (uncle->color == RED) {
|
||||||
|
/* Paint the parent and the uncle black... */
|
||||||
|
node->parent->color = BLACK;
|
||||||
|
uncle->color = BLACK;
|
||||||
|
|
||||||
|
/* And the grandparent red... */
|
||||||
|
node->parent->parent->color = RED;
|
||||||
|
|
||||||
|
/* And continue fixing the grandparent */
|
||||||
|
node = node->parent->parent;
|
||||||
|
} else { /* Our uncle is black... */
|
||||||
|
/* Are we the right child? */
|
||||||
|
if (node == node->parent->right) {
|
||||||
|
node = node->parent;
|
||||||
|
getdns_rbtree_rotate_left(rbtree, node);
|
||||||
|
}
|
||||||
|
/* Now we're the left child, repaint and rotate... */
|
||||||
|
node->parent->color = BLACK;
|
||||||
|
node->parent->parent->color = RED;
|
||||||
|
getdns_rbtree_rotate_right(rbtree, node->parent->parent);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uncle = node->parent->parent->left;
|
||||||
|
|
||||||
|
/* If our uncle is red... */
|
||||||
|
if (uncle->color == RED) {
|
||||||
|
/* Paint the parent and the uncle black... */
|
||||||
|
node->parent->color = BLACK;
|
||||||
|
uncle->color = BLACK;
|
||||||
|
|
||||||
|
/* And the grandparent red... */
|
||||||
|
node->parent->parent->color = RED;
|
||||||
|
|
||||||
|
/* And continue fixing the grandparent */
|
||||||
|
node = node->parent->parent;
|
||||||
|
} else { /* Our uncle is black... */
|
||||||
|
/* Are we the right child? */
|
||||||
|
if (node == node->parent->left) {
|
||||||
|
node = node->parent;
|
||||||
|
getdns_rbtree_rotate_right(rbtree, node);
|
||||||
|
}
|
||||||
|
/* Now we're the right child, repaint and rotate... */
|
||||||
|
node->parent->color = BLACK;
|
||||||
|
node->parent->parent->color = RED;
|
||||||
|
getdns_rbtree_rotate_left(rbtree, node->parent->parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rbtree->root->color = BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inserts a node into a red black tree.
|
||||||
|
*
|
||||||
|
* Returns NULL on failure or the pointer to the newly added node
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
getdns_rbnode_t *
|
||||||
|
getdns_rbtree_insert (getdns_rbtree_t *rbtree, getdns_rbnode_t *data)
|
||||||
|
{
|
||||||
|
/* XXX Not necessary, but keeps compiler quiet... */
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
|
/* We start at the root of the tree */
|
||||||
|
getdns_rbnode_t *node = rbtree->root;
|
||||||
|
getdns_rbnode_t *parent = RBTREE_NULL;
|
||||||
|
|
||||||
|
fptr_ok(fptr_whitelist_getdns_rbtree_cmp(rbtree->cmp));
|
||||||
|
/* Lets find the new parent... */
|
||||||
|
while (node != RBTREE_NULL) {
|
||||||
|
/* Compare two keys, do we have a duplicate? */
|
||||||
|
if ((r = rbtree->cmp(data->key, node->key)) == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
parent = node;
|
||||||
|
|
||||||
|
if (r < 0) {
|
||||||
|
node = node->left;
|
||||||
|
} else {
|
||||||
|
node = node->right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the new node */
|
||||||
|
data->parent = parent;
|
||||||
|
data->left = data->right = RBTREE_NULL;
|
||||||
|
data->color = RED;
|
||||||
|
rbtree->count++;
|
||||||
|
|
||||||
|
/* Insert it into the tree... */
|
||||||
|
if (parent != RBTREE_NULL) {
|
||||||
|
if (r < 0) {
|
||||||
|
parent->left = data;
|
||||||
|
} else {
|
||||||
|
parent->right = data;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rbtree->root = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fix up the red-black properties... */
|
||||||
|
getdns_rbtree_insert_fixup(rbtree, data);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Searches the red black tree, returns the data if key is found or NULL otherwise.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
getdns_rbnode_t *
|
||||||
|
getdns_rbtree_search (getdns_rbtree_t *rbtree, const void *key)
|
||||||
|
{
|
||||||
|
getdns_rbnode_t *node;
|
||||||
|
|
||||||
|
if (getdns_rbtree_find_less_equal(rbtree, key, &node)) {
|
||||||
|
return node;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** helpers for delete: swap node colours */
|
||||||
|
static void swap_int8(uint8_t* x, uint8_t* y)
|
||||||
|
{
|
||||||
|
uint8_t t = *x; *x = *y; *y = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** helpers for delete: swap node pointers */
|
||||||
|
static void swap_np(getdns_rbnode_t** x, getdns_rbnode_t** y)
|
||||||
|
{
|
||||||
|
getdns_rbnode_t* t = *x; *x = *y; *y = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Update parent pointers of child trees of 'parent' */
|
||||||
|
static void change_parent_ptr(getdns_rbtree_t* rbtree, getdns_rbnode_t* parent, getdns_rbnode_t* old, getdns_rbnode_t* new)
|
||||||
|
{
|
||||||
|
if(parent == RBTREE_NULL)
|
||||||
|
{
|
||||||
|
log_assert(rbtree->root == old);
|
||||||
|
if(rbtree->root == old) rbtree->root = new;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log_assert(parent->left == old || parent->right == old
|
||||||
|
|| parent->left == new || parent->right == new);
|
||||||
|
if(parent->left == old) parent->left = new;
|
||||||
|
if(parent->right == old) parent->right = new;
|
||||||
|
}
|
||||||
|
/** Update parent pointer of a node 'child' */
|
||||||
|
static void change_child_ptr(getdns_rbnode_t* child, getdns_rbnode_t* old, getdns_rbnode_t* new)
|
||||||
|
{
|
||||||
|
if(child == RBTREE_NULL) return;
|
||||||
|
log_assert(child->parent == old || child->parent == new);
|
||||||
|
if(child->parent == old) child->parent = new;
|
||||||
|
}
|
||||||
|
|
||||||
|
getdns_rbnode_t*
|
||||||
|
getdns_rbtree_delete(getdns_rbtree_t *rbtree, const void *key)
|
||||||
|
{
|
||||||
|
getdns_rbnode_t *to_delete;
|
||||||
|
getdns_rbnode_t *child;
|
||||||
|
if((to_delete = getdns_rbtree_search(rbtree, key)) == 0) return 0;
|
||||||
|
rbtree->count--;
|
||||||
|
|
||||||
|
/* make sure we have at most one non-leaf child */
|
||||||
|
if(to_delete->left != RBTREE_NULL && to_delete->right != RBTREE_NULL)
|
||||||
|
{
|
||||||
|
/* swap with smallest from right subtree (or largest from left) */
|
||||||
|
getdns_rbnode_t *smright = to_delete->right;
|
||||||
|
while(smright->left != RBTREE_NULL)
|
||||||
|
smright = smright->left;
|
||||||
|
/* swap the smright and to_delete elements in the tree,
|
||||||
|
* but the getdns_rbnode_t is first part of user data struct
|
||||||
|
* so cannot just swap the keys and data pointers. Instead
|
||||||
|
* readjust the pointers left,right,parent */
|
||||||
|
|
||||||
|
/* swap colors - colors are tied to the position in the tree */
|
||||||
|
swap_int8(&to_delete->color, &smright->color);
|
||||||
|
|
||||||
|
/* swap child pointers in parents of smright/to_delete */
|
||||||
|
change_parent_ptr(rbtree, to_delete->parent, to_delete, smright);
|
||||||
|
if(to_delete->right != smright)
|
||||||
|
change_parent_ptr(rbtree, smright->parent, smright, to_delete);
|
||||||
|
|
||||||
|
/* swap parent pointers in children of smright/to_delete */
|
||||||
|
change_child_ptr(smright->left, smright, to_delete);
|
||||||
|
change_child_ptr(smright->left, smright, to_delete);
|
||||||
|
change_child_ptr(smright->right, smright, to_delete);
|
||||||
|
change_child_ptr(smright->right, smright, to_delete);
|
||||||
|
change_child_ptr(to_delete->left, to_delete, smright);
|
||||||
|
if(to_delete->right != smright)
|
||||||
|
change_child_ptr(to_delete->right, to_delete, smright);
|
||||||
|
if(to_delete->right == smright)
|
||||||
|
{
|
||||||
|
/* set up so after swap they work */
|
||||||
|
to_delete->right = to_delete;
|
||||||
|
smright->parent = smright;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* swap pointers in to_delete/smright nodes */
|
||||||
|
swap_np(&to_delete->parent, &smright->parent);
|
||||||
|
swap_np(&to_delete->left, &smright->left);
|
||||||
|
swap_np(&to_delete->right, &smright->right);
|
||||||
|
|
||||||
|
/* now delete to_delete (which is at the location where the smright previously was) */
|
||||||
|
}
|
||||||
|
log_assert(to_delete->left == RBTREE_NULL || to_delete->right == RBTREE_NULL);
|
||||||
|
|
||||||
|
if(to_delete->left != RBTREE_NULL) child = to_delete->left;
|
||||||
|
else child = to_delete->right;
|
||||||
|
|
||||||
|
/* unlink to_delete from the tree, replace to_delete with child */
|
||||||
|
change_parent_ptr(rbtree, to_delete->parent, to_delete, child);
|
||||||
|
change_child_ptr(child, to_delete, to_delete->parent);
|
||||||
|
|
||||||
|
if(to_delete->color == RED)
|
||||||
|
{
|
||||||
|
/* if node is red then the child (black) can be swapped in */
|
||||||
|
}
|
||||||
|
else if(child->color == RED)
|
||||||
|
{
|
||||||
|
/* change child to BLACK, removing a RED node is no problem */
|
||||||
|
if(child!=RBTREE_NULL) child->color = BLACK;
|
||||||
|
}
|
||||||
|
else getdns_rbtree_delete_fixup(rbtree, child, to_delete->parent);
|
||||||
|
|
||||||
|
/* unlink completely */
|
||||||
|
to_delete->parent = RBTREE_NULL;
|
||||||
|
to_delete->left = RBTREE_NULL;
|
||||||
|
to_delete->right = RBTREE_NULL;
|
||||||
|
to_delete->color = BLACK;
|
||||||
|
return to_delete;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void getdns_rbtree_delete_fixup(getdns_rbtree_t* rbtree, getdns_rbnode_t* child, getdns_rbnode_t* child_parent)
|
||||||
|
{
|
||||||
|
getdns_rbnode_t* sibling;
|
||||||
|
int go_up = 1;
|
||||||
|
|
||||||
|
/* determine sibling to the node that is one-black short */
|
||||||
|
if(child_parent->right == child) sibling = child_parent->left;
|
||||||
|
else sibling = child_parent->right;
|
||||||
|
|
||||||
|
while(go_up)
|
||||||
|
{
|
||||||
|
if(child_parent == RBTREE_NULL)
|
||||||
|
{
|
||||||
|
/* removed parent==black from root, every path, so ok */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sibling->color == RED)
|
||||||
|
{ /* rotate to get a black sibling */
|
||||||
|
child_parent->color = RED;
|
||||||
|
sibling->color = BLACK;
|
||||||
|
if(child_parent->right == child)
|
||||||
|
getdns_rbtree_rotate_right(rbtree, child_parent);
|
||||||
|
else getdns_rbtree_rotate_left(rbtree, child_parent);
|
||||||
|
/* new sibling after rotation */
|
||||||
|
if(child_parent->right == child) sibling = child_parent->left;
|
||||||
|
else sibling = child_parent->right;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(child_parent->color == BLACK
|
||||||
|
&& sibling->color == BLACK
|
||||||
|
&& sibling->left->color == BLACK
|
||||||
|
&& sibling->right->color == BLACK)
|
||||||
|
{ /* fixup local with recolor of sibling */
|
||||||
|
if(sibling != RBTREE_NULL)
|
||||||
|
sibling->color = RED;
|
||||||
|
|
||||||
|
child = child_parent;
|
||||||
|
child_parent = child_parent->parent;
|
||||||
|
/* prepare to go up, new sibling */
|
||||||
|
if(child_parent->right == child) sibling = child_parent->left;
|
||||||
|
else sibling = child_parent->right;
|
||||||
|
}
|
||||||
|
else go_up = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(child_parent->color == RED
|
||||||
|
&& sibling->color == BLACK
|
||||||
|
&& sibling->left->color == BLACK
|
||||||
|
&& sibling->right->color == BLACK)
|
||||||
|
{
|
||||||
|
/* move red to sibling to rebalance */
|
||||||
|
if(sibling != RBTREE_NULL)
|
||||||
|
sibling->color = RED;
|
||||||
|
child_parent->color = BLACK;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log_assert(sibling != RBTREE_NULL);
|
||||||
|
|
||||||
|
/* get a new sibling, by rotating at sibling. See which child
|
||||||
|
of sibling is red */
|
||||||
|
if(child_parent->right == child
|
||||||
|
&& sibling->color == BLACK
|
||||||
|
&& sibling->right->color == RED
|
||||||
|
&& sibling->left->color == BLACK)
|
||||||
|
{
|
||||||
|
sibling->color = RED;
|
||||||
|
sibling->right->color = BLACK;
|
||||||
|
getdns_rbtree_rotate_left(rbtree, sibling);
|
||||||
|
/* new sibling after rotation */
|
||||||
|
if(child_parent->right == child) sibling = child_parent->left;
|
||||||
|
else sibling = child_parent->right;
|
||||||
|
}
|
||||||
|
else if(child_parent->left == child
|
||||||
|
&& sibling->color == BLACK
|
||||||
|
&& sibling->left->color == RED
|
||||||
|
&& sibling->right->color == BLACK)
|
||||||
|
{
|
||||||
|
sibling->color = RED;
|
||||||
|
sibling->left->color = BLACK;
|
||||||
|
getdns_rbtree_rotate_right(rbtree, sibling);
|
||||||
|
/* new sibling after rotation */
|
||||||
|
if(child_parent->right == child) sibling = child_parent->left;
|
||||||
|
else sibling = child_parent->right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now we have a black sibling with a red child. rotate and exchange colors. */
|
||||||
|
sibling->color = child_parent->color;
|
||||||
|
child_parent->color = BLACK;
|
||||||
|
if(child_parent->right == child)
|
||||||
|
{
|
||||||
|
log_assert(sibling->left->color == RED);
|
||||||
|
sibling->left->color = BLACK;
|
||||||
|
getdns_rbtree_rotate_right(rbtree, child_parent);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_assert(sibling->right->color == RED);
|
||||||
|
sibling->right->color = BLACK;
|
||||||
|
getdns_rbtree_rotate_left(rbtree, child_parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
getdns_rbtree_find_less_equal(getdns_rbtree_t *rbtree, const void *key, getdns_rbnode_t **result)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
getdns_rbnode_t *node;
|
||||||
|
|
||||||
|
log_assert(result);
|
||||||
|
|
||||||
|
/* We start at root... */
|
||||||
|
node = rbtree->root;
|
||||||
|
|
||||||
|
*result = NULL;
|
||||||
|
fptr_ok(fptr_whitelist_getdns_rbtree_cmp(rbtree->cmp));
|
||||||
|
|
||||||
|
/* While there are children... */
|
||||||
|
while (node != RBTREE_NULL) {
|
||||||
|
r = rbtree->cmp(key, node->key);
|
||||||
|
if (r == 0) {
|
||||||
|
/* Exact match */
|
||||||
|
*result = node;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (r < 0) {
|
||||||
|
node = node->left;
|
||||||
|
} else {
|
||||||
|
/* Temporary match */
|
||||||
|
*result = node;
|
||||||
|
node = node->right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finds the first element in the red black tree
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
getdns_rbnode_t *
|
||||||
|
getdns_rbtree_first (getdns_rbtree_t *rbtree)
|
||||||
|
{
|
||||||
|
getdns_rbnode_t *node;
|
||||||
|
|
||||||
|
for (node = rbtree->root; node->left != RBTREE_NULL; node = node->left);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
getdns_rbnode_t *
|
||||||
|
getdns_rbtree_last (getdns_rbtree_t *rbtree)
|
||||||
|
{
|
||||||
|
getdns_rbnode_t *node;
|
||||||
|
|
||||||
|
for (node = rbtree->root; node->right != RBTREE_NULL; node = node->right);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the next node...
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
getdns_rbnode_t *
|
||||||
|
getdns_rbtree_next (getdns_rbnode_t *node)
|
||||||
|
{
|
||||||
|
getdns_rbnode_t *parent;
|
||||||
|
|
||||||
|
if (node->right != RBTREE_NULL) {
|
||||||
|
/* One right, then keep on going left... */
|
||||||
|
for (node = node->right; node->left != RBTREE_NULL; node = node->left);
|
||||||
|
} else {
|
||||||
|
parent = node->parent;
|
||||||
|
while (parent != RBTREE_NULL && node == parent->right) {
|
||||||
|
node = parent;
|
||||||
|
parent = parent->parent;
|
||||||
|
}
|
||||||
|
node = parent;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
getdns_rbnode_t *
|
||||||
|
getdns_rbtree_previous(getdns_rbnode_t *node)
|
||||||
|
{
|
||||||
|
getdns_rbnode_t *parent;
|
||||||
|
|
||||||
|
if (node->left != RBTREE_NULL) {
|
||||||
|
/* One left, then keep on going right... */
|
||||||
|
for (node = node->left; node->right != RBTREE_NULL; node = node->right);
|
||||||
|
} else {
|
||||||
|
parent = node->parent;
|
||||||
|
while (parent != RBTREE_NULL && node == parent->left) {
|
||||||
|
node = parent;
|
||||||
|
parent = parent->parent;
|
||||||
|
}
|
||||||
|
node = parent;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** recursive descent traverse */
|
||||||
|
static void
|
||||||
|
traverse_post(void (*func)(getdns_rbnode_t*, void*), void* arg, getdns_rbnode_t* node)
|
||||||
|
{
|
||||||
|
if(!node || node == RBTREE_NULL)
|
||||||
|
return;
|
||||||
|
/* recurse */
|
||||||
|
traverse_post(func, arg, node->left);
|
||||||
|
traverse_post(func, arg, node->right);
|
||||||
|
/* call user func */
|
||||||
|
(*func)(node, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
traverse_postorder(getdns_rbtree_t* tree, void (*func)(getdns_rbnode_t*, void*), void* arg)
|
||||||
|
{
|
||||||
|
traverse_post(func, arg, tree->root);
|
||||||
|
}
|
|
@ -0,0 +1,192 @@
|
||||||
|
/*
|
||||||
|
* rbtree.h -- generic red-black tree
|
||||||
|
*
|
||||||
|
* Copyright (c) 2001-2007, NLnet Labs. All rights reserved.
|
||||||
|
*
|
||||||
|
* This software is open source.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the NLNET LABS nor the names of its contributors may
|
||||||
|
* be used to endorse or promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Red black tree. Implementation taken from NSD 3.0.5, adjusted for use
|
||||||
|
* in unbound (memory allocation, logging and so on).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UTIL_RBTREE_H_
|
||||||
|
#define UTIL_RBTREE_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This structure must be the first member of the data structure in
|
||||||
|
* the rbtree. This allows easy casting between an getdns_rbnode_t and the
|
||||||
|
* user data (poor man's inheritance).
|
||||||
|
*/
|
||||||
|
typedef struct getdns_rbnode_t getdns_rbnode_t;
|
||||||
|
/**
|
||||||
|
* The getdns_rbnode_t struct definition.
|
||||||
|
*/
|
||||||
|
struct getdns_rbnode_t {
|
||||||
|
/** parent in rbtree, RBTREE_NULL for root */
|
||||||
|
getdns_rbnode_t *parent;
|
||||||
|
/** left node (smaller items) */
|
||||||
|
getdns_rbnode_t *left;
|
||||||
|
/** right node (larger items) */
|
||||||
|
getdns_rbnode_t *right;
|
||||||
|
/** pointer to sorting key */
|
||||||
|
const void *key;
|
||||||
|
/** colour of this node */
|
||||||
|
uint8_t color;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** The nullpointer, points to empty node */
|
||||||
|
#define RBTREE_NULL &getdns_rbtree_null_node
|
||||||
|
/** the global empty node */
|
||||||
|
extern getdns_rbnode_t getdns_rbtree_null_node;
|
||||||
|
|
||||||
|
/** An entire red black tree */
|
||||||
|
typedef struct getdns_rbtree_t getdns_rbtree_t;
|
||||||
|
/** definition for tree struct */
|
||||||
|
struct getdns_rbtree_t {
|
||||||
|
/** The root of the red-black tree */
|
||||||
|
getdns_rbnode_t *root;
|
||||||
|
|
||||||
|
/** The number of the nodes in the tree */
|
||||||
|
size_t count;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key compare function. <0,0,>0 like strcmp.
|
||||||
|
* Return 0 on two NULL ptrs.
|
||||||
|
*/
|
||||||
|
int (*cmp) (const void *, const void *);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create new tree (malloced) with given key compare function.
|
||||||
|
* @param cmpf: compare function (like strcmp) takes pointers to two keys.
|
||||||
|
* @return: new tree, empty.
|
||||||
|
*/
|
||||||
|
getdns_rbtree_t *getdns_rbtree_create(int (*cmpf)(const void *, const void *));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Init a new tree (malloced by caller) with given key compare function.
|
||||||
|
* @param rbtree: uninitialised memory for new tree, returned empty.
|
||||||
|
* @param cmpf: compare function (like strcmp) takes pointers to two keys.
|
||||||
|
*/
|
||||||
|
void getdns_rbtree_init(getdns_rbtree_t *rbtree, int (*cmpf)(const void *, const void *));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert data into the tree.
|
||||||
|
* @param rbtree: tree to insert to.
|
||||||
|
* @param data: element to insert.
|
||||||
|
* @return: data ptr or NULL if key already present.
|
||||||
|
*/
|
||||||
|
getdns_rbnode_t *getdns_rbtree_insert(getdns_rbtree_t *rbtree, getdns_rbnode_t *data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete element from tree.
|
||||||
|
* @param rbtree: tree to delete from.
|
||||||
|
* @param key: key of item to delete.
|
||||||
|
* @return: node that is now unlinked from the tree. User to delete it.
|
||||||
|
* returns 0 if node not present
|
||||||
|
*/
|
||||||
|
getdns_rbnode_t *getdns_rbtree_delete(getdns_rbtree_t *rbtree, const void *key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find key in tree. Returns NULL if not found.
|
||||||
|
* @param rbtree: tree to find in.
|
||||||
|
* @param key: key that must match.
|
||||||
|
* @return: node that fits or NULL.
|
||||||
|
*/
|
||||||
|
getdns_rbnode_t *getdns_rbtree_search(getdns_rbtree_t *rbtree, const void *key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find, but match does not have to be exact.
|
||||||
|
* @param rbtree: tree to find in.
|
||||||
|
* @param key: key to find position of.
|
||||||
|
* @param result: set to the exact node if present, otherwise to element that
|
||||||
|
* precedes the position of key in the tree. NULL if no smaller element.
|
||||||
|
* @return: true if exact match in result. Else result points to <= element,
|
||||||
|
* or NULL if key is smaller than the smallest key.
|
||||||
|
*/
|
||||||
|
int getdns_rbtree_find_less_equal(getdns_rbtree_t *rbtree, const void *key,
|
||||||
|
getdns_rbnode_t **result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns first (smallest) node in the tree
|
||||||
|
* @param rbtree: tree
|
||||||
|
* @return: smallest element or NULL if tree empty.
|
||||||
|
*/
|
||||||
|
getdns_rbnode_t *getdns_rbtree_first(getdns_rbtree_t *rbtree);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns last (largest) node in the tree
|
||||||
|
* @param rbtree: tree
|
||||||
|
* @return: largest element or NULL if tree empty.
|
||||||
|
*/
|
||||||
|
getdns_rbnode_t *getdns_rbtree_last(getdns_rbtree_t *rbtree);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns next larger node in the tree
|
||||||
|
* @param rbtree: tree
|
||||||
|
* @return: next larger element or NULL if no larger in tree.
|
||||||
|
*/
|
||||||
|
getdns_rbnode_t *getdns_rbtree_next(getdns_rbnode_t *rbtree);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns previous smaller node in the tree
|
||||||
|
* @param rbtree: tree
|
||||||
|
* @return: previous smaller element or NULL if no previous in tree.
|
||||||
|
*/
|
||||||
|
getdns_rbnode_t *getdns_rbtree_previous(getdns_rbnode_t *rbtree);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call with node=variable of struct* with getdns_rbnode_t as first element.
|
||||||
|
* with type is the type of a pointer to that struct.
|
||||||
|
*/
|
||||||
|
#define RBTREE_FOR(node, type, rbtree) \
|
||||||
|
for(node=(type)getdns_rbtree_first(rbtree); \
|
||||||
|
(getdns_rbnode_t*)node != RBTREE_NULL; \
|
||||||
|
node = (type)getdns_rbtree_next((getdns_rbnode_t*)node))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call function for all elements in the redblack tree, such that
|
||||||
|
* leaf elements are called before parent elements. So that all
|
||||||
|
* elements can be safely free()d.
|
||||||
|
* Note that your function must not remove the nodes from the tree.
|
||||||
|
* Since that may trigger rebalances of the rbtree.
|
||||||
|
* @param tree: the tree
|
||||||
|
* @param func: function called with element and user arg.
|
||||||
|
* The function must not alter the rbtree.
|
||||||
|
* @param arg: user argument.
|
||||||
|
*/
|
||||||
|
void traverse_postorder(getdns_rbtree_t* tree, void (*func)(getdns_rbnode_t*, void*),
|
||||||
|
void* arg);
|
||||||
|
|
||||||
|
#endif /* UTIL_RBTREE_H_ */
|
Loading…
Reference in New Issue