/* * Jitsi, the OpenSource Java VoIP and Instant Messaging client. * * Copyright @ 2015 Atlassian Pty Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.java.sip.communicator.util; /** * The PortTracker class allows for a controlled selection of bind * ports. This is typically useful in cases where we would like to set bounds * for the ports that we are going to use for a particular socket. For example, * at the time of writing of this class, this policy allows Jitsi to bind RTP * sockets on ports that are always between 5000 and 6000 (default values). It * is also used to allow for different port ranges for Audio and Video streams. * * @author Emil Ivov */ public class PortTracker { /** * The local logger. */ private static final Logger logger = Logger.getLogger(NetworkUtils.class); /** * The minimum port number that this allocator would be allocate to return. */ private int minPort = NetworkUtils.MIN_PORT_NUMBER; /** * The maximum port number that this allocator would be allocate to return. */ private int maxPort = NetworkUtils.MAX_PORT_NUMBER; /** * The next port that we will return if asked. */ private int port = -1; /** * Initializes a port tracker with the specified port range. * * @param minPort the minimum port that we would like to bind on * @param maxPort the maximum port that we would like to bind on */ public PortTracker(int minPort, int maxPort) { setRange(minPort, maxPort); } /** * Returns the next port that the using class is supposed to try allocating. * * @return the next port that the using class is supposed to try allocating. */ public int getPort() { return port; } /** * (Re)Sets the range that this tracker returns values in. The method would * also update the value of the next port to allocate in case it is * currently outside the specified range. The method also allows configuring * this allocator in a way that it would always return the same port. This * would happen when newMinPort is equal to newMaxPort * which would make both equal to the only possible value. * * @param newMinPort the minimum port that we would like to bind on * @param newMaxPort the maximum port that we would like to bind on * * @throws IllegalArgumentException if the arguments do not correspond to * valid port numbers, or in case newMaxPort < newMinPort */ public void setRange(int newMinPort, int newMaxPort) throws IllegalArgumentException { //validate if((newMaxPort < newMinPort) || !NetworkUtils.isValidPortNumber(newMinPort) || !NetworkUtils.isValidPortNumber(newMaxPort)) { throw new IllegalArgumentException( "[" + newMinPort + ", " + newMaxPort + "] is not a valid port range."); } //reset bounds minPort = newMinPort; maxPort = newMaxPort; /* * Make sure that nextPort is within the specified range. Preserve value * if already valid. */ if (port < minPort || port > maxPort) port = minPort; } /** * Attempts to set the range specified by the min and max port string * params. If the attempt fails, for reasons such as invalid porameters, * this method will simply return without an exception and without an impact * on the state of this class. * * @param newMinPort the minimum port that we would like to bind on * @param newMaxPort the maximum port that we would like to bind on */ public void tryRange(String newMinPort, String newMaxPort) { try { setRange( Integer.parseInt(newMinPort), Integer.parseInt(newMaxPort)); } catch(Exception e)//Null, NumberFormat, IllegalArgument { logger.info( "Ignoring invalid port range [" + newMinPort + ", " + newMaxPort + "]"); if (logger.isDebugEnabled()) logger.debug("Cause: ", e); } } /** * Sets the next port to specified value unless allowing the caller to * request validation and force the port into the range that this tracker * operates in. * * @param nextPort the next port we'd like this tracker to return. * @param validate determines whether this tracker should bring the new * value into its current range. */ public void setNextPort(int nextPort, boolean validate) { /* * Make sure that nextPort is within the specified range unless */ if ((nextPort < minPort || nextPort > maxPort ) && validate) { port = minPort; } else { this.port = nextPort; } } /** * Sets the next port to specified value unless it is outside the range that * this tracker operates in, in which case it sets it to the minimal * possible. * * @param nextPort the next port we'd like this tracker to return. */ public void setNextPort(int nextPort) { setNextPort(nextPort, true); } /** * Returns the lowest/minimum port that this tracker would use. * * @return the minimum port number allowed by this tracker. */ public int getMinPort() { return minPort; } /** * Returns the highest/maximum port that this tracker would use. * * @return the maximum port number allowed by this tracker. */ public int getMaxPort() { return maxPort; } /** * Attempts to create a port tracker that uses the min and max values * indicated by the newMinPortString and newMinPortString * strings and returns it if successful. The method fails silently * (returning null) otherwise. * * @param newMinPortString the {@link String} containing the minimum port * number that this tracker should allow. * @param newMaxPortString the {@link String} containing the minimum port * number that this tracker should allow. * * @return the newly created port tracker or null if the string * params do not contain valid port numbers. */ public static PortTracker createTracker(String newMinPortString, String newMaxPortString) { try { int minPort = Integer.parseInt(newMinPortString); int maxPort = Integer.parseInt(newMaxPortString); return new PortTracker(minPort, maxPort); } catch(Exception exc)//Null, NumberFormat, IllegalArgument { logger.info("Ignoring invalid port range ["+ newMinPortString + " to " + newMaxPortString +"]"); logger.debug("Cause: ", exc); return null; } } }