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 <a href="http://mina.apache.org">Apache MINA Project</a>
    33   * @see <a href="http://www.iana.org/assignments/port-numbers">IANA.org</a>
    34   */
    35  public class AvailablePortFinder {
    36      /**
    37       * The minimum number of server port number.
    38       */
    39      public static final int MIN_PORT_NUMBER = 1;
    40
    41      /**
    42       * The maximum number of server port number.
    43       */
    44      public static final int MAX_PORT_NUMBER = 49151;
    45
    46      /**
    47       * Creates a new instance.
    48       */
    49      private AvailablePortFinder() {
    50          // Do nothing
    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 an available port, selected by the system.
    66       *
    67       * @throws NoSuchElementException if there are no ports available
    68       */
    69      public static int getNextAvailable() {
    70          ServerSocket serverSocket = null;
    71
    72          try {
    73              // Here, we simply return an available port found by the system
    74              serverSocket = new ServerSocket(0);
    75              int port = serverSocket.getLocalPort();
    76
    77              // Don't forget to close the socket...
    78              serverSocket.close();
    79
    80              return port;
    81          } catch (IOException ioe) {
    82              throw new NoSuchElementException(ioe.getMessage());
    83          }
    84      }
    85
    86      /**
    87       * Gets the next available port starting at a port.
    88       *
    89       * @param fromPort the port to scan for availability
    90       * @throws NoSuchElementException if there are no ports available
    91       */
    92      public static int getNextAvailable(int fromPort) {
    93          if (fromPort < MIN_PORT_NUMBER || fromPort > MAX_PORT_NUMBER) {
    94              throw new IllegalArgumentException("Invalid start port: " + fromPort);
    95          }
    96
    97          for (int i = fromPort; i <= MAX_PORT_NUMBER; i++) {
    98              if (available(i)) {
    99                  return i;
    100             }
    101         }
    102
    103         throw new NoSuchElementException("Could not find an available port " + "above " + fromPort);
    104     }
    105
    106     /**
    107      * Checks to see if a specific port is available.
    108      *
    109      * @param port the port to check for availability
    110      */
    111     public static boolean available(int port) {
    112         if (port < MIN_PORT_NUMBER || port > MAX_PORT_NUMBER) {
    113             throw new IllegalArgumentException("Invalid start port: " + port);
    114         }
    115
    116         ServerSocket ss = null;
    117         DatagramSocket ds = null;
    118
    119         try {
    120             ss = new ServerSocket(port);
    121             ss.setReuseAddress(true);
    122             ds = new DatagramSocket(port);
    123             ds.setReuseAddress(true);
    124             return true;
    125         } catch (IOException e) {
    126             // Do nothing
    127         } finally {
    128             if (ds != null) {
    129                 ds.close();
    130             }
    131
    132             if (ss != null) {
    133                 try {
    134                     ss.close();
    135                 } catch (IOException e) {
    136                     /* should not be thrown */
    137                 }
    138             }
    139         }
    140
    141         return false;
    142     }
    143
    144     /**
    145      * Returns the {@link Set} of currently avaliable port numbers ({@link Integer})
    146      * between the specified port range.
    147      *
    148      * @throws IllegalArgumentException if port range is not between
    149      * {@link #MIN_PORT_NUMBER} and {@link #MAX_PORT_NUMBER} or
    150      * <code>fromPort</code> if greater than <code>toPort</code>.
    151      */
    152     public static Set<Integer> getAvailablePorts(int fromPort, int toPort) {
    153         if (fromPort < MIN_PORT_NUMBER || toPort > MAX_PORT_NUMBER || fromPort > toPort) {
    154             throw new IllegalArgumentException("Invalid port range: " + fromPort + " ~ " + toPort);
    155         }
    156
    157         Set<Integer> result = new TreeSet<Integer>();
    158
    159         for (int i = fromPort; i <= toPort; i++) {
    160             ServerSocket s = null;
    161
    162             try {
    163                 s = new ServerSocket(i);
    164                 result.add(new Integer(i));
    165             } catch (IOException e) {
    166                 // Do nothing
    167             } finally {
    168                 if (s != null) {
    169                     try {
    170                         s.close();
    171                     } catch (IOException e) {
    172                         /* should not be thrown */
    173                     }
    174                 }
    175             }
    176         }
    177
    178         return result;
    179     }
    180 }