diff -rNu orig/com/sun/grizzly/PortRange.java src/com/sun/grizzly/PortRange.java --- orig/com/sun/grizzly/PortRange.java 1970-01-01 01:00:00.000000000 +0100 +++ src/com/sun/grizzly/PortRange.java 2009-09-01 15:07:42.000000000 +0200 @@ -0,0 +1,265 @@ +package com.sun.grizzly; + +import java.io.IOException; +import java.net.BindException; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.Random; +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +/** + * Immutable class representing a port range. + * @author: Gerd Behrmann + * @author: Tigran Mkrtchyan + */ +public class PortRange +{ + /** Pattern matching [:] */ + private final static Pattern FORMAT = + Pattern.compile("(\\d+)(?:(?:,|:)(\\d+))?"); + + private final int lower; + private final int upper; + /** + * Random number generator used when binding sockets. + */ + private final static Random _random = new Random(); + + /** + * Creates a port range with the given bounds (both inclusive). + * + * @throws IllegalArgumentException is either bound is not between + * 0 and 65535, or if high is lower than + * low. + */ + public PortRange(int low, int high) + { + if (low < 0 || high < low || 65535 < high) { + throw new IllegalArgumentException("Invalid range"); + } + lower = low; + upper = high; + } + + /** + * Creates a port range containing a single port. + */ + public PortRange(int port) + { + this(port, port); + } + + /** + * Parse a port range. A port range consists of either a single + * integer, or two integers separated by either a comma or a + * colon. + * + * The bounds must be between 0 and 65535, both inclusive. + * + * @return The port range represented by s. Returns + * the range [0,0] if s is null or empty. + */ + public static PortRange valueOf(String s) + throws IllegalArgumentException + { + try { + Matcher m = FORMAT.matcher(s); + + if (!m.matches()) { + throw new IllegalArgumentException("Invalid range: " + s); + } + + int low = Integer.parseInt(m.group(1)); + int high = + (m.groupCount() == 1) ? low : Integer.parseInt(m.group(2)); + + return new PortRange(low, high); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Invalid range: " + s); + } + } + + /** + * Returns a random port within the range. + */ + public int random() + { + return _random.nextInt(upper - lower + 1) + lower; + } + + /** + * Returns the successor of a port within the range, wrapping + * around to the lowest port if necessary. + */ + public int succ(int port) + { + return (port < upper ? port + 1 : (int) lower); + } + + public int getLower() { + return lower; + } + + public int getUpper() { + return upper; + } + /** + * Binds socket to endpoint. If the + * port in endpoint is zero, then a port is chosen + * from this port range. If the port range is [0,0], then a free + * port is chosen by the OS. + * + * @throws IOException if the bind operation fails, or if the + * socket is already bound. + */ + public void bind(ServerSocket socket, InetSocketAddress endpoint, int backLog) + throws IOException + { + int port = endpoint.getPort(); + PortRange range = (port > 0) ? new PortRange(port) : this; + range.bind(socket, endpoint.getAddress(), backLog); + } + + /** + * Binds socket to endpoint. If the + * port in endpoint is zero, then a port is chosen + * from this port range. If the port range is [0,0], then a free + * port is chosen by the OS. + * + * @throws IOException if the bind operation fails, or if the + * socket is already bound. + */ + public void bind(Socket socket, InetSocketAddress endpoint) + throws IOException + { + int port = endpoint.getPort(); + PortRange range = (port > 0) ? new PortRange(port) : this; + range.bind(socket, endpoint.getAddress()); + } + + /** + * Binds socket to address. A port is + * chosen from this port range. If the port range is [0,0], then a + * free port is chosen by the OS. + * + * @throws IOException if the bind operation fails, or if the + * socket is already bound. + */ + public void bind(ServerSocket socket, InetAddress address, int backLog) + throws IOException + { + int start = random(); + int port = start; + do { + try { + socket.bind(new InetSocketAddress(address, port), backLog); + return; + } catch (BindException e) { + } + port = succ(port); + } while (port != start); + + throw new BindException("No free port within range"); + } + + /** + * Binds socket to address. A port is + * chosen from this port range. If the port range is [0,0], then a + * free port is chosen by the OS. + * + * @throws IOException if the bind operation fails, or if the + * socket is already bound. + */ + public void bind(Socket socket, InetAddress address) + throws IOException + { + int start = random(); + int port = start; + do { + try { + socket.bind(new InetSocketAddress(address, port)); + return; + } catch (BindException e) { + } + port = succ(port); + } while (port != start); + + throw new BindException("No free port within range"); + } + + /** + * Binds socket to address. A port is + * chosen from this port range. If the port range is [0,0], then a + * free port is chosen by the OS. + * + * @throws IOException if the bind operation fails, or if the + * socket is already bound. + */ + public void bind(DatagramSocket socket, InetAddress address) + throws IOException { + int start = random(); + int port = start; + do { + try { + socket.bind(new InetSocketAddress(address, port)); + return; + } catch (BindException e) { + } + port = succ(port); + } while (port != start); + + throw new BindException("No free port within range"); + } + + /** + * Binds socket to the wildcard + * address. A port is chosen from this port range. If + * the port range is [0,0], then a free port is chosen by the OS. + * + * @throws IOException if the bind operation fails, or if the + * socket is already bound. + */ + public void bind(DatagramSocket socket) + throws IOException { + bind(socket, (InetAddress) null); + } + + /** + * Binds socket to the wildcard + * address. A port is chosen from this port range. If + * the port range is [0,0], then a free port is chosen by the OS. + * + * @throws IOException if the bind operation fails, or if the + * socket is already bound. + */ + public void bind(ServerSocket socket, int backLog) + throws IOException + { + bind(socket, (InetAddress) null, 50); + } + + /** + * Binds socket to the wildcard + * address. A port is chosen from this port range. If + * the port range is [0,0], then a free port is chosen by the OS. + * + * @throws IOException if the bind operation fails, or if the + * socket is already bound. + */ + public void bind(Socket socket) + throws IOException + { + bind(socket, (InetAddress) null); + } + + + @Override + public String toString() + { + return String.format("%d:%d", lower, upper); + } +} \ No newline at end of file diff -rNu orig/com/sun/grizzly/TCPSelectorHandler.java src/com/sun/grizzly/TCPSelectorHandler.java --- orig/com/sun/grizzly/TCPSelectorHandler.java 2009-08-11 18:05:16.000000000 +0200 +++ src/com/sun/grizzly/TCPSelectorHandler.java 2009-09-01 15:06:22.000000000 +0200 @@ -54,7 +54,6 @@ import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; -import java.net.InetSocketAddress; import java.net.SocketAddress; import java.net.SocketException; import java.nio.channels.CancelledKeyException; @@ -182,12 +181,15 @@ */ protected InetAddress inet; - /** - * The default TCP port. + * Port to witch serverSocket is bound. */ - protected int port = 18888; + int port = -1; + /** + * The default port range. + */ + protected PortRange portRange = new PortRange(18888); /** * The ServerSocket instance. @@ -326,7 +328,7 @@ copyHandler.selectTimeout = selectTimeout; copyHandler.serverTimeout = serverTimeout; copyHandler.inet = inet; - copyHandler.port = port; + copyHandler.portRange = portRange; copyHandler.ssBackLog = ssBackLog; copyHandler.tcpNoDelay = tcpNoDelay; copyHandler.linger = linger; @@ -417,9 +419,9 @@ } serverSocket.setReuseAddress(reuseAddress); if ( inet == null){ - serverSocket.bind(new InetSocketAddress(port),ssBackLog); + portRange.bind(serverSocket,ssBackLog ); } else { - serverSocket.bind(new InetSocketAddress(inet,port),ssBackLog); + portRange.bind(serverSocket,inet, ssBackLog ); } serverSocketChannel.configureBlocking(false); @@ -1174,6 +1176,15 @@ public void setPort(int port) { this.port = port; + this.portRange = new PortRange(port); + } + + public PortRange getPortRange() { + return portRange; + } + + public void setPortRange(PortRange portRange) { + this.portRange = portRange; } public int getSsBackLog() { diff -rNu orig/com/sun/grizzly/UDPSelectorHandler.java src/com/sun/grizzly/UDPSelectorHandler.java --- orig/com/sun/grizzly/UDPSelectorHandler.java 2009-08-11 18:05:16.000000000 +0200 +++ src/com/sun/grizzly/UDPSelectorHandler.java 2009-09-01 14:45:24.000000000 +0200 @@ -44,7 +44,6 @@ import java.io.IOException; import java.net.BindException; import java.net.DatagramSocket; -import java.net.InetSocketAddress; import java.net.SocketAddress; import java.net.SocketException; import java.nio.channels.DatagramChannel; @@ -163,10 +162,11 @@ } } datagramSocket.setReuseAddress(reuseAddress); - if (inet == null) - datagramSocket.bind(new InetSocketAddress(port)); - else - datagramSocket.bind(new InetSocketAddress(inet,port)); + if (inet == null) { + portRange.bind(datagramSocket); + } else { + portRange.bind(datagramSocket, inet); + } datagramChannel.configureBlocking(false); datagramChannel.register( selector, SelectionKey.OP_READ );