Class PortManager
- java.lang.Object
-
- org.terracotta.utilities.test.net.PortManager
-
public class PortManager extends java.lang.ObjectManages TCP port reservation/de-reservation while attempting to avoid intra- and extra-JVM interference.The port manager maintains two levels of reservation -- intra-JVM using an internal
BitSetand inter-JVM using locks against aRandomAccessFileallocated in a system-wide, world-writable, system-dependent location. To avoid reservation/use races, ephemeral ports are not used.All users of
PortManagerin a JVM must use the samePortManagerinstance to ensure proper intra-JVM reservations.By default, release of an assigned port back to
PortManager(viaPortManager.PortRef.close()or garbage collection of a weakly-reachablePortRefinstance) performs a check that the port is actually unused. This involves querying both the in-use ports and active processes on the system and, on some systems, could be a time-consuming activity. While the check is intended to identify "outside" interference with ports assigned byPortManager, it is possible to disable this check by setting the "org.terracotta.disablePortReleaseCheck" property or "DISABLE_PORT_RELEASE_CHECK" environment variable totrue. The property value is examined each time the release check is performed so the check may be disabled for some tests and left enabled for others; the environment variable is only examined when thePortMangerclass is loaded.
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description private static classPortManager.AllocatedPortReferenceimplementation used to track no longer used reserved ports.private static classPortManager.BitSearchEnumeration of search for aBitSet.private static classPortManager.PidDetermines the process identifier of the current process.static classPortManager.PortRefRepresents a reserved TCP port.
-
Field Summary
Fields Modifier and Type Field Description private java.util.Map<java.lang.Integer,PortManager.AllocatedPort>allocatedPortsReferences to outstandingPortManager.PortRefinstances.private intassignablePortCountThe number of non-reserved ports.private java.lang.ref.ReferenceQueue<PortManager.PortRef>dereferencedPortsAReferenceQueueacceptingPortManager.PortRefinstances no longer held by the reserving party.private static booleanDISABLE_PORT_RELEASE_CHECKReflects the value of the "DISABLE_PORT_RELEASE_CHECK" environment variable.static java.lang.StringDISABLE_PORT_RELEASE_CHECK_ENV_VARIABLEEnvironment variable checked for disabling the port release check performed at the time a port obtained from PortManager is returned to PortManger.static java.lang.StringDISABLE_PORT_RELEASE_CHECK_PROPERTYProperty checked for disabling the port release check performed at the time a port obtained fromPortManageris returned toPortManager.private static PortManagerINSTANCEprivate static java.net.InetAddressLOCALHOSTprivate static org.slf4j.LoggerLOGGERprivate static intMAXIMUM_PORT_NUMBERprivate static intMINIMUM_ASSIGNABLE_PORT_COUNTprivate java.util.BitSetportMapPort allocation map.private java.util.BitSetrestrictedPortsMarks the ports which cannot be allocated by this class.private java.util.Randomrndprivate SystemLevelLockersystemLevelLockerManages port reservations at a system level using file locks.
-
Constructor Summary
Constructors Modifier Constructor Description privatePortManager()Creates aPortManagerinstance primed for reserving ports outside of current system's the ephemeral port range.
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description private voidcleanReleasedPorts()ReleasesPortRefinstances no longer strongly held.private static <T,U>
java.util.function.BiConsumer<T,U>combine(java.util.function.BiConsumer<T,U> a, java.util.function.BiConsumer<T,U> b)CombinesBiConsumerinstances to run in reverse sequence.private voiddiagnosticReleaseCheck(int port, java.util.Set<PortManager.PortRef.CloseOption> options)Checks that the port being released is actually free and emits a detailed log message if not.private static voiddisablePortReleaseCheck()private static voidemitInstanceNotification(java.lang.String use)static PortManagergetInstance()Gets the singleton instance ofPortManagerto use in a JVM.java.util.Optional<PortManager.PortRef>getPortRef(int port)Gets the activePortManager.PortRefinstance for the designated port.booleanisReservablePort(int port)Indicates if the designated port is in the range of ports that may be allocated by this class.private booleanrefusesConnect(int port)Determines if a client connection to the specified port is accepted or refused.private voidrelease(int port, java.util.Set<PortManager.PortRef.CloseOption> options)java.util.Optional<PortManager.PortRef>reserve(int port)Attempts to reserve the specified port.private PortManager.PortRefreserveInternal(int candidatePort)Reserve and vet the specified candidate port.PortManager.PortRefreservePort()Reserve a single, randomly selected port.java.util.List<PortManager.PortRef>reservePorts(int portCount)Reserves the specified number of ports returning a list ofPortManager.PortRefinstances for those reserved.
-
-
-
Field Detail
-
DISABLE_PORT_RELEASE_CHECK_PROPERTY
public static final java.lang.String DISABLE_PORT_RELEASE_CHECK_PROPERTY
Property checked for disabling the port release check performed at the time a port obtained fromPortManageris returned toPortManager.- See Also:
- Constant Field Values
-
DISABLE_PORT_RELEASE_CHECK_ENV_VARIABLE
public static final java.lang.String DISABLE_PORT_RELEASE_CHECK_ENV_VARIABLE
Environment variable checked for disabling the port release check performed at the time a port obtained from PortManager is returned to PortManger.- See Also:
- Constant Field Values
-
LOGGER
private static final org.slf4j.Logger LOGGER
-
DISABLE_PORT_RELEASE_CHECK
private static final boolean DISABLE_PORT_RELEASE_CHECK
Reflects the value of the "DISABLE_PORT_RELEASE_CHECK" environment variable. If the environment variable is set to a case-insensitive value oftrue, the port release check will be disabled.The value of the environment variable is only checked when this class is loaded; changes to the environment variable after this class is loaded are not detected.
-
INSTANCE
private static final PortManager INSTANCE
-
MAXIMUM_PORT_NUMBER
private static final int MAXIMUM_PORT_NUMBER
- See Also:
- Constant Field Values
-
MINIMUM_ASSIGNABLE_PORT_COUNT
private static final int MINIMUM_ASSIGNABLE_PORT_COUNT
- See Also:
- Constant Field Values
-
LOCALHOST
private static final java.net.InetAddress LOCALHOST
-
rnd
private final java.util.Random rnd
-
restrictedPorts
private final java.util.BitSet restrictedPorts
Marks the ports which cannot be allocated by this class. Atruebit in thisBitSetindicates a non-reservable (restricted) port.
-
portMap
private final java.util.BitSet portMap
Port allocation map. A zero bit represents an available port.
-
allocatedPorts
private final java.util.Map<java.lang.Integer,PortManager.AllocatedPort> allocatedPorts
References to outstandingPortManager.PortRefinstances.
-
dereferencedPorts
private final java.lang.ref.ReferenceQueue<PortManager.PortRef> dereferencedPorts
AReferenceQueueacceptingPortManager.PortRefinstances no longer held by the reserving party.
-
systemLevelLocker
private final SystemLevelLocker systemLevelLocker
Manages port reservations at a system level using file locks.
-
assignablePortCount
private final int assignablePortCount
The number of non-reserved ports. This is the absolute upper limit of the number of ports that can possibly be assigned.
-
-
Method Detail
-
getInstance
public static PortManager getInstance()
Gets the singleton instance ofPortManagerto use in a JVM.- Returns:
- the singleton
PortManagerinstance
-
isReservablePort
public boolean isReservablePort(int port)
Indicates if the designated port is in the range of ports that may be allocated by this class. If the designated port is in the range of ports that may be allocated, thereserve(int)method may be used to attempt to allocate the port. The port may also be returned from thereservePort()andreservePorts(int)methods.- Parameters:
port- the port number to test- Returns:
trueifportmay be reserved usingreserve(int);falseifportis not a reservable port. Atrueresult is not an indication thatportis currently available to be reserved.- Throws:
java.lang.IllegalArgumentException- ifportis not between 0 and 65535 (inclusive)
-
getPortRef
public java.util.Optional<PortManager.PortRef> getPortRef(int port)
Gets the activePortManager.PortRefinstance for the designated port.This method returns a reference to the most recent
PortRefcreated for the designated port if thePortRefis both strongly reachable and not closed. The result of this method may be immediately stale -- thePortRefmay be closed between the time thePortRefis checked and the reference returned to the called.- Parameters:
port- the port number for which thePortRefis returned- Returns:
- an
Optionalof thePortRefforportif thePortRefis both strongly reachable and not closed;Optional.emptyif thePortRefforportis either not strongly reachable or closed - Throws:
java.lang.IllegalArgumentException- ifportis not between 0 and 65535 (inclusive) or is not a reservable port
-
reserve
public java.util.Optional<PortManager.PortRef> reserve(int port)
Attempts to reserve the specified port.The
PortManager.PortRef.close()method should be called when the port is no longer needed. However, the returnedPortRefinstance must strongly-referenced as long as the port is required -- once thePortRefinstance becomes weakly-referenced, the port reservation may be released.- Parameters:
port- the port number to reserve- Returns:
- an
Optionalcontaining thePortManager.PortRefif the port was successfully reserved;Optional.emptyif the port could not be reserved - Throws:
java.lang.IllegalArgumentException- ifportis not between 0 and 65535 (inclusive) or is not a reservable portjava.lang.IllegalStateException- if reservation fails due to an error
-
reservePorts
public java.util.List<PortManager.PortRef> reservePorts(int portCount)
Reserves the specified number of ports returning a list ofPortManager.PortRefinstances for those reserved.The
PortManager.PortRef.close()method should be called on each port when no longer needed. However, each returnedPortRefinstance must strongly-referenced as long as the port is required -- once thePortRefinstance becomes weakly-referenced, the port reservation may be released.- Parameters:
portCount- the number of ports to reserve- Returns:
- the list of
PortRefinstances for the reserved ports; the ports are not assigned sequentially - Throws:
java.lang.IllegalArgumentException- ifportCountis less than 1 or greater than the number of reservable portsjava.lang.IllegalStateException- if the reservable ports are exhausted or reservation fails due to an error
-
reservePort
public PortManager.PortRef reservePort()
Reserve a single, randomly selected port.The
PortManager.PortRef.close()method should be called on the port when no longer needed. However, the returnedPortRefinstance must strongly-referenced as long as the port is required -- once thePortRefinstance becomes weakly-referenced, the port reservation may be released.- Returns:
- a
PortRefinstance identifying the reserved port - Throws:
java.lang.IllegalStateException- if the reservable ports are exhausted or reservation fails due to an error
-
cleanReleasedPorts
private void cleanReleasedPorts()
ReleasesPortRefinstances no longer strongly held. ThesePortRefinstances are considered available for reuse.
-
reserveInternal
private PortManager.PortRef reserveInternal(int candidatePort)
Reserve and vet the specified candidate port.- Parameters:
candidatePort- the port to vet and reserve- Returns:
- a new
PortRefinstance is the reservation was successful;nullotherwise - Throws:
java.lang.IllegalStateException- if port reservation fails due to a locking error
-
release
private void release(int port, java.util.Set<PortManager.PortRef.CloseOption> options)
-
refusesConnect
private boolean refusesConnect(int port)
Determines if a client connection to the specified port is accepted or refused.On some versions of Windows, a port can pass the server bind test and still not really be free. According to issue MNK-5621, some Windows services, like Remote Desktop (RDP) don't establish an open listener but do respond to connection requests on their assigned port(s). A "failure to connect" is necessary to determine if the port is actually available. (This check presumes firewall rules aren't responsible for dropping the connection request -- not much we can do about that.)
- Parameters:
port- the port to test- Returns:
trueif the port is available (free);falseotherwise- See Also:
- Service overview and network port requirements for Windows
-
diagnosticReleaseCheck
private void diagnosticReleaseCheck(int port, java.util.Set<PortManager.PortRef.CloseOption> options)Checks that the port being released is actually free and emits a detailed log message if not. This check is not performed if the "org.terracotta.disablePortReleaseCheck" system property or the "DISABLE_PORT_RELEASE_CHECK" environment variable is set totrue.- Parameters:
port- the port to checkoptions- the set ofPortManager.PortRef.CloseOptionmembers used to influence the release check
-
disablePortReleaseCheck
private static void disablePortReleaseCheck()
-
emitInstanceNotification
private static void emitInstanceNotification(java.lang.String use)
-
combine
private static <T,U> java.util.function.BiConsumer<T,U> combine(java.util.function.BiConsumer<T,U> a, java.util.function.BiConsumer<T,U> b)CombinesBiConsumerinstances to run in reverse sequence.- Parameters:
a- the secondBiConsumerto runb- the firstBiConsumerto run- Returns:
- a new
BiConsumerrunningbthena
-
-