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 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.
-
-
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.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 java.util.function.IntConsumercombine(java.util.function.IntConsumer a, java.util.function.IntConsumer b)CombinesIntConsumerinstances to run in reverse sequence.private voiddiagnosticReleaseCheck(int port)Checks that the port being released is actually free and emits a detailed log message if not.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.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
-
LOGGER
private static final org.slf4j.Logger LOGGER
-
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)
-
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)
Checks that the port being released is actually free and emits a detailed log message if not. This check is not performed if "org.terracotta.disablePortReleaseCheck" is set totrue.- Parameters:
port- the port to check
-
emitInstanceNotification
private static void emitInstanceNotification(java.lang.String use)
-
combine
private static java.util.function.IntConsumer combine(java.util.function.IntConsumer a, java.util.function.IntConsumer b)CombinesIntConsumerinstances to run in reverse sequence.- Parameters:
a- the secondIntConsumerto runb- the firstIntConsumerto run- Returns:
- a new
IntConsumerrunningbthena
-
-