001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: *
019: */
020: package org.apache.mina.util;
021:
022: import java.io.IOException;
023: import java.net.DatagramSocket;
024: import java.net.ServerSocket;
025: import java.util.NoSuchElementException;
026: import java.util.Set;
027: import java.util.TreeSet;
028:
029: /**
030: * Finds currently available server ports.
031: *
032: * @author The Apache MINA Project (dev@mina.apache.org)
033: * @version $Rev: 576217 $
034: * @see <a href="http://www.iana.org/assignments/port-numbers">IANA.org</a>
035: */
036: public class AvailablePortFinder {
037: /**
038: * The minimum number of server port number.
039: */
040: public static final int MIN_PORT_NUMBER = 1;
041:
042: /**
043: * The maximum number of server port number.
044: */
045: public static final int MAX_PORT_NUMBER = 49151;
046:
047: /**
048: * Creates a new instance.
049: */
050: private AvailablePortFinder() {
051: }
052:
053: /**
054: * Returns the {@link Set} of currently available port numbers
055: * ({@link Integer}). This method is identical to
056: * <code>getAvailablePorts(MIN_PORT_NUMBER, MAX_PORT_NUMBER)</code>.
057: *
058: * WARNING: this can take a very long time.
059: */
060: public static Set<Integer> getAvailablePorts() {
061: return getAvailablePorts(MIN_PORT_NUMBER, MAX_PORT_NUMBER);
062: }
063:
064: /**
065: * Gets the next available port starting at the lowest port number.
066: *
067: * @throws NoSuchElementException if there are no ports available
068: */
069: public static int getNextAvailable() {
070: return getNextAvailable(MIN_PORT_NUMBER);
071: }
072:
073: /**
074: * Gets the next available port starting at a port.
075: *
076: * @param fromPort the port to scan for availability
077: * @throws NoSuchElementException if there are no ports available
078: */
079: public static int getNextAvailable(int fromPort) {
080: if (fromPort < MIN_PORT_NUMBER || fromPort > MAX_PORT_NUMBER) {
081: throw new IllegalArgumentException("Invalid start port: "
082: + fromPort);
083: }
084:
085: for (int i = fromPort; i <= MAX_PORT_NUMBER; i++) {
086: if (available(i)) {
087: return i;
088: }
089: }
090:
091: throw new NoSuchElementException(
092: "Could not find an available port " + "above "
093: + fromPort);
094: }
095:
096: /**
097: * Checks to see if a specific port is available.
098: *
099: * @param port the port to check for availability
100: */
101: public static boolean available(int port) {
102: if (port < MIN_PORT_NUMBER || port > MAX_PORT_NUMBER) {
103: throw new IllegalArgumentException("Invalid start port: "
104: + port);
105: }
106:
107: ServerSocket ss = null;
108: DatagramSocket ds = null;
109: try {
110: ss = new ServerSocket(port);
111: ss.setReuseAddress(true);
112: ds = new DatagramSocket(port);
113: ds.setReuseAddress(true);
114: return true;
115: } catch (IOException e) {
116: } finally {
117: if (ds != null) {
118: ds.close();
119: }
120:
121: if (ss != null) {
122: try {
123: ss.close();
124: } catch (IOException e) {
125: /* should not be thrown */
126: }
127: }
128: }
129:
130: return false;
131: }
132:
133: /**
134: * Returns the {@link Set} of currently avaliable port numbers ({@link Integer})
135: * between the specified port range.
136: *
137: * @throws IllegalArgumentException if port range is not between
138: * {@link #MIN_PORT_NUMBER} and {@link #MAX_PORT_NUMBER} or
139: * <code>fromPort</code> if greater than <code>toPort</code>.
140: */
141: public static Set<Integer> getAvailablePorts(int fromPort,
142: int toPort) {
143: if (fromPort < MIN_PORT_NUMBER || toPort > MAX_PORT_NUMBER
144: || fromPort > toPort) {
145: throw new IllegalArgumentException("Invalid port range: "
146: + fromPort + " ~ " + toPort);
147: }
148:
149: Set<Integer> result = new TreeSet<Integer>();
150:
151: for (int i = fromPort; i <= toPort; i++) {
152: ServerSocket s = null;
153:
154: try {
155: s = new ServerSocket(i);
156: result.add(new Integer(i));
157: } catch (IOException e) {
158: } finally {
159: if (s != null) {
160: try {
161: s.close();
162: } catch (IOException e) {
163: /* should not be thrown */
164: }
165: }
166: }
167: }
168:
169: return result;
170: }
171: }
|