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 Directory Project (mina-dev@directory.apache.org)
    33   * @version $Rev: 555855 $
    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 }