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 }