View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.mina.util;
21  
22  import java.io.IOException;
23  import java.net.DatagramSocket;
24  import java.net.ServerSocket;
25  import java.util.NoSuchElementException;
26  import java.util.Set;
27  import java.util.TreeSet;
28  
29  /**
30   * Finds currently available server ports.
31   *
32   * @author The Apache MINA Project (dev@mina.apache.org)
33   * @version $Rev: 576217 $
34   * @see <a href="http://www.iana.org/assignments/port-numbers">IANA.org</a>
35   */
36  public class AvailablePortFinder {
37      /**
38       * The minimum number of server port number.
39       */
40      public static final int MIN_PORT_NUMBER = 1;
41  
42      /**
43       * The maximum number of server port number.
44       */
45      public static final int MAX_PORT_NUMBER = 49151;
46  
47      /**
48       * Creates a new instance.
49       */
50      private AvailablePortFinder() {
51      }
52  
53      /**
54       * Returns the {@link Set} of currently available port numbers
55       * ({@link Integer}).  This method is identical to
56       * <code>getAvailablePorts(MIN_PORT_NUMBER, MAX_PORT_NUMBER)</code>.
57       *
58       * WARNING: this can take a very long time.
59       */
60      public static Set<Integer> getAvailablePorts() {
61          return getAvailablePorts(MIN_PORT_NUMBER, MAX_PORT_NUMBER);
62      }
63  
64      /**
65       * Gets the next available port starting at the lowest port number.
66       *
67       * @throws NoSuchElementException if there are no ports available
68       */
69      public static int getNextAvailable() {
70          return getNextAvailable(MIN_PORT_NUMBER);
71      }
72  
73      /**
74       * Gets the next available port starting at a port.
75       *
76       * @param fromPort the port to scan for availability
77       * @throws NoSuchElementException if there are no ports available
78       */
79      public static int getNextAvailable(int fromPort) {
80          if (fromPort < MIN_PORT_NUMBER || fromPort > MAX_PORT_NUMBER) {
81              throw new IllegalArgumentException("Invalid start port: "
82                      + fromPort);
83          }
84  
85          for (int i = fromPort; i <= MAX_PORT_NUMBER; i++) {
86              if (available(i)) {
87                  return i;
88              }
89          }
90  
91          throw new NoSuchElementException("Could not find an available port "
92                  + "above " + fromPort);
93      }
94  
95      /**
96       * Checks to see if a specific port is available.
97       *
98       * @param port the port to check for availability
99       */
100     public static boolean available(int port) {
101         if (port < MIN_PORT_NUMBER || port > MAX_PORT_NUMBER) {
102             throw new IllegalArgumentException("Invalid start port: " + port);
103         }
104 
105         ServerSocket ss = null;
106         DatagramSocket ds = null;
107         try {
108             ss = new ServerSocket(port);
109             ss.setReuseAddress(true);
110             ds = new DatagramSocket(port);
111             ds.setReuseAddress(true);
112             return true;
113         } catch (IOException e) {
114         } finally {
115             if (ds != null) {
116                 ds.close();
117             }
118 
119             if (ss != null) {
120                 try {
121                     ss.close();
122                 } catch (IOException e) {
123                     /* should not be thrown */
124                 }
125             }
126         }
127 
128         return false;
129     }
130 
131     /**
132      * Returns the {@link Set} of currently avaliable port numbers ({@link Integer})
133      * between the specified port range.
134      *
135      * @throws IllegalArgumentException if port range is not between
136      * {@link #MIN_PORT_NUMBER} and {@link #MAX_PORT_NUMBER} or
137      * <code>fromPort</code> if greater than <code>toPort</code>.
138      */
139     public static Set<Integer> getAvailablePorts(int fromPort, int toPort) {
140         if (fromPort < MIN_PORT_NUMBER || toPort > MAX_PORT_NUMBER
141                 || fromPort > toPort) {
142             throw new IllegalArgumentException("Invalid port range: "
143                     + fromPort + " ~ " + toPort);
144         }
145 
146         Set<Integer> result = new TreeSet<Integer>();
147 
148         for (int i = fromPort; i <= toPort; i++) {
149             ServerSocket s = null;
150 
151             try {
152                 s = new ServerSocket(i);
153                 result.add(new Integer(i));
154             } catch (IOException e) {
155             } finally {
156                 if (s != null) {
157                     try {
158                         s.close();
159                     } catch (IOException e) {
160                         /* should not be thrown */
161                     }
162                 }
163             }
164         }
165 
166         return result;
167     }
168 }