/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* Copyright (C) 2005 - Matteo Merli - matteo.merli@gmail.com *
* *
***************************************************************************/
/*
* $Id: PortManager.java 293 2005-11-24 19:50:47Z merlimat $
*
* $URL: http://svn.berlios.de/svnroot/repos/rtspproxy/tags/3.0-ALPHA2/src/main/java/rtspproxy/lib/PortManager.java $
*
*/
package video.lib;
import java.io.IOException;
import java.net.DatagramSocket;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.apache.log4j.Logger;
/**
* The PortManager will keep a list of reserved ports
*/
public class PortManager
{
private static Logger log = Logger.getLogger( PortManager.class );
protected static final int minUdpPort = 6790;
protected static final int maxUdpPort = 49151;
private static Set<Integer> reservedPorts = Collections.synchronizedSet( new HashSet<Integer>() );
// TODO: Using custom exceptions
public static synchronized void reservePort( int port ) throws Exception
{
if ( reservedPorts.contains( port ) )
throw new Exception( "Port " + port + "is reserved" );
reservedPorts.add( port );
}
public static synchronized void removePort( int port )
{
reservedPorts.remove( port );
}
/**
* @param port
* To port to be tested
* @return true if the port is already reserved, false if the port can be
* used.
*/
public static synchronized boolean isPortReserved( int port )
{
return reservedPorts.contains( port );
}
/**
* Get the first port (starting from <i>start</i>) that does not appear in
* the reservation list.
*
* @param start
* the base port number to start from
* @return the port number if found
*/
public static synchronized int getNextNotReservedPort( int start )
throws NoPortAvailableException
{
int port = start;
while ( reservedPorts.contains( port ) ) {
if ( port > maxUdpPort ) {
// port not found
throw new NoPortAvailableException();
}
port += 1;
}
return port;
}
public static synchronized int[] findAvailablePorts( int nPorts, int startFrom )
throws NoPortAvailableException
{
int dataPort, controlPort, startingPort;
startingPort = startFrom;
while ( true ) {
startingPort = getNextNotReservedPort( startingPort );
dataPort = getNextPortAvailable( startingPort );
if ( isPortReserved( dataPort ) ) {
// The port is effectively unbound, but reserved in
// PortManager.
startingPort += nPorts;
continue;
}
if ( nPorts == 1 ) {
// There is only the data port
int[] a = { dataPort };
log.debug( "DataPort: " + dataPort );
try {
reservePort( dataPort );
} catch ( Exception e ) {
continue;
}
return a;
} else if ( nPorts == 2 ) {
// We have to find 2 consequents free UDP ports.
// also: dataPort must be an even number
if ( ( dataPort % 2 ) != 0 ) {
continue;
} else {
controlPort = getNextPortAvailable( dataPort + 1 );
if ( controlPort != ( dataPort + 1 ) ) {
// port are not consequents
continue;
} else if ( isPortReserved( controlPort ) ) {
continue;
} else {
try {
reservePort( dataPort );
reservePort( controlPort );
} catch ( Exception e ) {
continue;
}
int[] a = { dataPort, controlPort };
log.debug( "DataPort: " + dataPort + " - ControlPort: "
+ controlPort );
return a;
}
}
}
}
}
private static int getNextPortAvailable( int startPort )
throws NoPortAvailableException
{
for ( int port = startPort; port <= maxUdpPort; port++ ) {
DatagramSocket s = null;
try {
s = new DatagramSocket( port );
s.close();
return port;
} catch ( IOException e ) {
// Ignore
}
}
// No port is available
throw new NoPortAvailableException();
}
}