andykimpe / rpms / 389-ds-base

Forked from rpms/389-ds-base 5 months ago
Clone
dc8c34
From 43c715dfb8a72bd61e8cf2fd43324b7d3b1b5143 Mon Sep 17 00:00:00 2001
dc8c34
From: Rich Megginson <rmeggins@redhat.com>
dc8c34
Date: Fri, 10 May 2013 15:11:13 -0600
dc8c34
Subject: [PATCH 62/99] Ticket #47359 - new ldap connections can block ldaps
dc8c34
 and ldapi connections
dc8c34
dc8c34
https://fedorahosted.org/389/ticket/47359
dc8c34
Reviewed by: lkrispen, nhosoi (Thanks!)
dc8c34
Branch: 389-ds-base-1.2.11
dc8c34
Fix Description: description
dc8c34
In the polling thread, first process all of the new connection requests from
dc8c34
the listening sockets, then process any new operation read requests
dc8c34
The listener_idxs keeps track of the index of the active listeners in the
dc8c34
poll fd array, and keeps a pointer to the listenfd object for that
dc8c34
listener.  This allows us to very quickly scan through the poll fd array
dc8c34
and find the ready listeners.  The work of scanning through the array
dc8c34
and handling the new connection requests has been moved to a new function
dc8c34
handle_listeners().
dc8c34
Platforms tested: RHEL6 x86_64
dc8c34
Flag Day: no
dc8c34
Doc impact: no
dc8c34
(cherry picked from commit 115ab1d9a3f026e8523b91bf62245a25454a3e8a)
dc8c34
(cherry picked from commit 24b751cc724468a7bce5f86848a82e4b03e24a3c)
dc8c34
(cherry picked from commit 5226ed9f2e585dc3d561f9286555efc7e3eea6b6)
dc8c34
(cherry picked from commit e0328aba6ed9254cf537f85927c55cbbb82cae77)
dc8c34
(cherry picked from commit 8a1fd0711e060aca3943ca346005bb43eddf82c4)
dc8c34
---
dc8c34
 ldap/servers/slapd/daemon.c | 115 ++++++++++++++++++++++++--------------------
dc8c34
 1 file changed, 62 insertions(+), 53 deletions(-)
dc8c34
dc8c34
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
dc8c34
index 75a83c0..93ebe4a 100644
dc8c34
--- a/ldap/servers/slapd/daemon.c
dc8c34
+++ b/ldap/servers/slapd/daemon.c
dc8c34
@@ -136,6 +136,15 @@ void disk_monitoring_stop();
dc8c34
 
dc8c34
 #define FDS_SIGNAL_PIPE 0
dc8c34
 
dc8c34
+typedef struct listener_info {
dc8c34
+	int idx; /* index of this listener in the ct->fd array */
dc8c34
+	PRFileDesc *listenfd; /* the listener fd */
dc8c34
+	int secure;
dc8c34
+	int local;
dc8c34
+} listener_info;
dc8c34
+
dc8c34
+#define SLAPD_POLL_LISTEN_READY(xxflagsxx) (xxflagsxx & PR_POLL_READ)
dc8c34
+
dc8c34
 static int get_configured_connection_table_size();
dc8c34
 #ifdef RESOLVER_NEEDS_LOW_FILE_DESCRIPTORS
dc8c34
 static void get_loopback_by_addr( void );
dc8c34
@@ -149,7 +158,7 @@ static PRFileDesc **createprlistensockets(unsigned short port,
dc8c34
 static const char *netaddr2string(const PRNetAddr *addr, char *addrbuf,
dc8c34
 	size_t addrbuflen);
dc8c34
 static void	set_shutdown (int);
dc8c34
-static void setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix, PRIntn *num_to_read);
dc8c34
+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);
dc8c34
 
dc8c34
 #ifdef HPUX10
dc8c34
 static void* catch_signals();
dc8c34
@@ -913,6 +922,30 @@ disk_monitoring_thread(void *nothing)
dc8c34
     }
dc8c34
 }
dc8c34
 
dc8c34
+static void
dc8c34
+handle_listeners(Connection_Table *ct, listener_info *listener_idxs, int n_listeners)
dc8c34
+{
dc8c34
+	int idx;
dc8c34
+	for (idx = 0; idx < n_listeners; ++idx) {
dc8c34
+		int fdidx = listener_idxs[idx].idx;
dc8c34
+		PRFileDesc *listenfd = listener_idxs[idx].listenfd;
dc8c34
+		int secure = listener_idxs[idx].secure;
dc8c34
+		int local = listener_idxs[idx].local;
dc8c34
+		if (fdidx && listenfd) {
dc8c34
+			if (SLAPD_POLL_LISTEN_READY(ct->fd[fdidx].out_flags)) {
dc8c34
+				/* accept() the new connection, put it on the active list for handle_pr_read_ready */
dc8c34
+				int rc = handle_new_connection(ct, SLAPD_INVALID_SOCKET, listenfd, secure, local);
dc8c34
+				if (rc) {
dc8c34
+					LDAPDebug1Arg(LDAP_DEBUG_CONNS, "Error accepting new connection listenfd=%d\n",
dc8c34
+					              PR_FileDesc2NativeHandle(listenfd));
dc8c34
+					continue;
dc8c34
+				}
dc8c34
+			}
dc8c34
+		}
dc8c34
+	}
dc8c34
+	return;
dc8c34
+}
dc8c34
+
dc8c34
 void slapd_daemon( daemon_ports_t *ports )
dc8c34
 {
dc8c34
 	/* We are passed some ports---one for regular connections, one
dc8c34
@@ -929,7 +962,6 @@ void slapd_daemon( daemon_ports_t *ports )
dc8c34
 	int s_tcps_native = 0;
dc8c34
 	PRFileDesc *s_tcps = NULL; 
dc8c34
 #else
dc8c34
-	PRFileDesc *tcps = 0;
dc8c34
 	PRFileDesc **n_tcps = NULL; 
dc8c34
 	PRFileDesc **s_tcps = NULL; 
dc8c34
 	PRFileDesc **i_unix = NULL;
dc8c34
@@ -940,6 +972,8 @@ void slapd_daemon( daemon_ports_t *ports )
dc8c34
 	PRThread *time_thread_p;
dc8c34
 	int threads;
dc8c34
 	int in_referral_mode = config_check_referral_mode();
dc8c34
+	int n_listeners = 0; /* number of listener sockets */
dc8c34
+	listener_info *listener_idxs = NULL; /* array of indexes of listener sockets in the ct->fd array */
dc8c34
 
dc8c34
 	int connection_table_size = get_configured_connection_table_size();
dc8c34
 	the_connection_table= connection_table_new(connection_table_size);
dc8c34
@@ -1054,6 +1088,7 @@ void slapd_daemon( daemon_ports_t *ports )
dc8c34
 			netaddr2string(&ports->n_listenaddr, addrbuf, sizeof(addrbuf)),
dc8c34
 			ports->n_port, oserr, slapd_system_strerror( oserr ) );
dc8c34
 		g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
dc8c34
+		n_listeners++;
dc8c34
 	}
dc8c34
 #else
dc8c34
 	if ( n_tcps != NULL ) {
dc8c34
@@ -1071,6 +1106,7 @@ void slapd_daemon( daemon_ports_t *ports )
dc8c34
 					slapd_pr_strerror( prerr ));
dc8c34
 				g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
dc8c34
 			}
dc8c34
+			n_listeners++;
dc8c34
 		}
dc8c34
 	}
dc8c34
 #endif
dc8c34
@@ -1090,6 +1126,7 @@ void slapd_daemon( daemon_ports_t *ports )
dc8c34
 					slapd_pr_strerror( prerr ));
dc8c34
 				g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
dc8c34
 			}
dc8c34
+			n_listeners++;
dc8c34
 		}
dc8c34
 	}
dc8c34
 
dc8c34
@@ -1108,11 +1145,13 @@ void slapd_daemon( daemon_ports_t *ports )
dc8c34
 					slapd_pr_strerror( prerr ));
dc8c34
 				g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
dc8c34
 			}
dc8c34
+			n_listeners++;
dc8c34
 		}
dc8c34
 	}
dc8c34
 #endif /* ENABLE_LDAPI */
dc8c34
 #endif
dc8c34
 
dc8c34
+	listener_idxs = (listener_info *)slapi_ch_calloc(n_listeners, sizeof(*listener_idxs));
dc8c34
 	/* Now we write the pid file, indicating that the server is finally and listening for connections */
dc8c34
 	write_pid_file();
dc8c34
 
dc8c34
@@ -1125,9 +1164,6 @@ void slapd_daemon( daemon_ports_t *ports )
dc8c34
 		int			oserr;
dc8c34
 #endif
dc8c34
 		int select_return = 0;
dc8c34
-		int secure = 0; /* is a new connection an SSL one ? */
dc8c34
-		int local = 0; /* is new connection an ldapi one? */
dc8c34
-		int i;
dc8c34
 
dc8c34
 #ifndef _WIN32
dc8c34
 		PRErrorCode prerr;
dc8c34
@@ -1139,7 +1175,7 @@ void slapd_daemon( daemon_ports_t *ports )
dc8c34
 		/* This select needs to timeout to give the server a chance to test for shutdown */
dc8c34
 		select_return = select(connection_table_size, &readfds, NULL, 0, &wakeup_timer);
dc8c34
 #else
dc8c34
-		setup_pr_read_pds(the_connection_table,n_tcps,s_tcps,i_unix,&num_poll);
dc8c34
+		setup_pr_read_pds(the_connection_table,n_tcps,s_tcps,i_unix,&num_poll,listener_idxs,n_listeners);
dc8c34
 		select_return = POLL_FN(the_connection_table->fd, num_poll, pr_timeout);
dc8c34
 #endif
dc8c34
 		switch (select_return) {
dc8c34
@@ -1175,52 +1211,8 @@ void slapd_daemon( daemon_ports_t *ports )
dc8c34
 			handle_read_ready(the_connection_table,&readfds);
dc8c34
 			clear_signal(&readfds);
dc8c34
 #else
dc8c34
-			tcps = NULL;
dc8c34
-            /* info for n_tcps is always in fd[n_tcps ~ n_tcpe] */
dc8c34
-			if( NULL != n_tcps ) {
dc8c34
-				for (i = the_connection_table->n_tcps;
dc8c34
-					 i < the_connection_table->n_tcpe; i++) {
dc8c34
-					if (the_connection_table->fd[i].out_flags &
dc8c34
-													SLAPD_POLL_FLAGS ) {
dc8c34
-						/* tcps = n_tcps[i - the_connection_table->n_tcps]; */
dc8c34
-						tcps = the_connection_table->fd[i].fd;
dc8c34
-						break;
dc8c34
-					}
dc8c34
-				}
dc8c34
-			}
dc8c34
-            /* info for s_tcps is always in fd[s_tcps ~ s_tcpe] */
dc8c34
-			if ( NULL == tcps && NULL != s_tcps ) {
dc8c34
-				for (i = the_connection_table->s_tcps;
dc8c34
-					 i < the_connection_table->s_tcpe; i++) {
dc8c34
-					if (the_connection_table->fd[i].out_flags &
dc8c34
-													SLAPD_POLL_FLAGS ) {
dc8c34
-						/* tcps = s_tcps[i - the_connection_table->s_tcps]; */
dc8c34
-						tcps = the_connection_table->fd[i].fd;
dc8c34
-						secure = 1;
dc8c34
-						break;
dc8c34
-					}
dc8c34
-				}
dc8c34
-			}
dc8c34
-#if defined(ENABLE_LDAPI)
dc8c34
-            /* info for i_unix is always in fd[i_unixs ~ i_unixe] */
dc8c34
-			if ( NULL == tcps && NULL != i_unix ) {
dc8c34
-				for (i = the_connection_table->i_unixs;
dc8c34
-					 i < the_connection_table->i_unixe; i++) {
dc8c34
-					if (the_connection_table->fd[i].out_flags &
dc8c34
-													SLAPD_POLL_FLAGS ) {
dc8c34
-						/* tcps = i_unix[i - the_connection_table->i_unixs]; */
dc8c34
-						tcps = the_connection_table->fd[i].fd;
dc8c34
-						local = 1;
dc8c34
-						break;
dc8c34
-					}
dc8c34
-				}
dc8c34
-			}
dc8c34
-#endif /* ENABLE_LDAPI */
dc8c34
-
dc8c34
-			/* If so, then handle a new connection */
dc8c34
-			if ( tcps != NULL ) {
dc8c34
-				handle_new_connection(the_connection_table,SLAPD_INVALID_SOCKET,tcps,secure,local);
dc8c34
-			}
dc8c34
+			/* handle new connections from the listeners */
dc8c34
+			handle_listeners(the_connection_table, listener_idxs, n_listeners);
dc8c34
 			/* handle new data ready */
dc8c34
 			handle_pr_read_ready(the_connection_table, connection_table_size);
dc8c34
 			clear_signal(the_connection_table->fd);
dc8c34
@@ -1548,7 +1540,7 @@ static void setup_read_fds(Connection_Table *ct, fd_set *readfds, int n_tcps, in
dc8c34
 static int first_time_setup_pr_read_pds = 1;
dc8c34
 static int listen_addr_count = 0;
dc8c34
 static void
dc8c34
-setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix, PRIntn *num_to_read)
dc8c34
+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)
dc8c34
 {
dc8c34
 	Connection *c= NULL;
dc8c34
 	Connection *next= NULL;
dc8c34
@@ -1558,6 +1550,7 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
dc8c34
 	PRIntn count = 0;
dc8c34
 	slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
dc8c34
 	int max_threads_per_conn = config_get_maxthreadsperconn();
dc8c34
+	int n_listeners = 0;
dc8c34
 
dc8c34
 	accept_new_connections = ((ct->size - g_get_current_conn_count())
dc8c34
 		> slapdFrontendConfig->reservedescriptors);
dc8c34
@@ -1609,6 +1602,9 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
dc8c34
 				ct->fd[count].fd = *fdesc;
dc8c34
 				ct->fd[count].in_flags = SLAPD_POLL_FLAGS;
dc8c34
 				ct->fd[count].out_flags = 0;
dc8c34
+				listener_idxs[n_listeners].listenfd = *fdesc;
dc8c34
+				listener_idxs[n_listeners].idx = count;
dc8c34
+				n_listeners++;
dc8c34
 				LDAPDebug( LDAP_DEBUG_HOUSE, 
dc8c34
 					"listening for connections on %d\n", socketdesc, 0, 0 );
dc8c34
 			}
dc8c34
@@ -1627,6 +1623,10 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
dc8c34
 				ct->fd[count].fd = *fdesc;
dc8c34
 				ct->fd[count].in_flags = SLAPD_POLL_FLAGS;
dc8c34
 				ct->fd[count].out_flags = 0;
dc8c34
+				listener_idxs[n_listeners].listenfd = *fdesc;
dc8c34
+				listener_idxs[n_listeners].idx = count;
dc8c34
+				listener_idxs[n_listeners].secure = 1;
dc8c34
+				n_listeners++;
dc8c34
 				LDAPDebug( LDAP_DEBUG_HOUSE, 
dc8c34
 					"listening for SSL connections on %d\n", socketdesc, 0, 0 );
dc8c34
 			}
dc8c34
@@ -1648,6 +1648,10 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
dc8c34
 				ct->fd[count].fd = *fdesc;
dc8c34
 				ct->fd[count].in_flags = SLAPD_POLL_FLAGS;
dc8c34
 				ct->fd[count].out_flags = 0;
dc8c34
+				listener_idxs[n_listeners].listenfd = *fdesc;
dc8c34
+				listener_idxs[n_listeners].idx = count;
dc8c34
+				listener_idxs[n_listeners].local = 1;
dc8c34
+				n_listeners++;
dc8c34
 				LDAPDebug( LDAP_DEBUG_HOUSE,
dc8c34
 					"listening for LDAPI connections on %d\n", socketdesc, 0, 0 );
dc8c34
 			}
dc8c34
@@ -1661,6 +1665,11 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
dc8c34
  
dc8c34
 		first_time_setup_pr_read_pds = 0;
dc8c34
 		listen_addr_count = count;
dc8c34
+
dc8c34
+		if (n_listeners < max_listeners) {
dc8c34
+			listener_idxs[n_listeners].idx = 0;
dc8c34
+			listener_idxs[n_listeners].listenfd = NULL;
dc8c34
+		}
dc8c34
 	}
dc8c34
 
dc8c34
 	/* count is the number of entries we've place in the fds array.
dc8c34
-- 
dc8c34
1.8.1.4
dc8c34