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) } /**