From ca86726f9f943b2b18e5694b442d3d2e1c0fa903 Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Wed, 25 Jun 2014 23:42:39 +0800
Subject: [PATCH] Improve handling lots of concurrent forwarded connections.
 Increase connection backlog, avoid check_close() for channels that haven't
 had IO

---
 common-channel.c | 13 ++++++++++---
 dbutil.c         |  2 +-
 sysoptions.h     |  6 ++++++
 3 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/common-channel.c b/common-channel.c
index 91629809..62e4be1c 100644
--- a/common-channel.c
+++ b/common-channel.c
@@ -208,11 +208,14 @@ struct Channel* getchannel() {
 /* Iterate through the channels, performing IO if available */
 void channelio(fd_set *readfds, fd_set *writefds) {
 
+	/* Listeners such as TCP, X11, agent-auth */
 	struct Channel *channel;
 	unsigned int i;
 
 	/* foreach channel */
 	for (i = 0; i < ses.chansize; i++) {
+		/* Close checking only needs to occur for channels that had IO events */
+		int do_check_close = 0;
 
 		channel = ses.channels[i];
 		if (channel == NULL) {
@@ -224,6 +227,7 @@ void channelio(fd_set *readfds, fd_set *writefds) {
 		if (channel->readfd >= 0 && FD_ISSET(channel->readfd, readfds)) {
 			TRACE(("send normal readfd"))
 			send_msg_channel_data(channel, 0);
+			do_check_close = 1;
 		}
 
 		/* read stderr data and send it over the wire */
@@ -231,6 +235,7 @@ void channelio(fd_set *readfds, fd_set *writefds) {
 			&& FD_ISSET(channel->errfd, readfds)) {
 				TRACE(("send normal errfd"))
 				send_msg_channel_data(channel, 1);
+			do_check_close = 1;
 		}
 
 		/* write to program/pipe stdin */
@@ -242,20 +247,22 @@ void channelio(fd_set *readfds, fd_set *writefds) {
 							 check_in_progress(), as it may be NULL */
 			}
 			writechannel(channel, channel->writefd, channel->writebuf);
+			do_check_close = 1;
 		}
 		
 		/* stderr for client mode */
 		if (ERRFD_IS_WRITE(channel)
 				&& channel->errfd >= 0 && FD_ISSET(channel->errfd, writefds)) {
 			writechannel(channel, channel->errfd, channel->extrabuf);
+			do_check_close = 1;
 		}
 	
 		/* handle any channel closing etc */
-		check_close(channel);
-
+		if (do_check_close) {
+			check_close(channel);
+		}
 	}
 
-	/* Listeners such as TCP, X11, agent-auth */
 #ifdef USING_LISTENERS
 	handle_listeners(readfds);
 #endif
diff --git a/dbutil.c b/dbutil.c
index 145bc332..2ea52ace 100644
--- a/dbutil.c
+++ b/dbutil.c
@@ -332,7 +332,7 @@ int dropbear_listen(const char* address, const char* port,
 			continue;
 		}
 
-		if (listen(sock, 20) < 0) {
+		if (listen(sock, DROPBEAR_LISTEN_BACKLOG) < 0) {
 			err = errno;
 			close(sock);
 			TRACE(("listen() failed"))
diff --git a/sysoptions.h b/sysoptions.h
index a587762f..8a359fb5 100644
--- a/sysoptions.h
+++ b/sysoptions.h
@@ -251,4 +251,10 @@
 #define USE_VFORK
 #endif  /* don't HAVE_FORK */
 
+#if MAX_UNAUTH_CLIENTS > MAX_CHANNELS
+#define DROPBEAR_LISTEN_BACKLOG MAX_UNAUTH_CLIENTS
+#else
+#define DROPBEAR_LISTEN_BACKLOG MAX_CHANNELS
+#endif
+
 /* no include guard for this file */
-- 
GitLab