This patch is generated from the push branch of HEAD in squid Mon Jan 26 12:58:16 2004 GMT See http://devel.squid-cache.org/ Index: squid/CONTRIBUTORS diff -u squid/CONTRIBUTORS:1.22 squid/CONTRIBUTORS:1.17.6.2 --- squid/CONTRIBUTORS:1.22 Fri Jul 5 15:42:12 2002 +++ squid/CONTRIBUTORS Tue Sep 3 10:39:07 2002 @@ -88,5 +88,6 @@ Ian Castle Brad Smitch Jerry Murdock + Jon Kay Duane Wessels Index: squid/acconfig.h diff -u squid/acconfig.h:1.20 squid/acconfig.h:1.12.2.4 --- squid/acconfig.h:1.20 Thu Aug 8 12:42:06 2002 +++ squid/acconfig.h Tue Sep 3 10:39:08 2002 @@ -130,6 +130,21 @@ #undef USE_ARP_ACL /* + * Define this to include code for Hint Caching. + */ +#undef USE_HINT_CACHE + +/* + * Define this to include code for the Plaxton dynamic cache hierarchy. + */ +#undef USE_DYNAMIC_HIERARCHY + +/* + * Define this to include code for sending data by ICP + */ +#undef USE_ICP_DATA + +/* * Define this to include code for the Hypertext Cache Protocol (HTCP) */ #undef USE_HTCP Index: squid/acinclude.m4 diff -u squid/acinclude.m4:1.4 squid/acinclude.m4:1.1.54.1 --- squid/acinclude.m4:1.4 Mon Jun 17 14:02:55 2002 +++ squid/acinclude.m4 Tue Sep 3 10:39:08 2002 @@ -16,8 +16,7 @@ changequote([, ])dnl AC_MSG_CHECKING(size of $1) AC_CACHE_VAL(AC_CV_NAME, -[AC_TRY_RUN([ -#include +[AC_TRY_RUN([#include #if STDC_HEADERS #include #include @@ -28,17 +27,13 @@ #if HAVE_SYS_TYPES_H #include #endif -#if HAVE_SYS_BITYPES_H -#include -#endif int main() { FILE *f=fopen("conftestval", "w"); if (!f) return(1); fprintf(f, "%d\n", sizeof($1)); return(0); -} -], AC_CV_NAME=`cat conftestval`, AC_CV_NAME=0, ifelse([$2], , , AC_CV_NAME=$2))])dnl +}], AC_CV_NAME=`cat conftestval`, AC_CV_NAME=0, ifelse([$2], , , AC_CV_NAME=$2))])dnl AC_MSG_RESULT($AC_CV_NAME) AC_DEFINE_UNQUOTED(AC_TYPE_NAME, $AC_CV_NAME) undefine([AC_TYPE_NAME])dnl @@ -53,12 +48,7 @@ [AC_EGREP_CPP(dnl changequote(<<,>>)dnl <<(^|[^a-zA-Z_0-9])$1[^a-zA-Z_0-9]>>dnl -changequote([,]), [ -/* What a mess.. many systems have added the (now standard) bit types - * in their own ways, so we need to scan a wide variety of headers to - * find them.. - */ -#include +changequote([,]), [#include #if STDC_HEADERS #include #include @@ -68,11 +58,7 @@ #endif #if HAVE_SYS_TYPES_H #include -#endif -#if HAVE_SYS_BITYPES_H -#include -#endif -], ac_cv_type_$1=yes, ac_cv_type_$1=no)])dnl +#endif], ac_cv_type_$1=yes, ac_cv_type_$1=no)])dnl AC_MSG_RESULT($ac_cv_type_$1) if test $ac_cv_type_$1 = no; then AC_DEFINE($1, $2) Index: squid/configure.in diff -u squid/configure.in:1.65 squid/configure.in:1.35.2.4 --- squid/configure.in:1.65 Sun Sep 1 09:30:40 2002 +++ squid/configure.in Tue Sep 3 10:39:09 2002 @@ -27,20 +27,19 @@ AM_PROG_CC_C_O AC_CANONICAL_HOST - CRYPTLIB='' -REGEXLIB='' # -lregex -LIBREGEX='' # libregex.a +REGEXLIB='' # -lregex +LIBREGEX='' # libregex.a dnl find out the exe extension for this platform. If it's not empty, use it for CGI's as well. AC_EXEEXT AC_OBJEXT if test -z "$EXEEXT"; then - CGIEXT=".cgi" + CGIEXT=".cgi" else - # automake automatically adds .exe when installing binaries - CGIEXT="" + # automake automatically adds .exe when installing binaries + CGIEXT="" fi AC_SUBST(CGIEXT) @@ -49,17 +48,17 @@ case "$host_os" in cygwin|cygwin32) AM_CONDITIONAL(ENABLE_WIN32SPECIFIC, true) - ;; + ;; *) - AM_CONDITIONAL(ENABLE_WIN32SPECIFIC, false) - ;; + AM_CONDITIONAL(ENABLE_WIN32SPECIFIC, false) + ;; esac if test -z "$CACHE_HTTP_PORT"; then - CACHE_HTTP_PORT="3128" + CACHE_HTTP_PORT="3128" fi if test -z "$CACHE_ICP_PORT"; then - CACHE_ICP_PORT="3130" + CACHE_ICP_PORT="3130" fi dnl Subsitutions @@ -76,43 +75,43 @@ dnl Gerben Wierda case "$host" in mab-next-nextstep3) - CC="$CC -arch m68k -arch i486 -arch hppa -arch sparc" - ;; + CC="$CC -arch m68k -arch i486 -arch hppa -arch sparc" + ;; esac dnl Set Default CFLAGS if test -z "$PRESET_CFLAGS"; then if test "$GCC" = "yes"; then case "$host" in - *-sun-sunos*) - # sunos has too many warnings for this to be useful - # motorola too - ;; - *m88k*) - # Motorola cc/ld does not like -02 but is ok on -O - CFLAGS=`echo $CFLAGS | sed -e 's/-O[0-9]/-O/'` - ;; + *-sun-sunos*) + # sunos has too many warnings for this to be useful + # motorola too + ;; + *m88k*) + # Motorola cc/ld does not like -02 but is ok on -O + CFLAGS=`echo $CFLAGS | sed -e 's/-O[0-9]/-O/'` + ;; *) - CFLAGS="$CFLAGS -Wall" - ;; + CFLAGS="$CFLAGS -Wall" + ;; esac else - case "$host" in - *mips-sgi-irix6.*) - # suggested by Rafael Seidl - CFLAGS="$CFLAGS -n32 -mips3 -O3 -OPT:Olimit=0:space=OFF \ - -woff 1009,1014,1110,1116,1185,1188,1204,1230,1233 \ - -Wl,-woff,85,-woff,84,-woff,134 \ - -nostdinc -I/usr/include -D_BSD_SIGNALS" - ;; - alpha-dec-osf4.*) - # Mogul says DEC compilers take both -g and -O2 - CFLAGS=`echo $CFLAGS | sed -e 's/-g/-g3/'` - CFLAGS="$CFLAGS -O2" - ;; - *) - ;; - esac + case "$host" in + *mips-sgi-irix6.*) + # suggested by Rafael Seidl + CFLAGS="$CFLAGS -n32 -mips3 -O3 -OPT:Olimit=0:space=OFF \ + -woff 1009,1014,1110,1116,1185,1188,1204,1230,1233 \ + -Wl,-woff,85,-woff,84,-woff,134 \ + -nostdinc -I/usr/include -D_BSD_SIGNALS" + ;; + alpha-dec-osf4.*) + # Mogul says DEC compilers take both -g and -O2 + CFLAGS=`echo $CFLAGS | sed -e 's/-g/-g3/'` + CFLAGS="$CFLAGS -O2" + ;; + *) + ;; + esac fi fi @@ -121,16 +120,16 @@ if test "$GCC" = "yes"; then case "$host" in *) - # nothing - ;; + # nothing + ;; esac else - case "$host" in - *mips-sgi-irix6.*) - # suggested by Rafael Seidl - LDFLAGS="-n32 -mips3 -nostdlib -L/usr/lib32" - ;; - esac + case "$host" in + *mips-sgi-irix6.*) + # suggested by Rafael Seidl + LDFLAGS="-n32 -mips3 -nostdlib -L/usr/lib32" + ;; + esac fi fi @@ -156,18 +155,18 @@ ]) if test "${use_dlmalloc-unset}" = unset; then case "$host" in - i386-*-solaris2.*) - echo "Enabling dlmalloc for $host" - use_dlmalloc="yes" - LIBDLMALLOC="libdlmalloc.a" - LIB_MALLOC="-L../lib -ldlmalloc" - ;; - *-sgi-irix*) - echo "Enabling dlmalloc for $host" - use_dlmalloc="yes" - LIBDLMALLOC="libdlmalloc.a" - LIB_MALLOC="-L../lib -ldlmalloc" - ;; + i386-*-solaris2.*) + echo "Enabling dlmalloc for $host" + use_dlmalloc="yes" + LIBDLMALLOC="libdlmalloc.a" + LIB_MALLOC="-L../lib -ldlmalloc" + ;; + *-sgi-irix*) + echo "Enabling dlmalloc for $host" + use_dlmalloc="yes" + LIBDLMALLOC="libdlmalloc.a" + LIB_MALLOC="-L../lib -ldlmalloc" + ;; esac fi if test "x$ac_cv_enabled_dlmalloc" = "xyes"; then @@ -267,7 +266,7 @@ else AC_DEFINE(USE_CARP, 1) fi -]) +]) AC_ARG_ENABLE(async-io, [ --enable-async-io[=N_THREADS] @@ -277,13 +276,13 @@ --enable-storeio=ufs,aufs], [ case $enableval in yes) - STORE_MODULES="ufs aufs" + STORE_MODULES="ufs aufs" ;; no) ;; *) - aufs_io_threads=$enableval - STORE_MODULES="ufs aufs" + aufs_io_threads=$enableval + STORE_MODULES="ufs aufs" ;; esac ]) @@ -313,9 +312,9 @@ ;; *-solaris2.*) if test "$GCC" = "yes" ; then - CFLAGS="$CFLAGS -pthreads" - else - CFLAGS="$CFLAGS -mt" + CFLAGS="$CFLAGS -pthreads" + else + CFLAGS="$CFLAGS -mt" fi ;; esac @@ -342,16 +341,16 @@ for details on how to build your custom store module], [ case $enableval in yes) - for module in $srcdir/src/fs/*; do - if test -f $module/Makefile.in; then - STORE_MODULES="$STORE_MODULES `basename $module`" - fi - done - ;; + for module in $srcdir/src/fs/*; do + if test -f $module/Makefile.in; then + STORE_MODULES="$STORE_MODULES `basename $module`" + fi + done + ;; no) - ;; - *) STORE_MODULES="`echo $enableval| sed -e 's/,/ /g;s/ */ /g'`" - ;; + ;; + *) STORE_MODULES="`echo $enableval| sed -e 's/,/ /g;s/ */ /g'`" + ;; esac ], [ if test -z "$STORE_MODULES"; then @@ -370,32 +369,31 @@ case "$fs" in diskd) STORE_MODULE_SUBDIRS="$STORE_MODULE_SUBDIRS $fs" - OPT_DISKD_EXE='diskd$(EXEEXT)' - ;; + OPT_DISKD_EXE='diskd$(EXEEXT)' + ;; aufs) - if test -z "$with_pthreads"; then - echo "aufs store used, pthreads support automatically enabled" - with_pthreads=yes - fi - ;; + if test -z "$with_pthreads"; then + echo "aufs store used, pthreads support automatically enabled" + with_pthreads=yes + fi + ;; coss) - if test -z "$with_aio"; then - echo "coss store used, aio support automatically enabled" - with_aio=yes - fi - ;; + if test -z "$with_aio"; then + echo "coss store used, aio support automatically enabled" + with_aio=yes + fi + ;; esac done AC_SUBST(STORE_MODULES) AC_SUBST(STORE_MODULE_SUBDIRS) AC_SUBST(OPT_DISKD_EXE) - dnl --enable-heap-replacement compability option AC_ARG_ENABLE(heap-replacement, [ --enable-heap-replacement Backwards compability option. Please use the - new --enable-removal-policies directive instead.], + new --enable-removal-policies directive instead.], [ if test "$enableval" = "yes" ; then echo "--enable-heap-replacement is obsolete. please use the new" echo "--enable-removal-policies directive instead" @@ -410,19 +408,19 @@ The default is only to build the "lru" module. See src/repl for a list of available modules, or Programmers Guide section 9.9 for details on how - to build your custom policy], + to build your custom policy], [ case $enableval in yes) - for module in $srcdir/src/repl/*; do - if test -f $module/Makefile.in; then - REPL_POLICIES="$REPL_POLICIES `basename $module`" - fi - done - ;; + for module in $srcdir/src/repl/*; do + if test -f $module/Makefile.in; then + REPL_POLICIES="$REPL_POLICIES `basename $module`" + fi + done + ;; no) - ;; - *) REPL_POLICIES="`echo $enableval| sed -e 's/,/ /g;s/ */ /g'`" - ;; + ;; + *) REPL_POLICIES="`echo $enableval| sed -e 's/,/ /g;s/ */ /g'`" + ;; esac ], [ if test -z "$REPL_POLICIES"; then @@ -467,8 +465,8 @@ dnl [ if test "$enableval" = "yes" ; then dnl echo "Memory trace (to file) enabled" dnl AC_DEFINE(MEM_GEN_TRACE) -dnl fi -dnl ]) +dnl fi +dnl ]) AC_ARG_ENABLE(useragent-log, [ --enable-useragent-log Enable logging of User-Agent header], @@ -486,7 +484,7 @@ fi ]) -AC_ARG_ENABLE(wccp, +AC_ARG_ENABLE(wccp, [ --disable-wccp Disable Web Cache Coordination Protocol], [ if test "$enableval" = "no" ; then echo "Web Cache Coordination Protocol disabled" @@ -494,7 +492,7 @@ else AC_DEFINE(USE_WCCP, 1) fi -]) +]) AC_ARG_ENABLE(kill-parent-hack, [ --enable-kill-parent-hack @@ -543,19 +541,50 @@ [ if test "$enableval" = "yes" ; then echo "ARP ACL lists enabled (ether address)" case "$host" in - *-linux-*) - ;; - *-solaris-*) - ;; - *) - echo "WARNING: ARP ACL support probably won't work on $host." - sleep 10 - ;; + *-linux-*) + ;; + *-solaris-*) + ;; + *) + echo "WARNING: ARP ACL support probably won't work on $host." + sleep 10 + ;; esac AC_DEFINE(USE_ARP_ACL) fi ]) +AM_CONDITIONAL(ENABLE_HINTS, false) +AC_ARG_ENABLE(hints, +[ --enable-hints Enable Hint Cache protocol], +[ if test "$enableval" = "yes" ; then + echo "Hint Cache enabled" + AC_DEFINE(USE_HINT_CACHE) + AM_CONDITIONAL(ENABLE_HINTS, true) + fi +]) + +AM_CONDITIONAL(ENABLE_PLAXTON, false) +AC_ARG_ENABLE(plaxton, +[ --enable-plaxton Enable Plaxton dynamic hierarchy protocol], +[ if test "$enableval" = "yes" ; then + echo "Plaxton dynamic hierarchy enabled" + AC_DEFINE(USE_DYNAMIC_HIERARCHY) + AM_CONDITIONAL(ENABLE_PLAXTON, true) + fi +]) + +AM_CONDITIONAL(ENABLE_ICP_DATA, false) +AC_ARG_ENABLE(icpdata, +[ --enable-icpdata Enable sending data by ICP], +[ if test "$enableval" = "yes" ; then + echo "Push over ICP/UDP enabled" + AC_DEFINE(USE_ICP_DATA) + AM_CONDITIONAL(ENABLE_ICP_DATA, true) + fi +]) + + AM_CONDITIONAL(ENABLE_HTCP, false) AM_CONDITIONAL(ENABLE_HTCP, false) AC_ARG_ENABLE(htcp, [ --enable-htcp Enable HTCP protocol], @@ -584,10 +613,10 @@ AC_ARG_WITH(openssl, [ --with-openssl[=prefix] Compile with the OpenSSL libraries. The path to - the OpenSSL development libraries and headers - installation can be specified if outside of the - system standard directories], -[ + the OpenSSL development libraries and headers + installation can be specified if outside of the + system standard directories], +[ case "$with_openssl" in yes) USE_OPENSSL=1 @@ -639,10 +668,10 @@ errors directory) ], [ if test -d $srcdir/errors/$enableval; then - ERR_DEFAULT_LANGUAGE=$enableval + ERR_DEFAULT_LANGUAGE=$enableval else - echo "ERROR! Unknown language $enableval, see errors/ directory" - exit 1 + echo "ERROR! Unknown language $enableval, see errors/ directory" + exit 1 fi ],[ERR_DEFAULT_LANGUAGE="English"]) AC_SUBST(ERR_DEFAULT_LANGUAGE) @@ -655,9 +684,9 @@ [ for l in $enableval; do if test -d $srcdir/errors/$l; then :; else - echo "ERROR! Unknown language $$l, see errors/" - exit 1 - fi + echo "ERROR! Unknown language $$l, see errors/" + exit 1 + fi done ERR_LANGUAGES=$enableval ],[ @@ -665,7 +694,7 @@ for l in $srcdir/errors/*; do if test -f $l/ERR_ACCESS_DENIED; then ERR_LANGUAGES="$ERR_LANGUAGES `basename $l`" - fi + fi done ]) AC_SUBST(ERR_LANGUAGES) @@ -753,9 +782,9 @@ Enable Transparent Proxy support for systems using IP-Filter network address redirection.], [ if test "$enableval" = "yes" ; then - echo "IP-Filter Transparent Proxy enabled" - AC_DEFINE(IPF_TRANSPARENT) - IPF_TRANSPARENT="yes" + echo "IP-Filter Transparent Proxy enabled" + AC_DEFINE(IPF_TRANSPARENT) + IPF_TRANSPARENT="yes" fi ]) @@ -765,9 +794,9 @@ Enable Transparent Proxy support for systems using PF network address redirection.], [ if test "$enableval" = "yes" ; then - echo "PF Transparent Proxy enabled" - AC_DEFINE(PF_TRANSPARENT) - PF_TRANSPARENT="yes" + echo "PF Transparent Proxy enabled" + AC_DEFINE(PF_TRANSPARENT) + PF_TRANSPARENT="yes" fi ]) @@ -776,9 +805,9 @@ [ --enable-linux-netfilter Enable Transparent Proxy support for Linux 2.4.], [ if test "$enableval" = "yes" ; then - echo "Linux-Netfilter Transparent Proxy enabled" - AC_DEFINE(LINUX_NETFILTER) - LINUX_NETFILTER="yes" + echo "Linux-Netfilter Transparent Proxy enabled" + AC_DEFINE(LINUX_NETFILTER) + LINUX_NETFILTER="yes" fi ]) @@ -787,8 +816,8 @@ [ --enable-large-files Enable support for large files (>2GB). Still experimental.], [ if test "$enableval" = "yes" ; then - echo "Large file support enabled" - CFLAGS="$CFLAGS -D_FILE_OFFSET_BITS=64" + echo "Large file support enabled" + CFLAGS="$CFLAGS -D_FILE_OFFSET_BITS=64" fi ]) @@ -798,13 +827,13 @@ [ --enable-leakfinder Enable Leak Finding code. Enabling this alone does nothing; you also have to modify the source - code to use the leak finding functions. Probably - Useful for hackers only.], + code to use the leak finding functions. Probably + Useful for hackers only.], [ if test "$enableval" = "yes" ; then - echo "Leak-Finding enabled" - AC_DEFINE(USE_LEAKFINDER) - USE_LEAKFINDER="yes" - AM_CONDITIONAL(MAKE_LEAKFINDER, true) + echo "Leak-Finding enabled" + AC_DEFINE(USE_LEAKFINDER) + USE_LEAKFINDER="yes" + AM_CONDITIONAL(MAKE_LEAKFINDER, true) fi ]) @@ -873,20 +902,19 @@ See hosts_file directive in squid.conf for details], [ if test "$enableval" != "none" ; then - if test -f $enableval; then - OPT_DEFAULT_HOSTS=$enableval - else - echo "Warning Unable to find $enableval" - sleep 5 - fi + if test -f $enableval; then + OPT_DEFAULT_HOSTS=$enableval + else + echo "Warning Unable to find $enableval" + sleep 5 + fi else - OPT_DEFAULT_HOSTS="none" + OPT_DEFAULT_HOSTS="none" fi echo "Default hosts file set to: $enableval" ],[OPT_DEFAULT_HOSTS="/etc/hosts"]) AC_SUBST(OPT_DEFAULT_HOSTS) - dnl Select auth schemes modules to build AC_ARG_ENABLE(auth, [ --enable-auth=\"list of auth scheme modules\" @@ -931,11 +959,11 @@ echo "option --enable-basic-auth-helpers" sleep 5 case "$enableval" in - yes) + yes) for helper in $srcdir/helpers/basic_auth/*; do - if test -f $helper/Makefile.in; then - BASIC_AUTH_HELPERS="$BASIC_AUTH_HELPERS `basename $helper`" - fi + if test -f $helper/Makefile.in; then + BASIC_AUTH_HELPERS="$BASIC_AUTH_HELPERS `basename $helper`" + fi done ;; no) @@ -947,16 +975,16 @@ AC_ARG_ENABLE(basic-auth-helpers, [ --enable-basic-auth-helpers=\"list of helpers\" This option selects which basic scheme proxy_auth - helpers to build and install as part of the normal + helpers to build and install as part of the normal build process. For a list of available helpers see the helpers/basic_auth directory.], [ case "$enableval" in - yes) + yes) BASIC_AUTH_HELPERS="" for helper in $srcdir/helpers/basic_auth/*; do - if test -f $helper/Makefile.in; then - BASIC_AUTH_HELPERS="$BASIC_AUTH_HELPERS `basename $helper`" - fi + if test -f $helper/Makefile.in; then + BASIC_AUTH_HELPERS="$BASIC_AUTH_HELPERS `basename $helper`" + fi done ;; no) @@ -967,12 +995,12 @@ ]) if test -n "$BASIC_AUTH_HELPERS"; then for helper in $BASIC_AUTH_HELPERS; do - if test -f $srcdir/helpers/basic_auth/$helper/Makefile.in; then - : - else - echo "ERROR: Basic auth helper $helper does not exists" - exit 1 - fi + if test -f $srcdir/helpers/basic_auth/$helper/Makefile.in; then + : + else + echo "ERROR: Basic auth helper $helper does not exists" + exit 1 + fi done echo "Basic auth helpers built: $BASIC_AUTH_HELPERS" fi @@ -983,15 +1011,15 @@ AC_ARG_ENABLE(ntlm-auth-helpers, [ --enable-ntlm-auth-helpers=\"list of helpers\" This option selects which proxy_auth ntlm helpers - to build and install as part of the normal build + to build and install as part of the normal build process. For a list of available helpers see the helpers/ntlm_auth directory.], [ case "$enableval" in - yes) + yes) for helper in $srcdir/helpers/ntlm_auth/*; do - if test -f $helper/Makefile.in; then - NTLM_AUTH_HELPERS="$NTLM_AUTH_HELPERS `basename $helper`" - fi + if test -f $helper/Makefile.in; then + NTLM_AUTH_HELPERS="$NTLM_AUTH_HELPERS `basename $helper`" + fi done ;; no) @@ -1002,12 +1030,12 @@ ]) if test -n "$NTLM_AUTH_HELPERS"; then for helper in $NTLM_AUTH_HELPERS; do - if test -f $srcdir/helpers/ntlm_auth/$helper/Makefile.in; then - : - else - echo "ERROR: NTLM auth helper $helper does not exists" - exit 1 - fi + if test -f $srcdir/helpers/ntlm_auth/$helper/Makefile.in; then + : + else + echo "ERROR: NTLM auth helper $helper does not exists" + exit 1 + fi done echo "NTLM auth helpers built: $NTLM_AUTH_HELPERS" fi @@ -1037,12 +1065,12 @@ ]) if test -n "$DIGEST_AUTH_HELPERS"; then for helper in $DIGEST_AUTH_HELPERS; do - if test -f $srcdir/helpers/digest_auth/$helper/Makefile.in; then - : - else - echo "ERROR: digest auth helper $helper does not exists" - exit 1 - fi + if test -f $srcdir/helpers/digest_auth/$helper/Makefile.in; then + : + else + echo "ERROR: digest auth helper $helper does not exists" + exit 1 + fi done echo "Digest auth helpers built: $DIGEST_AUTH_HELPERS" fi @@ -1082,12 +1110,12 @@ ]) if test -n "$EXTERNAL_ACL_HELPERS"; then for helper in $EXTERNAL_ACL_HELPERS; do - if test -f $srcdir/helpers/external_acl/$helper/Makefile.in; then - : - else - echo "ERROR: external acl helper $helper does not exists" - exit 1 - fi + if test -f $srcdir/helpers/external_acl/$helper/Makefile.in; then + : + else + echo "ERROR: external acl helper $helper does not exists" + exit 1 + fi done echo "External acl helpers built: $EXTERNAL_ACL_HELPERS" fi @@ -1153,19 +1181,19 @@ # case "$host" in alpha-dec-osf*) - if test "$ac_cv_prog_CC" = "cc" ; then - echo "adding '-std1' to cc args for $host" - CC="cc -std1"; - ac_cv_prog_CC="$CC" - fi - ;; + if test "$ac_cv_prog_CC" = "cc" ; then + echo "adding '-std1' to cc args for $host" + CC="cc -std1"; + ac_cv_prog_CC="$CC" + fi + ;; *-hp-hpux*) - if test "$ac_cv_prog_CC" = "cc" ; then - echo "adding '-Ae' to cc args for $host" - CC="cc -Ae"; - ac_cv_prog_CC="$CC" - fi - ;; + if test "$ac_cv_prog_CC" = "cc" ; then + echo "adding '-Ae' to cc args for $host" + CC="cc -Ae"; + ac_cv_prog_CC="$CC" + fi + ;; esac dnl Check for programs @@ -1185,24 +1213,24 @@ AC_PATH_PROG(AR, ar, $FALSE) if test "$ac_cv_path_PERL" = "none"; then - echo "Perl is required to compile Squid" - echo "Please install Perl and then re-run configure" - exit 1 + echo "Perl is required to compile Squid" + echo "Please install Perl and then re-run configure" + exit 1 fi case "$host" in *-hp-hpux*) - echo "Disabling 'ranlib' for HP-UX..." - RANLIB=":" - ;; + echo "Disabling 'ranlib' for HP-UX..." + RANLIB=":" + ;; esac dnl set $(AR) AR_R="$AR r" case "$host" in - *-next-nextstep3) - AR="libtool -o" - ;; + *-next-nextstep3) + AR="libtool -o" + ;; esac AC_SUBST(AR_R) @@ -1211,84 +1239,84 @@ AC_HEADER_STDC AC_CHECK_HEADERS( \ - arpa/inet.h \ - arpa/nameser.h \ - assert.h \ - bstring.h \ - crypt.h \ - ctype.h \ - errno.h \ - execinfo.h \ - fcntl.h \ - getopt.h \ - gnumalloc.h \ - grp.h \ - ip_compat.h \ - ip_fil_compat.h \ - ip_fil.h \ - ip_nat.h \ - libc.h \ - limits.h \ - linux/netfilter_ipv4.h \ - malloc.h \ - math.h \ - memory.h \ - mount.h \ - net/if.h \ - net/pfvar.h \ - netdb.h \ - netinet/if_ether.h \ - netinet/in.h \ - netinet/tcp.h \ - netinet/ip_compat.h \ - netinet/ip_fil_compat.h \ - netinet/ip_fil.h \ - netinet/ip_nat.h \ - openssl/err.h \ - openssl/md5.h \ - openssl/ssl.h \ - poll.h \ - pwd.h \ - regex.h \ - resolv.h \ - sched.h \ - signal.h \ - stdarg.h \ - stddef.h \ - stdio.h \ - stdlib.h \ - string.h \ - strings.h \ - sys/bitypes.h \ - sys/file.h \ - sys/ioctl.h \ - sys/mount.h \ - sys/msg.h \ - sys/param.h \ - sys/resource.h \ - sys/select.h\ - sys/socket.h \ - sys/stat.h \ - sys/statvfs.h \ - syscall.h \ - sys/syscall.h \ - sys/time.h \ - sys/types.h \ - sys/un.h \ - sys/vfs.h \ - sys/wait.h \ - syslog.h \ - time.h \ - unistd.h \ - utime.h \ - varargs.h \ - byteswap.h \ - glib.h \ - stdint.h \ - inttypes.h \ - grp.h \ - nss_common.h \ - nss.h + arpa/inet.h \ + arpa/nameser.h \ + assert.h \ + bstring.h \ + crypt.h \ + ctype.h \ + errno.h \ + execinfo.h \ + fcntl.h \ + getopt.h \ + gnumalloc.h \ + grp.h \ + ip_compat.h \ + ip_fil_compat.h \ + ip_fil.h \ + ip_nat.h \ + libc.h \ + limits.h \ + linux/netfilter_ipv4.h \ + malloc.h \ + math.h \ + memory.h \ + mount.h \ + net/if.h \ + net/pfvar.h \ + netdb.h \ + netinet/if_ether.h \ + netinet/in.h \ + netinet/tcp.h \ + netinet/ip_compat.h \ + netinet/ip_fil_compat.h \ + netinet/ip_fil.h \ + netinet/ip_nat.h \ + openssl/err.h \ + openssl/md5.h \ + openssl/ssl.h \ + poll.h \ + pwd.h \ + regex.h \ + resolv.h \ + sched.h \ + signal.h \ + stdarg.h \ + stddef.h \ + stdio.h \ + stdlib.h \ + string.h \ + strings.h \ + sys/bitypes.h \ + sys/file.h \ + sys/ioctl.h \ + sys/mount.h \ + sys/msg.h \ + sys/param.h \ + sys/resource.h \ + sys/select.h\ + sys/socket.h \ + sys/stat.h \ + sys/statvfs.h \ + syscall.h \ + sys/syscall.h \ + sys/time.h \ + sys/types.h \ + sys/un.h \ + sys/vfs.h \ + sys/wait.h \ + syslog.h \ + time.h \ + unistd.h \ + utime.h \ + varargs.h \ + byteswap.h \ + glib.h \ + stdint.h \ + inttypes.h \ + grp.h \ + nss_common.h \ + nss.h ) AC_C_CONST @@ -1406,49 +1434,49 @@ dnl int16_t if test "x$ac_cv_sizeof_short" = "x2"; then - AC_CHECK_SYSTYPE(int16_t,short) + AC_CHECK_SYSTYPE(int16_t,short) elif test "x$ac_cv_sizeof_int" = "x2"; then - AC_CHECK_SYSTYPE(int16_t,int) + AC_CHECK_SYSTYPE(int16_t,int) fi dnl u_int16t_t if test "x$ac_cv_sizeof_uint16_t" = "x2"; then - AC_CHECK_SYSTYPE(u_int16_t,uint16_t) + AC_CHECK_SYSTYPE(u_int16_t,uint16_t) elif test "x$ac_cv_sizeof_short" = "x2"; then - AC_CHECK_SYSTYPE(u_int16_t,unsigned short) + AC_CHECK_SYSTYPE(u_int16_t,unsigned short) elif test "x$ac_cv_sizeof_int" = "x2"; then - AC_CHECK_SYSTYPE(u_int16_t,unsigned int) + AC_CHECK_SYSTYPE(u_int16_t,unsigned int) fi dnl int32_t if test "x$ac_cv_sizeof_int" = "x4"; then - AC_CHECK_SYSTYPE(int32_t,int) + AC_CHECK_SYSTYPE(int32_t,int) elif "x$ac_cv_sizeof_long" = "x4"; then - AC_CHECK_SYSTYPE(int32_t,long) + AC_CHECK_SYSTYPE(int32_t,long) fi dnl u_int32_t if test "x$ac_cv_sizeof_uint32_t" = "x4"; then - AC_CHECK_SYSTYPE(u_int32_t,uint32_t) + AC_CHECK_SYSTYPE(u_int32_t,uint32_t) elif test "x$ac_cv_sizeof_int" = "x4"; then - AC_CHECK_SYSTYPE(u_int32_t,unsigned int) + AC_CHECK_SYSTYPE(u_int32_t,unsigned int) elif test "x$ac_cv_sizeof_long" = "x4"; then - AC_CHECK_SYSTYPE(u_int32_t,unsigned long) + AC_CHECK_SYSTYPE(u_int32_t,unsigned long) fi dnl int64_t if test "x$ac_cv_sizeof_long" = "x8"; then - AC_CHECK_SYSTYPE(int64_t,long) + AC_CHECK_SYSTYPE(int64_t,long) elif test "x$ac_cv_sizeof_long_long" = "x8"; then - AC_CHECK_SYSTYPE(int64_t,long long) + AC_CHECK_SYSTYPE(int64_t,long long) elif test "x$ac_cv_sizeof___int64" = "x8"; then - AC_CHECK_SYSTYPE(int64_t,__int64) + AC_CHECK_SYSTYPE(int64_t,__int64) fi dnl u_int64_t if test "x$ac_cv_sizeof_uint64_t" = "x8"; then - AC_CHECK_SYSTYPE(u_int64_t,uint64_t) + AC_CHECK_SYSTYPE(u_int64_t,uint64_t) elif test "x$ac_cv_sizeof_long" = "x8"; then - AC_CHECK_SYSTYPE(u_int64_t,unsigned long) + AC_CHECK_SYSTYPE(u_int64_t,unsigned long) elif test "x$ac_cv_sizeof_long_long" = "x8"; then - AC_CHECK_SYSTYPE(u_int64_t,unsigned long long) + AC_CHECK_SYSTYPE(u_int64_t,unsigned long long) elif test "x$ac_cv_sizeof___int64" = "x8"; then - AC_CHECK_SYSTYPE(int64_t,unsigned __int64) + AC_CHECK_SYSTYPE(int64_t,unsigned __int64) fi AC_CHECK_TYPE(pid_t, int) @@ -1464,7 +1492,6 @@ dnl Check for special functions AC_FUNC_ALLOCA - dnl Check for type in sys/socket.h AC_CACHE_CHECK(for socklen_t, ac_cv_type_socklen_t, [ AC_EGREP_CPP([socklen_t[^a-zA-Z_0-9]], [#include @@ -1505,7 +1532,7 @@ #include #include ], [ - struct sockaddr_un sunaddr; + struct sockaddr_un sunaddr; sunaddr.sun_family = AF_UNIX; ], squid_cv_unixsocket=yes,squid_cv_unixsocket=no)]) @@ -1519,23 +1546,23 @@ else AC_CHECK_LIB(gnumalloc, main) if test "$ac_cv_lib_gnumalloc_main" = "yes"; then - echo "Disabling extended malloc functions when using gnumalloc" - ac_cv_func_mallinfo=no - ac_cv_func_mallocblksize=no - ac_cv_func_mallopt=no + echo "Disabling extended malloc functions when using gnumalloc" + ac_cv_func_mallinfo=no + ac_cv_func_mallocblksize=no + ac_cv_func_mallopt=no else - case "$host" in - *-sun-solaris*) - echo "skipping libmalloc check for $host" - ;; - i386-*-freebsd*) - echo "skipping libmalloc check for $host" - ;; - *) - - AC_CHECK_LIB(malloc, main) - ;; - esac + case "$host" in + *-sun-solaris*) + echo "skipping libmalloc check for $host" + ;; + i386-*-freebsd*) + echo "skipping libmalloc check for $host" + ;; + *) + + AC_CHECK_LIB(malloc, main) + ;; + esac fi fi @@ -1544,13 +1571,13 @@ AC_CHECK_LIB(bind, gethostbyname) if test $ac_cv_lib_bind_gethostbyname = "no" ; then case "$host" in - i386-*-freebsd*) - echo "skipping libresolv checks for $host" - ;; - *) - AC_CHECK_LIB(resolv, inet_aton, AC_CHECK_LIB(44bsd, inet_aton)) - AC_CHECK_LIB(resolv, main) - ;; + i386-*-freebsd*) + echo "skipping libresolv checks for $host" + ;; + *) + AC_CHECK_LIB(resolv, inet_aton, AC_CHECK_LIB(44bsd, inet_aton)) + AC_CHECK_LIB(resolv, main) + ;; esac fi AC_CHECK_LIB(m, main) @@ -1582,173 +1609,173 @@ dnl Robert Side dnl Mon, 18 Jan 1999 17:48:00 GMT case "$host" in - *-pc-sco3.2*) - AC_CHECK_LIB(intl, strftime) - ;; + *-pc-sco3.2*) + AC_CHECK_LIB(intl, strftime) + ;; esac dnl System-specific library modifications dnl case "$host" in - i386-*-solaris2.*) - if test "$GCC" = "yes"; then - echo "Removing -O for gcc on $host" - CFLAGS="`echo $CFLAGS | sed -e 's/-O[[0-9]]*//'`" - fi - ;; - *-sgi-irix*) - echo "Removing -lsocket for IRIX..." - LIBS=`echo $LIBS | sed -e s/-lsocket//` - echo "Removing -lnsl for IRIX..." - LIBS=`echo $LIBS | sed -e s/-lnsl//` - ac_cv_lib_nsl_main=no - echo "Removing -lbsd for IRIX..." - LIBS=`echo $LIBS | sed -e s/-lbsd//` - ;; + i386-*-solaris2.*) + if test "$GCC" = "yes"; then + echo "Removing -O for gcc on $host" + CFLAGS="`echo $CFLAGS | sed -e 's/-O[[0-9]]*//'`" + fi + ;; + *-sgi-irix*) + echo "Removing -lsocket for IRIX..." + LIBS=`echo $LIBS | sed -e s/-lsocket//` + echo "Removing -lnsl for IRIX..." + LIBS=`echo $LIBS | sed -e s/-lnsl//` + ac_cv_lib_nsl_main=no + echo "Removing -lbsd for IRIX..." + LIBS=`echo $LIBS | sed -e s/-lbsd//` + ;; dnl From: c0032033@ws.rz.tu-bs.de (Joerg Schumacher) dnl Date: Thu, 17 Oct 1996 04:09:30 +0200 dnl Please change your configure script. AIX doesn't need -lbsd. - *-ibm-aix*) - echo "Removing -lbsd for AIX..." - LIBS=`echo $LIBS | sed -e s/-lbsd//` + *-ibm-aix*) + echo "Removing -lbsd for AIX..." + LIBS=`echo $LIBS | sed -e s/-lbsd//` dnl From: mlaster@metavillage.com (Mike Laster) dnl AIX 4.1.4.x does not have header files for snprintf/vsnprintf dnl So using the internal versions generates a load of warnings dnl during compile. - echo "disabling snprintf/vsnprintf for $host" - ac_cv_func_snprintf=no - ac_cv_func_vsnprintf=no - ;; - *m88k*) - CFLAGS="$CFLAGS -D_SQUID_MOTOROLA_" - AC_DEFINE(GETTIMEOFDAY_NO_TZP) - ;; - [*-*-solaris2.[0-4]]) - AC_DEFINE(GETTIMEOFDAY_NO_TZP) - ;; - [*-sony-newsos[56]*]) - AC_DEFINE(GETTIMEOFDAY_NO_TZP) - ;; + echo "disabling snprintf/vsnprintf for $host" + ac_cv_func_snprintf=no + ac_cv_func_vsnprintf=no + ;; + *m88k*) + CFLAGS="$CFLAGS -D_SQUID_MOTOROLA_" + AC_DEFINE(GETTIMEOFDAY_NO_TZP) + ;; + [*-*-solaris2.[0-4]]) + AC_DEFINE(GETTIMEOFDAY_NO_TZP) + ;; + [*-sony-newsos[56]*]) + AC_DEFINE(GETTIMEOFDAY_NO_TZP) + ;; esac # Remove optimization for GCC 2.95.[123] # gcc -O[2] on *BSD and Linux (x86) causes pointers to magically become NULL if test "$GCC" = "yes"; then - GCCVER=`$CC -v 2>&1 | awk '$2 == "version" {print $3}'` - case "$GCCVER" in - [2.95.[123]]) - echo "Removing -O for gcc on $host with GCC $GCCVER" - CFLAGS="`echo $CFLAGS | sed -e 's/-O[[0-9]]*//'`" - ;; - esac + GCCVER=`$CC -v 2>&1 | awk '$2 == "version" {print $3}'` + case "$GCCVER" in + [2.95.[123]]) + echo "Removing -O for gcc on $host with GCC $GCCVER" + CFLAGS="`echo $CFLAGS | sed -e 's/-O[[0-9]]*//'`" + ;; + esac fi # Recommended by Balint Nagy Endre case "$host" in - *-univel-sysv4.2MP) - if test `uname -v` = "2.03"; then - echo "disabling mallinfo for $host" - ac_cv_func_mallinfo=no - fi - ;; + *-univel-sysv4.2MP) + if test `uname -v` = "2.03"; then + echo "disabling mallinfo for $host" + ac_cv_func_mallinfo=no + fi + ;; esac dnl This has to be before AC_CHECK_FUNCS # Disable poll() on certain platforms. Override by setting ac_cv_func_poll # when running configure. if test -z "$ac_cv_func_poll"; then - case "$host" in - [alpha-dec-osf3.*]) - # John Kay (jkay@nlanr.net) 19970818 - echo "disabling poll for $host..." - ac_cv_func_poll='no' - ;; - [*-hp-hpux*.*]) - # Duane Wessels - echo "disabling poll for $host..." - ac_cv_func_poll='no' - ;; - [*-linux-*]) - # Henrik Nordstrom (hno@squid-cache.org) 19980817 - # poll is problematic on Linux. We disable it - # by default until Linux gets it right. - rev=`uname -r | awk -F. '{printf "%03d%03d",$1,$2}'` - if test $rev -lt 002002; then - echo "disabling poll for $host < 2.2..." - ac_cv_func_poll='no' - fi - ;; - [powerpc-ibm-aix4.1.*]) - # Mike Laster (mlaster@metavillage.com) 19981021 - echo "disabling poll for $host..." - ac_cv_func_poll='no' - ;; - [*-pc-sco3.2*]) - # Robert Side - # Mon, 18 Jan 1999 17:48:00 GMT - echo "disabling poll for $host..." - ac_cv_func_poll='no' - ;; - esac + case "$host" in + [alpha-dec-osf3.*]) + # John Kay (jkay@nlanr.net) 19970818 + echo "disabling poll for $host..." + ac_cv_func_poll='no' + ;; + [*-hp-hpux*.*]) + # Duane Wessels + echo "disabling poll for $host..." + ac_cv_func_poll='no' + ;; + [*-linux-*]) + # Henrik Nordstrom (hno@squid-cache.org) 19980817 + # poll is problematic on Linux. We disable it + # by default until Linux gets it right. + rev=`uname -r | awk -F. '{printf "%03d%03d",$1,$2}'` + if test $rev -lt 002002; then + echo "disabling poll for $host < 2.2..." + ac_cv_func_poll='no' + fi + ;; + [powerpc-ibm-aix4.1.*]) + # Mike Laster (mlaster@metavillage.com) 19981021 + echo "disabling poll for $host..." + ac_cv_func_poll='no' + ;; + [*-pc-sco3.2*]) + # Robert Side + # Mon, 18 Jan 1999 17:48:00 GMT + echo "disabling poll for $host..." + ac_cv_func_poll='no' + ;; + esac fi dnl Check for library functions AC_CHECK_FUNCS(\ - backtrace_symbols_fd \ - bcopy \ - bswap_16 \ - bswap_32 \ - crypt \ - fchmod \ - getdtablesize \ - getpagesize \ - getpass \ - getrlimit \ - getrusage \ - getspnam \ - lrand48 \ - mallinfo \ - mallocblksize \ - mallopt \ - memcpy \ - memmove \ - memset \ - mkstemp \ - mktime \ - mstats \ - poll \ - pthread_attr_setschedparam \ - pthread_attr_setscope \ - pthread_setschedparam \ - pthread_sigmask \ - putenv \ - random \ - regcomp \ - regexec \ - regfree \ - res_init \ - rint \ - select \ - seteuid \ - setgroups \ - setpgrp \ - setrlimit \ - setsid \ - sigaction \ - snprintf \ - socketpair \ - srand48 \ - srandom \ - statfs \ - sysconf \ - syslog \ - timegm \ - vsnprintf \ + backtrace_symbols_fd \ + bcopy \ + bswap_16 \ + bswap_32 \ + crypt \ + fchmod \ + getdtablesize \ + getpagesize \ + getpass \ + getrlimit \ + getrusage \ + getspnam \ + lrand48 \ + mallinfo \ + mallocblksize \ + mallopt \ + memcpy \ + memmove \ + memset \ + mkstemp \ + mktime \ + mstats \ + poll \ + pthread_attr_setschedparam \ + pthread_attr_setscope \ + pthread_setschedparam \ + pthread_sigmask \ + putenv \ + random \ + regcomp \ + regexec \ + regfree \ + res_init \ + rint \ + select \ + seteuid \ + setgroups \ + setpgrp \ + setrlimit \ + setsid \ + sigaction \ + snprintf \ + socketpair \ + srand48 \ + srandom \ + statfs \ + sysconf \ + syslog \ + timegm \ + vsnprintf \ ) dnl Magic which checks whether we are forcing a type of comm loop we dnl are actually going to (ab)use - + dnl Actually do the define magic now dnl mostly ripped from squid-commloops, thanks to adrian and benno @@ -1759,8 +1786,8 @@ SELECT_TYPE="select" AC_DEFINE(USE_SELECT) elif test "$ac_cv_func_kqueue" = "yes" ; then - SELECT_TYPE="kqueue" - AC_DEFINE(USE_KQUEUE) + SELECT_TYPE="kqueue" + AC_DEFINE(USE_KQUEUE) else echo "Eep! Can't find poll, kqueue or select!" echo "I'll try select and hope for the best." @@ -1769,7 +1796,6 @@ fi echo "Using ${SELECT_TYPE} for select loop." - dnl Yay! Another Linux brokenness. Its not good enough dnl to know that setresuid() exists, because RedHat 5.0 declares dnl setresuid() but doesn't implement it. @@ -1794,7 +1820,7 @@ if test "$ac_cv_func_snprintf" = "no" || test "$ac_cv_func_vsnprintf" = "no" ; then AM_CONDITIONAL(NEED_OWN_SNPRINTF, true) fi - + dnl IP-Filter support requires ipf header files. These aren't dnl installed by default, so we need to check for them if test "$IPF_TRANSPARENT" ; then @@ -1821,7 +1847,7 @@ AC_DEFINE(IPF_TRANSPARENT, 0) fi AC_MSG_RESULT($IPF_TRANSPARENT) -fi +fi if test "$IPF_TRANSPARENT" = "no" ; then echo "WARNING: Cannot find necessary IP-Filter header files" echo " Transparent Proxy support WILL NOT be enabled" @@ -1860,7 +1886,7 @@ AC_DEFINE(LINUX_NETFILTER, 0) fi AC_MSG_RESULT($LINUX_NETFILTER) -fi +fi if test "$LINUX_NETFILTER" = "no" ; then echo "WARNING: Cannot find necessary Linux 2.4 kernel header files" echo " Linux 2.4 Transparent Proxy support WILL NOT be enabled" @@ -1870,37 +1896,37 @@ if test -z "$USE_GNUREGEX" ; then case "$host" in *-sun-solaris2.[[0-4]]) - USE_GNUREGEX="yes" - ;; + USE_GNUREGEX="yes" + ;; *-next-nextstep*) - USE_GNUREGEX="yes" - ;; + USE_GNUREGEX="yes" + ;; esac fi AC_MSG_CHECKING(if GNUregex needs to be compiled) if test -z "$USE_GNUREGEX"; then if test "$ac_cv_func_regcomp" = "no" || test "$USE_GNUREGEX" = "yes" ; then - USE_GNUREGEX="yes" + USE_GNUREGEX="yes" else - AC_TRY_COMPILE([#include + AC_TRY_COMPILE([#include #include ],[regex_t t; regcomp(&t,"",0);], - USE_GNUREGEX="no", - USE_GNUREGEX="yes") + USE_GNUREGEX="no", + USE_GNUREGEX="yes") fi fi AC_MSG_RESULT($USE_GNUREGEX) if test "$USE_GNUREGEX" = "yes"; then - REGEXLIB="-lregex" - LIBREGEX="libregex.a" - AC_DEFINE(USE_GNUREGEX) + REGEXLIB="-lregex" + LIBREGEX="libregex.a" + AC_DEFINE(USE_GNUREGEX) fi AC_SUBST(REGEXLIB) AC_SUBST(LIBREGEX) AC_REPLACE_FUNCS(\ - drand48 \ - tempnam \ - strerror \ + drand48 \ + tempnam \ + strerror \ ) dnl Not cached since people are likely to tune this @@ -1922,9 +1948,9 @@ #include #endif main() { - FILE *fp = fopen("conftestval", "w"); - fprintf (fp, "%d\n", FD_SETSIZE); - exit(0); + FILE *fp = fopen("conftestval", "w"); + fprintf (fp, "%d\n", FD_SETSIZE); + exit(0); } ], DEFAULT_FD_SETSIZE=`cat conftestval`, @@ -1940,18 +1966,18 @@ case $host in i386-unknown-freebsd*) if echo "$LDFLAGS" | grep -q pthread; then - LDFLAGS=`echo $LDFLAGS | sed -e "s/-pthread//"` + LDFLAGS=`echo $LDFLAGS | sed -e "s/-pthread//"` fi esac AC_TRY_RUN([ #include #include -#include /* needed on FreeBSD */ +#include /* needed on FreeBSD */ #include #include main() { - FILE *fp; - int i,j; + FILE *fp; + int i,j; #if defined(__CYGWIN32__) || defined (__CYGWIN__) /* getrlimit and sysconf returns bogous values on cygwin32. * Number of fds is virtually unlimited in cygwin (sys/param.h) @@ -1981,12 +2007,12 @@ } #endif /* RLIMIT_NOFILE */ #endif /* HAVE_SETRLIMIT */ - /* by starting at 2^14, we will never get higher - than 2^15 for SQUID_MAXFD */ + /* by starting at 2^14, we will never get higher + than 2^15 for SQUID_MAXFD */ i = j = 1<<14; while (j) { j >>= 1; - if (dup2(0, i) < 0) { + if (dup2(0, i) < 0) { i -= j; } else { close(i); @@ -1995,9 +2021,9 @@ } i++; #endif /* IF !DEF CYGWIN */ - fp = fopen("conftestval", "w"); - fprintf (fp, "%d\n", i); - exit(0); + fp = fopen("conftestval", "w"); + fprintf (fp, "%d\n", i); + exit(0); } ], SQUID_MAXFD=`cat conftestval`, @@ -2024,14 +2050,14 @@ #include main () { - FILE *fp; + FILE *fp; int fd,val=0,len=sizeof(int); - if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) exit(1); + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) exit(1); if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &val, &len) < 0) exit(1); - if (val<=0) exit(1); + if (val<=0) exit(1); fp = fopen("conftestval", "w"); fprintf (fp, "%d\n", val); - exit(0); + exit(0); } ], SQUID_UDP_SO_SNDBUF=`cat conftestval`, @@ -2050,14 +2076,14 @@ #include main () { - FILE *fp; + FILE *fp; int fd,val=0,len=sizeof(int); - if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) exit(1); + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) exit(1); if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &val, &len) < 0) exit(1); - if (val <= 0) exit(1); - fp = fopen("conftestval", "w"); - fprintf (fp, "%d\n", val); - exit(0); + if (val <= 0) exit(1); + fp = fopen("conftestval", "w"); + fprintf (fp, "%d\n", val); + exit(0); } ], SQUID_UDP_SO_RCVBUF=`cat conftestval`, @@ -2076,14 +2102,14 @@ #include main () { - FILE *fp; + FILE *fp; int fd,val=0,len=sizeof(int); - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) exit(1); + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) exit(1); if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &val, &len) < 0) exit(1); - if (val <= 0) exit(1); - fp = fopen("conftestval", "w"); - fprintf (fp, "%d\n", val); - exit(0); + if (val <= 0) exit(1); + fp = fopen("conftestval", "w"); + fprintf (fp, "%d\n", val); + exit(0); } ], SQUID_TCP_SO_SNDBUF=`cat conftestval`, @@ -2102,14 +2128,14 @@ #include main () { - FILE *fp; + FILE *fp; int fd,val=0,len=sizeof(int); - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) exit(1); + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) exit(1); if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &val, &len) < 0) exit(1); - if (val <= 0) exit(1); - fp = fopen("conftestval", "w"); - fprintf (fp, "%d\n", val); - exit(0); + if (val <= 0) exit(1); + fp = fopen("conftestval", "w"); + fprintf (fp, "%d\n", val); + exit(0); } ], SQUID_TCP_SO_RCVBUF=`cat conftestval`, @@ -2143,27 +2169,27 @@ #include main () { - FILE *fp; - struct in_addr in; - in.s_addr = inet_addr("1.2.3.4"); - fp = fopen("conftestval", "w"); - fprintf (fp, "%s\n", inet_ntoa(in)); - exit(0); + FILE *fp; + struct in_addr in; + in.s_addr = inet_addr("1.2.3.4"); + fp = fopen("conftestval", "w"); + fprintf (fp, "%s\n", inet_ntoa(in)); + exit(0); } ], INET_NTOA_RESULT=`cat conftestval`, INET_NTOA_RESULT="broken", INET_NTOA_RESULT="broken") if test "$INET_NTOA_RESULT" = "1.2.3.4" ; then - AC_MSG_RESULT("yes") + AC_MSG_RESULT("yes") else - AC_MSG_RESULT("no") - echo "Will use our own inet_ntoa()." - LIBOBJS="$LIBOBJS inet_ntoa.o" -# echo "WARNING: This looks bad, and probably prevents Squid from working." -# echo " If you're on IRIX and using GCC 2.8, you probably need" -# echo " to use the IRIX C compiler instead." -# sleep 10 + AC_MSG_RESULT("no") + echo "Will use our own inet_ntoa()." + LIBOBJS="$LIBOBJS inet_ntoa.o" +# echo "WARNING: This looks bad, and probably prevents Squid from working." +# echo " If you're on IRIX and using GCC 2.8, you probably need" +# echo " to use the IRIX C compiler instead." +# sleep 10 fi if test "$ac_cv_header_sys_statvfs_h" = "yes" ; then @@ -2176,7 +2202,7 @@ ], [ struct statvfs sfs; -sfs.f_blocks = sfs.f_bfree = sfs.f_frsize = +sfs.f_blocks = sfs.f_bfree = sfs.f_frsize = sfs.f_files = sfs.f_ffree = 0; statvfs("/tmp", &sfs); ], @@ -2243,51 +2269,50 @@ dnl Need the debugging version of malloc if available XTRA_OBJS='' if test "$ac_cv_lib_malloc_main" = "yes" ; then - if test -r /usr/lib/debug/malloc.o ; then - XTRA_OBJS="$XTRA_OBJS /usr/lib/debug/malloc.o" - fi - if test -r /usr/lib/debug/mallocmap.o ; then - XTRA_OBJS="$XTRA_OBJS /usr/lib/debug/mallocmap.o" - fi + if test -r /usr/lib/debug/malloc.o ; then + XTRA_OBJS="$XTRA_OBJS /usr/lib/debug/malloc.o" + fi + if test -r /usr/lib/debug/mallocmap.o ; then + XTRA_OBJS="$XTRA_OBJS /usr/lib/debug/mallocmap.o" + fi fi AC_SUBST(XTRA_OBJS) if test -z "$XTRA_LIBS"; then - XTRA_LIBS="$LIBS" - dnl minor cleanup - XTRA_LIBS=`echo $XTRA_LIBS | sed -e "s/ */ /g"` - LIBS='' + XTRA_LIBS="$LIBS" + dnl minor cleanup + XTRA_LIBS=`echo $XTRA_LIBS | sed -e "s/ */ /g"` + LIBS='' fi AC_SUBST(XTRA_LIBS) dnl Clean up after OSF/1 core dump bug -rm -f core +rm -f core dnl FS_MAKEFILES="" dnl for fs in $STORE_MODULES none; do -dnl if test $fs != none; then -dnl FS_MAKEFILES="$FS_MAKEFILES ./src/fs/$fs/Makefile" -dnl fi +dnl if test $fs != none; then +dnl FS_MAKEFILES="$FS_MAKEFILES ./src/fs/$fs/Makefile" +dnl fi dnl done dnl REPL_MAKEFILES="" dnl for repl in $REPL_POLICIES none; do -dnl if test $repl != none; then -dnl REPL_MAKEFILES="$REPL_MAKEFILES ./src/repl/$repl/Makefile" -dnl fi +dnl if test $repl != none; then +dnl REPL_MAKEFILES="$REPL_MAKEFILES ./src/repl/$repl/Makefile" +dnl fi dnl done dnl This could actually be used to find all the Makefiles.. dnl One of Automake's limitations is that it needs to know all the created makefiles. dnl AUTH_MAKEFILES="" dnl for auth in `find $srcdir/src/auth -type d -print`; do -dnl if test -f $auth/Makefile.in; then -dnl dir=`echo $auth | sed -e "s|^$srcdir/||"` +dnl if test -f $auth/Makefile.in; then +dnl dir=`echo $auth | sed -e "s|^$srcdir/||"` dnl AUTH_MAKEFILES="$AUTH_MAKEFILES ./$dir/Makefile" -dnl fi +dnl fi dnl done - dnl src/fs/aufs/Makefile \ dnl src/fs/coss/Makefile \ dnl src/fs/diskd/Makefile \ @@ -2296,54 +2321,55 @@ dnl src/repl/heap/Makefile \ dnl src/repl/lru/Makefile \ AC_OUTPUT([\ - Makefile \ - lib/Makefile \ - scripts/Makefile \ - scripts/RunCache \ - scripts/RunAccel \ - src/Makefile \ - src/fs/Makefile \ - src/repl/Makefile \ - src/auth/Makefile \ - src/auth/basic/Makefile \ - src/auth/digest/Makefile \ - src/auth/ntlm/Makefile \ - contrib/Makefile \ - snmplib/Makefile \ - icons/Makefile \ - errors/Makefile \ - src/fs/aufs/Makefile \ - src/fs/coss/Makefile \ - src/fs/diskd/Makefile \ - src/fs/null/Makefile \ - src/fs/ufs/Makefile \ - src/repl/heap/Makefile \ - src/repl/lru/Makefile \ - doc/Makefile \ - helpers/Makefile \ - helpers/basic_auth/Makefile \ - helpers/basic_auth/LDAP/Makefile \ - helpers/basic_auth/MSNT/Makefile \ - helpers/basic_auth/NCSA/Makefile \ - helpers/basic_auth/PAM/Makefile \ - helpers/basic_auth/SMB/Makefile \ - helpers/basic_auth/YP/Makefile \ - helpers/basic_auth/getpwnam/Makefile \ - helpers/basic_auth/multi-domain-NTLM/Makefile \ - helpers/basic_auth/SASL/Makefile \ - helpers/basic_auth/winbind/Makefile \ - helpers/digest_auth/Makefile \ - helpers/digest_auth/password/Makefile \ - helpers/ntlm_auth/Makefile \ - helpers/ntlm_auth/fakeauth/Makefile \ - helpers/ntlm_auth/no_check/Makefile \ - helpers/ntlm_auth/SMB/Makefile \ - helpers/ntlm_auth/SMB/smbval/Makefile \ - helpers/ntlm_auth/winbind/Makefile \ - helpers/external_acl/Makefile \ - helpers/external_acl/ip_user/Makefile \ - helpers/external_acl/ldap_group/Makefile \ - helpers/external_acl/unix_group/Makefile \ - helpers/external_acl/wbinfo_group/Makefile \ - helpers/external_acl/winbind_group/Makefile \ + Makefile \ + lib/Makefile \ + scripts/Makefile \ + scripts/RunCache \ + scripts/RunAccel \ + src/Makefile \ + src/fs/Makefile \ + src/repl/Makefile \ + src/auth/Makefile \ + src/auth/basic/Makefile \ + src/auth/digest/Makefile \ + src/auth/ntlm/Makefile \ + contrib/Makefile \ + snmplib/Makefile \ + icons/Makefile \ + errors/Makefile \ + src/fs/aufs/Makefile \ + src/fs/coss/Makefile \ + src/fs/diskd/Makefile \ + src/fs/null/Makefile \ + src/fs/ufs/Makefile \ + src/repl/heap/Makefile \ + src/repl/lru/Makefile \ + doc/Makefile \ + helpers/Makefile \ + helpers/basic_auth/Makefile \ + helpers/basic_auth/LDAP/Makefile \ + helpers/basic_auth/MSNT/Makefile \ + helpers/basic_auth/NCSA/Makefile \ + helpers/basic_auth/PAM/Makefile \ + helpers/basic_auth/SMB/Makefile \ + helpers/basic_auth/YP/Makefile \ + helpers/basic_auth/getpwnam/Makefile \ + helpers/basic_auth/multi-domain-NTLM/Makefile \ + helpers/basic_auth/SASL/Makefile \ + helpers/basic_auth/winbind/Makefile \ + helpers/digest_auth/Makefile \ + helpers/digest_auth/password/Makefile \ + helpers/ntlm_auth/Makefile \ + helpers/ntlm_auth/fakeauth/Makefile \ + helpers/ntlm_auth/no_check/Makefile \ + helpers/ntlm_auth/SMB/Makefile \ + helpers/ntlm_auth/SMB/smbval/Makefile \ + helpers/ntlm_auth/winbind/Makefile \ + helpers/external_acl/Makefile \ + helpers/external_acl/ip_user/Makefile \ + helpers/external_acl/ldap_group/Makefile \ + helpers/external_acl/unix_group/Makefile \ + helpers/external_acl/wbinfo_group/Makefile \ + helpers/external_acl/winbind_group/Makefile \ ]) + Index: squid/mkrelease.sh diff -u squid/mkrelease.sh:1.6 squid/mkrelease.sh:1.2.12.2 --- squid/mkrelease.sh:1.6 Sun Sep 1 09:30:40 2002 +++ squid/mkrelease.sh Tue Sep 3 10:39:10 2002 @@ -50,6 +50,15 @@ make dist-all cd $startdir +<<<<<<< mkrelease.sh +cp -p $tmpdir/${name}.tar.gz $dst +cp -p $tmpdir/${name}.tar.bz2 $dst +cp -p $tmpdir/CONTRIBUTORS $dst/CONTRIBUTORS.txt +cp -p $tmpdir/COPYING $dst/COPYING.txt +cp -p $tmpdir/COPYRIGHT $dst/COPYRIGHT.txt +cp -p $tmpdir/CREDITS $dst/CREDITS.txt +cp -p $tmpdir/ChangeLog $dst/ChangeLog.txt +======= cp -p $tmpdir/${name}.tar.gz $dst cp -p $tmpdir/${name}.tar.bz2 $dst cp -p $tmpdir/CONTRIBUTORS $dst/CONTRIBUTORS.txt @@ -60,3 +69,4 @@ if [ -f $tmpdir/doc/release-notes/release-$RELEASE.html ]; then cp -p $tmpdir/doc/release-notes/release-$RELEASE.html $dst/RELEASENOTES.html fi +>>>>>>> 1.6 Index: squid/doc/push.txt diff -u /dev/null squid/doc/push.txt:1.1.2.2 --- /dev/null Mon Jan 26 04:57:35 2004 +++ squid/doc/push.txt Mon May 20 19:46:41 2002 @@ -0,0 +1,133 @@ + HOW TO USE PUSH + + Jon Kay + pushcache.com + + +This document is about how to make use of a pushcache. There are +basically two ways: you can either speak the protocol, which is a +couple of simple addenda to standard HTTP, or, those of you whose +lives extend beyond writing HTTP protocol code can use a shell script +called 'webpush.' Webpush is meant as a parallel command to 'client' +(e.g., it's client, but for push rather than pull), so, just like +client, it can be found in the bin subdirectory of installed Squid +trees, and the src subdirectory in source distributions. + +Arguably, there is no need for 'webpush.' You can do much the same +thing by executing: + client -m PUT + +But most people find that just really tough to think about, so instead +we have the more user-friendly + + webpush + +constitute the shell and scripting interface to pushcaches. Besides, +webpush preserves Last-modified information (stat st_mtime) from the +file. That may not seem like much, but it's seriously handy in the +push world, where that amounts to a version number, and it used to +figure out which of different URL contents to keep as current. + +You can push any kind of content. You can see the results by changing +your browsers Preferences/Advanced/Proxies settings to point to Squid +(default port is 3128), and then looking in on the file, or reloading +if you already have fetched an old copy. + +PUT ACL + +Before you do anything, whether with webpush or programming, you have +to set up your acls so that they permit PUT requests from everyone you +want to be able to do push. See the ACL section of your +etc/squid.conf; for most people, the appropriate thing will be to +simply allow all types of requests from whomever the Good Guys are. + +PUSHING HTTP + +The other way to do push is, as we said, to speak the protocol. +A push application would, probably with the aid of an appropriate +programming library such as pushcache.com's PushAp Kit push library, +use these protocol elements to communicate with pushcaches. + +Pushcaches, in turn, use these protocols plus hint cache protocols +(not defined in this document) to communicate. + +There are, in effect, two requests: push and dist. + + + +PUSH + +Push is accomplished by sending a standard HTTP PUT request to a local +pushcache. There is no protocol addendum, except in practical usage +terms. A pushcache receiving such a request is expected to +effectively propagate the object sent on the given URL to every +interested pushcache and application instance connected to the same +pushcache cloud. + +An application or cache is defined to be interested if it has sent a +dist request to a local pushcache. + + +DIST + +Dists are accomplished by sending a special nonstandard HTTP request +to a local pushcache. The format is a standard GET request, except +that the URL is augmented to append the string 'dist' and a TCP port +number to the URL method. E.g., the first line of a dist request +for http://server/file would be: + + GET httpdist6543://server/file HTTP/1.0\r\n + +The pushcache returns the contents of http://server/file, then, later, +when the contents of http://server/file change, it sends the new +contents via HTTP PUT to the host that originated the 'dist' at the +TCP port number specified in the dist request. Third-party dists are +not supported, for security. + +If there is an error, e.g., the server or the file does not exist, the +pushcache will not remember the request should the URL later become +valid. + +We chose not to define a new DIST request type to facilitate +interoperation with non-pushy firewalls and proxies. + + +PUSHCACHE OPERATION + +Pushcache clouds in effect create a distribution tree for each object +as interest in that object spreads. + +Most pushcaches forward GET requests to neighboring caches as dists +instead, in effect implementing eager consistency. + +If a pushcache receives a dist request for an object it has a copy of +already, it distributes the object and changes to it, in effect +implementing a distribution link, adding a link a node to whatever +digraph the pushcache is already part of. + +When pushcaches send dist requests to other pushcaches, they +act as though that pushcache sent them a dist request as well, for +purposes of propagating later changes (they do not send an immediate +current copy). Thus, distribution links between pushcaches are +automatically bidirectional (NOT true of distribution links to client +applications). + +A pushcache receiving a dist request for an object it does not know +about consults its magic hint cache. Each pushcache knows the closest +location of every object that any pushcache in the connected cloud +knows about. If it's in the hint cache, it knows about the object, +otherwise not. If it can find it, the pushcache sends a dist request +to that closest pushcache that does have it, attaching this cache to +the digraph for that object. + + +SEMANTICS VS. SCALING + +Pushcaches implement "best effort" consistency. That is, they make a +good effort, will usually succeed, but there are no guarantees. This +design point was chosen to optimize for scalability. We believe this +will suffice for most potential applications, though certainly not all. + +Research is ongoing into improving consistency without losing +scalability. + Index: squid/doc/Programming-Guide/prog-guide.sgml diff -u squid/doc/Programming-Guide/prog-guide.sgml:1.21 squid/doc/Programming-Guide/prog-guide.sgml:1.16.8.1 --- squid/doc/Programming-Guide/prog-guide.sgml:1.21 Fri Aug 9 14:45:58 2002 +++ squid/doc/Programming-Guide/prog-guide.sgml Tue Sep 3 10:39:11 2002 @@ -64,27 +64,6 @@ structures and their members will be written in an italicized font, such as Coding Conventions - -Infrastructure - -

- Most custom types and tools are documented in the code or the relevant - portions of this manual. Some key points apply globally however. - -Fixed width types -

- If you need to use specific width types - such as - a 16 bit unsigned integer, use one of the following types. To access - them simply include "config.h". - - int16_t - 16 bit signed. - u_int16_t - 16 bit unsigned. - int32t - 32 bit signed. - u_int32_t - 32 bit unsigned. - int64_t - 64 bit signed. - u_int64_t - 64 bit unsigned. - Overview of Squid Components @@ -405,7 +384,7 @@ Refresh Rules

- These routines decide whether a cached object is stale or fresh, + These routines decide wether a cached object is stale or fresh, based on the We are experimenting with URN support in Squid version 1.2. Note, we're not talking full-blown generic URN's here. This - is primarily targeted toward using URN's as an smart way + is primarily targeted towards using URN's as an smart way of handling lists of mirror sites. For more details, please see . @@ -2527,10 +2506,9 @@

Macro that defines a new cbdata datatype. Similar to a variable or struct definition. Scope is always local to the file/block - where it is defined and all calls to cbdataAlloc for this type - must be within the same scope as the CBDATA_TYPE declaration. - Allocated entries may be referenced or freed anywhere with no - restrictions on scope. + where it is defined and all allocations must be within this scope. + Allocated entries referenced or freed anywhere with no restrictions + on scope. CBDATA_GLOBAL_TYPE @@ -2643,12 +2621,10 @@

Removes a reference created by cbdataReference() and checks - it for validity. A temporary pointer to the referenced data - (if valid) is returned in the &pointer argument. + it for validity.

- Meant to be used on the last dereference, usually to make - a callback. + Meant to be used on the last dereference void *cbdata; @@ -2663,120 +2639,81 @@ Examples

- Here you can find some examples on how to use cbdata, and why - -Asynchronous operation without cbdata, showing why cbdata is needed - -

- For a asyncronous operation with callback functions, the normal - sequence of events in programs NOT using cbdata is as follows: + For a blocking operation + with callback functions, the normal sequence of events is as + follows: - /* initialization */ - type_of_data our_data; - ... - our_data = malloc(...); + callback_data = malloc(...); ... - /* Initiate a asyncronous operation, with our_data as callback_data */ - fooOperationStart(bar, callback_func, our_data); + fooOperationStart(bar, callback_func, callback_data); ... - /* The asyncronous operation completes and makes the callback */ + fooOperationComplete(...); callback_func(callback_data, ....); - /* Some time later we clean up our data */ - free(our_data); + ... + free(callback_data); However, things become more interesting if we want or need to free the callback_data, or otherwise cancel the callback, - before the operation completes. In constructs like this you - can quite easily end up with having the memory referenced - pointed to by callback_data freed before the callback is invoked - causing a program failure or memory corruption: - - /* initialization */ - type_of_data our_data; - ... - our_data = malloc(...); - ... - /* Initiate a asyncronous operation, with our_data as callback_data */ - fooOperationStart(bar, callback_func, our_data); - ... - /* ouch, something bad happened elsewhere.. try to cleanup - * but the programmer forgot there is a callback pending from - * fooOperationsStart() (an easy thing to forget when writing code - * to deal with errors, especially if there may be many different - * pending operation) - */ - free(our_data); - ... - /* The asyncronous operation completes and makes the callback */ - callback_func(callback_data, ....); - /* CRASH, the memory pointer to by callback_data is no longer valid - * at the time of the callback - */ - -Asyncronous operation with cbdata + before the operation completes.

The callback data allocator lets us do this in a uniform and safe manner. The callback data allocator is used to allocate, track and free memory pool objects used during callback - operations. Allocated memory is locked while the asyncronous + operations. Allocated memory is locked while the blocking operation executes elsewhere, and is freed when the operation completes. The normal sequence of events is: /* initialization */ - type_of_data our_data; + type_of_data callback_data; ... - our_data = cbdataAlloc(type_of_data); + callback_data = cbdataAlloc(type_of_data); ... - /* Initiate a asyncronous operation, with our_data as callback_data */ - fooOperationStart(..., callback_func, our_data); + /* calling "foo" */ + fooOperationStart(..., callback_func, callback_data); ... - /* foo */ - void *local_pointer = cbdataReference(callback_data); - .... - /* The asyncronous operation completes and makes the callback */ - void *cbdata; - if (cbdataReferenceValidDone(local_pointer, &cbdata)) - callback_func(...., cbdata); - ... - cbdataFree(our_data); + /* being destroyed */ + cbdataFree(callback_data); + /* foo */ + void + fooOperationStart(..., callback_func, void *callback_data) + { + void *local_pointer = cbdataReference(callback_data); + .... + } + void + fooOperationComplete(...) + { + void *cbdata; + ... + if (cbdataReferenceValidDone(local_pointer, &cbdata)) + callback_func(...., cbdata); + } -Asynchronous operation cancelled by cbdata -

With this scheme, nothing bad happens if - /* initialization */ - type_of_data our_data; - ... - our_data = cbdataAlloc(type_of_data); + callback_data = cbdataAlloc(...); ... - /* Initiate a asyncronous operation, with our_data as callback_data */ - fooOperationStart(..., callback_func, our_data); + fooOperationStart(bar, callback_func, callback_data); + local_pointer = cbdataReference(callback_data); ... - /* foo */ - void *local_pointer = cbdataReference(callback_data); - .... - /* something bad happened elsewhere.. cleanup */ - cbdataFree(our_data); + cbdataFree(callback_data); ... - /* The asyncronous operation completes and tries to make the callback */ + fooOperationComplete(...); void *cbdata; - if (cbdataReferenceValidDone(local_pointer, &cbdata)) - /* won't be called, as the data is no longer valid */ - callback_func(...., cbdata); - + if (cbdataReferenceValidDone(local_pointer, cbdata)) + callback_func(cbdata, ....); In this case, when Adding a new cbdata registered type + Before executing the callback function, To add new module specific data types to the allocator one uses the @@ -2795,24 +2732,16 @@ * (can be called multiple times with only a minimal overhead) */ CBDATA_INIT_TYPE(type_of_data); - /* Or if a free function is associated with the data type. This - * function is responsible for cleaning up any dependencies etc - * referenced by the structure and is called on cbdataFree or - * when the last reference is deleted by cbdataReferenceDone / - * cbdataReferenceValidDone - */ + /* Or if a free function is associated with the data type */ CBDATA_INIT_TYPE_FREECB(type_of_data, free_function); -Adding a new cbdata registered data type globally -

- To add new global data types that can be allocated from anywhere - within the code one have to add them to the cbdata_type enum in - enums.h, and a corresponding CREATE_CBDATA call in - cbdata.c:cbdataInit(). Or alternatively add a CBDATA_GLOBAL_TYPE - definition to globals.h as shown below and use CBDATA_INIT_TYPE at - the appropriate location(s) as described above. + To add new global data types one have to add them to the + cbdata_type enum in enums.h, and a corresponding + CREATE_CBDATA call in cbdata.c:cbdataInit(). Or alternatively + add a CBDATA_GLOBAL_TYPE definition to globals.h and use + CBDATA_INIT_TYPE as described above. extern CBDATA_GLOBAL_TYPE(type_of_data); /* CBDATA_UNDEF */ Index: squid/errors/list diff -u squid/errors/list:1.1.1.1 squid/errors/list:1.1.1.1.120.1 --- squid/errors/list:1.1.1.1 Tue Jan 25 19:21:47 2000 +++ squid/errors/list Fri Dec 7 15:25:31 2001 @@ -3,6 +3,7 @@ ERR_CACHE_MGR_ACCESS_DENIED ERR_CANNOT_FORWARD ERR_CLIENT_ABORT +ERR_CONFLICT ERR_CONNECT_FAIL ERR_DNS_FAIL ERR_FORWARDING_DENIED Index: squid/errors/Bulgarian/ERR_CONFLICT diff -u /dev/null squid/errors/Bulgarian/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:35 2004 +++ squid/errors/Bulgarian/ERR_CONFLICT Sat Dec 22 08:31:33 2001 @@ -0,0 +1,34 @@ + +ERROR: The requested URL could not be retrieved + +

ERROR

+

The requested URL could not be retrieved

+
+

+While trying to retrieve the URL: +%U +

+The following error was encountered: +

    +
  • + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+ +

+The system returned: +

    %E
+ +

+This means that: +

+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+
+

+ Index: squid/errors/Catalan/ERR_ACCESS_DENIED diff -u squid/errors/Catalan/ERR_ACCESS_DENIED:1.4 squid/errors/Catalan/ERR_ACCESS_DENIED:1.4.6.1 --- squid/errors/Catalan/ERR_ACCESS_DENIED:1.4 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_ACCESS_DENIED Tue Sep 3 10:39:18 2002 @@ -1,11 +1,9 @@ - - + ERROR: No es pot mostrar la URL que heu sol.licitat -

ERROR

No es pot mostrar la URL que heu sol.licitat

-
+

Mentre s'intentava llegir la URL: %U Index: squid/errors/Catalan/ERR_CACHE_ACCESS_DENIED diff -u squid/errors/Catalan/ERR_CACHE_ACCESS_DENIED:1.4 squid/errors/Catalan/ERR_CACHE_ACCESS_DENIED:1.4.6.1 --- squid/errors/Catalan/ERR_CACHE_ACCESS_DENIED:1.4 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_CACHE_ACCESS_DENIED Tue Sep 3 10:39:18 2002 @@ -1,12 +1,10 @@ - - + ERROR: Accés denegat a la cache -

ERROR

Accés denegat a la cache

-
+

Mentre s'intentava llegir la URL: %U Index: squid/errors/Catalan/ERR_CACHE_MGR_ACCESS_DENIED diff -u squid/errors/Catalan/ERR_CACHE_MGR_ACCESS_DENIED:1.4 squid/errors/Catalan/ERR_CACHE_MGR_ACCESS_DENIED:1.4.6.1 --- squid/errors/Catalan/ERR_CACHE_MGR_ACCESS_DENIED:1.4 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_CACHE_MGR_ACCESS_DENIED Tue Sep 3 10:39:19 2002 @@ -1,12 +1,10 @@ - - + ERROR: Accés denegat a l'administració de la cache -

ERROR

ERROR: Accés denegat a l'administració de la cache

-
+

Mentre s'intentava llegir la URL: %U Index: squid/errors/Catalan/ERR_CANNOT_FORWARD diff -u squid/errors/Catalan/ERR_CANNOT_FORWARD:1.4 squid/errors/Catalan/ERR_CANNOT_FORWARD:1.4.6.1 --- squid/errors/Catalan/ERR_CANNOT_FORWARD:1.4 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_CANNOT_FORWARD Tue Sep 3 10:39:19 2002 @@ -1,11 +1,9 @@ - - + ERROR: No es pot mostrar la URL que heu sol.licitat -

ERROR

No es pot mostrar la URL que heu sol.licitat

-
+

Mentre s'intentava llegir la URL: %U Index: squid/errors/Catalan/ERR_CONNECT_FAIL diff -u squid/errors/Catalan/ERR_CONNECT_FAIL:1.4 squid/errors/Catalan/ERR_CONNECT_FAIL:1.4.6.1 --- squid/errors/Catalan/ERR_CONNECT_FAIL:1.4 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_CONNECT_FAIL Tue Sep 3 10:39:20 2002 @@ -1,11 +1,9 @@ - - + ERROR: No es pot mostrar la URL que heu sol.licitat -

ERROR

No es pot mostrar la URL que heu sol.licitat

-
+

Mentre s'intentava llegir la URL: %U Index: squid/errors/Catalan/ERR_DNS_FAIL diff -u squid/errors/Catalan/ERR_DNS_FAIL:1.4 squid/errors/Catalan/ERR_DNS_FAIL:1.4.6.1 --- squid/errors/Catalan/ERR_DNS_FAIL:1.4 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_DNS_FAIL Tue Sep 3 10:39:20 2002 @@ -1,10 +1,8 @@ - - + ERROR: No es pot mostrar la URL que heu sol.licitat -

No es pot mostrar la URL que heu sol.licitat

-
+

Mentre s'intentava llegir la URL: %U Index: squid/errors/Catalan/ERR_FORWARDING_DENIED diff -u squid/errors/Catalan/ERR_FORWARDING_DENIED:1.4 squid/errors/Catalan/ERR_FORWARDING_DENIED:1.4.6.1 --- squid/errors/Catalan/ERR_FORWARDING_DENIED:1.4 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_FORWARDING_DENIED Tue Sep 3 10:39:21 2002 @@ -1,11 +1,9 @@ - - + ERROR: No es pot mostrar la URL que heu sol.licitat -

ERROR

No es pot mostrar la URL que heu sol.licitat

-
+

Mentre s'intentava llegir la URL: %U Index: squid/errors/Catalan/ERR_FTP_DISABLED diff -u squid/errors/Catalan/ERR_FTP_DISABLED:1.4 squid/errors/Catalan/ERR_FTP_DISABLED:1.4.6.1 --- squid/errors/Catalan/ERR_FTP_DISABLED:1.4 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_FTP_DISABLED Tue Sep 3 10:39:21 2002 @@ -1,11 +1,9 @@ - - + ERROR: No es pot mostrar la URL que heu sol.licitat -

ERROR

No es pot mostrar la URL que heu sol.licitat

-
+

Mentre s'intentava llegir la URL: %U Index: squid/errors/Catalan/ERR_FTP_FAILURE diff -u squid/errors/Catalan/ERR_FTP_FAILURE:1.4 squid/errors/Catalan/ERR_FTP_FAILURE:1.4.6.1 --- squid/errors/Catalan/ERR_FTP_FAILURE:1.4 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_FTP_FAILURE Tue Sep 3 10:39:21 2002 @@ -1,11 +1,9 @@ - - + ERROR: No es pot mostrar la URL que heu sol.licitat -

ERROR

No es pot mostrar la URL que heu sol.licitat

-
+

S'ha produït un error FTP mentre s'intentava llegir la URL: %U Index: squid/errors/Catalan/ERR_FTP_FORBIDDEN diff -u squid/errors/Catalan/ERR_FTP_FORBIDDEN:1.4 squid/errors/Catalan/ERR_FTP_FORBIDDEN:1.4.6.1 --- squid/errors/Catalan/ERR_FTP_FORBIDDEN:1.4 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_FTP_FORBIDDEN Tue Sep 3 10:39:21 2002 @@ -1,11 +1,9 @@ - - + ERROR: No es pot mostrar la URL que heu sol.licitat -

ERROR

No es pot mostrar la URL que heu sol.licitat

-
+

S'ha produït un error en l'autentificació FTP mentre s'intentava llegir la URL Index: squid/errors/Catalan/ERR_FTP_NOT_FOUND diff -u squid/errors/Catalan/ERR_FTP_NOT_FOUND:1.4 squid/errors/Catalan/ERR_FTP_NOT_FOUND:1.4.6.1 --- squid/errors/Catalan/ERR_FTP_NOT_FOUND:1.4 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_FTP_NOT_FOUND Tue Sep 3 10:39:21 2002 @@ -1,11 +1,9 @@ - - + ERROR: No es pot mostrar la URL que heu sol.licitat -

ERROR

No es pot mostrar la URL que heu sol.licitat

-
+

URL: %U Index: squid/errors/Catalan/ERR_FTP_PUT_CREATED diff -u squid/errors/Catalan/ERR_FTP_PUT_CREATED:1.4 squid/errors/Catalan/ERR_FTP_PUT_CREATED:1.4.6.1 --- squid/errors/Catalan/ERR_FTP_PUT_CREATED:1.4 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_FTP_PUT_CREATED Tue Sep 3 10:39:21 2002 @@ -1,8 +1,6 @@ - - + Comanda FTP PUT executada amb èxit: Fitxer creat -

Operació completada

Fitxer creat

-
+
Index: squid/errors/Catalan/ERR_FTP_PUT_ERROR diff -u squid/errors/Catalan/ERR_FTP_PUT_ERROR:1.4 squid/errors/Catalan/ERR_FTP_PUT_ERROR:1.4.6.1 --- squid/errors/Catalan/ERR_FTP_PUT_ERROR:1.4 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_FTP_PUT_ERROR Tue Sep 3 10:39:21 2002 @@ -1,11 +1,9 @@ - - + ERROR: Ha fallat l'enviament del fitxer FTP -

ERROR

Ha fallat la comanda FTP d'enviament de fitxer

-
+

Mentre s'intentava la comanda PUT a la URL: %U Index: squid/errors/Catalan/ERR_FTP_PUT_MODIFIED diff -u squid/errors/Catalan/ERR_FTP_PUT_MODIFIED:1.4 squid/errors/Catalan/ERR_FTP_PUT_MODIFIED:1.4.6.1 --- squid/errors/Catalan/ERR_FTP_PUT_MODIFIED:1.4 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_FTP_PUT_MODIFIED Tue Sep 3 10:39:21 2002 @@ -1,8 +1,6 @@ - - + Comanda FTP PUT completada amb éxit: Fitxer actualitzat -

Operació completada

Fitxer actualitzat

-
+
Index: squid/errors/Catalan/ERR_FTP_UNAVAILABLE diff -u squid/errors/Catalan/ERR_FTP_UNAVAILABLE:1.4 squid/errors/Catalan/ERR_FTP_UNAVAILABLE:1.4.6.1 --- squid/errors/Catalan/ERR_FTP_UNAVAILABLE:1.4 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_FTP_UNAVAILABLE Tue Sep 3 10:39:21 2002 @@ -1,11 +1,9 @@ - - + ERROR: No es pot mostrar la URL que heu sol.licitat -

ERROR

No es pot mostrar la URL que heu sol.licitat

-
+

El servidor FTP estava massa ocupat quan intentava mostrar la URL: %U Index: squid/errors/Catalan/ERR_INVALID_REQ diff -u squid/errors/Catalan/ERR_INVALID_REQ:1.4 squid/errors/Catalan/ERR_INVALID_REQ:1.4.6.1 --- squid/errors/Catalan/ERR_INVALID_REQ:1.4 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_INVALID_REQ Tue Sep 3 10:39:22 2002 @@ -1,11 +1,9 @@ - - + ERROR: No es pot mostrar la URL que heu sol.licitat -

ERROR

No es pot mostrar la URL que heu sol.licitat

-
+

Mentre s'intentava llegir la URL:

Index: squid/errors/Catalan/ERR_INVALID_URL
diff -u squid/errors/Catalan/ERR_INVALID_URL:1.4 squid/errors/Catalan/ERR_INVALID_URL:1.4.6.1
--- squid/errors/Catalan/ERR_INVALID_URL:1.4	Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_INVALID_URL	Tue Sep  3 10:39:22 2002
@@ -1,11 +1,9 @@
-
-
+
 ERROR: No es pot mostrar la URL que heu sol.licitat
-
 
 

ERROR

No es pot mostrar la URL que heu sol.licitat

-
+

Mentre s'intentava llegir la URL: %U Index: squid/errors/Catalan/ERR_LIFETIME_EXP diff -u squid/errors/Catalan/ERR_LIFETIME_EXP:1.4 squid/errors/Catalan/ERR_LIFETIME_EXP:1.4.6.1 --- squid/errors/Catalan/ERR_LIFETIME_EXP:1.4 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_LIFETIME_EXP Tue Sep 3 10:39:22 2002 @@ -1,11 +1,9 @@ - - + ERROR: No es pot mostrar la URL que heu sol.licitat -

ERROR

No es pot mostrar la URL que heu sol.licitat

-
+

Mentre s'intentava llegir la URL: %U Index: squid/errors/Catalan/ERR_NO_RELAY diff -u squid/errors/Catalan/ERR_NO_RELAY:1.4 squid/errors/Catalan/ERR_NO_RELAY:1.4.6.1 --- squid/errors/Catalan/ERR_NO_RELAY:1.4 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_NO_RELAY Tue Sep 3 10:39:22 2002 @@ -1,11 +1,9 @@ - - + ERROR: No es pot mostrar la URL que heu sol.licitat -

ERROR

No es pot mostrar la URL que heu sol.licitat

-
+

Mentre s'intentava llegir la URL: %U Index: squid/errors/Catalan/ERR_ONLY_IF_CACHED_MISS diff -u squid/errors/Catalan/ERR_ONLY_IF_CACHED_MISS:1.4 squid/errors/Catalan/ERR_ONLY_IF_CACHED_MISS:1.4.6.1 --- squid/errors/Catalan/ERR_ONLY_IF_CACHED_MISS:1.4 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_ONLY_IF_CACHED_MISS Tue Sep 3 10:39:22 2002 @@ -1,11 +1,9 @@ - - + ERROR: No es pot mostrar la URL que heu sol.licitat -

ERROR

No es pot mostrar la URL que heu sol.licitat

-
+

Mentre s'intentava llegir la URL: %U Index: squid/errors/Catalan/ERR_READ_ERROR diff -u squid/errors/Catalan/ERR_READ_ERROR:1.4 squid/errors/Catalan/ERR_READ_ERROR:1.4.6.1 --- squid/errors/Catalan/ERR_READ_ERROR:1.4 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_READ_ERROR Tue Sep 3 10:39:22 2002 @@ -1,11 +1,9 @@ - - + ERROR: No es pot mostrar la URL que heu sol.licitat -

ERROR

No es pot mostrar la URL que heu sol.licitat

-
+

Mentre s'intentava llegir la URL: %U Index: squid/errors/Catalan/ERR_READ_TIMEOUT diff -u squid/errors/Catalan/ERR_READ_TIMEOUT:1.4 squid/errors/Catalan/ERR_READ_TIMEOUT:1.4.6.1 --- squid/errors/Catalan/ERR_READ_TIMEOUT:1.4 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_READ_TIMEOUT Tue Sep 3 10:39:23 2002 @@ -1,11 +1,9 @@ - - + ERROR: No es pot mostrar la URL que heu sol.licitat -

ERROR

No es pot mostrar la URL que heu sol.licitat

-
+

Mentre s'intentava llegir la URL: %U Index: squid/errors/Catalan/ERR_SHUTTING_DOWN diff -u squid/errors/Catalan/ERR_SHUTTING_DOWN:1.4 squid/errors/Catalan/ERR_SHUTTING_DOWN:1.4.6.1 --- squid/errors/Catalan/ERR_SHUTTING_DOWN:1.4 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_SHUTTING_DOWN Tue Sep 3 10:39:23 2002 @@ -1,11 +1,9 @@ - - + ERROR: No es pot mostrar la URL que heu sol.licitat -

ERROR

No es pot mostrar la URL que heu sol.licitat

-
+

Mentre s'intentava llegir la URL: %U Index: squid/errors/Catalan/ERR_SOCKET_FAILURE diff -u squid/errors/Catalan/ERR_SOCKET_FAILURE:1.4 squid/errors/Catalan/ERR_SOCKET_FAILURE:1.4.6.1 --- squid/errors/Catalan/ERR_SOCKET_FAILURE:1.4 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_SOCKET_FAILURE Tue Sep 3 10:39:23 2002 @@ -1,11 +1,9 @@ - - + ERROR: No es pot mostrar la URL que heu sol.licitat -

ERROR

No es pot mostrar la URL que heu sol.licitat

-
+

Mentre s'intentava llegir la URL: %U Index: squid/errors/Catalan/ERR_TOO_BIG diff -u squid/errors/Catalan/ERR_TOO_BIG:1.4 squid/errors/Catalan/ERR_TOO_BIG:1.4.6.1 --- squid/errors/Catalan/ERR_TOO_BIG:1.4 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_TOO_BIG Tue Sep 3 10:39:23 2002 @@ -1,11 +1,9 @@ - - + ERROR: No es pot mostrar la URL que heu sol.licitat -

ERROR

No es pot mostrar la URL que heu sol.licitat

-
+

Mentre s'intentava llegir la URL: %U Index: squid/errors/Catalan/ERR_UNSUP_REQ diff -u squid/errors/Catalan/ERR_UNSUP_REQ:1.4 squid/errors/Catalan/ERR_UNSUP_REQ:1.4.6.1 --- squid/errors/Catalan/ERR_UNSUP_REQ:1.4 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_UNSUP_REQ Tue Sep 3 10:39:23 2002 @@ -1,11 +1,9 @@ - - + ERROR: No es pot mostrar la URL que heu sol.licitat -

ERROR

No es pot mostrar la URL que heu sol.licitat

-
+

Mentre s'intentava llegir la URL: %U Index: squid/errors/Catalan/ERR_URN_RESOLVE diff -u squid/errors/Catalan/ERR_URN_RESOLVE:1.4 squid/errors/Catalan/ERR_URN_RESOLVE:1.4.6.1 --- squid/errors/Catalan/ERR_URN_RESOLVE:1.4 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_URN_RESOLVE Tue Sep 3 10:39:23 2002 @@ -1,11 +1,9 @@ - - + ERROR: No es pot mostrar la URN que heu sol.licitat -

ERROR

No es pot mostrar la URN que heu sol.licitat

-
+

Mentre s'intentava llegir la URN: %U Index: squid/errors/Catalan/ERR_WRITE_ERROR diff -u squid/errors/Catalan/ERR_WRITE_ERROR:1.5 squid/errors/Catalan/ERR_WRITE_ERROR:1.5.6.1 --- squid/errors/Catalan/ERR_WRITE_ERROR:1.5 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_WRITE_ERROR Tue Sep 3 10:39:23 2002 @@ -1,11 +1,9 @@ - - -ERROR: No es pot mostrar la URL que heu sol.licitat - + +TITLE>ERROR: No es pot mostrar la URL que heu sol.licitat

ERROR

No es pot mostrar la URL que heu sol.licitat

-
+

Mentre s'intentava llegir la URL: %U Index: squid/errors/Catalan/ERR_ZERO_SIZE_OBJECT diff -u squid/errors/Catalan/ERR_ZERO_SIZE_OBJECT:1.4 squid/errors/Catalan/ERR_ZERO_SIZE_OBJECT:1.4.6.1 --- squid/errors/Catalan/ERR_ZERO_SIZE_OBJECT:1.4 Wed Aug 28 14:45:33 2002 +++ squid/errors/Catalan/ERR_ZERO_SIZE_OBJECT Tue Sep 3 10:39:23 2002 @@ -1,11 +1,9 @@ - - + ERROR: No es pot mostrar la URL que heu sol.licitat -

ERROR

No es pot mostrar la URL que heu sol.licitat

-
+

Mentre s'intentava llegir la URL: %U Index: squid/errors/Catalan/generic diff -u squid/errors/Catalan/generic:1.2 squid/errors/Catalan/generic:1.2.10.1 --- squid/errors/Catalan/generic:1.2 Thu Jul 18 17:00:42 2002 +++ squid/errors/Catalan/generic Tue Sep 3 10:39:24 2002 @@ -1,11 +1,9 @@ - ERROR: No es pot mostrar la URL que heu sol.licitat -

ERROR

No es pot mostrar la URL que heu sol.licitat

-
+

Mentre s'intentava llegir la URL:: %U Index: squid/errors/Czech/ERR_CONFLICT diff -u /dev/null squid/errors/Czech/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:35 2004 +++ squid/errors/Czech/ERR_CONFLICT Sat Dec 22 08:31:34 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +

ERROR

+

The requested URL could not be retrieved

+
+

+While trying to retrieve the URL: +%U +

+The following error was encountered: +

    +
  • + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+ +

+This means that: +

+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+
+

+ Index: squid/errors/Danish/ERR_CONFLICT diff -u /dev/null squid/errors/Danish/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:35 2004 +++ squid/errors/Danish/ERR_CONFLICT Sat Dec 22 08:31:34 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +

ERROR

+

The requested URL could not be retrieved

+
+

+While trying to retrieve the URL: +%U +

+The following error was encountered: +

    +
  • + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+ +

+This means that: +

+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+
+

+ Index: squid/errors/Dutch/ERR_CONFLICT diff -u /dev/null squid/errors/Dutch/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:35 2004 +++ squid/errors/Dutch/ERR_CONFLICT Sat Dec 22 08:31:34 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +

ERROR

+

The requested URL could not be retrieved

+
+

+While trying to retrieve the URL: +%U +

+The following error was encountered: +

    +
  • + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+ +

+This means that: +

+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+
+

+ Index: squid/errors/English/ERR_CONFLICT diff -u /dev/null squid/errors/English/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:35 2004 +++ squid/errors/English/ERR_CONFLICT Sat Dec 22 08:31:34 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +

ERROR

+

The requested URL could not be retrieved

+
+

+While trying to retrieve the URL: +%U +

+The following error was encountered: +

    +
  • + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+ +

+This means that: +

+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+
+

+ Index: squid/errors/Estonian/ERR_CONFLICT diff -u /dev/null squid/errors/Estonian/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:35 2004 +++ squid/errors/Estonian/ERR_CONFLICT Sat Dec 22 08:31:34 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +

ERROR

+

The requested URL could not be retrieved

+
+

+While trying to retrieve the URL: +%U +

+The following error was encountered: +

    +
  • + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+ +

+This means that: +

+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+
+

+ Index: squid/errors/Finnish/ERR_CONFLICT diff -u /dev/null squid/errors/Finnish/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:35 2004 +++ squid/errors/Finnish/ERR_CONFLICT Sat Dec 22 08:31:34 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +

ERROR

+

The requested URL could not be retrieved

+
+

+While trying to retrieve the URL: +%U +

+The following error was encountered: +

    +
  • + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+ +

+This means that: +

+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+
+

+ Index: squid/errors/French/ERR_CONFLICT diff -u /dev/null squid/errors/French/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:35 2004 +++ squid/errors/French/ERR_CONFLICT Sat Dec 22 08:31:34 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +

ERROR

+

The requested URL could not be retrieved

+
+

+While trying to retrieve the URL: +%U +

+The following error was encountered: +

    +
  • + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+ +

+This means that: +

+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+
+

+ Index: squid/errors/German/ERR_CONFLICT diff -u /dev/null squid/errors/German/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:35 2004 +++ squid/errors/German/ERR_CONFLICT Sat Dec 22 08:31:34 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +

ERROR

+

The requested URL could not be retrieved

+
+

+While trying to retrieve the URL: +%U +

+The following error was encountered: +

    +
  • + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+ +

+This means that: +

+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+
+

+ Index: squid/errors/Hebrew/ERR_ACCESS_DENIED diff -u squid/errors/Hebrew/ERR_ACCESS_DENIED:1.3 squid/errors/Hebrew/ERR_ACCESS_DENIED:1.3.6.1 --- squid/errors/Hebrew/ERR_ACCESS_DENIED:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_ACCESS_DENIED Tue Sep 3 10:39:55 2002 @@ -1,13 +1,11 @@ - ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -

ùâéàä

ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú

-
+

ëàùø ðéñéúé ìâùú àì äëúåáú: %U

Index: squid/errors/Hebrew/ERR_CACHE_ACCESS_DENIED diff -u squid/errors/Hebrew/ERR_CACHE_ACCESS_DENIED:1.3 squid/errors/Hebrew/ERR_CACHE_ACCESS_DENIED:1.3.6.1 --- squid/errors/Hebrew/ERR_CACHE_ACCESS_DENIED:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_CACHE_ACCESS_DENIED Tue Sep 3 10:39:55 2002 @@ -1,14 +1,12 @@ - ùâéàä: âéùä ìùøú ðãçéú -

ùâéàä

âéùä ìùøú ðãçéú

-
+

ëàùø ðéñéúé ìâùú àì äëúåáú: %U

Index: squid/errors/Hebrew/ERR_CACHE_MGR_ACCESS_DENIED diff -u squid/errors/Hebrew/ERR_CACHE_MGR_ACCESS_DENIED:1.3 squid/errors/Hebrew/ERR_CACHE_MGR_ACCESS_DENIED:1.3.6.1 --- squid/errors/Hebrew/ERR_CACHE_MGR_ACCESS_DENIED:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_CACHE_MGR_ACCESS_DENIED Tue Sep 3 10:39:56 2002 @@ -1,14 +1,12 @@ - ùâéàä: âéùú îðäì ìùøú ðãçéú -

ùâéàä

âéùú îðäì ìùøú ðãçéú

-
+

ëàùø ðéñéúé ìâùú àì äëúåáú: %U

Index: squid/errors/Hebrew/ERR_CANNOT_FORWARD diff -u squid/errors/Hebrew/ERR_CANNOT_FORWARD:1.3 squid/errors/Hebrew/ERR_CANNOT_FORWARD:1.3.6.1 --- squid/errors/Hebrew/ERR_CANNOT_FORWARD:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_CANNOT_FORWARD Tue Sep 3 10:39:56 2002 @@ -1,13 +1,11 @@ - ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -

ùâéàä

ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú

-
+

ëàùø ðéñéúé ìâùú àì äëúåáú: %U

Index: squid/errors/Hebrew/ERR_CONNECT_FAIL diff -u squid/errors/Hebrew/ERR_CONNECT_FAIL:1.3 squid/errors/Hebrew/ERR_CONNECT_FAIL:1.3.6.1 --- squid/errors/Hebrew/ERR_CONNECT_FAIL:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_CONNECT_FAIL Tue Sep 3 10:39:56 2002 @@ -1,13 +1,11 @@ - ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -

ùâéàä

ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú

-
+

ëàùø ðéñéúé ìâùú àì äëúåáú: %U

Index: squid/errors/Hebrew/ERR_DNS_FAIL diff -u squid/errors/Hebrew/ERR_DNS_FAIL:1.4 squid/errors/Hebrew/ERR_DNS_FAIL:1.4.6.1 --- squid/errors/Hebrew/ERR_DNS_FAIL:1.4 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_DNS_FAIL Tue Sep 3 10:39:57 2002 @@ -1,12 +1,10 @@ - ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -

ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú

-
+

ëàùø ðéñéúé ìâùú àì äëúåáú: %U

Index: squid/errors/Hebrew/ERR_FORWARDING_DENIED diff -u squid/errors/Hebrew/ERR_FORWARDING_DENIED:1.3 squid/errors/Hebrew/ERR_FORWARDING_DENIED:1.3.6.1 --- squid/errors/Hebrew/ERR_FORWARDING_DENIED:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_FORWARDING_DENIED Tue Sep 3 10:39:57 2002 @@ -1,13 +1,11 @@ - ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -

ùâéàä

ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú

-
+

ëàùø ðéñéúé ìâùú àì äëúåáú: %U

Index: squid/errors/Hebrew/ERR_FTP_DISABLED diff -u squid/errors/Hebrew/ERR_FTP_DISABLED:1.3 squid/errors/Hebrew/ERR_FTP_DISABLED:1.3.6.1 --- squid/errors/Hebrew/ERR_FTP_DISABLED:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_FTP_DISABLED Tue Sep 3 10:39:59 2002 @@ -1,13 +1,11 @@ - ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -

ùâéàä

ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú

-
+

ëàùø ðéñéúé ìâùú àì äëúåáú: %U

Index: squid/errors/Hebrew/ERR_FTP_FAILURE diff -u squid/errors/Hebrew/ERR_FTP_FAILURE:1.3 squid/errors/Hebrew/ERR_FTP_FAILURE:1.3.6.1 --- squid/errors/Hebrew/ERR_FTP_FAILURE:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_FTP_FAILURE Tue Sep 3 10:39:59 2002 @@ -1,13 +1,11 @@ - ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -

ùâéàä

ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú

-
+

÷øúä ùâéàú ôøåèå÷åì FTP ëàùø ðéñéúé ìâùú àì äëúåáú: %U Index: squid/errors/Hebrew/ERR_FTP_FORBIDDEN diff -u squid/errors/Hebrew/ERR_FTP_FORBIDDEN:1.3 squid/errors/Hebrew/ERR_FTP_FORBIDDEN:1.3.6.1 --- squid/errors/Hebrew/ERR_FTP_FORBIDDEN:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_FTP_FORBIDDEN Tue Sep 3 10:39:59 2002 @@ -1,13 +1,11 @@ - ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -

ùâéàä

ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú

-
+

ùâéàä áæéäåé îùúîù FTP ëàùø ðéñéúé ìâùú àì äëúåáú: %U Index: squid/errors/Hebrew/ERR_FTP_NOT_FOUND diff -u squid/errors/Hebrew/ERR_FTP_NOT_FOUND:1.3 squid/errors/Hebrew/ERR_FTP_NOT_FOUND:1.3.6.1 --- squid/errors/Hebrew/ERR_FTP_NOT_FOUND:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_FTP_NOT_FOUND Tue Sep 3 10:39:59 2002 @@ -1,13 +1,11 @@ - ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -

ùâéàä

ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú

-
+

ìà ðéúï ìâùú àì äëúåáú äð"ì: %U Index: squid/errors/Hebrew/ERR_FTP_PUT_CREATED diff -u squid/errors/Hebrew/ERR_FTP_PUT_CREATED:1.3 squid/errors/Hebrew/ERR_FTP_PUT_CREATED:1.3.6.1 --- squid/errors/Hebrew/ERR_FTP_PUT_CREATED:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_FTP_PUT_CREATED Tue Sep 3 10:39:59 2002 @@ -1,10 +1,8 @@ - ôòåìú FTP PUT òáøä áäöìçä: ä÷åáõ ðåöø -

ôòåìä òáøä áäöìçä

ä÷åáõ ðåöø

-
+
Index: squid/errors/Hebrew/ERR_FTP_PUT_ERROR diff -u squid/errors/Hebrew/ERR_FTP_PUT_ERROR:1.3 squid/errors/Hebrew/ERR_FTP_PUT_ERROR:1.3.6.1 --- squid/errors/Hebrew/ERR_FTP_PUT_ERROR:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_FTP_PUT_ERROR Tue Sep 3 10:39:59 2002 @@ -1,13 +1,11 @@ - ùâéàä: äòìàú ÷åáõ ì-FTP ðëùìä -

ùâéàä

äòìàú ÷åáõ ì-FTP ðëùìä

-
+

ùâéàä ëàùø ðéñéúé ìùìåç àú: %U Index: squid/errors/Hebrew/ERR_FTP_PUT_MODIFIED diff -u squid/errors/Hebrew/ERR_FTP_PUT_MODIFIED:1.3 squid/errors/Hebrew/ERR_FTP_PUT_MODIFIED:1.3.6.1 --- squid/errors/Hebrew/ERR_FTP_PUT_MODIFIED:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_FTP_PUT_MODIFIED Tue Sep 3 10:39:59 2002 @@ -1,10 +1,8 @@ - ôòåìú FTP PUT òáøä áäöìçä: ä÷åáõ òåãëï -

ôòåìä òáøä áäöìçä

ä÷åáõ òåãëï

-
+
Index: squid/errors/Hebrew/ERR_FTP_UNAVAILABLE diff -u squid/errors/Hebrew/ERR_FTP_UNAVAILABLE:1.3 squid/errors/Hebrew/ERR_FTP_UNAVAILABLE:1.3.6.1 --- squid/errors/Hebrew/ERR_FTP_UNAVAILABLE:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_FTP_UNAVAILABLE Tue Sep 3 10:39:59 2002 @@ -1,13 +1,11 @@ - ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -

ùâéàä

ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú

-
+

ùøú ä-FTP äéä òñå÷ îãé, ëàùø ðéñéúé ìâùú àì äëúåáú: %U

Index: squid/errors/Hebrew/ERR_INVALID_REQ diff -u squid/errors/Hebrew/ERR_INVALID_REQ:1.3 squid/errors/Hebrew/ERR_INVALID_REQ:1.3.6.1 --- squid/errors/Hebrew/ERR_INVALID_REQ:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_INVALID_REQ Tue Sep 3 10:39:59 2002 @@ -1,13 +1,11 @@ - ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -

ùâéàä

ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú

-
+

ëàùø ðéñéúé ìòáã àú äá÷ùä:

Index: squid/errors/Hebrew/ERR_INVALID_URL
diff -u squid/errors/Hebrew/ERR_INVALID_URL:1.3 squid/errors/Hebrew/ERR_INVALID_URL:1.3.6.1
--- squid/errors/Hebrew/ERR_INVALID_URL:1.3	Tue Aug 27 14:45:49 2002
+++ squid/errors/Hebrew/ERR_INVALID_URL	Tue Sep  3 10:39:59 2002
@@ -1,13 +1,11 @@
-
 
 
 ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä
-
 
 

ùâéàä

ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú

-
+

ëàùø ðéñéúé ìâùú àì äëúåáú: %U

Index: squid/errors/Hebrew/ERR_LIFETIME_EXP diff -u squid/errors/Hebrew/ERR_LIFETIME_EXP:1.3 squid/errors/Hebrew/ERR_LIFETIME_EXP:1.3.6.1 --- squid/errors/Hebrew/ERR_LIFETIME_EXP:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_LIFETIME_EXP Tue Sep 3 10:39:59 2002 @@ -1,13 +1,11 @@ - ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -

ùâéàä

ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú

-
+

ëàùø ðéñéúé ìâùú àì äëúåáú: %U

Index: squid/errors/Hebrew/ERR_NO_RELAY diff -u squid/errors/Hebrew/ERR_NO_RELAY:1.3 squid/errors/Hebrew/ERR_NO_RELAY:1.3.6.1 --- squid/errors/Hebrew/ERR_NO_RELAY:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_NO_RELAY Tue Sep 3 10:39:59 2002 @@ -1,13 +1,11 @@ - ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -

ùâéàä

ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú

-
+

ëàùø ðéñéúé ìâùú àì äëúåáú: %U

Index: squid/errors/Hebrew/ERR_ONLY_IF_CACHED_MISS diff -u squid/errors/Hebrew/ERR_ONLY_IF_CACHED_MISS:1.3 squid/errors/Hebrew/ERR_ONLY_IF_CACHED_MISS:1.3.6.1 --- squid/errors/Hebrew/ERR_ONLY_IF_CACHED_MISS:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_ONLY_IF_CACHED_MISS Tue Sep 3 10:39:59 2002 @@ -1,13 +1,11 @@ - ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -

ùâéàä

ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú

-
+

ëàùø ðéñéúé ìâùú àì äëúåáú: %U

Index: squid/errors/Hebrew/ERR_READ_ERROR diff -u squid/errors/Hebrew/ERR_READ_ERROR:1.3 squid/errors/Hebrew/ERR_READ_ERROR:1.3.6.1 --- squid/errors/Hebrew/ERR_READ_ERROR:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_READ_ERROR Tue Sep 3 10:39:59 2002 @@ -1,13 +1,11 @@ - ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -

ùâéàä

ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú

-
+

ëàùø ðéñéúé ìâùú àì äëúåáú: %U

Index: squid/errors/Hebrew/ERR_READ_TIMEOUT diff -u squid/errors/Hebrew/ERR_READ_TIMEOUT:1.3 squid/errors/Hebrew/ERR_READ_TIMEOUT:1.3.6.1 --- squid/errors/Hebrew/ERR_READ_TIMEOUT:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_READ_TIMEOUT Tue Sep 3 10:39:59 2002 @@ -1,13 +1,11 @@ - ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -

ùâéàä

ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú

-
+

ëàùø ðéñéúé ìâùú àì äëúåáú: %U

Index: squid/errors/Hebrew/ERR_SHUTTING_DOWN diff -u squid/errors/Hebrew/ERR_SHUTTING_DOWN:1.3 squid/errors/Hebrew/ERR_SHUTTING_DOWN:1.3.6.1 --- squid/errors/Hebrew/ERR_SHUTTING_DOWN:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_SHUTTING_DOWN Tue Sep 3 10:39:59 2002 @@ -1,13 +1,11 @@ - ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -

ùâéàä

ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú

-
+

ëàùø ðéñéúé ìâùú àì äëúåáú: %U

Index: squid/errors/Hebrew/ERR_SOCKET_FAILURE diff -u squid/errors/Hebrew/ERR_SOCKET_FAILURE:1.3 squid/errors/Hebrew/ERR_SOCKET_FAILURE:1.3.6.1 --- squid/errors/Hebrew/ERR_SOCKET_FAILURE:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_SOCKET_FAILURE Tue Sep 3 10:39:59 2002 @@ -1,13 +1,11 @@ - ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -

ùâéàä

ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú

-
+

ëàùø ðéñéúé ìâùú àì äëúåáú: %U

Index: squid/errors/Hebrew/ERR_TOO_BIG diff -u squid/errors/Hebrew/ERR_TOO_BIG:1.3 squid/errors/Hebrew/ERR_TOO_BIG:1.3.6.1 --- squid/errors/Hebrew/ERR_TOO_BIG:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_TOO_BIG Tue Sep 3 10:40:00 2002 @@ -1,13 +1,11 @@ - ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -

ùâéàä

ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú

-
+

ëàùø ðéñéúé ìâùú àì äëúåáú: %U

Index: squid/errors/Hebrew/ERR_UNSUP_REQ diff -u squid/errors/Hebrew/ERR_UNSUP_REQ:1.3 squid/errors/Hebrew/ERR_UNSUP_REQ:1.3.6.1 --- squid/errors/Hebrew/ERR_UNSUP_REQ:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_UNSUP_REQ Tue Sep 3 10:40:00 2002 @@ -1,13 +1,11 @@ - ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -

ùâéàä

ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú

-
+

ëàùø ðéñéúé ìâùú àì äëúåáú: %U

Index: squid/errors/Hebrew/ERR_URN_RESOLVE diff -u squid/errors/Hebrew/ERR_URN_RESOLVE:1.3 squid/errors/Hebrew/ERR_URN_RESOLVE:1.3.6.1 --- squid/errors/Hebrew/ERR_URN_RESOLVE:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_URN_RESOLVE Tue Sep 3 10:40:00 2002 @@ -1,13 +1,11 @@ - ERROR: The requested URN not be retrieved -

ùâéàä

A URL for the requested URN could not be retrieved

-
+

While trying to retrieve the URN: %U Index: squid/errors/Hebrew/ERR_WRITE_ERROR diff -u squid/errors/Hebrew/ERR_WRITE_ERROR:1.3 squid/errors/Hebrew/ERR_WRITE_ERROR:1.3.6.1 --- squid/errors/Hebrew/ERR_WRITE_ERROR:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_WRITE_ERROR Tue Sep 3 10:40:00 2002 @@ -1,13 +1,11 @@ - ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -

ùâéàä

ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú

-
+

ëàùø ðéñéúé ìâùú àì äëúåáú: %U

Index: squid/errors/Hebrew/ERR_ZERO_SIZE_OBJECT diff -u squid/errors/Hebrew/ERR_ZERO_SIZE_OBJECT:1.3 squid/errors/Hebrew/ERR_ZERO_SIZE_OBJECT:1.3.6.1 --- squid/errors/Hebrew/ERR_ZERO_SIZE_OBJECT:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_ZERO_SIZE_OBJECT Tue Sep 3 10:40:00 2002 @@ -1,13 +1,11 @@ - ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -

ùâéàä

ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú

-
+

ëàùø ðéñéúé ìâùú àì äëúåáú: %U

Index: squid/errors/Hungarian/ERR_CONFLICT diff -u /dev/null squid/errors/Hungarian/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:35 2004 +++ squid/errors/Hungarian/ERR_CONFLICT Sat Dec 22 08:31:34 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +

ERROR

+

The requested URL could not be retrieved

+
+

+While trying to retrieve the URL: +%U +

+The following error was encountered: +

    +
  • + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+ +

+This means that: +

+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+
+

+ Index: squid/errors/Italian/ERR_CONFLICT diff -u /dev/null squid/errors/Italian/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:35 2004 +++ squid/errors/Italian/ERR_CONFLICT Sat Dec 22 08:31:34 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +

ERROR

+

The requested URL could not be retrieved

+
+

+While trying to retrieve the URL: +%U +

+The following error was encountered: +

    +
  • + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+ +

+This means that: +

+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+
+

+ Index: squid/errors/Japanese/ERR_CONFLICT diff -u /dev/null squid/errors/Japanese/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Japanese/ERR_CONFLICT Sat Dec 22 08:31:34 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +

ERROR

+

The requested URL could not be retrieved

+
+

+While trying to retrieve the URL: +%U +

+The following error was encountered: +

    +
  • + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+ +

+This means that: +

+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+
+

+ Index: squid/errors/Korean/ERR_CONFLICT diff -u /dev/null squid/errors/Korean/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Korean/ERR_CONFLICT Sat Dec 22 08:31:35 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +

ERROR

+

The requested URL could not be retrieved

+
+

+While trying to retrieve the URL: +%U +

+The following error was encountered: +

    +
  • + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+ +

+This means that: +

+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+
+

+ Index: squid/errors/Polish/ERR_CONFLICT diff -u /dev/null squid/errors/Polish/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Polish/ERR_CONFLICT Sat Dec 22 08:31:35 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +

ERROR

+

The requested URL could not be retrieved

+
+

+While trying to retrieve the URL: +%U +

+The following error was encountered: +

    +
  • + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+ +

+This means that: +

+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+
+

+ Index: squid/errors/Portuguese/ERR_CONFLICT diff -u /dev/null squid/errors/Portuguese/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Portuguese/ERR_CONFLICT Sat Dec 22 08:31:35 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +

ERROR

+

The requested URL could not be retrieved

+
+

+While trying to retrieve the URL: +%U +

+The following error was encountered: +

    +
  • + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+ +

+This means that: +

+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+
+

+ Index: squid/errors/Romanian/ERR_CONFLICT diff -u /dev/null squid/errors/Romanian/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Romanian/ERR_CONFLICT Sat Dec 22 08:31:35 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +

ERROR

+

The requested URL could not be retrieved

+
+

+While trying to retrieve the URL: +%U +

+The following error was encountered: +

    +
  • + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+ +

+This means that: +

+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+
+

+ Index: squid/errors/Russian-1251/ERR_CONFLICT diff -u /dev/null squid/errors/Russian-1251/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Russian-1251/ERR_CONFLICT Sat Dec 22 08:31:35 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +

ERROR

+

The requested URL could not be retrieved

+
+

+While trying to retrieve the URL: +%U +

+The following error was encountered: +

    +
  • + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+ +

+This means that: +

+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+
+

+ Index: squid/errors/Russian-koi8-r/ERR_CONFLICT diff -u /dev/null squid/errors/Russian-koi8-r/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Russian-koi8-r/ERR_CONFLICT Sat Dec 22 08:31:35 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +

ERROR

+

The requested URL could not be retrieved

+
+

+While trying to retrieve the URL: +%U +

+The following error was encountered: +

    +
  • + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+ +

+This means that: +

+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+
+

+ Index: squid/errors/Serbian/ERR_CONFLICT diff -u /dev/null squid/errors/Serbian/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Serbian/ERR_CONFLICT Sat Dec 22 08:31:35 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +

ERROR

+

The requested URL could not be retrieved

+
+

+While trying to retrieve the URL: +%U +

+The following error was encountered: +

    +
  • + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+ +

+This means that: +

+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+
+

+ Index: squid/errors/Simplify_Chinese/ERR_CONFLICT diff -u /dev/null squid/errors/Simplify_Chinese/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Simplify_Chinese/ERR_CONFLICT Sat Dec 22 08:31:35 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +

ERROR

+

The requested URL could not be retrieved

+
+

+While trying to retrieve the URL: +%U +

+The following error was encountered: +

    +
  • + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+ +

+This means that: +

+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+
+

+ Index: squid/errors/Slovak/ERR_CONFLICT diff -u /dev/null squid/errors/Slovak/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Slovak/ERR_CONFLICT Sat Dec 22 08:31:35 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +

ERROR

+

The requested URL could not be retrieved

+
+

+While trying to retrieve the URL: +%U +

+The following error was encountered: +

    +
  • + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+ +

+This means that: +

+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+
+

+ Index: squid/errors/Spanish/ERR_CONFLICT diff -u /dev/null squid/errors/Spanish/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Spanish/ERR_CONFLICT Sat Dec 22 08:31:35 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +

ERROR

+

The requested URL could not be retrieved

+
+

+While trying to retrieve the URL: +%U +

+The following error was encountered: +

    +
  • + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+ +

+This means that: +

+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+
+

+ Index: squid/errors/Swedish/ERR_CONFLICT diff -u /dev/null squid/errors/Swedish/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Swedish/ERR_CONFLICT Sat Dec 22 08:31:35 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +

ERROR

+

The requested URL could not be retrieved

+
+

+While trying to retrieve the URL: +%U +

+The following error was encountered: +

    +
  • + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+ +

+This means that: +

+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+
+

+ Index: squid/errors/Traditional_Chinese/ERR_CONFLICT diff -u /dev/null squid/errors/Traditional_Chinese/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Traditional_Chinese/ERR_CONFLICT Sat Dec 22 08:31:35 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +

ERROR

+

The requested URL could not be retrieved

+
+

+While trying to retrieve the URL: +%U +

+The following error was encountered: +

    +
  • + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+ +

+This means that: +

+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+
+

+ Index: squid/errors/Turkish/ERR_CONFLICT diff -u /dev/null squid/errors/Turkish/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Turkish/ERR_CONFLICT Sat Dec 22 08:31:36 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +

ERROR

+

The requested URL could not be retrieved

+
+

+While trying to retrieve the URL: +%U +

+The following error was encountered: +

    +
  • + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+ +

+This means that: +

+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has.  Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere, 
+or your client push software is computing Last-Modified time incorrectly.
+
+

+ Index: squid/lib/MemPool.c diff -u squid/lib/MemPool.c:1.7 squid/lib/MemPool.c:1.1.46.1 --- squid/lib/MemPool.c:1.7 Fri Aug 9 14:46:00 2002 +++ squid/lib/MemPool.c Tue Sep 3 10:41:24 2002 @@ -80,13 +80,12 @@ * Andres Kroonmaa. */ -#include "config.h" - #define FLUSH_LIMIT 1000 /* Flush memPool counters to memMeters after flush limit calls */ #define MEM_MAX_MMAP_CHUNKS 2048 #include +#include "config.h" #if HAVE_STRING_H #include #endif Index: squid/src/HintCache.c diff -u /dev/null squid/src/HintCache.c:1.1.2.2 --- /dev/null Mon Jan 26 04:57:38 2004 +++ squid/src/HintCache.c Mon May 20 19:46:41 2002 @@ -0,0 +1,460 @@ +/* + * $Date: 2004/08/17 20:55:13 $ $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ + * + * AUTHOR: Mike Dahlin, UT Austin, 1998 + * DEBUG: section 84 Hint cache to Squid interface. + * + * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ + * -------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from the + * Internet community. Development is led by Duane Wessels of the + * National Laboratory for Applied Network Research and funded by + * the National Science Foundation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +/* + *------------------------------------------------------------------ + * LESS Group + * Computer Sciences Department + * University of Texas at Austin + * + * HintCache.c --- High-level interface to hint cache. + *------------------------------------------------------------------ + */ + +#include "squid.h" + +static EVH hintCacheTimer; /* timeout to flush StoreEntries */ + +#define HINT_CACHE_DEBUG 84 + +/* + * Globals + */ +#if USE_DYNAMIC_HIERARCHY +HintCacheNet *parentOutgoingA = NULL; +HintCacheNet *childrenOutgoingA = NULL; +HintCacheNet *neighborsOutgoing = NULL; +#endif +HintCacheDisk *hcDisk = NULL; + + +/* + *------------------------------------------------------------------ + * + * hintCacheInit -- + * + * description. + * + * Results: + * Return nonzero on error. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +int +hintCacheInit() +{ + peer *e; +#if USE_DYNAMIC_HIERARCHY + int ii; +#endif + + hcDisk = (HintCacheDisk *) xmalloc(sizeof(HintCacheDisk)); + assert(hcDisk); + hintCacheDiskInit(hcDisk, Config.Hints.cache_file); + +#if USE_DYNAMIC_HIERARCHY + /* + * Three sets of network buffers. Children and parents + * are the children and parents as determined by the + * dynamic hierarchy algorithm (HCHier.h). Neighbors + * are static squid neighbors (neighbors.h). The + * static neighbors are used to bootstrap the + * dynamic algorithm. + */ + neighborsOutgoing = (HintCacheNet *) xmalloc(sizeof(HintCacheNet)); + assert(neighborsOutgoing); + hintCacheNetInit(neighborsOutgoing); + hintCacheHierInit(); + + childrenOutgoingA = + (HintCacheNet *) xmalloc(sizeof(HintCacheNet) * + hintCacheHier_NChildrenQs()); + assert(childrenOutgoingA); + for (ii = 0; ii < hintCacheHierNChildrenQs(); ii++) { + hintCacheNet_Init(&childrenOutgoingA[ii]); + } + parentOutgoingA = + (HintCacheNet *) xmalloc(sizeof(HintCacheNet) * + hintCacheHier_NParentQs()); + assert(parentOutgoingA); + for (ii = 0; ii < hintCacheHierNParentQs(); ii++) { + hintCacheNetInit(&parentOutgoingA[ii]); + } +#else + for (e = getFirstPeer(); e; e = getNextPeer(e)) + hintCacheNetInit(&e->hcoutq); +#endif + + /* Start hint timer */ + eventAdd("hint timer", hintCacheTimer, NULL, + (double) (squid_random() % Config.Hints.intvl), 1); + + return 0; +} + +/* + *------------------------------------------------------------------ + * + * hintCacheDestroy -- + * + * Shut down. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +void +hintCacheDestroy() +{ +#if USE_DYNAMIC_HIERARCHY + int ii; + + for (ii = 0; ii < hintCacheHier_NChildrenQs(); ii++) { + hintCacheNetDestroy(&childrenOutgoingA[ii]); + } + xfree(childrenOutgoingA); + childrenOutgoingA = NULL; + for (ii = 0; ii < hintCacheHier_NParentQs(); ii++) { + hintCacheNetDestroy(&parentOutgoingA[ii]); + } + xfree(parentOutgoingA); + parentOutgoingA = NULL; + hintCacheNetDestroy(neighborsOutgoing); + xfree(neighborsOutgoing); + neighborsOutgoing = NULL; +#endif + + hintCacheHierDestroy(); + + hintCacheDiskClose(hcDisk); + xfree(hcDisk); + hcDisk = NULL; +} + +/* + *------------------------------------------------------------------ + * + * hintCacheCreate -- + * + * Create a NEW disk cache (obliterating the one + * already on disk, if any). Then do normal initialization. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +void +hintCacheCreate(void) +{ + if (access(Config.Hints.cache_file, R_OK | W_OK) == -1) + hintCacheDiskCreateFile(Config.Hints.cache_file, Config.Hints.size, + Config.Hints.assoc); + + hintCacheInit(); +} + +/* + *------------------------------------------------------------------ + * + * hintCacheinformLocalCopy -- + * + * description. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +void +hintCacheInformLocalCopy(StoreEntry * entry) +{ + char *url = entry->mem_obj->url; + struct sockaddr_in *me; + HintCacheEntry myentry; + URLKey *key; + HintCacheUpdate update; + + debug(HINT_CACHE_DEBUG, 5) ("hintCacheinformLocalCopy: got %s\n", + url); + + if (!HINT_CACHE_ACTIVE()) { + /* Hint cache is inoperative. Nothing to do. */ + return; + } + + if (strstr(url, "//updates")) + /* Routes handle their own updates */ + return; + + me = &Config.Sockaddr.http->s; + + /* Prepare data structures */ + key = HINT_CACHE_KEY(entry); + hintCacheEntryInit(&myentry, *key, me, entry->lastmod); + hintCacheUpdateInit(&update, HC_InformToParent, &myentry, 0); + + /* + * Update local and remote hint caches. + */ + hintCachePropHandleInformToParent(&update, me, 1); + update.action = HC_InformToChild; + hintCachePropHandleInformToChild(&update, me, 1); +} + +void +hintCacheInvalLocalCopy(StoreEntry * entry) +{ + struct sockaddr_in *me; + HintCacheEntry myentry; + HintCacheUpdate update; + + if (!HINT_CACHE_ACTIVE()) { + /* Hint cache is inoperative. Nothing to do. */ + return; + } + + me = &Config.Sockaddr.http->s; + + /* Prepare data structures */ + hintCacheEntryInit(&myentry, *HINT_CACHE_KEY(entry), + me, entry->lastmod); + hintCacheUpdateInit(&update, HC_InvalToParent, &myentry, 0); + + /* + * Update local and remote hint caches. + */ + hintCacheHandleInvalToParent(&update, me, 1); + update.action = HC_InvalToChild; + hintCachePropHandleInvalToChild(&update, me, 1); + + debug(HINT_CACHE_DEBUG, 5) ("hintCacheinvalLocalCopy: lost 0x%qx\n", + ((URLKey *) &entry->hchash.key)->key); +} + + +/* + *------------------------------------------------------------------ + * + * hintCachefindNearest -- + * + * Find the nearest copy of the specified URL. + * Return a copy of the location in *saddr. + * Return the saddr pointer if we found a copy + * or return NULL if no copy found. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------3.24.1998----------- + */ +struct sockaddr_in * +hintCacheFindNearest(StoreEntry *entry, struct sockaddr_in *saddr) +{ + const struct sockaddr_in *me; + URLKey *urlKey; + HintCacheEntry nearest; + int found; + + if (!HINT_CACHE_ACTIVE()) { + /* Hint cache is inoperative. Nothing to do. */ + return (NULL); + } + + urlKey = HINT_CACHE_KEY(entry); + found = hintCacheDiskFindNearest(hcDisk, *urlKey, &nearest); + if (!found) + return NULL; + + saddr->sin_family = AF_INET; + saddr->sin_port = nearest.port; + saddr->sin_addr = nearest.ipaddr; + + /* Never return ourselves. */ + me = &Config.Sockaddr.http->s; + if (saddr->sin_port == me->sin_port) { + if (saddr->sin_addr.s_addr == me->sin_addr.s_addr) + return NULL; + if (saddr->sin_addr.s_addr == 0x7f000000) + return NULL; + } +#if 0 /* Fixed? */ + /* XXX - shouldn't be needed, but is - noted in BUGS */ + /* Swap bytes to host format. */ + saddr->sin_addr.s_addr = ntohl(saddr->sin_addr.s_addr); + saddr->sin_port = ntohs(saddr->sin_port); +#endif + debug(HINT_CACHE_DEBUG, 5) ("hintCachefindNearest: %s is at <%s,%d>\n", + entry->mem_obj->url, inet_ntoa(saddr->sin_addr), saddr->sin_port); + return (saddr); +} + + +/* + *------------------------------------------------------------------ + * + * hintCacheTimer -- + * + * This gets called every so often. Its job is + * to flush outgoing messages. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +static void +hintCacheTimer(void *junk) +{ + struct sockaddr_in sin; +#if USE_DYNAMIC_HIERARCHY + struct sockaddr_in *childSinA = NULL; + static int nextjoin = 0; + int nchildren, ichild; + int error; + int ii; +#else + peer *e; +#endif + + /* Reload timer */ + eventAdd("hint timer", hintCacheTimer, NULL, + (double) (squid_random() % Config.Hints.intvl), 1); + +#if USE_DYNAMIC_HIERARCHY + /* Process peers */ + /* Send enqueued updates */ + if (parentOutgoingA != NULL) { + for (ii = 0; ii < hintCacheHier_NParentQs(); ii++) { + if (hintCacheNetBytesReady(&parentOutgoingA[ii]) > + sizeof(HintCacheNetHeader)) { + hintCacheNetComplete(&parentOutgoingA[ii]); + error = hintCacheHierGetParentAddr(ii, &sin); + debug(HINT_CACHE_DEBUG, 6) + ("Sending %d bytes from parentOutgoing[%d] to %s %s\n", + hintCacheNetbytesReady(&parentOutgoingA[ii]), ii, + inet_ntoa(sin.sin_addr), error ? "ERROR" : ""); + if (!error) { + hintCacheNetSendTo(&parentOutgoingA[ii], &sin); + } + hintCacheNetDone(&parentOutgoingA[ii]); + } + } + } + if (childrenOutgoingA != NULL) { + for (ii = 0; ii < hintCacheHierNChildrenQs(); ii++) { + if (hintCacheNet_bytesReady(&childrenOutgoingA[ii]) > + sizeof(HintCacheNetHeader)) { + hintCacheNetComplete(&childrenOutgoingA[ii]); + nchildren = hintCacheHierGetChildAddrs(ii, &childSinA); + debug(HINT_CACHE_DEBUG, 6) + ("Sending %d bytes to %d children from childrenOutgoing[%d]:", + hintCacheNetBytesReady(&childrenOutgoingA[ii]), nchildren, + ii); + + for (ichild = 0; ichild < nchildren; ichild++) { + debug(HINT_CACHE_DEBUG, 8) (" %s ", + inet_ntoa(childSinA[ichild].sin_addr)); + hintCacheNetSendTo(&childrenOutgoingA[ii], + &childSinA[ichild]); + } + + hintCacheNetDone(&childrenOutgoingA[ii]); + xfree(childSinA); + } + } + } +#else + for (e = getFirstPeer(); e; e = getNextPeer(e)) { + if (hintCacheNetBytesReady(&e->hcoutq) > sizeof(HintCacheNetHeader)) { + hintCacheNetComplete(&e->hcoutq); + sin.sin_addr = e->in_addr.sin_addr; + sin.sin_port = e->http_port; + hintCacheNetSendTo(&e->hcoutq, &sin); + hintCacheNetDone(&e->hcoutq); + } + } +#endif /* USE_DYNAMIC_HIERARCHY */ + + +#if USE_DYNAMIC_HIERARCHY + /* + * Send out Joins once every few hours. + */ + if (hintCacheNodelistMyStatus() == HC_Join) { + if (squid_curtime >= nextjoin) { + hintCacheNodelistLocalJoin(); + nextjoin = + squid_curtime + (squid_random() % Config.Hints.join_intvl); + } + } +#endif + +#ifdef DOTEST + if (0) { /* XXX */ + if (!hintCacheHierSelfTestDone) { + hintCacheHierTestNetwork(); + } + } +#endif +} Index: squid/src/HintCacheDisk.c diff -u /dev/null squid/src/HintCacheDisk.c:1.1.2.2 --- /dev/null Mon Jan 26 04:57:38 2004 +++ squid/src/HintCacheDisk.c Mon May 20 19:46:41 2002 @@ -0,0 +1,817 @@ +/* + * $Date: 2004/08/17 20:55:13 $ $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ + * + * AUTHOR: Mike Dahlin, UT Austin, 1998 + * DEBUG: section 82 On-disk hint cache + * + * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ + * -------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from the + * Internet community. Development is led by Duane Wessels of the + * National Laboratory for Applied Network Research and funded by + * the National Science Foundation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +/* + *------------------------------------------------------------------ + * + * LESS Group + * Computer Sciences Department + * University of Texas at Austin + * + * HintCacheDisk --- + * The on-disk cache of hints. The key data structure + * is an mmapped array which is treated as a - + * associative cache. + * + *------------------------------------------------------------------ + */ +#include "squid.h" + +#define HCDISK_DEBUG 82 + +#define BIG_ENOUGH 1024 + +static const char *suffix = ".hints"; + +static int readLine(int fd, char *buffer, int max); +static void initializeFile(int dataFD, int nbuckets, int associativity); +static int findKey(HintCacheDisk * d, int b, URLKey key, + HintCacheDiskEntry * foundRet); +static int deleteKey(HintCacheDisk * d, int b, HintCacheDiskEntry * oldEntry, + HintCacheDiskEntry * survivingEntry); +static void insertKey(HintCacheDisk * d, int b, HintCacheDiskEntry * newEntry); +#ifdef MADV_RANDOM +static caddr_t pageAddr(caddr_t e); +#endif +static void sanityCheckMatch(HintCacheDisk * d, HintCacheDiskEntry * bucketp, + HintCacheDiskEntry * entry, int expectFullMatch, int expectKeyMatch); +static int bucket(HintCacheDisk * d, URLKey key); +static HintCacheDiskEntry *readBucket(HintCacheDisk * d, int b); +static int writeBucket(HintCacheDisk * d, int b, HintCacheDiskEntry * bucketp); +#ifdef DOTEST +static void timeMadvise(); +#endif + +static long pageSize; + +/* + * Should we try to keep stuff we just read or wrote in the cache. + */ +/* + * You may not want to cache writes since they may or may not + * be about stuff you will later read. On the other hand, there + * may be temporal locality about stuff that gets updated -- + * I may be likely to read or discard the object in the near + * future. Also, telling system to kick it out of cache costs + * about 1ms per call. + */ +static const int CACHE_RECENT_WRITES = 1; +/* + * You may not want to cache reads since these are things + * that you will now have in your cache (so why would + * you look at the hints any time soon. On the other hand, + * telling system to kick out reads costs about 1ms per call + */ +static const int CACHE_RECENT_READS = 0; +/* + * You may not want to prefetch at all (we can only prefetch + * on network updates, and those are not on critical + * path anywhere. Maybe better to sacrifice latency for + * reduced overhead. + * + * No point int trying to pipeline if there are not many + * updates to pipeline. Otherwise the overhead of the + * system calls outweighs the reduced latency for disk + * reads. In the best case, madvise (tight loop of madvise + * about same location), madvise appears to take about 1ms per call. + */ +static const int DO_PREFETCH = 0; + +/* HintCacheDisk constructor */ +void +hintCacheDiskInit(HintCacheDisk * d, char *diskPath) +{ + int header; + int dataF; + char buffer[BIG_ENOUGH], token[BIG_ENOUGH], dataFile[BIG_ENOUGH]; + int version; + int size, buckets, associativity; + int gotVersion = 0, gotData = 0, gotAssoc = 0, gotSize = 0, gotBuckets = 0; + + if ((pageSize = sysconf(_SC_PAGESIZE)) < 0) { + perror("Cannot determine page size\n"); + exit(-1); + } + + header = open(diskPath, O_RDONLY); + if (header < 0) { + debug(HCDISK_DEBUG, 1) + ("warning: Can\'t open %s, hint caching disabled\n", diskPath); + HCDisk = NULL; + return; + } + + while (readLine(header, buffer, BIG_ENOUGH)) { + if (buffer[0] != '#') { + sscanf(buffer, "%s", token); + if (!strcmp(token, "VERSION")) { + gotVersion = sscanf(buffer, "VERSION %d\n", &version); + assert(gotVersion == 1); + assert(version == HCD_VERSION); + } else if (!strcmp(token, "DATA_FILE")) { + gotData = sscanf(buffer, "DATA_FILE %s\n", dataFile); + assert(gotData == 1); + } else if (!strcmp(token, "SIZE_BYTES")) { + gotSize = sscanf(buffer, "SIZE_BYTES %d\n", &size); + assert(gotSize == 1); + } else if (!strcmp(token, "BUCKETS")) { + gotBuckets = sscanf(buffer, "BUCKETS %d\n", &buckets); + assert(gotBuckets == 1); + } else if (!strcmp(token, "ASSOCIATIVITY")) { + gotAssoc = sscanf(buffer, "ASSOCIATIVITY %d\n", &associativity); + assert(gotAssoc == 1); + } else { + /* Ignore what we don't understand */ + } + } + } + close(header); + assert(gotVersion && gotData && gotAssoc && gotSize && gotBuckets); + assert(size == buckets * associativity * sizeof(HintCacheDiskEntry)); + d->nbuckets = buckets; + d->entriesPerBucket = associativity; + dataF = open(dataFile, O_RDWR); + if (dataF < 0) { + debug(HCDISK_DEBUG, 1) + ("warning: Can\'t open %s, hint caching disabled\n", dataFile); + HCDisk = NULL; + return; + } + if (Config.onoff.hint_cache_use_mmap) { + d->mmappedArray = + (HintCacheDiskEntry *) mmap(0, size, PROT_READ | PROT_WRITE, + MAP_SHARED, dataF, 0); + if (!d->mmappedArray) { + debug(HCDISK_DEBUG, 1) + ("warning: Can\'t mmap %s, hint caching disabled\n", dataFile); + HCDisk = NULL; + return; + } +#ifdef MADV_RANDOM + if (madvise((char *) d->mmappedArray, size, MADV_RANDOM)) { + debug(HCDISK_DEBUG, 1) + ("warning: madvise on hint cache data failed"); + } +#endif + close(dataF); + d->fd = -1; + } else { + d->fd = dataF; + } +} + +/* + * Read one line of input from file. We really want + * to use fgets(), but the fopen() etc. routines + * don't work if you have large numbers of + * files open (60 or 255 are the max for some implementations). + * So, we use the basic open/read/close routines + * instead, which let us open up to the max number + * of allowed file descriptors. + * + * Store a line of text ending with \n\0 in buffer + * and return nonzero if we succeeded in getting + * a well-formed line. + */ +static int +readLine(int fd, char *buffer, int max) +{ + ssize_t got; + int count = 0; + + assert(buffer); + assert(fd >= 0); + assert(fd <= 10000); + assert(max > 2); /* need room for \n\0 */ + + while (count < max - 2) { + got = read(fd, &buffer[count], 1); + if (got != 1) { + return 0; + } + if (buffer[count] == '\n') { + buffer[count + 1] = '\0'; + return 1; + } + count++; + } + return 0; +} + +/* + * Does the hard work of setting up a new empty file. + * + * Note: we use raw open() and write() rather than + * fopen() and fwrite() because the f-routines + * get unhappy in programs that open lots of files + * (they often die if you have more than 60 or 255 + * files open, even if you are allowed to + * have more open file descriptors than that). + */ +void +hintCacheDiskCreateFile(char *hcPath, int size, int associativity) +{ + char *dataPath; + int buckets; + int headerF, dataF; + char buffer[BIG_ENOUGH]; + int len; + + len = strlen(hcPath); + dataPath = (char *) xmalloc(len + strlen(suffix) + 1); + assert(dataPath); + snprintf(dataPath, len, "%s%s", hcPath, suffix); + + buckets = (size / associativity) / sizeof(HintCacheDiskEntry); + assert(buckets * associativity * sizeof(HintCacheDiskEntry) <= size); + size = buckets * associativity * sizeof(HintCacheDiskEntry); + + headerF = open(hcPath, O_WRONLY | O_CREAT | O_TRUNC, 0744); + if (headerF < 0) { + perror("Opening Hint Cache header"); + exit(-1); + } + + snprintf(buffer, BIG_ENOUGH, + "# *** Header for hint cache. Do not modify ***\n"); + write(headerF, buffer, strlen(buffer)); + snprintf(buffer, BIG_ENOUGH, "VERSION %d\n", HCD_VERSION); + write(headerF, buffer, strlen(buffer)); + snprintf(buffer, BIG_ENOUGH, "DATA_FILE %s\n", dataPath); + write(headerF, buffer, strlen(buffer)); + snprintf(buffer, BIG_ENOUGH, "SIZE_BYTES %d\n", size); + write(headerF, buffer, strlen(buffer)); + snprintf(buffer, BIG_ENOUGH, "BUCKETS %d\n", buckets); + write(headerF, buffer, strlen(buffer)); + snprintf(buffer, BIG_ENOUGH, "ASSOCIATIVITY %d\n", associativity); + write(headerF, buffer, strlen(buffer)); + + close(headerF); + + /* Open data file */ + dataF = open(dataPath, O_WRONLY | O_CREAT | O_TRUNC, 0744); + if (dataF < 0) { + perror("Opening Hint Cache data"); + exit(-1); + } + + /* Need to pre-extend file to 'size' */ + lseek(dataF, size - 1, 0); + write(dataF, "\0", 1); + lseek(dataF, 0, 0); + + initializeFile(dataF, buckets, associativity); + close(dataF); + xfree(dataPath); +} + +/* Set a file to empty by invalidating all entries. */ +static void +initializeFile(int fd, int nbuckets, int associativity) +{ + HintCacheDiskEntry invalidEntry; + int ibucket, ientry; + int count; + + HCE_INVALIDATE(&invalidEntry.entry); + + for (ibucket = 0; ibucket < nbuckets; ibucket++) { + for (ientry = 0; ientry < associativity; ientry++) { + count = write(fd, &invalidEntry, sizeof(HintCacheDiskEntry)); + if (count != sizeof(HintCacheDiskEntry)) { + perror("ERROR Creating HintCacheCache file"); + exit(-1); + } + } + } +} + +/* Unmap the file. */ +void +hintCacheDiskClose(HintCacheDisk * d) +{ + munmap((char *) d->mmappedArray, d->nbuckets * d->entriesPerBucket); + d->mmappedArray = NULL; +} + +/* Update data structures to reflect the fact a copy is cached locally. */ +void +hintCacheDiskInformLocal(HintCacheDisk * d, URLKey key, unsigned mtime) +{ + int b; + HintCacheDiskEntry new, dummyRet, old; + int foundOld; + + assert(d); + + if (!URLKEY_COMPARE(key, INVALID_URL_KEY)) { + return; + } + + b = bucket(d, key); + foundOld = findKey(d, b, key, &old); + if (foundOld) { + /* Delete old instead of replace to support multiversioning */ + deleteKey(d, b, &old, &dummyRet); + } + hintCacheEntryInit(&new.entry, key, &Config.Sockaddr.http->s, mtime); + new.rtime = squid_curtime; + insertKey(d, b, &new); +#ifdef MADV_RANDOM + if (!CACHE_RECENT_WRITES) { + if (madvise(pageAddr((caddr_t) (d->mmappedArray + b)), + pageSize, MADV_DONTNEED)) { + debug(HCDISK_DEBUG, 1) ("madvise DONTNEED failed\n"); + } + } +#endif +} + + + +/* Update local data structures to reflect the fact + * that we no longer have a copy locally. */ +void +hintCacheDiskInvalLocal(HintCacheDisk * d, URLKey key, unsigned mtime) +{ + HintCacheDiskEntry myent, dummyRet; + int b; + + debug(HCDISK_DEBUG, 2) ("HintCacheDiskinvalLocalCopy: deleting %ll\n", + key.key); + + if (!URLKEY_COMPARE(key, INVALID_URL_KEY)) { + return; + } + + hintCacheEntryInit(&myent.entry, key, &Config.Sockaddr.http->s, mtime); + myent.rtime = squid_curtime; + b = bucket(d, key); + deleteKey(d, b, &myent, &dummyRet); +#ifdef MADV_RANDOM + if (Config.onoff.hint_cache_use_mmap) { + if (madvise(pageAddr((caddr_t) (d->mmappedArray + b)), + pageSize, MADV_DONTNEED)) { + debug(HCDISK_DEBUG, 1) ("Madvise DONTNEED failed\n"); + } + } +#endif +} + +/* Warn vm system that certain pages will be needed. These pages + * hold or will hold object mentioned in this hint update. */ +void +hintCacheDiskprefetch(HintCacheDisk * d, HintCacheUpdate * uArray, int nupdates) +{ +#ifdef MADV_RANDOM + int b; + int ii; + if (DO_PREFETCH && Config.onoff.hint_cache_use_mmap) { + for (ii = 0; ii < nupdates; ii++) { + if (uArray[ii].action == HC_InvalToParent || + uArray[ii].action == HC_InvalToChild || + uArray[ii].action == HC_InformToParent || + uArray[ii].action == HC_InformToChild) { + b = bucket(d, uArray[ii].entry.key); + if (madvise(pageAddr((caddr_t) (d->mmappedArray + b)), + pageSize, MADV_WILLNEED)) { + debug(HCDISK_DEBUG, 1) ("madvise WILLNEED failed\n"); + } + } + } + } +#endif +} + +/* + * The network told us that is + * no longer a valid mapping. If we knew of a + * different copy than the one that was invalidated + * then report that back by returning 1 and putting + * a copy of the survivor in survivor. + * + * The function takes HCEntrys as args rather than + * HintCacheDiskEntrys because it is called exclusively + * from outside HintCacheDisk.c. + */ +int +hintCacheDisknetInvalRecord(HintCacheDisk * d, + HintCacheEntry * entry, HintCacheEntry * survivor) +{ + HintCacheDiskEntry dentry, dsurv; + int remainingCopy; + int b; + + if (!HCE_VALID(entry)) { + survivor->key.key = 0; + return 0; + } + + dentry.entry = *entry; + dentry.rtime = squid_curtime; + + b = bucket(d, entry->key); + remainingCopy = deleteKey(d, b, &dentry, &dsurv); + *survivor = dsurv.entry; +#ifdef MADV_RANDOM + if (Config.onoff.hint_cache_use_mmap) + if (madvise(pageAddr((caddr_t) (d->mmappedArray + b)), + pageSize, MADV_DONTNEED)) { + debug(HCDISK_DEBUG, 1) ("madvise DONTNEED failed\n"); + } +#endif + + return remainingCopy; +} + +/* + * The network told us that is a valid + * mapping. Install it if it is better than the one + * we have. + * + * Takes HintCacheEntrys as args because it's exported. + */ +int +hintCacheDiskUpdateIfCloser(HintCacheDisk * d, HintCacheEntry * new) +{ + HintCacheDiskEntry old, dummyRet, dnew, *todelete; + URLKey key = new->key; + int dochange = 0; + StoreEntry *e; + int ret = 0; + int foundOld; + int b; + + if (!HCE_VALID(new)) { + return 0; + } + + dnew.entry = *new; + dnew.rtime = squid_curtime; + + b = bucket(d, key); + foundOld = findKey(d, b, key, &old); + if (!foundOld) { + insertKey(d, b, &dnew); + todelete = &dnew; + ret = 1; + } else + todelete = &old; + + e = hintCacheStoreGet(key); + if (e && e->lastmod < new->mtime) { + /* This hint is about a new version. Invalidate the old version */ + storeRelease(e); + dochange = 1; + } else if (foundOld && squid_curtime >= old.rtime + Config.Hints.holddown) { + /* Don't propagate hints about the same version more often + * that once every fifteen minutes. */ + dochange = 1; + } else if (hintCacheHierCompareDistance(new->ipaddr, old.entry.ipaddr) < 0) { + /* This hint is for cache closer than what we got */ + dochange = 1; + } + + if (dochange) { + deleteKey(d, b, todelete, &dummyRet); + insertKey(d, b, &dnew); + ret = 1; + } +#ifdef MADV_RANDOM + if (!CACHE_RECENT_WRITES && Config.onoff.hint_cache_use_mmap) { + if (madvise(pageAddr((caddr_t) (d->mmappedArray + b)), + pageSize, MADV_DONTNEED)) { + perror("Madvise DONTNEED failed\n"); + } + } +#endif + return ret; +} + +/* + * Find the record for the key if one exists. Return 1 + * if matching record found and a copy in *match. + * Return 0 if no match found. + * + * Note: we can't just return a pointer to match + * because its location in the bucket can change + * at any time. + * + * Takes HintCacheEntry as arg because it is exported. + */ +int +hintCacheDiskFindNearest(HintCacheDisk * d, URLKey key, HintCacheEntry * match) +{ + int b; + int found; + HintCacheDiskEntry dent; + + assert(match != 0); + if (!URLKEY_COMPARE(key, INVALID_URL_KEY)) { + return 0; + } + + b = bucket(d, key); + found = findKey(d, b, key, &dent); + if (found) + *match = dent.entry; +#ifdef MADV_RANDOM + if (!CACHE_RECENT_READS && Config.onoff.hint_cache_use_mmap) { + if (madvise(pageAddr((caddr_t) (d->mmappedArray + b)), + pageSize, MADV_DONTNEED)) { + perror("Madvise DONTNEED failed\n"); + } + } +#endif + return found; +} + + +/* Return pointer to first entry in bucket for key. */ +static int +bucket(HintCacheDisk * d, URLKey key) +{ + int b; + + b = key.key % d->nbuckets; + return b * d->entriesPerBucket; +} + +#ifdef MADV_RANDOM +/* + * Return the address of the first byte of the + * page that holds an address. + */ +static caddr_t +pageAddr(caddr_t e) +{ + caddr_t ret; + ret = e - ((unsigned) e % pageSize); + return ret; +} +#endif /* MADV_RANDOM */ + +/* + * Delete the record associated with the specified + * pair. + * + * If there is a record for the key that survives the + * delete (e.g. the node doesn't match) return it + * in the HintCacheEntry *surviver field and return 1. If + * no record for the key survives the delete, return 0. + * + * Note: we can't just return a pointer to survivor + * because its location in the bucket can change + * at any time. + */ +static int +deleteKey(HintCacheDisk * d, int b, HintCacheDiskEntry * entry, + HintCacheDiskEntry * survivor) +{ + HintCacheDiskEntry *bucketp = d->mmappedArray + b; + int ii; + + assert(survivor != NULL); + assert(entry != survivor); + assert(HintCacheE_VALID(&entry->entry)); + + bucketp = readBucket(d, b); + for (ii = 0; ii < d->entriesPerBucket; ii++) { + if (!URLKEY_COMPARE(bucketp[ii].entry.key, entry->entry.key)) { + if (!HCEntry_Compare(&entry->entry, &bucketp[ii].entry)) { + HCE_INVALIDATE(&bucketp[ii].entry); + sanityCheckMatch(d, bucketp, entry, 0, 0); + break; + } else { + /* + * Matched key but not NodeId. + */ + *survivor = bucketp[ii]; + sanityCheckMatch(d, bucketp, entry, 0, 1); + sanityCheckMatch(d, bucketp, survivor, 1, 1); + return 1; + } + } + } + writeBucket(d, b, bucketp); + /* + * No match key + */ + return 0; +} + + +/* + * Insert an entry in a given bucket in hash table. + * The table is n-way associative. The new entry + * is always inserted into entry 0, and the remaining + * entries are shifted up. If there is an empty + * entry, we don't have to shift any higher entries. + * If all entries are full, entry d->entriesPerBucket - 1 + * (the last entry) is lost. + */ +static void +insertKey(HintCacheDisk * d, int b, HintCacheDiskEntry * entry) +{ + HintCacheDiskEntry *bucketp; + int from, to; + + /* Get bucket */ + bucketp = readBucket(d, b); + + /* + * Caller responsible for deleting old entry before inserting + * a new one. + */ + sanityCheckMatch(d, bucketp, entry, 0, 0); + + /* + * First, see if there are any empty entries. All entries + * below the first empty one get shifted up to make + * room in entry 0. The last entry by definition is + * emtpy if all earlier ones are empty (you are always + * allowed to shift over the last entry.) + */ + for (to = 0; to < d->entriesPerBucket - 1; to++) { + if (!HCE_VALID(&bucketp[to].entry)) { + break; + } + } + assert(to <= d->entriesPerBucket - 1); + assert(!HCE_VALID(&bucketp[to].entry) || (to == d->entriesPerBucket - 1)); + + /* + * Shift entry up to entry to make entry 0 empty. + * The last bucket we shift is entry (from==entriesPerBucket-2) + * which shifts into the last bucket (entriesPerBucket-1). + * Don't go any farther, or we clobber the next bucket. + */ + for (; to > 0; to--) { + from = to - 1; + assert(from >= 0); + bucketp[to] = bucketp[from]; + } + bucketp[0] = *entry; + sanityCheckMatch(d, bucketp, entry, 1, 1); + writeBucket(d, b, bucketp); +} + +/* + * Check to see that the expected number of entries in bucket + * match specified key. + */ +static void +sanityCheckMatch(HintCacheDisk * d, HintCacheDiskEntry * bucketp, + HintCacheDiskEntry * entry, int expectFullMatch, int expectKeyMatch) +{ + int ii; + int fullMatch = 0, keyMatch = 0; + + for (ii = 0; ii < d->entriesPerBucket; ii++) { + if (!hintCacheEntryCompare(&bucketp[ii].entry, &entry->entry)) { + fullMatch++; + } + if (!URLKEY_COMPARE(bucketp[ii].entry.key, entry->entry.key)) { + keyMatch++; + } + } + assert(fullMatch == expectFullMatch); + assert(keyMatch == expectKeyMatch); +} + +/* + * Find an entry that matches the key. Return + * true if found and put the result in foundRet. + * Since this is a read, + * update the LRU list by removing key and + * then re-inserting key. + * + * Note: we can't just return a pointer to copy + * because its location in the bucket can change + * at any time. + */ +static int +findKey(HintCacheDisk * d, int b, URLKey key, HintCacheDiskEntry * copy) +{ + HintCacheDiskEntry *bucketp; + int ii; + + bucketp = readBucket(d, b); + assert(copy != NULL); + assert(copy < bucketp || copy > &bucketp[d->entriesPerBucket - 1]); + assert(URLKEY_COMPARE(key, INVALID_URL_KEY)); + for (ii = 0; ii < d->entriesPerBucket; ii++) { + if (!URLKEY_COMPARE(bucketp[ii].entry.key, key)) { + *copy = bucketp[ii]; + assert(!URLKEY_COMPARE(copy->entry.key, key)); + if (ii != 0) { + /* + * Move to front of LRU list by deleting entry and inserting + */ + HCE_INVALIDATE(&bucketp[ii].entry); + writeBucket(d, b, &bucketp[ii]); + insertKey(d, b, copy); + } + return 1; + } + } + HCE_INVALIDATE(©->entry); + return 0; +} + +static HintCacheDiskEntry * +readBucket(HintCacheDisk * d, int b) +{ + static HintCacheDiskEntry *bucketp = 0; + int bucketlen; + + /* If using mmap, just return the pointer */ + if (Config.onoff.hint_cache_use_mmap) + return (d->mmappedArray + b); + + /* Get a static buffer to put stuff in */ + bucketlen = sizeof(HintCacheDiskEntry) * d->entriesPerBucket; + if (bucketp == 0) { + bucketp = (HintCacheDiskEntry *) xmalloc(bucketlen); + } + + /* Fetch hint from disk by Unix I/O */ + if (lseek(d->fd, b * sizeof(HintCacheDiskEntry), 0) == -1) { + debug(HCDISK_DEBUG, 1) ("warning: can't seek to hint at offset %d\n", + b * sizeof(HintCacheDiskEntry)); + return 0; + } + if (read(d->fd, bucketp, bucketlen) == -1) { + debug(HCDISK_DEBUG, 1) + ("warning: can't read hint at offset %d\n", + b * sizeof(HintCacheDiskEntry)); + return 0; + } + + return bucketp; +} + + +static int +writeBucket(HintCacheDisk * d, int b, HintCacheDiskEntry * bucketp) +{ + /* If using mmap, no action is necessary - model is that + * you modify stuff via direct pointer you got from read */ + if (Config.onoff.hint_cache_use_mmap) + return 0; + + /* Write bucket to disk by Unix I/O */ + if (lseek(d->fd, b * sizeof(HintCacheDiskEntry), 0) == -1) { + debug(HCDISK_DEBUG, 1) ("warning: can't seek to hint at offset %d\n", + b * sizeof(HintCacheDiskEntry)); + return -1; + } + if (write(d->fd, bucketp, + sizeof(HintCacheDiskEntry) * d->entriesPerBucket) == -1) { + debug(HCDISK_DEBUG, 1) ("warning: can't write hint at offset %d\n", + b * sizeof(HintCacheDiskEntry)); + return -1; + } + + return 0; +} + +void +hcdiskDeleteHintCache() +{ + char hcname[256]; + + if (!Config.Hints.cache_file[0]) + return; + + unlink(Config.Hints.cache_file); + strcpy(hcname, Config.Hints.cache_file); + strcat(hcname, ".theCache"); + unlink(hcname); +} Index: squid/src/HintCacheEndian.c diff -u /dev/null squid/src/HintCacheEndian.c:1.1.2.2 --- /dev/null Mon Jan 26 04:57:38 2004 +++ squid/src/HintCacheEndian.c Mon May 20 19:46:41 2002 @@ -0,0 +1,97 @@ +/* + * $Date: 2004/08/17 20:55:13 $ $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ + * + * DEBUG: section 85 Hint Cache Endianness conversion routines + * AUTHOR: Mike Dahlin, UT Austin, 1998 + * + * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ + * -------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from the + * Internet community. Development is led by Duane Wessels of the + * National Laboratory for Applied Network Research and funded by + * the National Science Foundation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +/* + *------------------------------------------------------------------ + * LESS Group + * Computer Sciences Department + * University of Texas at Austin + * + * HCEndian.c --- + * + * HCEndian has the really low-level stuff for transmorifying + * basic types -- long, long long. It is up to each class + * that wants to be able to go across the wire to call + * these primitives on its own fields. + *------------------------------------------------------------------ + */ + +#include "squid.h" +#include + +long long unsigned +HCEndian_llNetToMachine(long long unsigned net) +{ + long unsigned *netLong = (long unsigned *) &net; + long long unsigned machine; + long unsigned *machineLong = (long unsigned *) &machine; + + machineLong[0] = ntohl(netLong[0]); + machineLong[1] = ntohl(netLong[1]); + return machine; +} + + +long long unsigned +HCEndian_llMachineToNet(long long unsigned machine) +{ + long unsigned *machineLong = (long unsigned *) &machine; + long long unsigned net; + long unsigned *netLong = (long unsigned *) &net; + + netLong[0] = htonl(machineLong[0]); + netLong[1] = htonl(machineLong[1]); + return net; +} + + +#ifdef DOTEST +void +HCEndian_selfTest(void) +{ + static const int verbose = 0; + long long unsigned ll1 = (long long unsigned) 0x3BCDEF0213579876; + long long unsigned ll2; + + printf("HCEndian_selfTest."); + if (verbose) { + printf("before: %llx\n", ll1); + } + ll2 = HCEndian_llMachineToNet(ll1); + if (verbose) { + printf("during: %llx\n", ll2); + } + ll2 = HCEndian_llNetToMachine(ll2); + if (verbose) { + printf("after: %llx\n", ll2); + } + assert(ll1 == ll2); + printf("..OK\n"); +} +#endif Index: squid/src/HintCacheHier.c diff -u /dev/null squid/src/HintCacheHier.c:1.1.2.2 --- /dev/null Mon Jan 26 04:57:38 2004 +++ squid/src/HintCacheHier.c Mon May 20 19:46:41 2002 @@ -0,0 +1,755 @@ +/* + * $Date: 2004/08/17 20:55:13 $ $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ + * + * AUTHOR: Mike Dahlin, UT Austin, 1998 + * DEBUG: section 86, Hint cache hierarchy. + * + * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ + * -------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from the + * Internet community. Development is led by Duane Wessels of the + * National Laboratory for Applied Network Research and funded by + * the National Science Foundation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +/* + *------------------------------------------------------------------ + * + * LESS Group + * Computer Sciences Department + * University of Texas at Austin + * + * HCDisk --- + * The on-disk cache of hints. The key data structure + * is an mmapped array which is treated as a - + * associative cache. + * + *------------------------------------------------------------------ + */ +#include "squid.h" + +/* + * MDD 7.18.1998 + * We use a primitive hierarchy consisting of the edges + * listed in the config file for bootstrapping the real + * hierarchy. Each node floods Join/Leave events to + * neighbors on the peerlist. The peerlist initially comes from + * the config file cache_host entries. We add one thing: + * if node A lists B as a cache host to which it will + * propagate Join/Leave events, we also want B to have + * A on the peerlist. E.g., make all peerlist edges bidirectional + * even if the config file's don't make them bidirectional. + * The reason for this is that if a new node that no current + * nodes have ever heard of joins the system, we of course want to + * propagate membership information to it. E.g, if node D + * adds node A to its config file, that effectively also + * adds node D to A's config file. Otherwise the old nodes + * learn about the new node, but the new node doesn't learn + * about anything. + * + * We also need to help figure out the hierarchy for Plaxton's + * algorithm. Plaxton's algorithm figures out who the parents + * are, but it doesn't know who the children are. We observe + * messages to keep in sync. + * On recv message: + * recv parent msg from parent: process parent message + * recv child msg from child: process child message + * recv parent msg from !parent: send "I am not child" to parent; + * drop message + * recv child msg from !child: add child to child list; + * process child message + * recv "I am not child" from child: remove child + */ + +#define HCHIER_DEBUG 86 + +#ifdef DOTEST +static int doTestBarrier(int barrier); +static void writeTestBarrier(int barrier); +static int readTestBarrier(int barrier); +static void clearTestBarrier(); +static void testFindPeer(peer * p); +static void testPlax(void); +static void testCreateStuff(char *tag); +static void testFind(void); +static void testFindStuff(char *tag, const struct sockaddr_in *expect); +#endif /* DOTEST */ + +/* + * These must be an set of values each one greater than the + * last to define the series of states for the network test. + */ +#define BARRIER_START 1000 +#define BARRIER_READY 1001 +#define BARRIER_JOIN 1002 +#define BARRIER_JOIN2 1003 +#define BARRIER_NODELIST 1004 +#define BARRIER_CREATE_STUFF 1005 +#define BARRIER_CREATE_STUFF2 1006 +#define BARRIER_CREATE_STUFF3 1007 +#define BARRIER_PLAX 1008 +#define BARRIER_FIND 1009 +#define BARRIER_LAST 1010 +#define BARRIER_DONE 9999 + +int HintCacheHier_selfTestDone = 0; + + +dlink_list HintCacheHier_Nodes; + +int scanIDs (dlink_list * l, char *b, int *count); +int scanIDDistances (dlink_list * l, char *b, int *count); + +void +hintCacheHier_Init(void) +{ + HintCacheNodeListIter iter; + struct sockaddr_in saddr; + /* + * This should be set in config file + */ + static int bitsPerLevelXXX = 8; + + HintCacheNodelist_Init(); + HintCachePlax_Init(bitsPerLevelXXX); + HintCacheNodelist_LocalJoin(); + for (HintCacheNodeList_IterStart(&iter); + hintCacheNodeList_IterCheck(iter); hintCacheNodeList_IterNext(&iter)) { + if (hintCacheNodeList_IterGetAddr(iter, &saddr)) { + hintCachePlax_addNode(&saddr); + } + } +} + +void +hintCacheHier_Destroy(void) +{ + hintCacheNodelist_LocalLeave(); + hintCacheNodelist_Destroy(); + hintCachePlax_Destroy(); +} + +/* + *------------------------------------------------------------------ + * MDD 7.18.1998 + * + * HCHier_updateMembershipNeighbor -- + * + * Add the specified node to the peerlist. See HCHier.h + * for explanation. + * + * Arguments: + * None. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------7.18.1998--------- + */ +void +hintCacheHierUpdateMembershipNeighbor(struct sockaddr_in *neighbor, + NeighborAction action) +{ + /* Currently nothing */ +} + + +/* + *------------------------------------------------------------------ + * + * hintCacheHierCompareDistanceFromMe -- + * + * Return <0 if new node is closer than old node, 0 if same + * distance, >0 if new node is closer than old node. + * If either node is missing, it must be far away. If both + * are missing, say new one is closer (0) (needed to make + * initial sight of new host work). + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +int +hintCacheHierCompareDistanceFromMe(struct in_addr new, struct in_addr old) +{ + int nrtt, ortt; + int nhops, ohops; + char name[16]; + + /* Compare by rtt if both have measured rtts */ + /* Must make copy of result of inet_ntoa before making + * function call because netdb also uses that function */ + strcpy(name, inet_ntoa(new)); + nrtt = netdbHostRtt(name); + strcpy(name, inet_ntoa(old)); + ortt = netdbHostRtt(name); + if (nrtt && ortt) + return (nrtt - ortt); + + /* Otherwise compare hopcount */ + nhops = netdbHintHops(new); + ohops = netdbHintHops(old); + + /* If either host is unknown, say new one is nearer */ + if (nhops == 0 || ohops == 0) + return (-1); + + return (nhops - ohops); +} + +/* + *------------------------------------------------------------------ + * + * hintCacheHierNewNode -- + * + * This gets called when we hear about a new node in the system. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------4.1.1998----------- + */ +void +hintCacheHierNewNode(struct sockaddr_in *sin, int hops, long long joinTimeNS) +{ + hintCacheNodelist_NetJoin(sin, hops, joinTimeNS); +} + +/* + *------------------------------------------------------------------ + * + * hintCacheHierDelNode -- + * + * This gets called when we hear about a node leaving the system + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------4.1.1998----------- + */ +void +hintCacheHierDelNode(struct sockaddr_in *sin, int hops, long long joinTimeNS) +{ + hintCacheNodelist_NetLeave(sin, hops, joinTimeNS); +} + +/* + *------------------------------------------------------------------ + * + * hintCacheHierCheckIfParent -- + * + * See if the specified node is really my parent. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------4.10.1998--------- + */ +int +hintCacheHierCheckIfParent(URLKey key, struct sockaddr_in *candidate) +{ +#if USE_DYNAMIC_HIERARCHY + return hintCachePlax_CheckIfParent(key, candidate); +#else + /* + * For static algorithm, anyone that wants to be my parent can + * be. + */ + return 1; +#endif +} + +/* + *------------------------------------------------------------------ + * + * hintCacheHier_CheckIfChild -- + * + * See if the specified node is really my child. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------4.10.1998--------- + */ +int +hintCacheHierCheckIfChild(struct sockaddr_in *candidate) +{ +#if USE_DYNAMIC_HIERARCHY + return hintCachePlax_CheckIfChild(candidate); +#else + /* + * For static algorithm, anyone that wants to be my child can + * be. + */ + return 1; +#endif +} + +/* + *------------------------------------------------------------------ + * + * hintCacheHierAddChild -- + * + * This node has claimed to by my child, so add it + * to the dynamic hierarchy. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-----------------------------------------------------4.10.1998-------- + */ +void +hintCacheHierAddChild(struct sockaddr_in *child) +{ +#if USE_DYNAMIC_HIERARCHY + hintCachePlax_AddChild(child); +#else + /* + * For static algorithm, I don't track children. + */ + return; +#endif +} + + +/* + *------------------------------------------------------------------ + * + * hintCacheHierRemoveChild -- + * + * This node denies paternity. Disinherit it. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------4.10.1998---------- + */ +void +hintCacheHierRemoveChild(struct sockaddr_in *child) +{ +#if USE_DYNAMIC_HIERARCHY + hintCachePlax_RemoveChild(child); +#else + /* + * For static algorithm, I don't track children. + */ + return; +#endif +} + + +/* + * Network enqueue/send interface. + */ + +/* Each children queue holds messages that should go to a set of + * "equivalent" children (eg. the children at some level of the + * hierarchy.) There are hintCacheHier_NChildrenQs() such queues; + * Child queue q contains c = hintCacheHier_ChildrenPerQ(q) children. + * The addresses of the children can be found with the function + * hintCacheHier_GetChildAddr(q, c); + * + * Each parent queue holds messages that should go to one parent. + * In general, we may have different parents for different objects. + * So, enqueue messages for an object in the queue + * hintCacheHier_ParentQIndex(URLKey). + */ + +/* + *------------------------------------------------------------------ + * + * hintCacheHierChildQIndex -- + * + * Return the index into the array of queues of + * children for children that are my children + * for this object. (See hintCachePlax for how + * children are grouped into levels.) + * + * Also, if I have no children for this object, + * set amILeaf to true. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-----------------------------------------------4.10.1998------------- + */ +int +hintCacheHierChildQIndex(URLKey * key, int iAmRoot, int *amILeaf) +{ + assert(amILeaf != NULL); +#if USE_DYNAMIC_HIERARCHY + return hintCachePlax_ChildQIndex(key, iAmRoot, amILeaf); +#else + /* + * For static algorithm, we have one set of children and + * thus one outgoing children buffer with index 0. + */ + *amILeaf = 0; + return 0; +#endif +} + +/* + *------------------------------------------------------------------ + * + * hintCacheHierNChildrenQs -- + * + * Return the number of outgoing message queues + * to different classes of children. Each + * "class" corresponds to children for which + * I am a parent. (See hintCachePlax for how + * children are grouped into levels.) + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------4.10.1998------------ + */ +int +hintCacheHierNChildrenQs(void) +{ +#if USE_DYNAMIC_HIERARCHY + return hintCachePlax_NChildrenQs(); +#else + /* + * For static algorithm, we have one set of children and + * thus one outgoing children buffer with index 0. + */ + return 1; +#endif +} + + + +/* + *------------------------------------------------------------------ + * + * hintCacheHierGetChildAddrs -- + * + * Return the number of children for the specified message + * queue, allocate a buffer for that many addresses, + * and fill in that bufer with the children's addresses. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * See above. + * + * Side effects: + * Allocates a vector for the addresses. Caller must free + * this vector when done. + * + * Note: the vector may be out of date by the time ther caller + * uses it. This is inherent problem -- even if caller sent + * all messages instantaneously, by the time they arrive + * at destination, the child could have left the system + * or a new child could have joined. + * + *------------------------------------------------4.16.1998------------ + */ +int +hintCacheHierGetChildAddrs(int qIndex, struct sockaddr_in **retAddrAP) +{ +#ifndef USE_DYNAMIC_HIERARCHY + peer *p; + int count = 0, nchildren = 0; +#endif + + assert(retAddrAP); + assert(qIndex < hintCacheHierNChildrenQs()); + +#if USE_DYNAMIC_HIERARCHY + return hintCachePlaxGetChildAddrs(qIndex, retAddrAP); +#else + assert(qIndex == 0); + for (p = getFirstPeer(); p; p = getNextPeer(p)) { + nchildren++; + } + *retAddrAP = (struct sockaddr_in *) xmalloc(nchildren + * sizeof(struct sockaddr_in)); + for (p = getFirstPeer(); p; p = getNextPeer(p)) { + (*retAddrAP)[count] = p->in_addr; + count++; + } + /* + * Squid promises that we run atomically + */ + assert(count == nchildren); + return nchildren; +#endif +} + +/* + *------------------------------------------------------------------ + * + * hintCacheHierNParentQs -- + * + * How many different message queues are they for different + * parents? + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *--------------------------------------------------4.10.1998--------- + */ +int +hintCacheHierNParentQs(void) +{ +#if USE_DYNAMIC_HIERARCHY + return hintCachePlaxNParentQs(); +#else + /* + * For static algorithm, we have one parent + * thus one outgoing parent buffer with index 0. + */ + return 1; +#endif +} + + +/* + *------------------------------------------------------------------ + * + * hintCacheHierParentQIndex -- + * + * Return the index of the queue I should use to talk + * to the parent for the specified object (set amIRoot + * if I am the root for the object.) + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------4.10.1998--------- + */ +int +hintCacheHierParentQIndex(URLKey * key, int *amIRoot) +{ + assert(amIRoot != NULL); +#if USE_DYNAMIC_HIERARCHY + return hintCachePlaxParentQIndex(key, amIRoot); +#else + /* + * For static algorithm, we have one parent + * thus one outgoing parent buffer with index 0. + */ + *amIRoot = 0; + return 0; +#endif +} + +/* + *------------------------------------------------------------------ + * + * hintCacheHierGetParentAddr -- + * + * Return the address of the node that is curerntly + * the parent for the specified message queue. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * Put answer in *retAddr and return nonzero on error. + * + * Side effects: + * None. + * + *-----------------------------------------------------4.10.1998------- + */ +int +hintCacheHierGetParentAddr(int index, struct sockaddr_in *retAddr) +{ +#if USE_DYNAMIC_HIERARCHY + return hintCachePlaxGetParentAddr(index, retAddr); +#else + peer *p; + + for (p = getFirstPeer(); p; p = getNextPeer(p)) { + if (p->type == PEER_PARENT) { + *retAddr = p->in_addr; + return 0; + } + } + p = getFirstPeer(); + if (p) { + *retAddr = p->in_addr; + return 0; + } + return -1; +#endif +} + + +int +hintCacheHierSendToParent(struct sockaddr_in *src, HintCacheUpdate * update, int msgtype) +{ +#if USE_DYNAMIC_HIERARCHY + int stillHave; + int pIndex, cIndex; + int iAmRoot, iAmLeaf; +#else + peer *e; +#endif + +#if USE_DYNAMIC_HIERARCHY + pIndex = hintCacheHierParentQIndex(&update->entry.key, &iAmRoot); +#else + for (e = getFirstPeer(); e; e = getNextPeer(e)) { + if (e->type != PEER_PARENT) + continue; + if (e->in_addr.sin_addr.s_addr == src->sin_addr.s_addr + && e->http_port == src->sin_port) { + if (e->type != PEER_PARENT) { + debug(HCHIER_DEBUG, 0, + "warning: got parental msg from non-parent <%s,%d>.\n", + inet_ntoa(src->sin_addr), src->sin_port); + debug(HCHIER_DEBUG, 0, + " Not propagating it. Configuration mismatch?\n"); + return (-1); + } + continue; + } + hintCacheNetEnqueue(&e->hcoutq, msgtype, &update->entry, + update->hopcount + 1); + } + if (e == 0) { + /* Not found. */ + return (-1); + /* Don't propagate */ + } +#endif + +#if USE_DYNAMIC_HIERARCHY + /* Send message */ + if (!iAmRoot) { + assert(pIndex < hintCacheHier_NParentQs()); + hintCacheNetEnqueue(&parentOutgoingA[pIndex], msgtype, &update->entry, + update->hopcount + 1); + } +#endif + + return (0); +} + + + +int +hintCacheHierSendToSiblings(struct sockaddr_in *src, HintCacheUpdate * update, + int msgtype, int siblingtype) +{ +#if USE_DYNAMIC_HIERARCHY + int stillHave; + int pIndex, cIndex; + int iAmRoot, iAmLeaf; +#else + peer *e; +#endif + +#if USE_DYNAMIC_HIERARCHY + pIndex = hintCacheHierParentQIndex(&update->entry.key, &iAmRoot); + cIndex = hintCacheHierChildQIndex(&update->entry.key, iAmRoot, &iAmLeaf); + if (!iAmLeaf) { + assert(cIndex < hintCacheHierNChildrenQs()); + hintCacheNetEnqueue(&childrenOutgoingA[cIndex], msgtype, + &update->entry, update->hopcount + 1); + } +#else + for (e = getFirstPeer(); e; e = getNextPeer(e)) { + if (e->in_addr.sin_addr.s_addr != src->sin_addr.s_addr + || e->http_port != src->sin_port) { + if (siblingtype == PEER_NONE || e->type == siblingtype) + hintCacheNetEnqueue(&e->hcoutq, msgtype, &update->entry, + update->hopcount + 1); + } + } +#endif + return (0); +} + + Index: squid/src/HintCacheNet.c diff -u /dev/null squid/src/HintCacheNet.c:1.1.2.3 --- /dev/null Mon Jan 26 04:57:38 2004 +++ squid/src/HintCacheNet.c Mon May 20 19:46:41 2002 @@ -0,0 +1,563 @@ +/* + * $Date: 2004/08/17 20:55:13 $ $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ + * + * DEBUG: section 87 Hint cache networking. + * AUTHOR: Mike Dahlin, UT Austin, 1998 + * + * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ + * -------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from the + * Internet community. Development is led by Duane Wessels of the + * National Laboratory for Applied Network Research and funded by + * the National Science Foundation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +/* + *------------------------------------------------------------------ + * LESS Group + * Computer Sciences Department + * University of Texas at Austin + * + * hintCacheNet --- Simple send interface built on squid async send stuff. + *------------------------------------------------------------------ + */ + +#include "squid.h" +#include + +#define HCNET_DEBUG 87 + +#define RECV_DEBUG(type, u, hdr, src) \ + debug (HCNET_DEBUG, 2) ("Got %s: 0x%x at <%s,%d> from <%s,%d>\n", \ + (type), *(int *) &(u)->entry.key.key, \ + inet_ntoa((u)->entry.ipaddr), (u)->entry.port, \ + inet_ntoa((src)->sin_addr), (hdr)->httpport) + +static void enqueueBytes(HintCacheNet * n, char *data, int nbytes); +static int copyToLocal(HintCacheUpdate * updatesA, char *data, int len, + int oneUpdateSize); +static void clear(HintCacheNet * n); +static void updateHierarchy(HintCacheUpdate * updatesA, int nupdates, + struct sockaddr_in *source); +static void suppress(HintCacheUpdate * updateA, int nupdates); +static void scoldParent(struct sockaddr_in *parent); + +void +hintCacheNetInit(HintCacheNet * n) +{ +#ifdef DOTEST + n->testMode = 0; + n->testCount = 0; +#endif + clear(n); +} + +static void +clear(HintCacheNet * n) +{ + HintCacheNetHeader hdr; + const char *url = "route://updates"; + request_flags rflags; + StoreEntry *entry; + + assert(n); + + /* Set up entry with request */ + *(unsigned int *) &rflags = 0; + rflags.cachable = 1; + entry = storeCreateEntry(url, url, rflags, METHOD_GET); + n->sendBuffer = entry; + EBIT_SET(entry->flags, ENTRY_SPECIAL); /* formerly set KEEP_INMEM */ +/* EBIT_SET(entry->flags, DONT_FREE_FOR); */ + n->sendBuffer->mem_obj->request = + requestLink(urlParse(METHOD_GET, (char *) url)); + + n->sendLength = 0; + + n->state = HC_filling; + + /* Prepare header for next transmission */ + hdr.httpport = htons(Config.Sockaddr.http->s.sin_port); + hdr.updlen = htons(sizeof(HintCacheUpdateNet)); + enqueueBytes(n, (char *) &hdr, sizeof(hdr)); +} + +void +hintCacheNetDestroy(HintCacheNet * n) +{ + storeRelease(n->sendBuffer); + n->state = HC_destroyed; +} + +void +hintCacheNetEnqueue(HintCacheNet * n, int action, HintCacheEntry * entry, int hopcount) +{ + HintCacheUpdate update; + HintCacheUpdateNet netUpdate; + +#ifdef DOTEST + if (n->testMode) { + n->testCount++; + return; + } +#endif + debug(HCNET_DEBUG, 4) + ("HCNet_Enqueue onto 0x%x (action %d) (entry.key %llx entry.ipaddr %s port %d)\n", + n, action, entry->key.key, inet_ntoa(entry->ipaddr), entry->port); + + hintCacheUpdateInit(&update, action, entry, hopcount); + hintCacheUpdateNetInit(&netUpdate, &update); + enqueueBytes(n, (char *) &netUpdate, sizeof(HintCacheUpdateNet)); +} + +static void +enqueueBytes(HintCacheNet * n, char *data, int nbytes) +{ + static enqreentrancy = 0; + + assert(n->state == HC_filling); + assert(!enqreentrancy); + ++enqreentrancy; + n->sendLength += nbytes; + storeAppend(n->sendBuffer, data, nbytes); + --enqreentrancy; +} + +int +hintCacheNetBytesReady(HintCacheNet * n) +{ + return n->sendLength; +} + +void +hintCacheNetComplete(HintCacheNet * n) +{ + + assert(n); + assert(n->state == HC_filling); + n->state = HC_full; + hintCacheFinishHeader(n->sendBuffer); + storeComplete(n->sendBuffer); +} + +void +hintCacheNetSendTo(HintCacheNet * n, struct sockaddr_in *dest) +{ + assert(n->state == HC_full); + assert(n->sendLength > sizeof(HintCacheNetHeader)); + debug(HCNET_DEBUG, 2) ("HCNet_SendTo: sending routes on 0x%x to <%s,%d>\n", + n, inet_ntoa(dest->sin_addr), dest->sin_port); + putSend(n->sendBuffer, dest, NULL, NULL, 0); +} + +void +hintCacheNetDone(HintCacheNet * n) +{ + StoreEntry *entry = n->sendBuffer; + + assert(n->state == HC_full); + + EBIT_CLR(entry->flags, ENTRY_SPECIAL); /* formerly KEEP_INMEM flag */ + + EBIT_SET(entry->flags, RELEASE_REQUEST); + storeUnlockObject(entry); + + clear(n); +} + + +#ifdef DOTEST +void +hintCacheNetSetTestMode(HintCacheNet * n) +{ + n->testMode = 1; + n->testCount = 0; +} + +int +hintCacheNetGetTestCount(HintCacheNet * n) +{ + return n->testCount; +} +#endif /* DOTEST */ + +/* + *------------------------------------------------------------------ + * + * hintCacheNetDataArrives -- + * + * Action to take when messages arrive from network. + * + * Arguments: + * char *data -- unaligned buffer of network-formatted hintCacheNetUpdates + * int len -- number of bytes in that buffer + * struct sockaddr *source -- who sent the buffer + * + * Results: + * None. + * + * Side effects: + * Many. + * + *------------------------------------------------4.2.1998------------ + */ +void +hintCacheNetDataArrives(char *data, int len, HintCacheNetHeader * hdr, + struct sockaddr_in *source) +{ + struct sockaddr_in sin; + HintCacheUpdate *updatesA; + int nupdates; + int iupdate; + + if (!HC_ACTIVE()) { + /* Hint cache is inoperative. Nothing to do. */ + return; + } + + assert(source->sin_family == AF_INET); + assert(hdr->updlen >= HCU_MINLEN); + + debug(HCNET_DEBUG, 3) + ("HintCacheDataArrives: got %d bytes of stuff (probably %d updates xtra=%d\n", + len, len / hdr->updlen, len % hdr->updlen); + + /* Copy to alignment buffer and local format */ + updatesA = (HintCacheUpdate *) xmalloc(len); + nupdates = copyToLocal(updatesA, data, len, hdr->updlen); + + /* + * Suppress loops. Better to do this on send-side, but + * this should be uncommon --> no performance impact + */ + suppress(updatesA, nupdates); + + /* + * Help hierarchy learn about who our children are. + */ + source->sin_port = hdr->httpport; + + updateHierarchy(updatesA, nupdates, source); + + /* + * Prefetch if we have a large number of requests. + * Idea is to tell OS to start bringing in the pages + * that we are about to touch. + */ + if (nupdates >= HCD_PREFETCH_THRESH) { + hintCacheDisk_prefetch(hcDisk, updatesA, nupdates); + } + + /* + * OK. Now we can start processing the messages. + */ + for (iupdate = 0; iupdate < nupdates; iupdate++) { + switch (updatesA[iupdate].action) { + case HC_InvalToParent: + RECV_DEBUG("hintCache_InvalToParent", &updatesA[iupdate], hdr, source); + hcprop_handleInvalToParent(&updatesA[iupdate], source, 0); + break; + + case HC_InvalToChild: + RECV_DEBUG("hintCache_InvalToChild", &updatesA[iupdate], hdr, source); + hcprop_handleInvalToChild(&updatesA[iupdate], source, 0); + break; + + case HC_InformToParent: + RECV_DEBUG("hintCache_InformToParent", &updatesA[iupdate], hdr, source); + hcprop_handleInformToParent(&updatesA[iupdate], source, 0); + break; + + case HC_InformToChild: + RECV_DEBUG("hintCache_InformToChild", &updatesA[iupdate], hdr, source); + hcprop_handleInformToChild(&updatesA[iupdate], source, 0); + break; + + case HC_Join: + /* New cache node! Add to list. */ + RECV_DEBUG("hintCache_Join", &updatesA[iupdate], hdr, source); + /* + * MDD 7.18.1998 + * When a node relays a join/leave to us, make sure + * that we send future joins to that node by adding + * that node to the peer list if it's not already there. + */ + sin.sin_family = AF_INET; + sin.sin_addr = source->sin_addr; + sin.sin_port = hdr->httpport; + hintCacheHier_updateMembershipNeighbor(&sin, NEIGHBOR_ADD); + + /* + * Now update local state for join + */ + sin.sin_family = AF_INET; + sin.sin_addr = updatesA[iupdate].entry.ipaddr; + sin.sin_port = updatesA[iupdate].entry.port; + hintCacheHier_newNode(&sin, updatesA[iupdate].hopcount, + updatesA[iupdate].entry.key.key); + break; + + case HC_Leave: + /* Cache node is either dead or has been detected dead. */ + RECV_DEBUG("hintCache_Leave", &updatesA[iupdate], hdr, source); + sin.sin_family = AF_INET; + sin.sin_addr = updatesA[iupdate].entry.ipaddr; + sin.sin_port = updatesA[iupdate].entry.port; + hintCacheHier_delNode(&sin, updatesA[iupdate].hopcount, + updatesA[iupdate].entry.key.key); + + /* + * MDD 7.18.1998 + * When we receive a join from a node, make sure + * that we send future joins to that node by adding + * that node to the peer list if it's not already there. + */ + hintCacheHier_updateMembershipNeighbor(source, NEIGHBOR_ADD); + /* + * MDD 7.18.1998 + * And the node we just heard about is gone, so it must + * no longer be a neighbor across which to propagate changes + * in membership. + */ + hintCacheHier_updateMembershipNeighbor(&sin, NEIGHBOR_REMOVE); + + break; + + case HC_NotChild: + /* + * This message should have been handled and suppressed + * (by making it "HC_Ignore") in the updateHierarchy() code. + */ + RECV_DEBUG("HC_NotChild", &updatesA[iupdate], hdr, source); + assert(0); + break; + + case HC_Ignore: + /* This message was suppressed either because it is + * part of a loop or because it came from a node that + * thinks it is my parent but isnt. + */ + break; + + default: + /* Ignore bad messages */ + debug(HCNET_DEBUG, 1) + ("HCHintCache: unknown update action %d from net\n", + updatesA[iupdate].action); + break; + } + } + + xfree(updatesA); +} + +/* + *------------------------------------------------------------------ + * + * copyToLocal -- + * + * Copy unaligned network-format buffer to aligned, local format + * array of updates + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * Nelements + * + * Side effects: + * Copies data into udpatesA + * + *-----------------------------------------------3.31.1998----------- + */ +static int +copyToLocal(HintCacheUpdate * updatesA, char *data, int len, int oneUpdateSize) +{ + char *alignbuf; + int uoff; + HintCacheUpdateNet *nupdatep; + int ii; + + alignbuf = xmalloc(len); + memcpy(alignbuf, data, len); + + for (uoff = 0, ii = 0; uoff < len; uoff += oneUpdateSize, ii++) { + nupdatep = (HintCacheUpdateNet *) (alignbuf + uoff); + hintCacheUpdateNetLocalFormat(nupdatep, &updatesA[ii]); + } + xfree(alignbuf); + return ii; +} + +/* + *------------------------------------------------------------------ + * + * suppress -- + * + * Decide if any of these hints have bounced around + * network too much to be worth looking at (mainly + * we want to suppress loops.) In prinicple, + * the algorithm guarantees that loops cannot occur, + * but best to be safe. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * May modify records in updateA to mark them as "ignore." + * + *-----------------------------------------------4.1.1998------------- + */ +static void +suppress(HintCacheUpdate * updateA, int nupdates) +{ +#ifdef NOTYET + /* Need to fill this in */ + int iupdate; + + for (iupdate = 0; iupdate < nupdates; iupdate++) { + if (stoppable update) { + updateA[iupdate].action = HC_Ignore; + } + } +#endif + + return; +} + +/* + *------------------------------------------------------------------ + * + * updateHierarchy -- + * + * We also need to help figure out the hierarchy for Plaxton's + * algorithm. Plaxton's algorithm figures out who the parents + * are, but it doesn't know who the children are. We observe + * messages to keep in sync. + * On recv message: + * recv parent msg from parent: process parent message + * recv child msg from child: process child message + * recv parent msg from !parent: send "I am not child" to parent; + * drop message + * recv child msg from !child: add child to child list; + * process child message + * recv "I am not child" from child: remove child + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * May modify records in update array to be "HC_Ignore." + * + *------------------------------------------------4.1.1998------------ + */ +static void +updateHierarchy(HintCacheUpdate * updatesA, int nupdates, struct sockaddr_in *source) +{ + int iupdate; + int parentScolded = 0; + + for (iupdate = 0; iupdate < nupdates; iupdate++) { + switch (updatesA[iupdate].action) { + case HC_InformToChild: + case HC_InvalToChild: + if (!HCHier_CheckIfParent(updatesA[iupdate].entry.key, source)) { + if (!parentScolded) { + scoldParent(source); + parentScolded = 1; + } + updatesA[iupdate].action = HC_Ignore; + } + break; + + case HC_InformToParent: + case HC_InvalToParent: +#if 1 /* XXX! - disabling parent&child lists */ + if (!hintCacheHier_CheckIfChild(source)) { + hintCacheHier_AddChild(source); + } +#endif + break; + + case HC_NotChild: + hintCacheHier_RemoveChild(source); + updatesA[iupdate].action = HC_Ignore; + break; + + + default: + /* + * Other messages don't affect hierarchy. Ignore them here. + */ + break; + } + } +} + +/* + *------------------------------------------------------------------ + * + * scoldParent -- + * + * Tell parent "I am not child". Need to use + * our own private HintCacheNet queue since all of the + * other queues are associated with the hierarchy + * and this message is to tell someone they + * are *not* in the hierarchy. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------4.2.1998------------ + */ +static void +scoldParent(struct sockaddr_in *parent) +{ + static int initialized = 0; + static HintCacheNet netBuf; + static HintCacheEntry dummyEntry; + static URLKey dummyKey; + + debug(HCNET_DEBUG, 7) ("In scoldParent %s\n", inet_ntoa(parent->sin_addr)); + + if (!initialized) { + hintCacheNetInit(&netBuf); + URLKey_Init(&dummyKey, NULL); + hintCacheEntry_Init(&dummyEntry, dummyKey, + &Config.Sockaddr.http->s, squid_curtime); + initialized = 1; + } + + hintCacheNetEnqueue(&netBuf, HC_NotChild, &dummyEntry, 1); + hintCacheNetComplete(&netBuf); + hintCacheNetSendTo(&netBuf, parent); + hintCacheNetDone(&netBuf); + return; +} Index: squid/src/HintCacheNodes.c diff -u /dev/null squid/src/HintCacheNodes.c:1.1.2.2 --- /dev/null Mon Jan 26 04:57:38 2004 +++ squid/src/HintCacheNodes.c Mon May 20 19:46:41 2002 @@ -0,0 +1,970 @@ +/* + * $Date: 2004/08/17 20:55:13 $ $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ + * + * DEBUG: section 88 List of known caches. + * AUTHOR: Mike Dahlin, UT Austin, 1998 + * + * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ + * -------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from the + * Internet community. Development is led by Duane Wessels of the + * National Laboratory for Applied Network Research and funded by + * the National Science Foundation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +/* + *------------------------------------------------------------------ + * LESS Group + * Computer Sciences Department + * University of Texas at Austin + * + * HCNodelist --- + * The nodelist keeps a list of all nodes in the hierarchy whether they + * are alive or dead. It uses a flooding algorithm for this (see + * ../notes.3.17.1998). As part of this flooding algorithm, it learns + * a hopcount to other nodes. We tell squid_db this hopcount as an + * initial *rough* estimate of distance between nodes. + * + * The flooding algorithm needs as input a list of "neighbors". The lists + * of neighbors for all nodes MUST overlap. The lists of neighbors SHOULD + * include only nearby neighbors (so that the hopcounts are correct). + * It uses the squid static hierarchy (see neighbors.c e.g. getFirstPeer() + * etc) for this initial list. + *------------------------------------------------------------------ + */ +#include "squid.h" + +/* + * Mike Dahlin's interface comments from HCNodelist.h: + * + * Out-calls: These internal routines are where you should place + * outcalls for being notified of important events: + * + * static void HCNodelist_OutcallHops _PARAMS((struct sockaddr_in sin, + * int hops)); + * + * e.g. The nodelist promises to tell squid_db whenever it learns a new + * distance to a node. ?? The nodelist promises to tell Plaxton + * when the distance to a node changes?? + * + * static void HCNodelist_OutcallJoin() _PARAMS((struct sockaddr_in sin)); + * e.g. The nodelist promises to tell Plaxton when a new node joins. + * + * static void hintCacheNodelist_OutcallLeave() _PARAMS((struct sockaddr_in sin)); + * The nodelist promises to tell Plaxton when a node leaves. + */ + +#define HCNODES_DEBUG 88 + +typedef struct HierNodeElem +{ + dlink_node links; + struct sockaddr_in sin; + int action; /* HC_Join or HC_Leave */ + long long timestamp_ns; /* time of action */ +} +HierNodeElem; + +static dlink_list nodes; +static int myStatus = HC_Leave; + +static void HierNodeElem_Init _PARAMS((HierNodeElem *, struct sockaddr_in *, + int action, long long timestamp_ns)); + +static HierNodeElem *nodeFind(struct sockaddr_in *sin); +static long long currentTimeNS(); +static void floodEvent(int action, struct sockaddr_in *source, + long long timeNS, int hopcount); + +static void hintCacheNodelistOutcallHops(struct sockaddr_in *sin, + int hops, long long timeNS); +static void hintCacheNodelistOutcallJoin(struct sockaddr_in *sin, + int hops, long long timeNS); +static void hintCacheNodelistOutcallLeave(struct sockaddr_in *sin, + int hops, long long timeNS); + +static void printList(); + + +static void +HierNodeElem_Init(HierNodeElem * e, struct sockaddr_in *sin, int action, + long long timestamp_ns) +{ + assert(action == HC_Join || action == HC_Leave); + List_InitElement(&e->links); + e->sin = *sin; + e->action = action; + e->timestamp_ns = timestamp_ns; +} + +/* + *------------------------------------------------------------------ + * + * hintCacheNodeList_Init -- + * + * Constructor. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * Initialize nodelist to empty list. + * + *----------------------------------------------3.31.1998------------- + */ +void +hintCacheNodelistInit(void) +{ + nodes.head = nodes.tail = 0; +} + +/* + *------------------------------------------------------------------ + * + * hintCacheNodeListDestroy -- + * + * Deallocate all elements in list + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *--------------------------------------------------3.31.1998------- + */ +void +hintCacheNodelist_Destroy(void) +{ + dlink_node *item; + + while (nodes.head) { + item = nodes.head; + dlinkDelete(item, &nodes); + xfree(item); + } +} + + +/* + *------------------------------------------------------------------ + * + * hintCacheNodeListLocalJoin -- + * + * Do a local join. This tells the algorithm + * to flood "join" messages to the neighbors. + * + * Arguments: + * struct sockaddr_in myId -- my ip address + * + * Results: + * None. + * + * Side effects: + * None. + * + *-----------------------------------------------------4.1.1998---- + */ +void +hintCacheNodelistLocalJoin(void) +{ + struct sockaddr_in *myId; + int hopcount; + long long timeNS; +#if 0 + HintCacheEntry hcEntry; + HintCacheUpdate update; + URLKey key; + int nbpl; + int ii; +#endif + + myStatus = HC_Join; + + myId = &Config.Sockaddr.http->s; + timeNS = currentTimeNS(); + hopcount = 1; + floodEvent(HC_Join, myId, timeNS, hopcount); + +#if 0 + /* "Priming" code */ + if (parentOutgoingA) { + nbpl = (hintCachePlax_bucketsPerLevel > 0) ? hintCachePlax_bucketsPerLevel : 256; + for (ii = 0; ii < nbpl; ii++) { + key.key = ii; + hintCacheEntry_Init(&hcEntry, key, &Config.Sockaddr.http->s); + hintCacheUpdate_Init(&update, HC_InvalToParent, &hcEntry, 1); + hcprop_handleInvalToParent(&update, 1); + } + } +#endif +} + +/* + *------------------------------------------------------------------ + * + * hintCacheNodeListLocalLeave -- + * + * Do a local leave. This tells the algorithm + * to flood "leave" messages to the neighbors. + * + * Arguments: + * struct sockaddr_in myId -- my ip address + * + * Results: + * None. + * + * Side effects: + * None. + * + *-----------------------------------------------------4.1.1998---- + */ +void +hintCacheNodelistLocalLeave(void) +{ + struct sockaddr_in *myId; + int hopcount; + long long timeNS; + + myStatus = HC_Leave; + myId = &Config.Sockaddr.http->s; + timeNS = currentTimeNS(); + hopcount = 1; + floodEvent(HC_Leave, myId, timeNS, hopcount); +} + + +/* + *------------------------------------------------------------------ + * + * hintCacheNodelistgetMyStatus -- + * + * Am I currently in or out? + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.1.1998-------- + */ +int +hintCacheNodelistmyStatus(void) +{ + return myStatus; +} + + +/* + *------------------------------------------------------------------ + * + * hintCacheNodelistNetJoin -- + * + * Process a "join" received from the network. + * If this is a new node, a new action for a node, + * or a current action with a shorter distance, + * proceed with the join and propagate message + * to neighbors. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * Allocates and adds an element to the list; calls + * OutcallJoin(). + * + *------------------------------------------------------7.19.1998---- + */ +void +hintCacheNodelistNetJoin(struct sockaddr_in *sin, int hops, long long joinTimeNS) +{ + HierNodeElem *h, *oldCopy; + int oldHops; + int foundOldJoin = 0; + int joinIsNewer; + + assert(sin); + /* Ignore if it's already on list and either (1) a newer record + * or (2) a current record and at least as close as this + * update. Also ignore if it is me! + * For simplicity, rather than update a record in place, remove + * it and add a new record to front of list. This should be better + * for performance, too, since we expect to get a burst of + * notifications from all neighbors, so put record at front of list. + */ + if (!SINCMP(sin, &Config.Sockaddr.http->s)) { + return; + } + oldCopy = nodeFind(sin); + if (oldCopy != NULL) { + if (oldCopy->timestamp_ns > joinTimeNS) { + /* We got a stale message; ignore it */ + return; + } else if (oldCopy->action != HC_Join + && oldCopy->timestamp_ns < joinTimeNS) { + /* Join supercedes an old HC_Leave */ + dlinkDelete(&oldCopy->links, &nodes); + xfree(oldCopy); + /* Fall through and add this join to nodelist */ + } else { + assert(oldCopy->action == HC_Join); + foundOldJoin = 1; + assert(oldCopy->timestamp_ns <= joinTimeNS); + joinIsNewer = (oldCopy->timestamp_ns < joinTimeNS); + oldHops = netdbHintHops(sin->sin_addr); + + + if (oldHops > hops) { + dlinkDelete(&oldCopy->links, &nodes); + xfree(oldCopy); + /* Fall through and add this join to nodelist and flood */ + } else if (joinIsNewer) { + /* + * Join is newer but not closer. Propagate to neighbors + * but no need to do anything locally beyond updating + * the timestamp. + */ + oldCopy->timestamp_ns = joinTimeNS; + floodEvent(HC_Join, sin, joinTimeNS, hops + 1); + return; + } + } + } + /* + * Only get here if new join supercedes and old join removed or + * nonexistant. Do the join and flood it to neighbors. + */ + assert(!nodeFind(sin)); + + h = (HierNodeElem *) xmalloc(sizeof(HierNodeElem)); + HierNodeElem_Init(h, sin, HC_Join, joinTimeNS); + dlinkAdd(h, &h->links, &nodes); + + /* + * Now tell everyone else (locally and network) about + * the new addition or new distance + */ + floodEvent(HC_Join, sin, joinTimeNS, hops + 1); + if (foundOldJoin) { + HintCacheNodelistOutcallHops(sin, hops, joinTimeNS); + } else { + hintCacheNodelistOutcallJoin(sin, hops, joinTimeNS); + } + + if (!foundOldJoin) { + debug(HCNODES_DEBUG, 2) + ("hintCacheNodelist::NetJoin() adds %d.%d.%d.%d; list is: \n", + (unsigned char) ((sin->sin_addr.s_addr & 0xFF000000) >> 24), + (unsigned char) ((sin->sin_addr.s_addr & 0x00FF0000) >> 16), + (unsigned char) ((sin->sin_addr.s_addr & 0x0000FF00) >> 8), + (unsigned char) ((sin->sin_addr.s_addr & 0x000000FF) >> 0)); + printList(); + debug(HCNODES_DEBUG, 2) ("\n"); + } + +} + +/* + *------------------------------------------------------------------ + * + * hintCacheNodelistNetLeave -- + * + * Process a notification that a node has left the system + * + * We keep "departed" nodes on nodelist with a "leave" flag + * set so we know when to stop propagating messages. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------7.19.1998-------------- + */ +void +hintCacheNodelistNetLeave(struct sockaddr_in *sin, int hops, long long leaveTimeNS) +{ + HierNodeElem *h, *oldCopy; + int foundOldLeave = 0; + + assert(sin); + + /* Ignore if it's already on list and a newer record. + * For simplicity, rather than update a record in place, remove + * it and add a new record to front of list. This should be better + * for performance, too, since we expect to get a burst of + * notifications from all neighbors, so put record at front of list. + */ + oldCopy = nodeFind(sin); + if (oldCopy) { + if (oldCopy->action == HC_Leave) { + foundOldLeave = 1; + } + if (oldCopy->timestamp_ns < leaveTimeNS) { + dlinkDelete(&oldCopy->links, &nodes); + xfree(oldCopy); + } else { + /* + * old copy is actually newer than this update. Ignore this + * update. + */ + return; + } + } + /* + * Only get here if new leave supercedes old record removed or + * nonexistant + */ + assert(!nodeFind(sin)); + + h = (HierNodeElem *) xmalloc(sizeof(HierNodeElem)); + HierNodeElem_Init(h, sin, HC_Leave, leaveTimeNS); + dlinkAdd(h, &h->links, &nodes); + + /* + * Now tell everyone else (locally and network) about + * the new addition or new distance + */ + floodEvent(HC_Leave, sin, leaveTimeNS, hops + 1); + if (!foundOldLeave) { + HCNodelist_OutcallLeave(sin, hops, leaveTimeNS); + } + + if (!foundOldLeave) { + debug(HCNODES_DEBUG, 4) + ("HCNodelist::NetLeave() removes %d.%d.%d.%d; list is: \n", + (unsigned char) ((sin->sin_addr.s_addr & 0xFF000000) >> 24), + (unsigned char) ((sin->sin_addr.s_addr & 0x00FF0000) >> 16), + (unsigned char) ((sin->sin_addr.s_addr & 0x0000FF00) >> 8), + (unsigned char) ((sin->sin_addr.s_addr & 0x000000FF) >> 0)); + printList(); + debug(HCNODES_DEBUG, 4) ("\n"); + } +} + +/* + *------------------------------------------------------------------ + * + * hintCacheNodelist_OutcallHops -- + * + * This function gets called whenever the number of hops + * to a node *changes* due to network updates. This + * is a good place to put function calls to modules that + * care to hear about such things. + * + * 1) netdb + * 2) plaxton dynamic hierarchy algorithm + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *--------------------------------------------------------7.19.1998----- + */ +static void +hintCacheNodelistOutcallHops(struct sockaddr_in *sin, int hops, long long timeNS) +{ + char name[16]; + + /* + * Tell netdb + */ + strcpy(name, inet_ntoa(sin->sin_addr)); + if (!netdbHintHops(sin->sin_addr)) { + netdbAdd(sin->sin_addr, name); + } + netdbUpdateHintHops(sin->sin_addr, hops); + + /* + * Tell plaxton algorithm + */ + hintCachePlax_changeDistance(sin); +} + +/* + *------------------------------------------------------------------ + * + * hintCacheNodelistOutcallJoin -- + * + * This function gets called whenever a node joins the + * sytsem. + * This is a good place to put function calls to modules that + * care to hear about such things. + * + * Right now, 3 people care: + * 1) netdb + * 2) plaxton dynamic hierarchy algorithm + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------7.19.1998----------- + */ +static void +hintCacheNodelistOutcallJoin(struct sockaddr_in *sin, int hops, long long timeNS) +{ + char name[16]; + + /* + * Tell netdb + */ + strcpy(name, inet_ntoa(sin->sin_addr)); + netdbAdd(sin->sin_addr, name); + netdbUpdateHintHops(sin->sin_addr, hops); + + /* + * Tell plaxton algorithm + */ + hintCachePlax_addNode(sin); +} + +/* + *------------------------------------------------------------------ + * + * hintCacheNodelistOutcallLeave -- + * + * This function gets called whenever a node leaves the + * sytsem. + * This is a good place to put function calls to modules that + * care to hear about such things. + * + * 1) plaxton dynamic hierarchy algorithm + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-----------------------------------------------------7.19.1998---------- + */ +static void +hintCacheNodelistOutcallLeave(struct sockaddr_in *sin, int hops, long long timeNS) +{ + /* + * Tell plaxton algorithm + */ + hintCachePlax_removeNode(sin); +} + + +/* + *------------------------------------------------------------------ + * + * nodeFind -- + * + * Find node with matching address. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +static HierNodeElem * +nodeFind(struct sockaddr_in *sin) +{ + HierNodeElem *e; + dlink_node *item; + + for (item = nodes.head; item; item = item->next) { + e = (HierNodeElem *) item; + if (!SINCMP(&e->sin, sin)) { + return (e); + } + } + return (NULL); +} + +/* + *------------------------------------------------------------------ + * + * floodEvent -- + * + * Send the notification to our neighbors. + * + * Arguments: + * int action HC_Join or HC_Leave + * struct sockaddr_in *source -- the subject of the action + * long long timeNS -- the time of the action (used for + * ordering events and removing duplicates) + * int hopcount -- how many hops has this event seen? + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------3.31.1998-------- + */ +static void +floodEvent(int action, struct sockaddr_in *source, long long timeNS, + int hopcount) +{ +#ifdef USE_DYNAMIC_HIERARCHY + HintCacheEntry entry; + peer *p; + URLKey hackURLKey; + struct sockaddr_in dest; + + assert(action == HC_Join || action == HC_Leave); + + if (neighborsOutgoing == NULL) { + return; + } + + hackURLKey.key = timeNS; /* XXX Update should be a union XXX */ + + hintCacheEntry_Init(&entry, hackURLKey, source); + hintCacheNet_Enqueue(neighborsOutgoing, action, &entry, hopcount); +#if 1 + hintCacheNet_Complete(neighborsOutgoing); + + for (p = getFirstPeer(); p; p = getNextPeer(p)) { + if (p->in_addr.sin_addr.s_addr == 0) { + debug(HCNODES_DEBUG, 4) + ("hintCacheNodelist warning: peer %s addr not set\n", p->host); + continue; + } + dest.sin_family = AF_INET; + dest.sin_addr = p->in_addr.sin_addr; + dest.sin_port = p->http_port; + hintCacheNet_SendTo(neighborsOutgoing, &dest); + } + + hintCacheNet_Done(neighborsOutgoing); +#endif +#endif /* USE_DYNAMIC_HIERARCHY */ +} + + + +/* + *------------------------------------------------------------------ + * + * hintCacheNodeListIterXXX -- + * + * Used for iterating through all addresses on list. + * + * for(hintCacheNodeListIterStart(&iter); + * hintCacheNodeListIterCheck(&iter); + * hintCacheNodeListIterNext(&iter)){ + * valid = hintCacheNOdeListIterGetAddr(&iter, &addr); + * } + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * Note -- only itereates through "joined" elements; + * Skip the shadow elements representing nodes that + * have left. + * + * Warning -- iterator is pointer into element on list. + * If list changing during iteration, could get confused. + * + *------------------------------------------------------------------ + */ +void +hintCacheNodeListIterStart(HintCacheNodeListIter iter) +{ + iter = (HintCacheNodeListIter) nodes.head; +} + +int +hintCacheNodeList_IterCheck(HintCacheNodeListIter iter) +{ + dlink_node *links = iter; + return (links->next != 0); +} + +void +hintCacheNodeList_IterNext(HintCacheNodeListIter iter) +{ + HierNodeElem *elem; + + if (iter->next == 0) { + return; + } + + while (1) { + iter = iter->next; + /* + * Skip non-HC_Join elements by keeping going in that case. + */ + if (iter->next == 0) { + return; + } + elem = iter->data; + if (elem->action == HC_Join) { + return; + } + } + +} + +/* + *------------------------------------------------------------------ + * + * hintCacheNodelistIterGetAddr -- + * + * description. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +int +hintCacheNodelistIterGetAddr(HintCacheNodeListIter iter, struct sockaddr_in *ret) +{ + HierNodeElem *elem; + elem = iter->data; + *ret = elem->sin; + if (elem->action == HC_Join) { + return 1; + } + return 0; +} + + +/* + *------------------------------------------------------------------ + * + * currentTimeNS -- + * + * Return the current time in nanoseconds since Jan 1, 1970. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +static long long +currentTimeNS() +{ + static const long long NS_PER_SEC = 1000000000; + static const long long NS_PER_USEC = 1000; + int error; + struct timeval time; + long long ret; + + error = gettimeofday(&time, NULL); + assert(error != -1); + ret = NS_PER_SEC * (long long) time.tv_sec + + NS_PER_USEC * (long long) time.tv_usec; + return ret; +} + +/* + *------------------------------------------------------------------ + * + * printList -- + * + * Print the current list of nodes to stdout. + * + * Arguments: + * None. + * + * Results: + * None. + * + * Side effects: + * None. + * + + *------------------------------------------------------------------ + */ +static void +printList() +{ + HintCacheNodeListIter iter; + struct sockaddr_in nodeAddr; + int valid; + + for (hintCacheNodeListIterStart(iter); + hintCacheNodeListIterCheck(iter); hintCacheNodeListIterNext(&iter)) { + valid = hintCacheNodeListIterGetAddr(iter, &nodeAddr); + if (valid) { + debug(HCNODES_DEBUG, 2) + ("\t%d.%d.%d.%d\n", + (unsigned char) ((nodeAddr.sin_addr.s_addr & 0xFF000000) >> 24), + (unsigned char) ((nodeAddr.sin_addr.s_addr & 0x00FF0000) >> 16), + (unsigned char) ((nodeAddr.sin_addr.s_addr & 0x0000FF00) >> 8), + (unsigned char) ((nodeAddr.sin_addr.s_addr & 0x000000FF) >> 0)); + } + } +} + + +#ifdef DOTEST +/* + *------------------------------------------------------------------ + * + * hintCacheNodelistSelfTest -- + * + * description. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +void +hintCacheNodelistSelfTest(void) +{ + struct sockaddr_in n0, n1, n2; + HintCacheNodeListIter iter; + struct sockaddr_in nodeAddr; + int nhops; + int valid; + int found = 0; + + printf("HintCacheNodelistSelfTest..."); + n0.sin_addr.s_addr = 0x90536F00; + n0.sin_port = 0; + n1.sin_addr.s_addr = 0x91536F01; + n1.sin_port = 1; + n2.sin_addr.s_addr = 0x92536F02; + n2.sin_port = 2; + + hintCacheNodelistInit(); + hintCachePlax_Init(8); + + assert(neighborsOutgoing == NULL); + neighborsOutgoing = (HintCacheNet *) xmalloc(sizeof(HintCacheNet)); + assert(neighborsOutgoing); + hintCacheNet_Init(neighborsOutgoing); + hintCacheNet_SetTestMode(neighborsOutgoing); + + + /* + * How to test if this really works? For now look at how many + * outgoing messages were enqueued. + */ + hintCacheNodelistLocalJoin(); + hintCacheNodelistLocalLeave(); + assert(hintCacheNet_GetTestCount(neighborsOutgoing) == 2); + + /* + * Expected final state: + * n0 JOIN dist = 12 + * n1 LEAVE XXX + * n2 JOIN dist=20 + */ + hintCacheNodelistNetJoin(&n0, 10, 42); + hintCacheNodelistNetJoin(&n2, 20, 42); + hintCacheNodelistNetJoin(&n0, 13, 43); + hintCacheNodelistNetJoin(&n1, 20, 42); + hintCacheNodelistNetJoin(&n2, 20, 100); + hintCacheNodelistNetJoin(&n0, 9, 42); + hintCacheNodelistNetJoin(&n0, 12, 43); + hintCacheNodelistNetJoin(&n2, 20, 42); + hintCacheNodelistNetLeave(&n1, 999, 43); + hintCacheNodelistNetJoin(&n1, 19, 42); + + for (hintCacheNodeListIterStart(&iter); + hintCacheNodeListIterCheck(iter); hintCacheNodeList_IterNext(&iter)) { + valid = hintCacheNodeListIterGetAddr(iter, &nodeAddr); + if (valid) { + nhops = netdbHintHops(nodeAddr.sin_addr); + if (nodeAddr.sin_addr.s_addr == n0.sin_addr.s_addr) { + found++; + assert(nhops == 12); + } + if (nodeAddr.sin_addr.s_addr == n2.sin_addr.s_addr) { + found++; + assert(nhops = 20); + } + if (nodeAddr.sin_addr.s_addr == n1.sin_addr.s_addr) { + assert(0); + } + } + } + assert(found == 2); + + hintCacheNodelistDestroy(); + hintCachePlaxDestroy(); + + hintCacheNetDestroy(neighborsOutgoing); + free(neighborsOutgoing); + neighborsOutgoing = NULL; + + printf("..OK\n"); + +} + +#endif /* DOTEST */ Index: squid/src/HintCachePrim.c diff -u /dev/null squid/src/HintCachePrim.c:1.1.2.2 --- /dev/null Mon Jan 26 04:57:38 2004 +++ squid/src/HintCachePrim.c Mon May 20 19:46:42 2002 @@ -0,0 +1,404 @@ +/* + * $Date: 2004/08/17 20:55:13 $ $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ + * + * DEBUG: section 89 List of known caches. + * AUTHOR: Mike Dahlin, UT Austin, 1998 + * + * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ + * -------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from the + * Internet community. Development is led by Duane Wessels of the + * National Laboratory for Applied Network Research and funded by + * the National Science Foundation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +/* + *------------------------------------------------------------------ + * LESS Group + * Computer Sciences Department + * University of Texas at Austin + * + * HCPrimitives.h --- Primitive types for hint cache. + *------------------------------------------------------------------ + */ +#include "squid.h" +#include + + +const URLKey INVALID_URL_KEY = { 0 }; + +static HintCacheKey calculateStupidKey(char *url); +static void makeLowerCase(char *url); + +const static int useMD5 = 1; + + +/* + *------------------------------------------------------------------ + * + * URLKey -- + * + * The first 64 bits of the 128-bit Squid/Cache Digest URL key. + */ + + + +/* + * Make lower case, but stop at third '/' (e.g., after the hostname). + */ +static void +makeLowerCase(char *url) +{ + int len, ii; + int slashCount = 0; + + assert(url); + len = strlen(url); + for (ii = 0; ii < len; ii++) { + /* + * Alignment. + */ + if (url[ii] == '/') { + slashCount++; + if (slashCount == 3) { + return; + } + } + url[ii] = tolower(url[ii]); + } +} + + +/* functional encapsulation of the ever-popular macro of the + same name. Needed for hash table. */ +int +hintCacheURLKeyCompare(URLKey *u1, URLKey *u2) +{ + return(URLKEY_COMPARE(*u1, *u2)); +} + +/* + * Retrieve entry using hint_table. + * The hint_table keeps a pointer to the hchash part of th + * StoreEntry, so we apply the appropriate offset to + * retrieve the StoreEntry itself. + */ +StoreEntry * +hintCacheStoreGet(URLKey urlkey) +{ + hash_link *hchash; + StoreEntry *entry; + int hchoff; + + hchash = (hash_link *) hash_lookup(store_table, &urlkey); + hchoff = (u_char *) &entry->hchash - (u_char *) entry; + entry = (StoreEntry *) ((u_char *) hchash - hchoff); + return(entry); +} + + +void +hintCacheNetURLKeyNetInit(URLKeyNet * mungedKey, URLKey * key) +{ + mungedKey->mungedKey = hintCacheEndian_llMachineToNet(key->key); +} + +void +hintCacheNetURLKeyLocalFormat(URLKeyNet * mungedKey, URLKey * key) +{ + key->key = hintCacheEndian_llNetToMachine(mungedKey->mungedKey); +} + + + +/* + *------------------------------------------------------------------ + * + * NodeKey -- + * + * A pair (plus stuff to + * put it on a list. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------4.9.1998-------- + */ +void +hintCacheNodeKeyInit(NodeKey * k, const struct sockaddr_in *addrP) +{ + assert(k); + assert(addrP); + + k->links.data = k; + k->links.next = k->links.prev = 0; + k->key = hintCacheNodeKeyKey(addrP); + k->addr = *addrP; +} + +int +hintCacheNodeKeyCompare(const NodeKey * k1, const NodeKey * k2) +{ + assert(k1); + assert(k2); + if (k1->key != k2->key) { + return 1; + } + return 0; +} + +struct sockaddr_in +hintCacheNodeKeyGetAddr(const NodeKey * k) +{ + assert(k); + return k->addr; +} + +HintCacheKey +hintCacheNodeKeyKey(const struct sockaddr_in * addrP) +{ + HintCacheKey k; + char *name; + + name = inet_ntoa(addrP->sin_addr); + k = *(HintCacheKey *) storeKeyPublic(name, METHOD_PUT); + return k; +} + + +/* + *------------------------------------------------------------------ + * + * hintCacheEntry -- + * + * A structure including a pair. Generally + * points to the nearest copy of the specified url. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +void +hintCacheEntryInit(HintCacheEntry * entry, URLKey key, struct sockaddr_in *saddr, + unsigned int mtime) +{ + entry->key = key; + entry->ipaddr = saddr->sin_addr; + entry->port = saddr->sin_port; + entry->pad = 0; + entry->mtime = mtime; +} + +int +hintCacheEntryCompare(HintCacheEntry * e1, HintCacheEntry * e2) +{ + /* + * If you add a field, you must change this code. + */ + if (URLKEY_COMPARE(e1->key, e2->key)) { + return 1; + } + + if (e1->ipaddr.s_addr != e2->ipaddr.s_addr) + return 1; + + if (e1->port != e2->port) + return 1; + + if (e1->mtime != e2->mtime) + return 1; + + return 0; +} + +void +hintCacheNetEntryInit(HintCacheEntryNet * mungedEntry, HintCacheEntry * entry) +{ + /* + * If you add a field, you must change this code. + */ + URLKeyNetInit(&mungedEntry->mungedKey, &entry->key); +/* mungedEntry->mungedIpaddr.s_addr = htonl(entry->ipaddr.s_addr);*/ + mungedEntry->mungedIpaddr.s_addr = entry->ipaddr.s_addr; + mungedEntry->mungedPort = htons(entry->port); + mungedEntry->mungedMtime = htonl(entry->mtime); +} + +void +hintCacheEntryLocalFormatNet(HintCacheEntryNet * mungedEntry, HintCacheEntry * entry) +{ + /* + * If you add a field, you must change this code. + */ + URLKeyLocalFormatNet(&mungedEntry->mungedKey, &entry->key); +/* entry->ipaddr.s_addr = ntohl(mungedEntry->mungedIpaddr.s_addr);*/ + entry->ipaddr.s_addr = mungedEntry->mungedIpaddr.s_addr; + entry->port = ntohs(mungedEntry->mungedPort); + entry->mtime = htonl(mungedEntry->mungedMtime); +} + + +/* + *------------------------------------------------------------------ + * + * HCUpdate -- + * + * An update is a HintCacheEntry and an action. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +void +hintCacheUpdateInit(HintCacheUpdate * u, int action, HintCacheEntry * entry, int hopcount) +{ + u->action = action; + u->hopcount = hopcount; + u->UNUSED = 0; /* remove this field sometime */ + u->entry = *entry; +} + +void +hintCacheUpdateSelfTest() +{ + HintCacheUpdate update; + HintCacheUpdateNet netupd; + + /* HintCacheUpdate must be at least this min size */ + assert(sizeof(HintCacheUpdate) >= HCU_MINLEN); + + /* Test that some field in update has expected offset */ + assert((char *) &update.entry - (char *) &update == 8); + assert((char *) &netupd.mungedEntry - (char *) &netupd == 8); + + /* Make sure net version of struct stays in sync. */ + assert(sizeof(HintCacheUpdate) == sizeof(HintCacheUpdateNet)); +} + +void +hintCacheUpdateInitNet(HintCacheUpdateNet * mupdate, HintCacheUpdate * update) +{ + /* No need for htonl on action, hopcount, or len - they are single bytes. */ + mupdate->mungedAction = update->action; + mupdate->mungedUNUSED = update->UNUSED; /* remove this field sometime */ + mupdate->mungedHopcount = update->hopcount; + mupdate->mungedPad1 = -1; + mupdate->mungedPad2 = -1; +/* mupdate->mungedCchange = htonl(update->cchange); XXX - NOTYET */ + + hintCacheEntryInitNet(&mupdate->mungedEntry, &update->entry); +} + + +void +hintCacheUpdateLocalFormatNet(HintCacheUpdateNet * mupdate, HintCacheUpdate * update) +{ + /* No need for htonl on action or len - they are single bytes. */ + update->action = mupdate->mungedAction; + update->UNUSED = mupdate->mungedUNUSED;; + update->hopcount = mupdate->mungedHopcount; +/* update->cchange = ntohl(mupdate->mungedCchange); XXX - NOTYET */ + + hintCacheEntryLocalFormatNet(&mupdate->mungedEntry, &update->entry); +} + +int +hintCacheUpdateCompare(HintCacheUpdate * u1, HintCacheUpdate * u2) +{ + if ((u1->action != u2->action) + || (u1->hopcount != u2->hopcount) + || (hintCacheEntry_Compare(&u1->entry, &u2->entry))) { + return 1; + } + return 0; +} + +#ifdef DOTEST +/* + *------------------------------------------------------------------ + * + * primitivesSelfTest -- + * + * description. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +void +primitivesSelfTest() +{ + + URLKey urlKey, urlKey2; + URLKeyNet netUrlKey; + char url[128]; + HintCachEntry hcEntry, hcEntry2; + HintCacheEntry netHintCacheEntry; + HintCacheUpdate hcUpdate, hcUpdate2; + HintCacheUpdateNet netHintCacheUpdate; + struct sockaddr_in saddr = { AF_INET, 0, {{{0, 0, 0, 0}}} }; + + printf("primitivesSelfTest().."); + + sprintf(url, "http://www.cs.Utexas.edu"); + hintCacheURLKey_Init(&urlKey, url); + Net_URLKey_Init(&netUrlKey, &urlKey); + URLKeyLocalFormatNet(&netUrlKey, &urlKey2); + assert(!URLKEY_COMPARE(urlKey, urlKey2)); + + hintCacheEntryInit(&hcEntry, urlKey, &saddr); + hintCacheEntryInitNet(&netHintCacheEntry, &hcEntry); + hintCacheEntryLocalFormatNet(&netHintCacheEntry, &hcEntry2); + assert(!hintCacheEntryCompare(&hcEntry, &hcEntry2)); + + hintCacheUpdateInit(&hcUpdate, HC_InvalToChild, &hcEntry, 1); + hintCacheUpdate_selfTest(); + hintCacheUpdateInitNet(&netHintCacheUpdate, &hcUpdate); + hintCacheUpdateLocalFormatNet(&netHintCacheUpdate, &hcUpdate2); + assert(!HintCacheUpdate_Compare(&hcUpdate, &hcUpdate2)); + + printf(".OK\n"); +} +#endif /* DOTEST */ Index: squid/src/Makefile.am diff -u squid/src/Makefile.am:1.24 squid/src/Makefile.am:1.8.2.5 --- squid/src/Makefile.am:1.24 Sun Sep 1 09:30:40 2002 +++ squid/src/Makefile.am Tue Sep 3 10:41:32 2002 @@ -52,6 +52,32 @@ SSLSOURCE = endif +if ENABLE_HINTS +HINTSOURCE = \ + HintCache.c \ + HintCacheDisk.c \ + HintCacheEndian.c \ + HintCacheHier.c \ + HintCacheNet.c \ + HintCacheNodes.c \ + HintCachePrim.c \ + HintCacheProp.c +else +HINTSOURCE= +endif + +if ENABLE_PLAXTON +PLAXSOURCE = Plaxton.c +else +PLAXSOURCE = +endif + +if ENABLE_ICP_DATA +ICPDATASOURCE = icp_data.c +else +ICPDATASOURCE = +endif + if ENABLE_WIN32SPECIFIC WIN32SOURCE = win32.c else @@ -74,6 +100,7 @@ squid bin_PROGRAMS = \ + webpush \ squidclient libexec_PROGRAMS = \ @@ -122,6 +149,7 @@ defines.h \ $(DELAY_POOL_SOURCE) \ disk.c \ + dist.c \ $(DNSSOURCE) \ enums.h \ errorpage.c \ @@ -136,6 +164,7 @@ globals.h \ gopher.c \ helper.c \ + $(HINTSOURCE) \ $(HTCPSOURCE) \ http.c \ HttpStatusLine.c \ @@ -151,6 +180,7 @@ icmp.c \ icp_v2.c \ icp_v3.c \ + $(ICPDATASOURCE) \ ident.c \ internal.c \ ipc.c \ @@ -168,7 +198,9 @@ pconn.c \ peer_digest.c \ peer_select.c \ + $(PLAXSOURCE) \ protos.h \ + put.c \ redirect.c \ referer.c \ refresh.c \ @@ -283,6 +315,7 @@ DEFAULT_ICON_DIR = $(datadir)/icons DEFAULT_ERROR_DIR = $(datadir)/errors/@ERR_DEFAULT_LANGUAGE@ DEFAULT_MIB_PATH = $(datadir)/mib.txt +DEFAULT_HINT_FILE = $(DEFAULT_SWAP_DIR)/hints DEFAULT_HOSTS = @OPT_DEFAULT_HOSTS@ DEFS = @DEFS@ -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\" @@ -333,6 +366,7 @@ s%@DEFAULT_ICON_DIR@%$(DEFAULT_ICON_DIR)%g;\ s%@DEFAULT_MIB_PATH@%$(DEFAULT_MIB_PATH)%g;\ s%@DEFAULT_ERROR_DIR@%$(DEFAULT_ERROR_DIR)%g;\ + s%@DEFAULT_HINT_FILE@%$(DEFAULT_HINT_FILE)%g;\ s%@DEFAULT_PREFIX@%$(DEFAULT_PREFIX)%g;\ s%@DEFAULT_HOSTS@%$(DEFAULT_HOSTS)%g;"\ < $(srcdir)/cf.data.pre >$@ Index: squid/src/Plaxton.c diff -u /dev/null squid/src/Plaxton.c:1.1.2.2 --- /dev/null Mon Jan 26 04:57:38 2004 +++ squid/src/Plaxton.c Mon May 20 19:46:42 2002 @@ -0,0 +1,2440 @@ +/* + * $Date: 2004/08/17 20:55:13 $ $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ + * + * DEBUG: section 91 Greg Plaxton's per-object hierarchy. + * AUTHOR: Mike Dahlin, UT Austin, 1998 + * + * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ + * -------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from the + * Internet community. Development is led by Duane Wessels of the + * National Laboratory for Applied Network Research and funded by + * the National Science Foundation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +/* + *------------------------------------------------------------------ + * LESS Group + * Computer Sciences Department + * University of Texas at Austin + * + * Plaxton.c --- Dynamic algorithm via plaxton's algorithm. + *------------------------------------------------------------------ + */ + +/* + * Plaxton.c interface notes, from Mike Dahlin's comments in HCPlax.h: + * + * Each children queue holds messages that should go to a set of + * "equivalent" children (eg. the children at some level of the + * hierarchy.) There are HCHPlax_NChildrenQs() such queues; + * num = HCPlax_GetChildAddrs(q, arraypointer) allocates + * an array of addresses for a particular queue and returns + * the number of children. + * The rule is simple -- when I send a message to children about + * an object, I send it to all children who match that object's + * key in fewer bits than I do. + * + * Each parent queue holds messages that should go to one parent. + * In general, we may have different parents for different objects. + * So, enqueue messages for an object in the queue + * HCPlax_ParentQIndex(URLKey). + * + * We also need to help figure out the hierarchy for Plaxton's + * algorithm. Plaxton's algorithm figures out who the parents + * are, but it doesn't know who the children are. We observe + * messages to keep in sync. + * On recv message: + * recv parent msg from parent: process parent message + * recv child msg from child: process child message + * recv parent msg from !parent: send "I am not child" to parent; + * drop message + * recv child msg from !child: add child to child list; + * process child message + * recv "I am not child" from child: remove child + */ + +#include "squid.h" + + +#define HCPLAX_DEBUG 91 + +/* + * Array [BITS_PER_BYTE * sizeof(HintCacheNodeKeyKey) + 1] of dlink_nodes + */ +#define BITS_PER_BYTE 8 +#define BITS_PER_KEY (8 * sizeof(HintCacheKey)) + +static HintCacheKey myNodeKey; + +static int initialized = 0; + +/* + * For keeping track of children + */ +static int nChildLists = -9999; +static dlink_list *childrenListA; +static int *childrenCountA = NULL; /* Entry i is the number of children + * that match in i bits. */ +static int childrenCountTot = 0; + +/* + * For keeping track of parents + */ +int Plaxton_bucketsPerLevel = -999; +static int nParentLevels = -999; +static int bitsPerLevel = -999; +static int maxParentBucket = -9999; +/* + * parentListA is an array [nParentLevels][Plaxton_bucketsPerLevel] + * where entry k = l*bitsPerLevel + i (0 <= i < 2^bitsPerLevel) + * contains a list of all known nodes whose node key matches + * the local node key in the lowest l*bitsPerLevel bits + * and whose next bitsPerLevel bits have the same bit pattern + * as i + * For example, with bitsPerLevel = 2, if our local node key + * were 010110, a node with key 111010 would belong in level 1 + * (since the bottom two bits match us but the next two bits dont + * in entry 10), so node 111010 would go into bucket + * 1*Plaxton_bucketsPerLevel + 10 = 4 + 2 = 6. + * Maintain the invariant that the entries in each bucket are sorted + * by their distance from me with the closest node always + * at the head of its list. + */ +static dlink_list *parentListA = NULL; +/* + * Special case of parent finding when I match in as many bits + * as anyone. In case of a tie for root, + * we all need to agree on whom among us is the root. We need + * to do so in a way that avoids loops (and hopefully which + * gets everyone to agree on the same root.) Solution: if + * an object matches me in k bits and I know of no node + * that matches the object in more than k bits, choose as + * the root for that object, the node that matches the + * object (and me) in k bits and which has the highest + * known NodeKey. + * + * highestMatchA is an array [BITS_PER_KEY] where entry k + * contains a list of all nodes that match me in at least + * the bottom k bits. The lists all include me. The lists + * are sorted by the integer value of the key with the + * largest value at the head of the list. + */ +static dlink_list *highestMatchA = NULL; + +static int normalParentIndex(int bucket); +static int fullMatchIndex(HintCacheKey k); +static int firstLevelBucketForMatch(int matchBits); +static int highestMatchIndex(int matchBits); +static void childAdd _PARAMS((HintCacheNodeKey * key)); +static HintCacheNodeKey *childFind _PARAMS((HintCacheNodeKey * key)); +static void freeList(dlink_list * list); +static void addNodeParentList(struct sockaddr_in *addNode); +static void removeNodeParentList(struct sockaddr_in *goneNode); +static void changeDistanceParentList(struct sockaddr_in *changeDistNode); +static int parentListIndex(HintCacheNodeKey * n); +static void addNodeHighestMatch(struct sockaddr_in *addNode); +static void matchInsert(dlink_list *l, struct sockaddr_in *a); +static void removeNodeHighestMatch(struct sockaddr_in *goneNode); +static void matchRemove(dlink_list *l, struct sockaddr_in *a); +static int scanForParentMatch(int maxTry, int minTry, const URLKey * key, + int *parentIndexRet, int *amIRootRet); +static HintCacheKey makeMatchKey(const URLKey * key, int matchBits, + int permuteVal); + +#ifdef DOTEST +static void selfTestChildren(); +static int selfTestFindAddr(int addr, struct sockaddr_in *childrenA, + int childCount); +static void selfTestParents(); +static void testParentsBinaryTree(void); +static void testParentsMultiRootCase(void); +static void stressTestParents(void); +static void testParentsInternals(void); +static void testParentsInternals2(void); +static void testMakeMatchKey(void); +#endif /* DOTEST */ + +/* + *------------------------------------------------------------------ + * + * plaxtonInit -- + * + * description. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------4.15.1998----------- + */ +void +plaxtonInit(int bitsPerLevel_) +{ + int ii; + int nParentBuckets; + struct sockaddr_in *me = &Config.Sockaddr.http->s; + HintCacheNodeKey *key; + + assert(nChildLists < 0); /* We shouldn't be initialized yet */ + + assert(!initialized); + initialized = 1; + + myNodeKey = NodeKK_Key(me); + /* + * List i contains all children that match me in i bits. + * Legal values for i are [0, BITS_PER_KEY] + */ + nChildLists = BITS_PER_KEY + 1; + assert(childrenListA == NULL); + childrenListA = (dlink_list *) xcalloc(nChildLists, sizeof(dlink_list)); + assert(childrenListA); + childrenCountA = (int *) xcalloc(nChildLists, sizeof(int)); + childrenCountTot = 0; + + /* + * Parents + */ + bitsPerLevel = bitsPerLevel_; + nParentLevels = (BITS_PER_KEY) / bitsPerLevel; + if ((BITS_PER_KEY) % bitsPerLevel != 0) { + nParentLevels++; + } + Plaxton_bucketsPerLevel = 1; + for (ii = 0; ii < bitsPerLevel; ii++) { + Plaxton_bucketsPerLevel *= 2; + } + nParentBuckets = Plaxton_bucketsPerLevel * nParentLevels; + maxParentBucket = nParentBuckets - 1; + assert(parentListA == NULL); + parentListA = (dlink_list *) xcalloc(nParentBuckets, sizeof(dlink_list)); + assert(parentListA); + assert(highestMatchA == NULL); + highestMatchA = (dlink_list *) xcalloc(BITS_PER_KEY, sizeof(dlink_list)); + assert(highestMatchA); + for (ii = 0; ii < BITS_PER_KEY; ii++) { + key = (HintCacheNodeKey *) xmalloc(sizeof(HintCacheNodeKey)); + hintCacheNodeKeyInit(key, &Config.Sockaddr.http->s); + dlinkAdd(key, &key->links, &highestMatchA[ii]); + } +} + +/* + *------------------------------------------------------------------ + * + * plaxtonDestroy -- + * + * description. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------4.16.1998------ + */ +void +plaxtonDestroy(void) +{ + int ii; + + assert(initialized); + initialized = 0; + + assert(nChildLists > 0); /* Are we initialized? */ + for (ii = 0; ii < nChildLists; ii++) { + freeList(&childrenListA[ii]); + } + xfree(childrenListA); + childrenListA = NULL; + xfree(childrenCountA); + childrenCountA = NULL; + childrenCountTot = -999999; + nChildLists = -88888; + + /* + * Parents + */ + for (ii = 0; ii < nParentLevels * Plaxton_bucketsPerLevel; ii++) { + freeList(&parentListA[ii]); + } + xfree(parentListA); + parentListA = NULL; + nParentLevels = -8888; + bitsPerLevel = -8888; + Plaxton_bucketsPerLevel = -8888; + for (ii = 0; ii < BITS_PER_KEY; ii++) { + freeList(&highestMatchA[ii]); + } + xfree(highestMatchA); + highestMatchA = NULL; +} + + +/* + *------------------------------------------------------------------ + * + * freeList -- + * + * Free all elements on a list of HintCacheNodeKeys + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.16.1998-------- + */ +static void +freeList(dlink_list *list) +{ + dlink_node *node; + HintCacheNodeKey *k; + + assert(list); + for (node = list->head ; node; node = node->next) { + k = node->data; + dlinkDelete(node, list); + xfree(k); + } +} + +/* + *------------------------------------------------------------------ + * + * plaxtonAddChild -- + * + * Add the specified child to the list of children. + * We keep a separate list of children for each + * number of bits that can match the local addrss key. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.9.1998--------- + */ +void +plaxtonAddChild(struct sockaddr_in *child) +{ + HintCacheNodeKey *key; + + assert(initialized); + assert(nChildLists > 0); /* Are we initialized? */ + key = (HintCacheNodeKey *) xmalloc(sizeof(HintCacheNodeKey)); + hintCacheNodeKeyInit(key, child); + if (childFind(key)) { + xfree(key); + return; + } + childAdd(key); +} + +/* + *------------------------------------------------------------------ + * + * plaxtonRemoveChild -- + * + * Remove the specified child from its list of children. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------4.9.1998----- + */ +void +plaxtonRemoveChild(struct sockaddr_in *child) +{ + HintCacheNodeKey key, *found; + int match; + + assert(initialized); + assert(nChildLists > 0); /* Are we initialized? */ + hintCacheNodeKeyInit(&key, child); + found = childFind(&key); + if (found) { + dlinkDelete(&found->links, + List_Remove((dlink_node *) found); + xfree(found); + match = plaxtonMatchBits(key.key, myNodeKey); + childrenCountA[match]--; + childrenCountTot--; + assert(childrenCountA[match] >= 0); + assert(childrenCountTot >= 0); + return; + } + return; +} + + +/* + *------------------------------------------------------------------ + * + * plaxtonCheckIfChild -- + * + * Return nonzero if the specified node is listed + * as a child. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.9.1998------ + */ +int +plaxtonCheckIfChild(struct sockaddr_in *child) +{ + HintCacheNodeKey key, *found; + + assert(initialized); + assert(nChildLists > 0); /* Are we initialized? */ + hintCacheNodeKeyInit(&key, child); + found = childFind(&key); + if (found != NULL) { + return 1; + } + return 0; +} + + + + + +/* + *------------------------------------------------------------------ + * + * plaxtonChildQIndex -- + * + * Return the queue for which messages about the specified + * object should be stored. + * + * The rule is simple -- when I send a message to children about + * an object, I send it to all children who match that object's + * key in fewer bits than I do. (Unless I am the root + * for that object, in which case I send info to all + * nodes that think of me as a parent.) + * + * So, store messages for an object that matches me in i bits + * in queue i. Later, we will send it to all children + * that match me in i or fewer bits. (Store messages + * for objects for which I am root in queue nChildLists-1). + * + * As an optimization, if I have no children that match + * me in i or fewer bits, set *amILeaf to nozero. In that + * case, the caller may choose not to enqueue any message. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------5.1.1998------ + */ +int +plaxtonChildQIndex(URLKey * key, int iAmRoot, int *amILeaf) +{ + int match; + int leafCheck; + + assert(initialized); + assert(nChildLists > 0); /* Are we initialized? */ + + + if (iAmRoot) { + if ( /*childrenCountTot > 0 */ 1) { /* XXX */ + *amILeaf = 0; + return nChildLists - 1; + } else { + *amILeaf = 1; + return -999; + } + } + + match = plaxtonMatchBits(key->key, myNodeKey); + /* + * Check to see if I am a leaf for this object by looking + * at all childlists for children that match me in fewer bits + * than this object. If all such lists are empty, than I am + * a leaf. This is less inefficient than it seems. The expected + * number of queues I have to check is less than (1 + .5 + .25 + ...) + * (since I match in 0 bits half the time, ... ) + */ + *amILeaf = 1; + for (leafCheck = match - 1; leafCheck >= 0; leafCheck--) { + if (!List_IsEmpty(&childrenListA[leafCheck])) { + *amILeaf = 0; + break; + } + } + return match; +} + +/* + *------------------------------------------------------------------ + * + * plaxtonNChildrenQs -- + * + * Return the number of queues of messages for children + * caller should allocate. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------4.10.1998--- + */ +int +plaxtonNChildrenQs(void) +{ + assert(initialized); + assert(nChildLists > 0); /* Are we initialized? */ + return nChildLists; +} + + +/* + *------------------------------------------------------------------ + * + * plaxtonGetChildAddrs -- + * + * Return the number of children for the specified message + * queue, allocate a buffer for that many addresses, + * and fill in that buffer with the children's addresses. + * + * Notice -- the question being asked is "to whom should + * I send messages for objects that match me in k bits?" + * The answer is all nodes that match in k *or fewer* bits. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * Allocates a vector for the addresses. Caller must free + * this vector when done. + * + * Note: the vector may be out of date by the time ther caller + * uses it. This is inherent problem -- even if caller sent + * all messages instantaneously, by the time they arrive + * at destination, the child could have left the system + * or a new child could have joined. + * + *----------------------------------------------------4.10.1998------- + */ +int +plaxtonGetChildAddrs(int qIndex, struct sockaddr_in **retAddrAP) +{ + dlink_node *node; + int count; + int imatch; + HintCacheNodeKey *current; + int check; + + assert(initialized); + for (imatch = 0, count = 0; imatch <= qIndex; imatch++) { + count += childrenCountA[imatch]; + } + if (!count) { + *retAddrAP = NULL; + return 0; + } + *retAddrAP = + (struct sockaddr_in *) xmalloc(count * sizeof(struct sockaddr_in)); + for (imatch = 0, count = 0; imatch <= qIndex; imatch++) { + check = 0; + for (node = childrenListA[imatch].head; node; node = node->next) { + current = node->data; + check++; + (*retAddrAP)[count] = hintCacheNodeKeyGetAddr(current); + count++; + debug(HCPLAX_DEBUG, 2) + ("plaxtonGetChildAddrs: sending msg to child %s\n", + inet_ntoa((*retAddrAP)[count].sin_addr)); + } + assert(check == childrenCountA[imatch]); + } + return count; +} + + +/* + *------------------------------------------------------------------ + * + * nParentQs -- + * + * Return the number of parent q's to allocate. + * We need to account for both the normal case + * when we find a parent that matches an object + * in more bits than we do, and the root + * case when we match in k bits and so do some + * other nodes, but no one matches in more than + * k bits; in that case, we may not send + * to the closest node that matches us in k bits. + * + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.15.1998------- + */ +int +plaxtonNParentQs(void) +{ + int normalParentCount, rootCaseCount; + + assert(initialized); + assert(parentListA != NULL); + normalParentCount = nParentLevels * Plaxton_bucketsPerLevel; + rootCaseCount = BITS_PER_KEY; + return normalParentCount + rootCaseCount; +} + + +/* + *------------------------------------------------------------------ + * + * plaxtonParentQIndex -- + * + * Return the index of the parent queue to use + * for messages about the specified URLKey or + * set amIRoot to true if I have no parent + * for that object. + * + * I am trying to find someone who matches + * the object in more bits than I do. To + * reduce the number of levels of hierarchy + * I try to match bitsPerLevel bits at a + * time. + * + * If I match in at least l*bitsPerLevel bits but + * not in (l+1)*bitsPerLevel bits, then + * the parent is the node that matches in + * the most bits between (l+1)*bPL and (l)*bPL + * + * If there are multiple potential parents + * that match in the same number of bits, choose + * the closest one (all parent lists are maintained + * in sorted order) unless I also match the + * object in that many bits; in the latter case + * we need to decide on a root from among + * several equally qualified candidates. We + * always choose the node with the highest + * NodeKey in that case. + * + * Note the key invariant for avoiding loops: + * my parent always matches an object in more + * bits than I do or matches in as many bits + * as I do and has a higher ID. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.19.1998--------- + */ +int +plaxtonParentQIndex(URLKey * key, int *amIRoot) +{ + int match; + int nextLevelMatch; + int found, pindex; + + assert(initialized); + /* XXX */ + match = plaxtonMatchBits(key->key, myNodeKey); + if (match == nParentLevels * bitsPerLevel) { + /* + * Match all bits. I am root! + */ + *amIRoot = 1; + return -9999999; + } + + /* + * Try for full or partial match at next level. + */ + nextLevelMatch = ((match + bitsPerLevel) / bitsPerLevel) * bitsPerLevel; + found = scanForParentMatch(nextLevelMatch, match + 1, key, + &pindex, amIRoot); + if (found) { + assert(!*amIRoot); + return normalParentIndex(pindex); + } + + + /* + * I match in match bits, and didn't find anyone that matches + * in more. But, there may be other nodes that match the object + * in the same number of bits (but differ from me in some higher bit). + * We all need to agree on whom among us is the root. We need + * to do so in a way that avoids loops (and hopefully which + * gets everyone to agree on the same root.) Solution: if + * an object matches me in k bits and I know of no node + * that matches the object in more than k bits, choose as + * the root for that object, the node that matches the + * object (and me) in k bits and which has the highest + * known HintCacheNodeKey. + */ + assert(!List_IsEmpty(&highestMatchA[match])); + if (((HintCacheNodeKey *) List_First(&highestMatchA[match]))->key == myNodeKey) { + *amIRoot = 1; + return -999999; + } else { + *amIRoot = 0; + return highestMatchIndex(match); + } +} + + +/* + *------------------------------------------------------------------ + * + * scanForParentMatch -- + * + * Find the bucket index in parentsListA for + * a node matching between maxTry and minTry + * bits (inclusive) for the specified key. + * Return true if parent found and set + * parentIndexRet and amIRootRet. + * + * As we look at fewer and fewer bits we + * need to try all combinations of the + * high-order bits we are masking off. + * We currently do this by probing different + * entries in the table. It would be more + * efficient to maintain auxiliary data + * structures with all eligible nodes, + * but the data structures here are already + * more complicated than I like; Make it + * work first, then optimize performance later. + * + * Return the node that matches in the most + * possible bits. If more than one node + * matches in a specific # of bits, return the + * closest. + * + * Arguments: + * None. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +static int +scanForParentMatch(int maxTry, int minTry, const URLKey * key, + int *parentIndexRet, int *amIRootRet) +{ + HintCacheNodeKey *nk; + HintCacheKey tryKey; + int matchBits, permuteBits, permuteMax, ipermute; + int tryIndex; + int found = 0, bestIndex = -999999; + struct sockaddr_in bestSin, trySin; + + /* + * This code assumes that we are looking to match + * a "level" in the tree. + */ + assert(maxTry % bitsPerLevel == 0); + assert(maxTry - minTry < bitsPerLevel); + + for (matchBits = maxTry; matchBits >= minTry; matchBits--) { + /* + * Split the address into two parts, a set of low-order bits + * that must match the target and a set of high-order + * bits that are "don't care" for which we'll try all + * permutations. + */ + permuteBits = maxTry - matchBits; + permuteMax = (1 << permuteBits) - 1; + for (ipermute = 0; ipermute <= permuteMax; ipermute++) { + tryKey = makeMatchKey(key, matchBits, ipermute); + tryIndex = fullMatchIndex(tryKey); + if (parentListA[tryIndex].head != 0) { + /* parentListA[tryIndex] is not empty */ + nk = parentListA[tryIndex].head->data; + if (!found) { + found = 1; + *amIRootRet = 0; + bestSin = hintCacheNodeKeyGetAddr(nk); + bestIndex = tryIndex; + } else { + trySin = hintCacheNodeKeyGetAddr(nk); + if (HCHier_compareDistanceFromMe(bestSin.sin_addr, + trySin.sin_addr) > 0) { + bestSin = trySin; + bestIndex = tryIndex; + assert(*amIRootRet == 0); + } + } + } + } + if (found) { + assert(*amIRootRet == 0); + *parentIndexRet = bestIndex; + return 1; + } + } /* for matchBits */ + assert(!found); + return 0; +} + + +/* + *------------------------------------------------------------------ + * + * makeMatchKey -- + * + * Return a key that matches the specified key in the + * bottom bits, and add the prefix + * permuteVal to the front. Remaining bits are all 0. + * For example, if key is 110101101, matchBits is 4, + * and permuteVal is 3 (11), then return + * 000111101 (zero-fill: 000 prefix: 11 match: 1101). + * + * Arguments: + * None. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +static HintCacheKey +makeMatchKey(const URLKey * key, int matchBits, int permuteVal) +{ + HintCacheKey tryKey, matchMask; + + matchMask = (((HintCacheKey) 1) << matchBits) - 1; + tryKey = (key->key & matchMask) | (permuteVal << matchBits); + return tryKey; +} + + +/* + *------------------------------------------------------------------ + * + * highestMatchIndex -- + * + * Return the network buffer index that we should + * use for messages to the root node for objects + * that match us and some other node in + * bits and match no node in more than + * bits. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *--------------------------------------------------------4.15.1998----- + */ +static int +highestMatchIndex(int match) +{ + return maxParentBucket + 1 + match; +} + +/* + *------------------------------------------------------------------ + * + * normalParentIndex -- + * + * Return the network buffer index that we should + * use for parents that match in the specified bucket + * (where bucket is calculated as matchLevel * 2^bitsPerLevel + * + key%2^bitsPerLevel). + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------4.15.1998---- + */ +static int +normalParentIndex(int bucket) +{ + assert(bucket <= maxParentBucket); + return bucket; +} + +/* + *------------------------------------------------------------------ + * + * firstLevelBucketForMatch -- + * + * Return the index of the first bucket for the set + * of buckets for the first non-matching level for + * a key that we match in matchBits. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.19.1998------- + */ +static int +firstLevelBucketForMatch(int match) +{ + int level; + + assert(match <= BITS_PER_KEY); + level = (match / bitsPerLevel) * Plaxton_bucketsPerLevel; + return level; +} + + + +/* + *------------------------------------------------------------------ + * + * plaxtonGetParentAddr -- + * + * Return the address to whom to send messages + * from the specified parent queue in *retAddr. + * Return nonzero on error. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.16.1998-------- + */ +int +plaxtonGetParentAddr(int index, struct sockaddr_in *retAddr) +{ + assert(initialized); + assert(index >= 0); + assert(parentListA != NULL); + if (index <= maxParentBucket) { + if (!List_IsEmpty(&parentListA[index])) { + *retAddr = ((HintCacheNodeKey *) List_First(&parentListA[index]))->addr; + debug(HCPLAX_DEBUG, 2) + ("plaxtonGetParentAddr: Sending msg to parent %s\n", + inet_ntoa(retAddr->sin_addr)); + return 0; + } else { + return 1; + } + } else { + /* XXX index = index - maxParentBucket; */ + index = index - maxParentBucket - 1; + assert(index < BITS_PER_KEY); + assert(index >= 0); + /* + * List always contains at least me + */ + assert(!List_IsEmpty(&highestMatchA[index])); + if (((HintCacheNodeKey *) List_First(&highestMatchA[index]))->key == myNodeKey) { + return 1; + } else { + *retAddr = ((HintCacheNodeKey *) List_First(&highestMatchA[index]))->addr; + debug(HCPLAX_DEBUG, 2) + ("plaxtonGetParentAddr: Sending msg to parent %s\n", + inet_ntoa(retAddr->sin_addr)); + return 0; + } + } +} + +/* + *------------------------------------------------------------------ + * + * HCPLax_addNode -- + * + * Add a node to the lists of parents. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-----------------------------------------------------4.16.1998-------- + */ +void +plaxtonAddNode(struct sockaddr_in *newNode) +{ + assert(initialized); + assert(newNode); +#if 1 /* XXX! - disabling parent&child lists */ + addNodeParentList(newNode); +#endif + addNodeHighestMatch(newNode); + return; +} + +/* + *------------------------------------------------------------------ + * + * plaxtonRemoveNode -- + * + * Remove thenode from the lists of parents. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-----------------------------------------------------4.16.1998------ + */ +void +plaxtonRemoveNode(struct sockaddr_in *goneNode) +{ + assert(initialized); + assert(goneNode); + removeNodeParentList(goneNode); + removeNodeHighestMatch(goneNode); + return; +} + +/* + *------------------------------------------------------------------ + * + * plaxtonChangeDistance -- + * + * Change the distance (and perhaps the rank in sorted list) + * of the specified node. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-----------------------------------------------------4.16.1998------- + */ +void +plaxtonchangeDistance(struct sockaddr_in *changeDistNode) +{ + assert(initialized); + assert(changeDistNode); + changeDistanceParentList(changeDistNode); + /* + * Don't need to tell HighestMatch list since that one is + * not sorted by distance. + */ + return; +} + +/* + *------------------------------------------------------------------ + * + * addNodeParentList -- + * + * See definition of parentListA where it is declared. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.16.1998----- + */ +static void +addNodeParentList(struct sockaddr_in *addNode) +{ + HintCacheNodeKey *n; + int index; + HintCacheNodeKey *current; + struct sockaddr_in s1, s2; + + n = (HintCacheNodeKey *) xmalloc(sizeof(HintCacheNodeKey)); + assert(n); + hintCacheNodeKeyInit(n, addNode); + + index = parentListIndex(n); + + + if (List_IsEmpty(&parentListA[index])) { + List_Insert((dlink_node *) n, LIST_ATFRONT(&parentListA[index])); + return; + } else { + LIST_FORALL2(&parentListA[index], HintCacheNodeKey *, current) { + if (HCHier_compareDistanceFromMe(hintCacheNodeKeyGetAddr(current).sin_addr, + addNode->sin_addr) > 0) { + List_Insert((dlink_node *) n, LIST_BEFORE(current)); + return; + } + /* + * Check invariant that list is sorted by distance from me. + */ + if ((dlink_node *) current != LIST_ATREAR(&parentListA[index])) { + s1 = hintCacheNodeKeyGetAddr(current); + s2 = hintCacheNodeKeyGetAddr((HintCacheNodeKey *) List_Next((dlink_node *) + current)); + assert(HCHier_compareDistanceFromMe(s1.sin_addr, + s2.sin_addr) <= 0); + } + } + } + List_Insert((dlink_node *) n, LIST_ATREAR(&parentListA[index])); + return; +} + +/* + *------------------------------------------------------------------ + * + * removeNodeParentList -- + * + * Remove the specified node from the parentList + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------4.16.1998--------- + */ +static void +removeNodeParentList(struct sockaddr_in *goneNode) +{ + int index; + dlink_node *node; + HintCacheNodeKey n, *current; + struct sockaddr_in s1, s2; + + hintCacheNodeKeyInit(&n, goneNode); + + index = parentListIndex(&n); + + for (node = parentListA[index]; node; node = node->next) { + current = node->data; + if (!hintCacheNodeKeyCompare(&n, current)) { + dlinkDelete(node, &parentListA[index]); + xfree(current); + return; + } + /* + * Check invariant that list is sorted by distance from me. + */ + if ((dlink_node *) current != LIST_ATREAR(&parentListA[index])) { + s1 = hintCacheNodeKeyGetAddr(current); + s2 = hintCacheNodeKeyGetAddr((HintCacheNodeKey *) List_Next((dlink_node *) current)); + assert(hintCacheHierCompareDistanceFromMe(s1.sin_addr, s2.sin_addr) <= 0); + } + } +} + +/* + *------------------------------------------------------------------ + * + * changeDistanceParentList -- + * + * Since we need to keep this list sorted by distance + * from me, we need to reorder it if the distance + * to some node changes. + * + * Note: right now we do the simple thing -- remove + * and add the node. Faster implementations are possible. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------4.16.1998-------- + */ +static void +changeDistanceParentList(struct sockaddr_in *changeDistNode) +{ + removeNodeParentList(changeDistNode); + addNodeParentList(changeDistNode); +} + + +/* + *------------------------------------------------------------------ + * + * parentListIndex -- + * + * Return the index of the parent list for the element + * with the specified nodeKey. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.19.1998------ + */ +static int +parentListIndex(HintCacheNodeKey * n) +{ + return fullMatchIndex(n->key); +} + +/* + *------------------------------------------------------------------ + * + * fullMatchIndex -- + * + * Return the highest legal index into the parent list + * for object/node with the specified key. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-----------------------------------------------------4.19.1998------ + */ +static int +fullMatchIndex(HintCacheKey k) +{ + int bits, levelsThatMatch, indexInBucket, index; + + bits = plaxtonMatchBits(k, myNodeKey); + if (bits == nParentLevels * bitsPerLevel) { + /* + * I am root! want to match in all bits in last level + * This will force system to get right indexInBucket in + * last level. + */ + bits--; + } + levelsThatMatch = bits / bitsPerLevel; + indexInBucket = + (k >> (levelsThatMatch * bitsPerLevel)) % Plaxton_bucketsPerLevel; + index = firstLevelBucketForMatch(bits) + indexInBucket; + return index; +} + + +/* + *------------------------------------------------------------------ + * + * addNodeHighestMatch -- + * + * Add the specified node to all highestMatch lists k + * for for which the node matches me in at least the + * bottom k bits. Keep each list sorted by key with + * the head of the list containing the highest key. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.16.1998------ + */ +static void +addNodeHighestMatch(struct sockaddr_in *addNode) +{ + HintCacheNodeKey n; + int match, imatch; + + hintCacheNodeKeyInit(&n, addNode); + + match = plaxtonMatchBits(n.key, myNodeKey); + if (match == BITS_PER_KEY) { + match--; + } + for (imatch = 0; imatch <= match; imatch++) { + matchInsert(&highestMatchA[imatch], addNode); + } + return; +} + +/* + *------------------------------------------------------------------ + * + * matchInsert -- + * + * Insert new node key onto list sorted by node key. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------4.16.1998---- + */ +static void +matchInsert(dlink_list *l, struct sockaddr_in *a) +{ + HintCacheNodeKey *current, *n; + dlink_node *node; + + n = (HintCacheNodeKey *) xmalloc(sizeof(HintCacheNodeKey)); + assert(n); + hintCacheNodeKeyInit(n, a); + + /* + * Each list always contains at least me. + */ + assert(l->head != 0); + + for (node = l->head; node; node = node->next) { + current = node->data; + assert(current->key != n->key); + if (current->key < n->key) { + /* Put 'n' right before 'current' */ + n->next = current; + n->prev = current->prev; + current->prev = current; + n->prev->next = n; + return; + } + } + assert(((HintCacheNodeKey *) l->tail->data)->key >= n->key); + dlinkAddTail(n, &n->links, l); + return; +} + +/* + *------------------------------------------------------------------ + * + * removeNodeHighestMatch -- + * + * Remove node from all lists k where node's key + * matches my key in at least k bits. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------4.16.1998---------- + */ +static void +removeNodeHighestMatch(struct sockaddr_in *goneNode) +{ + HintCacheNodeKey n; + int match, imatch; + + hintCacheNodeKeyInit(&n, goneNode); + + match = plaxtonMatchBits(n.key, myNodeKey); + if (match == BITS_PER_KEY) { + match--; + } + for (imatch = 0; imatch <= match; imatch++) { + matchRemove(&highestMatchA[imatch], goneNode); + } + return; +} + +/* + *------------------------------------------------------------------ + * + * matchRemove -- + * + * Remove specified element from list. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *--------------------------------------------------4.16.1998----------- + */ +static void +matchRemove(dlink_llist *list, struct sockaddr_in *a) +{ + HintCacheNodeKey *current, n; + dlink_node *node; + + hintCacheNodeKeyInit(&n, a); + /* + * Each list always contains at least me. + */ + assert(list->head != 0); + + for (node = list->head; node; node = node->next) { + current = node->data; + if (!hintCacheNodeKeyCompare(current, &n)) { + dlinkDelete(node, list); + xfree(current); + return; + } + } + return; +} + +/* + *------------------------------------------------------------------ + * + * plaxtonCheckIfParent -- + * + * Return true if the specified node is, in fact, our + * current parent for objects with the specified URL. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +int +plaxtonCheckIfParent(URLKey key, struct sockaddr_in *candidate) +{ + int index, amIRoot; + struct sockaddr_in real; + + assert(initialized); + index = plaxtonParentQIndex(&key, &amIRoot); + if (amIRoot) { + return 0; + } + if (plaxtonGetParentAddr(index, &real)) { + return 0; + } + if (candidate->sin_addr.s_addr == real.sin_addr.s_addr) { + return 1; + } + return 0; +} + + + + +/* + *------------------------------------------------------------------ + * + * childAdd -- + * + * Add a child record to the appropriate child list. + * Does NOT check to see if child is already on list -- + * caller should already have done it. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------4.9.1998---------- + */ +static void +childAdd(HintCacheNodeKey * key) +{ + int l; + + l = plaxtonMatchBits(key->key, myNodeKey); + assert(l <= nChildLists); + dlinkAdd(key, &key->links, childrenListA[l]); + childrenCountA[l]++; + childrenCountTot++; + assert(childFind(key)); + return; +} + +/* + *------------------------------------------------------------------ + * + * childFind -- + * + * Find the specified child if on the list. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------4.9.1998--------- + */ +static HintCacheNodeKey * +childFind(HintCacheNodeKey * key) +{ + HintCacheNodeKey *current; + dlink_node *node; + int l; + + l = plaxtonMatchBits(key->key, myNodeKey); + assert(l <= nChildLists); + for (node = childrenListA[l].head; node ; node = node->next) { + current = node->data; + if (!hintCacheNodeKeyCompare(current, key)) { + return current; + } + } + return NULL; +} + + +/* + *------------------------------------------------------------------ + * + * matchBits -- + * + * Return the number of bits that match between the two + * keys. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-----------------------------------------------------4.10.1998------- + */ +int +plaxtonMatchBits(HintCacheKey k1, HintCacheKey k2) +{ + int ibit; + HintCacheKey mask; + + for (ibit = 0, mask = 0x1; ibit < nChildLists - 1; ibit++, mask = mask << 1) { + if ((k1 & mask) != (k2 & mask)) { + return ibit; + } + } + return ibit; +} + + +/* + *------------------------------------------------------------------ + * + * plaxtonmyNodeKey -- + * + * description. + * + * Arguments: + * None. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +HintCacheKey +plaxtonmyNodeKey(void) +{ + return myNodeKey; +} + + +#ifdef DOTEST +/* + *------------------------------------------------------------------ + * + * plaxtonSelfTest -- + * + * description. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.10.1998------ + */ + +void +plaxtonSelfTest() +{ + printf("plaxtonSelfTest..."); + fflush(stdout); + testMakeMatchKey(); + neighborsOutgoing = (HCNet *) xmalloc(sizeof(HCNet)); + assert(neighborsOutgoing); + printf("."); + fflush(stdout); + HCNet_Init(neighborsOutgoing); + HCNet_SetTestMode(neighborsOutgoing); + selfTestChildren(); + printf("."); + fflush(stdout); + selfTestParents(); + printf("."); + fflush(stdout); + HCNet_Destroy(neighborsOutgoing); + xfree(neighborsOutgoing); + printf(".Done.\n"); + fflush(stdout); + return; +} + +/* + *------------------------------------------------------------------ + * + * selfTestChildren -- + * + * description. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +static void +selfTestChildren() +{ + int iaddr; + struct sockaddr_in n0; + static int CHECK_ADDR_BEGIN = 1000; + static int CHECK_ADDR_END = 2000; + static int CHECK_NOT_THERE_END = 3000; + static URLKey urlMatchAll, urlMatchNone, urlMatchOne, urlMatchEight; + int amILeaf = -1; + int childCount, allChildren; + struct sockaddr_in *childrenA = NULL; + + assert(CHECK_ADDR_END > CHECK_ADDR_BEGIN); + assert(CHECK_ADDR_END < CHECK_NOT_THERE_END); + + + + allChildren = CHECK_ADDR_END - CHECK_ADDR_BEGIN; + plaxtonInit(8); + + assert(sizeof(URLKey) == sizeof(HintCacheKey)); /* bypassing normal init */ + urlMatchAll.key = myNodeKey; + urlMatchNone.key = ~myNodeKey; + urlMatchOne.key = (~myNodeKey) ^ 0x1; + urlMatchEight.key = (~myNodeKey) ^ 0xFF; + + assert(plaxtonNChildrenQs() == sizeof(HintCacheKey) * 8 + 1); + amILeaf = -1; + assert(plaxtonChildQIndex(&urlMatchAll, 0, + &amILeaf) == sizeof(HintCacheKey) * 8); + assert(amILeaf == 1); + amILeaf = -1; + assert(plaxtonChildQIndex(&urlMatchNone, 0, &amILeaf) == 0); + assert(amILeaf == 1); + amILeaf = -1; + assert(plaxtonChildQIndex(&urlMatchOne, 0, &amILeaf) == 1); + assert(amILeaf == 1); + amILeaf = -1; + assert(plaxtonChildQIndex(&urlMatchEight, 0, &amILeaf) == 8); + assert(amILeaf == 1); + childrenA = (struct sockaddr_in *) 0x888888; + childCount = plaxtonGetChildAddrs(15, &childrenA); + assert(childCount == 0); + assert(childrenA == NULL); + + for (iaddr = CHECK_ADDR_BEGIN; iaddr < CHECK_ADDR_END; iaddr++) { + n0.sin_addr.s_addr = iaddr; + n0.sin_port = 0; + plaxtonAddChild(&n0); + } + + childCount = plaxtonGetChildAddrs(sizeof(HintCacheKey) * 8, &childrenA); + assert(childCount == allChildren); + assert(childrenA != NULL); + assert(selfTestFindAddr(CHECK_ADDR_BEGIN, childrenA, childCount)); + assert(selfTestFindAddr((CHECK_ADDR_BEGIN + CHECK_ADDR_END) / 2, + childrenA, childCount)); + assert(selfTestFindAddr(CHECK_ADDR_END - 1, childrenA, childCount)); + assert(!selfTestFindAddr(CHECK_ADDR_END, childrenA, childCount)); + xfree(childrenA); + + /* + * The nodes we inserted as children were random. Assuming + * we inserted a reasonable number of them, it would be + * surprizing if more than, say, 60% matched us in the + * lowest bit or if fewer than, say, 40% match us in the + * lowest bit + */ + if (allChildren >= 1000) { + childCount = plaxtonGetChildAddrs(0, &childrenA); + if (allChildren * 0.6 < childCount) { + printf("WARNING WARNING WARNING WARNING\n"); + printf + ("WARNING: Plaxton saw unlikely distribution of random children.\n"); + printf + ("WARNING: (too many). This is very nearly an assertion failure.\n"); + } + if (allChildren * 0.4 > childCount) { + printf("WARNING WARNING WARNING WARNING\n"); + printf + ("WARNING: Plaxton saw unlikely distribution of random children.\n"); + printf + ("WARNING: (too few). This is very nearly an assertion failure.\n"); + } + xfree(childrenA); + } else { + printf + ("\nWARNING: Plaxton selftest skipping random match check (too few samples\n"); + } + + printf("."); + fflush(stdout); + for (iaddr = CHECK_ADDR_BEGIN; iaddr < CHECK_ADDR_END; iaddr++) { + n0.sin_addr.s_addr = iaddr; + n0.sin_port = 0; + assert(plaxtonCheckIfChild(&n0)); + plaxtonRemoveChild(&n0); + } + printf("."); + fflush(stdout); + for (iaddr = CHECK_ADDR_BEGIN; iaddr < CHECK_NOT_THERE_END; iaddr++) { + n0.sin_addr.s_addr = iaddr; + n0.sin_port = 0; + assert(!plaxtonCheckIfChild(&n0)); + } + plaxtonDestroy(); + printf(".OK\n"); +} + + + +/* + *------------------------------------------------------------------ + * + * selfTestFindAddr -- + * + * Return nonzero if the specified value is in + * the array. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-----------------------------------------------------4.10.1998------- + */ +static int +selfTestFindAddr(int addr, struct sockaddr_in *childrenA, int childCount) +{ + struct sockaddr_in n0; + int ii; + + assert(childrenA != NULL); + n0.sin_addr.s_addr = addr; + n0.sin_port = 0; + for (ii = 0; ii < childCount; ii++) { + assert(childrenA[ii].sin_port == 0); + if (childrenA[ii].sin_addr.s_addr == n0.sin_addr.s_addr) { + return 1; + } + } + return 0; +} + + +/* + *------------------------------------------------------------------ + * + * selfTestParents -- + * + * description. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-----------------------------------------------------4.19.1998-------- + */ +static void +selfTestParents(void) +{ + testParentsBinaryTree(); + testParentsMultiRootCase(); + testParentsInternals(); + testParentsInternals2(); + stressTestParents(); +} + +/* + *------------------------------------------------------------------ + * + * testParentsBinaryTree -- + * + * Test the following simple case: four nodes + * with low-order bits: 00 01 10 11 + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.19.1998-------- + */ +static void +testParentsBinaryTree(void) +{ + int myId, targetId, caseCount; + struct sockaddr_in parents[4], retAddr; + int ii, hops, qIndex, iAmRoot; + HintCacheNodeKey key; + URLKey targetURLKey; + + /* XXX Make sure that entire code merge happens. Funny little bug in + * tools.h that we fixed. + */ + parents[0].sin_addr.s_addr = 10; + parents[0].sin_port = 0; + parents[1].sin_addr.s_addr = 11; + parents[1].sin_port = 0; + assert(SINCMP(&parents[0], &parents[1])); /* if this fails, bug in SINCMP */ + + /* + * Try this test from every point of view + */ + for (myId = 0; myId < 4; myId++) { + plaxtonInit(1); + assert(plaxtonNParentQs() == 192); + + + /* + * Cheat to force my key to do right thing + */ + myNodeKey = (HintCacheKey) myId; + for (ii = 0; ii < BITS_PER_KEY; ii++) { + assert(highestMatchA[ii].head != 0); + ((HintCacheNodeKey *) highestMatchA[ii].head->data)->key = myNodeKey; + } + + for (caseCount = 1; caseCount <= 3; caseCount++) { + /* + * Do all combinations of bottom two bits except my own + */ + targetId = myId ^ caseCount; + /* + * Search for a node that matches desired bits + */ + for (ii = 0;; ii++) { + parents[caseCount].sin_addr.s_addr = myId * 1000 + ii; + parents[caseCount].sin_port = 0; + hintCacheNodeKeyInit(&key, &parents[caseCount]); + if ((key.key & 0x3) == targetId) { + if (caseCount == 1) { + assert((key.key & 0x2) == (myNodeKey & 0x2)); + assert((key.key & 0x1) != (myNodeKey & 0x1)); + hops = 1; + } else { + assert((key.key & 0x2) != (myNodeKey & 0x2)); + hops = 2; + } + HCHier_newNode(&parents[caseCount], hops, 999); + + break; + } + } + } + + + /* + * Case 0: same in all bits + */ + targetURLKey.key = myId; + qIndex = plaxtonParentQIndex(&targetURLKey, &iAmRoot); + assert(iAmRoot); + + + /* + * Case 1: differ in bit 0 --> queue is at level 0 + * and the (key & 0x1)th queue within level 0 + */ + targetURLKey.key = myId ^ 0x1; + qIndex = plaxtonParentQIndex(&targetURLKey, &iAmRoot); + assert(!iAmRoot); + assert(qIndex == ((unsigned) targetURLKey.key & 0x1)); + assert(plaxtonGetParentAddr(qIndex, &retAddr) == 0); + assert(retAddr.sin_addr.s_addr == parents[1].sin_addr.s_addr); + assert(plaxtonCheckIfParent(targetURLKey, &parents[1])); + assert(!plaxtonCheckIfParent(targetURLKey, &parents[2])); + assert(!plaxtonCheckIfParent(targetURLKey, &parents[3])); + + + /* + * Case 2: differ in bit 1; same bit 0 --> queue is + * at level 1 and the (key & 0x1)the queue within level 1 + */ + targetURLKey.key = myId ^ 0x2; + qIndex = plaxtonParentQIndex(&targetURLKey, &iAmRoot); + assert(!iAmRoot); + assert(qIndex == 2 + (((unsigned) targetURLKey.key & 0x2) >> 1)); + assert(plaxtonGetParentAddr(qIndex, &retAddr) == 0); + assert(retAddr.sin_addr.s_addr == parents[2].sin_addr.s_addr); + assert(!plaxtonCheckIfParent(targetURLKey, &parents[1])); + assert(plaxtonCheckIfParent(targetURLKey, &parents[2])); + assert(!plaxtonCheckIfParent(targetURLKey, &parents[3])); + + /* + * Case 3: differ in bits 0 and 1; should be same as case 1 + */ + targetURLKey.key = myId ^ 0x3; + qIndex = plaxtonParentQIndex(&targetURLKey, &iAmRoot); + assert(!iAmRoot); + assert(qIndex == ((unsigned) targetURLKey.key & 0x1)); + assert(plaxtonGetParentAddr(qIndex, &retAddr) == 0); + assert(retAddr.sin_addr.s_addr == parents[1].sin_addr.s_addr); + assert(plaxtonCheckIfParent(targetURLKey, &parents[1])); + assert(!plaxtonCheckIfParent(targetURLKey, &parents[2])); + assert(!plaxtonCheckIfParent(targetURLKey, &parents[3])); + + plaxtonDestroy(); + } +} + +/* + *------------------------------------------------------------------ + * + * testParentsMultiRootCase -- + * + * Test the case where several nodes match + * an object in k bits, and no nodes match in + * more than k bits. Answer should be that the + * highest key is the winner. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.19.1998-------- + */ +static void +testParentsMultiRootCase(void) +{ + int eligibleFound, ii; + struct sockaddr_in sin, maxAddr, retAddr; + static unsigned int nodeMask = 0xFF; + static unsigned int objMask = 0x3F; + HintCacheKey maxKey; + URLKey targetURLKey; + int qIndex, iAmRoot; + HintCacheNodeKey anotherNodeKey; + + plaxtonInit(2); + + assert(objMask < nodeMask); + assert((objMask & nodeMask) == objMask); + + /* + * Create a bunch of nodes that are eligible to be the root for + * for an object that matches them (and us) in objMask bits + * and mismatches in the next bit + */ + /* XXX targetURLKey.key = (myNodeKey & objMask) ^ (nodeMask ^ objMask); */ + targetURLKey.key = (myNodeKey & nodeMask) ^ (nodeMask ^ objMask); + + qIndex = plaxtonParentQIndex(&targetURLKey, &iAmRoot); + assert(iAmRoot); + + maxKey = myNodeKey; + maxAddr = Config.Sockaddr.http->s; + ii = 0; + eligibleFound = 0; + while (eligibleFound < 40) { + sin.sin_addr.s_addr = 10000 + ii; + sin.sin_port = 0; + hintCacheNodeKeyInit(&anotherNodeKey, &sin); + if ((anotherNodeKey.key & nodeMask) == (myNodeKey & nodeMask)) { + eligibleFound++; + HCHier_newNode(&sin, 1000, 999); + if (anotherNodeKey.key > maxKey) { + /* + * Found new root for object + */ + maxKey = anotherNodeKey.key; + maxAddr = sin; + } + } + qIndex = plaxtonParentQIndex(&targetURLKey, &iAmRoot); + if (maxKey == myNodeKey) { + assert(iAmRoot); + } + if (iAmRoot) { + assert(maxKey == myNodeKey); + } else { + assert(plaxtonGetParentAddr(qIndex, &retAddr) == 0); + assert(qIndex >= nParentLevels * plaxtonbucketsPerLevel); + assert(retAddr.sin_addr.s_addr == maxAddr.sin_addr.s_addr); + } + ii++; + } + plaxtonDestroy(); + +} + + +/* + *------------------------------------------------------------------ + * + * stressTestParents -- + * + * Add and remove a few bizillion nodes and elements. I don't + * know what the right answers should be, but + * I want to test to try to trigger assertion failures. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-----------------------------------------------------4.19.1998-------- + */ +static void +stressTestParents(void) +{ + int ii; + URLKey targetURLKey; + int qIndex, iamRoot; + static int BIG = 100; /* should be much bigger for good test */ + struct sockaddr_in sin, retAddr; + + plaxtonInit(4); + + for (ii = 0; ii < BIG; ii++) { + sin.sin_addr.s_addr = 100000 + ii; + sin.sin_port = 0; + HCHier_newNode(&sin, 1000, 999); + } + + for (ii = 0; ii < BIG; ii++) { + sin.sin_addr.s_addr = 100000 + ii; + sin.sin_port = 0; + plaxtonchangeDistance(&sin); + } + + + for (ii = 0; ii < BIG; ii++) { + targetURLKey.key = ii; + qIndex = plaxtonParentQIndex(&targetURLKey, &iamRoot); + if (!iamRoot) { + assert(!plaxtonGetParentAddr(qIndex, &retAddr)); + } + } + + for (ii = 0; ii < BIG; ii++) { + sin.sin_addr.s_addr = 100000 + ii; + sin.sin_port = 0; + HCHier_delNode(&sin, 1000, 1999); + } + + for (ii = 0; ii < BIG; ii++) { + targetURLKey.key = ii; + qIndex = plaxtonParentQIndex(&targetURLKey, &iamRoot); + if (!iamRoot) { + assert(!plaxtonGetParentAddr(qIndex, &retAddr)); + } + } + + plaxtonDestroy(); +} + + +/* + *------------------------------------------------------------------ + * + * testParentsInternals -- + * + * Test the internal data structures of the parents + * for the non-multi-root case. + * Set the local key address to 0 then + * generate a quand-ary tree with all possible + * values of node keys from 1..15, and make + * sure that the nodes land in the right buckets + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +static void +testParentsInternals(void) +{ + int ii, targetKey; + HintCacheNodeKey anotherNodeKey, *current, *next; + HintCacheKey k; + struct sockaddr_in sin, nodes[16]; + int iAmRoot; + URLKey urlKey; + dlink_node *node; + + plaxtonInit(2); + myNodeKey = 0; /* Fake it out to make tests easier to write and read */ + + targetKey = 1; + ii = 0; + while (targetKey < 16) { + /* + * Note: netdb only keeps distance info on granularity of + * networks; we want to know what distances there are between + * nodes, so make nodes be on different (hopfully unused) subnets + */ + sin.sin_addr.s_addr = 15000 + ii * 255; + sin.sin_port = 0; + if (netdbHintHops(sin.sin_addr)) + !=0) { + ii++; + continue; /* Someone already used this address and gave it a distance */ + } + hintCacheNodeKeyInit(&anotherNodeKey, &sin); + if ((anotherNodeKey.key & 15) == targetKey) { + nodes[targetKey] = sin; + HCHier_newNode(&sin, targetKey * 1000, 999); + targetKey++; + } + ii++; + } + + /* + * The level-0 lists should be in sorted order + */ + for (ii = 1; ii <= 3; ii++) { + for (node = parentListA[ii].head; node; node = node->next) { + current = node->data; + if (current != (HintCacheNodeKey *) parentListA[ii].tail->data)) { + next = (HintCacheNodeKey *) List_Next((dlink_node *) current); + assert(!List_IsAtEnd(&parentListA[ii], (dlink_node *) next)); + assert(HCHier_compareDistanceFromMe(hintCacheNodeKeyGetAddr(current). + sin_addr, hintCacheNodeKeyGetAddr(next).sin_addr) + <= 0); + } + } + } + + /* + * The level-0 lists XX01, XX10, and XX11 should each have + * four elements in the following order: 00--, 01--, 10--, + * and 11-- (where "--" is the index of the list) + */ + for (ii = 1; ii <= 3; ii++) { + assert((&parentListA[ii])->prevPtr + == (&parentListA[ii])->nextPtr->nextPtr->nextPtr->nextPtr); + + k = ((HintCacheNodeKey *) ((&parentListA[ii])->nextPtr))->key; + assert((k & 3) == ii); + assert(((k & 15) >> 2) == 0); /* 00 */ + + k = ((HintCacheNodeKey *) ((&parentListA[ii])->nextPtr->nextPtr))->key; + assert((k & 3) == ii); + assert(((k & 15) >> 2) == 1); /* 01 */ + + k = ((HintCacheNodeKey *) ((&parentListA[ii])->nextPtr->nextPtr->nextPtr))->key; + assert((k & 3) == ii); + assert(((k & 15) >> 2) == 2); /* 10 */ + + k = ((HintCacheNodeKey *) ((&parentListA[ii])->nextPtr->nextPtr->nextPtr-> + nextPtr))->key; + assert((k & 3) == ii); + assert(((k & 15) >> 2) == 3); /* 11 */ + + urlKey.key = 0xFFAA3400 | ii; + assert(plaxtonCheckIfParent(urlKey, &nodes[ii])); + assert(plaxtonParentQIndex(&urlKey, &iAmRoot) == ii); + assert(!iAmRoot); + } + /* + * The level-1 lists 0100, 1000, 1100 should each + * have one element + */ + /* 00 00 is list 4 and is empty */ + assert(List_IsEmpty(&parentListA[4])); + + /* 01 00 is list 5 and has one element "xxx0100" = 4 */ + assert(parentListA[5].nextPtr->nextPtr == &parentListA[5]); + k = ((HintCacheNodeKey *) ((&parentListA[5])->nextPtr))->key; + assert((k & 15) == 4); + urlKey.key = 0xFFAA1204; + assert(plaxtonCheckIfParent(urlKey, &nodes[4])); + assert(plaxtonParentQIndex(&urlKey, &iAmRoot) == 5); + assert(!iAmRoot); + + /* 10 00 is list 6 and has one element "xxx1000" = 8 */ + assert(parentListA[6].nextPtr->nextPtr == &parentListA[6]); + k = ((HintCacheNodeKey *) ((&parentListA[6])->nextPtr))->key; + assert((k & 15) == 8); + urlKey.key = 0xFFAA1208; + assert(plaxtonCheckIfParent(urlKey, &nodes[8])); + assert(plaxtonParentQIndex(&urlKey, &iAmRoot) == 6); + assert(!iAmRoot); + + /* 11 00 is list 7 and has one element "xxx1100" = 12 */ + assert(parentListA[7].nextPtr->nextPtr == &parentListA[7]); + k = ((HintCacheNodeKey *) ((&parentListA[7])->nextPtr))->key; + assert((k & 15) == 12); + urlKey.key = 0xFFAA120C; + assert(plaxtonCheckIfParent(urlKey, &nodes[12])); + assert(plaxtonParentQIndex(&urlKey, &iAmRoot) == 7); + assert(!iAmRoot); + + plaxtonDestroy(); +} + + +/* + *------------------------------------------------------------------ + * + * testParentsInternals2 -- + * + * Test finding parent when we can't match + * entire next level. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *--------------------------------------------------------5.4.1998---- + */ +static void testParentsInternals2(void) +{ + int ii; + struct sockaddr_in sin; + HintCacheNodeKey anotherNodeKey; + URLKey urlKey; + int iAmRoot; + + plaxtonInit(4); + myNodeKey = 0; /* Fake it out to make tests easier to write and read */ + + ii = 0; + while (1) + { + /* + * Note: netdb only keeps distance info on granularity of + * networks; so make nodes be on different (hopfully unused) subnets + */ + sin.sin_addr.s_addr = 15000 + ii * 255; + sin.sin_port = 0; + if (netdbHintHops(sin.sin_addr) != 0) + { + ii++; + continue; /* Someone already used this address and gave it a distance */ + } + hintCacheNodeKeyInit(&anotherNodeKey, &sin); + /* + * Want 0110 0000 + */ + if ((anotherNodeKey.key & 0xFF) == 0x60) { + HCHier_newNode(&sin, 1000, 999); + break; + } + ii++; + } + assert((anotherNodeKey.key & 0xFF) == 0x60); + urlKey.key = 0x20; + assert(plaxtonCheckIfParent(urlKey, &sin)); + assert(plaxtonParentQIndex(&urlKey, &iAmRoot) == 22); + assert(!iAmRoot); + plaxtonDestroy(); +} + +/* + *------------------------------------------------------------------ + * + * testMakeMatchKey -- + * + * description. + * + * Arguments: + * None. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------5.4.1998------ + */ +static void testMakeMatchKey(void) +{ + URLKey key; + HintCacheKey ret; + + key.key = 0xFFAABBCC; + ret = makeMatchKey(&key, 4, 0); + assert(ret == 0xC); + ret = makeMatchKey(&key, 4, 0xD); + assert(ret = 0xDC); + ret = makeMatchKey(&key, 0, 0xD); + assert(ret = 0xD); +} + +#endif /* DOTEST */ Index: squid/src/access_log.c diff -u squid/src/access_log.c:1.17 squid/src/access_log.c:1.15.2.2 --- squid/src/access_log.c:1.17 Sun Jun 16 10:48:14 2002 +++ squid/src/access_log.c Tue Sep 3 10:41:34 2002 @@ -64,6 +64,7 @@ "TCP_MEM_HIT", "TCP_DENIED", "TCP_OFFLINE_HIT", + "TCP_PUT", #if LOG_TCP_REDIRECTS "TCP_REDIRECT", #endif @@ -72,6 +73,7 @@ "UDP_DENIED", "UDP_INVALID", "UDP_MISS_NOFETCH", + "UDP_PUT", "ICP_QUERY", "LOG_TYPE_MAX" }; Index: squid/src/acl.c diff -u squid/src/acl.c:1.55 squid/src/acl.c:1.42.2.3 --- squid/src/acl.c:1.55 Sun Sep 1 09:30:41 2002 +++ squid/src/acl.c Tue Sep 3 10:41:35 2002 @@ -363,7 +363,7 @@ protocol_t protocol; for (Tail = curlist; *Tail; Tail = &((*Tail)->next)); while ((t = strtokFile())) { - protocol = urlParseProtocol(t); + protocol = urlParseProtocol(t, 0, 0); q = memAllocate(MEM_INTLIST); q->i = (int) protocol; *(Tail) = q; Index: squid/src/cache_cf.c diff -u squid/src/cache_cf.c:1.47 squid/src/cache_cf.c:1.38.2.4 --- squid/src/cache_cf.c:1.47 Sun Sep 1 09:30:41 2002 +++ squid/src/cache_cf.c Tue Sep 3 10:41:37 2002 @@ -1535,6 +1535,21 @@ p->options.allow_miss = 1; } else if (!strncasecmp(token, "max-conn=", 9)) { p->max_conn = xatoi(token + 9); + } else if (!strncasecmp(token, "dist", 4)) { + p->options.dist = 1; + } else if (!strncasecmp(token, "fwdpush", 7)) { + p->fwdpush = DistAllPeers; + DistAllPeers = p; +#if USE_ICP_DATA + } else if (!strncasecmp(token, "icpdata", 7)) { + p->options.icpdata = 1; + } else if (!strncasecmp(token, "maxrate=", 8)) { + p->maxrate = atoi(token + 8); +#endif +#if USE_HINT_CACHE + } else if (!strncasecmp(token, "nohint", 6)) { + p->options.nohint = 1; +#endif } else { debug(3, 0) ("parse_peer: token='%s'\n", token); self_destruct(); Index: squid/src/cbdata.c diff -u squid/src/cbdata.c:1.15 squid/src/cbdata.c:1.14.2.2 --- squid/src/cbdata.c:1.15 Sat Apr 13 16:09:15 2002 +++ squid/src/cbdata.c Tue Sep 3 10:41:39 2002 @@ -136,6 +136,7 @@ CREATE_CBDATA_FREE(peer, peerDestroy); CREATE_CBDATA(ps_state); CREATE_CBDATA(RemovalPolicy); + CREATE_CBDATA(Pusher); CREATE_CBDATA(RemovalPolicyWalker); CREATE_CBDATA(RemovalPurgeWalker); CREATE_CBDATA(store_client); Index: squid/src/cf.data.pre diff -u squid/src/cf.data.pre:1.79 squid/src/cf.data.pre:1.43.2.4 --- squid/src/cf.data.pre:1.79 Sun Sep 1 09:30:41 2002 +++ squid/src/cf.data.pre Tue Sep 3 10:41:39 2002 @@ -279,6 +279,8 @@ digest-url=url allow-miss max-conn + dist + nohint use 'proxy-only' to specify that objects fetched from this cache should not be saved locally. @@ -385,6 +387,19 @@ use 'max-conn' to limit the amount of connections Squid may open to this peer. + 'dist' tells squid to ask for consistency updates + via httpdist on all queries to that peer. + + 'nohint' tells squid not to send hint cache updates + to that peer. The default is that updates are sent + if hints are active. + + 'icpdata' says to send pushes to this peer by the + UDP-based ICPDATA protocol instead of TCP. + + 'maxrate=n' specifies the maximum rate to send + ICPDATA data at. + NOTE: non-ICP neighbors must be specified as 'parent'. DOC_END @@ -1405,6 +1420,11 @@ (off - for use when useragents generate nonce counts that occasionally miss 1 (ie, 1,2,4,6)). + "nonce_strictness" on|off + Determines if squid requires increment-by-1 behaviour for nonce counts + (on - the default), or strictly incrementing (off - for use when useragents + generate nonce counts that occasionally miss 1 (ie, 1,2,4,6)). + === NTLM scheme options follow === "program" cmdline @@ -3774,6 +3794,111 @@ time. By default it is set to 10% of the Cache Digest. DOC_END +NAME: hint_cache_listen +IFDEF: USE_HINT_CACHE +TYPE: onoff +LOC: Config.onoff.hint_cache_listen +DEFAULT: off +DOC_START + This controls whether hint cache is used to decide where to + forward misses. Hint caches exchange data to track nearest + location and metadata of all URLs in a hint cache cloud; + This variable also decides whether we listen to hints from + neighboring hint caches. +DOC_END + +NAME: hint_cache_advertise +IFDEF: USE_HINT_CACHE +TYPE: onoff +LOC: Config.onoff.hint_cache_advertise +DEFAULT: off +DOC_START + This controls whether we tell other caches about content in + our own cache. We only want to do that if we are in a + position to efficiently serve requests from other caches. + + We encourage you to turn this on, as participation in the + hint cloud as a full neighbor brings greater value to + everybody, including yourself. +DOC_END + +NAME: hint_cache_file +IFDEF: USE_HINT_CACHE +TYPE: string +LOC: Config.Hints.cache_file +DEFAULT: @DEFAULT_HINT_FILE@ +DOC_START + This is the name of the file holding the hint cache. +DOC_END + +NAME: hint_cache_size +COMMENT: bytes +IFDEF: USE_HINT_CACHE +TYPE: int +LOC: Config.Hints.size +DEFAULT: 83886080 +DOC_START + This is the size of the hint cache, in bytes. It has to be + big enough to hold location and metadata for all objects + tracked. +DOC_END + +NAME: hint_cache_assoc +IFDEF: USE_HINT_CACHE +TYPE: int +LOC: Config.Hints.assoc +DEFAULT: 4 +DOC_START + Hint cache associativity. +DOC_END + +NAME: hint_cache_interval +IFDEF: USE_HINT_CACHE +TYPE: int +LOC: Config.Hints.intvl +DEFAULT: 60 +DOC_START + Max interval between hint transmissions to neighbors, in + seconds. Actual interval is randomly, uniformly distributed + between 0 and hint_cache_interval. +DOC_END + +NAME: hint_cache_use_mmap +IFDEF: USE_HINT_CACHE +TYPE: onoff +LOC: Config.onoff.hint_cache_use_mmap +DEFAULT: off +DOC_START + This tells the hint cache to access the hint cache file + using mmap() instead of standard file I/O. A slight + speedup on machines with plenty of RAM. If you are not + so long on RAM for your cache, leave it off. It probably + isn't efficient unless you can hold almost the entire + cache in memory. See hint_cache_size, above, for how + big your hint cache is. +DOC_END + +NAME: hint_cache_join_interval +IFDEF: USE_HINT_CACHE +TYPE: int +LOC: Config.Hints.join_intvl +DEFAULT: 14400 +DOC_START + Max interval between join transmissions to neighbors, in + seconds. Actual interval is randomly, uniformly distributed + between 0 and hint_cache_join_interval. +DOC_END + +NAME: hint_cache_holddown +IFDEF: USE_HINT_CACHE +TYPE: int +LOC: Config.Hints.holddown +DEFAULT: 900 +DOC_START + Amount of time to pass before we can assume that a hint + has finished propagating. +DOC_END + NAME: chroot TYPE: string LOC: Config.chroot_dir Index: squid/src/client_side.c diff -u squid/src/client_side.c:1.71 squid/src/client_side.c:1.45.2.5 --- squid/src/client_side.c:1.71 Sun Sep 1 09:30:42 2002 +++ squid/src/client_side.c Tue Sep 3 10:41:41 2002 @@ -1986,6 +1986,9 @@ } /* yes, continue */ http->log_type = LOG_TCP_MISS; + } else if (r->method == METHOD_PUT) { + putRecv(http); + return; } else { http->log_type = clientProcessRequest2(http); } @@ -2007,6 +2010,15 @@ http->entry->mem_obj->method = r->method; } http->sc = storeClientListAdd(http->entry, http); + if (r->dist_type != DIST_NONE) { + if (r->dist_type == DIST_DIST) + distNewUpdatee(http->entry, r->client_addr, r->dist_port); + else { + /* DIST_UNDIST */ + assert(r->dist_type == DIST_UNDIST); + distDelUpdatee(http->entry, r->client_addr, r->dist_port); + } + } #if DELAY_POOLS delaySetStoreClient(http->sc, delayClient(http)); #endif @@ -2252,7 +2264,8 @@ *(*prefix_p + prefix_sz) = '\0'; dlinkAdd(http, &http->active, &ClientActiveRequests); - debug(33, 5) ("parseHttpRequest: Request Header is\n%s\n", (*prefix_p) + *req_line_sz_p); + debug(33, 5) ("parseHttpRequest: Request Header is\n%s\n", + http->hdr_str + *req_line_sz_p); #if THIS_VIOLATES_HTTP_SPECS_ON_URL_TRANSFORMATION if ((t = strchr(url, '#'))) /* remove HTML anchors */ *t = '\0'; @@ -2546,13 +2559,11 @@ if (nrequests == 0) fd_note(conn->fd, "Reading next request"); /* Process request */ - http = parseHttpRequest(conn, - &method, - &parser_return_code, - &prefix, - &req_line_sz); - if (!http) - safe_free(prefix); + http = parseHttpRequest(conn, + &method, + &parser_return_code, + &prefix, + &req_line_sz); if (http) { assert(http->req_sz > 0); conn->in.offset -= http->req_sz; @@ -2575,7 +2586,6 @@ err->request_hdrs = xstrdup(conn->in.buf); http->entry = clientCreateStoreEntry(http, method, null_request_flags); errorAppendEntry(http->entry, err); - safe_free(prefix); break; } if ((request = urlParse(method, http->uri)) == NULL) { @@ -2586,14 +2596,13 @@ http->al.http.code = err->http_status; http->entry = clientCreateStoreEntry(http, method, null_request_flags); errorAppendEntry(http->entry, err); - safe_free(prefix); break; } else { /* compile headers */ /* we should skip request line! */ - if (!httpRequestParseHeader(request, prefix + req_line_sz)) + if (!httpRequestParseHeader(request, http->hdr_str + req_line_sz)) debug(33, 1) ("Failed to parse request headers: %s\n%s\n", - http->uri, prefix); + http->uri, http->hdr_str); /* continue anyway? */ } request->flags.accelerated = http->flags.accel; @@ -2615,7 +2624,6 @@ request->content_length = httpHeaderGetInt(&request->header, HDR_CONTENT_LENGTH); request->flags.internal = http->flags.internal; - safe_free(prefix); safe_free(http->log_uri); http->log_uri = xstrdup(urlCanonicalClean(request)); request->client_addr = conn->peer.sin_addr; Index: squid/src/comm.c diff -u squid/src/comm.c:1.24 squid/src/comm.c:1.18.2.4 --- squid/src/comm.c:1.24 Thu Apr 18 23:30:40 2002 +++ squid/src/comm.c Tue Sep 3 10:41:42 2002 @@ -631,6 +631,9 @@ comm_close(int fd) { fde *F = NULL; +#if USE_ICP_DATA + int isvfd; +#endif debug(5, 5) ("comm_close: FD %d\n", fd); assert(fd >= 0); @@ -648,6 +651,9 @@ if (F->ssl) ssl_shutdown_method(fd); #endif +#if USE_ICP_DATA + isvfd = (conn->comm_type == SOCK_VIRTUAL); +#endif commSetTimeout(fd, -1, NULL, NULL); CommWriteStateCallbackAndFree(fd, COMM_ERR_CLOSING); commCallCloseHandlers(fd); @@ -660,7 +666,18 @@ } #endif fd_close(fd); /* update fdstat */ +#if USE_ICP_DATA + if (isvfd) { + /* flag for later reuse */ + conn->comm_type = SOCK_VIRTUAL; + } + else { + debug(5, 9) ("comm_close: really closing fd %d \n", fd); + close(fd); + } +#else /* USE_ICP_DATA */ close(fd); +#endif /* USE_ICP_DATA */ statCounter.syscalls.sock.closes++; } @@ -1027,3 +1044,47 @@ return 0; return F->defer_check(fd, F->defer_data); } + +#if USE_ICP_DATA +/* + * Get fake file descriptor suitable for indexing through fd_table. + */ +int +comm_virtual_fd() +{ + static int firstfd = -1; + struct in_addr nobody; + int vfd; + int i; + + if (firstfd == -1){ + nobody.s_addr = INADDR_ANY; + firstfd = comm_open(SOCK_DGRAM, 0, nobody, 0, COMM_NONBLOCKING, "virtual"); + vfd = firstfd; + } + else { + for (i = 0; i <= Biggest_FD; ++i) { + if (fd_table[i].comm_type == SOCK_VIRTUAL && !fd_table[i].openned) + break; + } + if (fd_table[i].comm_type != SOCK_VIRTUAL) { + nobody.s_addr = INADDR_ANY; + vfd = comm_open(SOCK_DGRAM, 0, nobody, 0, COMM_NONBLOCKING, "virtual"); + debug(5, 4, "comm_virtual_fd: opened new vfd %d (Biggest_FD = %d)\n", + vfd, Biggest_FD); + assert(vfd > -1); + } + else { + vfd = i; + } + } + + fdstat_open(vfd, FD_SOCKET); + memset((char *) &fd_table[vfd], '\0', sizeof(FD_ENTRY)); + fd_table[vfd].openned = 1; + fd_table[vfd].lifetime = -1; + fd_table[vfd].comm_type = SOCK_VIRTUAL; + debug(5, 7, "comm_virtual_fd: returning vfd %d \n", vfd); + return(vfd); +} +#endif /* USE_ICP_DATA */ Index: squid/src/defines.h diff -u squid/src/defines.h:1.24 squid/src/defines.h:1.15.2.4 --- squid/src/defines.h:1.24 Thu Aug 8 13:15:19 2002 +++ squid/src/defines.h Tue Sep 3 10:41:43 2002 @@ -313,6 +313,64 @@ #define O_BINARY 0 #endif +/* put.c */ +#define P_ACTIVE(p) ((p)->flags.connected | (p)->flags.connecting) + +#if USE_HINT_CACHE +/* Hint Cache Interface */ + +/* Not QUITE compatible with 1.0 due to different tolower treatment + of URLs before md5 coding. */ +#define HINT_CACHE_VERSION "2.0" /* Protocol version */ + +/* Returns true iff the hint cache is in operation. */ +#define HINT_CACHE_ACTIVE() (HCDisk != NULL) + +#define URLKEY_COMPARE(k1, k2) ((k1).key - (k2).key) + +/* Hint Cache Primitives */ +#define HCE_VALID(hce) ((hce)->ipaddr.s_addr != INADDR_ANY &&\ + URLKEY_COMPARE((hce)->key, INVALID_URL_KEY)) +#define HCE_INVALIDATE(hce) ((hce)->ipaddr.s_addr = INADDR_ANY, \ + (hce)->key = INVALID_URL_KEY); + +#define HINT_CACHE_KEY(e) (((URLKey *) ((e)->hchash.key))) + +/* Hint protocol event types */ +#define HC_InvalToParent 1 +#define HC_InvalToChild 2 +#define HC_InformToParent 3 +#define HC_InformToChild 4 +#define HC_NewVersion 5 +#define HC_Join 6 +#define HC_Leave 7 +#define HC_Ignore 8 /* Message supressed. Ignore it. */ +#define HC_NotChild 9 /* "I am not your child" */ +#define HC_Error 10 + +/* Smallest an HCUPDATE can be (e.g., length of a v1 update). */ +#define HCU_MINLEN 24 + +/* Hint Cache Disk */ +#define HCD_VERSION 2 + +#define HCD_PREFETCH_THRESH 3 + +#endif /* USE_HINT_CACHE */ + + +/* CygWin & Windows NT Port */ +#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) +#define _WIN_OS_UNKNOWN 0 +#define _WIN_OS_WIN32S 1 +#define _WIN_OS_WIN95 2 +#define _WIN_OS_WIN98 3 +#define _WIN_OS_WINNT 4 +#define _WIN_OS_WIN2K 5 +#define _WIN_OS_WINXP 6 +#endif + +#define HTTP_REQBUF_SZ 4096 /* * Macro to find file access mode */ Index: squid/src/dist.c diff -u /dev/null squid/src/dist.c:1.1.2.5 --- /dev/null Mon Jan 26 04:57:39 2004 +++ squid/src/dist.c Mon May 20 19:46:42 2002 @@ -0,0 +1,217 @@ +/* + * $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ + * + * Distribution network algorithm. + * + * AUTHOR: Jon Kay, 1997 + * + * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ + * -------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from the + * Internet community. Development is led by Duane Wessels of the + * National Laboratory for Applied Network Research and funded by + * the National Science Foundation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "squid.h" + +static void distUpdate(Updatee *u); + +static char urlbuf[MAX_URL + 48]; + +peer *DistAllPeers = 0; + +/* Create new updatee ds & add to object's updatee list */ +Updatee * +distNewUpdatee(StoreEntry *entry, struct in_addr host, u_short dport) +{ + Updatee *u; + + ++statCounter.dist.dists; + /* Don't add a client if it isn't interested in updates */ + if (dport == 0) + return(NULL); + + /* Make sure new guy isn't already on list */ + for (u = entry->updatees; u; u = u->next) { + if (u->saddr.sin_addr.s_addr == host.s_addr + && u->saddr.sin_port == dport) + return(u); + } + + /* Need new updatee, alloc and add to list */ + u = xcalloc(sizeof(*u), 1); + u->next = entry->updatees; + u->entry = entry; + u->saddr.sin_family = AF_INET; + u->saddr.sin_addr = host; + u->saddr.sin_port = dport; + u->lastmod = entry->lastmod; + entry->updatees = u; + ++statCounter.dist.updatees; + return(u); +} + +void +distDelUpdatee(StoreEntry *entry, struct in_addr host, int dport) +{ + Updatee *i, **optr; + + ++statCounter.dist.undists; + optr = &entry->updatees; + for (i = entry->updatees; i; i = i->next) { + if (i->saddr.sin_addr.s_addr == host.s_addr + && i->saddr.sin_port == dport) { + (*optr) = i->next; + --statCounter.dist.updatees; + xfree(i); + } + optr = &i->next; + } +} + +void +distDelUpdatees(Updatee *u) +{ + Updatee *nu; + + for ( ; u; u = nu) { + nu = u->next; + --statCounter.dist.updatees; + xfree(u); + } +} + +void +distUpdateeChangeEntry(StoreEntry *entry, Updatee *u) +{ + entry->updatees = u; + for ( ; u; u = u->next) { + u->entry = entry; + } +} + + +/* Code to distribute contents of entry to updatees */ + +static void +distUpdate(Updatee *u) +{ + if (u->lastmod >= u->entry->lastmod) + /* Already has this version */ + return; + u->lastmod = u->entry->lastmod; /* Mark version being xferred */ + + ++statCounter.dist.updates; + kb_incr(&statCounter.dist.update_kbytes, u->entry->mem_obj->inmem_hi); + + u->p = putSend(u->entry, &u->saddr, (PF *) 0, 0, 1 /* dodist */); +} + +/* Distribute entry contents to anybody interested */ +void +distEntryUpdate(StoreEntry *entry, request_t *req, struct sockaddr_in *src) +{ + Updatee *u; + + ++statCounter.dist.content_upd; + + /* Open distribution socket to everybody interested */ + for (u = entry->updatees; u; u = u->next) { + assert(req); + /* Don't send updates to GET-requesting clients, + when we happen to know their identity. We do + know with other peers and on DIST reqs. */ + if (req->dist_type == DIST_DIST + && req->dist_port == u->saddr.sin_port + && req->my_addr.s_addr == u->saddr.sin_addr.s_addr) + continue; + + /* No problems here - send it on out */ + distUpdate(u); + } +} + + +/* Best-case object consistency support */ + +/* Change url from http: to httpdist1234: */ +/* Note: returns pointer to static buffer - contents change on next call. */ +char * +distifyUrl(char *url) +{ + char distbuf[48]; /* dist string holder */ + int plen, poff; + char *eop; + + /* Find the end of the protocol field */ + if ((eop = strchr(url, ':')) == NULL) + /* Give up if not of form http://... */ + return(url); + poff = eop - url; + + snprintf(distbuf, sizeof(distbuf), "dist%d", + ntohs(Config.Sockaddr.http->s.sin_port)); + plen = strlen(distbuf); + + /* Assemble the new URL */ + xmemcpy(urlbuf, url, poff); + xmemcpy(urlbuf + poff, distbuf, plen); + xstrncpy(urlbuf + poff + plen, url + poff, MAX_URL); + + return(urlbuf); +} + + +/* Report on push stats */ +void +statDistPrint(StoreEntry * sentry) +{ + statPutPrint(sentry); + + storeAppendPrintf(sentry, "\nDIST Statistics:\n\n"); + storeAppendPrintf(sentry, "DIST requests: %d\n", + statCounter.dist.dists); + storeAppendPrintf(sentry, "unDIST requests: %d\n", + statCounter.dist.undists); + storeAppendPrintf(sentry, "Updates Sent: %d\n", + statCounter.dist.updates); + storeAppendPrintf(sentry, "KBytes of Update Sent: %d\n", + statCounter.dist.update_kbytes); + storeAppendPrintf(sentry, "Content Updates: %d\n", + statCounter.dist.content_upd); + storeAppendPrintf(sentry, "Updatee Structures: %d\n", + statCounter.dist.updatees); + storeAppendPrintf(sentry, "Updatee Memory Consumption: %d\n", + statCounter.dist.updatees * sizeof(Updatee)); +} + + +/* Need this to make sure that reconfiguration gives correctly + updated FwdPushLinks */ +void +distInit() +{ + DistAllPeers = 0; + + cachemgrRegister("push", "Push Stats", + statDistPrint, 0, 1); +} + + Index: squid/src/enums.h diff -u squid/src/enums.h:1.37 squid/src/enums.h:1.27.2.7 --- squid/src/enums.h:1.37 Sun Jul 21 14:48:03 2002 +++ squid/src/enums.h Tue Sep 3 10:41:45 2002 @@ -48,6 +48,7 @@ LOG_TCP_MEM_HIT, LOG_TCP_DENIED, LOG_TCP_OFFLINE_HIT, + LOG_TCP_PUT, #if LOG_TCP_REDIRECTS LOG_TCP_REDIRECT, #endif @@ -56,6 +57,7 @@ LOG_UDP_DENIED, LOG_UDP_INVALID, LOG_UDP_MISS_NOFETCH, + LOG_UDP_PUT, LOG_ICP_QUERY, LOG_TYPE_MAX } log_type; @@ -92,6 +94,7 @@ ERR_FTP_UNAVAILABLE, ERR_ONLY_IF_CACHED_MISS, /* failure to satisfy only-if-cached request */ ERR_TOO_BIG, + ERR_CONFLICT, TCP_RESET, ERR_MAX } err_type; @@ -437,6 +440,9 @@ PROTO_WHOIS, PROTO_INTERNAL, PROTO_HTTPS, +#if USE_HINT_CACHE + PROTO_ROUTE, +#endif PROTO_MAX } protocol_t; @@ -705,6 +711,7 @@ CBDATA_helper_stateful_server, CBDATA_HttpStateData, CBDATA_peer, + CBDATA_Pusher, CBDATA_ps_state, CBDATA_RemovalPolicy, CBDATA_RemovalPolicyWalker, @@ -723,6 +730,28 @@ VARY_CANCEL }; +enum { + DIST_NONE, + DIST_DIST, + DIST_UNDIST +}; + +#if USE_HINT_CACHE +enum HintCacheNet_State { + HC_uninitialized, + HC_filling, + HC_full, + HC_destroyed +}; + + +typedef enum HintCacheNeighborActionE { + NEIGHBOR_ADD, + NEIGHBOR_REMOVE +} NeighborAction; + +#endif /* USE_HINT_CACHE */ + /* * Store digest state enum */ Index: squid/src/globals.h diff -u squid/src/globals.h:1.17 squid/src/globals.h:1.14.2.4 --- squid/src/globals.h:1.17 Sun Jul 14 17:43:58 2002 +++ squid/src/globals.h Tue Sep 3 10:41:47 2002 @@ -159,6 +159,19 @@ extern RemovalPolicy *mem_policy; extern hash_table *proxy_auth_username_cache; /* NULL */ extern int incoming_sockets_accepted; +extern peer *DistAllPeers; +#if USE_HINT_CACHE +extern hash_table hint_table; +extern const URLKey INVALID_URL_KEY; +extern HintCacheDisk *HCDisk; +extern HintCacheNet *parentOutgoingA; +extern HintCacheNet *childrenOutgoingA; +extern HintCacheNet *neighborsOutgoing; +extern HintCacheDisk *hcDisk; +#if USE_DYNAMIC_HIERARCHY + +#endif /* USE_DYNAMIC_HIERARCHY */ +#endif /* USE_HINT_CACHE */ #if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) extern unsigned int WIN32_OS_version; /* 0 */ extern char *WIN32_OS_string; /* NULL */ Index: squid/src/http.c diff -u squid/src/http.c:1.22 squid/src/http.c:1.17.2.6 --- squid/src/http.c:1.22 Sun Sep 1 09:30:42 2002 +++ squid/src/http.c Tue Sep 3 10:41:48 2002 @@ -45,9 +45,7 @@ static CWCB httpSendComplete; static CWCB httpSendRequestEntity; -static PF httpReadReply; static void httpSendRequest(HttpStateData *); -static PF httpStateFree; static PF httpTimeout; static void httpCacheNegatively(StoreEntry *); static void httpMakePrivate(StoreEntry *); @@ -55,7 +53,7 @@ static int httpCachableReply(HttpStateData *); static void httpMaybeRemovePublic(StoreEntry *, http_status); -static void +void httpStateFree(int fd, void *data) { HttpStateData *httpState = data; @@ -79,9 +77,11 @@ int httpCachable(method_t method) { - /* GET and HEAD are cachable. Others are not. */ - if (method != METHOD_GET && method != METHOD_HEAD) + /* GET, PUT, and HEAD are cachable. Others are not. */ + if (method != METHOD_GET && method != METHOD_HEAD && + method != METHOD_PUT) { return 0; + } /* else cachable */ return 1; } @@ -414,6 +414,7 @@ t = httpState->reply_hdr + k; } *t = '\0'; + httpState->body_remain -= hdr_len - (t - httpState->reply_hdr); httpState->reply_hdr_state++; assert(httpState->reply_hdr_state == 1); ctx = ctx_enter(entry->mem_obj->url); @@ -423,6 +424,9 @@ /* Parse headers into reply structure */ /* what happens if we fail to parse here? */ httpReplyParse(reply, httpState->reply_hdr, hdr_len); + if (reply->content_length > 0) { + httpState->body_remain = reply->content_length + reply->hdr_sz; + } storeTimestampsSet(entry); /* Check if object is cacheable or not based on reply code */ debug(11, 3) ("httpProcessReplyHeader: HTTP CODE: %d\n", reply->sline.status); @@ -531,7 +535,7 @@ /* This will be called when data is ready to be read from fd. Read until * error or connection closed. */ /* XXX this function is too long! */ -static void +void httpReadReply(int fd, void *data) { HttpStateData *httpState = data; @@ -610,7 +614,7 @@ fwdFail(httpState->fwd, err); httpState->eof = 1; comm_close(fd); - } else if (len == 0) { + } else if (len == 0 || len >= httpState->body_remain) { /* Connection closed; retrieval done. */ httpState->eof = 1; if (httpState->reply_hdr_state < 2) @@ -621,8 +625,26 @@ * we want to process the reply headers. */ httpProcessReplyHeader(httpState, buf, len); - fwdComplete(httpState->fwd); - comm_close(fd); + else + /* whole body is subtracted */ + httpState->body_remain -= len; + debug(50, 7) ("httpReadReply: body_remain = %d (len %d, state %d)\n", + httpState->body_remain, len, httpState->reply_hdr_state); + if (len > 0) { + storeAppend(entry, buf, len); + distEntryUpdate(entry, entry->mem_obj->request, + httpState->peer ? &httpState->peer->in_addr : 0); + } + if (entry->mem_obj->request && + entry->mem_obj->request->method == METHOD_PUT) { + putReplyAndClose(fd, entry); + debug(50, 8) ("httpReadReply: called putReplyAndClose\n"); + /* putReplyAndClose calls storeComplete() */ + } + else { + fwdComplete(httpState->fwd); + comm_close(fd); + } } else { if (httpState->reply_hdr_state < 2) { httpProcessReplyHeader(httpState, buf, len); @@ -639,7 +661,11 @@ EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT); } } + httpState->body_remain -= len; + debug(50, 8) ("httpReadReply: %d remain\n", httpState->body_remain); storeAppend(entry, buf, len); + distEntryUpdate(entry, entry->mem_obj->request, + httpState->peer ? &httpState->peer->in_addr : 0); if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { /* * the above storeAppend() call could ABORT this entry, @@ -904,9 +930,16 @@ http_state_flags flags) { const int offset = mb->size; + const char *url; + + url = strLen(request->urlpath) ? strBuf(request->urlpath) : "/"; + if (request->flags.distify) { + /* Ask other cache for dist */ + url = (const char *) distifyUrl((char *) url); + } + memBufPrintf(mb, "%s %s HTTP/1.0\r\n", - RequestMethodStr[request->method], - strLen(request->urlpath) ? strBuf(request->urlpath) : "/"); + RequestMethodStr[request->method], url); /* build and pack headers */ { HttpHeader hdr; @@ -983,6 +1016,7 @@ HttpStateData *httpState; request_t *proxy_req; request_t *orig_req = fwd->request; + peer *peer; debug(11, 3) ("httpStart: \"%s %s\"\n", RequestMethodStr[orig_req->method], storeUrl(fwd->entry)); @@ -991,13 +1025,15 @@ httpState->fwd = fwd; httpState->entry = fwd->entry; httpState->fd = fd; + httpState->body_remain = 0x7fffffff; if (fwd->servers) httpState->peer = fwd->servers->peer; /* might be NULL */ - if (httpState->peer) { + peer = httpState->peer; + if (peer) { proxy_req = requestCreate(orig_req->method, PROTO_NONE, storeUrl(httpState->entry)); - xstrncpy(proxy_req->host, httpState->peer->host, SQUIDHOSTNAMELEN); - proxy_req->port = httpState->peer->http_port; + xstrncpy(proxy_req->host, peer->host, SQUIDHOSTNAMELEN); + proxy_req->port = peer->http_port; proxy_req->flags = orig_req->flags; proxy_req->lastmod = orig_req->lastmod; httpState->request = requestLink(proxy_req); @@ -1008,8 +1044,12 @@ * We might end up getting the object from somewhere else if, * for example, the request to this neighbor fails. */ - if (httpState->peer->options.proxy_only) + if (peer->options.proxy_only) storeReleaseRequest(httpState->entry); + /* Use consistency protocol for this request */ + if (peer->options.dist) { + httpState->request->flags.distify = 1; + } #if DELAY_POOLS assert(delayIsNoDelay(fd) == 0); if (httpState->peer->options.no_delay) @@ -1107,3 +1147,32 @@ version->major = major; version->minor = minor; } + +/* + * Create an httpState parallel to an existing clientHttpRequest + * Assumption: http->entry is either zero or locked. + */ +HttpStateData * +httpStateFromClient(clientHttpRequest *http) +{ + HttpStateData *httpState; + + /* Make me an httpState */ + httpState = cbdataAlloc(HttpStateData); + + /* Fill in the blanks */ + httpState->entry = http->entry; + httpState->request = http->request; + httpState->body_remain = 0x7fffffff; + + assert(http->entry->lock_count >= 1); + /* Lock entry for a second time to reflect presence in httpState */ + /* XXX - can't use storeLockObject() because is NOT_IN_MEMORY (!!!) */ + httpState->entry->lock_count++; + assert(http->entry->lock_count >= 2); + + /* Register new request pointer */ + requestLink(httpState->request); + + return(httpState); +} Index: squid/src/icp_data.c diff -u /dev/null squid/src/icp_data.c:1.1.2.1 --- /dev/null Mon Jan 26 04:57:39 2004 +++ squid/src/icp_data.c Mon Dec 10 14:22:24 2001 @@ -0,0 +1,414 @@ +/* + * $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ + * + * DEBUG: section 83 ICP data transmission + * AUTHOR: Jon Kay, 1999 + * + * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ + * -------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from the + * Internet community. Development is led by Duane Wessels of the + * National Laboratory for Applied Network Research and funded by + * the National Science Foundation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +static icpUdpData *UdpQueueHead = NULL; +static icpUdpData *UdpQueueTail = NULL; +icpQueue UdpCtlQ; +static List_Links icpFragQ; +ICPData_Stats icpdata_stats; + +static void icpRecvPush(int fd, struct sockaddr_in *from, icp_common_t *, + char *buf, int len); +static icpFragList *icpFragNew(char *buf, int off, int nextoff, int totlen, + icp_common_t *hdr, int isfirst); + +static icpFragList *icpFragFree(icpFragList *fl); + + +#define ICP_PUTLINE "PUT %s HTTP/1.0\r\n" + +/* Fragment and encapsulate stuff to be sent */ +void +icpSendData(int vfd, StoreEntry *entry, struct _pusher *p) +{ + int fd = theOutIcpConnection; + icpQueue *q = p->q; + int len, hdrlen, curlen; + struct icp_datab_s *dbhdr; + struct _http_reply *reply; + struct icp_data_s *dhdr; + char *firstline, *lnend; + icp_common_t *hdr; + char *buf, *tbuf; + icpUdpData *pktl; + int islast = 0; + int lchg, nllen, ollen; + + ++icpdata_stats.nsends; + debug(12, 5, "icpDataSend: vfd %d fd %d '%s'\n", vfd, fd, entry->key); + + reply = entry->mem_obj->reply; + curlen = entry->mem_obj->e_current_len; + if (p->objlen == 0) + p->objlen = reply->content_length + reply->hdr_sz; + + if (p->off < p->objlen) + /* Reregister handler */ + /* excess storeRegisters deregistered in putSendDone() call */ + storeRegister(entry, vfd, (PIF) icpSendData, p); + + while (p->off < curlen) { + /* Allocate 8k page, and put AppendUdp and ICP headers at beginning */ + buf = get_free_8k_page(); + hdr = (icp_common_t *) buf; + tbuf = (char *) &hdr[1]; + + /* Fill in ICP header */ + hdr->version = ICP_VERSION_CURRENT; + hdr->flags = 0; + hdr->pad = 0; + hdr->shostid = htonl(theOutICPAddr.s_addr); + + /* Is this the last fragment? */ + /* note: object_len == e_current_len iff storeComplete been called */ + islast = (p->off + 8000 >= entry->mem_obj->e_current_len + && (entry->object_len == curlen || p->objlen <= curlen)); + + if (p->off == 0) { + /* First fragment */ + p->reqnum = htonl(storeReqnum(entry, METHOD_PUT)); + hdr->opcode = ICP_OP_DATABEG; + dbhdr = (struct icp_datab_s *) tbuf; + tbuf = (char *) &dbhdr->db_data; + dbhdr->db_ttl = htonl(8); /* XXX*/ + dbhdr->db_ts = htonl(entry->lastmod); + hdrlen = sizeof(icp_common_t) + 12; + } + else { + /* Remaining fragments */ + hdr->opcode = islast ? ICP_OP_DATAEND : ICP_OP_DATA; + dhdr = (struct icp_data_s *) tbuf; + tbuf = (char *) &dhdr->d_data; + dhdr->d_offset = htonl(p->off); + hdrlen = sizeof(icp_common_t) + 4; + } + + storeClientCopy(entry, p->off, 8000, tbuf, &len, vfd); + + if (p->off == 0) { + /* Change the first line into a PUT line from a REPLY line */ + firstline = xmalloc(sizeof(ICP_PUTLINE) + strlen(entry->url)); + sprintf(firstline, ICP_PUTLINE, entry->url); + lnend = strchr(tbuf, '\n'); + if (lnend == NULL) { + /* Not enough stuff to send. */ + safe_free(firstline); + safe_free(buf); + storeUnregister(entry, vfd); + return; + } + while (lnend[1] == '\r' || lnend[1] == '\n') + ++lnend; + ollen = lnend - tbuf + 1; + nllen = strlen(firstline); + lchg = nllen - ollen; + memmove(tbuf + nllen, tbuf + ollen, len - ollen); + xmemcpy(tbuf, firstline, nllen); + p->objlen += lchg; + len += lchg; + dbhdr->db_size = htonl(p->objlen); + } + + p->off += len; + + hdr->length = hdrlen + len; + hdr->length = htons(hdr->length); + hdr->reqnum = p->reqnum; + + pktl = (icpUdpData *) xmalloc(sizeof(*pktl)); + pktl->address = q->dst; + pktl->msg = buf; + pktl->len = hdrlen + len; + pktl->start = current_time; + pktl->logcode = LOG_TAG_NONE; + pktl->proto = PROTO_NONE; + AppendUdp(q, pktl); + if (q->maxrate) + icpUdpReply(fd, q); + else + commSetSelect(fd, COMM_SELECT_WRITE, + (PF) icpUdpReply, (void *) q, 0); + + if (islast) + putSendDone(p->fd, p); + } + + if (p->off >= p->objlen) + storeUnregister(entry, vfd); +} + +void +icpRecvData(int fd, struct sockaddr_in *src, icp_common_t *hdr, char *buf, int len) +{ + struct icp_datab_s *dbhdr; + struct icp_data_s *dhdr; + icpFragList *fl, *fl2, *efl; + int off, datalen, objlen; + int ismerged; + char *nbuf; + + if (len < sizeof(icp_common_t)) { + debug(12, 0, "icpRecvData: packet shorter than headers (%d bytes)\n", len); + return; + } + if (len < hdr->length) { + debug(12, 0, "icpRecvData: incomplete packet (%d bytes out of %d bytes)\n", + len, hdr->length); + return; + } + + if (hdr->opcode == ICP_OP_DATABEG) { + dbhdr = (struct icp_datab_s *) buf; + buf = (char *) &dbhdr->db_data; + datalen = hdr->length - sizeof(icp_common_t) - 12; + off = 0; + objlen = ntohl(dbhdr->db_size); + if (objlen <= datalen) { + /* One packet long - no defrag needed. */ + nbuf = xmalloc(objlen + 1); + xmemcpy(nbuf, buf, objlen); + icpRecvPush(fd, src, hdr, nbuf, objlen); + return; + } + } + else if (hdr->opcode == ICP_OP_DATA || hdr->opcode == ICP_OP_DATAEND) { + /* A middle fragment */ + dhdr = (struct icp_data_s *) buf; + buf = (char *) &dhdr->d_data; + datalen = hdr->length - sizeof(icp_common_t) - 4; + off = ntohl(dhdr->d_offset); + objlen = 0; + } + else { + debug(12, 0, "icpRecvData: invalid opcode %d\n", hdr->opcode); + return; + } + + /* Find first fragment, with entry */ + debug(12, 5, "icpRecvData: id 0x%x defragging %d-%d\n", + hdr->reqnum, off, off + datalen); + ++icpdata_stats.nfrags; + efl = NULL; + ismerged = 0; + if (off == 0) { + assert(objlen); + fl = icpFragNew(buf, off, off + datalen, objlen, hdr, (int) efl); + LIST_FORALL2(&fl->links, icpFragList *, fl2); { + /* Look for more fragments */ + loopstart: + if (fl2->hdr.reqnum == hdr->reqnum && fl2->off == fl->nextoff) { + /* Consolidate this fragment */ + + if (fl2->off == 0) { + /* this is a dup */ + ++icpdata_stats.ndups; + icpFragFree(fl); + return; + } + + /* merge data */ + if (fl->nextoff < fl2->nextoff) + fl->nextoff = fl2->nextoff; + xmemcpy(fl->buf + fl2->off, fl2->buf, fl2->nextoff - fl2->off); + + /* delete old fragment */ + fl2 = icpFragFree(fl); + + goto loopstart; + } + } + } + else { + LIST_FORALL2(&icpFragQ, icpFragList *, fl) { + if (fl->hdr.reqnum == hdr->reqnum && fl->off == 0) { + if (!efl) + efl = fl; + if (fl->nextoff == off) { + /* Append to this packet */ + fl->nextoff += datalen; + xmemcpy(fl->buf + off, buf, datalen); + ismerged = 1; + if (fl->off == 0 && fl->objlen > 0 && fl->nextoff >= fl->objlen) { + /* Assembly complete*/ + icpRecvPush(fd, src, &fl->hdr, fl->buf, fl->objlen); + fl->buf = 0; + icpFragFree(fl); + return; + } + } + } + } + if (!ismerged) + icpFragNew(buf, off, off + datalen, objlen, hdr, (int) efl); + } +} + +static icpFragList * +icpFragNew(char *buf, int off, int nextoff, int objlen, + icp_common_t *hdr, int isfirst) +{ + icpFragList *fl; + int len; + + fl = (icpFragList *) xmalloc(sizeof *fl); + List_Insert(&fl->links, LIST_ATREAR(&icpFragQ)); + + len = (off ? nextoff - off : objlen + 1); + fl->buf = xmalloc(len + 1); + + xmemcpy(fl->buf, buf, nextoff - off); + fl->lasttime = squid_curtime; + fl->hdr = *hdr; + fl->off = off; + fl->nextoff = nextoff; + fl->objlen = objlen; + + return(fl); +} + +static icpFragList * +icpFragFree(icpFragList *fl) +{ + icpFragList *nfl; + +#if 0 + printf("icpFragFree: id 0x%x freeing %d-%d obj at 0x%x\n", + fl->hdr.reqnum, fl->off, fl->nextoff, fl->buf); +#endif + nfl = (icpFragList *) List_Next(&fl->links); + List_Remove(&fl->links); + if (fl->buf) + safe_free(fl->buf); + safe_free(fl); + return(nfl); +} + +static void +icpFragTimer() +{ + icpFragList *fl; +#if 0 /* JSKDEBUG */ + int nfrags = 0, mem = 0; +#endif + + eventAdd("icpdata fragment timer", (EVH) icpFragTimer, NULL, + Config.icp_frag_tmo); + + LIST_FORALL2(&icpFragQ, icpFragList *, fl) { + loopstart: + if ((char *) fl != (char *) &icpFragQ) { +#if 0 /* JSKDEBUG */ + ++nfrags; + mem += fl->objlen + sizeof(*fl); +#endif + if (squid_curtime - fl->lasttime >= Config.icp_frag_tmo) { + ++icpdata_stats.ntmofrags; + fl = icpFragFree(fl); + goto loopstart; + } + } + } +#if 0 /* JSKDEBUG */ + printf("icpFragTimer: %d frags, for total of %d bytes used\n", + nfrags, mem); +#endif +} + + +static void +icpRecvPush(int fd, struct sockaddr_in *src, icp_common_t *hdr,char *buf, int len) +{ + icpStateData *icpState = xcalloc(sizeof(icpStateData), 1); + request_t *request = NULL; + int err; + + debug(12, 3, "icpRecvPush on fd %d: Hi!\n", fd); + ++icpdata_stats.nrecvs; + + /* Construct icpState */ + icpState->start = current_time; + icpState->inbuf = buf; + icpState->inbufsize = 8192; + icpState->header = *hdr; + icpState->peer = *src; + icpState->log_addr = src->sin_addr; + icpState->log_addr.s_addr &= Config.Addrs.client_netmask.s_addr; + icpState->log_type = LOG_UDP_PUT; + icpState->me = *getMyAddr(); + icpState->me.sin_port = Config.Port.icp; + icpState->entry = NULL; + icpState->in_offset = len; + icpState->fd = comm_virtual_fd(); + + fd_note(fd, inet_ntoa(icpState->log_addr)); + comm_add_close_handler(icpState->fd, icpStateFree, (void *) icpState); + + err = parseHttpRequest(icpState); + icpState->inbuf[icpState->in_offset] = '\0'; /* Terminate the string */ + if (err == 1) { + if ((request = urlParse(icpState->method, icpState->url)) == NULL) { + debug(12, 0, "icpRecvPush: Invalid URL: %s\n", icpState->url); + return; + } + safe_free(icpState->log_url); + icpState->log_url = xstrdup(urlCanonicalClean(request)); + request->http_ver = icpState->http_ver; + if (!urlCheckRequest(request)) { + debug(12, 0, "icpRecvPush: Invalid request: %s\n"); + return; + } + icpState->request = requestLink(request); + + /* XXX - Uncomment to make acls work with icpdata pushes */ + /* Currently causes core dump, needs debugging */ + /* clientAccessCheck(icpState, clientAccessCheckDone);*/ + } + else if (err == 0) { + debug(12, 0, "icpRecvPush: got partial request\n"); + return; + } + else { /* err == -1 */ + debug(12, 0, "icpRecvPush: got invalid request\n"); + return; + } + + putRecv(icpState); +} + +void +icpDataInit() +{ + List_Init(&icpFragQ); + List_Init(&UdpCtlQ.links); + UdpCtlQ.nextsend.tv_sec = UdpCtlQ.nextsend.tv_usec = 0; + UdpCtlQ.maxrate = 0; + eventAdd("icpdata fragment timer", (EVH) icpFragTimer, NULL, + Config.icp_frag_tmo); +} Index: squid/src/icp_v2.c diff -u squid/src/icp_v2.c:1.6 squid/src/icp_v2.c:1.5.14.3 --- squid/src/icp_v2.c:1.6 Fri Aug 9 14:46:02 2002 +++ squid/src/icp_v2.c Tue Sep 3 10:41:49 2002 @@ -302,6 +302,14 @@ neighborsUdpAck(key, &header, &from); break; +#if USE_ICP_DATA + case ICP_OP_DATABEG: + case ICP_OP_DATA: + case ICP_OP_DATAEND: + icpRecvData(fd, &from, &header, buf + sizeof(header), len); + break; +#endif + case ICP_INVALID: case ICP_ERR: break; Index: squid/src/icp_v3.c diff -u squid/src/icp_v3.c:1.5 squid/src/icp_v3.c:1.4.44.3 --- squid/src/icp_v3.c:1.5 Fri Aug 9 14:46:02 2002 +++ squid/src/icp_v3.c Tue Sep 3 10:41:49 2002 @@ -143,6 +143,14 @@ neighborsUdpAck(key, &header, &from); break; +#if USE_ICP_DATA + case ICP_OP_DATABEG: + case ICP_OP_DATA: + case ICP_OP_DATAEND: + icpRecvData(fd, &from, &header, buf + sizeof(header), len); + break; +#endif + case ICP_INVALID: case ICP_ERR: break; Index: squid/src/main.c diff -u squid/src/main.c:1.36 squid/src/main.c:1.28.2.6 --- squid/src/main.c:1.36 Thu Aug 8 12:41:58 2002 +++ squid/src/main.c Tue Sep 3 10:41:51 2002 @@ -336,6 +336,7 @@ externalAclShutdown(); storeDirCloseSwapLogs(); errorClean(); + distInit(); enter_suid(); /* root to read config file */ parseConfigFile(ConfigFile); setEffectiveUser(); @@ -511,6 +512,12 @@ #if DELAY_POOLS delayPoolsInit(); #endif +#if USE_HINT_CACHE + hintCacheInit(); +#endif +#if USE_ICP_DATA + icpDataInit(); +#endif fwdInit(); } #if USE_WCCP @@ -626,6 +633,7 @@ eventInit(); /* eventInit() is required for config parsing */ storeFsInit(); /* required for config parsing */ authenticateSchemeInit(); /* required for config parsign */ + distInit(); /* Needed for fwdall list */ parse_err = parseConfigFile(ConfigFile); if (opt_parse_cfg_only) Index: squid/src/mem.c diff -u squid/src/mem.c:1.20 squid/src/mem.c:1.13.8.1 --- squid/src/mem.c:1.20 Sat Jul 20 18:06:07 2002 +++ squid/src/mem.c Tue Sep 3 10:41:52 2002 @@ -323,10 +323,6 @@ memInit(void) { int i; - - debug(13, 1) ("Memory pools are '%s'; limit: %.2f MB\n", - (Config.onoff.mem_pools ? "on" : "off"), toMB(mem_idle_limit)); - /* set all pointers to null */ memset(MemPools, '\0', sizeof(MemPools)); /* Index: squid/src/neighbors.c diff -u squid/src/neighbors.c:1.19 squid/src/neighbors.c:1.14.2.2 --- squid/src/neighbors.c:1.19 Wed Aug 28 14:45:44 2002 +++ squid/src/neighbors.c Tue Sep 3 10:41:53 2002 @@ -38,6 +38,8 @@ /* count mcast group peers every 15 minutes */ #define MCAST_COUNT_RATE 900 + + static int peerAllowedToUse(const peer *, request_t *); static int peerWouldBePinged(const peer *, request_t *); static void neighborRemove(peer *); Index: squid/src/protos.h diff -u squid/src/protos.h:1.59 squid/src/protos.h:1.41.2.7 --- squid/src/protos.h:1.59 Sat Jul 20 05:33:16 2002 +++ squid/src/protos.h Tue Sep 3 10:41:54 2002 @@ -180,6 +180,9 @@ extern void commCloseAllSockets(void); extern void checkTimeouts(void); extern int commDeferRead(int fd); +#if USE_ICP_DATA +extern int comm_virtual_fd(void); +#endif /* USE_ICP_DATA */ /* @@ -313,6 +316,9 @@ extern int httpAnonHdrDenied(http_hdr_type hdr_id); extern void httpBuildRequestHeader(request_t *, request_t *, StoreEntry *, HttpHeader *, int, http_state_flags); extern void httpBuildVersion(http_version_t * version, unsigned int major, unsigned int minor); +extern HttpStateData *httpStateFromClient(clientHttpRequest *http); +extern PF httpReadReply; +extern PF httpStateFree; extern const char *httpMakeVaryMark(request_t * request, HttpReply * reply); /* ETag */ @@ -532,6 +538,12 @@ int reqnum, int pad); extern int icpUdpSend(int, const struct sockaddr_in *, icp_common_t *, log_type, int); +#if USE_ICP_DATA +void icpSendData(int vfd, StoreEntry *entry, struct _pusher *p); +void icpRecvData(int fd, struct sockaddr_in *src, icp_common_t *hdr, + char *buf, int len); +void icpDataInit(); +#endif extern PF icpHandleUdp; extern PF icpUdpSendQueue; extern PF httpAccept; @@ -1102,7 +1114,8 @@ extern char *url_convert_hex(char *org_url, int allocate); extern char *url_escape(const char *url); -extern protocol_t urlParseProtocol(const char *); +extern protocol_t urlParseProtocol(const char *, u_short *, + int *); extern method_t urlParseMethod(const char *); extern void urlInitialize(void); extern request_t *urlParse(method_t, char *); @@ -1288,6 +1301,26 @@ extern void logfilePrintf(va_alist); #endif +/* put.c */ +void putRecv(clientHttpRequest *); +Pusher *putSend(StoreEntry *, struct sockaddr_in *, PF, void *, + int dodist); +void putSendDone(int fd, void *data); +void putReplyAndClose(int, StoreEntry *); +void statPutPrint(StoreEntry * sentry); + +/* dist.c */ +extern Updatee *distNewUpdatee(StoreEntry *entry, + struct in_addr host, u_short dport); +extern void distDelUpdatees(Updatee *u); +extern void distDelUpdatee(StoreEntry *entry, struct in_addr host, int dport); +extern void distUpdateeChangeEntry(StoreEntry *entry, Updatee *u); +extern void distEntryUpdate(StoreEntry *e, request_t *req, + struct sockaddr_in *peer); +extern char *distifyUrl(char *url); +extern void distInputDone(StoreEntry *); +void distInit(); + /* * Removal Policies */ @@ -1312,6 +1345,146 @@ */ extern StatCounters *snmpStatGet(int); + +#if USE_HINT_CACHE +/* Hint Cache Interface */ +/* open existing cache; return nonzero on error */ +int hintCacheInit(); +void hintCacheCreate(); /* create new cache */ +void hintCacheDestroy(); +void hintCacheInformLocalCopy(StoreEntry *); /* tell hierarchy I have a copy */ +void hintCacheInvalLocalCopy(StoreEntry *); /* say I don't have a copy */ +int hintCacheActive(); /* Ask hint cache if it is operational. */ +struct sockaddr_in *hintCachefindNearest(char *url, struct sockaddr_in *); + +void hintCacheNodeKeyInit(NodeKey *k, const struct sockaddr_in *addrP); +int hintCacheNodeKeyCompare(const NodeKey *k1, const NodeKey *k2); +struct sockaddr_in hintCacheNodeKeyGetAddr(const NodeKey *k); +HintCacheKey hintCacheNodeKeyKey(const struct sockaddr_in *addrP); + +void hintCacheEntryInit(HintCacheEntry *, URLKey, struct sockaddr_in *, + unsigned int mtime); +int hintCacheEntryCompare(HintCacheEntry *e1, HintCacheEntry *e2); +void hintCacheEntryInitNet(HintCacheEntryNet *mungedEntry, HintCacheEntry *entry); +void hintCacheEntryLocalFormatNet(HintCacheEntryNet *mungedEntry, HintCacheEntry *entry); + +int hintCacheUpdateCompare(HintCacheUpdate *u1, HintCacheUpdate *u2); +void hintCacheUpdateInit(HintCacheUpdate *, int action, HintCacheEntry *, int hopcount); + +void hintCacheUpdateInitNet(HintCacheUpdateNet *mungedUpdate, HintCacheUpdate *update); +void hintCacheUpdateLocalFormatNet(HintCacheUpdateNet *mungedUpdate, HintCacheUpdate *update); +int hintCacheURLKeyCompare(URLKey *u1, URLKey *u2); +StoreEntry *hintCacheStoreGet(URLKey urlkey); + + +/* Hint Cache Disk */ +void hintCacheDiskInit(HintCacheDisk *d, char *diskPath); +void hintCacheDiskClose(HintCacheDisk *d); +void hintCacheDiskCreateFile(char *hcPath, int size, int associativity); +void hintCacheDiskInformLocal(HintCacheDisk *d, URLKey key, unsigned mtime); +void hintCacheDiskInvalLocal(HintCacheDisk *d, URLKey key, unsigned mtime); +void hintCacheDiskPrefetch(HintCacheDisk *d, HintCacheUpdate *uArray, int nupdates); +int hintCacheDiskNetInvalRecord(HintCacheDisk *d, HintCacheEntry *target, HintCacheEntry *survivor); +int hintCacheDiskUpdateIfCloser(HintCacheDisk *d, HintCacheEntry *new); +int hintCacheDiskFindNearest(HintCacheDisk *d, URLKey key, HintCacheEntry *match); +void hintCacheDiskDeleteHintCache(); + +long long unsigned hintCacheEndian_llNetToMachine(long long unsigned net); +long long unsigned hintCacheEndian_llMachineToNet(long long unsigned mach); +void hintCacheEndian_selfTest(void); + +void hintCacheInitNet(HintCacheNet *n); +int hintCacheNetIsInitialized(void); + void hintCacheNetDestroy(HintCacheNet *n); +void hintCacheNetEnqueue(HintCacheNet *, int action, + HintCacheEntry *, int hopcount); +int hintCacheNetBytesReady(HintCacheNet *n); +void hintCacheNetComplete(HintCacheNet *n); +void hintCacheNetDone(HintCacheNet *n); +void hintCacheNetSendTo(HintCacheNet *, struct sockaddr_in *); +void hintCacheNetSendJoin(); +void hintCacheNetDataArrives(char *data, int len, HintCacheNetHeader *hdr, + struct sockaddr_in *source); +void hintCacheNetSetTestMode(HintCacheNet *n); +int hintCacheNetGetTestCount(HintCacheNet *n); + +void hintCachePropLocalAction(StoreEntry *, int action); +void hintCachePropHandleInvalToChild(HintCacheUpdate *update, + struct sockaddr_in *src, int local); +void hintCachePropHandleInformToChild(HintCacheUpdate *update, + struct sockaddr_in *src, int local) ; +void hintCachePropHandleInvalToParent(HintCacheUpdate *update, + struct sockaddr_in *src, int local); +void hintCachePropHandleInformToParent(HintCacheUpdate *update, + struct sockaddr_in *src, int local); + +void hintCacheNodelistInit(); /* constructor */ +void hintCacheNodelistDestroy(); /* destructor */ +void hintCacheNodelistSelfTest(); +void hintCacheNodelistLocalJoin(); /* I do a join */ +void hintCacheNodelistLocalLeave(); /* I do a leave */ +int hintCacheNodelistMyStatus(); /* Am I in or out? */ +void hintCacheNodelistNetJoin(struct sockaddr_in *sin, int hops, long long timeNS); +void hintCacheNodelistNetLeave(struct sockaddr_in *sin, int hops, long long timeNS); +void hintCacheNodelistIterStart(HintCacheNodeListIter *iter); +int hintCacheNodelistIterCheck(HintCacheNodeListIter iter); +void hintCacheNodelistIterNext(HintCacheNodeListIter *iter); +int hintCacheNodelistIterGetAddr(HintCacheNodeListIter iter, + struct sockaddr_in *ret); + +void hintCacheHierUpdateMembershipNeighbor(struct sockaddr_in *neighbor, + NeighborAction); +void hintCacheHierInit(); +void hintCacheHierDestroy(); +int hintCacheHierCompareDistanceFromMe(struct in_addr new, struct in_addr old); +void hintCacheHierNewNode(struct sockaddr_in *sin, int hops, long long time); +void hintCacheHierDelNode(struct sockaddr_in *sin, int hops, long long time); +int hintCacheHierCheckIfParent(URLKey key, struct sockaddr_in *candidate); +int hintCacheHierCheckIfChild(struct sockaddr_in *candidate); +void hintCacheHierAddChild(struct sockaddr_in *child); +void hintCacheHierRemoveChild(struct sockaddr_in *child); +int hintCacheHierNChildrenQs(); +int hintCacheHierChildQIndex(URLKey *key, int iAmRoot, int *amILeaf); +int hintCacheHierGetChildAddrs(int qIndex, struct sockaddr_in **retAddr); +int hintCacheHierNParentQs(); +int hintCacheHierParentQIndex(URLKey *key, int *amIRoot); +int hintCacheHierGetParentAddr(int index, struct sockaddr_in *retAddr); +int hintCacheHierSendToParent(struct sockaddr_in *src, HintCacheUpdate *update, + int msgtype); +int hintCacheHierSendToSiblings(struct sockaddr_in *src, HintCacheUpdate *update, + int msgtype, int siblingtype); + +#ifdef USE_DYNAMIC_HIERARCHY +/* Plaxton Dynamic Hierarchy algorithm */ +void plaxtonInit(int bitsPerLevel); +void plaxtonDestroy(); +int plaxtonChildQIndex(URLKey *key, int iAmRoot, int *amILeaf); +int plaxtonNChildrenQsI(); +int plaxtonGetChildAddrs(int qIndex, struct sockaddr_in **retAddrAP); +int plaxtonNParentQs(); +int plaxtonParentQIndex(URLKey *key, int *amIRoot); +int plaxtonGetParentAddr(int index, struct sockaddr_in *retAddr); +/* + * Callbacks when nodes added/removed/change distance + */ +void plaxtonAddNode(struct sockaddr_in *newNode); +void plaxtonRemoveNode(struct sockaddr_in *goneNode); +void plaxtonChangeDistance(struct sockaddr_in *changeDistNode); +int plaxtonCheckIfParent(URLKey key, struct sockaddr_in *candidate); +int plaxtonCheckIfChild(struct sockaddr_in *candidate); +void plaxtonAddChild(struct sockaddr_in *child); +void plaxtonRemoveChild(struct sockaddr_in *child); +int plaxtonMatchBits(HintCacheKey k1, HintCacheKey k2); +HintCacheKey plaxtonMyNodeKey(); + +extern int Plaxton_BucketsPerLevel; +extern HintCacheNet *Plaxton_parentOutgoingA; +extern HintCacheNet *Plaxton_childrenOutgoingA; +extern HintCacheNet *Plaxton_neighborsOutgoing; +#endif /* USE_DYNAMIC_HIERARCHY / Plaxton algorithm */ + +#endif /* USE_HINT_CACHE */ + /* Vary support functions */ int varyEvaluateMatch(StoreEntry * entry, request_t * req); Index: squid/src/put.c diff -u /dev/null squid/src/put.c:1.1.2.7 --- /dev/null Mon Jan 26 04:57:39 2004 +++ squid/src/put.c Tue Sep 3 10:41:55 2002 @@ -0,0 +1,457 @@ +/* + * $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ + * + * DEBUG: section 81 PUT transmission and reception + * AUTHOR: Jon Kay, 1997 + * + * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ + * -------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from the + * Internet community. Development is led by Duane Wessels of the + * National Laboratory for Applied Network Research and funded by + * the National Science Foundation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "squid.h" + +#define PUT_REPLY_HDR() "HTTP/1.0 200 OK\r\n" + +#define PUT_DELETE_GAP (1<<18) + +static PF putRecvFree; +static void putRecvError(clientHttpRequest *http, + err_type error, http_status entry); +static void putProcessHeader(HttpStateData *, clientHttpRequest *); +static void putSendWrite(void *data, char *buf, ssize_t len); +static CNCB putConnected; +static CWCB putSendSent; + +/* + * Code for dealing with incoming PUT requests + */ +void +putRecv(clientHttpRequest *http) +{ + request_t *request = http->request; + ConnStateData *conn = http->conn; + StoreEntry *entry, *oentry; + int lastmod, olastmod = -1; + HttpStateData *httpState; + request_flags rflags; + HttpReply *reply; + peer *p; + + http->request->flags.cachable = 1; + if (http->log_type != LOG_UDP_PUT) + http->log_type = LOG_TCP_PUT; + http->out.offset = 0; + + oentry = storeGetPublic(http->uri, request->method); + if (oentry) { + olastmod = oentry->lastmod; + storeSetPrivateKey(oentry); + } + + /* Create private, blank entry */ + *(unsigned int *) &rflags = 0; + rflags.cachable = 1; + entry = storeCreateEntry(http->uri, http->uri, rflags, request->method); + + http->entry = entry; + + /* Need a request pointer in the mem_obj */ + requestLink(http->request); + entry->mem_obj->request = request; + + debug(81, 4) ("putRecv: %s for '%s'\n", log_tags[http->log_type], + http->uri); + + /* Update timestamp */ + storeTimestampsSet(entry); + + /* Create an HTTP context from client_side info */ + assert(http->entry->lock_count >= 1 && http->entry->lock_count < 200); + httpState = httpStateFromClient(http); + assert(http->entry->lock_count >= 2 && http->entry->lock_count < 200); + httpState->entry = entry; + /* Prepare to reply and free httpState if PUT succeeds. */ + comm_add_close_handler(conn->fd, putRecvFree, httpState); + + assert(http->entry->lock_count >= 2 && http->entry->lock_count < 200); + /* Parse the headers */ + putProcessHeader(httpState, http); + reply = entry->mem_obj->reply; + + /* Update the timestamp */ + lastmod = entry->mem_obj->reply->last_modified; + if (lastmod > -1) { + if (lastmod < olastmod) { + /* We do not accept old versions */ + ++statCounter.put.conflicts; + putRecvError(http, ERR_CONFLICT, HTTP_CONFLICT); + if (oentry) + storeSetPublicKey(oentry); + /* putRecvFree will clean up on fd close */ + return; + } + /* Note: it's OK to overwrite the same version. It just won't be + propagated. */ + entry->lastmod = lastmod; + } + else + /* Make it clear the version has changed even if no lastmod */ + entry->lastmod = olastmod + 1; + + if (oentry) { + /* This PUT request is good to go in. + * Lose the old entry. */ + distUpdateeChangeEntry(entry, oentry->updatees); + oentry->updatees = 0; + storeRelease(oentry); + } + + /* Make sure dist knows about the sender, and distribute the update */ + if (request->dist_type == DIST_DIST) + distNewUpdatee(entry, conn->peer.sin_addr, request->dist_port); + else if (request->dist_type == DIST_UNDIST) + distDelUpdatee(entry, conn->peer.sin_addr, request->dist_port); + distEntryUpdate(entry, request, &conn->peer); + + /* fwdpush support */ + if (http->log_type == LOG_TCP_PUT) { + for (p = DistAllPeers; p; p = p->fwdpush) { +#if USE_ICP_DATA + if (p->options.icpdata) { + putSend(entry, &p->in_addr, NULL, NULL, P_ICPDATA, p->icp_data_q); + } + else { +#endif + struct sockaddr_in sin; + + sin.sin_family = AF_INET; + sin.sin_addr = p->in_addr.sin_addr; + sin.sin_port = htons(p->http_port); + putSend(entry, &sin, NULL, NULL, 0); +#if USE_ICP_DATA + } +#endif + } + } + + /* Update stats */ + ++statCounter.put.ins; + + /* XXX - Can we use httpReplyParse to simplify this? */ + + /* httpReadReply reads msgs with bodies */ + if (entry->mem_obj->inmem_hi < reply->content_length + reply->hdr_sz) { + httpReadReply(conn->fd, httpState); + } + else + putReplyAndClose(conn->fd, entry); +} + + +/* Process PUT header. */ +static void +putProcessHeader(HttpStateData *httpState, clientHttpRequest *client) +{ + static char replline[] = "HTTP/1.0 200 OK"; + char *hdr = client->hdr_str; + ConnStateData *conn = client->conn; + int hdrlen; + int bodylen = conn->in.offset; /* !yep! */ + char *eol; + + /* First change the PUT first line to a reply first line */ + eol = strchr(hdr, '\r'); + eol[0] = '\0'; + strcpy(hdr, replline); + memset(hdr + sizeof(replline) - 1, ' ', eol - hdr - sizeof(replline) + 1); + eol[0] = '\r'; + + hdrlen = strlen(hdr); + + httpProcessReplyHeader(httpState, hdr, hdrlen); + debug(81, 6) ("putProcessHeader: need %d bytes\n", httpState->body_remain); + + /* store header and start of data */ + storeAppend(client->entry, hdr, hdrlen); + if (bodylen > 0) + storeAppend(client->entry, conn->in.buf, bodylen); + + httpState->body_remain -= client->entry->mem_obj->inmem_hi; + debug(81, 6) ("putProcessHeader: got %d bytes, %d remain\n", + hdrlen + bodylen, httpState->body_remain); +} + +void +putClose(int fd, char *buf, size_t size, int errflag, void *data) +{ + comm_close(fd); /* close fd and call putRecvFree */ +} + +void +putReplyAndClose(int fd, StoreEntry *entry) +{ + storeComplete(entry); + + /* PUT succeeded, acknowledge this. */ + if (entry->mem_obj->reply->sline.status == 200) { + debug(81, 6) ("putReplyAndClose: replying on %d\n", fd); + comm_write(fd, PUT_REPLY_HDR(), sizeof(PUT_REPLY_HDR()), + putClose, 0, 0); + } + else { + /* Already aborted, hopefully with error msg */ + debug(81, 2) ("putReplyAndClose: not replying - code = %d\n", + entry->mem_obj->reply->sline.status); + comm_close(fd); /* close fd and call putRecvFree */ + } +} + +static void +putRecvFree(int fd, void *data) +{ + HttpStateData *httpState = data; + StoreEntry *entry = httpState->entry; + + kb_incr(&statCounter.put.kbytes_in, entry->mem_obj->inmem_hi); + + httpStateFree(fd, httpState); + assert(entry->lock_count >= 1); + /* Last unlock will be from httpRequestFree */ +} + +static void +putRecvError(clientHttpRequest *http, + err_type error, http_status status) +{ + ErrorState *err; + + http->log_type = LOG_TCP_DENIED; + err = errorCon(error, status); + err->request = requestLink(http->request); + err->src_addr = http->conn->peer.sin_addr; + http->entry = clientCreateStoreEntry(http, http->request->method, null_request_flags); + errorAppendEntry(http->entry, err); +} + + +/* Output PUTs */ + +/* + * Make up and send a PUT to a given location. + * + * The sockaddr_in does not have to persist when + * the call completes. + */ +Pusher * +putSend(StoreEntry *entry, struct sockaddr_in *saddr, + PF *handler, void *arg, int dodist) +{ + struct in_addr nobody; + Pusher *p; + int fd; + + /* Allocate memory for buffer and state tracking */ + storeLockObject(entry); /* Yes, we need this, even on top of StoreClient. */ + p = cbdataAlloc(Pusher); + p->hdr.sc = storeClientListAdd(entry, p); + p->hdr.flags.disting = dodist; + p->hdr.flags.active = 1; + p->hdr.off = 0; + p->hdr.objlen = 0; + p->hdr.entry = entry; + p->hdr.handler = handler; + p->hdr.arg = arg; +#if USE_ICP_DATA + if (flags & P_ICPDATA) { + p->hdr.fd = comm_virtual_fd(); + p->hdr.q = q; + q->dst = *saddr; + icpSendData(p->hdr.fd, entry, p); + return(p); + } + else + p->hdr.q = 0; +#endif + + /* Need to create and connect a PUT socket */ + nobody.s_addr = INADDR_ANY; + p->hdr.fd = fd = comm_open(SOCK_STREAM, 0, nobody, 0, COMM_NONBLOCKING, "put"); + if (fd == COMM_ERROR) { + debug(11, 1) ("putSend: Could not create new socket.\n"); + putSendDone(-1, p); + return(0); + } + + /* Deal with socket closing */ + comm_add_close_handler(fd, putSendDone, p); + + ++statCounter.put.outs; + + /* Connect to this updatee */ + strcpy(p->hdr.hname, inet_ntoa(saddr->sin_addr)); + commConnectStart(fd, p->hdr.hname, ntohs(saddr->sin_port), + putConnected, p); + + return(p); +} + +/* Update given updatee on contents of entry */ +static void +putConnected(int fd, int commstat, void *data) +{ + Pusher *p = (Pusher *) data; + StoreEntry *entry = p->hdr.entry; + char *url; + + if (commstat == COMM_ERROR) { + /* XXX - this should be more sophisticated */ + debug(11, 1) ("putConnected: Could not connect to %s\n", p->hdr.hname); + putSendDone(fd, p); + return; + } + + /* Figure out what URL to use */ + url = entry->mem_obj->url; + if (p->hdr.flags.disting) { + url = distifyUrl(url); + } + + /* Compose header */ + snprintf(p->data, sizeof(p->data), "PUT %s HTTP/1.0\r\n", url); + p->hdr.off = -strlen(p->data); + + /* Write object asynchronously, starting with header */ + comm_write(fd, p->data, strlen(p->data), putSendSent, p, 0); +} + +/* Xfer data from mem_obj to updatee */ +/* XXX - duplication with icpSendMoreData, etc. */ +static void +putSendSent(int fd, char *obuf, size_t size, int errflag, void *data) +{ + Pusher *p = (Pusher *) data; + StoreEntry *entry = p->hdr.entry; + + debug(53, 5) ("putSendSent: FD %d '%s'\n", fd, entry->mem_obj->url); + + if (errflag) { + debug(53, 3) ("putSendSent: write failed, errno %d\n", errno); + putSendDone(fd, p); + return; + } + + p->hdr.off += size; + + if (p->hdr.off >= entry->mem_obj->inmem_hi) { + /* We've sent everything we've seen so far */ + if (entry->mem_obj->object_sz == entry->mem_obj->inmem_hi) { + /* We've seen all we're gonna see of this version */ + /* note: object_len == inmem_hi iff storeComplete been called */ + putSendDone(fd, p); + return; + } + } + + storeClientCopy(p->hdr.sc, entry, p->hdr.off, + sizeof(p->data) - p->hdr.off, + p->data, putSendWrite, p); +} + +/* xlate storeClientCopy calling conventions to comm_write ones */ +static void +putSendWrite(void *data, char *buf, ssize_t len) +{ + Pusher *p = (Pusher *) data; + int skipped; + char *tbuf; + + /* + * Skip over the first line, if this is the first call to putSendSent + * and that first line starts with HTTP/1.x. That would be the first + * line in a server reply, and is incorrect in a PUT request. + */ + if (p->hdr.off == 0) { + tbuf = strchr(p->data, '\n'); + if (!tbuf) + /* Malformatted or not enough data present yet. + * Either way, don't propagate this message. */ + return; + + while (*++tbuf == '\r') + ; + skipped = tbuf - p->data; + p->hdr.off += skipped; + len -= skipped; + buf += skipped; + } + else + tbuf = p->data; + + /* Do the work. */ + comm_write(p->hdr.fd, buf, len, putSendSent, p, 0); +} + +/* Send the object's data */ +void +putSendDone(int fd, void *data) +{ + Pusher *p = data; + StoreEntry *entry = p->hdr.entry; + + if (!(p->hdr.flags.active)) + return; + p->hdr.flags.active = 0; + + if (p->hdr.handler) + (*p->hdr.handler)(fd, p->hdr.arg); + + kb_incr(&statCounter.put.kbytes_out, p->hdr.off); + storeUnregister(p->hdr.sc, entry, (void *) fd); + storeUnlockObject(entry); + + /* Free 8k buffer and pusher state along with it */ + cbdataFree(p); + + /* Don't close if ICP - ICP sends via theIcpOutConnection, + * which we cannot afford to close. */ + if (fd != -1) + comm_close(fd); +} + + +/* Report on push stats */ +void +statPutPrint(StoreEntry * sentry) +{ + storeAppendPrintf(sentry, "PUT Statistics:\n\n"); + storeAppendPrintf(sentry, "PUTs Sent: %d\n", + statCounter.put.outs); + storeAppendPrintf(sentry, "PUT KBytes Sent: %d\n", + (int) statCounter.put.kbytes_out.kb); + storeAppendPrintf(sentry, "PUTs Received: %d\n", + statCounter.put.ins); + storeAppendPrintf(sentry, "PUT KBytes Received: %d\n", + (int) statCounter.put.kbytes_in.kb); + storeAppendPrintf(sentry, "Stale Objects Received: %d\n", + statCounter.put.conflicts); +} Index: squid/src/squid.h diff -u squid/src/squid.h:1.19 squid/src/squid.h:1.13.2.3 --- squid/src/squid.h:1.19 Sun Sep 1 09:30:42 2002 +++ squid/src/squid.h Tue Sep 3 10:41:56 2002 @@ -410,6 +410,10 @@ #include "snprintf.h" #endif +#if HAVE_SYS_MMAN_H +#include +#endif + #define XMIN(x,y) ((x)<(y)? (x) : (y)) #define XMAX(a,b) ((a)>(b)? (a) : (b)) Index: squid/src/stat.c diff -u squid/src/stat.c:1.17 squid/src/stat.c:1.13.2.4 --- squid/src/stat.c:1.17 Sun Apr 7 17:38:18 2002 +++ squid/src/stat.c Tue Sep 3 10:41:57 2002 @@ -816,6 +816,32 @@ storeAppendPrintf(sentry, "aborted_requests = %f/sec\n", XAVG(aborted_requests)); + storeAppendPrintf(sentry, "dist.dists = %f/sec\n", + XAVG(dist.dists)); + storeAppendPrintf(sentry, "dist.undists = %f/sec\n", + XAVG(dist.undists)); + storeAppendPrintf(sentry, "dist.updates = %f/sec\n", + XAVG(dist.updates)); + storeAppendPrintf(sentry, "dist.update_kbytes = %f/sec\n", + XAVG(dist.update_kbytes.kb)); + storeAppendPrintf(sentry, "dist.content_upd = %f/sec\n", + XAVG(dist.content_upd)); + storeAppendPrintf(sentry, "dist.updatees = %f/sec\n", + XAVG(dist.updatees)); + storeAppendPrintf(sentry, "dist.updatees = %f/sec\n", + XAVG(dist.updatees * sizeof(Updatee))); + + storeAppendPrintf(sentry, "put.outs = %f/sec\n", + XAVG(put.outs)); + storeAppendPrintf(sentry, "put.kbytes_out = %f/sec\n", + XAVG(put.kbytes_out.kb)); + storeAppendPrintf(sentry, "put.ins =: %f\n", + XAVG(put.ins)); + storeAppendPrintf(sentry, "put.kbytes_in = %f/sec\n", + XAVG(put.kbytes_in.kb)); + storeAppendPrintf(sentry, "put.conflicts = %f/sec\n", + XAVG(put.conflicts)); + #if USE_POLL storeAppendPrintf(sentry, "syscalls.polls = %f/sec\n", XAVG(syscalls.polls)); #endif @@ -1200,6 +1226,32 @@ f->swap.files_cleaned); storeAppendPrintf(sentry, "aborted_requests = %d\n", f->aborted_requests); + + storeAppendPrintf(sentry, "dist.dists = %d\n", + f->dist.dists); + storeAppendPrintf(sentry, "dist.undists = %d\n", + f->dist.undists); + storeAppendPrintf(sentry, "dist.updates = %d\n", + f->dist.updates); + storeAppendPrintf(sentry, "dist.update_kbytes = %d\n", + (int) f->dist.update_kbytes.kb); + storeAppendPrintf(sentry, "dist.content_upd = %d\n", + f->dist.content_upd); + storeAppendPrintf(sentry, "dist.updatees = %d\n", + f->dist.updatees); + storeAppendPrintf(sentry, "dist.updatees = %d\n", + f->dist.updatees * sizeof(Updatee)); + + storeAppendPrintf(sentry, "put.outs = %d\n", + f->put.outs); + storeAppendPrintf(sentry, "put.kbytes_out = %d\n", + (int) f->put.kbytes_out.kb); + storeAppendPrintf(sentry, "put.ins =: %d\n", + f->put.ins); + storeAppendPrintf(sentry, "put.kbytes_in = %d\n", + (int) f->put.kbytes_in.kb); + storeAppendPrintf(sentry, "put.conflicts = %d\n", + f->put.conflicts); } void Index: squid/src/store.c diff -u squid/src/store.c:1.17 squid/src/store.c:1.16.2.3 --- squid/src/store.c:1.17 Thu Aug 15 11:14:04 2002 +++ squid/src/store.c Tue Sep 3 10:41:57 2002 @@ -179,6 +179,8 @@ if (e->mem_obj) destroy_MemObject(e); storeHashDelete(e); + if (e->updatees) + distDelUpdatees(e->updatees); assert(e->hash.key == NULL); memFree(e, MEM_STOREENTRY); } @@ -192,12 +194,22 @@ e, storeKeyText(key)); e->hash.key = storeKeyDup(key); hash_join(store_table, &e->hash); +#if USE_HINT_CACHE + if (HINT_CACHE_ACTIVE()) { + e->hchhash.key = e->hash.key; + hash_join(cache_table, &e->hchash); + } +#endif } static void storeHashDelete(StoreEntry * e) { hash_remove_link(store_table, &e->hash); +#if USE_HINT_CACHE + if (HINT_CACHE_ACTIVE()) + hash_remove_link(hint_table, &e->hchash); +#endif storeKeyFree(e->hash.key); e->hash.key = NULL; } @@ -710,6 +722,9 @@ assert(e->mem_obj->nclients == 0); return; } +#if USE_HINT_CACHE + hintCacheInformLocalCopy(e->mem_obj->url, e); +#endif e->mem_obj->object_sz = e->mem_obj->inmem_hi; e->store_status = STORE_OK; assert(e->mem_status == NOT_IN_MEMORY); @@ -873,6 +888,11 @@ destroy_StoreEntry(e); } } + +#if USE_HINT_CACHE + hintCacheInvalLocalCopy(e); +#endif + storeLog(STORE_LOG_RELEASE, e); if (e->swap_filen > -1) { storeUnlink(e); @@ -1000,6 +1020,20 @@ storeInitHashValues(); store_table = hash_create(storeKeyHashCmp, store_hash_buckets, storeKeyHashHash); +#if USE_HINT_CACHE + /* + * Need to be able to look up objects from hint + * cache key so we can invalidate obsolete objects + * based on hint cache updates. + * Note: the hint cache key is just the first 8 bytes + * of the 16-byte cache key, so storeKeyHashHash will + * always work. Although, right now, sKHH only looks + * at the first 32 bits anyway, giving double protection. + */ + if (HINT_CACHE_ACTIVE()) + hint_table = hash_create(hintCacheURLKeyCompare, + store_hash_buckets, storeKeyHashHash); +#endif mem_policy = createRemovalPolicy(Config.memPolicy); storeDigestInit(); storeLogOpen(); @@ -1056,6 +1090,12 @@ if (store_digest) cacheDigestDestroy(store_digest); #endif +#if USE_HINT_CACHE + if (HINT_CACHE_ACTIVE()) { + hashFreeMemory(hint_table); + hint_table = NULL; + } +#endif store_digest = NULL; } Index: squid/src/store_key_md5.c diff -u squid/src/store_key_md5.c:1.6 squid/src/store_key_md5.c:1.6.24.1 --- squid/src/store_key_md5.c:1.6 Fri Apr 13 17:31:02 2001 +++ squid/src/store_key_md5.c Fri Dec 14 00:00:37 2001 @@ -99,6 +99,11 @@ assert(id > 0); debug(20, 3) ("storeKeyPrivate: %s %s\n", RequestMethodStr[method], url); + + /* PUT goes to same namespace as GETs do, so treat them alike here */ + if (method == METHOD_PUT) + method = METHOD_GET; + MD5Init(&M); MD5Update(&M, (unsigned char *) &id, sizeof(id)); MD5Update(&M, (unsigned char *) &method, sizeof(method)); @@ -113,6 +118,11 @@ static cache_key digest[MD5_DIGEST_CHARS]; unsigned char m = (unsigned char) method; MD5_CTX M; + + /* PUT goes to same namespace as GETs do, so treat them alike here */ + if (m == METHOD_PUT) + m = METHOD_GET; + MD5Init(&M); MD5Update(&M, &m, sizeof(m)); MD5Update(&M, (unsigned char *) url, strlen(url)); @@ -133,6 +143,11 @@ unsigned char m = (unsigned char) method; const char *url = urlCanonical(request); MD5_CTX M; + + /* PUT goes to same namespace as GETs do, so treat them alike here */ + if (m == METHOD_PUT) + m = METHOD_GET; + MD5Init(&M); MD5Update(&M, &m, sizeof(m)); MD5Update(&M, (unsigned char *) url, strlen(url)); Index: squid/src/structs.h diff -u squid/src/structs.h:1.65 squid/src/structs.h:1.47.2.7 --- squid/src/structs.h:1.65 Sun Sep 1 09:30:42 2002 +++ squid/src/structs.h Tue Sep 3 10:41:58 2002 @@ -338,6 +338,12 @@ #endif +#if USE_HINT_CACHE +struct _URLKey { + HintCacheKey key; +}; +#endif + #if DELAY_POOLS struct _delaySpec { int restore_bps; @@ -588,6 +594,11 @@ int ie_refresh; int vary_ignore_expire; int pipeline_prefetch; +#if USE_HINT_CACHE + int hint_cache_listen; + int hint_cache_advertise; + int hint_cache_use_mmap; +#endif int check_hostnames; int via; } onoff; @@ -681,6 +692,16 @@ int unclean_shutdown; } SSL; #endif +#if USE_HINT_CACHE + struct { + char *cache_file; + int size; + int assoc; + int intvl; + int join_intvl; + int holddown; + } Hints; +#endif wordlist *ext_methods; struct { int high_rptm; @@ -979,6 +1000,7 @@ int fd; http_state_flags flags; FwdState *fwd; + int body_remain; }; struct _icpUdpData { @@ -1062,6 +1084,7 @@ } out; HttpHdrRangeIter range_iter; /* data for iterating thru range specs */ size_t req_sz; /* raw request size on input, not current request size */ + char *hdr_str; /* Copy of headers */ StoreEntry *entry; StoreEntry *old_entry; log_type log_type; @@ -1281,6 +1304,13 @@ unsigned int no_delay:1; #endif unsigned int allow_miss:1; + unsigned int dist:1; +#if USE_ICP_DATA + unsigned int icpdata:1; +#endif +#if USE_HINT_CACHE + unsigned int nohint:1; +#endif #if USE_CARP unsigned int carp:1; #endif @@ -1319,6 +1349,8 @@ char *login; /* Proxy authorization */ time_t connect_timeout; int max_conn; + peer *fwdpush; /* next peer on FwdPushLinks */ + int max_rate; /* Max push rate to this peer */ }; struct _net_db_name { @@ -1547,6 +1579,10 @@ ping_status_t ping_status:3; store_status_t store_status:3; swap_status_t swap_status:3; + Updatee *updatees; +#if USE_HINT_CACHE + hash_link hchash; +#endif }; struct _SwapDir { @@ -1623,6 +1659,7 @@ unsigned int accelerated:1; unsigned int internal:1; unsigned int body_sent:1; + unsigned int distify:1; /* Use dist reqs for consistency */ unsigned int reset_tcp:1; }; @@ -1672,6 +1709,8 @@ struct in_addr client_addr; struct in_addr my_addr; unsigned short my_port; + int dist_type; + unsigned short dist_port; HttpHeader header; ConnStateData *body_connection; /* used by clientReadBody() */ int content_length; @@ -1870,6 +1909,21 @@ int outs; int ins; } swap; + struct { + int dists; + int undists; + int updates; + kb_t update_kbytes; + int content_upd; + int updatees; + } dist; + struct { + int outs; + int ins; + kb_t kbytes_out; + kb_t kbytes_in; + int conflicts; + } put; }; /* per header statistics */ @@ -2159,10 +2213,149 @@ } flags; }; + + +/* + * Putting state. + */ +struct _PushHeader { + int fd; + store_client *sc; + struct { + unsigned int active:1; + unsigned int dead:1; + unsigned int disting:1; +#ifdef USE_ICP_DATA + unsigned int icpdata:1; +#endif + } flags; + int off; + int objlen; + StoreEntry *entry; + PF *handler; + void *arg; +#ifdef USE_ICP_DATA + icpQueue *q; +#endif + unsigned reqnum; /* ICP reqnum */ + char hname[20]; +}; + +struct _Pusher { + PushHeader hdr; + char data[16384 - sizeof(PushHeader)]; +}; + struct cache_dir_option { const char *name; void (*parse) (SwapDir * sd, const char *option, const char *value, int reconfiguring); void (*dump) (StoreEntry * e, const char *option, SwapDir * sd); }; + +/* Tracking state for update ("push") requester */ +struct _updatee { + struct _updatee *next; + StoreEntry *entry; /* Backpointer to relevant entry */ + struct sockaddr_in saddr; + time_t lastmod; + Pusher *p; +}; + + +#if USE_HINT_CACHE + +/* Hint Cache Interface */ +/* + * Primitive data types. All have a -Net format which has an + * agreed-upon endian-ness. + */ + + +struct _URLKeyNet { + HintCacheKey mungedKey; +}; + +struct _NodeKey { + dlink_node links; + HintCacheKey key; + struct sockaddr_in addr; +}; + +struct _HintCacheEntry { + URLKey key; + struct in_addr ipaddr; + unsigned short port; + short pad; /* Compiler padding space */ + unsigned int mtime; /* Last-modified time */ +}; + +/* This is what goes onto the net */ +struct _HintCacheEntryNet { + URLKeyNet mungedKey; + struct in_addr mungedIpaddr; + unsigned short mungedPort; + short mungedPad; + unsigned int mungedMtime; +}; + +struct _HintCacheUpdate { + unsigned char action; + char hopcount; + char UNUSED; /* Remove this field sometime XXX */ + char pad1; + int pad2; + HintCacheEntry entry; +}; + +struct _HintCacheUpdateNet { + unsigned char mungedAction; + char mungedHopcount; + char mungedUNUSED; + char mungedPad1; + int mungedPad2; + HintCacheEntryNet mungedEntry; +}; + +/* Hint Cache Disk */ +struct _HintCacheDiskEntry { + HintCacheEntry entry; + unsigned int rtime; /* Time of entry receipt */ +}; + +struct _HintCacheDisk { + unsigned int nbuckets; + int entriesPerBucket; + HintCacheDiskEntry *mmappedArray; + int fd; +}; + +typedef struct HintCacheNetS{ + StoreEntry *sendBuffer; + int sendLength; + enum HintCacheNet_State state; +#ifdef DOTEST + int testMode; + int testCount; +#endif +} HintCacheNet; + +typedef struct HintCacheNetHeaderS { + unsigned short httpport; /* Port of sending server */ + unsigned short updlen; /* Length of individual update */ +} HintCacheNetHeader; + +#endif /* USE_HINT_CACHE */ + +#if USE_ICP_DATA +typedef struct _icpDataStats { + int nsends; + int nrecvs; + int nfrags; + int ndups; + int ntmofrags; + int nbadfrags; +} +#endif + #endif /* SQUID_STRUCTS_H */ Index: squid/src/typedefs.h diff -u squid/src/typedefs.h:1.27 squid/src/typedefs.h:1.25.2.6 --- squid/src/typedefs.h:1.27 Sun Jun 23 06:38:04 2002 +++ squid/src/typedefs.h Tue Sep 3 10:42:00 2002 @@ -351,6 +351,37 @@ typedef int STDIRSELECT(const StoreEntry *); +/* PUT internal data structure */ +typedef struct _PushHeader PushHeader; +typedef struct _Pusher Pusher; + +/* Automatic update ("push") requester */ +typedef struct _updatee Updatee; + +#if USE_HINT_CACHE +/* Hint Cache Interface */ +typedef unsigned Net_unsigned; +typedef long long unsigned Net_longlong; +typedef unsigned long long HintCacheKey; +typedef struct _URLKey URLKey; +typedef struct _URLKeyNet URLKeyNet; +typedef struct _NodeKey NodeKey; +typedef struct _HintCacheEntry HintCacheEntry; +typedef struct _HintCacheEntryNet HintCacheEntryNet; +typedef struct _HintCacheUpdate HintCacheUpdate; +typedef struct _HintCacheUpdateNet HintCacheUpdateNet; + +/* Hint Cache Disk */ +typedef struct _HintCacheDiskEntry HintCacheDiskEntry; +typedef struct _HintCacheDisk HintCacheDisk; + +typedef dlink_node *HintCacheNodeListIter; +#endif /* USE_HINT_CACHE */ + +#if USE_ICP_DATA +typedef struct _icpDataStats icpDataStats; +#endif + typedef struct _external_acl external_acl; typedef struct _external_acl_entry external_acl_entry; Index: squid/src/url.c diff -u squid/src/url.c:1.10 squid/src/url.c:1.7.2.3 --- squid/src/url.c:1.10 Fri Aug 23 19:06:24 2002 +++ squid/src/url.c Tue Sep 3 10:42:01 2002 @@ -102,6 +102,9 @@ "whois", "internal", "https", +#if USE_HINT_CACHE + "route", +#endif "TOTAL" }; @@ -195,30 +198,84 @@ protocol_t -urlParseProtocol(const char *s) +urlParseProtocol(const char *s, u_short *dportp, int *dtypep) { + int proto; + /* test common stuff first */ - if (strcasecmp(s, "http") == 0) - return PROTO_HTTP; - if (strcasecmp(s, "ftp") == 0) - return PROTO_FTP; - if (strcasecmp(s, "https") == 0) - return PROTO_HTTPS; - if (strcasecmp(s, "file") == 0) - return PROTO_FTP; - if (strcasecmp(s, "gopher") == 0) - return PROTO_GOPHER; - if (strcasecmp(s, "wais") == 0) - return PROTO_WAIS; - if (strcasecmp(s, "cache_object") == 0) - return PROTO_CACHEOBJ; - if (strcasecmp(s, "urn") == 0) - return PROTO_URN; - if (strcasecmp(s, "whois") == 0) - return PROTO_WHOIS; - if (strcasecmp(s, "internal") == 0) - return PROTO_INTERNAL; - return PROTO_NONE; + if (strncasecmp(s, "http", 4) == 0) { + s += 4; + proto = PROTO_HTTP; + } +#if USE_HINT_CACHE + else if (strncasecmp(s, "route", 5) == 0) { + s += 5; + proto = PROTO_ROUTE; + } +#endif + else if (strncasecmp(s, "ftp", 3) == 0) { + s += 3; + proto = PROTO_FTP; + } + else if (strncasecmp(s, "https", 5) == 0) { + s += 5; + proto = PROTO_HTTPS; + } + else if (strncasecmp(s, "file", 4) == 0) { + s += 4; + proto = PROTO_FTP; + } + else if (strncasecmp(s, "gopher", 6) == 0) { + s += 6; + proto = PROTO_GOPHER; + } + else if (strncasecmp(s, "wais", 4) == 0) { + s += 4; + proto =PROTO_WAIS; + } + else if (strncasecmp(s, "cache_object", 12) == 0) { + s += 12; + proto = PROTO_CACHEOBJ; + } + else if (strncasecmp(s, "urn", 3) == 0) { + s += 3; + proto = PROTO_URN; + } + else if (strncasecmp(s, "whois", 5) == 0) { + s += 5; + proto = PROTO_WHOIS; + } + else if (strncasecmp(s, "internal", 8) == 0) { + s += 8; + proto = PROTO_INTERNAL; + } + else + proto = PROTO_NONE; + + if (dportp != NULL) { + if (strncasecmp(s, "dist", 4) == 0) { + s += 4; + if (dportp != NULL) + *dportp = ntohs(atoi(s)); + if (dtypep) + *dtypep = DIST_DIST; + } + else if (strncasecmp(s, "undist", 6) == 0) { + s += 6; + if (dportp != NULL) + *dportp = ntohs(atoi(s)); + if (dtypep) + *dtypep = DIST_UNDIST; + } + else { + if (dportp) + *dportp = 0; + if (dtypep) + *dtypep = 0; + } + } + + return proto; } @@ -256,7 +313,7 @@ request_t *request = NULL; char *t = NULL; char *q = NULL; - int port; + int port, dport, dtype; protocol_t protocol = PROTO_NONE; int l; proto[0] = host[0] = urlpath[0] = login[0] = '\0'; @@ -276,7 +333,7 @@ } else { if (sscanf(url, "%[^:]://%[^/]%[^\r\n]", proto, host, urlpath) < 2) return NULL; - protocol = urlParseProtocol(proto); + protocol = urlParseProtocol(proto, &dport, &dtype); port = urlDefaultPort(protocol); /* Is there any login informaiton? */ if ((t = strrchr(host, '@'))) { @@ -357,6 +414,8 @@ xstrncpy(request->host, host, SQUIDHOSTNAMELEN); xstrncpy(request->login, login, MAX_LOGIN_SZ); request->port = (u_short) port; + request->dist_port = (u_short) dport; + request->dist_type = dtype; return request; } Index: squid/src/webpush.c diff -u /dev/null squid/src/webpush.c:1.1.2.2 --- /dev/null Mon Jan 26 04:57:39 2004 +++ squid/src/webpush.c Fri Dec 14 00:00:37 2001 @@ -0,0 +1,267 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define OUTBUFLEN 65536 +/*#define OUTBUFLEN 1400*/ + +char *malloc(); +void free(); +int atoi(); +int gethostname(); +int write(); + +void usage(); +int puthdr(struct stat *st); +void hfcopy(FILE *to, FILE *from, char *buf, int buflen, int hdrlen); + +char *verstr = "Server: Webpush 2.0, Squid PUT utility\r\n"; + +static int port = 3128; +static int verbose = 0; +static int directfile = 0; +static int async = 0; + +static char *cmdname; +static char name[256]; +static char reply[BUFSIZ]; +static char *url = 0; +static char *htfile = 0; +static char *type = "text/html"; +static char outbuf[OUTBUFLEN]; + +int main(argc, argv) +int argc; +char **argv; +{ + struct sockaddr_in addr; + int argcnt = 0; + struct stat st; + FILE *sp, *fp; + int hdrlen; + char *arg; + int code; + int s; + + cmdname = argv[0]; + if (argc < 3) + usage(); + while (--argc) { + arg = *++argv; + if (arg[0] == '-') { + while (*++arg) { + switch(*arg) { + case 'a': /* Asynchronous - don't wait for reply */ + async = 1; + break; + case 'h': /* Don't generate HTTP headers - already in file */ + directfile = 1; + break; + case 'p': /* Specify port */ + --argc; + if (argc < 1) + usage(); + port = atoi(*++argv); + if (port == 0) + usage(); + break; + case 't': /* Specify Content-type */ + --argc; + if (argc < 1) + usage(); + type = *++argv; + usage(); + break; + case 'v': /* Verbose */ + verbose = 1; + break; + default: + usage(); + } + } + } + else { + ++argcnt; + if (argcnt == 1) { + /* First non-flagged arg is the URL */ + url = arg; + } + else if (argcnt == 2) { + /* Second non-flagged arg is the file to push */ + htfile = arg; + } + else + usage(); + } + } + + if (argcnt != 2) + usage(); + + s = socket(AF_INET, SOCK_STREAM, 0); + if (s == -1) { + perror("socket"); + exit(1); + } + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(0x7f000001); + addr.sin_port = htons(port); + if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) == -1) { + perror("connect"); + exit(1); + } + sp = fdopen(s, "r+"); + if (sp == NULL) { + perror("socket fdopen"); + exit(1); + } + + fp = fopen(htfile, "r"); + if (fp == 0) { + perror(htfile); + exit(1); + } + + if (fstat(fileno(fp), &st) == -1) { + perror("fstat"); + exit(1); + } + + /* If directfile, then the file will already have HTTP headers */ + if (!directfile) { + /* Generate header and send to proxy */ + hdrlen = puthdr(&st); + if (verbose) { + fwrite(outbuf, 1, hdrlen, stdout); + } + } + + /* Copy file to proxy */ + if (verbose) + printf("sending file to proxy\n"); + hfcopy(sp, fp, outbuf, OUTBUFLEN, hdrlen); + + /* Read response */ + if (!async) { + if (verbose) + printf("proxy response is:\n"); + fread(reply, 1, sizeof(reply), sp); + reply[sizeof(reply) - 2] = '\n'; + reply[sizeof(reply) - 1] = '\0'; + + /* Parse response */ + sscanf(reply, "%s %d", name, &code); + + /* Print the complaint if the server seems unhappy */ + if ((code != 200 && code != 204) || verbose) + fputs(reply, stdout); + } + exit(0); +} + +void usage(err) +char *err; +{ + fprintf(stderr, "usage: %s [-h][-p port][-t content-type] \n", cmdname); + exit(1); +} + +/* Generate PUT header */ +int puthdr(statp) +struct stat *statp; +{ + struct tm *gmtime(); + char *asctime(); + char *timestr; + time_t now; + int hdrlen; + + now = time(0); + timestr = asctime(gmtime(&now)); + timestr[strlen(timestr) - 1] = '\0'; + + gethostname(name, sizeof(name)); + + if (url == 0) { + fprintf(stderr, "webpush internal problem - URL unknown\n"); + exit(1); + } + + hdrlen = 0; + sprintf(outbuf, "PUT %s HTTP/1.0\r\n", url); + hdrlen = strchr(outbuf, '\n') - outbuf + 1; + + sprintf(outbuf + hdrlen, "Date: %s GMT\r\n", timestr); + hdrlen = strchr(outbuf + hdrlen, '\n') - outbuf + 1; + + sprintf(outbuf + hdrlen, verstr); + hdrlen = strchr(outbuf + hdrlen, '\n') - outbuf + 1; + + sprintf(outbuf + hdrlen, "Content-type: %s\r\n", type); + hdrlen = strchr(outbuf + hdrlen, '\n') - outbuf + 1; + + sprintf(outbuf + hdrlen, "Content-length: %d\r\n", (int) statp->st_size); + hdrlen = strchr(outbuf + hdrlen, '\n') - outbuf + 1; + + timestr = asctime(gmtime(&statp->st_mtime)); + timestr[strlen(timestr) - 1] = '\0'; + sprintf(outbuf + hdrlen, "Last-modified: %s GMT\r\n\r\n", timestr); + hdrlen = strchr(outbuf + hdrlen, '\n') - outbuf + 3; + + if (verbose) + printf("PUT header amounts to %d bytes\n", hdrlen); + + return(hdrlen); +} + +/* filecopy that makes allowances for an initial output header */ +void hfcopy(to, from, buf, buflen, hdrlen) +FILE *to, *from; +char *buf; +int buflen; +int hdrlen; +{ + int nmov, nwrote; + char *tbuf; + + while (1) { + nmov = fread(buf + hdrlen, 1, buflen - hdrlen, from); + if (nmov == -1) { + perror("filecopy read"); + exit(1); + } + if (nmov == 0) { + if (!feof(from)) + perror("webpost read"); + break; + } + nmov += hdrlen; + + tbuf = buf; + do { + if (verbose) + write(1, buf, nmov); + nwrote = write(fileno(to), buf, nmov); + if (nwrote == -1) { + perror("filecopy write"); + exit(1); + } + if (nwrote == 0) + break; + nmov -= nwrote; + tbuf += nwrote; + } while (nmov > 0); + + /* Sent header in first go-round, done now */ + hdrlen = 0; + } + if (verbose) + printf("filecopy complete - last move of %d chars\n", nmov); +} + Index: squid/src/auth/basic/helpers/Makefile.am diff -u /dev/null squid/src/auth/basic/helpers/Makefile.am:1.2.28.1 --- /dev/null Mon Jan 26 04:57:39 2004 +++ squid/src/auth/basic/helpers/Makefile.am Tue Sep 3 10:42:05 2002 @@ -0,0 +1,7 @@ +# Makefile for storage modules in the Squid Object Cache server +# +# $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ +# + +DIST_SUBDIRS = getpwnam LDAP MSNT multi-domain-NTLM NCSA PAM SMB YP SASL +SUBDIRS = @BASIC_AUTH_HELPERS@ Index: squid/src/auth/basic/helpers/LDAP/Makefile.am diff -u /dev/null squid/src/auth/basic/helpers/LDAP/Makefile.am:1.2.28.2 --- /dev/null Mon Jan 26 04:57:39 2004 +++ squid/src/auth/basic/helpers/LDAP/Makefile.am Tue Sep 3 10:42:07 2002 @@ -0,0 +1,14 @@ +# +# Makefile for the Squid LDAP authentication helper +# +# $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ +# +# Uncomment and customize the following to suit your needs: +# + +libexec_PROGRAMS = squid_ldap_auth +man_MANS = squid_ldap_auth.8 +EXTRA_DIST = squid_ldap_auth.8 +squid_ldap_auth_SOURCES = squid_ldap_auth.c + +LDADD = -lldap -llber Index: squid/src/auth/basic/helpers/MSNT/Makefile.am diff -u /dev/null squid/src/auth/basic/helpers/MSNT/Makefile.am:1.2.28.2 --- /dev/null Mon Jan 26 04:57:39 2004 +++ squid/src/auth/basic/helpers/MSNT/Makefile.am Tue Sep 3 10:42:10 2002 @@ -0,0 +1,22 @@ +# +# Makefile for the Squid Object Cache server +# +# $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ +# +# Uncomment and customize the following to suit your needs: +# + + +libexec_PROGRAMS = msnt_auth + +msnt_auth_SOURCES = md4.c rfcnb-io.c rfcnb-util.c session.c msntauth.c \ + msntauth.h smbdes.c smbencrypt.c smblib-util.c smblib.c \ + valid.c denyusers.c allowusers.c confload.c \ + byteorder.h rfcnb-common.h rfcnb-error.h rfcnb.h \ + rfcnb-io.h rfcnb-priv.h rfcnb-util.h smblib-common.h \ + smblib.h smblib-priv.h std-defines.h std-includes.h valid.h + +LDADD = @XTRA_LIBS@ + +INCLUDES = -I. -I$(top_builddir)/include -I$(top_srcdir)/include \ + -I$(top_srcdir)/src/ Index: squid/src/auth/basic/helpers/MSNT/README.html diff -u /dev/null squid/src/auth/basic/helpers/MSNT/README.html:1.2.62.1 --- /dev/null Mon Jan 26 04:57:39 2004 +++ squid/src/auth/basic/helpers/MSNT/README.html Tue Sep 3 10:42:10 2002 @@ -0,0 +1,355 @@ + + +MSNTAUTH readme + + + + + +

+MSNT Auth v2.0.3
+Squid web proxy NT authentication module
+Antonino Iannella, Stellar-X Pty Ltd
+Sun Sep 2 15:01:58 CST 2001 +

+ +

Contents

+ + + +

Introduction

+ +

+This is an authentication module for the Squid proxy server +to authenticate users on an NT domain. + +

+It originates from the Samba and SMB packages by Andrew Tridgell +and Richard Sharpe. This version is sourced from the Pike +authentication module by William Welliver (hwellive@intersil.com). + +

+Usage is simple. It accepts a username and password on standard input. +It will return OK if the username/password is valid for the domain, +or ERR if there was some problem. +Check syslog messages for reported problems. + +

+Msntauth is released under the GNU General Public License and +is available from +http://www.tripod.com/stellarx. +It also ships with the Squid web proxy, +http://www.squid-proxy.org. + +

+Msntauth has not been tested with Windows 2000 domains yet. + +

Installation

+ +

+Make any changes to the source code you need. + +

+If you are using the source provided with Squid, then Msntauth +will be compiled when you compile Squid. Refer to Squid documentation +for details. + +

+If you have downloaded Msntauth from the Stellar-X website, then +copy Makefile.MSNT to Makefile. +Review the Makefile, and modify based on target platform or +site requirements. + +

+Type 'make', then 'make install', then 'make clean'. + +

+To avoid using the makefile, it may compile with + + gcc -O2 -s -o msntauth *.c + +

+'Make install' will put 'msntauth' into +/usr/local/squid/bin by default. + +

+Hopefully nobody has problems compiling msntauth. + +

Issues when compiling

+ +

+The Makefile uses the GCC compiler, and assumes that it is in the current PATH. +Msntauth is known to compile properly on Redhat Linux 6, and FreeBSD 3.1 +without problems. Other operating systems are untested, +but use a recent copy of the GNU C compiler. +In Smbencrypt.c, '#include ' only gets included when +compiled with Solaris. + +

+When compiling under Solaris, the socket libraries must be linked to. +In the Makefile, hash the default CFLAGS line, and unhash the Solaris +CFLAGS line. It always helps to have /usr/ccs/bin in your path +prior to compiling. + +

+For Digital Unix/Tru64, review the INSTALL line in the makefile. + +

Configuration file

+ +

+Msntauth uses a configuration file as of version 2. +The file is /usr/local/squid/etc/msntauth.conf. +If this path needs to be changed, it is defined in confload.c - + +

+  #define CONFIGFILE   "/usr/local/squid/etc/msntauth.conf"
+
+ +

+An example configuration file is provided. It looks like + +

+# Sample MSNT authenticator configuration file
+# Antonino Iannella, Stellar-X Pty Ltd
+# Tue Sep 26 17:26:59 CST 2000
+
+server my_PDC           my_BDC          my_NTdomain
+server other_PDC        other_BDC       otherdomain
+
+denyusers       /usr/local/squid/etc/denyusers
+allowusers      /usr/local/squid/etc/allowusers
+
+ +

+All comments start with '#'. + +

+NT servers are used to query user accounts. The 'server' lines +are used for this, with the PDC, BDC, and NT domain as parameters. +Up to 5 servers/domains can be queried. If this is not enough, +modify the MAXSERVERS define in confload.c. +At least one server must be specified, or msntauth will not +run. +Server names must be resolvable by the system. If not, msntauth +reports an error. If you can't ping it, you might have a host +resolution problem. +You can't use NetBIOS hostnames, nor IP addresses. + +

+When a user provides a username/password, each of these +servers will be queried to authenticate the username. +It stops after a user has been successfully authenticated, +so it makes sense to specify the most commonly queried +server first. Make sure the servers can be reached and +are active, or else msntauth will start failing user accounts! + +

+The 'denyusers' and 'allowusers' lines give the absolute path +to files of user accounts. They can be used to deny or allow +access to the proxy. Do not use these directives if you +do not need these features. + +

Denying users

+ +

+Users who are not allowed to access the web proxy can be added to +the denied user list. This list is read around every minute, or when +the msntauth process receives a SIGHUP signal. + +

+The denied user file is set using the 'denyusers' directive +in msntauth.h. The denied user file +contains a list of usernames in no particular structure or form. +If the file does not exist, no users are denied. +The file must be readable by the web proxy user. + +

+Msntauth will send syslog messages if a user was denied, +at LOG_USER facility. + +

Allowing users

+ +

+Similar to denying users, you can allow users to access the proxy +by username. This is useful if only a number of people are +allowed supposed to be accessing a proxy. + +

+The allowed user file is set using the 'allowusers' directive +in msntauth.h. +If the file does not exist or if empty, all users are allowed. + +

+You could make use of the SHOWMBRS tool in Microsoft Technet. +This gives you a list of users which are in a particular +NT Domain Group. This list can be made into the allowed users +file. + +

+Some other rules - + +

    +
  1. The operation of the denied user file is independent of the +allowed user file. The former file is checked first. +
  2. You can use none, one, or both files. +
  3. If a username appears in the denied user file, they will +be denied, even if they are in the allowed user file. +
  4. If a username is not in either file, they will be denied, +because they have not been allowed. +
  5. If the allowed user file is in use and is empty, all +users will be allowed. +
+ +

+Hopefully this wasn't too confusing. + +

Squid.conf changes

+ +

+Refer to Squid documentation for the required changes to squid.conf. +You will need to set the following lines to enable authentication for +your access list - + +

+  acl  proxy_auth REQUIRED
+  http_access allow password
+  http_access allow 
+  http_access deny all
+
+ +

+You will also need to review the following directives. The number of +msntauth children spawned is set with authenticate_children. +The number of children needed is site-dependent, so some +experimentation may be required to find the best number. +There should be no visible delay in performance with Squid once +msntauth is in use. As an example, a firm with 1500 users and a T1 +internet connection required a value of 30.- + +

+  proxy_auth_realm enterprise web gateway
+  authenticate_program /usr/local/squid/bin/msntauth
+  authenticate_ttl 5
+  authenticate_children 20
+
+ +

Testing

+ +

+I strongly urge that Msntauth is tested prior to being used in a +production environment. It may behave differently on different platforms. +To test it, run it from the command line. Enter username and password +pairs separated by a space. + +

+It should behave in the following way - +

+ - Press ENTER to get an OK or ERR message.
+ - Make sure pressing CTRL-D behaves the same as a carriage return.
+ - Make sure pressing CTRL-C aborts the program.
+ - Test that entering no details does not result in an OK or ERR message.
+ - Test that entering an invalid username and password results in
+   an ERR message. Note that if NT guest user access is allowed on
+   the PDC, an OK message may be returned instead of ERR.
+ - Test that entering an valid username and password results in an OK message.
+   Try usernames which are and aren't in the denied/allowed user files,
+   if they're in use.
+ - Test that entering a guest username and password returns the correct response.
+
+ +

+If the above didn't work as expected, you may need to modify the main() +function in msntauth.c. Inform the maintainer of any problems. + +

+Usernames cannot have whitespace in them, but passwords can. + +

+As of version 2.0.3, the msntauth version can be found in the executable. +Type this to retrieve it - + +

+  strings msntauth | grep -i msntauth
+
+ +

Contact details

+ +

+To contact the maintainer of this package, email Antonino Iannella +at antonino@rager.com.au, or antonino.iannella@santos.com.au, or ring ++61 8408 800 007. + +

+The latest version may be found on http://members.tripod.com/stellarx. +It is also distributed as part of Squid. + +

Reported problem

+ +

+For an unknown username, Msntauth returns OK. +This is because the PDC returns guest access for unknown users, +even if guest access is disabled. +This problem was reported by Mr Vadim Popov (vap@iilsr.minsk.by). +I am not able to replicate this. + +

+The tested environment consisted of PDC on Windows NT 4, SP 6. +Squid 2.3 and Msntauth was tested on SuSe, RedHat, and Debian Linux. +A fix was provided in case you have this problem. +Apply the provided patch before compiling, using + +

+  patch smblib.c < smblib.c.patch
+
+ +

Revision history

+ +

+The following sequence of changes have been made to improve msntauth. +I have not had a chance to do too much testing due +to lack of resources. There should be no problems, though. + +

    +
  • Added many patches from Duane Wessels to stop compilation errors (?) +
  • Improved the main() function yet again +
  • Created a more informative Makefile +
  • Added an 'allowed users' feature to complement the 'denied users' feature +
  • Stopped the use of alarm() which was causing problems under Solaris +
  • Added more syslog messages for authentication problems +
  • Added the use of a configuration file, instead of hard-coding NT server details +
  • Allowed for querying multiple NT servers and domains (this was a hot issue) +
  • Changed README into an HTML document to improve readability +
  • Removed denied/allowed username substring search limitation +
  • Fixed a bug which occurred when reading denied/allowed usernames +
  • Allows whitespace in passwords +
  • To check user list changes, doesn't use an alarm every minute. +
  • Fixed a sigaction compilation error, causing problems on FreeBSD and HPUX +
  • Removed a problem of finding a valid username as a substring in the denied user list. +
  • Support email address change from antonino@usa.net to antonino@rager.com.au. +
  • Msntauth was successfully tested on Tru64. +
  • PDC and BDC hostnames are now checked if they are resolvable. +
  • Smbencrypt.c does not have to be checked for Solaris systems any more. +
  • Imbedded version information in the executable. +
+ +

+Hopefully msntauth and Squid prove to be a valuable auditing combination. +Feel free to send me success or problem stories. + + + Index: squid/src/auth/basic/helpers/MSNT/allowusers.c diff -u /dev/null squid/src/auth/basic/helpers/MSNT/allowusers.c:1.2.62.1 --- /dev/null Mon Jan 26 04:57:39 2004 +++ squid/src/auth/basic/helpers/MSNT/allowusers.c Tue Sep 3 10:42:10 2002 @@ -0,0 +1,193 @@ + +/* + * allowusers.c + * (C) 2000 Antonino Iannella, Stellar-X Pty Ltd + * Released under GPL, see COPYING-2.0 for details. + * + * These routines are to allow users attempting to use the proxy which + * have been explicitly allowed by the system administrator. + * The code originated from denyusers.c. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NAMELEN 50 /* Maximum username length */ + +/* Global variables */ + +char *AllowedUsers; /* Pointer to string of allowed users */ +off_t AllowUserSize; /* Size of allowed users file */ +struct stat FileBuf; /* Stat data buffer */ +time_t LastModTime; /* Last allowed user file modification time */ + +char Allowuserpath[MAXPATHLEN]; /* MAXPATHLEN defined in param.h */ + +/* Function declarations */ + +int Read_allowusers(); +int Check_ifuserallowed(char *); +void Checkforchange(); +void Checktimer(); + +/* + * Reads the allowed users file for all users to be permitted. + * Returns 0 if the user list was successfully loaded, + * and 1 in case of error. + * Logs any messages to the syslog daemon. + */ + +int +Read_allowusers() +{ + FILE *AFile; /* Allowed users file pointer */ + off_t APos = 0; /* File counter */ + char AChar; /* Character buffer */ + + /* Stat the file. If it does not exist, save the size as zero. + * Clear the allowed user string. Return. */ + if (stat(Allowuserpath, &FileBuf) == -1) { + if (errno == ENOENT) { + LastModTime = (time_t) 0; + AllowUserSize = 0; + free(AllowedUsers); + AllowedUsers = malloc(sizeof(char)); + AllowedUsers[0] = '\0'; + return 0; + } else { + syslog(LOG_USER | LOG_ERR, strerror(errno)); + return 1; + } + } + /* If it exists, save the modification time and size */ + LastModTime = FileBuf.st_mtime; + AllowUserSize = FileBuf.st_size; + + /* Handle the special case of a zero length file */ + if (AllowUserSize == 0) { + free(AllowedUsers); + AllowedUsers = malloc(sizeof(char)); + AllowedUsers[0] = '\0'; + return 0; + } + /* Free and allocate space for a string to store the allowed usernames */ + free(AllowedUsers); + + if ((AllowedUsers = malloc(sizeof(char) * (AllowUserSize + 3))) == NULL) { + syslog(LOG_USER | LOG_ERR, "Read_allowusers: malloc(AllowedUsers) failed."); + return 1; + } + /* Open the allowed users file. Report any errors. */ + + if ((AFile = fopen(Allowuserpath, "r")) == NULL) { + syslog(LOG_USER | LOG_ERR, "Read_allowusers: Failed to open allowed user file."); + syslog(LOG_USER | LOG_ERR, strerror(errno)); + return 1; + } + /* Read user names into the AllowedUsers string. + * Make sure each string is delimited by a space. */ + + AllowedUsers[APos++] = ' '; + + while (!feof(AFile)) { + if ((AChar = fgetc(AFile)) == EOF) + break; + else { + if (isspace(AChar)) + AllowedUsers[APos++] = ' '; + else + AllowedUsers[APos++] = toupper(AChar); + } + } + + AllowedUsers[APos++] = ' '; + AllowedUsers[APos] = '\0'; + fclose(AFile); + return 0; +} + +/* + * Check to see if the username provided by Squid appears in the allowed + * user list. Returns 0 if the user was not found, and 1 if they were. + */ + +int +Check_ifuserallowed(char *ConnectingUser) +{ + static char CUBuf[NAMELEN + 1]; + static char CUBuf1[NAMELEN + 1]; + static int x; + static char AllowMsg[256]; + + /* If user string is empty, allow */ + if (ConnectingUser[0] == '\0') + return 1; + + /* If allowed user list is empty, allow all users. + * If no users are supposed to be using the proxy, stop squid instead. */ + if (AllowUserSize == 0) + return 1; + + /* Check if username string is found in the allowed user list. + * If so, allow. If not, deny. Reconstruct the username + * to have whitespace, to avoid finding wrong string subsets. */ + + sscanf(ConnectingUser, " %s ", CUBuf1); + sprintf(CUBuf, " %s ", CUBuf1); + + for (x = 0; x <= strlen(CUBuf); x++) + CUBuf[x] = toupper(CUBuf[x]); + + if (strstr(AllowedUsers, CUBuf) != NULL) + return 1; + else { /* If NULL, they are not allowed to use the proxy */ + sprintf(AllowMsg, "Did not allow access to user '%s'.", CUBuf1); + syslog(LOG_USER | LOG_ERR, AllowMsg); + return 0; + } +} + +/* + * Checks if there has been a change in the allowed users file. + * If the modification time has changed, then reload the allowed user list. + * This function is called by the SIGHUP signal handler. + */ + +void +Check_forallowchange() +{ + struct stat ChkBuf; /* Stat data buffer */ + + /* Stat the allowed users file. If it cannot be accessed, return. */ + + if (stat(Allowuserpath, &ChkBuf) == -1) { + if (errno == ENOENT) { + LastModTime = (time_t) 0; + AllowUserSize = 0; + free(AllowedUsers); + AllowedUsers = malloc(sizeof(char)); + AllowedUsers[0] = '\0'; + return; + } else { /* Report error when accessing file */ + syslog(LOG_USER | LOG_ERR, strerror(errno)); + return; + } + } + /* If found, compare the modification time with the previously-recorded + * modification time. + * If the modification time has changed, reload the allowed user list. + * Log a message of its actions. */ + + if (ChkBuf.st_mtime != LastModTime) { + syslog(LOG_USER | LOG_INFO, "Check_forallowchange: Reloading allowed user list."); + Read_allowusers(); + } +} Index: squid/src/auth/basic/helpers/MSNT/confload.c diff -u /dev/null squid/src/auth/basic/helpers/MSNT/confload.c:1.2.62.1 --- /dev/null Mon Jan 26 04:57:39 2004 +++ squid/src/auth/basic/helpers/MSNT/confload.c Tue Sep 3 10:42:11 2002 @@ -0,0 +1,249 @@ + +/* + * confload.c + * (C) 2000 Antonino Iannella, Stellar-X Pty Ltd + * Released under GPL, see COPYING-2.0 for details. + * + * These routines load the msntauth configuration file. + * It stores the servers to query, sets the denied and + * allowed user files, and provides the + * authenticating function. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "msntauth.h" +#include "valid.h" + +#define CONFIGFILE "/usr/local/squid/etc/msntauth.conf" /* Path to configuration file */ +#define DENYUSERSDEFAULT "/usr/local/squid/etc/denyusers" +#define ALLOWUSERSDEFAULT "/usr/local/squid/etc/allowusers" + +#define MAXSERVERS 5 /* Maximum number of servers to query. This number can be increased. */ +#define NTHOSTLEN 65 + +extern char Denyuserpath[MAXPATHLEN]; /* MAXPATHLEN defined in param.h */ +extern char Allowuserpath[MAXPATHLEN]; + +typedef struct _ServerTuple { + char pdc[NTHOSTLEN]; + char bdc[NTHOSTLEN]; + char domain[NTHOSTLEN]; +} ServerTuple; + +ServerTuple ServerArray[MAXSERVERS]; /* Array of servers to query */ +int Serversqueried = 0; /* Number of servers queried */ + +/* Declarations */ + +static void ProcessLine(char *); +static void AddServer(char *, char *, char *); +static int QueryServerForUser(int, char *, char *); + +/* + * Opens and reads the configuration file. + * Returns 0 on success, or 1 for error. + */ + +int +OpenConfigFile(void) +{ + FILE *ConfigFile; + char Confbuf[2049]; /* Line reading buffer */ + + /* Initialise defaults */ + + Serversqueried = 0; + strcpy(Denyuserpath, DENYUSERSDEFAULT); + strcpy(Allowuserpath, ALLOWUSERSDEFAULT); + + /* Open file */ + if ((ConfigFile = fopen(CONFIGFILE, "r")) == NULL) { + syslog(LOG_USER | LOG_ERR, "OpenConfigFile: Failed to open %s.", CONFIGFILE); + syslog(LOG_USER | LOG_ERR, strerror(errno)); + return 1; + } + /* Read in, one line at a time */ + + while (!feof(ConfigFile)) { + Confbuf[0] = '\0'; + fgets(Confbuf, 2049, ConfigFile); + ProcessLine(Confbuf); + } + + /* Check that at least one server is being queried. Report error if not. + * Denied and allowed user files are hardcoded, so it's fine if they're + * not set in the confugration file. */ + + if (Serversqueried == 0) { + syslog(LOG_USER | LOG_ERR, "OpenConfigFile: No servers set in %s. At least one is needed.", CONFIGFILE); + return 1; + } + fclose(ConfigFile); + return 0; +} + +/* Parses a configuration file line. */ + +static void +ProcessLine(char *Linebuf) +{ + char *Directive; + char *Param1; + char *Param2; + char *Param3; + + /* Ignore empty lines */ + if (strlen(Linebuf) == 0) + return; + + /* Break up on whitespaces */ + if ((Directive = strtok(Linebuf, " \t\n")) == NULL) + return; + + /* Check for a comment line. If found, stop . */ + if (Directive[0] == '#') + return; + + /* Check for server line. Check for 3 parameters. */ + if (strcasecmp(Directive, "server") == 0) { + Param1 = strtok(NULL, " \t\n"); + Param2 = strtok(NULL, " \t\n"); + Param3 = strtok(NULL, " \t\n"); + + if ((Param1[0] == '\0') || + (Param2[0] == '\0') || + (Param3[0] == '\0')) { + syslog(LOG_USER | LOG_ERR, "ProcessLine: A 'server' line needs PDC, BDC, and domain parameters."); + return; + } + AddServer(Param1, Param2, Param3); + return; + } + /* Check for denyusers line */ + if (strcasecmp(Directive, "denyusers") == 0) { + Param1 = strtok(NULL, " \t\n"); + + if (Param1[0] == '\0') { + syslog(LOG_USER | LOG_ERR, "ProcessLine: A 'denyusers' line needs a filename parameter."); + return; + } + strcpy(Denyuserpath, Param1); + return; + } + /* Check for allowusers line */ + if (strcasecmp(Directive, "allowusers") == 0) { + Param1 = strtok(NULL, " \t\n"); + + if (Param1[0] == '\0') { + syslog(LOG_USER | LOG_ERR, "ProcessLine: An 'allowusers' line needs a filename parameter."); + return; + } + strcpy(Allowuserpath, Param1); + return; + } + /* Reports error for unknown line */ + syslog(LOG_USER | LOG_ERR, "ProcessLine: Ignoring '%s' line.", Directive); +} + +/* + * Adds a server to query to the server array. + * Checks if the server IP is resolvable. + * Checks if the number of servers to query is not exceeded. + * Does not allow parameters longer than NTHOSTLEN. + */ + +void +AddServer(char *ParamPDC, char *ParamBDC, char *ParamDomain) +{ + if (Serversqueried + 1 > MAXSERVERS) { + syslog(LOG_USER | LOG_ERR, "AddServer: Ignoring '%s' server line; too many servers.", ParamPDC); + return; + } + if (gethostbyname(ParamPDC) == (struct hostent *) NULL) { + syslog(LOG_USER | LOG_ERR, "AddServer: Ignoring host '%s'. Cannot resolve its address.", ParamPDC); + return; + } + if (gethostbyname(ParamBDC) == (struct hostent *) NULL) { + syslog(LOG_USER | LOG_ERR, "AddServer: Ignoring host '%s'. Cannot resolve its address.", ParamBDC); + return; + } + Serversqueried++; + strncpy(ServerArray[Serversqueried].pdc, ParamPDC, NTHOSTLEN); + strncpy(ServerArray[Serversqueried].bdc, ParamBDC, NTHOSTLEN); + strncpy(ServerArray[Serversqueried].domain, ParamDomain, NTHOSTLEN); + ServerArray[Serversqueried].pdc[NTHOSTLEN - 1] = '\0'; + ServerArray[Serversqueried].bdc[NTHOSTLEN - 1] = '\0'; + ServerArray[Serversqueried].domain[NTHOSTLEN - 1] = '\0'; +} + +/* + * Cycles through all servers to query. + * Returns 0 if one server could authenticate the user. + * Returns 1 if no server authenticated the user. + */ + +int +QueryServers(char *username, char *password) +{ + int Queryresult = 1; /* Default result is an error */ + int x = 1; + + while (x <= Serversqueried) { /* Query one server. Change Queryresult if user passed. */ + if (QueryServerForUser(x++, username, password) == 0) { + Queryresult = 0; + break; + } + } + + return Queryresult; +} + +/* + * Attempts to authenticate the user with one server. + * Logs syslog messages for different errors. + * Returns 0 on success, non-zero on failure. + */ + +/* Define for systems which don't support it, like Solaris */ +#ifndef LOG_AUTHPRIV +#define LOG_AUTHPRIV LOG_AUTH +#endif + +int +QueryServerForUser(int x, char *username, char *password) +{ + int result = 1; + + result = Valid_User(username, password, ServerArray[x].pdc, + ServerArray[x].bdc, ServerArray[x].domain); + + switch (result) { /* Write any helpful syslog messages */ + case 0: + break; + case 1: + syslog(LOG_AUTHPRIV | LOG_INFO, "Server error when checking %s.", username); + break; + case 2: + syslog(LOG_AUTHPRIV | LOG_INFO, "Protocol error when checking %s.", username); + break; + case 3: + syslog(LOG_AUTHPRIV | LOG_INFO, "Authentication failed for %s.", username); + } + + return result; +} + +/* Valid_User return codes - + * + * 0 - User authenticated successfully. + * 1 - Server error. + * 2 - Protocol error. + * 3 - Logon error; Incorrect password or username given. + */ Index: squid/src/auth/basic/helpers/MSNT/denyusers.c diff -u /dev/null squid/src/auth/basic/helpers/MSNT/denyusers.c:1.2.62.1 --- /dev/null Mon Jan 26 04:57:39 2004 +++ squid/src/auth/basic/helpers/MSNT/denyusers.c Tue Sep 3 10:42:11 2002 @@ -0,0 +1,250 @@ + +/* + * denyusers.c + * (C) 2000 Antonino Iannella, Stellar-X Pty Ltd + * Released under GPL, see COPYING-2.0 for details. + * + * These routines are to block users attempting to use the proxy which + * have been explicitly denied by the system administrator. + * Routines at the bottom also use the allowed user functions. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NAMELEN 50 /* Maximum username length */ + +/* Global variables */ + +char *DeniedUsers; /* Pointer to string of denied users */ +off_t DenyUserSize; /* Size of denied user file */ +struct stat FileBuf; /* Stat data buffer */ +time_t LastModTime; /* Last denied user file modification time */ + +char Denyuserpath[MAXPATHLEN]; /* MAXPATHLEN defined in param.h */ + +/* Function declarations */ + +int Read_denyusers(); +int Check_ifuserdenied(char *); +int Check_user(char *); +void Checktimer(); +void Check_forchange(); +void Check_fordenychange(); +extern void Check_forallowchange(); /* For allowed users */ +extern int Check_ifuserallowed(char *); + +/* + * Reads Denyuserpath for all users to be excluded. + * Returns 0 if the user list was successfully loaded, + * and 1 in case of error. + * Logs any messages to the syslog daemon. + */ + +int +Read_denyusers() +{ + FILE *DFile; /* Denied user file pointer */ + off_t DPos = 0; /* File counter */ + char DChar; /* Character buffer */ + + /* Stat the file. If it does not exist, save the size as zero. + * Clear the denied user string. Return. */ + if (stat(Denyuserpath, &FileBuf) == -1) { + if (errno == ENOENT) { + LastModTime = (time_t) 0; + DenyUserSize = 0; + free(DeniedUsers); + DeniedUsers = malloc(sizeof(char)); + DeniedUsers[0] = '\0'; + return 0; + } else { + syslog(LOG_USER | LOG_ERR, strerror(errno)); + return 1; + } + } + /* If it exists, save the modification time and size */ + LastModTime = FileBuf.st_mtime; + DenyUserSize = FileBuf.st_size; + + /* Handle the special case of a zero length file */ + if (DenyUserSize == 0) { + free(DeniedUsers); + DeniedUsers = malloc(sizeof(char)); + DeniedUsers[0] = '\0'; + return 0; + } + /* Free and allocate space for a string to store the denied usernames */ + free(DeniedUsers); + + if ((DeniedUsers = malloc(sizeof(char) * (DenyUserSize + 3))) == NULL) { + syslog(LOG_USER | LOG_ERR, "Read_denyusers: malloc(DeniedUsers) failed."); + return 1; + } + /* Open the denied user file. Report any errors. */ + + if ((DFile = fopen(Denyuserpath, "r")) == NULL) { + syslog(LOG_USER | LOG_ERR, "Read_denyusers: Failed to open denied user file."); + syslog(LOG_USER | LOG_ERR, strerror(errno)); + return 1; + } + /* Read user names into the DeniedUsers string. + * Make sure each string is delimited by a space. */ + + DeniedUsers[DPos++] = ' '; + + while (!feof(DFile)) { + if ((DChar = fgetc(DFile)) == EOF) + break; + else { + if (isspace(DChar)) + DeniedUsers[DPos++] = ' '; + else + DeniedUsers[DPos++] = toupper(DChar); + } + } + + DeniedUsers[DPos++] = ' '; + DeniedUsers[DPos] = '\0'; + fclose(DFile); + return 0; +} + +/* + * Check to see if the username provided by Squid appears in the denied + * user list. Returns 0 if the user was not found, and 1 if they were. + */ + +int +Check_ifuserdenied(char *ConnectingUser) +{ + static char CUBuf[NAMELEN + 1]; + static char CUBuf1[NAMELEN + 1]; + static int x; + static char DenyMsg[256]; + + /* If user string is empty, deny */ + if (ConnectingUser[0] == '\0') + return 1; + + /* If denied user list is empty, allow */ + if (DenyUserSize == 0) + return 0; + + /* Check if username string is found in the denied user list. + * If so, deny. If not, allow. Reconstruct the username + * to have whitespace, to avoid finding wrong string subsets. */ + + sscanf(ConnectingUser, " %s ", CUBuf1); + sprintf(CUBuf, " %s ", CUBuf1); + + for (x = 0; x <= strlen(CUBuf); x++) + CUBuf[x] = toupper(CUBuf[x]); + + if (strstr(DeniedUsers, CUBuf) == NULL) + return 0; + else { + sprintf(DenyMsg, "Denied access to user '%s'.", CUBuf1); + syslog(LOG_USER | LOG_ERR, DenyMsg); + return 1; + } +} + +/* + * Checks if there has been a change in the denied user file. + * If the modification time has changed, then reload the denied user list. + * This function is called by the SIGHUP signal handler. + */ + +void +Check_fordenychange() +{ + struct stat ChkBuf; /* Stat data buffer */ + + /* Stat the denied user file. If it cannot be accessed, return. */ + + if (stat(Denyuserpath, &ChkBuf) == -1) { + if (errno == ENOENT) { + LastModTime = (time_t) 0; + DenyUserSize = 0; + free(DeniedUsers); + DeniedUsers = malloc(sizeof(char)); + DeniedUsers[0] = '\0'; + return; + } else { /* Report error when accessing file */ + syslog(LOG_USER | LOG_ERR, strerror(errno)); + return; + } + } + /* If found, compare the modification time with the previously-recorded + * modification time. + * If the modification time has changed, reload the denied user list. + * Log a message of its actions. */ + + if (ChkBuf.st_mtime != LastModTime) { + syslog(LOG_USER | LOG_INFO, "Check_fordenychange: Reloading denied user list."); + Read_denyusers(); + } +} + +/* + * Decides if a user is denied or allowed. + * If they have been denied, or not allowed, return 1. + * Else return 0. + */ + +int +Check_user(char *ConnectingUser) +{ + if (Check_ifuserdenied(ConnectingUser) == 1) + return 1; + + if (Check_ifuserallowed(ConnectingUser) == 0) + return 1; + + return 0; +} + +/* + * Checks the denied and allowed user files for change. + * This function is invoked when a SIGHUP signal is received. + * It is also run after every 60 seconds, at the next request. + */ + +void +Check_forchange() +{ + Check_fordenychange(); + Check_forallowchange(); +} + +/* + * Checks the timer. If longer than 1 minute has passed since the last + * time someone has accessed the proxy, then check for changes in the + * denied user file. If longer than one minute hasn't passed, return. + */ + +void +Checktimer() +{ + static time_t Lasttime; /* The last time the timer was checked */ + static time_t Currenttime; /* The current time */ + + Currenttime = time(NULL); + + /* If timeout has expired, check the denied user file, else return */ + if (difftime(Currenttime, Lasttime) < 60) + return; + else { + Check_forchange(); + Lasttime = Currenttime; + } +} Index: squid/src/auth/basic/helpers/MSNT/msntauth-v2.0.lsm diff -u /dev/null squid/src/auth/basic/helpers/MSNT/msntauth-v2.0.lsm:1.2.62.1 --- /dev/null Mon Jan 26 04:57:39 2004 +++ squid/src/auth/basic/helpers/MSNT/msntauth-v2.0.lsm Tue Sep 3 10:42:11 2002 @@ -0,0 +1,13 @@ +Begin3 +Title: msntauth +Version: 2.0 +Entered-date: 01SEP01 +Description: Squid web proxy NT domain authentication module +Keywords: Squid WWW proxy SMB NT domain authentication module source +Author: antonino@rager.com.au (Antonino Iannella) +Maintained-by: antonino@rager.com.au (Antonino Iannella) +Primary-site: sunsite.unc.edu /pub/Linux/system/network/misc + msntauth-v2.0.tgz +Original-site: http://members.tripod.com/stellarx +Copying-policy: GPL +End Index: squid/src/auth/basic/helpers/MSNT/msntauth.c diff -u /dev/null squid/src/auth/basic/helpers/MSNT/msntauth.c:1.2.62.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/MSNT/msntauth.c Tue Sep 3 10:42:12 2002 @@ -0,0 +1,112 @@ + +/* + * MSNT - Microsoft Windows NT domain squid authenticator module + * Version 2.0 by Stellar-X Pty Ltd, Antonino Iannella + * Sun Sep 2 14:39:53 CST 2001 + * + * Modified to act as a Squid authenticator module. + * Removed all Pike stuff. + * Returns OK for a successful authentication, or ERR upon error. + * + * Uses code from - + * Andrew Tridgell 1997 + * Richard Sharpe 1996 + * Bill Welliver 1999 + * Duane Wessels 2000 (wessels@squid-cache.org) + * + * Released under GNU Public License + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +#include "msntauth.h" + +extern char version[]; +char msntauth_version[] = "Msntauth v2.0.3 (C) 2 Sep 2001 Stellar-X Antonino Iannella."; + +/* Main program for simple authentication. + * Reads the denied user file. Sets alarm timer. + * Scans and checks for Squid input, and attempts to validate the user. + */ + +int +main() +{ + char username[256]; + char password[256]; + char wstr[256]; + + /* Read configuration file. Abort wildly if error. */ + if (OpenConfigFile() == 1) + return 1; + + /* Read denied and allowed user files. + * If they fails, there is a serious problem. + * Check syslog messages. Deny all users while in this state. + * The msntauth process should then be killed. */ + + if ((Read_denyusers() == 1) || (Read_allowusers() == 1)) { + while (1) { + fgets(wstr, 255, stdin); + puts("ERR"); + fflush(stdout); + } + } + /* Make Check_forchange() the handle for HUP signals. + * Don't use alarms any more. I don't think it was very + * portable between systems. */ + signal(SIGHUP, Check_forchange); + + while (1) { + /* Read whole line from standard input. Terminate on break. */ + if (fgets(wstr, 255, stdin) == NULL) + break; + + /* Clear any current settings. Read new ones. Use \n as a + * convenient EOL marker which is not even there. */ + username[0] = '\0'; + password[0] = '\0'; + sscanf(wstr, "%s %[^\n]", username, password); /* Extract parameters */ + + /* Check for invalid or blank entries */ + if ((username[0] == '\0') || (password[0] == '\0')) { + puts("ERR"); + fflush(stdout); + continue; + } + Checktimer(); /* Check if the user lists have changed */ + + /* Check if user is explicitly denied or allowed. + * If user passes both checks, they can be authenticated. */ + + if (Check_user(username) == 1) + puts("ERR"); + else { + if (QueryServers(username, password) == 0) + puts("OK"); + else + puts("ERR"); + } + + fflush(stdout); + } + + return 0; +} Index: squid/src/auth/basic/helpers/MSNT/msntauth.conf diff -u /dev/null squid/src/auth/basic/helpers/MSNT/msntauth.conf:1.2.62.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/MSNT/msntauth.conf Tue Sep 3 10:42:12 2002 @@ -0,0 +1,13 @@ + +# Sample MSNT authenticator configuration file +# Antonino Iannella, Stellar-X Pty Ltd +# Sun Sep 2 15:52:31 CST 2001 + +# NT hosts to use. Best to put their IP addresses in /etc/hosts. +server my_PDC my_BDC my_NTdomain +server other_PDC other_BDC otherdomain + +# Denied and allowed users. Comment these if not needed. +denyusers /usr/local/squid/etc/denyusers +allowusers /usr/local/squid/etc/allowusers + Index: squid/src/auth/basic/helpers/MSNT/msntauth.h diff -u /dev/null squid/src/auth/basic/helpers/MSNT/msntauth.h:1.3.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/MSNT/msntauth.h Tue Sep 3 10:42:12 2002 @@ -0,0 +1,8 @@ +extern int OpenConfigFile(void); +extern int QueryServers(char *, char *); +extern void Checktimer(void); +extern void Check_forchange(); +extern int Read_denyusers(void); +extern int Read_allowusers(void); +extern int Check_user(char *); +extern int QueryServers(char *, char *); Index: squid/src/auth/basic/helpers/MSNT/rfcnb-io.c diff -u /dev/null squid/src/auth/basic/helpers/MSNT/rfcnb-io.c:1.3.2.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/MSNT/rfcnb-io.c Tue Sep 3 10:42:13 2002 @@ -0,0 +1,419 @@ +/* UNIX RFCNB (RFC1001/RFC1002) NEtBIOS implementation + * + * Version 1.0 + * RFCNB IO Routines ... + * + * Copyright (C) Richard Sharpe 1996 + * + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* #include */ +#include "std-includes.h" +#include "rfcnb-priv.h" +#include "rfcnb-util.h" +#include "rfcnb-io.h" +#include +#include +#include + + +int RFCNB_Timeout = 0; /* Timeout in seconds ... */ + +void +rfcnb_alarm(int sig) +{ + + fprintf(stderr, "IO Timed out ...\n"); + +} + +/* Set timeout value and setup signal handling */ + +int +RFCNB_Set_Timeout(int seconds) +{ +#ifdef __GLIBC__ + int temp; +#endif + /* If we are on a Bezerkeley system, use sigvec, else sigaction */ +#ifndef SA_RESTART + struct sigvec invec, outvec; +#else + struct sigaction inact, outact; +#endif + + RFCNB_Timeout = seconds; + + if (RFCNB_Timeout > 0) { /* Set up handler to ignore but not restart */ + +#ifndef SA_RESTART + invec.sv_handler = (void (*)()) rfcnb_alarm; + invec.sv_mask = 0; + invec.sv_flags = SV_INTERRUPT; + + if (sigvec(SIGALRM, &invec, &outvec) < 0) + return (-1); +#else + inact.sa_handler = (void (*)()) rfcnb_alarm; +#ifdef SOLARIS + /* Solaris seems to have an array of vectors ... */ + inact.sa_mask.__sigbits[0] = 0; + inact.sa_mask.__sigbits[1] = 0; + inact.sa_mask.__sigbits[2] = 0; + inact.sa_mask.__sigbits[3] = 0; +#else +#ifdef __GLIBC__ + for (temp = 0; temp < 32; temp++) + inact.sa_mask.__val[temp] = 0; +#else + /* AI - If you have problems with this line, contact the author */ + /* AI - This is the old line: inact.sa_mask = 0; */ + memset(&inact.sa_mask, 0, sizeof(inact.sa_mask)); +#endif +#endif + inact.sa_flags = 0; /* Don't restart */ + + if (sigaction(SIGALRM, &inact, &outact) < 0) + return (-1); + +#endif + + } + return (0); + +} + +/* Discard the rest of an incoming packet as we do not have space for it + * in the buffer we allocated or were passed ... */ + +int +RFCNB_Discard_Rest(struct RFCNB_Con *con, int len) +{ + char temp[100]; /* Read into here */ + int rest, this_read, bytes_read; + + /* len is the amount we should read */ + +#ifdef RFCNB_DEBUG + fprintf(stderr, "Discard_Rest called to discard: %i\n", len); +#endif + + rest = len; + + while (rest > 0) { + + this_read = (rest > sizeof(temp) ? sizeof(temp) : rest); + + bytes_read = read(con->fd, temp, this_read); + + if (bytes_read <= 0) { /* Error so return */ + + if (bytes_read < 0) + RFCNB_errno = RFCNBE_BadRead; + else + RFCNB_errno = RFCNBE_ConGone; + + RFCNB_saved_errno = errno; + return (RFCNBE_Bad); + + } + rest = rest - bytes_read; + + } + + return (0); + +} + + +/* Send an RFCNB packet to the connection. + * + * We just send each of the blocks linked together ... + * + * If we can, try to send it as one iovec ... + * + */ + +int +RFCNB_Put_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len) +{ + int len_sent, tot_sent, this_len; + struct RFCNB_Pkt *pkt_ptr; + char *this_data; + int i; + struct iovec io_list[10]; /* We should never have more */ + /* If we do, this will blow up ... */ + + /* Try to send the data ... We only send as many bytes as len claims */ + /* We should try to stuff it into an IOVEC and send as one write */ + + + pkt_ptr = pkt; + len_sent = tot_sent = 0; /* Nothing sent so far */ + i = 0; + + while ((pkt_ptr != NULL) & (i < 10)) { /* Watch that magic number! */ + + this_len = pkt_ptr->len; + this_data = pkt_ptr->data; + if ((tot_sent + this_len) > len) + this_len = len - tot_sent; /* Adjust so we don't send too much */ + + /* Now plug into the iovec ... */ + + io_list[i].iov_len = this_len; + io_list[i].iov_base = this_data; + i++; + + tot_sent += this_len; + + if (tot_sent == len) + break; /* Let's not send too much */ + + pkt_ptr = pkt_ptr->next; + + } + +#ifdef RFCNB_DEBUG + fprintf(stderr, "Frags = %i, tot_sent = %i\n", i, tot_sent); +#endif + + /* Set up an alarm if timeouts are set ... */ + + if (RFCNB_Timeout > 0) + alarm(RFCNB_Timeout); + + if ((len_sent = writev(con->fd, io_list, i)) < 0) { /* An error */ + + con->rfc_errno = errno; + if (errno == EINTR) /* We were interrupted ... */ + RFCNB_errno = RFCNBE_Timeout; + else + RFCNB_errno = RFCNBE_BadWrite; + RFCNB_saved_errno = errno; + return (RFCNBE_Bad); + + } + if (len_sent < tot_sent) { /* Less than we wanted */ + if (errno == EINTR) /* We were interrupted */ + RFCNB_errno = RFCNBE_Timeout; + else + RFCNB_errno = RFCNBE_BadWrite; + RFCNB_saved_errno = errno; + return (RFCNBE_Bad); + } + if (RFCNB_Timeout > 0) + alarm(0); /* Reset that sucker */ + +#ifdef RFCNB_DEBUG + + fprintf(stderr, "Len sent = %i ...\n", len_sent); + RFCNB_Print_Pkt(stderr, "sent", pkt, len_sent); /* Print what send ... */ + +#endif + + return (len_sent); + +} + +/* Read an RFCNB packet off the connection. + * + * We read the first 4 bytes, that tells us the length, then read the + * rest. We should implement a timeout, but we don't just yet + * + */ + + +int +RFCNB_Get_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len) +{ + int read_len, pkt_len; + char hdr[RFCNB_Pkt_Hdr_Len]; /* Local space for the header */ + struct RFCNB_Pkt *pkt_frag; + int more, this_time, offset, frag_len, this_len; + BOOL seen_keep_alive = TRUE; + + /* Read that header straight into the buffer */ + + if (len < RFCNB_Pkt_Hdr_Len) { /* What a bozo */ + +#ifdef RFCNB_DEBUG + fprintf(stderr, "Trying to read less than a packet:"); + perror(""); +#endif + RFCNB_errno = RFCNBE_BadParam; + return (RFCNBE_Bad); + + } + /* We discard keep alives here ... */ + + if (RFCNB_Timeout > 0) + alarm(RFCNB_Timeout); + + while (seen_keep_alive) { + + if ((read_len = read(con->fd, hdr, sizeof(hdr))) < 0) { /* Problems */ +#ifdef RFCNB_DEBUG + fprintf(stderr, "Reading the packet, we got:"); + perror(""); +#endif + if (errno == EINTR) + RFCNB_errno = RFCNBE_Timeout; + else + RFCNB_errno = RFCNBE_BadRead; + RFCNB_saved_errno = errno; + return (RFCNBE_Bad); + + } + /* Now we check out what we got */ + + if (read_len == 0) { /* Connection closed, send back eof? */ + +#ifdef RFCNB_DEBUG + fprintf(stderr, "Connection closed reading\n"); +#endif + + if (errno == EINTR) + RFCNB_errno = RFCNBE_Timeout; + else + RFCNB_errno = RFCNBE_ConGone; + RFCNB_saved_errno = errno; + return (RFCNBE_Bad); + + } + if (RFCNB_Pkt_Type(hdr) == RFCNB_SESSION_KEEP_ALIVE) { + +#ifdef RFCNB_DEBUG + fprintf(stderr, "RFCNB KEEP ALIVE received\n"); +#endif + + } else { + seen_keep_alive = FALSE; + } + + } + + /* What if we got less than or equal to a hdr size in bytes? */ + + if (read_len < sizeof(hdr)) { /* We got a small packet */ + + /* Now we need to copy the hdr portion we got into the supplied packet */ + + memcpy(pkt->data, hdr, read_len); /*Copy data */ + +#ifdef RFCNB_DEBUG + RFCNB_Print_Pkt(stderr, "rcvd", pkt, read_len); +#endif + + return (read_len); + + } + /* Now, if we got at least a hdr size, alloc space for rest, if we need it */ + + pkt_len = RFCNB_Pkt_Len(hdr); + +#ifdef RFCNB_DEBUG + fprintf(stderr, "Reading Pkt: Length = %i\n", pkt_len); +#endif + + /* Now copy in the hdr */ + + memcpy(pkt->data, hdr, sizeof(hdr)); + + /* Get the rest of the packet ... first figure out how big our buf is? */ + /* And make sure that we handle the fragments properly ... Sure should */ + /* use an iovec ... */ + + if (len < pkt_len) /* Only get as much as we have space for */ + more = len - RFCNB_Pkt_Hdr_Len; + else + more = pkt_len; + + this_time = 0; + + /* We read for each fragment ... */ + + if (pkt->len == read_len) { /* If this frag was exact size */ + pkt_frag = pkt->next; /* Stick next lot in next frag */ + offset = 0; /* then we start at 0 in next */ + } else { + pkt_frag = pkt; /* Otherwise use rest of this frag */ + offset = RFCNB_Pkt_Hdr_Len; /* Otherwise skip the header */ + } + + frag_len = pkt_frag->len; + + if (more <= frag_len) /* If len left to get less than frag space */ + this_len = more; /* Get the rest ... */ + else + this_len = frag_len - offset; + + while (more > 0) { + + if ((this_time = read(con->fd, (pkt_frag->data) + offset, this_len)) <= 0) { /* Problems */ + + if (errno == EINTR) { + + RFCNB_errno = RFCNB_Timeout; + + } else { + if (this_time < 0) + RFCNB_errno = RFCNBE_BadRead; + else + RFCNB_errno = RFCNBE_ConGone; + } + + RFCNB_saved_errno = errno; + return (RFCNBE_Bad); + + } +#ifdef RFCNB_DEBUG + fprintf(stderr, "Frag_Len = %i, this_time = %i, this_len = %i, more = %i\n", frag_len, + this_time, this_len, more); +#endif + + read_len = read_len + this_time; /* How much have we read ... */ + + /* Now set up the next part */ + + if (pkt_frag->next == NULL) + break; /* That's it here */ + + pkt_frag = pkt_frag->next; + this_len = pkt_frag->len; + offset = 0; + + more = more - this_time; + + } + +#ifdef RFCNB_DEBUG + fprintf(stderr, "Pkt Len = %i, read_len = %i\n", pkt_len, read_len); + RFCNB_Print_Pkt(stderr, "rcvd", pkt, read_len + sizeof(hdr)); +#endif + + if (read_len < (pkt_len + sizeof(hdr))) { /* Discard the rest */ + + return (RFCNB_Discard_Rest(con, (pkt_len + sizeof(hdr)) - read_len)); + + } + if (RFCNB_Timeout > 0) + alarm(0); /* Reset that sucker */ + + return (read_len + sizeof(RFCNB_Hdr)); +} Index: squid/src/auth/basic/helpers/MSNT/smbencrypt.c diff -u /dev/null squid/src/auth/basic/helpers/MSNT/smbencrypt.c:1.2.62.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/MSNT/smbencrypt.c Tue Sep 3 10:42:14 2002 @@ -0,0 +1,209 @@ +/* + * Unix SMB/Netbios implementation. + * Version 1.9. + * SMB parameters and setup + * Copyright (C) Andrew Tridgell 1992-1997 + * Modified by Jeremy Allison 1995. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* AI inclusion for Solaris filesystem */ +#ifdef SOLARIS +#include +#endif + +#include "smblib-priv.h" +#define uchar unsigned char +extern int DEBUGLEVEL; + +#include "byteorder.h" + +char *StrnCpy(char *dest, char *src, int n); +void strupper(char *s); +extern void E_P16(unsigned char *, unsigned char *); +extern void E_P24(unsigned char *, unsigned char *, unsigned char *); +extern void mdfour(unsigned char *, unsigned char *, int); + + +/* + * This implements the X/Open SMB password encryption + * It takes a password, a 8 byte "crypt key" and puts 24 bytes of + * encrypted password into p24 */ +void +SMBencrypt(uchar * passwd, uchar * c8, uchar * p24) +{ + uchar p14[15], p21[21]; + + memset(p21, '\0', 21); + memset(p14, '\0', 14); + StrnCpy((char *) p14, (char *) passwd, 14); + + strupper((char *) p14); + E_P16(p14, p21); + E_P24(p21, c8, p24); +} + +/* Routines for Windows NT MD4 Hash functions. */ +static int +_my_wcslen(int16 * str) +{ + int len = 0; + while (*str++ != 0) + len++; + return len; +} + +/* + * Convert a string into an NT UNICODE string. + * Note that regardless of processor type + * this must be in intel (little-endian) + * format. + */ + +static int +_my_mbstowcs(int16 * dst, uchar * src, int len) +{ + int i; + int16 val; + + for (i = 0; i < len; i++) { + val = *src; + SSVAL(dst, 0, val); + dst++; + src++; + if (val == 0) + break; + } + return i; +} + +/* + * Creates the MD4 Hash of the users password in NT UNICODE. + */ + +void +E_md4hash(uchar * passwd, uchar * p16) +{ + int len; + int16 wpwd[129]; + + /* Password cannot be longer than 128 characters */ + len = strlen((char *) passwd); + if (len > 128) + len = 128; + /* Password must be converted to NT unicode */ + _my_mbstowcs(wpwd, passwd, len); + wpwd[len] = 0; /* Ensure string is null terminated */ + /* Calculate length in bytes */ + len = _my_wcslen(wpwd) * sizeof(int16); + + mdfour(p16, (unsigned char *) wpwd, len); +} + +/* Does the NT MD4 hash then des encryption. */ + +void +SMBNTencrypt(uchar * passwd, uchar * c8, uchar * p24) +{ + uchar p21[21]; + + memset(p21, '\0', 21); + + E_md4hash(passwd, p21); + E_P24(p21, c8, p24); +} + +/* Does both the NT and LM owfs of a user's password */ + +void +nt_lm_owf_gen(char *pwd, char *nt_p16, char *p16) +{ + char passwd[130]; + StrnCpy(passwd, pwd, sizeof(passwd) - 1); + + /* Calculate the MD4 hash (NT compatible) of the password */ + memset(nt_p16, '\0', 16); + E_md4hash((uchar *) passwd, (uchar *) nt_p16); + + /* Mangle the passwords into Lanman format */ + passwd[14] = '\0'; + strupper(passwd); + + /* Calculate the SMB (lanman) hash functions of the password */ + + memset(p16, '\0', 16); + E_P16((uchar *) passwd, (uchar *) p16); + + /* clear out local copy of user's password (just being paranoid). */ + bzero(passwd, sizeof(passwd)); +} + +/**************************************************************************** +line strncpy but always null terminates. Make sure there is room! +****************************************************************************/ +char * +StrnCpy(char *dest, char *src, int n) +{ + char *d = dest; + if (!dest) + return (NULL); + if (!src) { + *dest = 0; + return (dest); + } + while (n-- && (*d++ = *src++)); + *d = 0; + return (dest); +} + +void +strupper(char *s) +{ + while (*s) { +#if UNUSED_CODE +#if !defined(KANJI_WIN95_COMPATIBILITY) + if (lp_client_code_page() == KANJI_CODEPAGE) { + + if (is_shift_jis(*s)) { + if (is_sj_lower(s[0], s[1])) + s[1] = sj_toupper2(s[1]); + s += 2; + } else if (is_kana(*s)) { + s++; + } else { + if (islower(*s)) + *s = toupper(*s); + s++; + } + } else +#endif /* KANJI_WIN95_COMPATIBILITY */ +#endif /* UNUSED_CODE */ + { + if (islower(*s)) + *s = toupper(*s); + s++; + } + } +} Index: squid/src/auth/basic/helpers/MSNT/smblib-util.c diff -u /dev/null squid/src/auth/basic/helpers/MSNT/smblib-util.c:1.2.62.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/MSNT/smblib-util.c Tue Sep 3 10:42:15 2002 @@ -0,0 +1,803 @@ +/* UNIX SMBlib NetBIOS implementation + * + * Version 1.0 + * SMBlib Utility Routines + * + * Copyright (C) Richard Sharpe 1996 + * + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "smblib-priv.h" + +#include "rfcnb.h" +#include "rfcnb-priv.h" +#include "rfcnb-util.h" + +#include +#include +#include + +char *SMB_Prots[] = +{"PC NETWORK PROGRAM 1.0", + "MICROSOFT NETWORKS 1.03", + "MICROSOFT NETWORKS 3.0", + "DOS LANMAN1.0", + "LANMAN1.0", + "DOS LM1.2X002", + "LM1.2X002", + "DOS LANMAN2.1", + "LANMAN2.1", + "Samba", + "NT LM 0.12", + "NT LANMAN 1.0", + NULL}; + +int SMB_Types[] = +{SMB_P_Core, + SMB_P_CorePlus, + SMB_P_DOSLanMan1, + SMB_P_DOSLanMan1, + SMB_P_LanMan1, + SMB_P_DOSLanMan2, + SMB_P_LanMan2, + SMB_P_LanMan2_1, + SMB_P_LanMan2_1, + SMB_P_NT1, + SMB_P_NT1, + SMB_P_NT1, + -1}; + +/* Print out an SMB pkt in all its gory detail ... */ + +void +SMB_Print_Pkt(FILE fd, RFCNB_Pkt * pkt, BOOL command, int Offset, int Len) +{ + + /* Well, just how do we do this ... print it I suppose */ + + /* Print out the SMB header ... */ + + /* Print the command */ + + /* Print the other bits in the header */ + + + /* etc */ + +} + +/* Convert a DOS Date_Time to a local host type date time for printing */ + +char * +SMB_DOSTimToStr(int DOS_time) +{ + static char SMB_Time_Temp[48]; + int DOS_sec, DOS_min, DOS_hour, DOS_day, DOS_month, DOS_year; + + SMB_Time_Temp[0] = 0; + + DOS_sec = (DOS_time & 0x001F) * 2; + DOS_min = (DOS_time & 0x07E0) >> 5; + DOS_hour = ((DOS_time & 0xF800) >> 11); + + DOS_day = (DOS_time & 0x001F0000) >> 16; + DOS_month = (DOS_time & 0x01E00000) >> 21; + DOS_year = ((DOS_time & 0xFE000000) >> 25) + 80; + + sprintf(SMB_Time_Temp, "%2d/%02d/%2d %2d:%02d:%02d", DOS_day, DOS_month, + DOS_year, DOS_hour, DOS_min, DOS_sec); + + return (SMB_Time_Temp); + +} + +/* Convert an attribute byte/word etc to a string ... We return a pointer + * to a static string which we guarantee is long enough. If verbose is + * true, we print out long form of strings ... */ + +char * +SMB_AtrToStr(int attribs, BOOL verbose) +{ + static char SMB_Attrib_Temp[128]; + + SMB_Attrib_Temp[0] = 0; + + if (attribs & SMB_FA_ROF) + strcat(SMB_Attrib_Temp, (verbose ? "Read Only " : "R")); + + if (attribs & SMB_FA_HID) + strcat(SMB_Attrib_Temp, (verbose ? "Hidden " : "H")); + + if (attribs & SMB_FA_SYS) + strcat(SMB_Attrib_Temp, (verbose ? "System " : "S")); + + if (attribs & SMB_FA_VOL) + strcat(SMB_Attrib_Temp, (verbose ? "Volume " : "V")); + + if (attribs & SMB_FA_DIR) + strcat(SMB_Attrib_Temp, (verbose ? "Directory " : "D")); + + if (attribs & SMB_FA_ARC) + strcat(SMB_Attrib_Temp, (verbose ? "Archive " : "A")); + + return (SMB_Attrib_Temp); + +} + +/* Pick up the Max Buffer Size from the Tree Structure ... */ + +int +SMB_Get_Tree_MBS(SMB_Tree_Handle tree) +{ + if (tree != NULL) { + return (tree->mbs); + } else { + return (SMBlibE_BAD); + } +} + +/* Pick up the Max buffer size */ + +int +SMB_Get_Max_Buf_Siz(SMB_Handle_Type Con_Handle) +{ + if (Con_Handle != NULL) { + return (Con_Handle->max_xmit); + } else { + return (SMBlibE_BAD); + } + +} +/* Pickup the protocol index from the connection structure */ + +int +SMB_Get_Protocol_IDX(SMB_Handle_Type Con_Handle) +{ + if (Con_Handle != NULL) { + return (Con_Handle->prot_IDX); + } else { + return (0xFFFF); /* Invalid protocol */ + } + +} + +/* Pick up the protocol from the connection structure */ + +int +SMB_Get_Protocol(SMB_Handle_Type Con_Handle) +{ + if (Con_Handle != NULL) { + return (Con_Handle->protocol); + } else { + return (0xFFFF); /* Invalid protocol */ + } + +} + +/* Figure out what protocol was accepted, given the list of dialect strings */ +/* We offered, and the index back from the server. We allow for a user */ +/* supplied list, and assume that it is a subset of our list */ + +int +SMB_Figure_Protocol(char *dialects[], int prot_index) +{ + int i; + + if (dialects == SMB_Prots) { /* The jobs is easy, just index into table */ + + return (SMB_Types[prot_index]); + } else { /* Search through SMB_Prots looking for a match */ + + for (i = 0; SMB_Prots[i] != NULL; i++) { + + if (strcmp(dialects[prot_index], SMB_Prots[i]) == 0) { /* A match */ + + return (SMB_Types[i]); + + } + } + + /* If we got here, then we are in trouble, because the protocol was not */ + /* One we understand ... */ + + return (SMB_P_Unknown); + + } + +} + + +/* Negotiate the protocol we will use from the list passed in Prots */ +/* we return the index of the accepted protocol in NegProt, -1 indicates */ +/* none acceptible, and our return value is 0 if ok, <0 if problems */ + +int +SMB_Negotiate(SMB_Handle_Type Con_Handle, char *Prots[]) +{ + struct RFCNB_Pkt *pkt; + int prots_len, i, pkt_len, prot, alloc_len; + char *p; + + /* Figure out how long the prot list will be and allocate space for it */ + + prots_len = 0; + + for (i = 0; Prots[i] != NULL; i++) { + + prots_len = prots_len + strlen(Prots[i]) + 2; /* Account for null etc */ + + } + + /* The -1 accounts for the one byte smb_buf we have because some systems */ + /* don't like char msg_buf[] */ + + pkt_len = SMB_negp_len + prots_len; + + /* Make sure that the pkt len is long enough for the max response ... */ + /* Which is a problem, because the encryption key len eec may be long */ + + if (pkt_len < (SMB_hdr_wct_offset + (19 * 2) + 40)) { + + alloc_len = SMB_hdr_wct_offset + (19 * 2) + 40; + + } else { + + alloc_len = pkt_len; + + } + + pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(alloc_len); + + if (pkt == NULL) { + + SMBlib_errno = SMBlibE_NoSpace; + return (SMBlibE_BAD); + + } + /* Now plug in the bits we need */ + + bzero(SMB_Hdr(pkt), SMB_negp_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBnegprot; + SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle->pid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle->mid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle->uid); + *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0; + + SSVAL(SMB_Hdr(pkt), SMB_negp_bcc_offset, prots_len); + + /* Now copy the prot strings in with the right stuff */ + + p = (char *) (SMB_Hdr(pkt) + SMB_negp_buf_offset); + + for (i = 0; Prots[i] != NULL; i++) { + + *p = SMBdialectID; + strcpy(p + 1, Prots[i]); + p = p + strlen(Prots[i]) + 2; /* Adjust len of p for null plus dialectID */ + + } + + /* Now send the packet and sit back ... */ + + if (RFCNB_Send(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) { + + +#ifdef DEBUG + fprintf(stderr, "Error sending negotiate protocol\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_SendFailed; /* Failed, check lower layer errno */ + return (SMBlibE_BAD); + + } + /* Now get the response ... */ + + if (RFCNB_Recv(Con_Handle->Trans_Connect, pkt, alloc_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to negotiate\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_RecvFailed; /* Failed, check lower layer errno */ + return (SMBlibE_BAD); + + } + if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ + +#ifdef DEBUG + fprintf(stderr, "SMB_Negotiate failed with errorclass = %i, Error Code = %i\n", + CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset), + SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset)); +#endif + + SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset); + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_Remote; + return (SMBlibE_BAD); + + } + if (SVAL(SMB_Hdr(pkt), SMB_negrCP_idx_offset) == 0xFFFF) { + +#ifdef DEBUG + fprintf(stderr, "None of our protocols was accepted ... "); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_NegNoProt; + return (SMBlibE_BAD); + + } + /* Now, unpack the info from the response, if any and evaluate the proto */ + /* selected. We must make sure it is one we like ... */ + + Con_Handle->prot_IDX = prot = SVAL(SMB_Hdr(pkt), SMB_negrCP_idx_offset); + Con_Handle->protocol = SMB_Figure_Protocol(Prots, prot); + + if (Con_Handle->protocol == SMB_P_Unknown) { /* No good ... */ + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_ProtUnknown; + return (SMBlibE_BAD); + + } + switch (CVAL(SMB_Hdr(pkt), SMB_hdr_wct_offset)) { + + case 0x01: /* No more info ... */ + + break; + + case 13: /* Up to and including LanMan 2.1 */ + + Con_Handle->Security = SVAL(SMB_Hdr(pkt), SMB_negrLM_sec_offset); + Con_Handle->encrypt_passwords = ((Con_Handle->Security & SMB_sec_encrypt_mask) != 0x00); + Con_Handle->Security = Con_Handle->Security & SMB_sec_user_mask; + + Con_Handle->max_xmit = SVAL(SMB_Hdr(pkt), SMB_negrLM_mbs_offset); + Con_Handle->MaxMPX = SVAL(SMB_Hdr(pkt), SMB_negrLM_mmc_offset); + Con_Handle->MaxVC = SVAL(SMB_Hdr(pkt), SMB_negrLM_mnv_offset); + Con_Handle->Raw_Support = SVAL(SMB_Hdr(pkt), SMB_negrLM_rm_offset); + Con_Handle->SessionKey = IVAL(SMB_Hdr(pkt), SMB_negrLM_sk_offset); + Con_Handle->SvrTZ = SVAL(SMB_Hdr(pkt), SMB_negrLM_stz_offset); + Con_Handle->Encrypt_Key_Len = SVAL(SMB_Hdr(pkt), SMB_negrLM_ekl_offset); + + p = (SMB_Hdr(pkt) + SMB_negrLM_buf_offset); + fprintf(stderr, "%d", (int) (SMB_Hdr(pkt) + SMB_negrLM_buf_offset)); + memcpy(Con_Handle->Encrypt_Key, p, 8); + + p = (SMB_Hdr(pkt) + SMB_negrLM_buf_offset + Con_Handle->Encrypt_Key_Len); + + strncpy(p, Con_Handle->Svr_PDom, sizeof(Con_Handle->Svr_PDom) - 1); + + break; + + case 17: /* NT LM 0.12 and LN LM 1.0 */ + + Con_Handle->Security = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_sec_offset); + Con_Handle->encrypt_passwords = ((Con_Handle->Security & SMB_sec_encrypt_mask) != 0x00); + Con_Handle->Security = Con_Handle->Security & SMB_sec_user_mask; + + Con_Handle->max_xmit = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_mbs_offset); + Con_Handle->MaxMPX = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_mmc_offset); + Con_Handle->MaxVC = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_mnv_offset); + Con_Handle->MaxRaw = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_mrs_offset); + Con_Handle->SessionKey = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_sk_offset); + Con_Handle->SvrTZ = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_stz_offset); + Con_Handle->Encrypt_Key_Len = CVAL(SMB_Hdr(pkt), SMB_negrNTLM_ekl_offset); + + p = (SMB_Hdr(pkt) + SMB_negrNTLM_buf_offset); + memcpy(Con_Handle->Encrypt_Key, p, 8); + p = (SMB_Hdr(pkt) + SMB_negrNTLM_buf_offset + Con_Handle->Encrypt_Key_Len); + + strncpy(p, Con_Handle->Svr_PDom, sizeof(Con_Handle->Svr_PDom) - 1); + + break; + + default: + +#ifdef DEBUG + fprintf(stderr, "Unknown NegProt response format ... Ignored\n"); + fprintf(stderr, " wct = %i\n", CVAL(SMB_Hdr(pkt), SMB_hdr_wct_offset)); +#endif + + break; + } + +#ifdef DEBUG + fprintf(stderr, "Protocol selected is: %i:%s\n", prot, Prots[prot]); +#endif + + RFCNB_Free_Pkt(pkt); + return (0); + +} + +/* Get our hostname */ + +void +SMB_Get_My_Name(char *name, int len) +{ + + if (gethostname(name, len) < 0) { /* Error getting name */ + + strncpy(name, "unknown", len); + + /* Should check the error */ + +#ifdef DEBUG + fprintf(stderr, "gethostname in SMB_Get_My_Name returned error:"); + perror(""); +#endif + + } + /* only keep the portion up to the first "." */ + + +} + +/* Send a TCON to the remote server ... */ + +SMB_Tree_Handle +SMB_TreeConnect(SMB_Handle_Type Con_Handle, + SMB_Tree_Handle Tree_Handle, + char *path, + char *password, + char *device) +{ + struct RFCNB_Pkt *pkt; + int param_len, pkt_len; + char *p; + SMB_Tree_Handle tree; + + /* Figure out how much space is needed for path, password, dev ... */ + + if ((path == NULL) | (password == NULL) | (device == NULL)) { + +#ifdef DEBUG + fprintf(stderr, "Bad parameter passed to SMB_TreeConnect\n"); +#endif + + SMBlib_errno = SMBlibE_BadParam; + return (NULL); + + } + /* The + 2 is because of the \0 and the marker ... */ + + param_len = strlen(path) + 2 + strlen(password) + 2 + strlen(device) + 2; + + /* The -1 accounts for the one byte smb_buf we have because some systems */ + /* don't like char msg_buf[] */ + + pkt_len = SMB_tcon_len + param_len; + + pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { + + SMBlib_errno = SMBlibE_NoSpace; + return (NULL); /* Should handle the error */ + + } + /* Now allocate a tree for this to go into ... */ + + if (Tree_Handle == NULL) { + + tree = (SMB_Tree_Handle) malloc(sizeof(struct SMB_Tree_Structure)); + + if (tree == NULL) { + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_NoSpace; + return (NULL); + + } + } else { + + tree = Tree_Handle; + + } + + tree->next = tree->prev = NULL; + tree->con = Con_Handle; + strncpy(tree->path, path, sizeof(tree->path)); + strncpy(tree->device_type, device, sizeof(tree->device_type)); + + /* Now plug in the values ... */ + + bzero(SMB_Hdr(pkt), SMB_tcon_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBtcon; + SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle->pid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle->mid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle->uid); + *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0; + + SSVAL(SMB_Hdr(pkt), SMB_tcon_bcc_offset, param_len); + + /* Now copy the param strings in with the right stuff */ + + p = (char *) (SMB_Hdr(pkt) + SMB_tcon_buf_offset); + *p = SMBasciiID; + strcpy(p + 1, path); + p = p + strlen(path) + 2; + *p = SMBasciiID; + strcpy(p + 1, password); + p = p + strlen(password) + 2; + *p = SMBasciiID; + strcpy(p + 1, device); + + /* Now send the packet and sit back ... */ + + if (RFCNB_Send(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error sending TCon request\n"); +#endif + + if (Tree_Handle == NULL) + free(tree); + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_SendFailed; + return (NULL); + + } + /* Now get the response ... */ + + if (RFCNB_Recv(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to TCon\n"); +#endif + + if (Tree_Handle == NULL) + free(tree); + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_RecvFailed; + return (NULL); + + } + /* Check out the response type ... */ + + if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ + +#ifdef DEBUG + fprintf(stderr, "SMB_TCon failed with errorclass = %i, Error Code = %i\n", + CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset), + SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset)); +#endif + + if (Tree_Handle == NULL) + free(tree); + SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset); + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_Remote; + return (NULL); + + } + tree->tid = SVAL(SMB_Hdr(pkt), SMB_tconr_tid_offset); + tree->mbs = SVAL(SMB_Hdr(pkt), SMB_tconr_mbs_offset); + +#ifdef DEBUG + fprintf(stderr, "TConn succeeded, with TID=%i, Max Xmit=%i\n", + tree->tid, tree->mbs); +#endif + + /* Now link the Tree to the Server Structure ... */ + + if (Con_Handle->first_tree == NULL) { + + Con_Handle->first_tree = tree; + Con_Handle->last_tree = tree; + + } else { + + Con_Handle->last_tree->next = tree; + tree->prev = Con_Handle->last_tree; + Con_Handle->last_tree = tree; + + } + + RFCNB_Free_Pkt(pkt); + return (tree); + +} + +int +SMB_TreeDisconnect(SMB_Tree_Handle Tree_Handle, BOOL discard) +{ + struct RFCNB_Pkt *pkt; + int pkt_len; + + pkt_len = SMB_tdis_len; + + pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { + + SMBlib_errno = SMBlibE_NoSpace; + return (SMBlibE_BAD); /* Should handle the error */ + + } + /* Now plug in the values ... */ + + bzero(SMB_Hdr(pkt), SMB_tdis_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBtdis; + SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Tree_Handle->con->pid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Tree_Handle->con->mid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Tree_Handle->con->uid); + *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0; + + SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, Tree_Handle->tid); + SSVAL(SMB_Hdr(pkt), SMB_tcon_bcc_offset, 0); + + /* Now send the packet and sit back ... */ + + if (RFCNB_Send(Tree_Handle->con->Trans_Connect, pkt, pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error sending TDis request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_SendFailed; + return (SMBlibE_BAD); + + } + /* Now get the response ... */ + + if (RFCNB_Recv(Tree_Handle->con->Trans_Connect, pkt, pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to TCon\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_RecvFailed; + return (SMBlibE_BAD); + + } + /* Check out the response type ... */ + + if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ + +#ifdef DEBUG + fprintf(stderr, "SMB_TDis failed with errorclass = %i, Error Code = %i\n", + CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset), + SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset)); +#endif + + SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset); + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_Remote; + return (SMBlibE_BAD); + + } + Tree_Handle->tid = 0xFFFF; /* Invalid TID */ + Tree_Handle->mbs = 0; /* Invalid */ + +#ifdef DEBUG + + fprintf(stderr, "Tree disconnect successful ...\n"); + +#endif + + /* What about the tree handle ? */ + + if (discard == TRUE) { /* Unlink it and free it ... */ + + if (Tree_Handle->next == NULL) + Tree_Handle->con->first_tree = Tree_Handle->prev; + else + Tree_Handle->next->prev = Tree_Handle->prev; + + if (Tree_Handle->prev == NULL) + Tree_Handle->con->last_tree = Tree_Handle->next; + else + Tree_Handle->prev->next = Tree_Handle->next; + + } + RFCNB_Free_Pkt(pkt); + return (0); + +} + +/* Pick up the last LMBlib error ... */ + +int +SMB_Get_Last_Error() +{ + + return (SMBlib_errno); + +} + +/* Pick up the last error returned in an SMB packet */ +/* We will need macros to extract error class and error code */ + +int +SMB_Get_Last_SMB_Err() +{ + + return (SMBlib_SMB_Error); + +} + +/* Pick up the error message associated with an error from SMBlib */ + +/* Keep this table in sync with the message codes in smblib-common.h */ + +static char *SMBlib_Error_Messages[] = +{ + + "Request completed sucessfully.", + "Server returned a non-zero SMB Error Class and Code.", + "A lower layer protocol error occurred.", + "Function not yet implemented.", + "The protocol negotiated does not support the request.", + "No space available for operation.", + "One or more bad parameters passed.", + "None of the protocols we offered were accepted.", + "The attempt to send an SMB request failed. See protocol error info.", + "The attempt to get an SMB response failed. See protocol error info.", + "The logon request failed, but you were logged in as guest.", + "The attempt to call the remote server failed. See protocol error info.", + "The protocol dialect specified in a NegProt and accepted by the server is unknown.", + /* This next one simplifies error handling */ + "No such error code.", + NULL}; + +void +SMB_Get_Error_Msg(int msg, char *msgbuf, int len) +{ + + if (msg >= 0) { + + strncpy(msgbuf, + SMBlib_Error_Messages[msg > SMBlibE_NoSuchMsg ? SMBlibE_NoSuchMsg : msg], + len - 1); + msgbuf[len - 1] = 0; /* Make sure it is a string */ + } else { /* Add the lower layer message ... */ + + char prot_msg[1024]; + + msg = -msg; /* Make it positive */ + + strncpy(msgbuf, + SMBlib_Error_Messages[msg > SMBlibE_NoSuchMsg ? SMBlibE_NoSuchMsg : msg], + len - 1); + + msgbuf[len - 1] = 0; /* make sure it is a string */ + + if (strlen(msgbuf) < len) { /* If there is space, put rest in */ + + strncat(msgbuf, "\n\t", len - strlen(msgbuf)); + + RFCNB_Get_Error(prot_msg, sizeof(prot_msg) - 1); + + strncat(msgbuf, prot_msg, len - strlen(msgbuf)); + + } + } + +} Index: squid/src/auth/basic/helpers/MSNT/smblib.c diff -u /dev/null squid/src/auth/basic/helpers/MSNT/smblib.c:1.2.62.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/MSNT/smblib.c Tue Sep 3 10:42:15 2002 @@ -0,0 +1,554 @@ +/* UNIX SMBlib NetBIOS implementation + * + * Version 1.0 + * SMBlib Routines + * + * Copyright (C) Richard Sharpe 1996 + * + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +int SMBlib_errno; +int SMBlib_SMB_Error; +#define SMBLIB_ERRNO +#define uchar unsigned char +#include "smblib-priv.h" +#include "smblib.h" +#include "rfcnb-priv.h" +#include "rfcnb.h" +#include "rfcnb-util.h" + +#include +#include +#include +#include +#include + +SMB_State_Types SMBlib_State; + +extern int RFCNB_Set_Sock_NoDelay(RFCNB_Con *, BOOL); +extern void SMB_Get_My_Name(char *, int); + +/* Initialize the SMBlib package */ + +int +SMB_Init() +{ + + SMBlib_State = SMB_State_Started; + + signal(SIGPIPE, SIG_IGN); /* Ignore these ... */ + +/* If SMBLIB_Instrument is defines, turn on the instrumentation stuff */ +#ifdef SMBLIB_INSTRUMENT + + SMBlib_Instrument_Init(); + +#endif + + return 0; + +} + +int +SMB_Term() +{ + +#ifdef SMBLIB_INSTRUMENT + + SMBlib_Instrument_Term(); /* Clean up and print results */ + +#endif + + return 0; + +} + +/* SMB_Create: Create a connection structure and return for later use */ +/* We have other helper routines to set variables */ + +SMB_Handle_Type +SMB_Create_Con_Handle(void) +{ + + SMBlib_errno = SMBlibE_NotImpl; + return (NULL); + +} + +int +SMBlib_Set_Sock_NoDelay(SMB_Handle_Type Con_Handle, BOOL yn) +{ + + + if (RFCNB_Set_Sock_NoDelay(Con_Handle->Trans_Connect, yn) < 0) { + +#ifdef DEBUG +#endif + + fprintf(stderr, "Setting no-delay on TCP socket failed ...\n"); + + } + return (0); + +} + +/* SMB_Connect_Server: Connect to a server, but don't negotiate protocol */ +/* or anything else ... */ + +SMB_Handle_Type +SMB_Connect_Server(SMB_Handle_Type Con_Handle, + char *server, char *NTdomain) +{ + SMB_Handle_Type con; + char called[80], calling[80], *address; + int i; + + /* Get a connection structure if one does not exist */ + + con = Con_Handle; + + if (Con_Handle == NULL) { + + if ((con = (struct SMB_Connect_Def *) malloc(sizeof(struct SMB_Connect_Def))) == NULL) { + + + SMBlib_errno = SMBlibE_NoSpace; + return NULL; + } + } + /* Init some things ... */ + + strcpy(con->service, ""); + strcpy(con->username, ""); + strcpy(con->password, ""); + strcpy(con->sock_options, ""); + strcpy(con->address, ""); + strcpy(con->desthost, server); + strcpy(con->PDomain, NTdomain); + strcpy(con->OSName, SMBLIB_DEFAULT_OSNAME); + strcpy(con->LMType, SMBLIB_DEFAULT_LMTYPE); + con->first_tree = con->last_tree = NULL; + + SMB_Get_My_Name(con->myname, sizeof(con->myname)); + + con->port = 0; /* No port selected */ + + /* Get some things we need for the SMB Header */ + + con->pid = getpid(); + con->mid = con->pid; /* This will do for now ... */ + con->uid = 0; /* Until we have done a logon, no uid ... */ + con->gid = getgid(); + + /* Now connect to the remote end, but first upper case the name of the + * service we are going to call, sine some servers want it in uppercase */ + + for (i = 0; i < strlen(server); i++) + called[i] = toupper(server[i]); + + called[strlen(server)] = 0; /* Make it a string */ + + for (i = 0; i < strlen(con->myname); i++) + calling[i] = toupper(con->myname[i]); + + calling[strlen(con->myname)] = 0; /* Make it a string */ + + if (strcmp(con->address, "") == 0) + address = con->desthost; + else + address = con->address; + + con->Trans_Connect = RFCNB_Call(called, + calling, + address, /* Protocol specific */ + con->port); + + /* Did we get one? */ + + if (con->Trans_Connect == NULL) { + + if (Con_Handle == NULL) { + Con_Handle = NULL; + free(con); + } + SMBlib_errno = -SMBlibE_CallFailed; + return NULL; + + } + return (con); + +} + +/* SMB_Connect: Connect to the indicated server */ +/* If Con_Handle == NULL then create a handle and connect, otherwise */ +/* use the handle passed */ + +char *SMB_Prots_Restrict[] = +{"PC NETWORK PROGRAM 1.0", + NULL}; + + +SMB_Handle_Type +SMB_Connect(SMB_Handle_Type Con_Handle, + SMB_Tree_Handle * tree, + char *service, + char *username, + char *password) +{ + SMB_Handle_Type con; + char *host, *address; + char temp[80], called[80], calling[80]; + int i; + + /* Get a connection structure if one does not exist */ + + con = Con_Handle; + + if (Con_Handle == NULL) { + + if ((con = (struct SMB_Connect_Def *) malloc(sizeof(struct SMB_Connect_Def))) == NULL) { + + SMBlib_errno = SMBlibE_NoSpace; + return NULL; + } + } + /* Init some things ... */ + + strcpy(con->service, service); + strcpy(con->username, username); + strcpy(con->password, password); + strcpy(con->sock_options, ""); + strcpy(con->address, ""); + strcpy(con->PDomain, SMBLIB_DEFAULT_DOMAIN); + strcpy(con->OSName, SMBLIB_DEFAULT_OSNAME); + strcpy(con->LMType, SMBLIB_DEFAULT_LMTYPE); + con->first_tree = con->last_tree = NULL; + + SMB_Get_My_Name(con->myname, sizeof(con->myname)); + + con->port = 0; /* No port selected */ + + /* Get some things we need for the SMB Header */ + + con->pid = getpid(); + con->mid = con->pid; /* This will do for now ... */ + con->uid = 0; /* Until we have done a logon, no uid */ + con->gid = getgid(); + + /* Now figure out the host portion of the service */ + + strcpy(temp, service); + /* AI - Added (char *) to stop compiler warnings */ + host = (char *) strtok(temp, "/\\"); /* Separate host name portion */ + strcpy(con->desthost, host); + + /* Now connect to the remote end, but first upper case the name of the + * service we are going to call, sine some servers want it in uppercase */ + + for (i = 0; i < strlen(host); i++) + called[i] = toupper(host[i]); + + called[strlen(host)] = 0; /* Make it a string */ + + for (i = 0; i < strlen(con->myname); i++) + calling[i] = toupper(con->myname[i]); + + calling[strlen(con->myname)] = 0; /* Make it a string */ + + if (strcmp(con->address, "") == 0) + address = con->desthost; + else + address = con->address; + + con->Trans_Connect = RFCNB_Call(called, + calling, + address, /* Protocol specific */ + con->port); + + /* Did we get one? */ + + if (con->Trans_Connect == NULL) { + + if (Con_Handle == NULL) { + free(con); + Con_Handle = NULL; + } + SMBlib_errno = -SMBlibE_CallFailed; + return NULL; + + } + /* Now, negotiate the protocol */ + + if (SMB_Negotiate(con, SMB_Prots_Restrict) < 0) { + + /* Hmmm what should we do here ... We have a connection, but could not + * negotiate ... */ + + return NULL; + + } + /* Now connect to the service ... */ + + if ((*tree = SMB_TreeConnect(con, NULL, service, password, "A:")) == NULL) { + + return NULL; + + } + return (con); + +} + +/* Logon to the server. That is, do a session setup if we can. We do not do */ +/* Unicode yet! */ + +int +SMB_Logon_Server(SMB_Handle_Type Con_Handle, char *UserName, + char *PassWord) +{ + struct RFCNB_Pkt *pkt; + int param_len, pkt_len, pass_len; + char *p, pword[128]; + + /* First we need a packet etc ... but we need to know what protocol has */ + /* been negotiated to figure out if we can do it and what SMB format to */ + /* use ... */ + + if (Con_Handle->protocol < SMB_P_LanMan1) { + + SMBlib_errno = SMBlibE_ProtLow; + return (SMBlibE_BAD); + + } + strcpy(pword, PassWord); +#ifdef PAM_SMB_ENC_PASS + if (Con_Handle->encrypt_passwords) { + pass_len = 24; + SMBencrypt((uchar *) PassWord, (uchar *) Con_Handle->Encrypt_Key, (uchar *) pword); + } else +#endif + pass_len = strlen(pword); + + + /* Now build the correct structure */ + + if (Con_Handle->protocol < SMB_P_NT1) { + + param_len = strlen(UserName) + 1 + pass_len + 1 + + strlen(Con_Handle->PDomain) + 1 + + strlen(Con_Handle->OSName) + 1; + + pkt_len = SMB_ssetpLM_len + param_len; + + pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { + + SMBlib_errno = SMBlibE_NoSpace; + return (SMBlibE_BAD); /* Should handle the error */ + + } + bzero(SMB_Hdr(pkt), SMB_ssetpLM_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX; + SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle->pid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle->mid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle->uid); + *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 10; + *(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = 0xFF; /* No extra command */ + SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, 0); + + SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mbs_offset, SMBLIB_MAX_XMIT); + SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mmc_offset, 2); + SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_vcn_offset, Con_Handle->pid); + SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_snk_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_pwl_offset, pass_len + 1); + SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_res_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_bcc_offset, param_len); + + /* Now copy the param strings in with the right stuff */ + + p = (char *) (SMB_Hdr(pkt) + SMB_ssetpLM_buf_offset); + + /* Copy in password, then the rest. Password has a null at end */ + + memcpy(p, pword, pass_len); + + p = p + pass_len + 1; + + strcpy(p, UserName); + p = p + strlen(UserName); + *p = 0; + + p = p + 1; + + strcpy(p, Con_Handle->PDomain); + p = p + strlen(Con_Handle->PDomain); + *p = 0; + p = p + 1; + + strcpy(p, Con_Handle->OSName); + p = p + strlen(Con_Handle->OSName); + *p = 0; + + } else { + + /* We don't admit to UNICODE support ... */ + + param_len = strlen(UserName) + 1 + pass_len + + strlen(Con_Handle->PDomain) + 1 + + strlen(Con_Handle->OSName) + 1 + + strlen(Con_Handle->LMType) + 1; + + pkt_len = SMB_ssetpNTLM_len + param_len; + + pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { + + SMBlib_errno = SMBlibE_NoSpace; + return (-1); /* Should handle the error */ + + } + bzero(SMB_Hdr(pkt), SMB_ssetpNTLM_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX; + SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle->pid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle->mid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle->uid); + *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 13; + *(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = 0xFF; /* No extra command */ + SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, 0); + + SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mbs_offset, SMBLIB_MAX_XMIT); + SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mmc_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_vcn_offset, 0); + SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_snk_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cipl_offset, pass_len); + SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cspl_offset, 0); + SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_res_offset, 0); + SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cap_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_bcc_offset, param_len); + + /* Now copy the param strings in with the right stuff */ + + p = (char *) (SMB_Hdr(pkt) + SMB_ssetpNTLM_buf_offset); + + /* Copy in password, then the rest. Password has no null at end */ + + memcpy(p, pword, pass_len); + + p = p + pass_len; + + strcpy(p, UserName); + p = p + strlen(UserName); + *p = 0; + + p = p + 1; + + strcpy(p, Con_Handle->PDomain); + p = p + strlen(Con_Handle->PDomain); + *p = 0; + p = p + 1; + + strcpy(p, Con_Handle->OSName); + p = p + strlen(Con_Handle->OSName); + *p = 0; + p = p + 1; + + strcpy(p, Con_Handle->LMType); + p = p + strlen(Con_Handle->LMType); + *p = 0; + + } + + /* Now send it and get a response */ + + if (RFCNB_Send(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error sending SessSetupX request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_SendFailed; + return (SMBlibE_BAD); + + } + /* Now get the response ... */ + + if (RFCNB_Recv(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to SessSetupAndX\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_RecvFailed; + return (SMBlibE_BAD); + + } + /* Check out the response type ... */ + + if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ + +#ifdef DEBUG + fprintf(stderr, "SMB_SessSetupAndX failed with errorclass = %i, Error Code = %i\n", + CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset), + SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset)); +#endif + + SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset); + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_Remote; + return (SMBlibE_BAD); + + } +#ifdef DEBUG + fprintf(stderr, "SessSetupAndX response. Action = %i\n", + SVAL(SMB_Hdr(pkt), SMB_ssetpr_act_offset)); +#endif + + /* Now pick up the UID for future reference ... */ + + Con_Handle->uid = SVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset); + RFCNB_Free_Pkt(pkt); + + return (0); + +} + + +/* Disconnect from the server, and disconnect all tree connects */ + +int +SMB_Discon(SMB_Handle_Type Con_Handle, BOOL KeepHandle) +{ + + /* We just disconnect the connection for now ... */ + + RFCNB_Hangup(Con_Handle->Trans_Connect); + + if (!KeepHandle) + free(Con_Handle); + + return (0); + +} Index: squid/src/auth/basic/helpers/PAM/Makefile.am diff -u /dev/null squid/src/auth/basic/helpers/PAM/Makefile.am:1.2.28.2 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/PAM/Makefile.am Tue Sep 3 10:42:17 2002 @@ -0,0 +1,15 @@ +# +# Makefile for the Squid PAM authentication helper +# +# $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ +# +# Uncomment and customize the following to suit your needs: +# + +INCLUDES = -I. -I$(top_builddir)/include -I$(top_srcdir)/include \ + -I$(top_srcdir)/src/ + +man_MANS = pam_auth.8 +EXTRA_DIST = pam_auth.8 +libexec_PROGRAMS = pam_auth +LDADD = -lpam $(XTRA_LIBS) Index: squid/src/auth/basic/helpers/PAM/pam_auth.8 diff -u /dev/null squid/src/auth/basic/helpers/PAM/pam_auth.8:1.1.6.2 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/PAM/pam_auth.8 Tue Sep 3 10:42:17 2002 @@ -0,0 +1,94 @@ +.TH pam_auth 8 "15 May 2002" "Squid PAM Auth" +. +.SH NAME +pam_auth - Squid PAM authentication helper +. +.SH SYNOPSIS +squid_pam_auth [-n "service name"] [-t TTL] [-o] [-1] +. +.SH DESCRIPTION +This helper allows Squid to connect to a mostly any available PAM +database to validate the user name and password of Basic HTTP +authentication. +. +.TP +.BI "-s " "service-name" +Specifies the PAM service name Squid uses, defaults to "squid" +. +.TP +.BI "-t " TTL +Unless the -1 option is used, this specified for how long +the connection to the PAM database should be kept open and +reused for new logins. Defaults to 60 seconds. +. +.TP +.BI "-o" +Do not perform the PAM account management group (account +expiration etc) + +.TP +.BI "-1" +Specifies "One shot" mode, where a new PAM connection will +be opened for each new user. This is how PAM is normally +used and may be required by some backend databases. +The default is to reuse the PAM connection to maximize +performance. (see -t above) +. +.SH CONFIGURATION +. +The program needs a PAM service to be configured in +.B /etc/pam.conf +or +.B /etc/pam.d/ +.P +The default service name is "squid", and the program makes use +of the +.BR "" ' auth "' and '" account ' +management groups to verify the password and the accounts validity. +.P +For details on how to configure PAM services, see the PAM +documentation for your system. This manual does not cover PAM +configuration details. +. +.SH NOTES +. +When used for authenticating to local UNIX shadow password databases +the program must be running as root or else it won't have sufficient +permissions to access the user password database. Such use of this +program is not recommended, but if you absolutely need to then make +the program setuid root +.RS +.P +.B chown root pam_auth +.br +.B chmod u+s pam_auth +.RE +.P +Please note that in such configurations it is also strongly recommended +that the program is moved into a directory where normal users cannot +access it, as this mode of operation will allow any local user to +brute-force other users passwords. Also note the program has not been +fully audited and the author cannot be held responsible for any security +issues due to such installations. +. +.SH AUTHOR +Squid pam_auth and this manual is written by +.I Henrik Nordstrom +. +.SH COPYRIGHT +Squid pam_auth and this manual is Copyright 1999,2002 +Henrik Nordstrom +. +.SH QUESTIONS +Questions on the usage of this program can be sent to the +.I Squid Users +mailing list. +. +.SH REPORTING BUGS +Report bugs or bug-fixes to +.I Squid Bugs +or ideas for new improvements to +.I Squid Developers +. +.SH "SEE ALSO" +.BR pam (8), " PAM Systems Administrator Guide" Index: squid/src/auth/basic/helpers/SASL/.cvsignore diff -u /dev/null squid/src/auth/basic/helpers/SASL/.cvsignore:1.2.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/SASL/.cvsignore Tue Sep 3 10:42:17 2002 @@ -0,0 +1,2 @@ +.cvsignore +Makefile.in Index: squid/src/auth/basic/helpers/SASL/Makefile.am diff -u /dev/null squid/src/auth/basic/helpers/SASL/Makefile.am:1.3.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/SASL/Makefile.am Tue Sep 3 10:42:18 2002 @@ -0,0 +1,14 @@ +# +# Makefile for the Squid SASL authentication helper +# +# $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ +# +# Uncomment and customize the following to suit your needs: +# + +INCLUDES = -I. -I$(top_builddir)/include -I$(top_srcdir)/include \ + -I$(top_srcdir)/src/ + +libexec_PROGRAMS = sasl_auth +LDADD = -lsasl $(XTRA_LIBS) +EXTRA_DIST = squid_sasl_auth squid_sasl_auth.conf Index: squid/src/auth/basic/helpers/SASL/README diff -u /dev/null squid/src/auth/basic/helpers/SASL/README:1.2.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/SASL/README Tue Sep 3 10:42:18 2002 @@ -0,0 +1,49 @@ +This program authenticates users using SASL (specifically the +cyrus-sasl authentication method). + +SASL is configurable (somewhat like PAM). Each service authenticating +against SASL identifies itself with an application name. Each +"application" can be configured independently by the SASL administrator. + +For this authenticator, the SASL application name is, by default, + + squid_sasl_auth + +To configure the authentication method used the file "squid_sasl_auth.conf" +can be placed in the appropriate location, usually "/usr/lib/sasl". + +The authentication database is defined by the "pwcheck_method" parameter. +Only the "PLAIN" authentication mechanism is used. + +Examples: + +pwcheck_method:sasldb + use sasldb - the default if no conf file is installed. +pwcheck_method:pam + use PAM +pwcheck_method:passwd + use traditional /etc/passwd +pwcheck_method:shadow + use slightly less traditional /etc/shadow + +Others methods may be supported by your cyrus-sasl implementation - +consult your cyrus-sasl documentation for information. + +Typically the authentication database (/etc/sasldb, /etc/shadow, pam) +can not be accessed by a "normal" user. You should use setuid/setgid +and an appropriate user/group on the executable to allow the +authenticator to access the appropriate password database. If the +access to the database is not permitted then the authenticator +will typically fail with "-1, generic error". + + chown root.mail sasl_auth + chmod ug+s sasl_auth + +If the application name ("squid_sasl_auth") will also be used for the +pam service name if pwcheck_method:pam is chosen. And example pam +configuration file "squid_sasl_auth" is also included. + + +Ian Castle +ian.castle@coldcomfortfarm.net +March 2002 Index: squid/src/auth/basic/helpers/SASL/sasl_auth.c diff -u /dev/null squid/src/auth/basic/helpers/SASL/sasl_auth.c:1.3.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/SASL/sasl_auth.c Tue Sep 3 10:42:18 2002 @@ -0,0 +1,103 @@ +/* + * $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ + * + * SASL authenticator module for Squid. + * Copyright (C) 2002 Ian Castle + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + * Install instructions: + * + * This program authenticates users against using cyrus-sasl + * + * Compile this program with: gcc -Wall -o sasl_auth sasl_auth.c -lsasl + * + */ +#include +#include +#include +#include +#include + +#define APP_NAME_SASL "squid_sasl_auth" + +int +main() +{ + char line[8192]; + char *username, *password; + const char *errstr; + + int rc; + sasl_conn_t *conn = NULL; + + /* make standard output line buffered */ + setvbuf(stdout, NULL, _IOLBF, 0); + + rc = sasl_server_init( NULL, APP_NAME_SASL ); + + if ( rc != SASL_OK ) { + fprintf( stderr, "error %d %s\n", rc, sasl_errstring(rc, NULL, NULL )); + fprintf( stdout, "ERR\n" ); + return 1; + } + + rc = sasl_server_new( APP_NAME_SASL, NULL, NULL, NULL, 0, &conn ); + + if ( rc != SASL_OK ) { + fprintf( stderr, "error %d %s\n", rc, sasl_errstring(rc, NULL, NULL )); + fprintf( stdout, "ERR\n" ); + return 1; + } + + while ( fgets( line, sizeof( line ), stdin )) { + username = &line[0]; + password = strchr( line, '\n' ); + if ( !password) { + fprintf( stderr, "authenticator: Unexpected input '%s'\n", line ); + fprintf( stdout, "ERR\n" ); + continue; + } + *password = '\0'; + password = strchr ( line, ' ' ); + if ( !password) { + fprintf( stderr, "authenticator: Unexpected input '%s'\n", line ); + fprintf( stdout, "ERR\n" ); + continue; + } + *password++ = '\0'; + + rc = sasl_checkpass(conn, username, strlen(username), password, strlen(password), &errstr); + + if ( rc != SASL_OK ) { + if ( errstr ) { + fprintf( stderr, "errstr %s\n", errstr ); + } + if ( rc != SASL_BADAUTH ) { + fprintf( stderr, "error %d %s\n", rc, sasl_errstring(rc, NULL, NULL )); + } + fprintf( stdout, "ERR\n" ); + } + else { + fprintf( stdout, "OK\n" ); + } + + } + + sasl_dispose( &conn ); + sasl_done(); + + return 0; +} Index: squid/src/auth/basic/helpers/SASL/squid_sasl_auth diff -u /dev/null squid/src/auth/basic/helpers/SASL/squid_sasl_auth:1.2.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/SASL/squid_sasl_auth Tue Sep 3 10:42:18 2002 @@ -0,0 +1,7 @@ +#%PAM-1.0 +# +# Example PAM service configuration file if using the sasl pam password +# backend (pwcheck_method:pam) +# +auth required /lib/security/pam_pwdb.so shadow nullok +account required /lib/security/pam_pwdb.so Index: squid/src/auth/basic/helpers/SASL/squid_sasl_auth.conf diff -u /dev/null squid/src/auth/basic/helpers/SASL/squid_sasl_auth.conf:1.2.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/SASL/squid_sasl_auth.conf Tue Sep 3 10:42:18 2002 @@ -0,0 +1 @@ +pwcheck_method:sasldb Index: squid/src/auth/basic/helpers/winbind/Makefile.am diff -u /dev/null squid/src/auth/basic/helpers/winbind/Makefile.am:1.5.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/winbind/Makefile.am Tue Sep 3 10:42:22 2002 @@ -0,0 +1,11 @@ +# +# Makefile for the Squid Object Cache server +# +# $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ +# + +libexec_PROGRAMS = wb_auth +wb_auth_SOURCES = wb_basic_auth.c wb_common.c +INCLUDES = -I