浏览代码

support nunc-stans for basic accept and read events

NOTE: shutdown is not working.  You will have to kill -9 ns-slapd
in order to shut it down.
To build:
First, checkout and build liblfds.
Next, checkout and build nunc-stans.
Next, checkout a branch of 389 and apply this patch.
Next, configure ds with the following arguments:
--enable-nunc-stans --with-lfds=/path/to/liblfds --with-nunc-stans=/path/to/nunc-stans
Make and install ds.
Edit the ds etc/sysconfig/dirsrv - add export LD_LIBRARY_PATH=/path/to/liblfds/bin:/path/to/nunc-stans
Run setup-ds
Edit etc/sysconfig/dirsrv-instance - add export LD_LIBRARY_PATH=/path/to/liblfds/bin:/path/to/nunc-stans
might be ~/.dirsrv/dirsrv-instance instead
Rich Megginson 10 年之前
父节点
当前提交
ffb41430eb
共有 13 个文件被更改,包括 853 次插入38 次删除
  1. 7 3
      Makefile.am
  2. 23 10
      Makefile.in
  3. 3 0
      config.h.in
  4. 270 0
      configure
  5. 20 0
      configure.ac
  6. 28 2
      ldap/servers/slapd/connection.c
  7. 15 2
      ldap/servers/slapd/conntable.c
  8. 315 19
      ldap/servers/slapd/daemon.c
  9. 2 1
      ldap/servers/slapd/fe.h
  10. 5 0
      ldap/servers/slapd/proto-slap.h
  11. 9 1
      ldap/servers/slapd/slap.h
  12. 78 0
      m4/lfds.m4
  13. 78 0
      m4/nunc-stans.m4

+ 7 - 3
Makefile.am

@@ -14,7 +14,12 @@ DEBUG_DEFINES = @debug_defs@
 # the -U undefines these symbols - should use the corresponding DS_ ones instead - see configure.ac
 # the -U undefines these symbols - should use the corresponding DS_ ones instead - see configure.ac
 DS_DEFINES = -DBUILD_NUM=$(BUILDNUM) -DVENDOR="\"$(vendor)\"" -DBRAND="\"$(brand)\"" -DCAPBRAND="\"$(capbrand)\"" \
 DS_DEFINES = -DBUILD_NUM=$(BUILDNUM) -DVENDOR="\"$(vendor)\"" -DBRAND="\"$(brand)\"" -DCAPBRAND="\"$(capbrand)\"" \
 	-UPACKAGE_VERSION -UPACKAGE_TARNAME -UPACKAGE_STRING -UPACKAGE_BUGREPORT
 	-UPACKAGE_VERSION -UPACKAGE_TARNAME -UPACKAGE_STRING -UPACKAGE_BUGREPORT
-DS_INCLUDES = -I$(srcdir)/ldap/include -I$(srcdir)/ldap/servers/slapd -I$(srcdir)/include -I.
+if enable_nunc_stans
+NUNC_STANS_INCLUDES = $(nunc_stans_inc) $(lfds_inc)
+NUNC_STANS_LINK = $(nunc_stans_lib) -lnunc-stans $(lfds_lib) -llfds
+endif
+DS_INCLUDES = -I$(srcdir)/ldap/include -I$(srcdir)/ldap/servers/slapd -I$(srcdir)/include -I. $(NUNC_STANS_INCLUDES)
+
 # these paths are dependent on the settings of prefix and exec_prefix which may be specified
 # these paths are dependent on the settings of prefix and exec_prefix which may be specified
 # at make time.  So we cannot use AC_DEFINE in the configure.ac because that would set the
 # at make time.  So we cannot use AC_DEFINE in the configure.ac because that would set the
 # values prior to their being defined.  Defining them here ensures that they are properly
 # values prior to their being defined.  Defining them here ensures that they are properly
@@ -793,8 +798,7 @@ libslapd_la_CPPFLAGS = $(PLUGIN_CPPFLAGS) @sasl_inc@ @db_inc@ @svrcore_inc@ @ker
 if SPARC
 if SPARC
 libslapd_la_SOURCES += ldap/servers/slapd/slapi_counter_sunos_sparcv9.S
 libslapd_la_SOURCES += ldap/servers/slapd/slapi_counter_sunos_sparcv9.S
 endif
 endif
-
-libslapd_la_LIBADD = $(LDAPSDK_LINK) $(SASL_LINK) $(SVRCORE_LINK) $(NSS_LINK) $(NSPR_LINK) $(KERBEROS_LINK) $(PCRE_LINK) $(THREADLIB)
+libslapd_la_LIBADD = $(LDAPSDK_LINK) $(SASL_LINK) $(NUNC_STANS_LINK) $(SVRCORE_LINK) $(NSS_LINK) $(NSPR_LINK) $(KERBEROS_LINK) $(PCRE_LINK) $(THREADLIB)
 
 
 
 
 #////////////////////////////////////////////////////////////////
 #////////////////////////////////////////////////////////////////

+ 23 - 10
Makefile.in

@@ -108,7 +108,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
 	$(top_srcdir)/m4/sasl.m4 $(top_srcdir)/m4/svrcore.m4 \
 	$(top_srcdir)/m4/sasl.m4 $(top_srcdir)/m4/svrcore.m4 \
 	$(top_srcdir)/m4/icu.m4 $(top_srcdir)/m4/netsnmp.m4 \
 	$(top_srcdir)/m4/icu.m4 $(top_srcdir)/m4/netsnmp.m4 \
 	$(top_srcdir)/m4/kerberos.m4 $(top_srcdir)/m4/pcre.m4 \
 	$(top_srcdir)/m4/kerberos.m4 $(top_srcdir)/m4/pcre.m4 \
-	$(top_srcdir)/m4/selinux.m4 $(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/selinux.m4 $(top_srcdir)/m4/lfds.m4 \
+	$(top_srcdir)/m4/nunc-stans.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 	$(ACLOCAL_M4)
 am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
 am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
@@ -705,11 +706,14 @@ libschemareload_plugin_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
 	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
 	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
 	$(AM_CFLAGS) $(CFLAGS) $(libschemareload_plugin_la_LDFLAGS) \
 	$(AM_CFLAGS) $(CFLAGS) $(libschemareload_plugin_la_LDFLAGS) \
 	$(LDFLAGS) -o $@
 	$(LDFLAGS) -o $@
-am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
+@enable_nunc_stans_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) \
+@enable_nunc_stans_TRUE@	$(am__DEPENDENCIES_1)
+am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1)
 libslapd_la_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 libslapd_la_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
-	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \
-	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+	$(am__DEPENDENCIES_3) $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1)
 am__libslapd_la_SOURCES_DIST = ldap/servers/slapd/add.c \
 am__libslapd_la_SOURCES_DIST = ldap/servers/slapd/add.c \
 	ldap/servers/slapd/agtmmap.c ldap/servers/slapd/apibroker.c \
 	ldap/servers/slapd/agtmmap.c ldap/servers/slapd/apibroker.c \
 	ldap/servers/slapd/attr.c ldap/servers/slapd/attrlist.c \
 	ldap/servers/slapd/attr.c ldap/servers/slapd/attrlist.c \
@@ -951,8 +955,8 @@ am_ldap_agent_bin_OBJECTS =  \
 	ldap/servers/snmp/ldap_agent_bin-ldap-agent.$(OBJEXT) \
 	ldap/servers/snmp/ldap_agent_bin-ldap-agent.$(OBJEXT) \
 	ldap/servers/slapd/ldap_agent_bin-agtmmap.$(OBJEXT)
 	ldap/servers/slapd/ldap_agent_bin-agtmmap.$(OBJEXT)
 ldap_agent_bin_OBJECTS = $(am_ldap_agent_bin_OBJECTS)
 ldap_agent_bin_OBJECTS = $(am_ldap_agent_bin_OBJECTS)
-@OPENLDAP_FALSE@am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1)
-ldap_agent_bin_DEPENDENCIES = $(am__DEPENDENCIES_3) \
+@OPENLDAP_FALSE@am__DEPENDENCIES_4 = $(am__DEPENDENCIES_1)
+ldap_agent_bin_DEPENDENCIES = $(am__DEPENDENCIES_4) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
@@ -993,7 +997,7 @@ am_ldif_bin_OBJECTS =  \
 	ldap/servers/slapd/tools/ldif_bin-ldif.$(OBJEXT)
 	ldap/servers/slapd/tools/ldif_bin-ldif.$(OBJEXT)
 ldif_bin_OBJECTS = $(am_ldif_bin_OBJECTS)
 ldif_bin_OBJECTS = $(am_ldif_bin_OBJECTS)
 ldif_bin_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 ldif_bin_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
-	$(am__DEPENDENCIES_3) $(am__DEPENDENCIES_1)
+	$(am__DEPENDENCIES_4) $(am__DEPENDENCIES_1)
 am_makstrdb_OBJECTS = lib/libsi18n/makstrdb-makstrdb.$(OBJEXT)
 am_makstrdb_OBJECTS = lib/libsi18n/makstrdb-makstrdb.$(OBJEXT)
 makstrdb_OBJECTS = $(am_makstrdb_OBJECTS)
 makstrdb_OBJECTS = $(am_makstrdb_OBJECTS)
 makstrdb_LDADD = $(LDADD)
 makstrdb_LDADD = $(LDADD)
@@ -1007,7 +1011,7 @@ am_mmldif_bin_OBJECTS =  \
 mmldif_bin_OBJECTS = $(am_mmldif_bin_OBJECTS)
 mmldif_bin_OBJECTS = $(am_mmldif_bin_OBJECTS)
 mmldif_bin_DEPENDENCIES = libslapd.la $(am__DEPENDENCIES_1) \
 mmldif_bin_DEPENDENCIES = libslapd.la $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
-	$(am__DEPENDENCIES_3) $(am__DEPENDENCIES_1)
+	$(am__DEPENDENCIES_4) $(am__DEPENDENCIES_1)
 am__ns_slapd_SOURCES_DIST = ldap/servers/slapd/abandon.c \
 am__ns_slapd_SOURCES_DIST = ldap/servers/slapd/abandon.c \
 	ldap/servers/slapd/auth.c ldap/servers/slapd/bind.c \
 	ldap/servers/slapd/auth.c ldap/servers/slapd/bind.c \
 	ldap/servers/slapd/compare.c ldap/servers/slapd/config.c \
 	ldap/servers/slapd/compare.c ldap/servers/slapd/config.c \
@@ -1419,6 +1423,9 @@ ldapsdk_lib = @ldapsdk_lib@
 ldapsdk_libdir = @ldapsdk_libdir@
 ldapsdk_libdir = @ldapsdk_libdir@
 ldaptool_bindir = @ldaptool_bindir@
 ldaptool_bindir = @ldaptool_bindir@
 ldaptool_opts = @ldaptool_opts@
 ldaptool_opts = @ldaptool_opts@
+lfds_inc = @lfds_inc@
+lfds_lib = @lfds_lib@
+lfds_libdir = @lfds_libdir@
 libdir = @libdir@
 libdir = @libdir@
 libexecdir = @libexecdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
 localedir = @localedir@
@@ -1437,6 +1444,9 @@ nspr_libdir = @nspr_libdir@
 nss_inc = @nss_inc@
 nss_inc = @nss_inc@
 nss_lib = @nss_lib@
 nss_lib = @nss_lib@
 nss_libdir = @nss_libdir@
 nss_libdir = @nss_libdir@
+nunc_stans_inc = @nunc_stans_inc@
+nunc_stans_lib = @nunc_stans_lib@
+nunc_stans_libdir = @nunc_stans_libdir@
 ol_libver = @ol_libver@
 ol_libver = @ol_libver@
 oldincludedir = @oldincludedir@
 oldincludedir = @oldincludedir@
 openldap_bindir = @openldap_bindir@
 openldap_bindir = @openldap_bindir@
@@ -1502,7 +1512,10 @@ DEBUG_DEFINES = @debug_defs@
 DS_DEFINES = -DBUILD_NUM=$(BUILDNUM) -DVENDOR="\"$(vendor)\"" -DBRAND="\"$(brand)\"" -DCAPBRAND="\"$(capbrand)\"" \
 DS_DEFINES = -DBUILD_NUM=$(BUILDNUM) -DVENDOR="\"$(vendor)\"" -DBRAND="\"$(brand)\"" -DCAPBRAND="\"$(capbrand)\"" \
 	-UPACKAGE_VERSION -UPACKAGE_TARNAME -UPACKAGE_STRING -UPACKAGE_BUGREPORT
 	-UPACKAGE_VERSION -UPACKAGE_TARNAME -UPACKAGE_STRING -UPACKAGE_BUGREPORT
 
 
-DS_INCLUDES = -I$(srcdir)/ldap/include -I$(srcdir)/ldap/servers/slapd -I$(srcdir)/include -I.
+@enable_nunc_stans_TRUE@NUNC_STANS_INCLUDES = $(nunc_stans_inc) $(lfds_inc)
+@enable_nunc_stans_TRUE@NUNC_STANS_LINK = $(nunc_stans_lib) -lnunc-stans $(lfds_lib) -llfds
+DS_INCLUDES = -I$(srcdir)/ldap/include -I$(srcdir)/ldap/servers/slapd -I$(srcdir)/include -I. $(NUNC_STANS_INCLUDES)
+
 # these paths are dependent on the settings of prefix and exec_prefix which may be specified
 # these paths are dependent on the settings of prefix and exec_prefix which may be specified
 # at make time.  So we cannot use AC_DEFINE in the configure.ac because that would set the
 # at make time.  So we cannot use AC_DEFINE in the configure.ac because that would set the
 # values prior to their being defined.  Defining them here ensures that they are properly
 # values prior to their being defined.  Defining them here ensures that they are properly
@@ -2146,7 +2159,7 @@ libslapd_la_SOURCES = ldap/servers/slapd/add.c \
 	ldap/servers/slapd/value.c ldap/servers/slapd/valueset.c \
 	ldap/servers/slapd/value.c ldap/servers/slapd/valueset.c \
 	ldap/servers/slapd/vattr.c $(libavl_a_SOURCES) $(am__append_1)
 	ldap/servers/slapd/vattr.c $(libavl_a_SOURCES) $(am__append_1)
 libslapd_la_CPPFLAGS = $(PLUGIN_CPPFLAGS) @sasl_inc@ @db_inc@ @svrcore_inc@ @kerberos_inc@ @pcre_inc@
 libslapd_la_CPPFLAGS = $(PLUGIN_CPPFLAGS) @sasl_inc@ @db_inc@ @svrcore_inc@ @kerberos_inc@ @pcre_inc@
-libslapd_la_LIBADD = $(LDAPSDK_LINK) $(SASL_LINK) $(SVRCORE_LINK) $(NSS_LINK) $(NSPR_LINK) $(KERBEROS_LINK) $(PCRE_LINK) $(THREADLIB)
+libslapd_la_LIBADD = $(LDAPSDK_LINK) $(SASL_LINK) $(NUNC_STANS_LINK) $(SVRCORE_LINK) $(NSS_LINK) $(NSPR_LINK) $(KERBEROS_LINK) $(PCRE_LINK) $(THREADLIB)
 
 
 #////////////////////////////////////////////////////////////////
 #////////////////////////////////////////////////////////////////
 #
 #

+ 3 - 0
config.h.in

@@ -54,6 +54,9 @@
 /* enable ldapi support in the server */
 /* enable ldapi support in the server */
 #undef ENABLE_LDAPI
 #undef ENABLE_LDAPI
 
 
+/* enable support for nunc-stans event framework */
+#undef ENABLE_NUNC_STANS
+
 /* enable the pam passthru auth plugin */
 /* enable the pam passthru auth plugin */
 #undef ENABLE_PAM_PASSTHRU
 #undef ENABLE_PAM_PASSTHRU
 
 

+ 270 - 0
configure

@@ -640,6 +640,12 @@ vendor
 capbrand
 capbrand
 brand
 brand
 localrundir
 localrundir
+nunc_stans_libdir
+nunc_stans_lib
+nunc_stans_inc
+lfds_libdir
+lfds_lib
+lfds_inc
 pcre_libdir
 pcre_libdir
 pcre_lib
 pcre_lib
 pcre_inc
 pcre_inc
@@ -738,6 +744,8 @@ PKG_CONFIG_PATH
 PKG_CONFIG
 PKG_CONFIG
 with_tmpfiles_d
 with_tmpfiles_d
 with_fhs_opt
 with_fhs_opt
+enable_nunc_stans_FALSE
+enable_nunc_stans_TRUE
 enable_posix_winsync_FALSE
 enable_posix_winsync_FALSE
 enable_posix_winsync_TRUE
 enable_posix_winsync_TRUE
 enable_acctpolicy_FALSE
 enable_acctpolicy_FALSE
@@ -911,6 +919,7 @@ enable_bitwise
 enable_presence
 enable_presence
 enable_acctpolicy
 enable_acctpolicy
 enable_posix_winsync
 enable_posix_winsync
+enable_nunc_stans
 with_fhs
 with_fhs
 with_fhs_opt
 with_fhs_opt
 with_tmpfiles_d
 with_tmpfiles_d
@@ -956,6 +965,12 @@ with_kerberos_inc
 with_kerberos_lib
 with_kerberos_lib
 with_pcre
 with_pcre
 with_selinux
 with_selinux
+with_lfds
+with_lfds_inc
+with_lfds_lib
+with_nunc_stans
+with_nunc_stans_inc
+with_nunc_stans_lib
 '
 '
       ac_precious_vars='build_alias
       ac_precious_vars='build_alias
 host_alias
 host_alias
@@ -1625,6 +1640,8 @@ Optional Features:
   --enable-acctpolicy     enable the account policy plugin (default: yes)
   --enable-acctpolicy     enable the account policy plugin (default: yes)
   --enable-posix-winsync  enable support for POSIX user/group attributes in
   --enable-posix-winsync  enable support for POSIX user/group attributes in
                           winsync (default: yes)
                           winsync (default: yes)
+  --enable-nunc-stans     enable support for nunc-stans event framework
+                          (default: no)
 
 
 Optional Packages:
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -1717,6 +1734,15 @@ Optional Packages:
                           kerberos
                           kerberos
   --with-pcre[=PATH]      Perl Compatible Regular Expression directory
   --with-pcre[=PATH]      Perl Compatible Regular Expression directory
   --with-selinux          Support SELinux policy
   --with-selinux          Support SELinux policy
+  --with-lfds[=PATH]      LFDS directory
+  --with-lfds-inc=PATH    LFDS include file directory
+  --with-lfds-lib=PATH    LFDS library directory
+  --with-nunc-stans[=PATH]
+                          nunc-stans directory
+  --with-nunc-stans-inc=PATH
+                          nunc-stans include file directory
+  --with-nunc-stans-lib=PATH
+                          nunc-stans library directory
 
 
 Some influential environment variables:
 Some influential environment variables:
   CXX         C++ compiler command
   CXX         C++ compiler command
@@ -17887,6 +17913,32 @@ else
 fi
 fi
 
 
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --enable-nunc-stans" >&5
+$as_echo_n "checking for --enable-nunc-stans... " >&6; }
+# Check whether --enable-nunc_stans was given.
+if test "${enable_nunc_stans+set}" = set; then :
+  enableval=$enable_nunc_stans;
+fi
+
+if test "$enable_nunc_stans" = yes ; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define ENABLE_NUNC_STANS 1" >>confdefs.h
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+ if test "$enable_nunc_stans" = "yes"; then
+  enable_nunc_stans_TRUE=
+  enable_nunc_stans_FALSE='#'
+else
+  enable_nunc_stans_TRUE='#'
+  enable_nunc_stans_FALSE=
+fi
+
+
 # the default prefix - override with --prefix or --with-fhs
 # the default prefix - override with --prefix or --with-fhs
 
 
 
 
@@ -21241,6 +21293,214 @@ $as_echo "no" >&6; }
 fi
 fi
 
 
 
 
+# BEGIN COPYRIGHT BLOCK
+# Copyright (C) 2015 Red Hat, Inc.
+# All rights reserved.
+#
+# 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# END COPYRIGHT BLOCK
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for lfds..." >&5
+$as_echo "$as_me: checking for lfds..." >&6;}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-lfds" >&5
+$as_echo_n "checking for --with-lfds... " >&6; }
+
+# Check whether --with-lfds was given.
+if test "${with_lfds+set}" = set; then :
+  withval=$with_lfds;
+  if test "$withval" = "yes"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+  elif test "$withval" = "no"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+  elif test -d "$withval"/inc -a -d "$withval"/bin; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using $withval" >&5
+$as_echo "using $withval" >&6; }
+        lfds_lib="-L$withval/bin"
+    lfds_libdir="$withval/lib"
+    lfds_incdir="$withval/inc"
+    if ! test -e "$lfds_incdir/liblfds.h" ; then
+      as_fn_error $? "$withval include dir not found" "$LINENO" 5
+    fi
+    lfds_inc="-I$lfds_incdir"
+  else
+    echo
+    as_fn_error $? "$withval not found" "$LINENO" 5
+  fi
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+# check for --with-lfds-inc
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-lfds-inc" >&5
+$as_echo_n "checking for --with-lfds-inc... " >&6; }
+
+# Check whether --with-lfds-inc was given.
+if test "${with_lfds_inc+set}" = set; then :
+  withval=$with_lfds_inc;
+  if test -e "$withval"/liblfds.h
+  then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using $withval" >&5
+$as_echo "using $withval" >&6; }
+    lfds_incdir="$withval"
+    lfds_inc="-I$withval"
+  else
+    echo
+    as_fn_error $? "$withval not found" "$LINENO" 5
+  fi
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+# check for --with-lfds-lib
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-lfds-lib" >&5
+$as_echo_n "checking for --with-lfds-lib... " >&6; }
+
+# Check whether --with-lfds-lib was given.
+if test "${with_lfds_lib+set}" = set; then :
+  withval=$with_lfds_lib;
+  if test -d "$withval"
+  then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using $withval" >&5
+$as_echo "using $withval" >&6; }
+    lfds_lib="-L$withval"
+    lfds_libdir="$withval"
+  else
+    echo
+    as_fn_error $? "$withval not found" "$LINENO" 5
+  fi
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+# BEGIN COPYRIGHT BLOCK
+# Copyright (C) 2015 Red Hat, Inc.
+# All rights reserved.
+#
+# 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# END COPYRIGHT BLOCK
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for nunc-stans..." >&5
+$as_echo "$as_me: checking for nunc-stans..." >&6;}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-nunc-stans" >&5
+$as_echo_n "checking for --with-nunc-stans... " >&6; }
+
+# Check whether --with-nunc-stans was given.
+if test "${with_nunc_stans+set}" = set; then :
+  withval=$with_nunc_stans;
+  if test "$withval" = "yes"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+  elif test "$withval" = "no"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+  elif test -d "$withval"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using $withval" >&5
+$as_echo "using $withval" >&6; }
+        nunc_stans_lib="-L$withval"
+    nunc_stans_libdir="$withval"
+    nunc_stans_incdir="$withval"
+    if ! test -e "$nunc_stans_incdir/ns_thrpool.h" ; then
+      as_fn_error $? "$withval include dir not found" "$LINENO" 5
+    fi
+    nunc_stans_inc="-I$nunc_stans_incdir"
+  else
+    echo
+    as_fn_error $? "$withval not found" "$LINENO" 5
+  fi
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+# check for --with-nunc-stans-inc
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-nunc-stans-inc" >&5
+$as_echo_n "checking for --with-nunc-stans-inc... " >&6; }
+
+# Check whether --with-nunc-stans-inc was given.
+if test "${with_nunc_stans_inc+set}" = set; then :
+  withval=$with_nunc_stans_inc;
+  if test -e "$withval"/ns_thrpool.h
+  then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using $withval" >&5
+$as_echo "using $withval" >&6; }
+    nunc_stans_incdir="$withval"
+    nunc_stans_inc="-I$withval"
+  else
+    echo
+    as_fn_error $? "$withval not found" "$LINENO" 5
+  fi
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+# check for --with-nunc-stans-lib
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-nunc-stans-lib" >&5
+$as_echo_n "checking for --with-nunc-stans-lib... " >&6; }
+
+# Check whether --with-nunc-stans-lib was given.
+if test "${with_nunc_stans_lib+set}" = set; then :
+  withval=$with_nunc_stans_lib;
+  if test -d "$withval"
+  then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using $withval" >&5
+$as_echo "using $withval" >&6; }
+    nunc_stans_lib="-L$withval"
+    nunc_stans_libdir="$withval"
+  else
+    echo
+    as_fn_error $? "$withval not found" "$LINENO" 5
+  fi
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
 
 
 PACKAGE_BASE_VERSION=`echo $PACKAGE_VERSION | awk -F\. '{print $1"."$2}'`
 PACKAGE_BASE_VERSION=`echo $PACKAGE_VERSION | awk -F\. '{print $1"."$2}'`
 
 
@@ -21325,6 +21585,12 @@ fi
 
 
 
 
 
 
+
+
+
+
+
+
 
 
 
 
 
 
@@ -21550,6 +21816,10 @@ if test -z "${enable_posix_winsync_TRUE}" && test -z "${enable_posix_winsync_FAL
   as_fn_error $? "conditional \"enable_posix_winsync\" was never defined.
   as_fn_error $? "conditional \"enable_posix_winsync\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
 fi
+if test -z "${enable_nunc_stans_TRUE}" && test -z "${enable_nunc_stans_FALSE}"; then
+  as_fn_error $? "conditional \"enable_nunc_stans\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 if test -z "${WINNT_TRUE}" && test -z "${WINNT_FALSE}"; then
 if test -z "${WINNT_TRUE}" && test -z "${WINNT_FALSE}"; then
   as_fn_error $? "conditional \"WINNT\" was never defined.
   as_fn_error $? "conditional \"WINNT\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 Usually this means the macro was only invoked conditionally." "$LINENO" 5

+ 20 - 0
configure.ac

@@ -226,6 +226,18 @@ else
 fi
 fi
 AM_CONDITIONAL(enable_posix_winsync,test "$enable_posix_winsync" = "yes")
 AM_CONDITIONAL(enable_posix_winsync,test "$enable_posix_winsync" = "yes")
 
 
+AC_MSG_CHECKING(for --enable-nunc-stans)
+AC_ARG_ENABLE(nunc_stans,
+        AS_HELP_STRING([--enable-nunc-stans],
+                       [enable support for nunc-stans event framework (default: no)]))
+if test "$enable_nunc_stans" = yes ; then
+  AC_MSG_RESULT(yes)
+  AC_DEFINE([ENABLE_NUNC_STANS], [1], [enable support for nunc-stans event framework])
+else
+  AC_MSG_RESULT(no)
+fi
+AM_CONDITIONAL(enable_nunc_stans,test "$enable_nunc_stans" = "yes")
+
 # the default prefix - override with --prefix or --with-fhs
 # the default prefix - override with --prefix or --with-fhs
 AC_PREFIX_DEFAULT([/opt/$PACKAGE_NAME])
 AC_PREFIX_DEFAULT([/opt/$PACKAGE_NAME])
 
 
@@ -678,6 +690,8 @@ m4_include(m4/netsnmp.m4)
 m4_include(m4/kerberos.m4)
 m4_include(m4/kerberos.m4)
 m4_include(m4/pcre.m4)
 m4_include(m4/pcre.m4)
 m4_include(m4/selinux.m4)
 m4_include(m4/selinux.m4)
+m4_include(m4/lfds.m4)
+m4_include(m4/nunc-stans.m4)
 
 
 PACKAGE_BASE_VERSION=`echo $PACKAGE_VERSION | awk -F\. '{print $1"."$2}'`
 PACKAGE_BASE_VERSION=`echo $PACKAGE_VERSION | awk -F\. '{print $1"."$2}'`
 AC_SUBST(PACKAGE_BASE_VERSION)
 AC_SUBST(PACKAGE_BASE_VERSION)
@@ -735,6 +749,12 @@ AC_SUBST(netsnmp_link)
 AC_SUBST(pcre_inc)
 AC_SUBST(pcre_inc)
 AC_SUBST(pcre_lib)
 AC_SUBST(pcre_lib)
 AC_SUBST(pcre_libdir)
 AC_SUBST(pcre_libdir)
+AC_SUBST(lfds_inc)
+AC_SUBST(lfds_lib)
+AC_SUBST(lfds_libdir)
+AC_SUBST(nunc_stans_inc)
+AC_SUBST(nunc_stans_lib)
+AC_SUBST(nunc_stans_libdir)
 AC_SUBST(localrundir)
 AC_SUBST(localrundir)
 
 
 AC_SUBST(brand)
 AC_SUBST(brand)

+ 28 - 2
ldap/servers/slapd/connection.c

@@ -199,6 +199,8 @@ connection_done(Connection *conn)
 void
 void
 connection_cleanup(Connection *conn)
 connection_cleanup(Connection *conn)
 {
 {
+	int enable_listeners = 0;
+
 	bind_credentials_clear( conn, PR_FALSE /* do not lock conn */,
 	bind_credentials_clear( conn, PR_FALSE /* do not lock conn */,
 							PR_TRUE /* clear external creds. */ );
 							PR_TRUE /* clear external creds. */ );
 	slapi_ch_free((void**)&conn->c_authtype);
 	slapi_ch_free((void**)&conn->c_authtype);
@@ -232,6 +234,7 @@ connection_cleanup(Connection *conn)
 	if (conn->c_prfd)
 	if (conn->c_prfd)
 	{
 	{
 		PR_Close(conn->c_prfd);
 		PR_Close(conn->c_prfd);
+		enable_listeners = 1; /* re-enable listeners disabled due to no fds */
 	}
 	}
 #endif
 #endif
 
 
@@ -275,6 +278,12 @@ connection_cleanup(Connection *conn)
 
 
 	/* free the connection socket buffer */
 	/* free the connection socket buffer */
 	connection_free_private_buffer(conn);
 	connection_free_private_buffer(conn);
+	if (enable_listeners) {
+		ns_enable_listeners();
+	}
+#ifdef ENABLE_NUNC_STANS
+	conn->c_ns_close_jobs = 0;
+#endif
 }
 }
 
 
 /*
 /*
@@ -741,10 +750,10 @@ int connection_release_nolock (Connection *conn)
 }
 }
 
 
 /* this function should be called under c_mutex */
 /* this function should be called under c_mutex */
-int connection_acquire_nolock (Connection *conn)
+int connection_acquire_nolock_ext (Connection *conn, int allow_when_closing)
 {
 {
     /* connection in the closing state can't be acquired */
     /* connection in the closing state can't be acquired */
-    if (conn->c_flags & CONN_FLAG_CLOSING)
+    if (!allow_when_closing && (conn->c_flags & CONN_FLAG_CLOSING))
     {
     {
 	/* This may happen while other threads are still working on this connection */
 	/* This may happen while other threads are still working on this connection */
         slapi_log_error(SLAPI_LOG_FATAL, "connection",
         slapi_log_error(SLAPI_LOG_FATAL, "connection",
@@ -759,6 +768,10 @@ int connection_acquire_nolock (Connection *conn)
     }
     }
 }
 }
 
 
+int connection_acquire_nolock (Connection *conn) {
+	return connection_acquire_nolock_ext(conn, 0);
+}
+
 /* returns non-0 if connection can be reused and 0 otherwise */
 /* returns non-0 if connection can be reused and 0 otherwise */
 int connection_is_free (Connection *conn)
 int connection_is_free (Connection *conn)
 {
 {
@@ -2169,6 +2182,9 @@ void connection_make_readable(Connection *conn)
 void connection_make_readable_nolock(Connection *conn)
 void connection_make_readable_nolock(Connection *conn)
 {
 {
 	conn->c_gettingber = 0;
 	conn->c_gettingber = 0;
+	LDAPDebug2Args(LDAP_DEBUG_CONNS, "making readable conn %" NSPRIu64 " fd=%d\n",
+		       conn->c_connid, conn->c_sd);
+	ns_connection_post_io_or_closing(conn);
 }
 }
 
 
 /*
 /*
@@ -3000,6 +3016,8 @@ disconnect_server_nomutex( Connection *conn, PRUint64 opconnid, int opid, PRErro
     if ( ( conn->c_sd != SLAPD_INVALID_SOCKET &&
     if ( ( conn->c_sd != SLAPD_INVALID_SOCKET &&
 	    conn->c_connid == opconnid ) && !(conn->c_flags & CONN_FLAG_CLOSING) )
 	    conn->c_connid == opconnid ) && !(conn->c_flags & CONN_FLAG_CLOSING) )
 	{
 	{
+		LDAPDebug(LDAP_DEBUG_CONNS, "setting conn %" NSPRIu64 " fd=%d "
+			  "to be disconnected: reason %d\n", conn->c_connid, conn->c_sd, reason);
 		/*
 		/*
 		 * PR_Close must be called before anything else is done because
 		 * PR_Close must be called before anything else is done because
 		 * of NSPR problem on NT which requires that the socket on which
 		 * of NSPR problem on NT which requires that the socket on which
@@ -3070,6 +3088,14 @@ disconnect_server_nomutex( Connection *conn, PRUint64 opconnid, int opid, PRErro
 				}
 				}
 			}
 			}
 		}
 		}
+		ns_connection_post_io_or_closing(conn); /* make sure event loop wakes up and closes this conn */
+
+    } else {
+	    LDAPDebug2Args(LDAP_DEBUG_CONNS, "not setting conn %d to be disconnected: %s\n",
+			   conn->c_sd,
+			   (conn->c_sd == SLAPD_INVALID_SOCKET) ? "socket is invalid" :
+			    ((conn->c_connid != opconnid) ? "conn id does not match op conn id" :
+			     ((conn->c_flags & CONN_FLAG_CLOSING) ? "conn is closing" : "unknown")));
     }
     }
 }
 }
 
 

+ 15 - 2
ldap/servers/slapd/conntable.c

@@ -211,6 +211,9 @@ connection_table_get_connection(Connection_Table *ct, int sd)
 		 * far then `c' is not being used by any operation threads, etc.
 		 * far then `c' is not being used by any operation threads, etc.
 		 */
 		 */
 		connection_cleanup(c);
 		connection_cleanup(c);
+#ifdef ENABLE_NUNC_STANS
+		c->c_ct = ct; /* pointer to connection table that owns this connection */
+#endif
     }
     }
     else
     else
     {
     {
@@ -289,9 +292,10 @@ connection_table_dump_active_connections (Connection_Table *ct)
  * list. This list is used to find the connections that should be used in the
  * list. This list is used to find the connections that should be used in the
  * poll call. 
  * poll call. 
  */
  */
-void
+int
 connection_table_move_connection_out_of_active_list(Connection_Table *ct,Connection *c)
 connection_table_move_connection_out_of_active_list(Connection_Table *ct,Connection *c)
 {
 {
+    int c_sd; /* for logging */
     /* we always have previous element because list contains a dummy header */;
     /* we always have previous element because list contains a dummy header */;
     PR_ASSERT (c->c_prev);
     PR_ASSERT (c->c_prev);
 
 
@@ -300,11 +304,17 @@ connection_table_move_connection_out_of_active_list(Connection_Table *ct,Connect
     connection_table_dump_active_connection (c);
     connection_table_dump_active_connection (c);
 #endif
 #endif
 
 
+    c_sd = c->c_sd;
     /*
     /*
      * Note: the connection will NOT be moved off the active list if any other threads still hold
      * Note: the connection will NOT be moved off the active list if any other threads still hold
      * a reference to the connection (that is, its reference count must be 1 or less).
      * a reference to the connection (that is, its reference count must be 1 or less).
      */
      */
-    if(c->c_refcnt > 1) return;
+    if(c->c_refcnt > 1) {
+	    LDAPDebug2Args(LDAP_DEBUG_CONNS,
+		           "not moving conn %d out of active list because refcnt is %d\n",
+		           c_sd, c->c_refcnt);
+	    return 1; /* failed */
+    }
 	
 	
     /* We need to lock here because we're modifying the linked list */
     /* We need to lock here because we're modifying the linked list */
     PR_Lock(ct->table_mutex);
     PR_Lock(ct->table_mutex);
@@ -321,10 +331,13 @@ connection_table_move_connection_out_of_active_list(Connection_Table *ct,Connect
     connection_cleanup (c);
     connection_cleanup (c);
 
 
     PR_Unlock(ct->table_mutex);
     PR_Unlock(ct->table_mutex);
+
+    LDAPDebug1Arg(LDAP_DEBUG_CONNS, "moved conn %d out of active list and freed\n", c_sd);
 	
 	
 #ifdef FOR_DEBUGGING
 #ifdef FOR_DEBUGGING
     connection_table_dump_active_connections (ct);
     connection_table_dump_active_connections (ct);
 #endif
 #endif
+    return 0; /* success */
 }
 }
 
 
 /*
 /*

+ 315 - 19
ldap/servers/slapd/daemon.c

@@ -131,10 +131,17 @@ void disk_monitoring_stop();
 #define FDS_SIGNAL_PIPE 0
 #define FDS_SIGNAL_PIPE 0
 
 
 typedef struct listener_info {
 typedef struct listener_info {
+#ifdef ENABLE_NUNC_STANS
+	PRStackElem stackelem; /* must be first in struct for PRStack to work */
+#endif
 	int idx; /* index of this listener in the ct->fd array */
 	int idx; /* index of this listener in the ct->fd array */
 	PRFileDesc *listenfd; /* the listener fd */
 	PRFileDesc *listenfd; /* the listener fd */
 	int secure;
 	int secure;
 	int local;
 	int local;
+#ifdef ENABLE_NUNC_STANS
+	Connection_Table *ct; /* for listen job callback */
+	struct ns_job_t *ns_job; /* the ns accept job */
+#endif
 } listener_info;
 } listener_info;
 
 
 #define SLAPD_POLL_LISTEN_READY(xxflagsxx) (xxflagsxx & PR_POLL_READ)
 #define SLAPD_POLL_LISTEN_READY(xxflagsxx) (xxflagsxx & PR_POLL_READ)
@@ -152,6 +159,9 @@ static PRFileDesc **createprlistensockets(unsigned short port,
 static const char *netaddr2string(const PRNetAddr *addr, char *addrbuf,
 static const char *netaddr2string(const PRNetAddr *addr, char *addrbuf,
 	size_t addrbuflen);
 	size_t addrbuflen);
 static void	set_shutdown (int);
 static void	set_shutdown (int);
+#ifdef ENABLE_NUNC_STANS
+static void	ns_set_shutdown (struct ns_job_t *job);
+#endif
 static void setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix, PRIntn *num_to_read, listener_info *listener_idxs, int max_listeners);
 static void setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix, PRIntn *num_to_read, listener_info *listener_idxs, int max_listeners);
 
 
 #ifdef HPUX10
 #ifdef HPUX10
@@ -376,7 +386,10 @@ static void set_timeval_ms(struct timeval *t, int ms);
 #endif
 #endif
 /* GGOODREPL static void handle_timeout( void ); */
 /* GGOODREPL static void handle_timeout( void ); */
 static void handle_pr_read_ready(Connection_Table *ct, PRIntn num_poll);
 static void handle_pr_read_ready(Connection_Table *ct, PRIntn num_poll);
-static int handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, int secure, int local );
+static int handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, int secure, int local, Connection **newconn );
+#ifdef ENABLE_NUNC_STANS
+static void ns_handle_new_connection(struct ns_job_t *job);
+#endif
 #ifdef _WIN32
 #ifdef _WIN32
 static void unfurl_banners(Connection_Table *ct,daemon_ports_t *ports, int n_tcps, PRFileDesc *s_tcps);
 static void unfurl_banners(Connection_Table *ct,daemon_ports_t *ports, int n_tcps, PRFileDesc *s_tcps);
 #else
 #else
@@ -925,7 +938,7 @@ handle_listeners(Connection_Table *ct, listener_info *listener_idxs, int n_liste
 		if (fdidx && listenfd) {
 		if (fdidx && listenfd) {
 			if (SLAPD_POLL_LISTEN_READY(ct->fd[fdidx].out_flags)) {
 			if (SLAPD_POLL_LISTEN_READY(ct->fd[fdidx].out_flags)) {
 				/* accept() the new connection, put it on the active list for handle_pr_read_ready */
 				/* accept() the new connection, put it on the active list for handle_pr_read_ready */
-				int rc = handle_new_connection(ct, SLAPD_INVALID_SOCKET, listenfd, secure, local);
+				int rc = handle_new_connection(ct, SLAPD_INVALID_SOCKET, listenfd, secure, local, NULL);
 				if (rc) {
 				if (rc) {
 					LDAPDebug1Arg(LDAP_DEBUG_CONNS, "Error accepting new connection listenfd=%d\n",
 					LDAPDebug1Arg(LDAP_DEBUG_CONNS, "Error accepting new connection listenfd=%d\n",
 					              PR_FileDesc2NativeHandle(listenfd));
 					              PR_FileDesc2NativeHandle(listenfd));
@@ -1175,6 +1188,47 @@ done:
     }
     }
 }
 }
 
 
+#ifdef ENABLE_NUNC_STANS
+static ns_job_type_t ns_listen_job_flags = NS_JOB_ACCEPT|NS_JOB_PERSIST|NS_JOB_PRESERVE_FD;
+static PRStack *ns_disabled_listeners; /* holds the disabled listeners, if any */
+static PRInt32 num_disabled_listeners;
+#endif
+
+#ifdef ENABLE_NUNC_STANS
+static void
+ns_disable_listener(listener_info *listener)
+{
+	/* tell the event framework not to listen for new connections on this listener */
+	ns_job_modify(listener->ns_job, NS_JOB_DISABLE_ONLY);
+	/* add the listener to our list of disabled listeners */
+	PR_StackPush(ns_disabled_listeners, (PRStackElem *)listener);
+	PR_AtomicIncrement(&num_disabled_listeners);
+        LDAPDebug2Args(LDAP_DEBUG_ANY, "ns_disable_listener: "
+        	       "disabling listener for fd [%d]: [%d] now disabled\n",
+        	       PR_FileDesc2NativeHandle(listener->listenfd),
+        	       num_disabled_listeners);
+}
+#endif
+
+void
+ns_enable_listeners()
+{
+#ifdef ENABLE_NUNC_STANS
+	int num_enabled = 0;
+	listener_info *listener;
+	while ((listener = (listener_info *)PR_StackPop(ns_disabled_listeners))) {
+		/* there was a disabled listener - re-enable it to listen for new connections */
+		ns_job_modify(listener->ns_job, ns_listen_job_flags);
+		PR_AtomicDecrement(&num_disabled_listeners);
+		num_enabled++;
+	}
+	if (num_enabled) {
+		LDAPDebug1Arg(LDAP_DEBUG_ANY, "ns_enable_listeners: "
+			      "enabled [%d] listeners\n", num_enabled);
+	}
+#endif
+}
+
 void slapd_daemon( daemon_ports_t *ports )
 void slapd_daemon( daemon_ports_t *ports )
 {
 {
 	/* We are passed some ports---one for regular connections, one
 	/* We are passed some ports---one for regular connections, one
@@ -1203,7 +1257,9 @@ void slapd_daemon( daemon_ports_t *ports )
 	int in_referral_mode = config_check_referral_mode();
 	int in_referral_mode = config_check_referral_mode();
 	int n_listeners = 0; /* number of listener sockets */
 	int n_listeners = 0; /* number of listener sockets */
 	listener_info *listener_idxs = NULL; /* array of indexes of listener sockets in the ct->fd array */
 	listener_info *listener_idxs = NULL; /* array of indexes of listener sockets in the ct->fd array */
-
+#ifdef ENABLE_NUNC_STANS
+	ns_thrpool_t *tp;
+#endif
 	int connection_table_size = get_configured_connection_table_size();
 	int connection_table_size = get_configured_connection_table_size();
 	the_connection_table= connection_table_new(connection_table_size);
 	the_connection_table= connection_table_new(connection_table_size);
 
 
@@ -1379,20 +1435,46 @@ void slapd_daemon( daemon_ports_t *ports )
 #endif /* ENABLE_LDAPI */
 #endif /* ENABLE_LDAPI */
 #endif
 #endif
 	listener_idxs = (listener_info *)slapi_ch_calloc(n_listeners, sizeof(*listener_idxs));
 	listener_idxs = (listener_info *)slapi_ch_calloc(n_listeners, sizeof(*listener_idxs));
+#ifdef ENABLE_NUNC_STANS
+	ns_disabled_listeners = PR_CreateStack("disabled_listeners");
+#endif
+	/*
+	 * Convert old DES encoded passwords to AES
+	 */
+	convert_pbe_des_to_aes();
+
+#ifdef ENABLE_NUNC_STANS
+	if (!g_get_shutdown()) {
+		int ii;
+		PRInt32 maxthreads = 3;
+		if (getenv("MAX_THREADS")) {
+			maxthreads = atoi(getenv("MAX_THREADS"));
+		}
+		tp = ns_thrpool_new(maxthreads, maxthreads, 0, 1024);
+		ns_add_signal_job(tp, SIGINT, NS_JOB_SIGNAL, ns_set_shutdown, NULL, NULL);
+		ns_add_signal_job(tp, SIGTERM, NS_JOB_SIGNAL, ns_set_shutdown, NULL, NULL);
+		ns_add_signal_job(tp, SIGHUP, NS_JOB_SIGNAL, ns_set_shutdown, NULL, NULL);
+		setup_pr_read_pds(the_connection_table,n_tcps,s_tcps,i_unix,&num_poll,listener_idxs,n_listeners);
+		for (ii = 0; ii < n_listeners; ++ii) {
+			listener_idxs[ii].ct = the_connection_table; /* to pass to handle_new_connection */
+			ns_add_io_job(tp, listener_idxs[ii].listenfd, ns_listen_job_flags,
+				      ns_handle_new_connection, &listener_idxs[ii], &listener_idxs[ii].ns_job);
+
+		}
+	}
+#endif
 	/* Now we write the pid file, indicating that the server is finally and listening for connections */
 	/* Now we write the pid file, indicating that the server is finally and listening for connections */
 	write_pid_file();
 	write_pid_file();
 
 
 	/* The server is ready and listening for connections. Logging "slapd started" message. */
 	/* The server is ready and listening for connections. Logging "slapd started" message. */
 	unfurl_banners(the_connection_table,ports,n_tcps,s_tcps,i_unix);
 	unfurl_banners(the_connection_table,ports,n_tcps,s_tcps,i_unix);
 
 
-	/*
-	 * Convert old DES encoded passwords to AES
-	 */
-	convert_pbe_des_to_aes();
-
 	/* The meat of the operation is in a loop on a call to select */
 	/* The meat of the operation is in a loop on a call to select */
 	while(!g_get_shutdown())
 	while(!g_get_shutdown())
 	{
 	{
+#ifdef ENABLE_NUNC_STANS
+		DS_Sleep(1);
+#else
 #ifdef _WIN32
 #ifdef _WIN32
 		fd_set			readfds;
 		fd_set			readfds;
 		struct timeval	wakeup_timer;
 		struct timeval	wakeup_timer;
@@ -1420,28 +1502,27 @@ void slapd_daemon( daemon_ports_t *ports )
 		case -1: /* Error */
 		case -1: /* Error */
 #ifdef _WIN32
 #ifdef _WIN32
 			oserr = errno;
 			oserr = errno;
-
 			LDAPDebug( LDAP_DEBUG_TRACE,
 			LDAPDebug( LDAP_DEBUG_TRACE,
-			    "select failed errno %d (%s)\n", oserr,
-			    slapd_system_strerror(oserr), 0 );
+				   "select failed errno %d (%s)\n", oserr,
+				   slapd_system_strerror(oserr), 0 );
 #else
 #else
 			prerr = PR_GetError();
 			prerr = PR_GetError();
 			LDAPDebug( LDAP_DEBUG_TRACE, "PR_Poll() failed, "
 			LDAPDebug( LDAP_DEBUG_TRACE, "PR_Poll() failed, "
-					SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
-					prerr, slapd_system_strerror(prerr), 0 );
+				   SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+				   prerr, slapd_system_strerror(prerr), 0 );
 #endif
 #endif
 			break;
 			break;
 		default: /* either a new connection or some new data ready */
 		default: /* either a new connection or some new data ready */
 			/* Figure out if we are dealing with one of the listen sockets */
 			/* Figure out if we are dealing with one of the listen sockets */
 #ifdef _WIN32
 #ifdef _WIN32
 			/* If so, then handle a new connection */
 			/* If so, then handle a new connection */
-			if ( n_tcps != SLAPD_INVALID_SOCKET && FD_ISSET( n_tcps,&readfds ) ) {
+			if ( n_tcps != SLAPD_INVALID_SOCKET && FD_ISSET( n_tcps, &readfds ) ) {
 				handle_new_connection(the_connection_table,n_tcps,NULL,0,0);
 				handle_new_connection(the_connection_table,n_tcps,NULL,0,0);
-			} 
+			}
 			/* If so, then handle a new connection */
 			/* If so, then handle a new connection */
 			if ( s_tcps != SLAPD_INVALID_SOCKET && FD_ISSET( s_tcps_native,&readfds ) ) {
 			if ( s_tcps != SLAPD_INVALID_SOCKET && FD_ISSET( s_tcps_native,&readfds ) ) {
 				handle_new_connection(the_connection_table,SLAPD_INVALID_SOCKET,s_tcps,1,0);
 				handle_new_connection(the_connection_table,SLAPD_INVALID_SOCKET,s_tcps,1,0);
-			} 
+			}
 			/* handle new data ready */
 			/* handle new data ready */
 			handle_read_ready(the_connection_table,&readfds);
 			handle_read_ready(the_connection_table,&readfds);
 			clear_signal(&readfds);
 			clear_signal(&readfds);
@@ -1454,9 +1535,8 @@ void slapd_daemon( daemon_ports_t *ports )
 #endif
 #endif
 			break;
 			break;
 		}
 		}
-
+#endif
 	}
 	}
-	slapi_ch_free((void **)&listener_idxs);
 	/* We get here when the server is shutting down */
 	/* We get here when the server is shutting down */
 	/* Do what we have to do before death */
 	/* Do what we have to do before death */
 
 
@@ -1474,6 +1554,14 @@ void slapd_daemon( daemon_ports_t *ports )
  		PR_Close( s_tcps );
  		PR_Close( s_tcps );
 	}
 	}
 #else
 #else
+	/* shutdown the listeners - no more client ops */
+#ifdef ENABLE_NUNC_STANS
+	int ii;
+	for (ii = 0; ii < n_listeners; ++ii) {
+		ns_job_done(listener_idxs[ii].ns_job);
+	}
+#endif
+	slapi_ch_free((void **)&listener_idxs);
 	for (fdesp = n_tcps; fdesp && *fdesp; fdesp++) {
 	for (fdesp = n_tcps; fdesp && *fdesp; fdesp++) {
 		PR_Close( *fdesp );
 		PR_Close( *fdesp );
 	}
 	}
@@ -1598,7 +1686,13 @@ void slapd_daemon( daemon_ports_t *ports )
 	 */
 	 */
 	connection_table_free(the_connection_table);
 	connection_table_free(the_connection_table);
 	the_connection_table= NULL;
 	the_connection_table= NULL;
+#ifdef ENABLE_NUNC_STANS
+	if (ns_thrpool_wait(tp)) {
+		/* error */
+	}
 
 
+	ns_thrpool_destroy(tp);
+#endif
 	be_cleanupall ();
 	be_cleanupall ();
 	connection_post_shutdown_cleanup();
 	connection_post_shutdown_cleanup();
 	LDAPDebug( LDAP_DEBUG_TRACE, "slapd shutting down - backends closed down\n",
 	LDAPDebug( LDAP_DEBUG_TRACE, "slapd shutting down - backends closed down\n",
@@ -2248,6 +2342,146 @@ handle_pr_read_ready(Connection_Table *ct, PRIntn num_poll)
 #endif
 #endif
 }
 }
 
 
+#ifdef ENABLE_NUNC_STANS
+/* This function is called when the connection has been marked
+ * as closing and needs to be cleaned up.  It will keep trying
+ * and re-arming itself until there are no references.
+ */
+static void
+ns_handle_closure(struct ns_job_t *job)
+{
+	Connection *c = (Connection *)ns_job_get_data(job);
+	int do_yield = 0;
+
+	/* this function must be called from the event loop thread */
+	PR_ASSERT(0 == NS_JOB_IS_THREAD(ns_job_get_type(job)));
+	PR_Lock(c->c_mutex);
+	c->c_ns_close_jobs--;
+	connection_release_nolock(c); /* release ref acquired when job was added */
+	if (connection_table_move_connection_out_of_active_list(c->c_ct, c)) {
+		do_yield = 1;
+		ns_connection_post_io_or_closing(c);
+	}
+	PR_Unlock(c->c_mutex);
+	ns_job_done(job);
+	if (do_yield) {
+		/* yield thread after unlocking conn mutex */
+		PR_Sleep(PR_INTERVAL_NO_WAIT); /* yield to allow other thread to release conn */
+	}
+	return;
+}
+#endif
+#define CONN_NEEDS_CLOSING(c) (c->c_flags & CONN_FLAG_CLOSING) || (c->c_sd == SLAPD_INVALID_SOCKET)
+
+/**
+ * Schedule more I/O for this connection, or make sure that it
+ * is closed in the event loop.
+ */
+void
+ns_connection_post_io_or_closing(Connection *conn)
+{
+#ifdef ENABLE_NUNC_STANS
+	struct timeval tv;
+	ns_job_func_t job_func;
+
+	if (CONN_NEEDS_CLOSING(conn)) {
+		if (conn->c_ns_close_jobs) {
+			LDAPDebug2Args(LDAP_DEBUG_CONNS, "already a close job in progress on conn %" NSPRIu64 " for fd=%d\n",
+				       conn->c_connid, conn->c_sd);
+			return;
+		} else {
+			/* just make sure the event is processed at the next possible event loop run */
+			tv.tv_sec = 0;
+			tv.tv_usec = 1000;
+			job_func = ns_handle_closure;
+			conn->c_ns_close_jobs++;
+			LDAPDebug2Args(LDAP_DEBUG_CONNS, "post closure job for conn %" NSPRIu64 " for fd=%d\n",
+				       conn->c_connid, conn->c_sd);
+		}
+	} else {
+		/* process event normally - wait for I/O until idletimeout */
+		tv.tv_sec = conn->c_idletimeout;
+		tv.tv_usec = 0;
+		job_func = ns_handle_pr_read_ready;
+		LDAPDebug2Args(LDAP_DEBUG_CONNS, "post I/O job for conn %" NSPRIu64 " for fd=%d\n",
+			       conn->c_connid, conn->c_sd);
+	}
+	connection_acquire_nolock_ext(conn, 1 /* allow acquire even when closing */); /* event framework will have reference */
+	ns_add_io_timeout_job(conn->c_tp, conn->c_prfd, &tv,
+			      NS_JOB_READ|NS_JOB_PRESERVE_FD,
+			      job_func, conn, NULL);
+#endif
+}
+
+#ifdef ENABLE_NUNC_STANS
+/* This function must be called without the thread flag, in the
+ * event loop.  This function may free the connection.  This can
+ * only be done in the event loop thread.
+ */
+void
+ns_handle_pr_read_ready(struct ns_job_t *job)
+{
+	int need_closure = 0;
+	int maxthreads = config_get_maxthreadsperconn();
+	Connection *c = (Connection *)ns_job_get_data(job);
+
+	/* this function must be called from the event loop thread */
+	PR_ASSERT(0 == NS_JOB_IS_THREAD(ns_job_get_type(job)));
+
+	PR_Lock(c->c_mutex);
+	LDAPDebug2Args(LDAP_DEBUG_CONNS, "activity on conn %" NSPRIu64 " for fd=%d\n",
+		       c->c_connid, c->c_sd);
+	/* if we were called due to some i/o event, see what the state of the socket is */
+	if (slapi_is_loglevel_set(SLAPI_LOG_CONNS) && !NS_JOB_IS_TIMER(ns_job_get_output_type(job)) && c && c->c_sd) {
+		/* see if socket is closed */
+		char buf[1];
+		ssize_t rc = recv(c->c_sd, buf, sizeof(buf), MSG_PEEK);
+		if (!rc) {
+			LDAPDebug2Args(LDAP_DEBUG_CONNS, "socket is closed conn %" NSPRIu64 " for fd=%d\n",
+				       c->c_connid, c->c_sd);
+		} else if (rc > 0) {
+			LDAPDebug2Args(LDAP_DEBUG_CONNS, "socket has data available for conn %" NSPRIu64 " for fd=%d\n",
+				       c->c_connid, c->c_sd);
+		} else if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
+			LDAPDebug2Args(LDAP_DEBUG_CONNS, "socket has no data available conn %" NSPRIu64 " for fd=%d\n",
+				       c->c_connid, c->c_sd);
+		} else {
+			LDAPDebug(LDAP_DEBUG_CONNS, "socket has error [%d] conn %" NSPRIu64 " for fd=%d\n",
+				  errno, c->c_connid, c->c_sd);
+		}
+	}
+	connection_release_nolock(c); /* release ref acquired when job was added */
+	if (CONN_NEEDS_CLOSING(c)) {
+		need_closure = 1;
+	} else if (NS_JOB_IS_TIMER(ns_job_get_output_type(job))) {
+		/* idle timeout */
+		disconnect_server_nomutex(c, c->c_connid, -1,
+				          SLAPD_DISCONNECT_IDLE_TIMEOUT, EAGAIN);
+		need_closure = 1;
+	} else if ((connection_activity(c, maxthreads)) == -1) {
+		/* This might happen as a result of
+		 * trying to acquire a closing connection
+		 */
+		LDAPDebug2Args(LDAP_DEBUG_ANY, "connection_activity: abandoning conn %" NSPRIu64
+			       " as fd=%d is already closing\n", c->c_connid, c->c_sd);
+		/* The call disconnect_server should do nothing,
+		 * as the connection c should be already set to CLOSING */
+		disconnect_server_nomutex(c, c->c_connid, -1,
+				          SLAPD_DISCONNECT_POLL, EPIPE);
+		need_closure = 1;
+	} else {
+		LDAPDebug2Args(LDAP_DEBUG_CONNS, "queued conn %" NSPRIu64 " for fd=%d\n",
+			       c->c_connid, c->c_sd);
+	}
+	if (need_closure) {
+		ns_connection_post_io_or_closing(c);
+	}
+	PR_Unlock(c->c_mutex);
+	ns_job_done(job);
+	return;
+}
+#endif
+
 /*
 /*
  * wrapper functions required so we can implement ioblock_timeout and
  * wrapper functions required so we can implement ioblock_timeout and
  * avoid blocking forever.
  * avoid blocking forever.
@@ -2796,7 +3030,7 @@ handle_closed_connection(Connection *conn)
 
 
 /* NOTE: this routine is not reentrant */
 /* NOTE: this routine is not reentrant */
 static int
 static int
-handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, int secure, int local)
+handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, int secure, int local, Connection **newconn)
 {
 {
 	int ns = 0;
 	int ns = 0;
 	Connection *conn = NULL;
 	Connection *conn = NULL;
@@ -2806,6 +3040,9 @@ handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, i
 	ber_len_t maxbersize;
 	ber_len_t maxbersize;
 	slapdFrontendConfig_t *fecfg = getFrontendConfig();
 	slapdFrontendConfig_t *fecfg = getFrontendConfig();
 
 
+	if (newconn) {
+		*newconn = NULL;
+	}
 	memset(&from, 0, sizeof(from)); /* reset to nulls so we can see what was set */
 	memset(&from, 0, sizeof(from)); /* reset to nulls so we can see what was set */
 	if ( (ns = accept_and_configure( tcps, pr_acceptfd, &from,
 	if ( (ns = accept_and_configure( tcps, pr_acceptfd, &from,
 		sizeof(from), secure, local, &pr_clonefd)) == SLAPD_INVALID_SOCKET ) {
 		sizeof(from), secure, local, &pr_clonefd)) == SLAPD_INVALID_SOCKET ) {
@@ -2936,9 +3173,57 @@ handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, i
 
 
 	g_increment_current_conn_count();
 	g_increment_current_conn_count();
 
 
+	if (newconn) {
+		*newconn = conn;
+	}
 	return 0;
 	return 0;
 }
 }
 
 
+#ifdef ENABLE_NUNC_STANS
+static void
+ns_handle_new_connection(struct ns_job_t *job)
+{
+	int rc;
+	Connection *c = NULL;
+	listener_info *li = (listener_info *)ns_job_get_data(job);
+
+	/* only accept new connections if we have enough fds, more than
+	 * the number of reserved descriptors
+	 */
+	if ((li->ct->size - g_get_current_conn_count())
+	     <= config_get_reservedescriptors()) {
+		/* too many open fds - shut off this listener - when an fd is
+		 * closed, try to resume this listener
+		 */
+		ns_disable_listener(li);
+		return;
+	}
+
+	rc = handle_new_connection(li->ct, SLAPD_INVALID_SOCKET, li->listenfd, li->secure, li->local, &c);
+	if (rc) {
+		PRErrorCode prerr = PR_GetError();
+		if (PR_PROC_DESC_TABLE_FULL_ERROR == prerr) {
+			/* too many open fds - shut off this listener - when an fd is
+			 * closed, try to resume this listener
+			 */
+			ns_disable_listener(li);
+		} else {
+			LDAPDebug(LDAP_DEBUG_CONNS, "Error accepting new connection listenfd=%d [%d:%s]\n",
+				  PR_FileDesc2NativeHandle(li->listenfd), prerr,
+				  slapd_pr_strerror(prerr));
+		}
+		return;
+	}
+	/* now, set up the conn for reading - no thread - ns_handle_pr_read_ready
+	 * must be run in the event loop thread
+	 */
+	c->c_tp = ns_job_get_tp(job);
+	connection_acquire_nolock(c); /* event framework now has ref */
+	ns_add_job(ns_job_get_tp(job), NULL, NS_JOB_NONE, ns_handle_pr_read_ready, c);
+	return;
+}
+#endif
+
 static int init_shutdown_detect()
 static int init_shutdown_detect()
 {
 {
 
 
@@ -3003,8 +3288,10 @@ static int init_shutdown_detect()
 	(void) SIGNAL( SIGUSR1, slapd_do_nothing );
 	(void) SIGNAL( SIGUSR1, slapd_do_nothing );
 	(void) SIGNAL( SIGUSR2, set_shutdown );
 	(void) SIGNAL( SIGUSR2, set_shutdown );
 #endif
 #endif
+#ifndef ENABLE_NUNC_STANS
 	(void) SIGNAL( SIGTERM, set_shutdown );
 	(void) SIGNAL( SIGTERM, set_shutdown );
 	(void) SIGNAL( SIGHUP,  set_shutdown );
 	(void) SIGNAL( SIGHUP,  set_shutdown );
+#endif
 #endif /* _WIN32 */
 #endif /* _WIN32 */
 	return 0;
 	return 0;
 }
 }
@@ -3193,6 +3480,15 @@ set_shutdown (int sig)
 #endif
 #endif
 }
 }
 
 
+#ifdef ENABLE_NUNC_STANS
+static void
+ns_set_shutdown(struct ns_job_t *job)
+{
+	set_shutdown(0);
+	ns_thrpool_shutdown(ns_job_get_tp(job));
+}
+#endif
+
 #ifndef LINUX
 #ifndef LINUX
 void
 void
 slapd_do_nothing (int sig)
 slapd_do_nothing (int sig)

+ 2 - 1
ldap/servers/slapd/fe.h

@@ -158,7 +158,7 @@ Connection_Table *connection_table_new(int table_size);
 void connection_table_free(Connection_Table *ct);
 void connection_table_free(Connection_Table *ct);
 void connection_table_abandon_all_operations(Connection_Table *ct);
 void connection_table_abandon_all_operations(Connection_Table *ct);
 Connection *connection_table_get_connection(Connection_Table *ct, int sd);
 Connection *connection_table_get_connection(Connection_Table *ct, int sd);
-void connection_table_move_connection_out_of_active_list(Connection_Table *ct, Connection *c);
+int connection_table_move_connection_out_of_active_list(Connection_Table *ct, Connection *c);
 void connection_table_move_connection_on_to_active_list(Connection_Table *ct, Connection *c);
 void connection_table_move_connection_on_to_active_list(Connection_Table *ct, Connection *c);
 void connection_table_as_entry(Connection_Table *ct, Slapi_Entry *e);
 void connection_table_as_entry(Connection_Table *ct, Slapi_Entry *e);
 void connection_table_dump_activity_to_errors_log(Connection_Table *ct);
 void connection_table_dump_activity_to_errors_log(Connection_Table *ct);
@@ -185,6 +185,7 @@ int daemon_register_reslimits( void );
 PRFileDesc * get_ssl_listener_fd();
 PRFileDesc * get_ssl_listener_fd();
 int configure_pr_socket( PRFileDesc **pr_socket, int secure, int local );
 int configure_pr_socket( PRFileDesc **pr_socket, int secure, int local );
 void configure_ns_socket( int * ns );
 void configure_ns_socket( int * ns );
+void ns_enable_listeners();
 
 
 /*
 /*
  * sasl_io.c
  * sasl_io.c

+ 5 - 0
ldap/servers/slapd/proto-slap.h

@@ -1421,6 +1421,7 @@ int mapping_tree_get_extension_type ();
  * connection.c
  * connection.c
  */
  */
 int connection_acquire_nolock (Connection *conn);
 int connection_acquire_nolock (Connection *conn);
+int connection_acquire_nolock_ext (Connection *conn, int allow_when_closing);
 int connection_release_nolock (Connection *conn);
 int connection_release_nolock (Connection *conn);
 int connection_is_free (Connection *conn);
 int connection_is_free (Connection *conn);
 int connection_is_active_nolock (Connection *conn);
 int connection_is_active_nolock (Connection *conn);
@@ -1462,6 +1463,10 @@ void slapd_wait4child (int);
 #else
 #else
 void *slapd_service_exit_wait();
 void *slapd_service_exit_wait();
 #endif
 #endif
+#ifdef ENABLE_NUNC_STANS
+void ns_handle_pr_read_ready(struct ns_job_t *job);
+#endif
+void ns_connection_post_io_or_closing(Connection *conn);
 
 
 /*
 /*
  * main.c
  * main.c

+ 9 - 1
ldap/servers/slapd/slap.h

@@ -172,6 +172,10 @@ typedef struct symbol_t {
 #include "csngen.h"
 #include "csngen.h"
 #include "uuid.h"
 #include "uuid.h"
 
 
+#ifdef ENABLE_NUNC_STANS
+#include <ns_thrpool.h>
+#endif
+
 #if defined(OS_solaris)
 #if defined(OS_solaris)
 #  include <thread.h>
 #  include <thread.h>
 #  define GET_THREAD_ID() thr_self()
 #  define GET_THREAD_ID() thr_self()
@@ -1503,7 +1507,11 @@ typedef struct conn {
     Conn_IO_Layer_cb c_push_io_layer_cb; /* callback to push an IO layer on the conn->c_prfd */
     Conn_IO_Layer_cb c_push_io_layer_cb; /* callback to push an IO layer on the conn->c_prfd */
     Conn_IO_Layer_cb c_pop_io_layer_cb; /* callback to pop an IO layer off of the conn->c_prfd */
     Conn_IO_Layer_cb c_pop_io_layer_cb; /* callback to pop an IO layer off of the conn->c_prfd */
     void             *c_io_layer_cb_data; /* callback data */
     void             *c_io_layer_cb_data; /* callback data */
-
+#ifdef ENABLE_NUNC_STANS
+    struct connection_table     *c_ct; /* connection table that this connection belongs to */
+    ns_thrpool_t                *c_tp; /* thread pool for this connection */
+    int                         c_ns_close_jobs; /* number of current close jobs */
+#endif
 } Connection;
 } Connection;
 #define CONN_FLAG_SSL	1	/* Is this connection an SSL connection or not ? 
 #define CONN_FLAG_SSL	1	/* Is this connection an SSL connection or not ? 
 							 * Used to direct I/O code when SSL is handled differently 
 							 * Used to direct I/O code when SSL is handled differently 

+ 78 - 0
m4/lfds.m4

@@ -0,0 +1,78 @@
+# BEGIN COPYRIGHT BLOCK
+# Copyright (C) 2015 Red Hat, Inc.
+# All rights reserved.
+#
+# 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# END COPYRIGHT BLOCK
+
+AC_CHECKING(for lfds)
+
+dnl  - check for --with-lfds
+AC_MSG_CHECKING(for --with-lfds)
+AC_ARG_WITH(lfds, AS_HELP_STRING([--with-lfds@<:@=PATH@:>@],[LFDS directory]),
+[
+  if test "$withval" = "yes"; then
+    AC_MSG_RESULT(yes)
+  elif test "$withval" = "no"; then
+    AC_MSG_RESULT(no)
+  elif test -d "$withval"/inc -a -d "$withval"/bin; then
+    AC_MSG_RESULT([using $withval])
+    dnl - check the user provided location
+    lfds_lib="-L$withval/bin"
+    lfds_libdir="$withval/lib"
+    lfds_incdir="$withval/inc"
+    if ! test -e "$lfds_incdir/liblfds.h" ; then
+      AC_MSG_ERROR([$withval include dir not found])
+    fi
+    lfds_inc="-I$lfds_incdir"
+  else
+    echo
+    AC_MSG_ERROR([$withval not found])
+  fi
+],
+AC_MSG_RESULT(no))
+
+# check for --with-lfds-inc
+AC_MSG_CHECKING(for --with-lfds-inc)
+AC_ARG_WITH(lfds-inc, AS_HELP_STRING([--with-lfds-inc=PATH],[LFDS include file directory]),
+[
+  if test -e "$withval"/liblfds.h
+  then
+    AC_MSG_RESULT([using $withval])
+    lfds_incdir="$withval"
+    lfds_inc="-I$withval"
+  else
+    echo
+    AC_MSG_ERROR([$withval not found])
+  fi
+],
+AC_MSG_RESULT(no))
+
+# check for --with-lfds-lib
+AC_MSG_CHECKING(for --with-lfds-lib)
+AC_ARG_WITH(lfds-lib, AS_HELP_STRING([--with-lfds-lib=PATH],[LFDS library directory]),
+[
+  if test -d "$withval"
+  then
+    AC_MSG_RESULT([using $withval])
+    lfds_lib="-L$withval"
+    lfds_libdir="$withval"
+  else
+    echo
+    AC_MSG_ERROR([$withval not found])
+  fi
+],
+AC_MSG_RESULT(no))

+ 78 - 0
m4/nunc-stans.m4

@@ -0,0 +1,78 @@
+# BEGIN COPYRIGHT BLOCK
+# Copyright (C) 2015 Red Hat, Inc.
+# All rights reserved.
+#
+# 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# END COPYRIGHT BLOCK
+
+AC_CHECKING(for nunc-stans)
+
+dnl  - check for --with-nunc-stans
+AC_MSG_CHECKING(for --with-nunc-stans)
+AC_ARG_WITH(nunc-stans, AS_HELP_STRING([--with-nunc-stans@<:@=PATH@:>@],[nunc-stans directory]),
+[
+  if test "$withval" = "yes"; then
+    AC_MSG_RESULT(yes)
+  elif test "$withval" = "no"; then
+    AC_MSG_RESULT(no)
+  elif test -d "$withval"; then
+    AC_MSG_RESULT([using $withval])
+    dnl - check the user provided location
+    nunc_stans_lib="-L$withval"
+    nunc_stans_libdir="$withval"
+    nunc_stans_incdir="$withval"
+    if ! test -e "$nunc_stans_incdir/ns_thrpool.h" ; then
+      AC_MSG_ERROR([$withval include dir not found])
+    fi
+    nunc_stans_inc="-I$nunc_stans_incdir"
+  else
+    echo
+    AC_MSG_ERROR([$withval not found])
+  fi
+],
+AC_MSG_RESULT(no))
+
+# check for --with-nunc-stans-inc
+AC_MSG_CHECKING(for --with-nunc-stans-inc)
+AC_ARG_WITH(nunc-stans-inc, AS_HELP_STRING([--with-nunc-stans-inc=PATH],[nunc-stans include file directory]),
+[
+  if test -e "$withval"/ns_thrpool.h
+  then
+    AC_MSG_RESULT([using $withval])
+    nunc_stans_incdir="$withval"
+    nunc_stans_inc="-I$withval"
+  else
+    echo
+    AC_MSG_ERROR([$withval not found])
+  fi
+],
+AC_MSG_RESULT(no))
+
+# check for --with-nunc-stans-lib
+AC_MSG_CHECKING(for --with-nunc-stans-lib)
+AC_ARG_WITH(nunc-stans-lib, AS_HELP_STRING([--with-nunc-stans-lib=PATH],[nunc-stans library directory]),
+[
+  if test -d "$withval"
+  then
+    AC_MSG_RESULT([using $withval])
+    nunc_stans_lib="-L$withval"
+    nunc_stans_libdir="$withval"
+  else
+    echo
+    AC_MSG_ERROR([$withval not found])
+  fi
+],
+AC_MSG_RESULT(no))