Add some debug for NET-584

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/net/trunk@1786513 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/examples/ftp/FTPClientExample.java b/src/main/java/examples/ftp/FTPClientExample.java
index d906120..f4274c9 100644
--- a/src/main/java/examples/ftp/FTPClientExample.java
+++ b/src/main/java/examples/ftp/FTPClientExample.java
@@ -398,6 +398,10 @@
                 ftp.storeFile(remote, input);
 
                 input.close();
+
+                if (keepAliveTimeout > 0) {
+                    showCslStats(ftp);
+                }
             }
             // Allow multiple list types for single invocation
             else if (listFiles || mlsd || mdtm || mlst || listNames)
@@ -499,6 +503,10 @@
                 ftp.retrieveFile(remote, output);
 
                 output.close();
+               
+                if (keepAliveTimeout > 0) {
+                    showCslStats(ftp);
+                }
             }
 
             ftp.noop(); // check that control connection is working OK
@@ -534,6 +542,13 @@
         System.exit(error ? 1 : 0);
     } // end main
 
+    private static void showCslStats(FTPClient ftp) {
+        @SuppressWarnings("deprecation") // debug code
+        int []stats = ftp.getCslDebug();
+        System.out.println("CslDebug="+Arrays.toString(stats));
+        
+    }
+
     private static CopyStreamListener createListener(){
         return new CopyStreamListener(){
             private long megsTotal = 0;
diff --git a/src/main/java/org/apache/commons/net/ftp/FTPClient.java b/src/main/java/org/apache/commons/net/ftp/FTPClient.java
index 9bf723a..cca9058 100644
--- a/src/main/java/org/apache/commons/net/ftp/FTPClient.java
+++ b/src/main/java/org/apache/commons/net/ftp/FTPClient.java
@@ -405,6 +405,9 @@
     // Most FTP servers don't seem to support concurrent control and data connection usage
     private int __controlKeepAliveReplyTimeout=1000;
 
+    // Debug counts for NOOP acks
+    private int[] __cslDebug;
+
     /**
      * Enable or disable replacement of internal IP in passive mode. Default enabled
      * using {code NatServerResolverImpl}.
@@ -681,7 +684,7 @@
         {
             Util.closeQuietly(socket); // ignore close errors here
             if (csl != null) {
-                csl.cleanUp(); // fetch any outstanding keepalive replies
+                __cslDebug = csl.cleanUp(); // fetch any outstanding keepalive replies
             }
             throw e;
         }
@@ -1925,7 +1928,7 @@
             Util.closeQuietly(input);
             Util.closeQuietly(socket);
             if (csl != null) {
-                csl.cleanUp(); // fetch any outstanding keepalive replies
+                __cslDebug = csl.cleanUp(); // fetch any outstanding keepalive replies
             }
         }
 
@@ -3751,6 +3754,24 @@
     }
 
     /**
+     * Get the CSL debug array.
+     * <p>
+     * <b>For debug use only</b>
+     * <p>
+     * Currently contains:
+     * <ul>
+     * <li>successfully acked NOOPs at end of transfer</li>
+     * <li>unanswered NOOPs at end of transfer</li>
+     * <li>unanswered NOOPs after fetching additional replies</li>
+     * </ul>
+     * @return the debug array
+     * @deprecated 3.7 For testing only; may be dropped or changed at any time
+     */
+    @Deprecated // only for use in testing
+    public int[] getCslDebug() {
+        return __cslDebug;
+    }
+    /**
      * Set how long to wait for control keep-alive message replies.
      *
      * @param timeout number of milliseconds to wait (defaults to 1000)
@@ -3866,6 +3887,7 @@
 
         private long time = System.currentTimeMillis();
         private int notAcked;
+        private int acksAcked;
 
         CSL(FTPClient parent, long idleTime, int maxWait) throws SocketException {
             this.idle = idleTime;
@@ -3886,6 +3908,7 @@
             if (now - time > idle) {
                 try {
                     parent.__noop();
+                    acksAcked++;
                 } catch (SocketTimeoutException e) {
                     notAcked++;
                 } catch (IOException e) {
@@ -3895,13 +3918,15 @@
             }
         }
 
-        void cleanUp() throws IOException {
+        int[] cleanUp() throws IOException {
+            int remain = notAcked;
             if (notAcked > 0) { // TODO remove this before next release!
                 System.err.println("NET-584: notAcked=" + notAcked);
             }
             try {
-                while(notAcked-- > 0) {
+                while(notAcked > 0) {
                     parent.__getReplyNoReport();
+                    notAcked--; // only decrement if actually received
                 }
             } catch (SocketTimeoutException e) { // NET-584
                 System.err.println("NET-584: ignoring " + e.getMessage()); // TODO remove print before release!
@@ -3909,6 +3934,7 @@
             } finally {
                 parent.setSoTimeout(currentSoTimeout);
             }
+            return new int [] {acksAcked, remain, notAcked}; // debug counts
         }
 
     }