All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.grizzly.PortRange Maven / Gradle / Ivy

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);
    }
}