Debug( LDAP_DEBUG_ANY,
"connection_init(%d, %s): set nonblocking failed\n",
s, c->c_peer_name.bv_val, 0 );
+
+ c->c_listener = NULL;
+ if(c->c_peer_domain.bv_val != NULL) {
+ free(c->c_peer_domain.bv_val);
+ }
+ BER_BVZERO( &c->c_peer_domain );
+ if(c->c_peer_name.bv_val != NULL) {
+ free(c->c_peer_name.bv_val);
+ }
+ BER_BVZERO( &c->c_peer_name );
+
+ ber_sockbuf_free( c->c_sb );
+ c->c_sb = NULL;
+ c->c_sd = AC_SOCKET_INVALID;
+ ldap_pvt_thread_mutex_unlock( &c->c_mutex );
+
+ return NULL;
}
ldap_pvt_thread_mutex_lock( &conn_nextid_mutex );
}
#endif
+#ifdef DEBUG_CLOSE
+/* Was used to find a bug causing slapd's descriptors to be closed
+ * out from under it. Tracked it down to a long-standing (from 2009)
+ * bug in Heimdal https://github.com/heimdal/heimdal/issues/431 .
+ * Leaving this here for future use, if necessary.
+ */
+#include <dlfcn.h>
+#ifndef RTLD_NEXT
+#define RTLD_NEXT (void *)-1L
+#endif
+static char *newconns;
+typedef int (closefunc)(int fd);
+static closefunc *close_ptr;
+int close( int s )
+{
+ if (newconns) {
+ Debug( LDAP_DEBUG_CONNS,
+ "daemon: close(%ld)\n", s, 0, 0 );
+ if (s >= 0 && s < dtblsize && newconns[s])
+ assert(newconns[s] == 2);
+ }
+ return close_ptr ? close_ptr(s) : -1;
+}
+
+void slapd_debug_close()
+{
+ if (dtblsize)
+ newconns = ch_calloc(1, dtblsize);
+ close_ptr = dlsym(RTLD_NEXT, "close");
+}
+
+void slapd_set_close(int fd)
+{
+ newconns[fd] = 3;
+}
+#define SETUP_CLOSE() slapd_debug_close()
+#define SET_CLOSE(fd) slapd_set_close(fd)
+#define CLR_CLOSE(fd) if (newconns[fd]) newconns[fd]--
+#else
+#define SETUP_CLOSE(fd)
+#define SET_CLOSE(fd)
+#define CLR_CLOSE(fd)
+#endif
+
/*
* Add a descriptor to daemon control
*
if ( waswriter ) slap_daemon[id].sd_nwriters--;
SLAP_SOCK_DEL(id, s);
+ CLR_CLOSE(s);
if ( sb )
ber_sockbuf_free(sb);
{
Debug( LDAP_DEBUG_CONNS, "daemon: closing %ld\n",
(long) s, 0, 0 );
+ CLR_CLOSE( SLAP_FD2SOCK(s) );
tcp_close( SLAP_FD2SOCK(s) );
#ifdef HAVE_WINSOCK
slapd_sockdel( s );
dtblsize = FD_SETSIZE;
#endif /* ! HAVE_SYSCONF && ! HAVE_GETDTABLESIZE */
+ SETUP_CLOSE();
+
/* open a pipe (or something equivalent connected to itself).
* we write a byte on this fd whenever we catch a signal. The main
* loop will be select'ing on this socket, and will wake up when
# endif /* LDAP_PF_LOCAL */
s = accept( SLAP_FD2SOCK( sl->sl_sd ), (struct sockaddr *) &from, &len );
+ if ( s != AC_SOCKET_INVALID ) {
+ SET_CLOSE(s);
+ }
+ Debug( LDAP_DEBUG_CONNS,
+ "daemon: accept() = %ld\n", s, 0, 0 );
/* Resume the listener FD to allow concurrent-processing of
* additional incoming connections.
Debug( LDAP_DEBUG_ANY,
"slapd(%ld): setsockopt(SO_KEEPALIVE) failed "
"errno=%d (%s)\n", (long) sfd, err, sock_errstr(err) );
+ slapd_close(sfd);
+ return 0;
}
#endif /* SO_KEEPALIVE */
#ifdef TCP_NODELAY
Debug( LDAP_DEBUG_ANY,
"slapd(%ld): setsockopt(TCP_NODELAY) failed "
"errno=%d (%s)\n", (long) sfd, err, sock_errstr(err) );
+ slapd_close(sfd);
+ return 0;
}
#endif /* TCP_NODELAY */
}
void
slapd_add_internal( ber_socket_t s, int isactive )
{
+ if (!isactive) {
+ SET_CLOSE(s);
+ }
slapd_add( s, isactive, NULL, -1 );
}
slap_sl_mem_init();
+
(void) ldap_pvt_thread_initialize();
serverName = lutil_progname( "slapd", argc, argv );
if ( strcmp( serverName, "slapd" ) ) {
+#ifdef DEBUG_CLOSE
+ extern void slapd_debug_close();
+ slapd_debug_close();
+#endif
for (i=0; tools[i].name; i++) {
if ( !strcmp( serverName, tools[i].name ) ) {
rc = tools[i].func(argc, argv);
optarg );
}
+#ifdef DEBUG_CLOSE
+ extern void slapd_debug_close();
+ slapd_debug_close();
+#endif
/* try full option string first */
for ( i = 0; tools[i].name; i++ ) {
if ( strcmp( optarg, &tools[i].name[4] ) == 0 ) {