Class PortManager
The port manager maintains two levels of reservation -- intra-JVM using
an internal BitSet and inter-JVM using locks against a
RandomAccessFile
allocated in a system-wide, world-writable, system-dependent location.
To avoid reservation/use races,
ephemeral ports
are not used.
All users of PortManager in a JVM must use the same PortManager
instance to ensure proper intra-JVM reservations.
By default, release of an assigned port back to PortManager (via PortManager.PortRef.close()
or garbage collection of a weakly-reachable PortRef instance) 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 by PortManager, it
is possible to disable this check by setting the "org.terracotta.disablePortReleaseCheck"
property or "DISABLE_PORT_RELEASE_CHECK" environment variable to true.
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 the PortManger class is loaded.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionprivate static classReferenceimplementation used to track no longer used reserved ports.private static enumEnumeration of search for aBitSet.private static final classDetermines the process identifier of the current process.static classRepresents a reserved TCP port. -
Field Summary
FieldsModifier and TypeFieldDescriptionprivate final Map<Integer,PortManager.AllocatedPort> References to outstandingPortManager.PortRefinstances.private final intThe number of non-reserved ports.private final ReferenceQueue<PortManager.PortRef>AReferenceQueueacceptingPortManager.PortRefinstances no longer held by the reserving party.private static final booleanReflects the value of the "DISABLE_PORT_RELEASE_CHECK" environment variable.static final StringEnvironment variable checked for disabling the port release check performed at the time a port obtained from PortManager is returned to PortManger.static final StringProperty checked for disabling the port release check performed at the time a port obtained fromPortManageris returned toPortManager.private static final PortManagerprivate static final InetAddressprivate static final org.slf4j.Loggerprivate static final intprivate static final intprivate final BitSetPort allocation map.private final BitSetMarks the ports which cannot be allocated by this class.private final Randomprivate final SystemLevelLockerManages port reservations at a system level using file locks. -
Constructor Summary
ConstructorsModifierConstructorDescriptionprivateCreates aPortManagerinstance primed for reserving ports outside of current system's the ephemeral port range. -
Method Summary
Modifier and TypeMethodDescriptionprivate voidReleasesPortRefinstances no longer strongly held.private static <T,U> BiConsumer<T, U> combine(BiConsumer<T, U> a, BiConsumer<T, U> b) CombinesBiConsumerinstances to run in reverse sequence.private voiddiagnosticReleaseCheck(int port, Set<PortManager.PortRef.CloseOption> options) Checks that the port being released is actually free and emits a detailed log message if not.private static voidprivate static voidstatic PortManagerGets the singleton instance ofPortManagerto use in a JVM.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, Set<PortManager.PortRef.CloseOption> options) reserve(int port) Attempts to reserve the specified port.private PortManager.PortRefreserveInternal(int candidatePort) Reserve and vet the specified candidate port.Reserve a single, randomly selected port.reservePorts(int portCount) Reserves the specified number of ports returning a list ofPortManager.PortRefinstances for those reserved.
-
Field Details
-
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:
-
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:
-
LOGGER
private static final org.slf4j.Logger LOGGER -
DISABLE_PORT_RELEASE_CHECK
private static final boolean DISABLE_PORT_RELEASE_CHECKReflects 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
-
MAXIMUM_PORT_NUMBER
private static final int MAXIMUM_PORT_NUMBER- See Also:
-
MINIMUM_ASSIGNABLE_PORT_COUNT
private static final int MINIMUM_ASSIGNABLE_PORT_COUNT- See Also:
-
LOCALHOST
-
rnd
-
restrictedPorts
Marks the ports which cannot be allocated by this class. Atruebit in thisBitSetindicates a non-reservable (restricted) port. -
portMap
Port allocation map. A zero bit represents an available port. -
allocatedPorts
References to outstandingPortManager.PortRefinstances. -
dereferencedPorts
AReferenceQueueacceptingPortManager.PortRefinstances no longer held by the reserving party. -
systemLevelLocker
Manages port reservations at a system level using file locks. -
assignablePortCount
private final int assignablePortCountThe number of non-reserved ports. This is the absolute upper limit of the number of ports that can possibly be assigned.
-
-
Constructor Details
-
PortManager
private PortManager()Creates aPortManagerinstance primed for reserving ports outside of current system's the ephemeral port range.
-
-
Method Details
-
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:
IllegalArgumentException- ifportis not between 0 and 65535 (inclusive)
-
getPortRef
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:
IllegalArgumentException- ifportis not between 0 and 65535 (inclusive) or is not a reservable port
-
reserve
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:
IllegalArgumentException- ifportis not between 0 and 65535 (inclusive) or is not a reservable portIllegalStateException- if reservation fails due to an error
-
reservePorts
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:
IllegalArgumentException- ifportCountis less than 1 or greater than the number of reservable portsIllegalStateException- if the reservable ports are exhausted or reservation fails due to an error
-
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:
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
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:
IllegalStateException- if port reservation fails due to a locking error
-
release
-
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:
-
diagnosticReleaseCheck
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
-
combine
CombinesBiConsumerinstances to run in reverse sequence.- Parameters:
a- the secondBiConsumerto runb- the firstBiConsumerto run- Returns:
- a new
BiConsumerrunningbthena
-