From bd3d7ac91e41cb145f31bafaa378fd8e3f1f7ff5 Mon Sep 17 00:00:00 2001
From: Tomas Hozza <thozza@redhat.com>
Date: Wed, 5 Jun 2013 14:16:19 +0200
Subject: [PATCH 1/2] Ncat: Implement idle timeout option for listen mode
This patch implements "-i" (idle timeout) option for listen mode.
Signed-off-by: Tomas Hozza <thozza@redhat.com>
---
ncat/ncat_listen.c | 34 +++++++++++++++++++++++++++++++---
ncat/ncat_main.c | 3 ---
ncat/ncat_proxy.c | 14 +++++++++++++-
ncat/util.c | 11 +++++++++++
ncat/util.h | 3 +++
5 files changed, 58 insertions(+), 7 deletions(-)
diff --git a/ncat/ncat_listen.c b/ncat/ncat_listen.c
index ce26587..e3ccde4 100644
--- a/ncat/ncat_listen.c
+++ b/ncat/ncat_listen.c
@@ -199,6 +199,8 @@ static int ncat_listen_stream(int proto)
{
int rc, i, fds_ready;
fd_set listen_fds;
+ struct timeval tv;
+ struct timeval *tvp = NULL;
/* clear out structs */
FD_ZERO(&master_readfds);
@@ -254,6 +256,9 @@ static int ncat_listen_stream(int proto)
init_fdlist(&broadcast_fdlist, o.conn_limit);
+ if (o.idletimeout > 0)
+ tvp = &tv;
+
while (1) {
/* We pass these temporary descriptor sets to fselect, since fselect
modifies the sets it receives. */
@@ -266,11 +271,17 @@ static int ncat_listen_stream(int proto)
if (o.debug > 1 && o.broker)
logdebug("Broker connection count is %d\n", get_conn_count());
- fds_ready = fselect(client_fdlist.fdmax + 1, &readfds, &writefds, NULL, NULL);
+ if (o.idletimeout > 0)
+ ms_to_timeval(tvp, o.idletimeout);
+
+ fds_ready = fselect(client_fdlist.fdmax + 1, &readfds, &writefds, NULL, tvp);
if (o.debug > 1)
logdebug("select returned %d fds ready\n", fds_ready);
+ if (fds_ready == 0)
+ bye("Idle timeout expired (%d ms).", o.idletimeout);
+
/*
* FIXME: optimize this loop to look only at the fds in the fd list,
* doing it this way means that if you have one descriptor that is very
@@ -584,6 +595,8 @@ static int ncat_listen_dgram(int proto)
fd_set read_fds;
union sockaddr_u remotess;
socklen_t sslen = sizeof(remotess.storage);
+ struct timeval tv;
+ struct timeval *tvp = NULL;
for (i = 0; i < NUM_LISTEN_ADDRS; i++) {
sockfd[i] = -1;
@@ -618,6 +631,9 @@ static int ncat_listen_dgram(int proto)
add_fd(&listen_fdlist, sockfd[i]);
}
+ if (o.idletimeout > 0)
+ tvp = &tv;
+
while (1) {
int i, j, conn_count, socket_n;
@@ -643,11 +659,17 @@ static int ncat_listen_dgram(int proto)
if (o.debug > 1)
logdebug("selecting, fdmax %d\n", listen_fdlist.fdmax);
fds = listen_fds;
- fds_ready = fselect(listen_fdlist.fdmax + 1, &fds, NULL, NULL, NULL);
+
+ if (o.idletimeout > 0)
+ ms_to_timeval(tvp, o.idletimeout);
+
+ fds_ready = fselect(listen_fdlist.fdmax + 1, &fds, NULL, NULL, tvp);
if (o.debug > 1)
logdebug("select returned %d fds ready\n", fds_ready);
+ if (fds_ready == 0)
+ bye("Idle timeout expired (%d ms).", o.idletimeout);
/*
* Figure out which listening socket got a connection. This loop should
@@ -755,7 +777,13 @@ static int ncat_listen_dgram(int proto)
if (o.debug > 1)
logdebug("udp select'ing\n");
- fds_ready = fselect(fdmax + 1, &fds, NULL, NULL, NULL);
+ if (o.idletimeout > 0)
+ ms_to_timeval(tvp, o.idletimeout);
+
+ fds_ready = fselect(fdmax + 1, &fds, NULL, NULL, tvp);
+
+ if (fds_ready == 0)
+ bye("Idle timeout expired (%d ms).", o.idletimeout);
if (FD_ISSET(STDIN_FILENO, &fds)) {
nbytes = Read(STDIN_FILENO, buf, sizeof(buf));
diff --git a/ncat/ncat_main.c b/ncat/ncat_main.c
index 084f17c..aaff9aa 100644
--- a/ncat/ncat_main.c
+++ b/ncat/ncat_main.c
@@ -822,9 +822,6 @@ static int ncat_listen_mode(void)
if (httpconnect.storage.ss_family != AF_UNSPEC || socksconnect.storage.ss_family != AF_UNSPEC)
bye("Invalid option combination: --proxy and -l.");
- if (o.idletimeout != 0)
- bye("An idle timeout only works in connect mode.");
-
if (o.broker && o.cmdexec != NULL)
bye("Invalid option combination: --broker and -e.");
diff --git a/ncat/ncat_proxy.c b/ncat/ncat_proxy.c
index ec2f9df..112b338 100644
--- a/ncat/ncat_proxy.c
+++ b/ncat/ncat_proxy.c
@@ -158,6 +158,8 @@ int ncat_http_server(void)
int listen_socket[NUM_LISTEN_ADDRS];
socklen_t sslen;
union sockaddr_u conn;
+ struct timeval tv;
+ struct timeval *tvp = NULL;
#ifndef WIN32
Signal(SIGCHLD, proxyreaper);
@@ -194,6 +196,9 @@ int ncat_http_server(void)
}
+ if (o.idletimeout > 0)
+ tvp = &tv;
+
for (;;) {
fd_set read_fds;
@@ -204,11 +209,18 @@ int ncat_http_server(void)
if (o.debug > 1)
logdebug("selecting, fdmax %d\n", listen_fdlist.fdmax);
read_fds = listen_fds;
- int fds_ready = fselect(listen_fdlist.fdmax + 1, &read_fds, NULL, NULL, NULL);
+
+ if (o.idletimeout > 0)
+ ms_to_timeval(tvp, o.idletimeout);
+
+ int fds_ready = fselect(listen_fdlist.fdmax + 1, &read_fds, NULL, NULL, tvp);
if (o.debug > 1)
logdebug("select returned %d fds ready\n", fds_ready);
+ if (fds_ready == 0)
+ bye("Idle timeout expired (%d ms).", o.idletimeout);
+
for (i = 0; i <= listen_fdlist.fdmax && fds_ready > 0; i++) {
/* Loop through descriptors until there is something ready */
if (!FD_ISSET(i, &read_fds))
diff --git a/ncat/util.c b/ncat/util.c
index 2e2bd54..b542295 100644
--- a/ncat/util.c
+++ b/ncat/util.c
@@ -507,6 +507,17 @@ int allow_access(const union sockaddr_u *su)
}
/*
+ * Fills the given timeval struct with proper
+ * values based on the given time in milliseconds.
+ * The pointer to timeval struct must NOT be NULL.
+ */
+void ms_to_timeval(struct timeval *tv, long ms)
+{
+ tv->tv_sec = ms / 1000;
+ tv->tv_usec = (ms - (tv->tv_sec * 1000)) * 1000;
+}
+
+/*
* ugly code to maintain our list of fds so we can have proper fdmax for
* select(). really this should be generic list code, not this silly bit of
* stupidity. -sean
diff --git a/ncat/util.h b/ncat/util.h
index 113b3da..c0b2b07 100644
--- a/ncat/util.h
+++ b/ncat/util.h
@@ -165,6 +165,9 @@ unsigned char *buildsrcrte(struct in_addr dstaddr, struct in_addr routes[],
int allow_access(const union sockaddr_u *su);
+void ms_to_timeval(struct timeval *tv, long ms)
+ __attribute__ ((nonnull));
+
struct fdinfo {
int fd;
union sockaddr_u remoteaddr;
--
1.8.1.4