From 9e62112ac4b7644f13dfa7b69e099ad714931ed8 Mon Sep 17 00:00:00 2001 From: Max Lv Date: Wed, 3 Apr 2013 10:39:12 +0800 Subject: [PATCH] add async dns support --- Makefile.am | 3 +- Makefile.in | 4 +- config.h.in | 88 +++ configure | 1144 +++++++++++++++++++++++++++++- configure.ac | 29 + libasyncns/Makefile.am | 26 + libasyncns/Makefile.in | 571 +++++++++++++++ libasyncns/asyncns.c | 1500 ++++++++++++++++++++++++++++++++++++++++ libasyncns/asyncns.h | 163 +++++ src/Makefile.am | 3 + src/Makefile.in | 15 +- src/jconf.h | 1 + src/server.c | 99 ++- src/server.h | 9 +- 14 files changed, 3617 insertions(+), 38 deletions(-) create mode 100644 libasyncns/Makefile.am create mode 100644 libasyncns/Makefile.in create mode 100644 libasyncns/asyncns.c create mode 100644 libasyncns/asyncns.h diff --git a/Makefile.am b/Makefile.am index 7cb29006..5197c154 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,3 +1,2 @@ -#bin_PROGRAMS = ss-local ss-server -SUBDIRS = libev src +SUBDIRS = libasyncns libev src ACLOCAL_AMFLAGS = -I m4 diff --git a/Makefile.in b/Makefile.in index ec9c642c..8a175766 100644 --- a/Makefile.in +++ b/Makefile.in @@ -221,9 +221,7 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ - -#bin_PROGRAMS = ss-local ss-server -SUBDIRS = libev src +SUBDIRS = libasyncns libev src ACLOCAL_AMFLAGS = -I m4 all: config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive diff --git a/config.h.in b/config.h.in index 2a48dfbb..bc521597 100644 --- a/config.h.in +++ b/config.h.in @@ -27,6 +27,9 @@ /* Define to 1 if the floor function is available */ #undef HAVE_FLOOR +/* Define to 1 if you have the `fork' function. */ +#undef HAVE_FORK + /* Define to 1 if you have the `inotify_init' function. */ #undef HAVE_INOTIFY_INIT @@ -39,9 +42,15 @@ /* Define to 1 if you have the header file. */ #undef HAVE_LANGINFO_H +/* Define to 1 if you have the `nsl' library (-lnsl). */ +#undef HAVE_LIBNSL + /* Define to 1 if you have the `rt' library (-lrt). */ #undef HAVE_LIBRT +/* Define to 1 if you have the `socket' library (-lsocket). */ +#undef HAVE_LIBSOCKET + /* Define to 1 if you have the header file. */ #undef HAVE_LOCALE_H @@ -78,6 +87,12 @@ /* Define to 1 if you have the `select' function. */ #undef HAVE_SELECT +/* Define to 1 if you have the `setresuid' function. */ +#undef HAVE_SETRESUID + +/* Define to 1 if you have the `setreuid' function. */ +#undef HAVE_SETREUID + /* Define to 1 if you have the `signalfd' function. */ #undef HAVE_SIGNALFD @@ -90,12 +105,18 @@ /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H +/* Define to 1 if you have the `strerror' function. */ +#undef HAVE_STRERROR + /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H +/* Define to 1 if you have the `strndup' function. */ +#undef HAVE_STRNDUP + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_EPOLL_H @@ -123,13 +144,31 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H +/* Define to 1 if you have that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H +/* Define to 1 if you have the `vfork' function. */ +#undef HAVE_VFORK + +/* Define to 1 if you have the header file. */ +#undef HAVE_VFORK_H + +/* Define to 1 if `fork' works. */ +#undef HAVE_WORKING_FORK + +/* Define to 1 if `vfork' works. */ +#undef HAVE_WORKING_VFORK + /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #undef LT_OBJDIR +/* Define to 1 if assertions should be disabled. */ +#undef NDEBUG + /* Name of package */ #undef PACKAGE @@ -151,9 +190,24 @@ /* Define to the version of this package. */ #undef PACKAGE_VERSION +/* Define as the return type of signal handlers (`int' or `void'). */ +#undef RETSIGTYPE + +/* Define to the type of arg 1 for `select'. */ +#undef SELECT_TYPE_ARG1 + +/* Define to the type of args 2, 3 and 4 for `select'. */ +#undef SELECT_TYPE_ARG234 + +/* Define to the type of arg 5 for `select'. */ +#undef SELECT_TYPE_ARG5 + /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS +/* Define to 1 if you can safely include both and . */ +#undef TIME_WITH_SYS_TIME + /* Version number of package */ #undef VERSION @@ -169,11 +223,45 @@ # endif #endif +/* Number of bits in a file offset, on hosts where this is settable. */ +#undef _FILE_OFFSET_BITS + +/* Define for large files, on AIX-style hosts. */ +#undef _LARGE_FILES + +/* Define for Solaris 2.5.1 so the uint8_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +#undef _UINT8_T + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif +/* Define to rpl_malloc if the replacement function should be used. */ +#undef malloc + +/* Define to `int' if does not define. */ +#undef pid_t + +/* Define to `unsigned int' if does not define. */ +#undef size_t + /* Define to `int' if does not define. */ #undef ssize_t + +/* Define to the type of an unsigned integer type of width exactly 16 bits if + such a type exists and the standard includes do not define it. */ +#undef uint16_t + +/* Define to the type of an unsigned integer type of width exactly 8 bits if + such a type exists and the standard includes do not define it. */ +#undef uint8_t + +/* Define as `fork' if `vfork' does not work. */ +#undef vfork diff --git a/configure b/configure index 6ce6877e..db2f3d54 100755 --- a/configure +++ b/configure @@ -735,6 +735,8 @@ enable_fast_install with_gnu_ld with_sysroot enable_libtool_lock +enable_assert +enable_largefile ' ac_precious_vars='build_alias host_alias @@ -1372,6 +1374,8 @@ Optional Features: --enable-fast-install[=PKGS] optimize for fast installation [default=yes] --disable-libtool-lock avoid locking (might break parallel builds) + --disable-assert turn off assertions + --disable-largefile omit support for large files Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] @@ -1877,6 +1881,59 @@ $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type + +# ac_fn_c_find_uintX_t LINENO BITS VAR +# ------------------------------------ +# Finds an unsigned integer type with width BITS, setting cache variable VAR +# accordingly. +ac_fn_c_find_uintX_t () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5 +$as_echo_n "checking for uint$2_t... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + # Order is important - never check a type that is potentially smaller + # than half of the expected target width. + for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \ + 'unsigned long long int' 'unsigned short int' 'unsigned char'; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + case $ac_type in #( + uint$2_t) : + eval "$3=yes" ;; #( + *) : + eval "$3=\$ac_type" ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if eval test \"x\$"$3"\" = x"no"; then : + +else + break +fi + done +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_find_uintX_t cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. @@ -11322,6 +11379,48 @@ CC="$lt_save_CC" # Only expand once: +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +$as_echo_n "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +$as_echo "no, using $LN_S" >&6; } +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + for ac_header in sys/inotify.h sys/epoll.h sys/event.h port.h poll.h sys/select.h sys/eventfd.h sys/signalfd.h @@ -11891,6 +11990,1048 @@ _ACEOF fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable assertions" >&5 +$as_echo_n "checking whether to enable assertions... " >&6; } + # Check whether --enable-assert was given. +if test "${enable_assert+set}" = set; then : + enableval=$enable_assert; ac_enable_assert=$enableval + if test "x$enableval" = xno; then : + +$as_echo "#define NDEBUG 1" >>confdefs.h + +elif test "x$enableval" != xyes; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: invalid argument supplied to --enable-assert" >&5 +$as_echo "$as_me: WARNING: invalid argument supplied to --enable-assert" >&2;} + ac_enable_assert=yes +fi +else + ac_enable_assert=yes +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_enable_assert" >&5 +$as_echo "$ac_enable_assert" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5 +$as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } +if ${ac_cv_header_sys_wait_h+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#ifndef WEXITSTATUS +# define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8) +#endif +#ifndef WIFEXITED +# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif + +int +main () +{ + int s; + wait (&s); + s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_sys_wait_h=yes +else + ac_cv_header_sys_wait_h=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5 +$as_echo "$ac_cv_header_sys_wait_h" >&6; } +if test $ac_cv_header_sys_wait_h = yes; then + +$as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h + +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 +$as_echo_n "checking for an ANSI C-conforming const... " >&6; } +if ${ac_cv_c_const+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset cs; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *pcpcc; + char **ppc; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + pcpcc = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++pcpcc; + ppc = (char**) pcpcc; + pcpcc = (char const *const *) ppc; + { /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + if (s) return 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + if (!foo) return 0; + } + return !cs[0] && !zero.x; +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_const=yes +else + ac_cv_c_const=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_const" >&5 +$as_echo "$ac_cv_c_const" >&6; } +if test $ac_cv_c_const = no; then + +$as_echo "#define const /**/" >>confdefs.h + +fi + +ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" +if test "x$ac_cv_type_pid_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define pid_t int +_ACEOF + +fi + +ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" +if test "x$ac_cv_type_size_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned int +_ACEOF + +fi + +ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default" +if test "x$ac_cv_type_ssize_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define ssize_t int +_ACEOF + +fi + +ac_fn_c_find_uintX_t "$LINENO" "16" "ac_cv_c_uint16_t" +case $ac_cv_c_uint16_t in #( + no|yes) ;; #( + *) + + +cat >>confdefs.h <<_ACEOF +#define uint16_t $ac_cv_c_uint16_t +_ACEOF +;; + esac + +ac_fn_c_find_uintX_t "$LINENO" "8" "ac_cv_c_uint8_t" +case $ac_cv_c_uint8_t in #( + no|yes) ;; #( + *) + +$as_echo "#define _UINT8_T 1" >>confdefs.h + + +cat >>confdefs.h <<_ACEOF +#define uint8_t $ac_cv_c_uint8_t +_ACEOF +;; + esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5 +$as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } +if ${ac_cv_header_time+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include + +int +main () +{ +if ((struct tm *) 0) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_time=yes +else + ac_cv_header_time=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5 +$as_echo "$ac_cv_header_time" >&6; } +if test $ac_cv_header_time = yes; then + +$as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h + +fi + + +for ac_header in vfork.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "vfork.h" "ac_cv_header_vfork_h" "$ac_includes_default" +if test "x$ac_cv_header_vfork_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_VFORK_H 1 +_ACEOF + +fi + +done + +for ac_func in fork vfork +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" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +if test "x$ac_cv_func_fork" = xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working fork" >&5 +$as_echo_n "checking for working fork... " >&6; } +if ${ac_cv_func_fork_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_fork_works=cross +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* By Ruediger Kuhlmann. */ + return fork () < 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_fork_works=yes +else + ac_cv_func_fork_works=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fork_works" >&5 +$as_echo "$ac_cv_func_fork_works" >&6; } + +else + ac_cv_func_fork_works=$ac_cv_func_fork +fi +if test "x$ac_cv_func_fork_works" = xcross; then + case $host in + *-*-amigaos* | *-*-msdosdjgpp*) + # Override, as these systems have only a dummy fork() stub + ac_cv_func_fork_works=no + ;; + *) + ac_cv_func_fork_works=yes + ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&5 +$as_echo "$as_me: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&2;} +fi +ac_cv_func_vfork_works=$ac_cv_func_vfork +if test "x$ac_cv_func_vfork" = xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working vfork" >&5 +$as_echo_n "checking for working vfork... " >&6; } +if ${ac_cv_func_vfork_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_vfork_works=cross +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Thanks to Paul Eggert for this test. */ +$ac_includes_default +#include +#ifdef HAVE_VFORK_H +# include +#endif +/* On some sparc systems, changes by the child to local and incoming + argument registers are propagated back to the parent. The compiler + is told about this with #include , but some compilers + (e.g. gcc -O) don't grok . Test for this by using a + static variable whose address is put into a register that is + clobbered by the vfork. */ +static void +#ifdef __cplusplus +sparc_address_test (int arg) +# else +sparc_address_test (arg) int arg; +#endif +{ + static pid_t child; + if (!child) { + child = vfork (); + if (child < 0) { + perror ("vfork"); + _exit(2); + } + if (!child) { + arg = getpid(); + write(-1, "", 0); + _exit (arg); + } + } +} + +int +main () +{ + pid_t parent = getpid (); + pid_t child; + + sparc_address_test (0); + + child = vfork (); + + if (child == 0) { + /* Here is another test for sparc vfork register problems. This + test uses lots of local variables, at least as many local + variables as main has allocated so far including compiler + temporaries. 4 locals are enough for gcc 1.40.3 on a Solaris + 4.1.3 sparc, but we use 8 to be safe. A buggy compiler should + reuse the register of parent for one of the local variables, + since it will think that parent can't possibly be used any more + in this routine. Assigning to the local variable will thus + munge parent in the parent process. */ + pid_t + p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(), + p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid(); + /* Convince the compiler that p..p7 are live; otherwise, it might + use the same hardware register for all 8 local variables. */ + if (p != p1 || p != p2 || p != p3 || p != p4 + || p != p5 || p != p6 || p != p7) + _exit(1); + + /* On some systems (e.g. IRIX 3.3), vfork doesn't separate parent + from child file descriptors. If the child closes a descriptor + before it execs or exits, this munges the parent's descriptor + as well. Test for this by closing stdout in the child. */ + _exit(close(fileno(stdout)) != 0); + } else { + int status; + struct stat st; + + while (wait(&status) != child) + ; + return ( + /* Was there some problem with vforking? */ + child < 0 + + /* Did the child fail? (This shouldn't happen.) */ + || status + + /* Did the vfork/compiler bug occur? */ + || parent != getpid() + + /* Did the file descriptor bug occur? */ + || fstat(fileno(stdout), &st) != 0 + ); + } +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_vfork_works=yes +else + ac_cv_func_vfork_works=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_vfork_works" >&5 +$as_echo "$ac_cv_func_vfork_works" >&6; } + +fi; +if test "x$ac_cv_func_fork_works" = xcross; then + ac_cv_func_vfork_works=$ac_cv_func_vfork + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&5 +$as_echo "$as_me: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&2;} +fi + +if test "x$ac_cv_func_vfork_works" = xyes; then + +$as_echo "#define HAVE_WORKING_VFORK 1" >>confdefs.h + +else + +$as_echo "#define vfork fork" >>confdefs.h + +fi +if test "x$ac_cv_func_fork_works" = xyes; then + +$as_echo "#define HAVE_WORKING_FORK 1" >>confdefs.h + +fi + +for ac_header in stdlib.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" +if test "x$ac_cv_header_stdlib_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STDLIB_H 1 +_ACEOF + +fi + +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5 +$as_echo_n "checking for GNU libc compatible malloc... " >&6; } +if ${ac_cv_func_malloc_0_nonnull+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_malloc_0_nonnull=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if defined STDC_HEADERS || defined HAVE_STDLIB_H +# include +#else +char *malloc (); +#endif + +int +main () +{ +return ! malloc (0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_malloc_0_nonnull=yes +else + ac_cv_func_malloc_0_nonnull=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5 +$as_echo "$ac_cv_func_malloc_0_nonnull" >&6; } +if test $ac_cv_func_malloc_0_nonnull = yes; then : + +$as_echo "#define HAVE_MALLOC 1" >>confdefs.h + +else + $as_echo "#define HAVE_MALLOC 0" >>confdefs.h + + case " $LIBOBJS " in + *" malloc.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS malloc.$ac_objext" + ;; +esac + + +$as_echo "#define malloc rpl_malloc" >>confdefs.h + +fi + + +for ac_header in sys/select.h sys/socket.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking types of arguments for select" >&5 +$as_echo_n "checking types of arguments for select... " >&6; } +if ${ac_cv_func_select_args+:} false; then : + $as_echo_n "(cached) " >&6 +else + for ac_arg234 in 'fd_set *' 'int *' 'void *'; do + for ac_arg1 in 'int' 'size_t' 'unsigned long int' 'unsigned int'; do + for ac_arg5 in 'struct timeval *' 'const struct timeval *'; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +#ifdef HAVE_SYS_SELECT_H +# include +#endif +#ifdef HAVE_SYS_SOCKET_H +# include +#endif + +int +main () +{ +extern int select ($ac_arg1, + $ac_arg234, $ac_arg234, $ac_arg234, + $ac_arg5); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_func_select_args="$ac_arg1,$ac_arg234,$ac_arg5"; break 3 +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done + done +done +# Provide a safe default value. +: "${ac_cv_func_select_args=int,int *,struct timeval *}" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_select_args" >&5 +$as_echo "$ac_cv_func_select_args" >&6; } +ac_save_IFS=$IFS; IFS=',' +set dummy `echo "$ac_cv_func_select_args" | sed 's/\*/\*/g'` +IFS=$ac_save_IFS +shift + +cat >>confdefs.h <<_ACEOF +#define SELECT_TYPE_ARG1 $1 +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define SELECT_TYPE_ARG234 ($2) +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define SELECT_TYPE_ARG5 ($3) +_ACEOF + +rm -f conftest* + +{ $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 +#include + +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 + + +for ac_func in memset select strndup setresuid setreuid strerror +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" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +# Check whether --enable-largefile was given. +if test "${enable_largefile+set}" = set; then : + enableval=$enable_largefile; +fi + +if test "$enable_largefile" != no; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 +$as_echo_n "checking for special C compiler options needed for large files... " >&6; } +if ${ac_cv_sys_largefile_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_sys_largefile_CC=no + if test "$GCC" != yes; then + ac_save_CC=$CC + while :; do + # IRIX 6.2 and later do not support large files by default, + # so use the C compiler's -n32 option if that helps. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF + if ac_fn_c_try_compile "$LINENO"; then : + break +fi +rm -f core conftest.err conftest.$ac_objext + CC="$CC -n32" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_largefile_CC=' -n32'; break +fi +rm -f core conftest.err conftest.$ac_objext + break + done + CC=$ac_save_CC + rm -f conftest.$ac_ext + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 +$as_echo "$ac_cv_sys_largefile_CC" >&6; } + if test "$ac_cv_sys_largefile_CC" != no; then + CC=$CC$ac_cv_sys_largefile_CC + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 +$as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } +if ${ac_cv_sys_file_offset_bits+:} false; then : + $as_echo_n "(cached) " >&6 +else + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_file_offset_bits=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _FILE_OFFSET_BITS 64 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_file_offset_bits=64; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_file_offset_bits=unknown + break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 +$as_echo "$ac_cv_sys_file_offset_bits" >&6; } +case $ac_cv_sys_file_offset_bits in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits +_ACEOF +;; +esac +rm -rf conftest* + if test $ac_cv_sys_file_offset_bits = unknown; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 +$as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } +if ${ac_cv_sys_large_files+:} false; then : + $as_echo_n "(cached) " >&6 +else + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_large_files=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _LARGE_FILES 1 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_large_files=1; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_large_files=unknown + break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 +$as_echo "$ac_cv_sys_large_files" >&6; } +case $ac_cv_sys_large_files in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _LARGE_FILES $ac_cv_sys_large_files +_ACEOF +;; +esac +rm -rf conftest* + fi +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 +$as_echo_n "checking for gethostbyname in -lnsl... " >&6; } +if ${ac_cv_lib_nsl_gethostbyname+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnsl $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 gethostbyname (); +int +main () +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_nsl_gethostbyname=yes +else + ac_cv_lib_nsl_gethostbyname=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_nsl_gethostbyname" >&5 +$as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; } +if test "x$ac_cv_lib_nsl_gethostbyname" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBNSL 1 +_ACEOF + + LIBS="-lnsl $LIBS" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5 +$as_echo_n "checking for connect in -lsocket... " >&6; } +if ${ac_cv_lib_socket_connect+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket $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 connect (); +int +main () +{ +return connect (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_socket_connect=yes +else + ac_cv_lib_socket_connect=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_socket_connect" >&5 +$as_echo "$ac_cv_lib_socket_connect" >&6; } +if test "x$ac_cv_lib_socket_connect" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBSOCKET 1 +_ACEOF + + LIBS="-lsocket $LIBS" + +fi + + # Checks for library functions. for ac_func in malloc memset socket do : @@ -11907,7 +13048,7 @@ done -ac_config_files="$ac_config_files Makefile libev/Makefile src/Makefile" +ac_config_files="$ac_config_files Makefile libasyncns/Makefile libev/Makefile src/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -12920,6 +14061,7 @@ do "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "libasyncns/Makefile") CONFIG_FILES="$CONFIG_FILES libasyncns/Makefile" ;; "libev/Makefile") CONFIG_FILES="$CONFIG_FILES libev/Makefile" ;; "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; diff --git a/configure.ac b/configure.ac index a340e0e6..ac74cf38 100755 --- a/configure.ac +++ b/configure.ac @@ -12,6 +12,8 @@ AM_INIT_AUTOMAKE([foreign -Wall -Werror]) AC_PROG_CC AC_PROG_INSTALL AC_PROG_LIBTOOL +AC_PROG_LN_S +AC_PROG_MAKE_SET m4_include([libev/libev.m4]) @@ -27,12 +29,39 @@ AC_C_BIGENDIAN AC_C_INLINE AC_TYPE_SSIZE_T +dnl Checks for header files. +AC_HEADER_ASSERT +AC_HEADER_STDC +AC_HEADER_SYS_WAIT + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_TYPE_SSIZE_T +AC_TYPE_UINT16_T +AC_TYPE_UINT8_T +AC_HEADER_TIME + +dnl Checks for library functions. +AC_FUNC_FORK +AC_FUNC_MALLOC +AC_FUNC_SELECT_ARGTYPES +AC_TYPE_SIGNAL +AC_CHECK_FUNCS([memset select strndup setresuid setreuid strerror]) + +AC_SYS_LARGEFILE + +AC_CHECK_LIB(nsl, gethostbyname) +AC_CHECK_LIB(socket, connect) + # Checks for library functions. AC_CHECK_FUNCS([malloc memset socket]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_FILES([Makefile + libasyncns/Makefile libev/Makefile src/Makefile]) AC_OUTPUT diff --git a/libasyncns/Makefile.am b/libasyncns/Makefile.am new file mode 100644 index 00000000..54f39418 --- /dev/null +++ b/libasyncns/Makefile.am @@ -0,0 +1,26 @@ +# This file is part of libasyncns. +# +# Copyright 2005-2008 Lennart Poettering +# +# libasyncns is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of the +# License, or (at your option) any later version. +# +# libasyncns is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with libasyncns. If not, see +# . + +AM_CFLAGS=-D__EXTENSIONS__ $(PTHREAD_CFLAGS) + +lib_LTLIBRARIES=libasyncns.la +libasyncns_la_CC=$(PTHREAD_CC) +libasyncns_la_SOURCES=asyncns.c asyncns.h +libasyncns_la_LIBADD=$(PTHREAD_LIBS) + +include_HEADERS=asyncns.h diff --git a/libasyncns/Makefile.in b/libasyncns/Makefile.in new file mode 100644 index 00000000..f9a44d37 --- /dev/null +++ b/libasyncns/Makefile.in @@ -0,0 +1,571 @@ +# Makefile.in generated by automake 1.11.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# This file is part of libasyncns. +# +# Copyright 2005-2008 Lennart Poettering +# +# libasyncns is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of the +# License, or (at your option) any later version. +# +# libasyncns is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with libasyncns. If not, see +# . + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = libasyncns +DIST_COMMON = $(include_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/libev/libev.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +libasyncns_la_DEPENDENCIES = +am_libasyncns_la_OBJECTS = asyncns.lo +libasyncns_la_OBJECTS = $(am_libasyncns_la_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libasyncns_la_SOURCES) +DIST_SOURCES = $(libasyncns_la_SOURCES) +HEADERS = $(include_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AM_CFLAGS = -D__EXTENSIONS__ $(PTHREAD_CFLAGS) +lib_LTLIBRARIES = libasyncns.la +libasyncns_la_CC = $(PTHREAD_CC) +libasyncns_la_SOURCES = asyncns.c asyncns.h +libasyncns_la_LIBADD = $(PTHREAD_LIBS) +include_HEADERS = asyncns.h +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libasyncns/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign libasyncns/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libasyncns.la: $(libasyncns_la_OBJECTS) $(libasyncns_la_DEPENDENCIES) $(EXTRA_libasyncns_la_DEPENDENCIES) + $(LINK) -rpath $(libdir) $(libasyncns_la_OBJECTS) $(libasyncns_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asyncns.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-includeHEADERS: $(include_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)" + @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \ + done + +uninstall-includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir) + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-includeHEADERS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-includeHEADERS install-info \ + install-info-am install-libLTLIBRARIES install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-includeHEADERS \ + uninstall-libLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libasyncns/asyncns.c b/libasyncns/asyncns.c new file mode 100644 index 00000000..3b05aa29 --- /dev/null +++ b/libasyncns/asyncns.c @@ -0,0 +1,1500 @@ +/*** + This file is part of libasyncns. + + Copyright 2005-2008 Lennart Poettering + + libasyncns is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libasyncns is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libasyncns. If not, see + . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +/* #undef HAVE_PTHREAD */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_PRCTL_H +#include +#endif + +#if HAVE_PTHREAD +#include +#endif + +#include "asyncns.h" + +#ifndef MSG_NOSIGNAL +#define MSG_NOSIGNAL 0 +#endif + +#define MAX_WORKERS 16 +#define MAX_QUERIES 256 +#define BUFSIZE (10240) + +typedef enum { + REQUEST_ADDRINFO, + RESPONSE_ADDRINFO, + REQUEST_NAMEINFO, + RESPONSE_NAMEINFO, + REQUEST_RES_QUERY, + REQUEST_RES_SEARCH, + RESPONSE_RES, + REQUEST_TERMINATE, + RESPONSE_DIED +} query_type_t; + +enum { + REQUEST_RECV_FD = 0, + REQUEST_SEND_FD = 1, + RESPONSE_RECV_FD = 2, + RESPONSE_SEND_FD = 3, + MESSAGE_FD_MAX = 4 +}; + +struct asyncns { + int fds[4]; + +#ifndef HAVE_PTHREAD + pid_t workers[MAX_WORKERS]; +#else + pthread_t workers[MAX_WORKERS]; +#endif + unsigned valid_workers; + + unsigned current_id, current_index; + asyncns_query_t* queries[MAX_QUERIES]; + + asyncns_query_t *done_head, *done_tail; + + int n_queries; + int dead; +}; + +struct asyncns_query { + asyncns_t *asyncns; + int done; + unsigned id; + query_type_t type; + asyncns_query_t *done_next, *done_prev; + int ret; + int _errno; + int _h_errno; + struct addrinfo *addrinfo; + char *serv, *host; + void *userdata; +}; + +typedef struct rheader { + query_type_t type; + unsigned id; + size_t length; +} rheader_t; + +typedef struct addrinfo_request { + struct rheader header; + int hints_is_null; + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t node_len, service_len; +} addrinfo_request_t; + +typedef struct addrinfo_response { + struct rheader header; + int ret; + int _errno; + int _h_errno; + /* followed by addrinfo_serialization[] */ +} addrinfo_response_t; + +typedef struct addrinfo_serialization { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + size_t canonname_len; + /* Followed by ai_addr amd ai_canonname with variable lengths */ +} addrinfo_serialization_t; + +typedef struct nameinfo_request { + struct rheader header; + int flags; + socklen_t sockaddr_len; + int gethost, getserv; +} nameinfo_request_t; + +typedef struct nameinfo_response { + struct rheader header; + size_t hostlen, servlen; + int ret; + int _errno; + int _h_errno; +} nameinfo_response_t; + +typedef struct res_request { + struct rheader header; + int class; + int type; + size_t dname_len; +} res_request_t; + +typedef struct res_response { + struct rheader header; + int ret; + int _errno; + int _h_errno; +} res_response_t; + +typedef union packet { + rheader_t rheader; + addrinfo_request_t addrinfo_request; + addrinfo_response_t addrinfo_response; + nameinfo_request_t nameinfo_request; + nameinfo_response_t nameinfo_response; + res_request_t res_request; + res_response_t res_response; +} packet_t; + +#ifndef HAVE_STRNDUP + +static char *strndup(const char *s, size_t l) { + size_t a; + char *n; + + a = strlen(s); + if (a > l) + a = l; + + if (!(n = malloc(a+1))) + return NULL; + + memcpy(n, s, a); + n[a] = 0; + + return n; +} + +#endif + +#ifndef HAVE_PTHREAD + +static int close_allv(const int except_fds[]) { + struct rlimit rl; + int fd, maxfd; + +#ifdef __linux__ + + DIR *d; + + assert(except_fds); + + if ((d = opendir("/proc/self/fd"))) { + + struct dirent *de; + + while ((de = readdir(d))) { + int found; + long l; + char *e = NULL; + int i; + + if (de->d_name[0] == '.') + continue; + + errno = 0; + l = strtol(de->d_name, &e, 10); + if (errno != 0 || !e || *e) { + closedir(d); + errno = EINVAL; + return -1; + } + + fd = (int) l; + + if ((long) fd != l) { + closedir(d); + errno = EINVAL; + return -1; + } + + if (fd < 3) + continue; + + if (fd == dirfd(d)) + continue; + + found = 0; + for (i = 0; except_fds[i] >= 0; i++) + if (except_fds[i] == fd) { + found = 1; + break; + } + + if (found) + continue; + + if (close(fd) < 0) { + int saved_errno; + + saved_errno = errno; + closedir(d); + errno = saved_errno; + + return -1; + } + } + + closedir(d); + return 0; + } + +#endif + + if (getrlimit(RLIMIT_NOFILE, &rl) > 0) + maxfd = (int) rl.rlim_max; + else + maxfd = sysconf(_SC_OPEN_MAX); + + for (fd = 3; fd < maxfd; fd++) { + int i, found; + + found = 0; + for (i = 0; except_fds[i] >= 0; i++) + if (except_fds[i] == fd) { + found = 1; + continue; + } + + if (found) + continue; + + if (close(fd) < 0 && errno != EBADF) + return -1; + } + + return 0; +} + +static int reset_sigsv(const int except[]) { + int sig; + assert(except); + + for (sig = 1; sig < NSIG; sig++) { + int reset = 1; + + switch (sig) { + case SIGKILL: + case SIGSTOP: + reset = 0; + break; + + default: { + int i; + + for (i = 0; except[i] > 0; i++) { + if (sig == except[i]) { + reset = 0; + break; + } + } + } + } + + if (reset) { + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; + + /* On Linux the first two RT signals are reserved by + * glibc, and sigaction() will return EINVAL for them. */ + if ((sigaction(sig, &sa, NULL) < 0)) + if (errno != EINVAL) + return -1; + } + } + + return 0; +} + +static int ignore_sigsv(const int ignore[]) { + int i; + assert(ignore); + + for (i = 0; ignore[i] > 0; i++) { + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_IGN; + + if ((sigaction(ignore[i], &sa, NULL) < 0)) + return -1; + } + + return 0; +} + +#endif + +static int fd_nonblock(int fd) { + int i; + assert(fd >= 0); + + if ((i = fcntl(fd, F_GETFL, 0)) < 0) + return -1; + + if (i & O_NONBLOCK) + return 0; + + return fcntl(fd, F_SETFL, i | O_NONBLOCK); +} + +static int fd_cloexec(int fd) { + int v; + assert(fd >= 0); + + if ((v = fcntl(fd, F_GETFD, 0)) < 0) + return -1; + + if (v & FD_CLOEXEC) + return 0; + + return fcntl(fd, F_SETFD, v | FD_CLOEXEC); +} + +static int send_died(int out_fd) { + rheader_t rh; + assert(out_fd > 0); + + memset(&rh, 0, sizeof(rh)); + rh.type = RESPONSE_DIED; + rh.id = 0; + rh.length = sizeof(rh); + + return send(out_fd, &rh, rh.length, MSG_NOSIGNAL); +} + +static void *serialize_addrinfo(void *p, const struct addrinfo *ai, size_t *length, size_t maxlength) { + addrinfo_serialization_t s; + size_t cnl, l; + assert(p); + assert(ai); + assert(length); + assert(*length <= maxlength); + + cnl = (ai->ai_canonname ? strlen(ai->ai_canonname)+1 : 0); + l = sizeof(addrinfo_serialization_t) + ai->ai_addrlen + cnl; + + if (*length + l > maxlength) + return NULL; + + s.ai_flags = ai->ai_flags; + s.ai_family = ai->ai_family; + s.ai_socktype = ai->ai_socktype; + s.ai_protocol = ai->ai_protocol; + s.ai_addrlen = ai->ai_addrlen; + s.canonname_len = cnl; + + memcpy((uint8_t*) p, &s, sizeof(addrinfo_serialization_t)); + memcpy((uint8_t*) p + sizeof(addrinfo_serialization_t), ai->ai_addr, ai->ai_addrlen); + + if (ai->ai_canonname) + strcpy((char*) p + sizeof(addrinfo_serialization_t) + ai->ai_addrlen, ai->ai_canonname); + + *length += l; + return (uint8_t*) p + l; +} + +static int send_addrinfo_reply(int out_fd, unsigned id, int ret, struct addrinfo *ai, int _errno, int _h_errno) { + addrinfo_response_t data[BUFSIZE/sizeof(addrinfo_response_t) + 1]; + addrinfo_response_t *resp = data; + assert(out_fd >= 0); + + memset(data, 0, sizeof(data)); + resp->header.type = RESPONSE_ADDRINFO; + resp->header.id = id; + resp->header.length = sizeof(addrinfo_response_t); + resp->ret = ret; + resp->_errno = _errno; + resp->_h_errno = _h_errno; + + if (ret == 0 && ai) { + void *p = data + 1; + struct addrinfo *k; + + for (k = ai; k; k = k->ai_next) { + + if (!(p = serialize_addrinfo(p, k, &resp->header.length, (char*) data + BUFSIZE - (char*) p))) { + resp->ret = EAI_MEMORY; + break; + } + } + } + + if (ai) + freeaddrinfo(ai); + + return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL); +} + +static int send_nameinfo_reply(int out_fd, unsigned id, int ret, const char *host, const char *serv, int _errno, int _h_errno) { + nameinfo_response_t data[BUFSIZE/sizeof(nameinfo_response_t) + 1]; + size_t hl, sl; + nameinfo_response_t *resp = data; + + assert(out_fd >= 0); + + sl = serv ? strlen(serv)+1 : 0; + hl = host ? strlen(host)+1 : 0; + + memset(data, 0, sizeof(data)); + resp->header.type = RESPONSE_NAMEINFO; + resp->header.id = id; + resp->header.length = sizeof(nameinfo_response_t) + hl + sl; + resp->ret = ret; + resp->_errno = _errno; + resp->_h_errno = _h_errno; + resp->hostlen = hl; + resp->servlen = sl; + + assert(sizeof(data) >= resp->header.length); + + if (host) + memcpy((uint8_t *)data + sizeof(nameinfo_response_t), host, hl); + + if (serv) + memcpy((uint8_t *)data + sizeof(nameinfo_response_t) + hl, serv, sl); + + return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL); +} + +static int send_res_reply(int out_fd, unsigned id, const unsigned char *answer, int ret, int _errno, int _h_errno) { + res_response_t data[BUFSIZE/sizeof(res_response_t) + 1]; + res_response_t *resp = data; + + assert(out_fd >= 0); + + memset(data, 0, sizeof(data)); + resp->header.type = RESPONSE_RES; + resp->header.id = id; + resp->header.length = sizeof(res_response_t) + (ret < 0 ? 0 : ret); + resp->ret = ret; + resp->_errno = _errno; + resp->_h_errno = _h_errno; + + assert(sizeof(data) >= resp->header.length); + + if (ret > 0) + memcpy((uint8_t *)data + sizeof(res_response_t), answer, ret); + + return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL); +} + +static int handle_request(int out_fd, const packet_t *packet, size_t length) { + const rheader_t *req; + assert(out_fd >= 0); + + req = &packet->rheader; + assert(req); + assert(length >= sizeof(rheader_t)); + assert(length == req->length); + + switch (req->type) { + + case REQUEST_ADDRINFO: { + struct addrinfo ai, *result = NULL; + const addrinfo_request_t *ai_req = &packet->addrinfo_request; + const char *node, *service; + int ret; + + assert(length >= sizeof(addrinfo_request_t)); + assert(length == sizeof(addrinfo_request_t) + ai_req->node_len + ai_req->service_len); + + memset(&ai, 0, sizeof(ai)); + ai.ai_flags = ai_req->ai_flags; + ai.ai_family = ai_req->ai_family; + ai.ai_socktype = ai_req->ai_socktype; + ai.ai_protocol = ai_req->ai_protocol; + + node = ai_req->node_len ? (const char*) ai_req + sizeof(addrinfo_request_t) : NULL; + service = ai_req->service_len ? (const char*) ai_req + sizeof(addrinfo_request_t) + ai_req->node_len : NULL; + + ret = getaddrinfo(node, service, + ai_req->hints_is_null ? NULL : &ai, + &result); + + /* send_addrinfo_reply() frees result */ + return send_addrinfo_reply(out_fd, req->id, ret, result, errno, h_errno); + } + + case REQUEST_NAMEINFO: { + int ret; + const nameinfo_request_t *ni_req = &packet->nameinfo_request; + char hostbuf[NI_MAXHOST], servbuf[NI_MAXSERV]; + struct sockaddr_storage sa; + + assert(length >= sizeof(nameinfo_request_t)); + assert(length == sizeof(nameinfo_request_t) + ni_req->sockaddr_len); + + memcpy(&sa, (const uint8_t *) ni_req + sizeof(nameinfo_request_t), ni_req->sockaddr_len); + + ret = getnameinfo((struct sockaddr *)&sa, ni_req->sockaddr_len, + ni_req->gethost ? hostbuf : NULL, ni_req->gethost ? sizeof(hostbuf) : 0, + ni_req->getserv ? servbuf : NULL, ni_req->getserv ? sizeof(servbuf) : 0, + ni_req->flags); + + return send_nameinfo_reply(out_fd, req->id, ret, + ret == 0 && ni_req->gethost ? hostbuf : NULL, + ret == 0 && ni_req->getserv ? servbuf : NULL, + errno, h_errno); + } + + case REQUEST_TERMINATE: + /* Quit */ + return -1; + + default: + ; + } + + return 0; +} + +#ifndef HAVE_PTHREAD + +static int process_worker(int in_fd, int out_fd) { + int have_death_sig = 0; + int good_fds[3]; + int ret = 1; + + const int ignore_sigs[] = { + SIGINT, + SIGHUP, + SIGPIPE, + SIGUSR1, + SIGUSR2, + -1 + }; + + assert(in_fd > 2); + assert(out_fd > 2); + + close(0); + close(1); + close(2); + + if (open("/dev/null", O_RDONLY) != 0) + goto fail; + + if (open("/dev/null", O_WRONLY) != 1) + goto fail; + + if (open("/dev/null", O_WRONLY) != 2) + goto fail; + + if (chdir("/") < 0) + goto fail; + + if (geteuid() == 0) { + struct passwd *pw; + int r; + + if ((pw = getpwnam("nobody"))) { +#ifdef HAVE_SETRESUID + r = setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid); +#elif HAVE_SETREUID + r = setreuid(pw->pw_uid, pw->pw_uid); +#else + if ((r = setuid(pw->pw_uid)) >= 0) + r = seteuid(pw->pw_uid); +#endif + if (r < 0) + goto fail; + } + } + + if (reset_sigsv(ignore_sigs) < 0) + goto fail; + + if (ignore_sigsv(ignore_sigs) < 0) + goto fail; + + good_fds[0] = in_fd; good_fds[1] = out_fd; good_fds[2] = -1; + if (close_allv(good_fds) < 0) + goto fail; + +#ifdef PR_SET_PDEATHSIG + if (prctl(PR_SET_PDEATHSIG, SIGTERM) >= 0) + have_death_sig = 1; +#endif + + if (!have_death_sig) + fd_nonblock(in_fd); + + while (getppid() > 1) { /* if the parent PID is 1 our parent process died. */ + packet_t buf[BUFSIZE/sizeof(packet_t) + 1]; + ssize_t length; + + if (!have_death_sig) { + fd_set fds; + struct timeval tv = { 0, 500000 }; + + FD_ZERO(&fds); + FD_SET(in_fd, &fds); + + if (select(in_fd+1, &fds, NULL, NULL, &tv) < 0) + break; + + if (getppid() == 1) + break; + } + + if ((length = recv(in_fd, buf, sizeof(buf), 0)) <= 0) { + + if (length < 0 && + (errno == EAGAIN || errno == EINTR)) + continue; + + break; + } + + if (handle_request(out_fd, buf, (size_t) length) < 0) + break; + } + + ret = 0; + +fail: + send_died(out_fd); + + return ret; +} + +#else + +static void* thread_worker(void *p) { + asyncns_t *asyncns = p; + sigset_t fullset; + + /* No signals in this thread please */ + sigfillset(&fullset); + pthread_sigmask(SIG_BLOCK, &fullset, NULL); + + while (!asyncns->dead) { + packet_t buf[BUFSIZE/sizeof(packet_t) + 1]; + ssize_t length; + + if ((length = recv(asyncns->fds[REQUEST_RECV_FD], buf, sizeof(buf), 0)) <= 0) { + + if (length < 0 && + (errno == EAGAIN || errno == EINTR)) + continue; + + break; + } + + if (asyncns->dead) + break; + + if (handle_request(asyncns->fds[RESPONSE_SEND_FD], buf, (size_t) length) < 0) + break; + } + + send_died(asyncns->fds[RESPONSE_SEND_FD]); + + return NULL; +} + +#endif + +asyncns_t* asyncns_new(unsigned n_proc) { + asyncns_t *asyncns = NULL; + int i; + assert(n_proc >= 1); + + if (n_proc > MAX_WORKERS) + n_proc = MAX_WORKERS; + + if (!(asyncns = malloc(sizeof(asyncns_t)))) { + errno = ENOMEM; + goto fail; + } + + asyncns->dead = 0; + asyncns->valid_workers = 0; + + for (i = 0; i < MESSAGE_FD_MAX; i++) + asyncns->fds[i] = -1; + + memset(asyncns->queries, 0, sizeof(asyncns->queries)); + + if (socketpair(PF_UNIX, SOCK_DGRAM, 0, asyncns->fds) < 0 || + socketpair(PF_UNIX, SOCK_DGRAM, 0, asyncns->fds+2) < 0) + goto fail; + + for (i = 0; i < MESSAGE_FD_MAX; i++) + fd_cloexec(asyncns->fds[i]); + + for (asyncns->valid_workers = 0; asyncns->valid_workers < n_proc; asyncns->valid_workers++) { + +#ifndef HAVE_PTHREAD + if ((asyncns->workers[asyncns->valid_workers] = fork()) < 0) + goto fail; + else if (asyncns->workers[asyncns->valid_workers] == 0) { + int ret; + + close(asyncns->fds[REQUEST_SEND_FD]); + close(asyncns->fds[RESPONSE_RECV_FD]); + ret = process_worker(asyncns->fds[REQUEST_RECV_FD], asyncns->fds[RESPONSE_SEND_FD]); + close(asyncns->fds[REQUEST_RECV_FD]); + close(asyncns->fds[RESPONSE_SEND_FD]); + _exit(ret); + } +#else + int r; + + if ((r = pthread_create(&asyncns->workers[asyncns->valid_workers], NULL, thread_worker, asyncns)) != 0) { + errno = r; + goto fail; + } +#endif + } + +#ifndef HAVE_PTHREAD + close(asyncns->fds[REQUEST_RECV_FD]); + close(asyncns->fds[RESPONSE_SEND_FD]); + asyncns->fds[REQUEST_RECV_FD] = asyncns->fds[RESPONSE_SEND_FD] = -1; +#endif + + asyncns->current_index = asyncns->current_id = 0; + asyncns->done_head = asyncns->done_tail = NULL; + asyncns->n_queries = 0; + + fd_nonblock(asyncns->fds[RESPONSE_RECV_FD]); + + return asyncns; + +fail: + if (asyncns) + asyncns_free(asyncns); + + return NULL; +} + +void asyncns_free(asyncns_t *asyncns) { + int i; + int saved_errno = errno; + unsigned p; + + assert(asyncns); + + asyncns->dead = 1; + + if (asyncns->fds[REQUEST_SEND_FD] >= 0) { + rheader_t req; + + memset(&req, 0, sizeof(req)); + req.type = REQUEST_TERMINATE; + req.length = sizeof(req); + req.id = 0; + + /* Send one termination packet for each worker */ + for (p = 0; p < asyncns->valid_workers; p++) + send(asyncns->fds[REQUEST_SEND_FD], &req, req.length, MSG_NOSIGNAL); + } + + /* Now terminate them and wait until they are gone. */ + for (p = 0; p < asyncns->valid_workers; p++) { +#ifndef HAVE_PTHREAD + kill(asyncns->workers[p], SIGTERM); + for (;;) { + if (waitpid(asyncns->workers[p], NULL, 0) >= 0 || errno != EINTR) + break; + } +#else + for (;;) { + if (pthread_join(asyncns->workers[p], NULL) != EINTR) + break; + } +#endif + } + + /* Close all communication channels */ + for (i = 0; i < MESSAGE_FD_MAX; i++) + if (asyncns->fds[i] >= 0) + close(asyncns->fds[i]); + + for (p = 0; p < MAX_QUERIES; p++) + if (asyncns->queries[p]) + asyncns_cancel(asyncns, asyncns->queries[p]); + + free(asyncns); + + errno = saved_errno; +} + +int asyncns_fd(asyncns_t *asyncns) { + assert(asyncns); + + return asyncns->fds[RESPONSE_RECV_FD]; +} + +static asyncns_query_t *lookup_query(asyncns_t *asyncns, unsigned id) { + asyncns_query_t *q; + assert(asyncns); + + if ((q = asyncns->queries[id % MAX_QUERIES])) + if (q->id == id) + return q; + + return NULL; +} + +static void complete_query(asyncns_t *asyncns, asyncns_query_t *q) { + assert(asyncns); + assert(q); + assert(!q->done); + + q->done = 1; + + if ((q->done_prev = asyncns->done_tail)) + asyncns->done_tail->done_next = q; + else + asyncns->done_head = q; + + asyncns->done_tail = q; + q->done_next = NULL; +} + +static const void *unserialize_addrinfo(const void *p, struct addrinfo **ret_ai, size_t *length) { + addrinfo_serialization_t s; + size_t l; + struct addrinfo *ai; + assert(p); + assert(ret_ai); + assert(length); + + if (*length < sizeof(addrinfo_serialization_t)) + return NULL; + + memcpy(&s, p, sizeof(s)); + + l = sizeof(addrinfo_serialization_t) + s.ai_addrlen + s.canonname_len; + if (*length < l) + return NULL; + + if (!(ai = malloc(sizeof(struct addrinfo)))) + goto fail; + + ai->ai_addr = NULL; + ai->ai_canonname = NULL; + ai->ai_next = NULL; + + if (s.ai_addrlen && !(ai->ai_addr = malloc(s.ai_addrlen))) + goto fail; + + if (s.canonname_len && !(ai->ai_canonname = malloc(s.canonname_len))) + goto fail; + + ai->ai_flags = s.ai_flags; + ai->ai_family = s.ai_family; + ai->ai_socktype = s.ai_socktype; + ai->ai_protocol = s.ai_protocol; + ai->ai_addrlen = s.ai_addrlen; + + if (ai->ai_addr) + memcpy(ai->ai_addr, (const uint8_t*) p + sizeof(addrinfo_serialization_t), s.ai_addrlen); + + if (ai->ai_canonname) + memcpy(ai->ai_canonname, (const uint8_t*) p + sizeof(addrinfo_serialization_t) + s.ai_addrlen, s.canonname_len); + + *length -= l; + *ret_ai = ai; + + return (const uint8_t*) p + l; + + +fail: + if (ai) + asyncns_freeaddrinfo(ai); + + return NULL; +} + +static int handle_response(asyncns_t *asyncns, const packet_t *packet, size_t length) { + const rheader_t *resp; + asyncns_query_t *q; + + assert(asyncns); + + resp = &packet->rheader; + assert(resp); + assert(length >= sizeof(rheader_t)); + assert(length == resp->length); + + if (resp->type == RESPONSE_DIED) { + asyncns->dead = 1; + return 0; + } + + if (!(q = lookup_query(asyncns, resp->id))) + return 0; + + switch (resp->type) { + case RESPONSE_ADDRINFO: { + const addrinfo_response_t *ai_resp = &packet->addrinfo_response; + const void *p; + size_t l; + struct addrinfo *prev = NULL; + + assert(length >= sizeof(addrinfo_response_t)); + assert(q->type == REQUEST_ADDRINFO); + + q->ret = ai_resp->ret; + q->_errno = ai_resp->_errno; + q->_h_errno = ai_resp->_h_errno; + l = length - sizeof(addrinfo_response_t); + p = (const uint8_t*) resp + sizeof(addrinfo_response_t); + + while (l > 0 && p) { + struct addrinfo *ai = NULL; + p = unserialize_addrinfo(p, &ai, &l); + + if (!p || !ai) { + q->ret = EAI_MEMORY; + break; + } + + if (prev) + prev->ai_next = ai; + else + q->addrinfo = ai; + + prev = ai; + } + + complete_query(asyncns, q); + break; + } + + case RESPONSE_NAMEINFO: { + const nameinfo_response_t *ni_resp = &packet->nameinfo_response; + + assert(length >= sizeof(nameinfo_response_t)); + assert(q->type == REQUEST_NAMEINFO); + + q->ret = ni_resp->ret; + q->_errno = ni_resp->_errno; + q->_h_errno = ni_resp->_h_errno; + + if (ni_resp->hostlen) + if (!(q->host = strndup((const char*) ni_resp + sizeof(nameinfo_response_t), ni_resp->hostlen-1))) + q->ret = EAI_MEMORY; + + if (ni_resp->servlen) + if (!(q->serv = strndup((const char*) ni_resp + sizeof(nameinfo_response_t) + ni_resp->hostlen, ni_resp->servlen-1))) + q->ret = EAI_MEMORY; + + complete_query(asyncns, q); + break; + } + + case RESPONSE_RES: { + const res_response_t *res_resp = &packet->res_response; + + assert(length >= sizeof(res_response_t)); + assert(q->type == REQUEST_RES_QUERY || q->type == REQUEST_RES_SEARCH); + + q->ret = res_resp->ret; + q->_errno = res_resp->_errno; + q->_h_errno = res_resp->_h_errno; + + if (res_resp->ret >= 0) { + if (!(q->serv = malloc(res_resp->ret))) { + q->ret = -1; + q->_errno = ENOMEM; + } else + memcpy(q->serv, (const char *)resp + sizeof(res_response_t), res_resp->ret); + } + + complete_query(asyncns, q); + break; + } + + default: + ; + } + + return 0; +} + +int asyncns_wait(asyncns_t *asyncns, int block) { + int handled = 0; + assert(asyncns); + + for (;;) { + packet_t buf[BUFSIZE/sizeof(packet_t) + 1]; + ssize_t l; + + if (asyncns->dead) { + errno = ECHILD; + return -1; + } + + if (((l = recv(asyncns->fds[RESPONSE_RECV_FD], buf, sizeof(buf), 0)) < 0)) { + fd_set fds; + + if (errno != EAGAIN) + return -1; + + if (!block || handled) + return 0; + + FD_ZERO(&fds); + FD_SET(asyncns->fds[RESPONSE_RECV_FD], &fds); + + if (select(asyncns->fds[RESPONSE_RECV_FD]+1, &fds, NULL, NULL, NULL) < 0) + return -1; + + continue; + } + + if (handle_response(asyncns, buf, (size_t) l) < 0) + return -1; + + handled = 1; + } +} + +static asyncns_query_t *alloc_query(asyncns_t *asyncns) { + asyncns_query_t *q; + assert(asyncns); + + if (asyncns->n_queries >= MAX_QUERIES) { + errno = ENOMEM; + return NULL; + } + + while (asyncns->queries[asyncns->current_index]) { + + asyncns->current_index++; + asyncns->current_id++; + + while (asyncns->current_index >= MAX_QUERIES) + asyncns->current_index -= MAX_QUERIES; + } + + if (!(q = asyncns->queries[asyncns->current_index] = malloc(sizeof(asyncns_query_t)))) { + errno = ENOMEM; + return NULL; + } + + asyncns->n_queries++; + + q->asyncns = asyncns; + q->done = 0; + q->id = asyncns->current_id; + q->done_next = q->done_prev = NULL; + q->ret = 0; + q->_errno = 0; + q->_h_errno = 0; + q->addrinfo = NULL; + q->userdata = NULL; + q->host = q->serv = NULL; + + return q; +} + +asyncns_query_t* asyncns_getaddrinfo(asyncns_t *asyncns, const char *node, const char *service, const struct addrinfo *hints) { + addrinfo_request_t data[BUFSIZE/sizeof(addrinfo_request_t) + 1]; + addrinfo_request_t *req = data; + asyncns_query_t *q; + assert(asyncns); + assert(node || service); + + if (asyncns->dead) { + errno = ECHILD; + return NULL; + } + + if (!(q = alloc_query(asyncns))) + return NULL; + + memset(req, 0, sizeof(addrinfo_request_t)); + + req->node_len = node ? strlen(node)+1 : 0; + req->service_len = service ? strlen(service)+1 : 0; + + req->header.id = q->id; + req->header.type = q->type = REQUEST_ADDRINFO; + req->header.length = sizeof(addrinfo_request_t) + req->node_len + req->service_len; + + if (req->header.length > BUFSIZE) { + errno = ENOMEM; + goto fail; + } + + if (!(req->hints_is_null = !hints)) { + req->ai_flags = hints->ai_flags; + req->ai_family = hints->ai_family; + req->ai_socktype = hints->ai_socktype; + req->ai_protocol = hints->ai_protocol; + } + + if (node) + strcpy((char*) req + sizeof(addrinfo_request_t), node); + + if (service) + strcpy((char*) req + sizeof(addrinfo_request_t) + req->node_len, service); + + if (send(asyncns->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0) + goto fail; + + return q; + +fail: + if (q) + asyncns_cancel(asyncns, q); + + return NULL; +} + +int asyncns_getaddrinfo_done(asyncns_t *asyncns, asyncns_query_t* q, struct addrinfo **ret_res) { + int ret; + assert(asyncns); + assert(q); + assert(q->asyncns == asyncns); + assert(q->type == REQUEST_ADDRINFO); + + if (asyncns->dead) { + errno = ECHILD; + return EAI_SYSTEM; + } + + if (!q->done) + return EAI_AGAIN; + + *ret_res = q->addrinfo; + q->addrinfo = NULL; + + ret = q->ret; + + if (ret == EAI_SYSTEM) + errno = q->_errno; + + if (ret != 0) + h_errno = q->_h_errno; + + asyncns_cancel(asyncns, q); + + return ret; +} + +asyncns_query_t* asyncns_getnameinfo(asyncns_t *asyncns, const struct sockaddr *sa, socklen_t salen, int flags, int gethost, int getserv) { + nameinfo_request_t data[BUFSIZE/sizeof(nameinfo_request_t) + 1]; + nameinfo_request_t *req = data; + asyncns_query_t *q; + + assert(asyncns); + assert(sa); + assert(salen > 0); + + if (asyncns->dead) { + errno = ECHILD; + return NULL; + } + + if (!(q = alloc_query(asyncns))) + return NULL; + + memset(req, 0, sizeof(nameinfo_request_t)); + + req->header.id = q->id; + req->header.type = q->type = REQUEST_NAMEINFO; + req->header.length = sizeof(nameinfo_request_t) + salen; + + if (req->header.length > BUFSIZE) { + errno = ENOMEM; + goto fail; + } + + req->flags = flags; + req->sockaddr_len = salen; + req->gethost = gethost; + req->getserv = getserv; + + memcpy((uint8_t*) req + sizeof(nameinfo_request_t), sa, salen); + + if (send(asyncns->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0) + goto fail; + + return q; + +fail: + if (q) + asyncns_cancel(asyncns, q); + + return NULL; +} + +int asyncns_getnameinfo_done(asyncns_t *asyncns, asyncns_query_t* q, char *ret_host, size_t hostlen, char *ret_serv, size_t servlen) { + int ret; + assert(asyncns); + assert(q); + assert(q->asyncns == asyncns); + assert(q->type == REQUEST_NAMEINFO); + assert(!ret_host || hostlen); + assert(!ret_serv || servlen); + + if (asyncns->dead) { + errno = ECHILD; + return EAI_SYSTEM; + } + + if (!q->done) + return EAI_AGAIN; + + if (ret_host && q->host) { + strncpy(ret_host, q->host, hostlen); + ret_host[hostlen-1] = 0; + } + + if (ret_serv && q->serv) { + strncpy(ret_serv, q->serv, servlen); + ret_serv[servlen-1] = 0; + } + + ret = q->ret; + + if (ret == EAI_SYSTEM) + errno = q->_errno; + + if (ret != 0) + h_errno = q->_h_errno; + + asyncns_cancel(asyncns, q); + + return ret; +} + +static asyncns_query_t * asyncns_res(asyncns_t *asyncns, query_type_t qtype, const char *dname, int class, int type) { + res_request_t data[BUFSIZE/sizeof(res_request_t) + 1]; + res_request_t *req = data; + asyncns_query_t *q; + + assert(asyncns); + assert(dname); + + if (asyncns->dead) { + errno = ECHILD; + return NULL; + } + + if (!(q = alloc_query(asyncns))) + return NULL; + + memset(req, 0, sizeof(res_request_t)); + + req->dname_len = strlen(dname) + 1; + + req->header.id = q->id; + req->header.type = q->type = qtype; + req->header.length = sizeof(res_request_t) + req->dname_len; + + if (req->header.length > BUFSIZE) { + errno = ENOMEM; + goto fail; + } + + req->class = class; + req->type = type; + + strcpy((char*) req + sizeof(res_request_t), dname); + + if (send(asyncns->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0) + goto fail; + + return q; + +fail: + if (q) + asyncns_cancel(asyncns, q); + + return NULL; +} + +asyncns_query_t* asyncns_res_query(asyncns_t *asyncns, const char *dname, int class, int type) { + return asyncns_res(asyncns, REQUEST_RES_QUERY, dname, class, type); +} + +asyncns_query_t* asyncns_res_search(asyncns_t *asyncns, const char *dname, int class, int type) { + return asyncns_res(asyncns, REQUEST_RES_SEARCH, dname, class, type); +} + +int asyncns_res_done(asyncns_t *asyncns, asyncns_query_t* q, unsigned char **answer) { + int ret; + assert(asyncns); + assert(q); + assert(q->asyncns == asyncns); + assert(q->type == REQUEST_RES_QUERY || q->type == REQUEST_RES_SEARCH); + assert(answer); + + if (asyncns->dead) { + errno = ECHILD; + return -ECHILD; + } + + if (!q->done) { + errno = EAGAIN; + return -EAGAIN; + } + + *answer = (unsigned char *)q->serv; + q->serv = NULL; + + ret = q->ret; + + if (ret < 0) { + errno = q->_errno; + h_errno = q->_h_errno; + } + + asyncns_cancel(asyncns, q); + + return ret < 0 ? -errno : ret; +} + +asyncns_query_t* asyncns_getnext(asyncns_t *asyncns) { + assert(asyncns); + return asyncns->done_head; +} + +int asyncns_getnqueries(asyncns_t *asyncns) { + assert(asyncns); + return asyncns->n_queries; +} + +void asyncns_cancel(asyncns_t *asyncns, asyncns_query_t* q) { + int i; + int saved_errno = errno; + + assert(asyncns); + assert(q); + assert(q->asyncns == asyncns); + assert(asyncns->n_queries > 0); + + if (q->done) { + + if (q->done_prev) + q->done_prev->done_next = q->done_next; + else + asyncns->done_head = q->done_next; + + if (q->done_next) + q->done_next->done_prev = q->done_prev; + else + asyncns->done_tail = q->done_prev; + } + + i = q->id % MAX_QUERIES; + assert(asyncns->queries[i] == q); + asyncns->queries[i] = NULL; + + asyncns_freeaddrinfo(q->addrinfo); + free(q->host); + free(q->serv); + + asyncns->n_queries--; + free(q); + + errno = saved_errno; +} + +void asyncns_freeaddrinfo(struct addrinfo *ai) { + int saved_errno = errno; + + while (ai) { + struct addrinfo *next = ai->ai_next; + + free(ai->ai_addr); + free(ai->ai_canonname); + free(ai); + + ai = next; + } + + errno = saved_errno; +} + +void asyncns_freeanswer(unsigned char *answer) { + int saved_errno = errno; + + if (!answer) + return; + + /* Please note that this function is new in libasyncns 0.4. In + * older versions you were supposed to free the answer directly + * with free(). Hence, if this function is changed to do more than + * just a simple free() this must be considered ABI/API breakage! */ + + free(answer); + + errno = saved_errno; +} + +int asyncns_isdone(asyncns_t *asyncns, asyncns_query_t*q) { + assert(asyncns); + assert(q); + assert(q->asyncns == asyncns); + + return q->done; +} + +void asyncns_setuserdata(asyncns_t *asyncns, asyncns_query_t *q, void *userdata) { + assert(q); + assert(asyncns); + assert(q->asyncns = asyncns); + + q->userdata = userdata; +} + +void* asyncns_getuserdata(asyncns_t *asyncns, asyncns_query_t *q) { + assert(q); + assert(asyncns); + assert(q->asyncns = asyncns); + + return q->userdata; +} diff --git a/libasyncns/asyncns.h b/libasyncns/asyncns.h new file mode 100644 index 00000000..9f2cbd6f --- /dev/null +++ b/libasyncns/asyncns.h @@ -0,0 +1,163 @@ +#ifndef fooasyncnshfoo +#define fooasyncnshfoo + +/*** + This file is part of libasyncns. + + Copyright 2005-2008 Lennart Poettering + + libasyncns is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libasyncns is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libasyncns. If not, see + . +***/ + +#include +#include +#include + +/** \mainpage + * + * \section moo Method of operation + * + * To use libasyncns allocate an asyncns_t object with + * asyncns_new(). This will spawn a number of worker threads (or processes, depending on what is available) which + * are subsequently used to process the queries the controlling + * program issues via asyncns_getaddrinfo() and + * asyncns_getnameinfo(). Use asyncns_free() to shut down the worker + * threads/processes. + * + * Since libasyncns may fork off new processes you have to make sure that + * your program is not irritated by spurious SIGCHLD signals. + */ + +/** \example asyncns-test.c + * An example program */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** An opaque libasyncns session structure */ +typedef struct asyncns asyncns_t; + +/** An opaque libasyncns query structure */ +typedef struct asyncns_query asyncns_query_t; + +/** Allocate a new libasyncns session with n_proc worker processes/threads */ +asyncns_t* asyncns_new(unsigned n_proc); + +/** Free a libasyncns session. This destroys all attached + * asyncns_query_t objects automatically */ +void asyncns_free(asyncns_t *asyncns); + +/** Return the UNIX file descriptor to select() for readability + * on. Use this function to integrate libasyncns with your custom main + * loop. */ +int asyncns_fd(asyncns_t *asyncns); + +/** Process pending responses. After this function is called you can + * get the next completed query object(s) using asyncns_getnext(). If + * block is non-zero wait until at least one response has been + * processed. If block is zero, process all pending responses and + * return. */ +int asyncns_wait(asyncns_t *asyncns, int block); + +/** Issue a name to address query on the specified session. The + * arguments are compatible with the ones of libc's + * getaddrinfo(3). The function returns a new query object. When the + * query is completed you may retrieve the results using + * asyncns_getaddrinfo_done().*/ +asyncns_query_t* asyncns_getaddrinfo(asyncns_t *asyncns, const char *node, const char *service, const struct addrinfo *hints); + +/** Retrieve the results of a preceding asyncns_getaddrinfo() + * call. Returns a addrinfo structure and a return value compatible + * with libc's getaddrinfo(3). The query object q is destroyed by this + * call and may not be used any further. Make sure to free the + * returned addrinfo structure with asyncns_freeaddrinfo() and not + * libc's freeaddrinfo(3)! If the query is not completed yet EAI_AGAIN + * is returned.*/ +int asyncns_getaddrinfo_done(asyncns_t *asyncns, asyncns_query_t* q, struct addrinfo **ret_res); + +/** Issue an address to name query on the specified session. The + * arguments are compatible with the ones of libc's + * getnameinfo(3). The function returns a new query object. When the + * query is completed you may retrieve the results using + * asyncns_getnameinfo_done(). Set gethost (resp. getserv) to non-zero + * if you want to query the hostname (resp. the service name). */ +asyncns_query_t* asyncns_getnameinfo(asyncns_t *asyncns, const struct sockaddr *sa, socklen_t salen, int flags, int gethost, int getserv); + +/** Retrieve the results of a preceding asyncns_getnameinfo() + * call. Returns the hostname and the service name in ret_host and + * ret_serv. The query object q is destroyed by this call and may not + * be used any further. If the query is not completed yet EAI_AGAIN is + * returned. */ +int asyncns_getnameinfo_done(asyncns_t *asyncns, asyncns_query_t* q, char *ret_host, size_t hostlen, char *ret_serv, size_t servlen); + +/** Issue a resolver query on the specified session. The arguments are + * compatible with the ones of libc's res_query(3). The function returns a new + * query object. When the query is completed you may retrieve the results using + * asyncns_res_done(). */ +asyncns_query_t* asyncns_res_query(asyncns_t *asyncns, const char *dname, int class, int type); + +/** Issue an resolver query on the specified session. The arguments are + * compatible with the ones of libc's res_search(3). The function returns a new + * query object. When the query is completed you may retrieve the results using + * asyncns_res_done(). */ +asyncns_query_t* asyncns_res_search(asyncns_t *asyncns, const char *dname, int class, int type); + +/** Retrieve the results of a preceding asyncns_res_query() or + * asyncns_res_search call. The query object q is destroyed by this + * call and may not be used any further. Returns a pointer to the + * answer of the res_query call. If the query is not completed yet + * -EAGAIN is returned, on failure -errno is returned, otherwise the + * length of answer is returned. Make sure to free the answer is a + * call to asyncns_freeanswer(). */ +int asyncns_res_done(asyncns_t *asyncns, asyncns_query_t* q, unsigned char **answer); + +/** Return the next completed query object. If no query has been + * completed yet, return NULL. Please note that you need to run + * asyncns_wait() before this function will return sensible data. */ +asyncns_query_t* asyncns_getnext(asyncns_t *asyncns); + +/** Return the number of query objects (completed or not) attached to + * this session */ +int asyncns_getnqueries(asyncns_t *asyncns); + +/** Cancel a currently running query. q is is destroyed by this call + * and may not be used any futher. */ +void asyncns_cancel(asyncns_t *asyncns, asyncns_query_t* q); + +/** Free the addrinfo structure as returned by + * asyncns_getaddrinfo_done(). Make sure to use this functions instead + * of the libc's freeaddrinfo()! */ +void asyncns_freeaddrinfo(struct addrinfo *ai); + +/** Free the answer data as returned by asyncns_res_done().*/ +void asyncns_freeanswer(unsigned char *answer); + +/** Returns non-zero when the query operation specified by q has been completed */ +int asyncns_isdone(asyncns_t *asyncns, asyncns_query_t*q); + +/** Assign some opaque userdata with a query object */ +void asyncns_setuserdata(asyncns_t *asyncns, asyncns_query_t *q, void *userdata); + +/** Return userdata assigned to a query object. Use + * asyncns_setuserdata() to set this data. If no data has been set + * prior to this call it returns NULL. */ +void* asyncns_getuserdata(asyncns_t *asyncns, asyncns_query_t *q); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index 51b645e2..c7fd4e0a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,6 +6,9 @@ ss_server_SOURCES = utils.c jconf.c json.c \ rc4.c md5.c encrypt.c \ server.c ss_local_LDADD = $(top_builddir)/libev/libev.la +ss_local_LDADD += $(top_builddir)/libasyncns/libasyncns.la ss_server_LDADD = $(top_builddir)/libev/libev.la +ss_server_LDADD += $(top_builddir)/libasyncns/libasyncns.la AM_CFLAGS = -O2 -Wall -fno-strict-aliasing AM_CFLAGS += -I$(top_builddir)/libev +AM_CFLAGS += -I$(top_builddir)/libasyncns diff --git a/src/Makefile.in b/src/Makefile.in index f34aae6f..30b95aa1 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -53,11 +53,13 @@ PROGRAMS = $(bin_PROGRAMS) am_ss_local_OBJECTS = utils.$(OBJEXT) jconf.$(OBJEXT) json.$(OBJEXT) \ rc4.$(OBJEXT) md5.$(OBJEXT) encrypt.$(OBJEXT) local.$(OBJEXT) ss_local_OBJECTS = $(am_ss_local_OBJECTS) -ss_local_DEPENDENCIES = $(top_builddir)/libev/libev.la +ss_local_DEPENDENCIES = $(top_builddir)/libev/libev.la \ + $(top_builddir)/libasyncns/libasyncns.la am_ss_server_OBJECTS = utils.$(OBJEXT) jconf.$(OBJEXT) json.$(OBJEXT) \ rc4.$(OBJEXT) md5.$(OBJEXT) encrypt.$(OBJEXT) server.$(OBJEXT) ss_server_OBJECTS = $(am_ss_server_OBJECTS) -ss_server_DEPENDENCIES = $(top_builddir)/libev/libev.la +ss_server_DEPENDENCIES = $(top_builddir)/libev/libev.la \ + $(top_builddir)/libasyncns/libasyncns.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles @@ -197,9 +199,12 @@ ss_server_SOURCES = utils.c jconf.c json.c \ rc4.c md5.c encrypt.c \ server.c -ss_local_LDADD = $(top_builddir)/libev/libev.la -ss_server_LDADD = $(top_builddir)/libev/libev.la -AM_CFLAGS = -O2 -Wall -fno-strict-aliasing -I$(top_builddir)/libev +ss_local_LDADD = $(top_builddir)/libev/libev.la \ + $(top_builddir)/libasyncns/libasyncns.la +ss_server_LDADD = $(top_builddir)/libev/libev.la \ + $(top_builddir)/libasyncns/libasyncns.la +AM_CFLAGS = -O2 -Wall -fno-strict-aliasing -I$(top_builddir)/libev \ + -I$(top_builddir)/libasyncns all: all-am .SUFFIXES: diff --git a/src/jconf.h b/src/jconf.h index b2c5160d..f87e1813 100644 --- a/src/jconf.h +++ b/src/jconf.h @@ -3,6 +3,7 @@ #define MAX_REMOTE_NUM 10 #define MAX_CONF_SIZE 16 * 1024 +#define DNS_THREAD 4 typedef struct { int remote_num; diff --git a/src/server.c b/src/server.c index bfbf2eaf..51dc5a26 100644 --- a/src/server.c +++ b/src/server.c @@ -92,25 +92,15 @@ int create_and_bind(const char *host, const char *port) { return listen_sock; } -struct remote *connect_to_remote(char *remote_host, char *remote_port, int timeout) { - struct addrinfo hints, *res; +struct remote *connect_to_remote(struct addrinfo *res, int timeout) { int sockfd; - memset(&hints, 0, sizeof hints); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - - int err = getaddrinfo(remote_host, remote_port, &hints, &res); - if (err) { - ERROR("getaddrinfo"); - return NULL; - } // initilize remote socks sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (sockfd < 0) { ERROR("socket"); close(sockfd); - freeaddrinfo(res); + asyncns_freeaddrinfo(res); return NULL; } @@ -121,12 +111,11 @@ struct remote *connect_to_remote(char *remote_host, char *remote_port, int timeo connect(sockfd, res->ai_addr, res->ai_addrlen); // release addrinfo - freeaddrinfo(res); + asyncns_freeaddrinfo(res); return remote; } - static void server_recv_cb (EV_P_ ev_io *w, int revents) { struct server_ctx *server_recv_ctx = (struct server_ctx *)w; struct server *server = server_recv_ctx->server; @@ -231,8 +220,6 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { } if (offset == 0) { - LOGE("unsupported addrtype: %d", atyp); - close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } @@ -246,20 +233,21 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { LOGD("connect to: %s:%s", host, port); } - struct remote *remote = connect_to_remote(host, port, server->timeout); - if (remote == NULL) { + struct addrinfo hints; + asyncns_query_t *query; + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + query = asyncns_getaddrinfo(server->asyncns, + host, port, &hints); + + if (query == NULL) { + ERROR("asyncns_getaddrinfo"); close_and_free_server(EV_A_ server); return; } - server->remote = remote; - remote->server = server; - - // listen to remote connected event - ev_io_stop(EV_A_ &server_recv_ctx->io); - ev_io_start(EV_A_ &remote->send_ctx->io); - ev_timer_start(EV_A_ &remote->send_ctx->watcher); - // XXX: should handel buffer carefully if (r > offset) { remote->buf_len = r - offset; @@ -268,6 +256,9 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { server->stage = 4; + ev_io_stop(EV_A_ &server_recv_ctx->io); + ev_timer_start(EV_A_ &server->recv_ctx->watcher); + return; } // should not reach here @@ -323,6 +314,49 @@ static void server_send_cb (EV_P_ ev_io *w, int revents) { } } +static void server_resolve_cb(EV_P_ ev_timer *watcher, int revents) { + int err; + struct addrinfo *result; + struct server_ctx *server_ctx = (struct server_ctx *) (((void*)watcher) + - sizeof(ev_io)); + struct server *server = server_ctx->server; + asyncns_t *asyncns = server->asyncns; + asyncns_query_t *query = server->query; + + if (asyncns == NULL || query == NULL) { + LOGE("invalid dns query."); + close_and_free_server(EV_A_ server); + return; + } + + if (!asyncns_isdone(asyncns, query)) { + // wait for reolver + return; + } + + ev_timer_stop(EV_A_ watcher); + + err = asyncns_getaddrinfo_done(asyncns, query, &result); + if (err) { + ERROR("getaddrinfo"); + close_and_free_server(EV_A_ server); + } else { + struct remote *remote = connect_to_remote(result, server->timeout); + if (remote == NULL) { + close_and_free_server(EV_A_ server); + return; + } + + server->remote = remote; + remote->server = server; + + // listen to remote connected event + ev_io_start(EV_A_ &remote->send_ctx->io); + ev_timer_start(EV_A_ &remote->send_ctx->watcher); + } + +} + static void remote_timeout_cb(EV_P_ ev_timer *watcher, int revents) { struct remote_ctx *remote_ctx = (struct remote_ctx *) (((void*)watcher) - sizeof(ev_io)); @@ -524,11 +558,14 @@ struct server* new_server(int fd) { server->fd = fd; ev_io_init(&server->recv_ctx->io, server_recv_cb, fd, EV_READ); ev_io_init(&server->send_ctx->io, server_send_cb, fd, EV_WRITE); + ev_timer_init(&server->recv_ctx->watcher, server_resolve_cb, 0.5, 1.0); server->recv_ctx->server = server; server->recv_ctx->connected = 0; server->send_ctx->server = server; server->send_ctx->connected = 0; server->stage = 0; + server->asyncns = NULL; + server->query = NULL; if (enc_conf.method == RC4) { server->e_ctx = malloc(sizeof(struct rc4_state)); server->d_ctx = malloc(sizeof(struct rc4_state)); @@ -563,6 +600,7 @@ void close_and_free_server(EV_P_ struct server *server) { if (server != NULL) { ev_io_stop(EV_A_ &server->send_ctx->io); ev_io_stop(EV_A_ &server->recv_ctx->io); + ev_timer_stop(EV_A_ &server->recv_ctx->watcher); close(server->fd); free_server(server); } @@ -586,6 +624,7 @@ static void accept_cb (EV_P_ ev_io *w, int revents) { struct server *server = new_server(serverfd); server->timeout = listener->timeout; + server->asyncns = listener->asyncns; ev_io_start(EV_A_ &server->recv_ctx->io); } @@ -666,6 +705,13 @@ int main (int argc, char **argv) { // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); + signal(SIGCHLD, SIG_IGN); + + // Setup asyncns + asyncns_t *asyncns; + if (!(asyncns = asyncns_new(DNS_THREAD))) { + FATAL("asyncns failed"); + } // Setup keys LOGD("calculating ciphers..."); @@ -694,6 +740,7 @@ int main (int argc, char **argv) { // Setup proxy context struct listen_ctx listen_ctx; listen_ctx.timeout = atoi(timeout); + listen_ctx.asyncns = asyncns; listen_ctx.fd = listenfd; ev_io_init (&listen_ctx.io, accept_cb, listenfd, EV_READ); diff --git a/src/server.h b/src/server.h index 38b7f9a8..ee9fa86e 100644 --- a/src/server.h +++ b/src/server.h @@ -6,16 +6,19 @@ #include "encrypt.h" #include "jconf.h" +#include "asyncns.h" struct listen_ctx { ev_io io; int fd; int timeout; + asyncns_t *asyncns; struct sockaddr sock; }; struct server_ctx { ev_io io; + ev_timer watcher; int connected; struct server *server; }; @@ -30,6 +33,8 @@ struct server { struct rc4_state *d_ctx; struct server_ctx *recv_ctx; struct server_ctx *send_ctx; + asyncns_t *asyncns; + asyncns_query_t *query; struct remote *remote; }; @@ -55,9 +60,11 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents); static void server_send_cb (EV_P_ ev_io *w, int revents); static void remote_recv_cb (EV_P_ ev_io *w, int revents); static void remote_send_cb (EV_P_ ev_io *w, int revents); +static void remote_timeout_cb(EV_P_ ev_timer *watcher, int revents); +static void server_resolve_cb(EV_P_ ev_timer *watcher, int revents); struct remote* new_remote(int fd, int timeout); -struct remote *connect_to_remote(char *remote_host, char *remote_port, int timeout); +struct remote *connect_to_remote(struct addrinfo *res, int timeout); void free_remote(struct remote *remote); void close_and_free_remote(EV_P_ struct remote *remote); struct server* new_server(int fd);