Blob Blame History Raw
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