incubator-ftpserver-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From n..@apache.org
Subject svn commit: r491204 - in /incubator/ftpserver/trunk/core/src: java/org/apache/ftpserver/PassivePorts.java test/org/apache/ftpserver/PassivePortsTest.java
Date Sat, 30 Dec 2006 10:01:47 GMT
Author: ngn
Date: Sat Dec 30 02:01:46 2006
New Revision: 491204

URL: http://svn.apache.org/viewvc?view=rev&rev=491204
Log:
Adding support for specifying passive port ranges. All combinations of single ports, multiple
ports and ranges (both open ended and closed) are supported. The current implementation is
somewhat naive and can be improved for better performance and memory usage in the future

Modified:
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/PassivePorts.java
    incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/PassivePortsTest.java

Modified: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/PassivePorts.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/PassivePorts.java?view=diff&rev=491204&r1=491203&r2=491204
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/PassivePorts.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/PassivePorts.java Sat Dec
30 02:01:46 2006
@@ -19,6 +19,9 @@
 
 package org.apache.ftpserver;
 
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
 import java.util.StringTokenizer;
 
 
@@ -28,41 +31,121 @@
  */
 public class PassivePorts {
 
-    private int[][] passivePorts;
+    private static final int MAX_PORT = 65535;
+    private int[] passivePorts;
+    private boolean[] reservedPorts;
     
     /**
      * Parse a string containing passive ports
      * @param portsString A string of passive ports, can contain a single
-     *   port (as an integer) or multiple ports seperated by commas
+     *   port (as an integer), multiple ports seperated by commas (e.g. 123,124,125) 
+     *   or ranges of ports, including open ended ranges (e.g. 123-125, 30000-, -1023).
+     *   Combinations for single ports and ranges is also supported.
      * @return An instance of {@link PassivePorts} based on the parsed string
-     * @throws NumberFormatException If any of of the ports in the string is
-     *   invalid (e.g. not an integer) 
+     * @throws IllegalArgumentException If any of of the ports in the string is
+     *   invalid (e.g. not an integer or too large for a port number) 
      */
     public static PassivePorts parse(String portsString) {
-        int[][] passivePorts;
+        List passivePortsList = new ArrayList();
         
-        StringTokenizer st = new StringTokenizer(portsString, " ,;\t\n\r\f");
-        passivePorts = new int[st.countTokens()][2];
-        for(int i=0; i<passivePorts.length; i++) {
-            passivePorts[i][0] = Integer.parseInt(st.nextToken());
-            passivePorts[i][1] = 0;
+        boolean inRange = false;
+        Integer lastPort = new Integer(1);
+        StringTokenizer st = new StringTokenizer(portsString, ",;-", true);
+        while(st.hasMoreTokens()) {
+            String token = st.nextToken().trim();
+
+            if(",".equals(token) || ";".equals(token)) {
+                if(inRange) {
+                    fillRange(passivePortsList, lastPort, new Integer(MAX_PORT));
+                }
+                
+                // reset state
+                lastPort = new Integer(1);
+                inRange = false;
+            } else if("-".equals(token)) {
+                inRange = true;
+            } else if(token.length() == 0) {
+                // ignore whitespace
+            } else {
+                Integer port = Integer.valueOf(token);
+                
+                verifyPort(port.intValue());
+                
+                if(inRange) {
+                    // add all numbers from last int
+                    fillRange(passivePortsList, lastPort, port);
+                    
+                    inRange = false;
+                }
+                
+                addPort(passivePortsList, port);
+                
+                lastPort = port;
+            }
+        }
+        
+        if(inRange) {
+            fillRange(passivePortsList, lastPort, new Integer(MAX_PORT));
+        }
+        
+        int[] passivePorts = new int[passivePortsList.size()];
+        
+        Iterator iter = passivePortsList.iterator();
+        
+        int counter = 0;
+        while (iter.hasNext()) {
+            Integer port = (Integer) iter.next();
+            passivePorts[counter] = port.intValue();
+            counter++;
         }
         
         return new PassivePorts(passivePorts);
     }
+
+    /**
+     * Fill a range of ports
+     */
+    private static void fillRange(List passivePortsList, Integer beginPort, Integer endPort)
{
+        for(int i = beginPort.intValue(); i<=endPort.intValue(); i++ ) {
+            Integer rangePort = Integer.valueOf(i);
+            addPort(passivePortsList, rangePort);
+        }
+    }
+
+    /**
+     * Add a single port if not already in list
+     */
+    private static void addPort(List passivePortsList, Integer rangePort) {
+        if(!passivePortsList.contains(rangePort)) {
+            passivePortsList.add(rangePort);
+        }
+    }
     
-    private PassivePorts(int[][] passivePorts) {
+    /**
+     * Verify that the port is within the range of allowed ports
+     */
+    private static void verifyPort(int port) {
+        if(port < 0) {
+            throw new IllegalArgumentException("Port can not be negative: " + port);
+        } else if(port > MAX_PORT) {
+            throw new IllegalArgumentException("Port too large: " + port);
+        }
+    }
+    
+    private PassivePorts(int[] passivePorts) {
         this.passivePorts = passivePorts;
+        
+        reservedPorts = new boolean[passivePorts.length];
     }
     
     public int reserveNextPort() {
         // search for a free port            
         for(int i=0; i<passivePorts.length; i++) {
-            if(passivePorts[i][1] == 0) {
-                if(passivePorts[i][0] != 0) {
-                    passivePorts[i][1] = 1;
+            if(!reservedPorts[i]) {
+                if(passivePorts[i] != 0) {
+                    reservedPorts[i] = true;
                 }
-                return passivePorts[i][0];
+                return passivePorts[i];
             }
         }
         
@@ -71,8 +154,8 @@
     
     public void releasePort(int port) {
         for(int i=0; i<passivePorts.length; i++) {
-            if(passivePorts[i][0] == port) {
-                passivePorts[i][1] = 0;
+            if(passivePorts[i] == port) {
+                reservedPorts[i] = false;
                 break;
             }
         }

Modified: incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/PassivePortsTest.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/PassivePortsTest.java?view=diff&rev=491204&r1=491203&r2=491204
==============================================================================
--- incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/PassivePortsTest.java (original)
+++ incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/PassivePortsTest.java Sat
Dec 30 02:01:46 2006
@@ -31,13 +31,159 @@
         assertEquals(-1, ports.reserveNextPort());
     }
 
+    public void testParseMaxValue() {
+        PassivePorts ports = PassivePorts.parse("65535");
+        
+        assertEquals(65535, ports.reserveNextPort());
+        assertEquals(-1, ports.reserveNextPort());
+    }
+
+    public void testParseMinValue() {
+        PassivePorts ports = PassivePorts.parse("0");
+        
+        assertEquals(0, ports.reserveNextPort());
+        assertEquals(0, ports.reserveNextPort());
+        assertEquals(0, ports.reserveNextPort());
+        assertEquals(0, ports.reserveNextPort());
+        // should return 0 forever
+    }
+
+    public void testParseTooLargeValue() {
+        try {
+            PassivePorts.parse("65536");
+            fail("Must fail due to too high port number");
+        } catch(IllegalArgumentException e) {
+            // ok
+        }
+    }
+
+    public void testParseNonNumericValue() {
+        try {
+            PassivePorts.parse("foo");
+            fail("Must fail due to non numerical port number");
+        } catch(IllegalArgumentException e) {
+            // ok
+        }
+    }
+    
     public void testParseListOfValues() {
-        PassivePorts ports = PassivePorts.parse("123, 456,789");
+        PassivePorts ports = PassivePorts.parse("123, 456,\t\n789");
+
+        assertEquals(123, ports.reserveNextPort());
+        assertEquals(456, ports.reserveNextPort());
+        assertEquals(789, ports.reserveNextPort());
+        assertEquals(-1, ports.reserveNextPort());
+    }
 
+    public void testParseListOfValuesOrder() {
+        PassivePorts ports = PassivePorts.parse("123, 789, 456");
         
         assertEquals(123, ports.reserveNextPort());
+        assertEquals(789, ports.reserveNextPort());
         assertEquals(456, ports.reserveNextPort());
+        assertEquals(-1, ports.reserveNextPort());
+    }
+    
+    public void testParseListOfValuesDuplicate() {
+        PassivePorts ports = PassivePorts.parse("123, 789, 456, 789");
+        
+        assertEquals(123, ports.reserveNextPort());
         assertEquals(789, ports.reserveNextPort());
+        assertEquals(456, ports.reserveNextPort());
+        assertEquals(-1, ports.reserveNextPort());
+    }
+    
+    public void testParseSimpleRange() {
+        PassivePorts ports = PassivePorts.parse("123-125");
+        
+        assertEquals(123, ports.reserveNextPort());
+        assertEquals(124, ports.reserveNextPort());
+        assertEquals(125, ports.reserveNextPort());
+        assertEquals(-1, ports.reserveNextPort());
+    }
+
+    public void testParseMultipleRanges() {
+        PassivePorts ports = PassivePorts.parse("123-125, 127-128, 130-132");
+        
+        assertEquals(123, ports.reserveNextPort());
+        assertEquals(124, ports.reserveNextPort());
+        assertEquals(125, ports.reserveNextPort());
+        assertEquals(127, ports.reserveNextPort());
+        assertEquals(128, ports.reserveNextPort());
+        assertEquals(130, ports.reserveNextPort());
+        assertEquals(131, ports.reserveNextPort());
+        assertEquals(132, ports.reserveNextPort());
+        assertEquals(-1, ports.reserveNextPort());
+    }
+    
+    public void testParseMixedRangeAndSingle() {
+        PassivePorts ports = PassivePorts.parse("123-125, 126, 128-129");
+        
+        assertEquals(123, ports.reserveNextPort());
+        assertEquals(124, ports.reserveNextPort());
+        assertEquals(125, ports.reserveNextPort());
+        assertEquals(126, ports.reserveNextPort());
+        assertEquals(128, ports.reserveNextPort());
+        assertEquals(129, ports.reserveNextPort());
+        assertEquals(-1, ports.reserveNextPort());
+    }
+
+    public void testParseOverlapingRanges() {
+        PassivePorts ports = PassivePorts.parse("123-125, 124-126");
+        
+        assertEquals(123, ports.reserveNextPort());
+        assertEquals(124, ports.reserveNextPort());
+        assertEquals(125, ports.reserveNextPort());
+        assertEquals(126, ports.reserveNextPort());
+        assertEquals(-1, ports.reserveNextPort());
+    }
+
+    public void testParseOverlapingRangesorder() {
+        PassivePorts ports = PassivePorts.parse("124-126, 123-125");
+        
+        assertEquals(124, ports.reserveNextPort());
+        assertEquals(125, ports.reserveNextPort());
+        assertEquals(126, ports.reserveNextPort());
+        assertEquals(123, ports.reserveNextPort());
+        assertEquals(-1, ports.reserveNextPort());
+    }
+
+    public void testParseOpenLowerRange() {
+        PassivePorts ports = PassivePorts.parse("9, -3");
+        
+        assertEquals(9, ports.reserveNextPort());
+        assertEquals(1, ports.reserveNextPort());
+        assertEquals(2, ports.reserveNextPort());
+        assertEquals(3, ports.reserveNextPort());
+        assertEquals(-1, ports.reserveNextPort());
+    }
+
+    public void testParseOpenUpperRange() {
+        PassivePorts ports = PassivePorts.parse("65533-");
+        
+        assertEquals(65533, ports.reserveNextPort());
+        assertEquals(65534, ports.reserveNextPort());
+        assertEquals(65535, ports.reserveNextPort());
+        assertEquals(-1, ports.reserveNextPort());
+    }
+    
+    public void testParseOpenUpperRange3() {
+        PassivePorts ports = PassivePorts.parse("65533-, 65532-");
+        
+        assertEquals(65533, ports.reserveNextPort());
+        assertEquals(65534, ports.reserveNextPort());
+        assertEquals(65535, ports.reserveNextPort());
+        assertEquals(65532, ports.reserveNextPort());
+        assertEquals(-1, ports.reserveNextPort());
+    }
+    
+    public void testParseOpenUpperRange2() {
+        PassivePorts ports = PassivePorts.parse("65533-, 1");
+        
+        assertEquals(65533, ports.reserveNextPort());
+        assertEquals(65534, ports.reserveNextPort());
+        assertEquals(65535, ports.reserveNextPort());
+        assertEquals(1, ports.reserveNextPort());
         assertEquals(-1, ports.reserveNextPort());
     }
 



Mime
View raw message