diff --git a/jvb/src/main/java/org/jitsi/videobridge/ice/Harvesters.java b/jvb/src/main/java/org/jitsi/videobridge/ice/Harvesters.java
deleted file mode 100644
index b3e8a89f6e..0000000000
--- a/jvb/src/main/java/org/jitsi/videobridge/ice/Harvesters.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright @ 2018 - present 8x8, Inc.
- *
- * 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 org.jitsi.videobridge.ice;
-
-import org.ice4j.ice.harvest.*;
-import org.jitsi.utils.logging2.*;
-
-import java.io.*;
-import java.util.*;
-
-public class Harvesters
-{
- /**
- * The flag which indicates whether application-wide harvesters, stored
- * in the static fields {@link #tcpHarvester} and
- * {@link #singlePortHarvesters} have been initialized.
- */
- private static boolean staticConfigurationInitialized = false;
-
- /**
- * Global variable do we consider this transport manager as healthy.
- * By default we consider healthy, if we fail to bind to the single port
- * port we consider the bridge as unhealthy.
- */
- private static boolean healthy = true;
-
- public static boolean isHealthy()
- {
- return healthy;
- }
-
- /**
- * The {@link Logger} used by the {@link Harvesters} class to
- * print debug information.
- */
- private static final Logger classLogger
- = new LoggerImpl(Harvesters.class.getName());
-
- /**
- * The single TcpHarvester instance for the
- * application.
- */
- public static TcpHarvester tcpHarvester = null;
-
- /**
- * The SinglePortUdpHarvesters which will be appended to ICE
- * Agents managed by IceTransport instances.
- */
- public static List singlePortHarvesters = null;
-
- /**
- * Initializes the static Harvester instances used by all
- * IceTransport instances, that is
- * {@link #tcpHarvester} and {@link #singlePortHarvesters}.
- */
- public static void initializeStaticConfiguration()
- {
- synchronized (Harvesters.class)
- {
- if (staticConfigurationInitialized)
- {
- return;
- }
- staticConfigurationInitialized = true;
-
-
- singlePortHarvesters
- = SinglePortUdpHarvester.createHarvesters(IceConfig.config.getPort());
- if (singlePortHarvesters.isEmpty())
- {
- singlePortHarvesters = null;
- classLogger.info("No single-port harvesters created.");
- }
-
- healthy = singlePortHarvesters != null;
-
- if (IceConfig.config.getTcpEnabled())
- {
- int port = IceConfig.config.getTcpPort();
- try
- {
- tcpHarvester = new TcpHarvester(port, IceConfig.config.getIceSslTcp());
- classLogger.info("Initialized TCP harvester on port "
- + port + ", ssltcp=" + IceConfig.config.getIceSslTcp());
-
- }
- catch (IOException ioe)
- {
- classLogger.warn(
- "Failed to initialize TCP harvester on port " + port);
- }
-
- Integer mappedPort = IceConfig.config.getTcpMappedPort();
- if (mappedPort != null)
- {
- tcpHarvester.addMappedPort(mappedPort);
- }
- }
- }
- }
-
- /**
- * Stops the static Harvester instances used by all
- * IceTransport instances, that is
- * {@link #tcpHarvester} and {@link #singlePortHarvesters}.
- */
- public static void closeStaticConfiguration()
- {
- synchronized (Harvesters.class)
- {
- if (!staticConfigurationInitialized)
- {
- return;
- }
- staticConfigurationInitialized = false;
-
- if (singlePortHarvesters != null)
- {
- singlePortHarvesters.forEach(AbstractUdpListener::close);
- singlePortHarvesters = null;
- }
-
- if (tcpHarvester != null)
- {
- tcpHarvester.close();
- tcpHarvester = null;
- }
-
- // Reset the flag to initial state.
- healthy = true;
- }
- }
-}
diff --git a/jvb/src/main/kotlin/org/jitsi/videobridge/Main.kt b/jvb/src/main/kotlin/org/jitsi/videobridge/Main.kt
index 9af6988949..ce0ccd0c27 100644
--- a/jvb/src/main/kotlin/org/jitsi/videobridge/Main.kt
+++ b/jvb/src/main/kotlin/org/jitsi/videobridge/Main.kt
@@ -76,7 +76,9 @@ fun main() {
}
startIce4j()
- Harvesters.initializeStaticConfiguration()
+
+ // Initialize, binding on the main ICE port.
+ Harvesters.init()
XmppStringPrepUtil.setMaxCacheSizes(XmppClientConnectionConfig.config.jidCacheSize)
PacketQueue.setEnableStatisticsDefault(true)
@@ -219,5 +221,5 @@ private fun startIce4j() {
private fun stopIce4j() {
// Shut down harvesters.
- Harvesters.closeStaticConfiguration()
+ Harvesters.close()
}
diff --git a/jvb/src/main/kotlin/org/jitsi/videobridge/health/JvbHealthChecker.kt b/jvb/src/main/kotlin/org/jitsi/videobridge/health/JvbHealthChecker.kt
index d01402dc67..e02a8738bb 100644
--- a/jvb/src/main/kotlin/org/jitsi/videobridge/health/JvbHealthChecker.kt
+++ b/jvb/src/main/kotlin/org/jitsi/videobridge/health/JvbHealthChecker.kt
@@ -43,7 +43,7 @@ class JvbHealthChecker : HealthCheckService {
if (config.requireStun && MappingCandidateHarvesters.stunDiscoveryFailed) {
return Result(success = false, message = "Address discovery through STUN failed")
}
- if (!Harvesters.isHealthy()) {
+ if (!Harvesters.INSTANCE.healthy) {
return Result(success = false, message = "Failed to bind single-port")
}
@@ -57,7 +57,7 @@ class JvbHealthChecker : HealthCheckService {
}
private fun hasValidAddress(): Boolean {
- if (Harvesters.singlePortHarvesters?.any { it.localAddress.address.isValid() } == true) {
+ if (Harvesters.INSTANCE.singlePortHarvesters.any { it.localAddress.address.isValid() }) {
return true
}
if (MappingCandidateHarvesters.getHarvesters().any { it.mask?.address?.isValid() == true }) {
diff --git a/jvb/src/main/kotlin/org/jitsi/videobridge/ice/Harvesters.kt b/jvb/src/main/kotlin/org/jitsi/videobridge/ice/Harvesters.kt
new file mode 100644
index 0000000000..c5ea68ccaf
--- /dev/null
+++ b/jvb/src/main/kotlin/org/jitsi/videobridge/ice/Harvesters.kt
@@ -0,0 +1,72 @@
+/*
+* Copyright @ 2018 - present 8x8, Inc.
+*
+* 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 org.jitsi.videobridge.ice
+
+import org.ice4j.ice.harvest.SinglePortUdpHarvester
+import org.ice4j.ice.harvest.TcpHarvester
+import org.jitsi.utils.logging2.createLogger
+import java.io.IOException
+
+class Harvesters private constructor(
+ val tcpHarvester: TcpHarvester?,
+ val singlePortHarvesters: List
+) {
+ /* We're unhealthy if there are no single port harvesters. */
+ val healthy: Boolean
+ get() = singlePortHarvesters.isNotEmpty()
+
+ private fun close() {
+ singlePortHarvesters.forEach { it.close() }
+ tcpHarvester?.close()
+ }
+
+ companion object {
+ private val logger = createLogger()
+
+ fun init() {
+ // Trigger the lazy init.
+ INSTANCE
+ }
+
+ fun close() = INSTANCE.close()
+
+ val INSTANCE: Harvesters by lazy {
+ val singlePortHarvesters = SinglePortUdpHarvester.createHarvesters(IceConfig.config.port)
+ if (singlePortHarvesters.isEmpty()) {
+ logger.warn("No single-port harvesters created.")
+ }
+ val tcpHarvester: TcpHarvester? = if (IceConfig.config.tcpEnabled) {
+ val port = IceConfig.config.tcpPort
+ try {
+ TcpHarvester(IceConfig.config.port, IceConfig.config.iceSslTcp).apply {
+ logger.info("Initialized TCP harvester on port $port, ssltcp=${IceConfig.config.iceSslTcp}")
+ IceConfig.config.tcpMappedPort?.let { mappedPort ->
+ logger.info("Adding mapped port $mappedPort")
+ addMappedPort(mappedPort)
+ }
+ }
+ } catch (ioe: IOException) {
+ logger.warn("Failed to initialize TCP harvester on port $port")
+ null
+ }
+ } else {
+ null
+ }
+
+ Harvesters(tcpHarvester, singlePortHarvesters)
+ }
+ }
+}
diff --git a/jvb/src/main/kotlin/org/jitsi/videobridge/transport/ice/IceTransport.kt b/jvb/src/main/kotlin/org/jitsi/videobridge/transport/ice/IceTransport.kt
index e9cccd98d1..317c35b8aa 100755
--- a/jvb/src/main/kotlin/org/jitsi/videobridge/transport/ice/IceTransport.kt
+++ b/jvb/src/main/kotlin/org/jitsi/videobridge/transport/ice/IceTransport.kt
@@ -393,10 +393,10 @@ class IceTransport @JvmOverloads constructor(
companion object {
fun appendHarvesters(iceAgent: Agent) {
- Harvesters.tcpHarvester?.let {
+ Harvesters.INSTANCE.tcpHarvester?.let {
iceAgent.addCandidateHarvester(it)
}
- Harvesters.singlePortHarvesters?.forEach(iceAgent::addCandidateHarvester)
+ Harvesters.INSTANCE.singlePortHarvesters.forEach(iceAgent::addCandidateHarvester)
}
/**