389-ds-base/SOURCES/0003-Issue-5924-ASAN-server...

627 lines
25 KiB
Diff

From 26716f0edefe4690d9fd9143d07156e01321020c Mon Sep 17 00:00:00 2001
From: progier389 <progier@redhat.com>
Date: Thu, 28 Sep 2023 12:15:25 +0200
Subject: [PATCH] issue 5924 - ASAN server build crash when looping
opening/closing connections (#5926)
* issue 5924 - ASAN server build crash when looping opening/closing connections
Issue: Got a crash due to:
1. Failure to get a connection slot because connection freelist is misshandled.
2. A confusion between listening and acceptedfd descriptor leaded to
close the listening descriptor while handing the error.
Solution:
Rename clearly the file descriptor variables
Close the accepted file descriptor in error handler
Rewrite the freelist management so that first connection chosen is the last released one.
(Code is simpler, this fix the end of list issue, and it avoid to spread the open connection over too much memory)
Issue: #5924
Reviewed by: @Firstyear, @vashirov, @droideck (Thanks !)
(cherry picked from commit 02d333251419ff3c4d0384595e9fe7ded5bcd8fc)
---
dirsrvtests/tests/suites/basic/basic_test.py | 287 +++++++++++++++++++
ldap/servers/slapd/conntable.c | 100 +++----
ldap/servers/slapd/daemon.c | 35 ++-
ldap/servers/slapd/fe.h | 1 -
4 files changed, 351 insertions(+), 72 deletions(-)
diff --git a/dirsrvtests/tests/suites/basic/basic_test.py b/dirsrvtests/tests/suites/basic/basic_test.py
index fac0f7371e..f4525e1848 100644
--- a/dirsrvtests/tests/suites/basic/basic_test.py
+++ b/dirsrvtests/tests/suites/basic/basic_test.py
@@ -28,7 +28,15 @@
from lib389.backend import Backends
from lib389.idm.domain import Domain
from lib389.nss_ssl import NssSsl
+from lib389._constants import *
+from lib389 import DirSrv
+from lib389.instance.setup import SetupDs
+from lib389.instance.options import General2Base, Slapd2Base
import os
+import random
+import ldap
+import time
+import subprocess
pytestmark = pytest.mark.tier0
@@ -36,6 +44,7 @@
default_paths = Paths()
log = logging.getLogger(__name__)
+DEBUGGING = os.getenv("DEBUGGING", default=False)
# Globals
USER1_DN = 'uid=user1,' + DEFAULT_SUFFIX
@@ -51,6 +60,190 @@
'vendorName',
'vendorVersion')
+# This MAX_FDS value left about 22 connections available with bdb
+# (should have more connections with lmdb)
+MAX_FDS = 150
+
+
+
+default_paths = Paths()
+
+
+
+log = logging.getLogger(__name__)
+DEBUGGING = os.getenv("DEBUGGING", default=False)
+
+
+class CustomSetup():
+ DEFAULT_GENERAL = { 'config_version': 2,
+ 'full_machine_name': 'localhost.localdomain',
+ 'strict_host_checking': False,
+ # Not setting 'systemd' because it is not used.
+ # (that is the global default.inf setting that matters)
+ }
+ DEFAULT_SLAPD = { 'root_password': PW_DM,
+ 'defaults': INSTALL_LATEST_CONFIG,
+ }
+ DEFAULT_BACKENDS = [ {
+ 'cn': 'userroot',
+ 'nsslapd-suffix': DEFAULT_SUFFIX,
+ 'sample_entries': 'yes',
+ BACKEND_SAMPLE_ENTRIES: INSTALL_LATEST_CONFIG,
+ }, ]
+
+ WRAPPER_FORMAT = '''#!/bin/sh
+{wrapper_options}
+exec {nsslapd} -D {cfgdir} -i {pidfile}
+'''
+
+
+ class CustomDirSrv(DirSrv):
+ def __init__(self, verbose=False, external_log=log):
+ super().__init__(verbose=verbose, external_log=external_log)
+ self.wrapper = None # placeholder for the wrapper file name
+
+ def _reset_systemd(self):
+ self.systemd_override = False
+
+ def status(self):
+ self._reset_systemd()
+ return super().status()
+
+ def start(self, timeout=120, *args):
+ if self.status():
+ return
+ tmp_env = os.environ
+ # Unset PYTHONPATH to avoid mixing old CLI tools and new lib389
+ if "PYTHONPATH" in tmp_env:
+ del tmp_env["PYTHONPATH"]
+ try:
+ subprocess.check_call([
+ '/usr/bin/sh',
+ self.wrapper
+ ], env=tmp_env, stderr=subprocess.STDOUT)
+ except subprocess.CalledProcessError as e:
+ log.fatal("%s failed! Error (%s) %s" % (self.wrapper, e.returncode, e.output))
+ raise e from None
+ for count in range(timeout):
+ if self.status():
+ return
+ time.sleep(1)
+ raise TimeoutException('Failed to start ns-slpad')
+
+ def stop(self, timeout=120):
+ self._reset_systemd()
+ super().stop(timeout=timeout)
+
+
+ def _search_be(belist, beinfo):
+ for be in belist:
+ if be['cn'] == beinfo['cn']:
+ return be
+ return None
+
+ def __init__(self, serverid, general=None, slapd=None, backends=None, log=log):
+ verbose = log.level > logging.DEBUG
+ self.log = log
+ self.serverid = serverid
+ self.verbose = verbose
+ self.wrapper = f'/tmp/ds_{serverid}_wrapper.sh'
+ if serverid.startswith('slapd-'):
+ self.instname = server.id
+ else:
+ self.instname = 'slapd-'+serverid
+ self.ldapi = None
+ self.pid_file = None
+ self.inst = None
+
+ # Lets prepare the options
+ general_options = General2Base(log)
+ for d in (CustomSetup.DEFAULT_GENERAL, general):
+ if d:
+ for key,val in d.items():
+ general_options.set(key,val)
+ log.debug('[general]: %s' % general_options._options)
+ self.general = general_options
+
+ slapd_options = Slapd2Base(self.log)
+ slapd_options.set('instance_name', serverid)
+ for d in (CustomSetup.DEFAULT_SLAPD, slapd):
+ if d:
+ for key,val in d.items():
+ slapd_options.set(key,val)
+ log.debug('[slapd]: %s' % slapd_options._options)
+ self.slapd = slapd_options
+
+ backend_options = []
+ for backend_list in (CustomSetup.DEFAULT_BACKENDS, backends):
+ if not backend_list:
+ continue
+ for backend in backend_list:
+ target_be = CustomSetup._search_be(backend_options, backend)
+ if not target_be:
+ target_be = {}
+ backend_options.append(target_be)
+ for key,val in backend.items():
+ target_be[key] = val
+ log.debug('[backends]: %s' % backend_options)
+ self.backends = backend_options
+
+ def _to_dirsrv_args(self):
+ args = {}
+ slapd = self.slapd.collect()
+ general = self.general.collect()
+ args["SER_HOST"] = general['full_machine_name']
+ args["SER_PORT"] = slapd['port']
+ args["SER_SECURE_PORT"] = slapd['secure_port']
+ args["SER_SERVERID_PROP"] = self.serverid
+ return args
+
+ def create_instance(self):
+ sds = SetupDs(verbose=self.verbose, dryrun=False, log=self.log)
+ self.general.verify()
+ general = self.general.collect()
+ self.slapd.verify()
+ slapd = self.slapd.collect()
+ sds.create_from_args(general, slapd, self.backends, None)
+ self.ldapi = get_ldapurl_from_serverid(self.serverid)[0]
+ args = self._to_dirsrv_args()
+ log.debug('DirSrv.allocate args = %s' % str(args))
+ log.debug('ldapi = %s' % str(self.ldapi))
+ root_dn = slapd['root_dn']
+ root_password = slapd['root_password']
+ inst = DirSrv(verbose=self.verbose, external_log=self.log)
+ inst.local_simple_allocate(self.serverid, ldapuri=self.ldapi, binddn=root_dn, password=root_password)
+ self.pid_file = inst.pid_file()
+ # inst.setup_ldapi()
+ log.debug('DirSrv = %s' % str(inst.__dict__))
+ inst.open()
+ inst.stop()
+ inst = CustomSetup.CustomDirSrv(verbose=self.verbose, external_log=self.log)
+ inst.local_simple_allocate(self.serverid, ldapuri=self.ldapi, binddn=root_dn, password=root_password)
+ self.inst = inst
+ return inst
+
+ def create_wrapper(self, maxfds=None):
+ self.inst.wrapper = self.wrapper
+ slapd = self.slapd.collect()
+ sbin_dir = slapd['sbin_dir']
+ config_dir = slapd['config_dir']
+ fmtvalues = {
+ 'nsslapd': f'{sbin_dir}/ns-slapd',
+ 'cfgdir': config_dir.format(instance_name=self.instname),
+ 'pidfile': self.pid_file,
+ 'wrapper_options': ''
+ }
+ if maxfds:
+ fmtvalues['wrapper_options']=f'ulimit -n {maxfds}\nulimit -H -n {maxfds}'
+ with open(self.wrapper, 'w') as f:
+ f.write(CustomSetup.WRAPPER_FORMAT.format(**fmtvalues))
+
+ def cleanup(self):
+ self.inst.stop()
+ self.inst.delete()
+ if os.path.exists(self.wrapper):
+ os.remove(self.wrapper)
+
@pytest.fixture(scope="function")
def _reset_attr(request, topology_st):
@@ -2222,6 +2415,100 @@ def test_dscreate_with_different_rdn(dscreate_test_rdn_value):
assert True
+@pytest.fixture(scope="module")
+def dscreate_custom_instance(request):
+ topo = CustomSetup('custom')
+
+ def fin():
+ topo.cleanup()
+
+ request.addfinalizer(fin)
+ topo.create_instance()
+ # Return CustomSetup object associated with
+ # a stopped instance named "custom"
+ return topo
+
+ obj.create_wrapper(maxfds=150)
+ log.info("Starting wrapper")
+ inst.start()
+ log.info("Server is started.")
+ log.info("Open connection")
+ inst.open()
+
+
+@pytest.fixture(scope="module", params=set(range(1,5)))
+def dscreate_with_numlistener(request, dscreate_custom_instance):
+ numlisteners = request.param
+ dscreate_custom_instance.create_wrapper(maxfds=MAX_FDS)
+ inst = dscreate_custom_instance.inst
+ inst.stop()
+ dse_ldif = DSEldif(inst)
+ dse_ldif.replace('cn=config', 'nsslapd-numlisteners', str(numlisteners))
+ inst.start()
+ inst.open()
+ return inst
+
+
+@pytest.mark.skipif(ds_is_older('2.2.0.0'),
+ reason="This test is only required with multiple listener support.")
+def test_conn_limits(dscreate_with_numlistener):
+ """Check the connections limits for various number of listeners.
+
+ :id: 7be2eb5c-4d8f-11ee-ae3d-482ae39447e5
+ :parametrized: yes
+ :setup: Setup an instance then set nsslapd-numlisteners and maximum file descriptors
+ :steps:
+ 1. Loops on:
+ Open new connection and perform search until timeout expires
+ 2. Close one of the previously open connections
+ 3. Loops MAX_FDS times on:
+ - opening a new connection
+ - perform a search
+ - close the connection
+ 4. Close all open connections
+ 5. Remove the instance
+ :expectedresults:
+ 1. Should get a timeout (because the server has no more any connections)
+ 2. Should success
+ 3. Should success (otherwise issue #5924 has probably been hit)
+ 4. Should success
+ 5. Should success
+ """
+ inst = dscreate_with_numlistener
+
+ conns = []
+ timeout_occured = False
+ for i in range(MAX_FDS):
+ try:
+ ldc = ldap.initialize(f'ldap://localhost:{inst.port}')
+ ldc.set_option(ldap.OPT_TIMEOUT, 5)
+ ldc.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, "(uid=demo)")
+ conns.append(ldc)
+ except ldap.TIMEOUT:
+ timeout_occured = True
+ break
+ # Should not be able to open MAX_FDS connections (some file descriptor are
+ # reserved (for example for the listening socket )
+ assert timeout_occured
+
+ conn = random.choice(conns)
+ conn.unbind()
+ conns.remove(conn)
+
+ # Should loop enough time so trigger issue #5924 if it is not fixed.
+ for i in range(MAX_FDS):
+ ldc = ldap.initialize(f'ldap://localhost:{inst.port}')
+ # Set a timeout long enough so that the test fails if server is unresponsive
+ ldc.set_option(ldap.OPT_TIMEOUT, 60)
+ ldc.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, "(uid=demo)")
+ ldc.unbind()
+
+ # Close all open connections
+ for c in conns:
+ c.unbind()
+
+ # Step 6 is done in teardown phase by dscreate_instance finalizer
+
if __name__ == '__main__':
# Run isolated
# -s for DEBUG mode
diff --git a/ldap/servers/slapd/conntable.c b/ldap/servers/slapd/conntable.c
index 11e997432b..1ca60e0e5f 100644
--- a/ldap/servers/slapd/conntable.c
+++ b/ldap/servers/slapd/conntable.c
@@ -48,69 +48,59 @@
* under the connection table lock. This should move the allocation algorithm from O(n) worst case
* to O(1) worst case as we always recieve and empty slot *or* ct full. It also reduces lock/atomic
* contention on the CPU to improve things.
+ * Lastly a change was done: Instead of having a sliding windows that tend to get a never used
+ * slot for each new connection, it nows reuse last freed one. That has several benefits:
+ * - Fix a bug because the last free list slots may not be alloced.
+ * - Avoid to grow the memory footprint when there is no much load
+ * - Simplify the code (as only a single is needed. )
*
- * The freelist is a ringbuffer of pointers to the connection table. On a small scale it looks like:
+ * The freelist is a stack of pointers to the connection table.
+ * It is NULL terminated. On a small scale it looks like:
*
* |--------------------------------------------|
- * | slot 1 | slot 2 | slot 3 | slot 4 | slot 5 |
- * | _ ptr | _ ptr | _ ptr | _ ptr | _ ptr |
+ * | slot 0 | slot 1 | slot 2 | slot 3 | slot 4 |
+ * | _ ptr | _ ptr | _ ptr | _ ptr | NULL |
* |--------------------------------------------|
- * ^ ^- conn_next
- * |
- * \-- conn_free
+ * ^- conn_next
*
- * As we allocate, we shift conn_next through the list, yielding the ptr that was stored (and
- * setting it to NULL as we proceed)
+ * To allocate, we pop one of the stored connection ptr out of the stack (yield the ptr, set
+ * its slot to NULL then increase conn_next)
*
* |--------------------------------------------|
- * | slot 1 | slot 2 | slot 3 | slot 4 | slot 5 |
- * | _NULL | _NULL | _ ptr | _ ptr | _ ptr |
+ * | slot 0 | slot 1 | slot 2 | slot 3 | slot 4 |
+ * | _NULL | _NULL | _ ptr | _ ptr | NULL |
* |--------------------------------------------|
- * ^ ^- conn_next
- * |
- * \-- conn_free
+ * ^- conn_next
*
- * When a connection is "freed" we return it to conn_free, which is then also slid up.
+ * When a connection is "freed" we push it back in the stack after decreasing conn_next
*
* |--------------------------------------------|
- * | slot 1 | slot 2 | slot 3 | slot 4 | slot 5 |
- * | _ ptr | _NULL | _ ptr | _ ptr | _ ptr |
+ * | slot 0 | slot 1 | slot 2 | slot 3 | slot 4 |
+ * | _NULL | _ ptr | _ ptr | _ ptr | NULL |
* |--------------------------------------------|
- * ^ ^- conn_next
- * |
- * \-- conn_free
+ * ^- conn_next
*
- * If all connections are exhausted, conn_next will == conn_next, as conn_next must have proceeded
- * to the end of the ring, and then wrapped back allocating all previous until we meet with conn_free.
+ * If all connections are exhausted, freelist[conn_next] is NULL
*
* |--------------------------------------------|
- * | slot 1 | slot 2 | slot 3 | slot 4 | slot 5 |
+ * | slot 0 | slot 1 | slot 2 | slot 3 | slot 4 |
* | _NULL | _NULL | _NULL | _NULL | _NULL |
* |--------------------------------------------|
- * ^ ^- conn_next
- * |
- * \-- conn_free
+ * ^- conn_next
*
* This means allocations of conns will keep failing until a connection is returned.
*
* |--------------------------------------------|
- * | slot 1 | slot 2 | slot 3 | slot 4 | slot 5 |
- * | _NULL | _ ptr | _NULL | _NULL | _NULL |
+ * | slot 0 | slot 1 | slot 2 | slot 3 | slot 4 |
+ * | _NULL | _NULL | _NULL | _ ptr | NULL |
* |--------------------------------------------|
- * ^- conn_next ^
- * |
- * \-- conn_free
+ * ^- conn_next
*
* And now conn_next can begin to allocate again.
*
*
* -- invariants
- * * when conn_free is slid back to meet conn_next, there can be no situation where another
- * connection is returned, as none must allocated -if they were allocated, conn_free would have
- * moved_along.
- * * the ring buffer must be as large as conntable.
- * * We do not check conn_next == conn_free (that's the starting state), but we check if the
- * slot at conn_next is NULL, which must imply that conn_free has nothing to return.
+ * * the stack must be as large as conntable.
* * connection_table_move_connection_out_of_active_list is the only function able to return a
* connection to the freelist, as it is the function that is called when the event system has
* determined all IO's are complete, or unable to complete. This function is what prepares the
@@ -136,11 +126,9 @@ connection_table_new(int table_size)
ct->c = (Connection **)slapi_ch_calloc(1, ct->size * sizeof(Connection *));
ct->fd = (struct POLL_STRUCT **)slapi_ch_calloc(1, ct->list_num * sizeof(struct POLL_STRUCT*));
ct->table_mutex = PR_NewLock();
- /* Allocate the freelist */
- ct->c_freelist = (Connection **)slapi_ch_calloc(1, ct->size * sizeof(Connection *));
- /* NEVER use slot 0, this is a list pointer */
- ct->conn_next_offset = 1;
- ct->conn_free_offset = 1;
+ /* Allocate the freelist (a slot for each connection plus another slot for the final NULL pointer) */
+ ct->c_freelist = (Connection **)slapi_ch_calloc(1, (ct->size+1) * sizeof(Connection *));
+ ct->conn_next_offset = 0;
slapi_log_err(SLAPI_LOG_INFO, "connection_table_new", "Number of connection sub-tables %d, each containing %d slots.\n",
ct->list_num, ct->list_size);
@@ -273,22 +261,22 @@ connection_table_get_connection(Connection_Table *ct, int sd)
{
PR_Lock(ct->table_mutex);
- PR_ASSERT(ct->conn_next_offset != 0);
Connection *c = ct->c_freelist[ct->conn_next_offset];
if (c != NULL) {
/* We allocated it, so now NULL the slot and move forward. */
- ct->c_freelist[ct->conn_next_offset] = NULL;
- /* Handle overflow. */
- ct->conn_next_offset = (ct->conn_next_offset + 1) % ct->size;
- if (ct->conn_next_offset == 0) {
- /* Never use slot 0 */
- ct->conn_next_offset += 1;
- }
+ PR_ASSERT(ct->conn_next_offset>=0 && ct->conn_next_offset<ct->size);
+ ct->c_freelist[ct->conn_next_offset++] = NULL;
PR_Unlock(ct->table_mutex);
} else {
/* couldn't find a Connection, table must be full */
- slapi_log_err(SLAPI_LOG_CONNS, "connection_table_get_connection", "Max open connections reached\n");
PR_Unlock(ct->table_mutex);
+ static time_t last_err_msg_time = 0;
+ time_t curtime = slapi_current_utc_time();
+ /* Logs the message only once per seconds */
+ if (curtime != last_err_msg_time) {
+ slapi_log_err(SLAPI_LOG_ERR, "connection_table_get_connection", "Max open connections reached\n");
+ last_err_msg_time = curtime;
+ }
return NULL;
}
@@ -461,14 +449,10 @@ connection_table_move_connection_out_of_active_list(Connection_Table *ct, Connec
/* Finally, place the connection back into the freelist for use */
PR_ASSERT(c->c_refcnt == 0);
- PR_ASSERT(ct->conn_free_offset != 0);
- PR_ASSERT(ct->c_freelist[ct->conn_free_offset] == NULL);
- ct->c_freelist[ct->conn_free_offset] = c;
- ct->conn_free_offset = (ct->conn_free_offset + 1) % ct->size;
- if (ct->conn_free_offset == 0) {
- /* Never use slot 0 */
- ct->conn_free_offset += 1;
- }
+ PR_ASSERT(ct->conn_next_offset != 0);
+ ct->conn_next_offset--;
+ PR_ASSERT(ct->c_freelist[ct->conn_next_offset] == NULL);
+ ct->c_freelist[ct->conn_next_offset] = c;
PR_Unlock(ct->table_mutex);
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
index e8b979acaf..10aabed6d3 100644
--- a/ldap/servers/slapd/daemon.c
+++ b/ldap/servers/slapd/daemon.c
@@ -135,19 +135,25 @@ get_pid_file(void)
}
static int
-accept_and_configure(int s __attribute__((unused)), PRFileDesc *pr_acceptfd, PRNetAddr *pr_netaddr, int addrlen __attribute__((unused)), int secure, int local, PRFileDesc **pr_clonefd)
+accept_and_configure(int s __attribute__((unused)), PRFileDesc *listenfd, PRNetAddr *pr_netaddr, int addrlen __attribute__((unused)), int secure, int local, PRFileDesc **pr_accepted_fd)
{
int ns = 0;
PRIntervalTime pr_timeout = PR_MillisecondsToInterval(slapd_accept_wakeup_timer);
- (*pr_clonefd) = PR_Accept(pr_acceptfd, pr_netaddr, pr_timeout);
- if (!(*pr_clonefd)) {
+ (*pr_accepted_fd) = PR_Accept(listenfd, pr_netaddr, pr_timeout);
+ if (!(*pr_accepted_fd)) {
PRErrorCode prerr = PR_GetError();
- slapi_log_err(SLAPI_LOG_ERR, "accept_and_configure", "PR_Accept() failed, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
- prerr, slapd_pr_strerror(prerr));
+ static time_t last_err_msg_time = 0;
+ time_t curtime = slapi_current_utc_time();
+ /* Logs the message only once per seconds */
+ if (curtime != last_err_msg_time) {
+ slapi_log_err(SLAPI_LOG_ERR, "accept_and_configure", "PR_Accept() failed, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_pr_strerror(prerr));
+ last_err_msg_time = curtime;
+ }
return (SLAPD_INVALID_SOCKET);
}
- ns = configure_pr_socket(pr_clonefd, secure, local);
+ ns = configure_pr_socket(pr_accepted_fd, secure, local);
return ns;
}
@@ -155,7 +161,7 @@ accept_and_configure(int s __attribute__((unused)), PRFileDesc *pr_acceptfd, PRN
/*
* This is the shiny new re-born daemon function, without all the hair
*/
-static int handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, int secure, int local, Connection **newconn);
+static int handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *listenfd, int secure, int local, Connection **newconn);
static void handle_pr_read_ready(Connection_Table *ct, int list_id, PRIntn num_poll);
static int clear_signal(struct POLL_STRUCT *fds, int list_id);
static void unfurl_banners(Connection_Table *ct, daemon_ports_t *ports, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix);
@@ -831,6 +837,7 @@ accept_thread(void *vports)
}
/* Need a sleep delay here. */
PR_Sleep(pr_timeout);
+ last_accept_new_connections = accept_new_connections;
continue;
} else {
/* Log that we are now listening again */
@@ -1846,28 +1853,30 @@ handle_closed_connection(Connection *conn)
* this function returns the connection table list the new connection is in
*/
static int
-handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, int secure, int local, Connection **newconn)
+handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *listenfd, int secure, int local, Connection **newconn)
{
int ns = 0;
Connection *conn = NULL;
/* struct sockaddr_in from;*/
PRNetAddr from = {{0}};
- PRFileDesc *pr_clonefd = NULL;
+ PRFileDesc *pr_accepted_fd = NULL;
slapdFrontendConfig_t *fecfg = getFrontendConfig();
ber_len_t maxbersize;
if (newconn) {
*newconn = NULL;
}
- if ((ns = accept_and_configure(tcps, pr_acceptfd, &from,
- sizeof(from), secure, local, &pr_clonefd)) == SLAPD_INVALID_SOCKET) {
+ if ((ns = accept_and_configure(tcps, listenfd, &from,
+ sizeof(from), secure, local, &pr_accepted_fd)) == SLAPD_INVALID_SOCKET) {
return -1;
}
/* get a new Connection from the Connection Table */
conn = connection_table_get_connection(ct, ns);
if (conn == NULL) {
- PR_Close(pr_acceptfd);
+ if (pr_accepted_fd) {
+ PR_Close(pr_accepted_fd);
+ }
return -1;
}
pthread_mutex_lock(&(conn->c_mutex));
@@ -1879,7 +1888,7 @@ handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, i
conn->c_idletimeout = fecfg->idletimeout;
conn->c_idletimeout_handle = idletimeout_reslimit_handle;
conn->c_sd = ns;
- conn->c_prfd = pr_clonefd;
+ conn->c_prfd = pr_accepted_fd;
conn->c_flags &= ~CONN_FLAG_CLOSING;
/* Set per connection static config */
diff --git a/ldap/servers/slapd/fe.h b/ldap/servers/slapd/fe.h
index 64c6645e7b..95dfeeb89b 100644
--- a/ldap/servers/slapd/fe.h
+++ b/ldap/servers/slapd/fe.h
@@ -88,7 +88,6 @@ struct connection_table
/* An array of free connections awaiting allocation. */;
Connection **c_freelist;
size_t conn_next_offset;
- size_t conn_free_offset;
struct POLL_STRUCT **fd;
PRLock *table_mutex;
};