From 34049ccc1b25bec4b56548999490f6c892776889 Mon Sep 17 00:00:00 2001 From: Brutus5000 Date: Tue, 26 Nov 2024 23:33:25 +0100 Subject: [PATCH] Apply code formatting with Spotless and palantir format --- build.gradle | 5 +- ice-adapter/build.gradle | 12 + .../com/faforever/iceadapter/IceAdapter.java | 52 ++-- .../com/faforever/iceadapter/IceOptions.java | 25 +- .../com/faforever/iceadapter/debug/Debug.java | 103 +++---- .../iceadapter/debug/DebugFacade.java | 1 - .../iceadapter/debug/DebugWindow.java | 106 ++++--- .../debug/DebugWindowController.java | 193 ++++++------ .../faforever/iceadapter/debug/Debugger.java | 4 +- .../iceadapter/debug/InfoWindow.java | 86 +++--- .../debug/InfoWindowController.java | 33 +-- .../iceadapter/debug/TelemetryDebugger.java | 63 ++-- .../iceadapter/debug/TextAreaLogAppender.java | 139 +++++---- .../iceadapter/gpgnet/FaDataInputStream.java | 1 - .../iceadapter/gpgnet/FaDataOutputStream.java | 1 - .../iceadapter/gpgnet/GPGNetServer.java | 42 ++- .../iceadapter/gpgnet/GameState.java | 7 +- .../iceadapter/gpgnet/LobbyInitMode.java | 7 +- .../iceadapter/ice/CandidatePacket.java | 4 +- .../iceadapter/ice/CandidatesMessage.java | 7 +- .../faforever/iceadapter/ice/GameSession.java | 125 ++++---- .../faforever/iceadapter/ice/IceServer.java | 26 +- .../faforever/iceadapter/ice/IceState.java | 2 +- .../com/faforever/iceadapter/ice/Peer.java | 39 ++- .../ice/PeerConnectivityCheckerModule.java | 43 ++- .../iceadapter/ice/PeerIceModule.java | 276 +++++++++++------- .../iceadapter/ice/PeerTurnRefreshModule.java | 148 +++++----- .../faforever/iceadapter/rpc/RPCHandler.java | 81 +++-- .../faforever/iceadapter/rpc/RPCService.java | 204 ++++++------- .../iceadapter/telemetry/ConnectToPeer.java | 5 +- .../iceadapter/telemetry/CoturnServer.java | 3 +- .../telemetry/DisconnectFromPeer.java | 3 +- .../telemetry/OutgoingMessageV1.java | 3 +- .../iceadapter/telemetry/RegisterAsPeer.java | 4 +- .../telemetry/UpdateCoturnList.java | 5 +- .../iceadapter/telemetry/UpdateGameState.java | 4 +- .../telemetry/UpdateGpgnetState.java | 3 +- .../telemetry/UpdatePeerConnectivity.java | 5 +- .../iceadapter/telemetry/UpdatePeerState.java | 12 +- .../iceadapter/util/CandidateUtil.java | 58 ++-- .../faforever/iceadapter/util/Executor.java | 14 +- .../iceadapter/util/NetworkToolbox.java | 11 +- .../iceadapter/util/PingWrapper.java | 7 +- .../faforever/iceadapter/util/TrayIcon.java | 161 +++++----- ice-adapter/src/test/java/IceTest.java | 146 +++++---- .../src/test/java/SignallingServer.java | 12 +- 46 files changed, 1264 insertions(+), 1027 deletions(-) diff --git a/build.gradle b/build.gradle index c3f57a4..4379ba4 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,7 @@ plugins { - id 'com.github.johnrengelman.shadow' version '7.1.2' id 'java' + id 'com.diffplug.spotless' version '6.25.0' + id 'com.github.johnrengelman.shadow' version '7.1.2' } @@ -23,4 +24,4 @@ allprojects { task createAllJars (type: GradleBuild) { tasks = [":client:shadowJar",":server:shadowJar",":ice-adapter:shadowJar"] -} +} \ No newline at end of file diff --git a/ice-adapter/build.gradle b/ice-adapter/build.gradle index 57a8322..c478cae 100644 --- a/ice-adapter/build.gradle +++ b/ice-adapter/build.gradle @@ -9,6 +9,7 @@ apply plugin: 'idea' apply plugin: 'java' apply plugin: 'java-library' apply plugin: 'com.github.johnrengelman.shadow' +apply plugin: 'com.diffplug.spotless' group 'com.faforever' @@ -67,3 +68,14 @@ shadowJar { attributes 'Main-Class': 'com.faforever.iceadapter.IceAdapter' } } + +tasks.named("check") { + dependsOn("spotlessCheck") +} + +spotless { + java { + cleanthat() + palantirJavaFormat() + } +} \ No newline at end of file diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/IceAdapter.java b/ice-adapter/src/main/java/com/faforever/iceadapter/IceAdapter.java index abd6c56..9a5cd74 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/IceAdapter.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/IceAdapter.java @@ -1,5 +1,7 @@ package com.faforever.iceadapter; +import static com.faforever.iceadapter.debug.Debug.debug; + import com.faforever.iceadapter.debug.Debug; import com.faforever.iceadapter.gpgnet.GPGNetServer; import com.faforever.iceadapter.gpgnet.GameState; @@ -7,13 +9,14 @@ import com.faforever.iceadapter.rpc.RPCService; import com.faforever.iceadapter.util.Executor; import com.faforever.iceadapter.util.TrayIcon; +import java.util.concurrent.Callable; import lombok.extern.slf4j.Slf4j; import picocli.CommandLine; -import java.util.concurrent.Callable; - -import static com.faforever.iceadapter.debug.Debug.debug; -@CommandLine.Command(name = "faf-ice-adapter", mixinStandardHelpOptions = true, usageHelpAutoWidth = true, +@CommandLine.Command( + name = "faf-ice-adapter", + mixinStandardHelpOptions = true, + usageHelpAutoWidth = true, description = "An ice (RFC 5245) based network bridge between FAF client and ForgedAlliance.exe") @Slf4j public class IceAdapter implements Callable { @@ -43,9 +46,7 @@ public class IceAdapter implements Callable { public static volatile GameSession gameSession; public static void main(String[] args) { - new CommandLine(new IceAdapter()) - .setUnmatchedArgumentsAllowed(true) - .execute(args); + new CommandLine(new IceAdapter()).setUnmatchedArgumentsAllowed(true).execute(args); } @Override @@ -61,14 +62,15 @@ public static void start(IceOptions iceOptions) { TrayIcon.create(); - //Configure file appender -// RollingFileAppender fileAppender = (ch.qos.logback.core.rolling.RollingFileAppender)((ch.qos.logback.classic.Logger)log).getAppender("FILE"); -// if (logDirectory != null) { -// Util.mkdir(Paths.get(logDirectory).toFile()); -// //TODO: set log dir -// } else { -//// fileAppender.stop(); -// } + // Configure file appender + // RollingFileAppender fileAppender = + // (ch.qos.logback.core.rolling.RollingFileAppender)((ch.qos.logback.classic.Logger)log).getAppender("FILE"); + // if (logDirectory != null) { + // Util.mkdir(Paths.get(logDirectory).toFile()); + // //TODO: set log dir + // } else { + //// fileAppender.stop(); + // } log.info("Version: {}", VERSION); @@ -102,7 +104,10 @@ public static void onJoinGame(String remotePlayerLogin, int remotePlayerId) { } public static void onConnectToPeer(String remotePlayerLogin, int remotePlayerId, boolean offer) { - if(GPGNetServer.isConnected() && GPGNetServer.getGameState().isPresent() && (GPGNetServer.getGameState().get() == GameState.LAUNCHING || GPGNetServer.getGameState().get() == GameState.ENDED)) { + if (GPGNetServer.isConnected() + && GPGNetServer.getGameState().isPresent() + && (GPGNetServer.getGameState().get() == GameState.LAUNCHING + || GPGNetServer.getGameState().get() == GameState.ENDED)) { log.warn("Game ended or in progress, ABORTING connectToPeer"); return; } @@ -128,7 +133,7 @@ public static void onDisconnectFromPeer(int remotePlayerId) { }); } - private synchronized static void createGameSession() { + private static synchronized void createGameSession() { if (gameSession != null) { gameSession.close(); gameSession = null; @@ -141,12 +146,12 @@ private synchronized static void createGameSession() { * Triggered by losing gpgnet connection to FA. * Closes the active Game/ICE session */ - public synchronized static void onFAShutdown() { - if(gameSession != null) { + public static synchronized void onFAShutdown() { + if (gameSession != null) { log.info("FA SHUTDOWN, closing everything"); gameSession.close(); gameSession = null; - //Do not put code outside of this if clause, else it will be executed multiple times + // Do not put code outside of this if clause, else it will be executed multiple times } } @@ -158,7 +163,7 @@ public static void close() { Executor.executeDelayed(500, () -> System.exit(0)); - onFAShutdown();//will close gameSession aswell + onFAShutdown(); // will close gameSession aswell GPGNetServer.close(); RPCService.close(); TrayIcon.close(); @@ -166,7 +171,6 @@ public static void close() { System.exit(0); } - /** * Read command line arguments and set global, constant values * @param iceOptions The arguments to be read @@ -180,7 +184,7 @@ public static void loadOptions(IceOptions iceOptions) { GPGNET_PORT = iceOptions.getGpgnetPort(); LOBBY_PORT = iceOptions.getLobbyPort(); - if(iceOptions.isForceRelay()) { + if (iceOptions.isForceRelay()) { ALLOW_HOST = false; ALLOW_REFLEXIVE = false; ALLOW_RELAY = true; @@ -197,7 +201,7 @@ public static void loadOptions(IceOptions iceOptions) { private static void determineVersion() { String versionFromGradle = IceAdapter.class.getPackage().getImplementationVersion(); - if(versionFromGradle != null) { + if (versionFromGradle != null) { VERSION = versionFromGradle; } } diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/IceOptions.java b/ice-adapter/src/main/java/com/faforever/iceadapter/IceOptions.java index 076b046..834232f 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/IceOptions.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/IceOptions.java @@ -24,7 +24,10 @@ public class IceOptions { @Option(names = "--gpgnet-port", defaultValue = "0", description = "set the port of internal GPGNet server") private int gpgnetPort; - @Option(names = "--lobby-port", defaultValue = "0", description = "set the port the game lobby should use for incoming UDP packets from the PeerRelay") + @Option( + names = "--lobby-port", + defaultValue = "0", + description = "set the port the game lobby should use for incoming UDP packets from the PeerRelay") private int lobbyPort; @Option(names = "--force-relay", description = "force the usage of relay candidates only") @@ -36,15 +39,27 @@ public class IceOptions { @Option(names = "--info-window", description = "activate the info window") private boolean infoWindow; - @Option(names = "--delay-ui", defaultValue = "0", description = "delays the launch of the info and debug window (in ms)") + @Option( + names = "--delay-ui", + defaultValue = "0", + description = "delays the launch of the info and debug window (in ms)") private int delayUi; - @Option(names = "--ping-count", defaultValue = "1", description = "number of times to ping each turn server to determine latency") + @Option( + names = "--ping-count", + defaultValue = "1", + description = "number of times to ping each turn server to determine latency") private int pingCount; - @Option(names = "--acceptable-latency", defaultValue = "250.0", description = "number of times to ping each turn server to determine latency") + @Option( + names = "--acceptable-latency", + defaultValue = "250.0", + description = "number of times to ping each turn server to determine latency") private double acceptableLatency; - @Option(names = "--telemetry-server", defaultValue = "wss://ice-telemetry.faforever.com", description = "Telemetry server to connect to") + @Option( + names = "--telemetry-server", + defaultValue = "wss://ice-telemetry.faforever.com", + description = "Telemetry server to connect to") private String telemetryServer; } diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/debug/Debug.java b/ice-adapter/src/main/java/com/faforever/iceadapter/debug/Debug.java index 140838e..835cc58 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/debug/Debug.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/debug/Debug.java @@ -1,66 +1,71 @@ package com.faforever.iceadapter.debug; import com.faforever.iceadapter.IceAdapter; -import lombok.extern.slf4j.Slf4j; - import java.lang.reflect.InvocationTargetException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; +import lombok.extern.slf4j.Slf4j; @Slf4j public class Debug { - //TODO - public static boolean ENABLE_DEBUG_WINDOW_LOG_TEXT_AREA = false; // disabled as this causes high memory and cpu load, should be replaced by limiting the number of lines in the text area - - public static boolean ENABLE_DEBUG_WINDOW = false; - public static boolean ENABLE_INFO_WINDOW = false; - public static int DELAY_UI_MS = 0;//delays the launch of the user interface by X ms + // TODO + public static boolean ENABLE_DEBUG_WINDOW_LOG_TEXT_AREA = + false; // disabled as this causes high memory and cpu load, should be replaced by limiting the number of + // lines in the text area - private final static DebugFacade debugFacade = new DebugFacade(); + public static boolean ENABLE_DEBUG_WINDOW = false; + public static boolean ENABLE_INFO_WINDOW = false; + public static int DELAY_UI_MS = 0; // delays the launch of the user interface by X ms - public static void register(Debugger debugger) { - debugFacade.add(debugger); - } + private static final DebugFacade debugFacade = new DebugFacade(); - public static void remove(Debugger debugger) { - debugFacade.remove(debugger); - } + public static void register(Debugger debugger) { + debugFacade.add(debugger); + } - public static void init() { - new TelemetryDebugger(IceAdapter.TELEMETRY_SERVER, IceAdapter.gameId, IceAdapter.id); + public static void remove(Debugger debugger) { + debugFacade.remove(debugger); + } - // Debugger window is started and set to debugFuture when either window is requested as the info window can be used to open the debug window - // This is not used anymore as the debug window is started and hidden in case it is requested via the tray icon - if(! ENABLE_DEBUG_WINDOW && ! ENABLE_INFO_WINDOW) { - return; - } + public static void init() { + new TelemetryDebugger(IceAdapter.TELEMETRY_SERVER, IceAdapter.gameId, IceAdapter.id); - if(isJavaFxSupported()) { - new Thread(() -> { - try { - Class.forName("com.faforever.iceadapter.debug.DebugWindow").getMethod("launchApplication").invoke(null); - } catch (IllegalAccessException | ClassNotFoundException | NoSuchMethodException | InvocationTargetException e) { - e.printStackTrace(); - log.error("Could not create DebugWindow. Running without debug window."); - } - }).start(); //Completes future once application started - } else { - log.info("No JavaFX support detected. Running without debug window."); - } - } + // Debugger window is started and set to debugFuture when either window is requested as the info window can be + // used to open the debug window + // This is not used anymore as the debug window is started and hidden in case it is requested via the tray icon + if (!ENABLE_DEBUG_WINDOW && !ENABLE_INFO_WINDOW) { + return; + } + if (isJavaFxSupported()) { + new Thread(() -> { + try { + Class.forName("com.faforever.iceadapter.debug.DebugWindow") + .getMethod("launchApplication") + .invoke(null); + } catch (IllegalAccessException + | ClassNotFoundException + | NoSuchMethodException + | InvocationTargetException e) { + e.printStackTrace(); + log.error("Could not create DebugWindow. Running without debug window."); + } + }) + .start(); // Completes future once application started + } else { + log.info("No JavaFX support detected. Running without debug window."); + } + } - public static Debugger debug() { - return debugFacade; - } + public static Debugger debug() { + return debugFacade; + } - public static boolean isJavaFxSupported() { - try { - Debug.class.getClassLoader().loadClass("javafx.application.Application"); - return true; - } catch(ClassNotFoundException e) { - log.warn("Could not create debug window, no JavaFX found."); - return false; - } - } + public static boolean isJavaFxSupported() { + try { + Debug.class.getClassLoader().loadClass("javafx.application.Application"); + return true; + } catch (ClassNotFoundException e) { + log.warn("Could not create debug window, no JavaFX found."); + return false; + } + } } diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/debug/DebugFacade.java b/ice-adapter/src/main/java/com/faforever/iceadapter/debug/DebugFacade.java index 0a6d439..d7a60eb 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/debug/DebugFacade.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/debug/DebugFacade.java @@ -3,7 +3,6 @@ import com.faforever.iceadapter.ice.Peer; import com.faforever.iceadapter.telemetry.CoturnServer; import com.nbarraille.jjsonrpc.JJsonPeer; - import java.util.Collection; import java.util.List; import java.util.concurrent.CompletableFuture; diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/debug/DebugWindow.java b/ice-adapter/src/main/java/com/faforever/iceadapter/debug/DebugWindow.java index 0aeea5e..1de7bae 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/debug/DebugWindow.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/debug/DebugWindow.java @@ -7,6 +7,9 @@ import com.faforever.iceadapter.ice.PeerConnectivityCheckerModule; import com.faforever.iceadapter.util.Executor; import com.nbarraille.jjsonrpc.JJsonPeer; +import java.io.IOException; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; import javafx.application.Application; import javafx.application.Platform; import javafx.beans.property.SimpleBooleanProperty; @@ -27,10 +30,6 @@ import org.ice4j.ice.CandidateType; import org.ice4j.ice.Component; -import java.io.IOException; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; - @Slf4j public class DebugWindow extends Application implements Debugger { public static CompletableFuture INSTANCE = new CompletableFuture<>(); @@ -45,7 +44,6 @@ public class DebugWindow extends Application implements Debugger { private final ObservableList peers = FXCollections.observableArrayList(); - @Override public void start(Stage stage) { INSTANCE = CompletableFuture.completedFuture(this); @@ -71,14 +69,14 @@ public void start(Stage stage) { stage.setScene(scene); stage.setTitle(String.format("FAF ICE adapter - Debugger - Build: %s", IceAdapter.VERSION)); -// stage.setOnCloseRequest(Event::consume); -// stage.show(); + // stage.setOnCloseRequest(Event::consume); + // stage.show(); if (Debug.ENABLE_DEBUG_WINDOW) { Executor.executeDelayed(Debug.DELAY_UI_MS, () -> runOnUIThread(stage::show)); } -// new Thread(() -> Debug.debug.complete(this)).start(); + // new Thread(() -> Debug.debug.complete(this)).start(); log.info("Created debug window."); if (Debug.ENABLE_INFO_WINDOW) { @@ -128,7 +126,8 @@ public void rpcStarted(CompletableFuture peerFuture) { controller.rpcServerStatus.setText("RPCServer: started"); }); peerFuture.thenAccept(peer -> runOnUIThread(() -> { - controller.rpcClientStatus.setText(String.format("RPCClient: %s", peer.getSocket().getInetAddress())); + controller.rpcClientStatus.setText( + String.format("RPCClient: %s", peer.getSocket().getInetAddress())); })); } @@ -142,7 +141,8 @@ public void gpgnetStarted() { @Override public void gpgnetConnectedDisconnected() { runOnUIThread(() -> { - controller.gpgnetServerStatus.setText(String.format("GPGNetClient: %s", GPGNetServer.isConnected() ? "connected" : "-")); + controller.gpgnetServerStatus.setText( + String.format("GPGNetClient: %s", GPGNetServer.isConnected() ? "connected" : "-")); gameStateChanged(); }); } @@ -150,37 +150,44 @@ public void gpgnetConnectedDisconnected() { @Override public void gameStateChanged() { runOnUIThread(() -> { - controller.gameState.setText(String.format("GameState: %s", GPGNetServer.getGameState().map(GameState::getName).orElse("-"))); + controller.gameState.setText(String.format( + "GameState: %s", + GPGNetServer.getGameState().map(GameState::getName).orElse("-"))); }); } @Override public void connectToPeer(int id, String login, boolean localOffer) { new Thread(() -> { - synchronized (peers) { - peers.add(new DebugPeer(id, login, localOffer));//Might callback into jfx - } - }).start(); + synchronized (peers) { + peers.add(new DebugPeer(id, login, localOffer)); // Might callback into jfx + } + }) + .start(); } @Override public void disconnectFromPeer(int id) { new Thread(() -> { - synchronized (peers) { - peers.removeIf(peer -> peer.id.get() == id);//Might callback into jfx - } - }).start(); + synchronized (peers) { + peers.removeIf(peer -> peer.id.get() == id); // Might callback into jfx + } + }) + .start(); } @Override public void peerStateChanged(Peer peer) { new Thread(() -> { - synchronized (peers) { - peers.stream().filter(p -> p.id.get() == peer.getRemoteId()).forEach(p -> { - p.stateChangedUpdate(peer); - }); - } - }).start(); + synchronized (peers) { + peers.stream() + .filter(p -> p.id.get() == peer.getRemoteId()) + .forEach(p -> { + p.stateChangedUpdate(peer); + }); + } + }) + .start(); } @Override @@ -208,7 +215,8 @@ public static void launchApplication() { @NoArgsConstructor @AllArgsConstructor - //@Getter //PropertyValueFactory will attempt to access fieldNameProperty(), then getFieldName() (expecting value, not property) and then isFieldName() methods + // @Getter //PropertyValueFactory will attempt to access fieldNameProperty(), then getFieldName() (expecting value, + // not property) and then isFieldName() methods public static class DebugPeer { public SimpleIntegerProperty id = new SimpleIntegerProperty(-1); public SimpleStringProperty login = new SimpleStringProperty(""); @@ -296,9 +304,13 @@ public int getInvalidEchosReceived() { return invalidEchosReceived.get(); } - public SimpleIntegerProperty echosReceivedProperty() { return echosReceived; } + public SimpleIntegerProperty echosReceivedProperty() { + return echosReceived; + } - public SimpleIntegerProperty invalidEchosReceivedProperty() { return invalidEchosReceived; } + public SimpleIntegerProperty invalidEchosReceivedProperty() { + return invalidEchosReceived; + } public String getLocalCandidate() { return localCandidate.get(); @@ -319,16 +331,40 @@ public SimpleStringProperty remoteCandidateProperty() { public void stateChangedUpdate(Peer peer) { connected.set(peer.getIce().isConnected()); state.set(peer.getIce().getIceState().getMessage()); - localCandidate.set(Optional.ofNullable(peer.getIce().getComponent()).map(Component::getSelectedPair).map(CandidatePair::getLocalCandidate).map(Candidate::getType).map(CandidateType::toString).orElse("")); - remoteCandidate.set(Optional.ofNullable(peer.getIce().getComponent()).map(Component::getSelectedPair).map(CandidatePair::getRemoteCandidate).map(Candidate::getType).map(CandidateType::toString).orElse("")); + localCandidate.set(Optional.ofNullable(peer.getIce().getComponent()) + .map(Component::getSelectedPair) + .map(CandidatePair::getLocalCandidate) + .map(Candidate::getType) + .map(CandidateType::toString) + .orElse("")); + remoteCandidate.set(Optional.ofNullable(peer.getIce().getComponent()) + .map(Component::getSelectedPair) + .map(CandidatePair::getRemoteCandidate) + .map(Candidate::getType) + .map(CandidateType::toString) + .orElse("")); } public void connectivityUpdate(Peer peer) { - Optional connectivityChecker = Optional.ofNullable(peer.getIce().getConnectivityChecker()); - averageRtt.set(connectivityChecker.map(PeerConnectivityCheckerModule::getAverageRTT).orElse(-1.0f).intValue()); - lastReceived.set(connectivityChecker.map(PeerConnectivityCheckerModule::getLastPacketReceived).map(last -> System.currentTimeMillis() - last).orElse(-1L).intValue()); - echosReceived.set(connectivityChecker.map(PeerConnectivityCheckerModule::getEchosReceived).orElse(-1L).intValue()); - echosReceived.set(connectivityChecker.map(PeerConnectivityCheckerModule::getEchosReceived).orElse(-1L).intValue()); + Optional connectivityChecker = + Optional.ofNullable(peer.getIce().getConnectivityChecker()); + averageRtt.set(connectivityChecker + .map(PeerConnectivityCheckerModule::getAverageRTT) + .orElse(-1.0f) + .intValue()); + lastReceived.set(connectivityChecker + .map(PeerConnectivityCheckerModule::getLastPacketReceived) + .map(last -> System.currentTimeMillis() - last) + .orElse(-1L) + .intValue()); + echosReceived.set(connectivityChecker + .map(PeerConnectivityCheckerModule::getEchosReceived) + .orElse(-1L) + .intValue()); + echosReceived.set(connectivityChecker + .map(PeerConnectivityCheckerModule::getEchosReceived) + .orElse(-1L) + .intValue()); } } } diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/debug/DebugWindowController.java b/ice-adapter/src/main/java/com/faforever/iceadapter/debug/DebugWindowController.java index e10906e..e4b367a 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/debug/DebugWindowController.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/debug/DebugWindowController.java @@ -1,6 +1,7 @@ package com.faforever.iceadapter.debug; import com.faforever.iceadapter.IceAdapter; +import java.util.Objects; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.*; @@ -10,102 +11,102 @@ import lombok.extern.slf4j.Slf4j; import org.slf4j.LoggerFactory; -import java.util.Objects; - - @Slf4j public class DebugWindowController { - public static DebugWindowController INSTANCE; - - public HBox genericInfo; - public Label versionLabel; - public Label userLabel; - public Label rpcPortLabel; - public Label gpgnetPortLabel; - public Label lobbyPortLabel; - public TextArea logTextArea; - public HBox rpcGpgInfo; - public HBox gpgnetInfo; - public Label rpcServerStatus; - public Label rpcClientStatus; - public HBox rpcInfo; - public Label gpgnetServerStatus; - public Label gpgnetClientStatus; - public Label gameState; - public TableView peerTable; - public TableColumn idColumn; - public TableColumn loginColumn; - public TableColumn offerColumn; - public TableColumn connectedColumn; - public TableColumn buttonReconnect; - public TableColumn stateColumn; - public TableColumn rttColumn; - public TableColumn lastColumn; - public TableColumn echosRcvColumn; - public TableColumn invalidEchosRcvColumn; - public TableColumn localCandColumn; - public TableColumn remoteCandColumn; - - public Button killAdapterButton; - - public DebugWindowController() { - - } - - public void onKillAdapterClicked(ActionEvent actionEvent) { - System.exit(337); - } - - public void reconnectToPeer(DebugWindow.DebugPeer peer) { - if (Objects.nonNull(peer)) { - new Thread(() -> IceAdapter.gameSession.reconnectToPeer(peer.getId())).start(); - } - } - - @FXML - private void initialize() { - if(Debug.ENABLE_DEBUG_WINDOW_LOG_TEXT_AREA) { - ((TextAreaLogAppender)((ch.qos.logback.classic.Logger)LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME)).getAppender("TEXTAREA")).setTextArea(logTextArea); - } - - logTextArea.textProperty().addListener((observableValue, oldVal, newVal) -> logTextArea.setScrollTop(Double.MAX_VALUE)); - - idColumn.setCellValueFactory(new PropertyValueFactory<>("id")); - loginColumn.setCellValueFactory(new PropertyValueFactory<>("login")); - offerColumn.setCellValueFactory(new PropertyValueFactory<>("localOffer")); - connectedColumn.setCellValueFactory(new PropertyValueFactory<>("connected")); - stateColumn.setCellValueFactory(new PropertyValueFactory<>("state")); - rttColumn.setCellValueFactory(new PropertyValueFactory<>("averageRtt")); - lastColumn.setCellValueFactory(new PropertyValueFactory<>("lastReceived")); - echosRcvColumn.setCellValueFactory(new PropertyValueFactory<>("echosReceived")); - invalidEchosRcvColumn.setCellValueFactory(new PropertyValueFactory<>("invalidEchosReceived")); - localCandColumn.setCellValueFactory(new PropertyValueFactory<>("localCandidate")); - remoteCandColumn.setCellValueFactory(new PropertyValueFactory<>("remoteCandidate")); - - buttonReconnect.setCellFactory(new Callback() { - @Override - public TableCell call(TableColumn param) { - return new TableCell<>() { - final Button btn = new Button("reconnect"); - - @Override - protected void updateItem(DebugWindow.DebugPeer item, boolean empty) { - super.updateItem(item, empty); - setText(null); - if (empty) { - setGraphic(null); - } else { - btn.setOnAction(event -> { - DebugWindow.DebugPeer peer = getTableRow().getItem(); - reconnectToPeer(peer); - }); - setGraphic(btn); - } - } - }; - } - }); - - killAdapterButton.setOnAction(this::onKillAdapterClicked); - } + public static DebugWindowController INSTANCE; + + public HBox genericInfo; + public Label versionLabel; + public Label userLabel; + public Label rpcPortLabel; + public Label gpgnetPortLabel; + public Label lobbyPortLabel; + public TextArea logTextArea; + public HBox rpcGpgInfo; + public HBox gpgnetInfo; + public Label rpcServerStatus; + public Label rpcClientStatus; + public HBox rpcInfo; + public Label gpgnetServerStatus; + public Label gpgnetClientStatus; + public Label gameState; + public TableView peerTable; + public TableColumn idColumn; + public TableColumn loginColumn; + public TableColumn offerColumn; + public TableColumn connectedColumn; + public TableColumn buttonReconnect; + public TableColumn stateColumn; + public TableColumn rttColumn; + public TableColumn lastColumn; + public TableColumn echosRcvColumn; + public TableColumn invalidEchosRcvColumn; + public TableColumn localCandColumn; + public TableColumn remoteCandColumn; + + public Button killAdapterButton; + + public DebugWindowController() {} + + public void onKillAdapterClicked(ActionEvent actionEvent) { + System.exit(337); + } + + public void reconnectToPeer(DebugWindow.DebugPeer peer) { + if (Objects.nonNull(peer)) { + new Thread(() -> IceAdapter.gameSession.reconnectToPeer(peer.getId())).start(); + } + } + + @FXML + private void initialize() { + if (Debug.ENABLE_DEBUG_WINDOW_LOG_TEXT_AREA) { + ((TextAreaLogAppender) + ((ch.qos.logback.classic.Logger) LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME)) + .getAppender("TEXTAREA")) + .setTextArea(logTextArea); + } + + logTextArea + .textProperty() + .addListener((observableValue, oldVal, newVal) -> logTextArea.setScrollTop(Double.MAX_VALUE)); + + idColumn.setCellValueFactory(new PropertyValueFactory<>("id")); + loginColumn.setCellValueFactory(new PropertyValueFactory<>("login")); + offerColumn.setCellValueFactory(new PropertyValueFactory<>("localOffer")); + connectedColumn.setCellValueFactory(new PropertyValueFactory<>("connected")); + stateColumn.setCellValueFactory(new PropertyValueFactory<>("state")); + rttColumn.setCellValueFactory(new PropertyValueFactory<>("averageRtt")); + lastColumn.setCellValueFactory(new PropertyValueFactory<>("lastReceived")); + echosRcvColumn.setCellValueFactory(new PropertyValueFactory<>("echosReceived")); + invalidEchosRcvColumn.setCellValueFactory(new PropertyValueFactory<>("invalidEchosReceived")); + localCandColumn.setCellValueFactory(new PropertyValueFactory<>("localCandidate")); + remoteCandColumn.setCellValueFactory(new PropertyValueFactory<>("remoteCandidate")); + + buttonReconnect.setCellFactory(new Callback() { + @Override + public TableCell call(TableColumn param) { + return new TableCell<>() { + final Button btn = new Button("reconnect"); + + @Override + protected void updateItem(DebugWindow.DebugPeer item, boolean empty) { + super.updateItem(item, empty); + setText(null); + if (empty) { + setGraphic(null); + } else { + btn.setOnAction(event -> { + DebugWindow.DebugPeer peer = getTableRow().getItem(); + reconnectToPeer(peer); + }); + setGraphic(btn); + } + } + }; + } + }); + + killAdapterButton.setOnAction(this::onKillAdapterClicked); + } } diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/debug/Debugger.java b/ice-adapter/src/main/java/com/faforever/iceadapter/debug/Debugger.java index dbbf857..e2e6edc 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/debug/Debugger.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/debug/Debugger.java @@ -3,7 +3,6 @@ import com.faforever.iceadapter.ice.Peer; import com.faforever.iceadapter.telemetry.CoturnServer; import com.nbarraille.jjsonrpc.JJsonPeer; - import java.util.Collection; import java.util.concurrent.CompletableFuture; @@ -27,6 +26,5 @@ public interface Debugger { void peerConnectivityUpdate(Peer peer); - default void updateCoturnList(Collection servers) { - } + default void updateCoturnList(Collection servers) {} } diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/debug/InfoWindow.java b/ice-adapter/src/main/java/com/faforever/iceadapter/debug/InfoWindow.java index 527391b..7ed324a 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/debug/InfoWindow.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/debug/InfoWindow.java @@ -1,5 +1,9 @@ package com.faforever.iceadapter.debug; +import static javafx.application.Application.STYLESHEET_MODENA; +import static javafx.application.Application.setUserAgentStylesheet; + +import java.io.IOException; import javafx.application.Platform; import javafx.event.Event; import javafx.fxml.FXMLLoader; @@ -9,64 +13,58 @@ import javafx.stage.Stage; import lombok.extern.slf4j.Slf4j; -import java.io.IOException; - -import static javafx.application.Application.STYLESHEET_MODENA; -import static javafx.application.Application.setUserAgentStylesheet; - @Slf4j public class InfoWindow { - public static InfoWindow INSTANCE; - - private Stage stage; - private Parent root; - private Scene scene; - private InfoWindowController controller; + public static InfoWindow INSTANCE; - private static final int WIDTH = 533; - private static final int HEIGHT = 330; + private Stage stage; + private Parent root; + private Scene scene; + private InfoWindowController controller; - public InfoWindow() { - INSTANCE = this; - } + private static final int WIDTH = 533; + private static final int HEIGHT = 330; - public void init() { - stage = new Stage(); - stage.getIcons().add(new Image("https://faforever.com/images/faf-logo.png")); + public InfoWindow() { + INSTANCE = this; + } - try { - FXMLLoader loader = new FXMLLoader(getClass().getResource("/infoWindow.fxml")); - root = loader.load(); + public void init() { + stage = new Stage(); + stage.getIcons().add(new Image("https://faforever.com/images/faf-logo.png")); - controller = loader.getController(); + try { + FXMLLoader loader = new FXMLLoader(getClass().getResource("/infoWindow.fxml")); + root = loader.load(); - } catch (IOException e) { - log.error("Could not load debugger window fxml", e); - } + controller = loader.getController(); - setUserAgentStylesheet(STYLESHEET_MODENA); + } catch (IOException e) { + log.error("Could not load debugger window fxml", e); + } - scene = new Scene(root, WIDTH, HEIGHT); + setUserAgentStylesheet(STYLESHEET_MODENA); - stage.setScene(scene); - stage.setTitle("FAF ICE adapter"); - stage.setOnCloseRequest(Event::consume); - stage.show(); + scene = new Scene(root, WIDTH, HEIGHT); + stage.setScene(scene); + stage.setTitle("FAF ICE adapter"); + stage.setOnCloseRequest(Event::consume); + stage.show(); - log.info("Created info window."); - } + log.info("Created info window."); + } - public void minimize() { - Platform.setImplicitExit(false); - Platform.runLater(this.stage::hide); - } + public void minimize() { + Platform.setImplicitExit(false); + Platform.runLater(this.stage::hide); + } - public void show() { - Platform.runLater(() -> { - this.stage.show(); - Platform.setImplicitExit(true); - }); - } + public void show() { + Platform.runLater(() -> { + this.stage.show(); + Platform.setImplicitExit(true); + }); + } } diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/debug/InfoWindowController.java b/ice-adapter/src/main/java/com/faforever/iceadapter/debug/InfoWindowController.java index db5f9d1..7fcf2a7 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/debug/InfoWindowController.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/debug/InfoWindowController.java @@ -2,31 +2,28 @@ import com.faforever.iceadapter.IceAdapter; import com.faforever.iceadapter.util.TrayIcon; -import javafx.application.Platform; +import java.awt.*; +import java.io.IOException; +import java.net.URI; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.Button; import lombok.SneakyThrows; -import java.awt.*; -import java.io.IOException; -import java.net.URI; -import java.util.concurrent.ExecutorService; - public class InfoWindowController { public Button killAdapterButton; public Button showDebugWindowButton; public Button showTelemetryWebUiButton; public Button minimizeToTray; - private volatile int killRequests = 0; public void onKillAdapterClicked(ActionEvent actionEvent) { killRequests++; if (killRequests < 3) { - killAdapterButton.setText("This will disconnect you from the game! Click " + (3 - killRequests) + " more times."); + killAdapterButton.setText( + "This will disconnect you from the game! Click " + (3 - killRequests) + " more times."); } else { System.exit(337); } @@ -38,19 +35,17 @@ public void onShowDebugWindowClicked(ActionEvent actionEvent) { @SneakyThrows public void onTelemetryWebUiClicked(ActionEvent actionEvent) { - String url = "%s/app.html?gameId=%d&playerId=%d".formatted( - IceAdapter.TELEMETRY_SERVER.replaceFirst("ws", "http"), - IceAdapter.gameId, - IceAdapter.id - ); + String url = "%s/app.html?gameId=%d&playerId=%d" + .formatted(IceAdapter.TELEMETRY_SERVER.replaceFirst("ws", "http"), IceAdapter.gameId, IceAdapter.id); new Thread(() -> { - try { - Desktop.getDesktop().browse(URI.create(url)); - } catch (IOException e) { - throw new RuntimeException(e); - } - }).start(); + try { + Desktop.getDesktop().browse(URI.create(url)); + } catch (IOException e) { + throw new RuntimeException(e); + } + }) + .start(); } public void onMinimizeToTrayClicked(ActionEvent actionEvent) { diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/debug/TelemetryDebugger.java b/ice-adapter/src/main/java/com/faforever/iceadapter/debug/TelemetryDebugger.java index 3bf7a2e..81a80e8 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/debug/TelemetryDebugger.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/debug/TelemetryDebugger.java @@ -18,15 +18,6 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.google.common.util.concurrent.RateLimiter; import com.nbarraille.jjsonrpc.JJsonPeer; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.ice4j.ice.Candidate; -import org.ice4j.ice.CandidatePair; -import org.ice4j.ice.Component; -import org.java_websocket.client.WebSocketClient; -import org.java_websocket.handshake.ServerHandshake; - -import java.io.IOException; import java.net.ConnectException; import java.net.URI; import java.time.Instant; @@ -38,6 +29,13 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.LinkedBlockingQueue; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.ice4j.ice.Candidate; +import org.ice4j.ice.CandidatePair; +import org.ice4j.ice.Component; +import org.java_websocket.client.WebSocketClient; +import org.java_websocket.handshake.ServerHandshake; @Slf4j public class TelemetryDebugger implements Debugger { @@ -53,7 +51,11 @@ public TelemetryDebugger(String telemetryServer, int gameId, int playerId) { Debug.register(this); URI uri = URI.create("%s/adapter/v1/game/%d/player/%d".formatted(telemetryServer, gameId, playerId)); - log.info("Open the telemetry ui via {}/app.html?gameId={}&playerId={}", telemetryServer.replaceFirst("ws", "http"), gameId, playerId); + log.info( + "Open the telemetry ui via {}/app.html?gameId={}&playerId={}", + telemetryServer.replaceFirst("ws", "http"), + gameId, + playerId); websocketClient = new WebSocketClient(uri) { @Override @@ -78,7 +80,6 @@ public void onError(Exception ex) { Debug.remove(TelemetryDebugger.this); } else { log.error("Error in Telemetry websocket", ex); - } } }; @@ -87,7 +88,8 @@ public void onError(Exception ex) { objectMapper.registerModule(new JavaTimeModule()); sendingLoopThread = new Thread(this::sendingLoop, "sendingLoop"); - sendingLoopThread.setUncaughtExceptionHandler((t, e) -> log.error("Thread sendingLoop crashed unexpectedly", e)); + sendingLoopThread.setUncaughtExceptionHandler( + (t, e) -> log.error("Thread sendingLoop crashed unexpectedly", e)); sendingLoopThread.start(); } @@ -106,7 +108,7 @@ private void sendingLoop() { try { String json = objectMapper.writeValueAsString(message); - if(websocketClient.isClosed()) { + if (websocketClient.isClosed()) { log.warn("Telemetry websocket is closed"); websocketClient.reconnectBlocking(); log.info("Telemetry websocket reconnected"); @@ -132,11 +134,7 @@ public void startupComplete() { log.error("Failed to connect to telemetry websocket", e); } - sendMessage(new RegisterAsPeer( - UUID.randomUUID(), - "java-ice-adapter/"+IceAdapter.VERSION, - IceAdapter.login - )); + sendMessage(new RegisterAsPeer(UUID.randomUUID(), "java-ice-adapter/" + IceAdapter.VERSION, IceAdapter.login)); } @Override @@ -147,26 +145,21 @@ public void rpcStarted(CompletableFuture peerFuture) { @Override public void gpgnetStarted() { - sendMessage(new UpdateGpgnetState( - UUID.randomUUID(), - "WAITING_FOR_GAME" - )); + sendMessage(new UpdateGpgnetState(UUID.randomUUID(), "WAITING_FOR_GAME")); } @Override public void gpgnetConnectedDisconnected() { sendMessage(new UpdateGpgnetState( - UUID.randomUUID(), - GPGNetServer.isConnected() ? "GAME_CONNECTED" : "WAITING_FOR_GAME" - )); + UUID.randomUUID(), GPGNetServer.isConnected() ? "GAME_CONNECTED" : "WAITING_FOR_GAME")); } @Override public void gameStateChanged() { sendMessage(new UpdateGameState( - UUID.randomUUID(), GPGNetServer.getGameState() - .orElseThrow(() -> new IllegalStateException("gameState must not change to null"))) - ); + UUID.randomUUID(), + GPGNetServer.getGameState() + .orElseThrow(() -> new IllegalStateException("gameState must not change to null")))); } @Override @@ -195,8 +188,7 @@ public void peerStateChanged(Peer peer) { .map(Component::getSelectedPair) .map(CandidatePair::getRemoteCandidate) .map(Candidate::getType) - .orElse(null) - )); + .orElse(null))); } @Override @@ -205,7 +197,10 @@ public void peerConnectivityUpdate(Peer peer) { .computeIfAbsent(peer.getRemoteId(), i -> RateLimiter.create(1.0)) .tryAcquire()) { // We only want to send one connectivity update per second (per peer) - log.trace("Rate limiting prevents connectivity update for peer {} (id {})", peer.getRemoteLogin(), peer.getRemoteId()); + log.trace( + "Rate limiting prevents connectivity update for peer {} (id {})", + peer.getRemoteLogin(), + peer.getRemoteId()); return; } @@ -220,8 +215,7 @@ public void peerConnectivityUpdate(Peer peer) { Optional.ofNullable(peer.getIce().getConnectivityChecker()) .map(PeerConnectivityCheckerModule::getLastPacketReceived) .map(Instant::ofEpochMilli) - .orElse(null) - )); + .orElse(null))); } @Override @@ -229,7 +223,6 @@ public void updateCoturnList(Collection servers) { sendMessage(new UpdateCoturnList( UUID.randomUUID(), servers.stream().map(CoturnServer::host).findFirst().orElse(null), - servers - )); + servers)); } } diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/debug/TextAreaLogAppender.java b/ice-adapter/src/main/java/com/faforever/iceadapter/debug/TextAreaLogAppender.java index 3f74884..9f63bc1 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/debug/TextAreaLogAppender.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/debug/TextAreaLogAppender.java @@ -1,84 +1,81 @@ package com.faforever.iceadapter.debug; import ch.qos.logback.core.OutputStreamAppender; -import javafx.application.Platform; - import java.io.FilterOutputStream; import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; +import javafx.application.Platform; public class TextAreaLogAppender extends OutputStreamAppender { - private TextAreaOutputStream textAreaOutputStream = new TextAreaOutputStream(); - - public TextAreaLogAppender() { - } - - public void setTextArea(Object textArea) { - textAreaOutputStream.setTextArea(textArea); - } - - @Override - public void start() { - setOutputStream(new FilterOutputStream(textAreaOutputStream)); - super.start(); - } - - - private static class TextAreaOutputStream extends OutputStream { - - private Object textArea; - private Method textAreaAppendMethod; - private List buffer = new ArrayList<>(); - - public TextAreaOutputStream() { - - } - - @Override - public void write(int b) { - if(DebugWindow.INSTANCE.isDone()) { - if(! buffer.isEmpty()) { - buffer.clear(); - } - } - - if(textArea != null) { - while(! buffer.isEmpty()) { - appendText(String.valueOf((char) buffer.remove(0).intValue())); - } - appendText(String.valueOf((char) b)); - } else { - buffer.add(b); - } - } - - private void appendText(String text) { - Platform.runLater(() -> { - try { - textAreaAppendMethod.invoke(textArea, text); - } catch (IllegalAccessException | InvocationTargetException e) { - e.printStackTrace(); - throw new RuntimeException("Could not append log to textArea"); - } - }); - } - - public void setTextArea(Object textArea) { - if(! textArea.getClass().getCanonicalName().equals("javafx.scene.control.TextArea")) { - throw new RuntimeException(String.format("Object is of class %s, expected javafx.scene.control.TextArea", textArea.getClass().getCanonicalName())); - } - this.textArea = textArea; - try { - this.textAreaAppendMethod = textArea.getClass().getMethod("appendText", String.class); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - throw new RuntimeException("Could not instantiate TextAreaLogAppender, could not find TextArea appendText method"); - } - } - } - + private TextAreaOutputStream textAreaOutputStream = new TextAreaOutputStream(); + + public TextAreaLogAppender() {} + + public void setTextArea(Object textArea) { + textAreaOutputStream.setTextArea(textArea); + } + + @Override + public void start() { + setOutputStream(new FilterOutputStream(textAreaOutputStream)); + super.start(); + } + + private static class TextAreaOutputStream extends OutputStream { + + private Object textArea; + private Method textAreaAppendMethod; + private List buffer = new ArrayList<>(); + + public TextAreaOutputStream() {} + + @Override + public void write(int b) { + if (DebugWindow.INSTANCE.isDone()) { + if (!buffer.isEmpty()) { + buffer.clear(); + } + } + + if (textArea != null) { + while (!buffer.isEmpty()) { + appendText(String.valueOf((char) buffer.remove(0).intValue())); + } + appendText(String.valueOf((char) b)); + } else { + buffer.add(b); + } + } + + private void appendText(String text) { + Platform.runLater(() -> { + try { + textAreaAppendMethod.invoke(textArea, text); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + throw new RuntimeException("Could not append log to textArea"); + } + }); + } + + public void setTextArea(Object textArea) { + if (!textArea.getClass().getCanonicalName().equals("javafx.scene.control.TextArea")) { + throw new RuntimeException(String.format( + "Object is of class %s, expected javafx.scene.control.TextArea", + textArea.getClass().getCanonicalName())); + } + this.textArea = textArea; + try { + this.textAreaAppendMethod = textArea.getClass().getMethod("appendText", String.class); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + throw new RuntimeException( + "Could not instantiate TextAreaLogAppender, could not find TextArea appendText method"); + } + } + } } diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/gpgnet/FaDataInputStream.java b/ice-adapter/src/main/java/com/faforever/iceadapter/gpgnet/FaDataInputStream.java index 189dad8..4809b23 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/gpgnet/FaDataInputStream.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/gpgnet/FaDataInputStream.java @@ -1,7 +1,6 @@ package com.faforever.iceadapter.gpgnet; import com.google.common.io.LittleEndianDataInputStream; - import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/gpgnet/FaDataOutputStream.java b/ice-adapter/src/main/java/com/faforever/iceadapter/gpgnet/FaDataOutputStream.java index 0886c13..02bb91a 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/gpgnet/FaDataOutputStream.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/gpgnet/FaDataOutputStream.java @@ -1,7 +1,6 @@ package com.faforever.iceadapter.gpgnet; import com.google.common.io.LittleEndianDataOutputStream; - import java.io.BufferedOutputStream; import java.io.IOException; import java.io.OutputStream; diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/gpgnet/GPGNetServer.java b/ice-adapter/src/main/java/com/faforever/iceadapter/gpgnet/GPGNetServer.java index fb4164a..50c6088 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/gpgnet/GPGNetServer.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/gpgnet/GPGNetServer.java @@ -1,11 +1,10 @@ package com.faforever.iceadapter.gpgnet; +import static com.faforever.iceadapter.debug.Debug.debug; + import com.faforever.iceadapter.IceAdapter; import com.faforever.iceadapter.rpc.RPCService; import com.faforever.iceadapter.util.NetworkToolbox; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; - import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; @@ -15,20 +14,19 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; - -import static com.faforever.iceadapter.debug.Debug.debug; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; @Slf4j public class GPGNetServer { private static ServerSocket serverSocket; private static volatile GPGNetClient currentClient; - //Used by other services to get a callback on FA connecting + // Used by other services to get a callback on FA connecting public static volatile CompletableFuture clientFuture = new CompletableFuture<>(); public static volatile LobbyInitMode lobbyInitMode = LobbyInitMode.NORMAL; - public static void init() { if (IceAdapter.GPGNET_PORT == 0) { IceAdapter.GPGNET_PORT = NetworkToolbox.findFreeTCPPort(20000, 65536); @@ -84,7 +82,6 @@ private GPGNetClient(Socket socket) { log.info("GPGNetClient has connected"); } - /** * Process an incoming message from FA */ @@ -95,7 +92,13 @@ private void processGpgnetMessage(String command, List args) { log.debug("New GameState: {}", gameState.getName()); if (gameState == GameState.IDLE) { - sendGpgnetMessage("CreateLobby", lobbyInitMode.getId(), IceAdapter.LOBBY_PORT, IceAdapter.login, IceAdapter.id, 1); + sendGpgnetMessage( + "CreateLobby", + lobbyInitMode.getId(), + IceAdapter.LOBBY_PORT, + IceAdapter.login, + IceAdapter.id, + 1); } else if (gameState == GameState.LOBBY) { lobbyFuture.complete(this); } @@ -109,11 +112,14 @@ private void processGpgnetMessage(String command, List args) { } } default -> { - //No need to log, as we are not processing all messages but just forward them via RPC + // No need to log, as we are not processing all messages but just forward them via RPC } } - log.info("Received GPGNet message: {} {}", command, args.stream().map(Object::toString).collect(Collectors.joining(" "))); + log.info( + "Received GPGNet message: {} {}", + command, + args.stream().map(Object::toString).collect(Collectors.joining(" "))); RPCService.onGpgNetMessageReceived(command, args); } @@ -123,7 +129,10 @@ private void processGpgnetMessage(String command, List args) { public synchronized void sendGpgnetMessage(String command, Object... args) { try { gpgnetOut.writeMessage(command, args); - log.info("Sent GPGNet message: {} {}", command, Arrays.stream(args).map(Object::toString).collect(Collectors.joining(" "))); + log.info( + "Sent GPGNet message: {} {}", + command, + Arrays.stream(args).map(Object::toString).collect(Collectors.joining(" "))); } catch (IOException e) { log.error("Error while communicating with FA (output), assuming shutdown", e); GPGNetServer.onGpgnetConnectionLost(); @@ -135,9 +144,11 @@ public synchronized void sendGpgnetMessage(String command, Object... args) { */ private void listenerThread() { log.debug("Listening for GPG messages"); - boolean triggerActive = false;//Prevents a race condition between this thread and the thread that has created this object and is now going to set GPGNetServer.currentClient + boolean triggerActive = + false; // Prevents a race condition between this thread and the thread that has created this object + // and is now going to set GPGNetServer.currentClient try (var inputStream = socket.getInputStream(); - var gpgnetIn = new FaDataInputStream(inputStream)) { + var gpgnetIn = new FaDataInputStream(inputStream)) { while ((!triggerActive || GPGNetServer.currentClient == this) && !stopping) { String command = gpgnetIn.readString(); List args = gpgnetIn.readChunks(); @@ -145,7 +156,8 @@ private void listenerThread() { processGpgnetMessage(command, args); if (!triggerActive && GPGNetServer.currentClient != null) { - triggerActive = true;//From now on we will check GPGNetServer.currentClient to see if we should stop + triggerActive = + true; // From now on we will check GPGNetServer.currentClient to see if we should stop } } } catch (IOException e) { diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/gpgnet/GameState.java b/ice-adapter/src/main/java/com/faforever/iceadapter/gpgnet/GameState.java index 497a533..72a5750 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/gpgnet/GameState.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/gpgnet/GameState.java @@ -1,13 +1,12 @@ package com.faforever.iceadapter.gpgnet; +import java.util.Arrays; import lombok.Getter; import lombok.RequiredArgsConstructor; -import java.util.Arrays; - /** * GameState as sent by FA, - ENDED was added by the FAF project + * ENDED was added by the FAF project */ @Getter @RequiredArgsConstructor @@ -16,7 +15,7 @@ public enum GameState { IDLE("Idle"), LOBBY("Lobby"), LAUNCHING("Launching"), - ENDED("Ended"); //TODO: more? + ENDED("Ended"); // TODO: more? private final String name; diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/gpgnet/LobbyInitMode.java b/ice-adapter/src/main/java/com/faforever/iceadapter/gpgnet/LobbyInitMode.java index 240183c..6c3d463 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/gpgnet/LobbyInitMode.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/gpgnet/LobbyInitMode.java @@ -1,17 +1,17 @@ package com.faforever.iceadapter.gpgnet; +import java.util.Arrays; import lombok.Getter; import lombok.RequiredArgsConstructor; -import java.util.Arrays; - /** * Lobby init mode, set by the client via RPC, transmitted to game via CreateLobby */ @Getter @RequiredArgsConstructor public enum LobbyInitMode { - NORMAL("normal", 0), AUTO("auto", 1); //Normal = normal lobby, Auto = skip lobby screen (e.g. ranked) + NORMAL("normal", 0), + AUTO("auto", 1); // Normal = normal lobby, Auto = skip lobby screen (e.g. ranked) private final String name; private final int id; @@ -23,4 +23,3 @@ public static LobbyInitMode getByName(String name) { .orElse(null); } } - diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/ice/CandidatePacket.java b/ice-adapter/src/main/java/com/faforever/iceadapter/ice/CandidatePacket.java index 7b2b5f5..f5fee69 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/ice/CandidatePacket.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/ice/CandidatePacket.java @@ -15,8 +15,8 @@ public record CandidatePacket( int generation, String id, String relAddr, - int relPort -) implements Comparable { + int relPort) + implements Comparable { @Override public int compareTo(CandidatePacket o) { return (int) (o.priority - this.priority); diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/ice/CandidatesMessage.java b/ice-adapter/src/main/java/com/faforever/iceadapter/ice/CandidatesMessage.java index cb7a656..1a965c6 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/ice/CandidatesMessage.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/ice/CandidatesMessage.java @@ -6,12 +6,7 @@ * Represents and IceMessage, consists out of candidates and ufrag aswell as password */ public record CandidatesMessage( - int srcId, - int destId, - String password, - String ufrag, - List candidates -) { + int srcId, int destId, String password, String ufrag, List candidates) { public CandidatesMessage { candidates = List.copyOf(candidates); } diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/ice/GameSession.java b/ice-adapter/src/main/java/com/faforever/iceadapter/ice/GameSession.java index 82b2f38..399c274 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/ice/GameSession.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/ice/GameSession.java @@ -1,17 +1,13 @@ package com.faforever.iceadapter.ice; +import static com.faforever.iceadapter.debug.Debug.debug; + import com.faforever.iceadapter.IceAdapter; import com.faforever.iceadapter.telemetry.CoturnServer; import com.faforever.iceadapter.util.PingWrapper; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; -import lombok.Getter; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; -import org.ice4j.Transport; -import org.ice4j.TransportAddress; - import java.net.URI; import java.util.ArrayList; import java.util.Arrays; @@ -25,8 +21,11 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; - -import static com.faforever.iceadapter.debug.Debug.debug; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.ice4j.Transport; +import org.ice4j.TransportAddress; /** * Represents a game session and the current ICE status/communication with all peers @@ -37,15 +36,15 @@ public class GameSession { private static final String STUN = "stun"; private static final String TURN = "turn"; + @Getter private final Map peers = new ConcurrentHashMap<>(); + @Getter @Setter private volatile boolean gameEnded = false; - public GameSession() { - - } + public GameSession() {} /** * Initiates a connection to a peer (ICE) @@ -68,8 +67,8 @@ public void disconnectFromPeer(int remotePlayerId) { removedPeer.close(); debug().disconnectFromPeer(remotePlayerId); } - //TODO: still testing connectivity and reporting disconnect via rpc, why??? - //TODO: still attempting to ICE + // TODO: still testing connectivity and reporting disconnect via rpc, why??? + // TODO: still attempting to ICE } /** @@ -81,8 +80,7 @@ public void reconnectToPeer(Integer remotePlayerId) { if (Objects.nonNull(reconnectPeer)) { String remotePlayerLogin = reconnectPeer.getRemoteLogin(); boolean offer = reconnectPeer.isLocalOffer(); - int port = reconnectPeer.getFaSocket() - .getLocalPort(); + int port = reconnectPeer.getFaSocket().getLocalPort(); disconnectFromPeer(remotePlayerId); connectToPeer(remotePlayerLogin, remotePlayerId, offer, port); @@ -114,14 +112,14 @@ public static void setIceServers(List> iceServersData) { // For caching RTT to a given host (the same host can appear in multiple urls) LoadingCache> hostRTTCache = CacheBuilder.newBuilder() - .build(new CacheLoader<>() { - @Override - public CompletableFuture load(String host) { - return PingWrapper.getLatency(host, IceAdapter.PING_COUNT) - .thenApply(OptionalDouble::of) - .exceptionally(ex -> OptionalDouble.empty()); - } - }); + .build(new CacheLoader<>() { + @Override + public CompletableFuture load(String host) { + return PingWrapper.getLatency(host, IceAdapter.PING_COUNT) + .thenApply(OptionalDouble::of) + .exceptionally(ex -> OptionalDouble.empty()); + } + }); Set coturnServers = new HashSet<>(); @@ -144,40 +142,42 @@ public CompletableFuture load(String host) { urls = Collections.singletonList((String) iceServerData.get("url")); } - urls.stream().map(stringUrl -> { - try { - return new URI(stringUrl); - } catch (Exception e) { - log.warn("Invalid ICE server URI: {}", stringUrl); - return null; - } - }).filter(Objects::nonNull).forEach(uri -> { - String host = uri.getHost(); - int port = uri.getPort() == -1 ? 3478 : uri.getPort(); - Transport transport = Optional.ofNullable(uri.getQuery()) - .stream() - .flatMap(query -> Arrays.stream(query.split("&"))) - .map(param -> param.split("=")) - .filter(param -> param.length == 2) - .filter(param -> param[0].equals("transport")) - .map(param -> param[1]) - .map(Transport::parse) - .findFirst() - .orElse(Transport.UDP); - - TransportAddress address = new TransportAddress(host, port, transport); - switch (uri.getScheme()) { - case STUN -> iceServer.getStunAddresses().add(address); - case TURN -> iceServer.getTurnAddresses().add(address); - default -> log.warn("Invalid ICE server protocol: {}", uri); - } - - if (IceAdapter.PING_COUNT > 0) { - iceServer.setRoundTripTime(hostRTTCache.getUnchecked(host)); - } - - coturnServers.add(new CoturnServer("n/a", host, port, null)); - }); + urls.stream() + .map(stringUrl -> { + try { + return new URI(stringUrl); + } catch (Exception e) { + log.warn("Invalid ICE server URI: {}", stringUrl); + return null; + } + }) + .filter(Objects::nonNull) + .forEach(uri -> { + String host = uri.getHost(); + int port = uri.getPort() == -1 ? 3478 : uri.getPort(); + Transport transport = Optional.ofNullable(uri.getQuery()).stream() + .flatMap(query -> Arrays.stream(query.split("&"))) + .map(param -> param.split("=")) + .filter(param -> param.length == 2) + .filter(param -> param[0].equals("transport")) + .map(param -> param[1]) + .map(Transport::parse) + .findFirst() + .orElse(Transport.UDP); + + TransportAddress address = new TransportAddress(host, port, transport); + switch (uri.getScheme()) { + case STUN -> iceServer.getStunAddresses().add(address); + case TURN -> iceServer.getTurnAddresses().add(address); + default -> log.warn("Invalid ICE server protocol: {}", uri); + } + + if (IceAdapter.PING_COUNT > 0) { + iceServer.setRoundTripTime(hostRTTCache.getUnchecked(host)); + } + + coturnServers.add(new CoturnServer("n/a", host, port, null)); + }); } iceServers.add(iceServer); @@ -185,10 +185,11 @@ public CompletableFuture load(String host) { debug().updateCoturnList(coturnServers); - log.info("Ice Servers set, total addresses: {}", - iceServers.stream() - .mapToInt(iceServer -> iceServer.getStunAddresses().size() + - iceServer.getTurnAddresses().size()) - .sum()); + log.info( + "Ice Servers set, total addresses: {}", + iceServers.stream() + .mapToInt(iceServer -> iceServer.getStunAddresses().size() + + iceServer.getTurnAddresses().size()) + .sum()); } } diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/ice/IceServer.java b/ice-adapter/src/main/java/com/faforever/iceadapter/ice/IceServer.java index b5d6cf4..c4e6d25 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/ice/IceServer.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/ice/IceServer.java @@ -1,27 +1,27 @@ package com.faforever.iceadapter.ice; import com.faforever.iceadapter.IceAdapter; -import lombok.Data; -import org.ice4j.TransportAddress; - import java.util.ArrayList; import java.util.List; import java.util.OptionalDouble; import java.util.concurrent.CompletableFuture; import java.util.regex.Pattern; +import lombok.Data; +import org.ice4j.TransportAddress; @Data public class IceServer { - private List stunAddresses = new ArrayList<>(); - private List turnAddresses = new ArrayList<>(); - private String turnUsername = ""; - private String turnCredential = ""; - private CompletableFuture roundTripTime = CompletableFuture.completedFuture(OptionalDouble.empty()); + private List stunAddresses = new ArrayList<>(); + private List turnAddresses = new ArrayList<>(); + private String turnUsername = ""; + private String turnCredential = ""; + private CompletableFuture roundTripTime = CompletableFuture.completedFuture(OptionalDouble.empty()); - public static final Pattern urlPattern = Pattern.compile("(?stun|turn):(?(\\w|\\.)+)(:(?\\d+))?(\\?transport=(?(tcp|udp)))?"); + public static final Pattern urlPattern = Pattern.compile( + "(?stun|turn):(?(\\w|\\.)+)(:(?\\d+))?(\\?transport=(?(tcp|udp)))?"); - public boolean hasAcceptableLatency() { - OptionalDouble rtt = this.getRoundTripTime().join(); - return !rtt.isPresent() || rtt.getAsDouble() < IceAdapter.ACCEPTABLE_LATENCY; - } + public boolean hasAcceptableLatency() { + OptionalDouble rtt = this.getRoundTripTime().join(); + return !rtt.isPresent() || rtt.getAsDouble() < IceAdapter.ACCEPTABLE_LATENCY; + } } diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/ice/IceState.java b/ice-adapter/src/main/java/com/faforever/iceadapter/ice/IceState.java index e8ccd17..536e780 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/ice/IceState.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/ice/IceState.java @@ -18,4 +18,4 @@ public enum IceState { DISCONNECTED("disconnected"); private final String message; -} \ No newline at end of file +} diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/ice/Peer.java b/ice-adapter/src/main/java/com/faforever/iceadapter/ice/Peer.java index 039944f..e09c222 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/ice/Peer.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/ice/Peer.java @@ -1,11 +1,10 @@ package com.faforever.iceadapter.ice; import com.faforever.iceadapter.IceAdapter; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; - import java.io.IOException; import java.net.*; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; /** * Represents a peer in the current game session which we are connected to @@ -18,13 +17,13 @@ public class Peer { private final int remoteId; private final String remoteLogin; - private final boolean localOffer;//Do we offer or are we waiting for a remote offer + private final boolean localOffer; // Do we offer or are we waiting for a remote offer private final int preferredPort; public volatile boolean closing = false; private final PeerIceModule ice = new PeerIceModule(this); - private DatagramSocket faSocket;//Socket on which we are listening for FA / sending data to FA + private DatagramSocket faSocket; // Socket on which we are listening for FA / sending data to FA public Peer(GameSession gameSession, int remoteId, String remoteLogin, boolean localOffer, int preferredPort) { this.gameSession = gameSession; @@ -33,7 +32,11 @@ public Peer(GameSession gameSession, int remoteId, String remoteLogin, boolean l this.localOffer = localOffer; this.preferredPort = preferredPort; - log.debug("Peer created: {}, localOffer: {}, preferredPort: {}", getPeerIdentifier(), String.valueOf(localOffer), preferredPort); + log.debug( + "Peer created: {}, localOffer: {}, preferredPort: {}", + getPeerIdentifier(), + String.valueOf(localOffer), + preferredPort); initForwarding(preferredPort); @@ -65,14 +68,18 @@ private void initForwarding(int port) { */ synchronized void onIceDataReceived(byte data[], int offset, int length) { try { - DatagramPacket packet = new DatagramPacket(data, offset, length, InetAddress.getByName("127.0.0.1"), IceAdapter.LOBBY_PORT); + DatagramPacket packet = + new DatagramPacket(data, offset, length, InetAddress.getByName("127.0.0.1"), IceAdapter.LOBBY_PORT); faSocket.send(packet); } catch (UnknownHostException e) { } catch (IOException e) { if (closing) { log.debug("Ignoring error the send packet because the connection was closed {}", getPeerIdentifier()); } else { - log.error("Error while writing to local FA as peer (probably disconnecting from peer) {}", getPeerIdentifier(), e); + log.error( + "Error while writing to local FA as peer (probably disconnecting from peer) {}", + getPeerIdentifier(), + e); } } } @@ -81,7 +88,8 @@ synchronized void onIceDataReceived(byte data[], int offset, int length) { * This method get's invoked by the thread listening for data from FA */ private void faListener() { - byte data[] = new byte[65536];//64KiB = UDP MTU, in practice due to ethernet frames being <= 1500 B, this is often not used + byte data[] = new byte + [65536]; // 64KiB = UDP MTU, in practice due to ethernet frames being <= 1500 B, this is often not used while (IceAdapter.running && IceAdapter.gameSession == gameSession) { try { DatagramPacket packet = new DatagramPacket(data, data.length); @@ -89,9 +97,14 @@ private void faListener() { ice.onFaDataReceived(data, packet.getLength()); } catch (IOException e) { if (closing) { - log.debug("Ignoring error the receive packet because the connection was closed as peer {}", getPeerIdentifier()); + log.debug( + "Ignoring error the receive packet because the connection was closed as peer {}", + getPeerIdentifier()); } else { - log.debug("Error while reading from local FA as peer (probably disconnecting from peer) {}", getPeerIdentifier(), e); + log.debug( + "Error while reading from local FA as peer (probably disconnecting from peer) {}", + getPeerIdentifier(), + e); } return; } @@ -100,14 +113,14 @@ private void faListener() { } public void close() { - if(closing) { + if (closing) { return; } log.info("Closing peer for player {}", getPeerIdentifier()); closing = true; - if(faSocket != null) { + if (faSocket != null) { faSocket.close(); } diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/ice/PeerConnectivityCheckerModule.java b/ice-adapter/src/main/java/com/faforever/iceadapter/ice/PeerConnectivityCheckerModule.java index cf0239a..d32a477 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/ice/PeerConnectivityCheckerModule.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/ice/PeerConnectivityCheckerModule.java @@ -1,13 +1,12 @@ package com.faforever.iceadapter.ice; +import static com.faforever.iceadapter.debug.Debug.debug; + import com.google.common.primitives.Longs; +import java.util.Arrays; import lombok.Getter; import lombok.extern.slf4j.Slf4j; -import java.util.Arrays; - -import static com.faforever.iceadapter.debug.Debug.debug; - @Slf4j /** * Periodically sends echo requests via the ICE data channel and initiates a reconnect after timeout @@ -21,10 +20,17 @@ public class PeerConnectivityCheckerModule { private volatile boolean running = false; private volatile Thread checkerThread; - @Getter private float averageRTT = 0.0f; - @Getter private long lastPacketReceived; - @Getter private long echosReceived = 0; - @Getter private long invalidEchosReceived = 0; + @Getter + private float averageRTT = 0.0f; + + @Getter + private long lastPacketReceived; + + @Getter + private long echosReceived = 0; + + @Getter + private long invalidEchosReceived = 0; public PeerConnectivityCheckerModule(PeerIceModule ice) { this.ice = ice; @@ -42,12 +48,13 @@ synchronized void start() { lastPacketReceived = System.currentTimeMillis(); checkerThread = new Thread(this::checkerThread, getThreadName()); - checkerThread.setUncaughtExceptionHandler((t, e) -> log.error("Thread {} crashed unexpectedly", t.getName(), e)); + checkerThread.setUncaughtExceptionHandler( + (t, e) -> log.error("Thread {} crashed unexpectedly", t.getName(), e)); checkerThread.start(); } private String getThreadName() { - return "connectivityChecker-"+ice.getPeer().getRemoteId(); + return "connectivityChecker-" + ice.getPeer().getRemoteId(); } synchronized void stop() { @@ -77,7 +84,8 @@ void echoReceived(byte[] data, int offset, int length) { invalidEchosReceived++; } - int rtt = (int) (System.currentTimeMillis() - Longs.fromByteArray(Arrays.copyOfRange(data, offset + 1, length))); + int rtt = + (int) (System.currentTimeMillis() - Longs.fromByteArray(Arrays.copyOfRange(data, offset + 1, length))); if (averageRTT == 0) { averageRTT = rtt; } else { @@ -87,7 +95,8 @@ void echoReceived(byte[] data, int offset, int length) { lastPacketReceived = System.currentTimeMillis(); debug().peerConnectivityUpdate(ice.getPeer()); -// System.out.printf("Received echo from %d after %d ms, averageRTT: %d ms", ice.getPeer().getRemoteId(), rtt, (int) averageRTT); + // System.out.printf("Received echo from %d after %d ms, averageRTT: %d ms", ice.getPeer().getRemoteId(), + // rtt, (int) averageRTT); } private void checkerThread() { @@ -97,7 +106,7 @@ private void checkerThread() { byte[] data = new byte[9]; data[0] = 'e'; - //Copy current time (long, 8 bytes) into array after leading prefix indicating echo + // Copy current time (long, 8 bytes) into array after leading prefix indicating echo System.arraycopy(Longs.toByteArray(System.currentTimeMillis()), 0, data, 1, 8); ice.sendViaIce(data, 0, data.length); @@ -107,13 +116,17 @@ private void checkerThread() { try { Thread.sleep(ECHO_INTERVAL); } catch (InterruptedException e) { - log.warn("{} (sleeping checkerThread) was interrupted", Thread.currentThread().getName()); + log.warn( + "{} (sleeping checkerThread) was interrupted", + Thread.currentThread().getName()); Thread.currentThread().interrupt(); return; } if (System.currentTimeMillis() - lastPacketReceived > 10000) { - log.warn("Didn't receive any answer to echo requests for the past 10 seconds from {}, aborting connection", ice.getPeer().getRemoteLogin()); + log.warn( + "Didn't receive any answer to echo requests for the past 10 seconds from {}, aborting connection", + ice.getPeer().getRemoteLogin()); new Thread(ice::onConnectionLost).start(); return; } diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/ice/PeerIceModule.java b/ice-adapter/src/main/java/com/faforever/iceadapter/ice/PeerIceModule.java index aacd281..058ab08 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/ice/PeerIceModule.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/ice/PeerIceModule.java @@ -1,39 +1,37 @@ package com.faforever.iceadapter.ice; +import static com.faforever.iceadapter.debug.Debug.debug; +import static com.faforever.iceadapter.ice.IceState.*; + import com.faforever.iceadapter.IceAdapter; import com.faforever.iceadapter.rpc.RPCService; import com.faforever.iceadapter.util.CandidateUtil; import com.faforever.iceadapter.util.Executor; import com.faforever.iceadapter.util.TrayIcon; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import org.ice4j.Transport; -import org.ice4j.TransportAddress; -import org.ice4j.ice.*; -import org.ice4j.ice.harvest.StunCandidateHarvester; -import org.ice4j.ice.harvest.TurnCandidateHarvester; -import org.ice4j.security.LongTermCredential; - import java.io.IOException; import java.net.DatagramPacket; import java.util.ArrayList; -import java.util.Comparator; import java.util.List; -import java.util.Optional; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; - -import static com.faforever.iceadapter.debug.Debug.debug; -import static com.faforever.iceadapter.ice.IceState.*; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.ice4j.TransportAddress; +import org.ice4j.ice.*; +import org.ice4j.ice.harvest.StunCandidateHarvester; +import org.ice4j.ice.harvest.TurnCandidateHarvester; +import org.ice4j.security.LongTermCredential; @Getter @Slf4j public class PeerIceModule { - private static final int MINIMUM_PORT = 6112; // PORT (range +1000) to be used by ICE for communicating, each peer needs a seperate port - private static final long FORCE_SRFLX_RELAY_INTERVAL = 2 * 60 * 1000; // 2 mins, the interval in which multiple connects have to happen to force srflx/relay + private static final int MINIMUM_PORT = + 6112; // PORT (range +1000) to be used by ICE for communicating, each peer needs a seperate port + private static final long FORCE_SRFLX_RELAY_INTERVAL = + 2 * 60 * 1000; // 2 mins, the interval in which multiple connects have to happen to force srflx/relay private static final int FORCE_SRFLX_COUNT = 1; private static final int FORCE_RELAY_COUNT = 2; @@ -49,12 +47,12 @@ public class PeerIceModule { private PeerTurnRefreshModule turnRefreshModule; - //Checks the connection by sending echo requests and initiates a reconnect if needed + // Checks the connection by sending echo requests and initiates a reconnect if needed private final PeerConnectivityCheckerModule connectivityChecker = new PeerConnectivityCheckerModule(this); - //A list of the timestamps of initiated connectivity attempts, used to detect if relay/srflx should be forced + // A list of the timestamps of initiated connectivity attempts, used to detect if relay/srflx should be forced private final List connectivityAttemptTimes = new ArrayList<>(); - //How often have we been waiting for a response to local candidates/offer + // How often have we been waiting for a response to local candidates/offer private final AtomicInteger awaitingCandidatesEventId = new AtomicInteger(0); public PeerIceModule(Peer peer) { @@ -76,7 +74,9 @@ private void setState(IceState newState) { */ synchronized void initiateIce() { if (iceState != NEW && iceState != DISCONNECTED) { - log.warn(getLogPrefix() + "ICE already in progress, aborting re initiation. current state: {}", iceState.getMessage()); + log.warn( + getLogPrefix() + "ICE already in progress, aborting re initiation. current state: {}", + iceState.getMessage()); return; } @@ -91,7 +91,7 @@ synchronized void initiateIce() { * Creates an agent and media stream for handling the ICE */ private void createAgent() { - if(agent != null) { + if (agent != null) { agent.free(); } @@ -109,55 +109,74 @@ private void gatherCandidates() { List iceServers = getViableIceServers(); - iceServers.stream().flatMap(s -> s.getStunAddresses().stream()).map(StunCandidateHarvester::new).forEach(agent::addCandidateHarvester); - iceServers.forEach(iceServer -> - iceServer.getTurnAddresses().stream().map(a -> new TurnCandidateHarvester(a, new LongTermCredential(iceServer.getTurnUsername(), iceServer.getTurnCredential()))) - .forEach(agent::addCandidateHarvester) - ); + iceServers.stream() + .flatMap(s -> s.getStunAddresses().stream()) + .map(StunCandidateHarvester::new) + .forEach(agent::addCandidateHarvester); + iceServers.forEach(iceServer -> iceServer.getTurnAddresses().stream() + .map(a -> new TurnCandidateHarvester( + a, new LongTermCredential(iceServer.getTurnUsername(), iceServer.getTurnCredential()))) + .forEach(agent::addCandidateHarvester)); CompletableFuture gatheringFuture = CompletableFuture.runAsync(() -> { try { - component = agent.createComponent(mediaStream,MINIMUM_PORT + (int) (Math.random() * 999.0), MINIMUM_PORT, MINIMUM_PORT + 1000); + component = agent.createComponent( + mediaStream, MINIMUM_PORT + (int) (Math.random() * 999.0), MINIMUM_PORT, MINIMUM_PORT + 1000); } catch (IOException e) { throw new RuntimeException(e); } }); Executor.executeDelayed(5000, () -> { - if(! gatheringFuture.isDone()) { + if (!gatheringFuture.isDone()) { gatheringFuture.cancel(true); } }); try { gatheringFuture.join(); - } catch(CompletionException e) { - //Completed exceptionally + } catch (CompletionException e) { + // Completed exceptionally log.error(getLogPrefix() + "Error while creating stream component/gathering candidates", e); new Thread(this::onConnectionLost).start(); return; - } catch(CancellationException e) { - //was cancelled due to timeout + } catch (CancellationException e) { + // was cancelled due to timeout log.error(getLogPrefix() + "Gathering candidates timed out", e); new Thread(this::onConnectionLost).start(); return; } - int previousConnectivityAttempts = getConnectivityAttempsInThePast(FORCE_SRFLX_RELAY_INTERVAL); - CandidatesMessage localCandidatesMessage = CandidateUtil.packCandidates(IceAdapter.id, peer.getRemoteId(), agent, component, previousConnectivityAttempts < FORCE_SRFLX_COUNT && IceAdapter.ALLOW_HOST, previousConnectivityAttempts < FORCE_RELAY_COUNT && IceAdapter.ALLOW_REFLEXIVE, IceAdapter.ALLOW_RELAY); - log.debug(getLogPrefix() + "Sending own candidates to {}, offered candidates: {}", peer.getRemoteId(), localCandidatesMessage.candidates().stream().map(it -> it.type().toString() + "(" + it.protocol() + ")").collect(Collectors.joining(", "))); + CandidatesMessage localCandidatesMessage = CandidateUtil.packCandidates( + IceAdapter.id, + peer.getRemoteId(), + agent, + component, + previousConnectivityAttempts < FORCE_SRFLX_COUNT && IceAdapter.ALLOW_HOST, + previousConnectivityAttempts < FORCE_RELAY_COUNT && IceAdapter.ALLOW_REFLEXIVE, + IceAdapter.ALLOW_RELAY); + log.debug( + getLogPrefix() + "Sending own candidates to {}, offered candidates: {}", + peer.getRemoteId(), + localCandidatesMessage.candidates().stream() + .map(it -> it.type().toString() + "(" + it.protocol() + ")") + .collect(Collectors.joining(", "))); setState(AWAITING_CANDIDATES); RPCService.onIceMsg(localCandidatesMessage); - //Make sure to abort the connection process and reinitiate when we haven't received an answer to our offer in 6 seconds, candidate packet was probably lost + // Make sure to abort the connection process and reinitiate when we haven't received an answer to our offer in 6 + // seconds, candidate packet was probably lost final int currentAwaitingCandidatesEventId = awaitingCandidatesEventId.incrementAndGet(); Executor.executeDelayed(6000, () -> { - if(peer.isClosing()) { - log.warn(getLogPrefix() + "Peer {} not connected anymore, aborting reinitiation of ICE", peer.getRemoteId()); + if (peer.isClosing()) { + log.warn( + getLogPrefix() + "Peer {} not connected anymore, aborting reinitiation of ICE", + peer.getRemoteId()); return; } - if (iceState == AWAITING_CANDIDATES && currentAwaitingCandidatesEventId == awaitingCandidatesEventId.get()) { + if (iceState == AWAITING_CANDIDATES + && currentAwaitingCandidatesEventId == awaitingCandidatesEventId.get()) { onConnectionLost(); } }); @@ -170,15 +189,30 @@ private List getViableIceServers() { } // Try servers with acceptable latency - List viableIceServers = allIceServers.stream() - .filter(IceServer::hasAcceptableLatency) - .collect(Collectors.toList()); + List viableIceServers = + allIceServers.stream().filter(IceServer::hasAcceptableLatency).collect(Collectors.toList()); if (!viableIceServers.isEmpty()) { - log.info("Using all viable ice servers: {}", viableIceServers.stream().map(it -> "[" + it.getTurnAddresses().stream().map(TransportAddress::toString).collect(Collectors.joining(", ")) + "]").collect(Collectors.joining(", "))); + log.info( + "Using all viable ice servers: {}", + viableIceServers.stream() + .map(it -> "[" + + it.getTurnAddresses().stream() + .map(TransportAddress::toString) + .collect(Collectors.joining(", ")) + + "]") + .collect(Collectors.joining(", "))); return viableIceServers; } - log.info("Using all ice servers: {}", allIceServers.stream().map(it -> "[" + it.getTurnAddresses().stream().map(TransportAddress::toString).collect(Collectors.joining(", ")) + "]").collect(Collectors.joining(", "))); + log.info( + "Using all ice servers: {}", + allIceServers.stream() + .map(it -> "[" + + it.getTurnAddresses().stream() + .map(TransportAddress::toString) + .collect(Collectors.joining(", ")) + + "]") + .collect(Collectors.joining(", "))); return allIceServers; } @@ -187,40 +221,53 @@ private List getViableIceServers() { * @param remoteCandidatesMessage */ public synchronized void onIceMessageReceived(CandidatesMessage remoteCandidatesMessage) { - if(peer.isClosing()) { + if (peer.isClosing()) { log.warn(getLogPrefix() + "Peer not connected anymore, discarding ice message"); return; } - //Start ICE async as it's blocking and this is the RPC thread + // Start ICE async as it's blocking and this is the RPC thread new Thread(() -> { - log.debug(getLogPrefix() + "Got IceMsg for peer, offered candidates: {}", remoteCandidatesMessage.candidates().stream().map(it -> it.type().toString() + "(" + it.protocol() + ")").collect(Collectors.joining(", "))); - - if (peer.isLocalOffer()) { - if (iceState != AWAITING_CANDIDATES) { - log.warn(getLogPrefix() + "Received candidates unexpectedly, current state: {}", iceState.getMessage()); - return; - } - - } else { - //Check if we are already processing an ICE offer and if so stop it - if (iceState != NEW && iceState != DISCONNECTED) { - log.info(getLogPrefix() + "Received new candidates/offer, stopping..."); - onConnectionLost(); - } + log.debug( + getLogPrefix() + "Got IceMsg for peer, offered candidates: {}", + remoteCandidatesMessage.candidates().stream() + .map(it -> it.type().toString() + "(" + it.protocol() + ")") + .collect(Collectors.joining(", "))); - //Answer mode, initialize agent and gather candidates - initiateIce(); - } - - setState(CHECKING); - - int previousConnectivityAttempts = getConnectivityAttempsInThePast(FORCE_SRFLX_RELAY_INTERVAL); - CandidateUtil.unpackCandidates(remoteCandidatesMessage, agent, component, mediaStream, previousConnectivityAttempts < FORCE_SRFLX_COUNT && IceAdapter.ALLOW_HOST, previousConnectivityAttempts < FORCE_RELAY_COUNT && IceAdapter.ALLOW_REFLEXIVE, IceAdapter.ALLOW_RELAY); + if (peer.isLocalOffer()) { + if (iceState != AWAITING_CANDIDATES) { + log.warn( + getLogPrefix() + "Received candidates unexpectedly, current state: {}", + iceState.getMessage()); + return; + } - startIce(); + } else { + // Check if we are already processing an ICE offer and if so stop it + if (iceState != NEW && iceState != DISCONNECTED) { + log.info(getLogPrefix() + "Received new candidates/offer, stopping..."); + onConnectionLost(); + } + + // Answer mode, initialize agent and gather candidates + initiateIce(); + } - }).start(); + setState(CHECKING); + + int previousConnectivityAttempts = getConnectivityAttempsInThePast(FORCE_SRFLX_RELAY_INTERVAL); + CandidateUtil.unpackCandidates( + remoteCandidatesMessage, + agent, + component, + mediaStream, + previousConnectivityAttempts < FORCE_SRFLX_COUNT && IceAdapter.ALLOW_HOST, + previousConnectivityAttempts < FORCE_RELAY_COUNT && IceAdapter.ALLOW_REFLEXIVE, + IceAdapter.ALLOW_RELAY); + + startIce(); + }) + .start(); } /** @@ -232,37 +279,40 @@ private void startIce() { log.debug(getLogPrefix() + "Starting ICE for peer {}", peer.getRemoteId()); agent.startConnectivityEstablishment(); - //Wait for termination/completion of the agent + // Wait for termination/completion of the agent long iceStartTime = System.currentTimeMillis(); - while (agent.getState() != IceProcessingState.COMPLETED) {//TODO include more?, maybe stop on COMPLETED, is that to early? + while (agent.getState() + != IceProcessingState.COMPLETED) { // TODO include more?, maybe stop on COMPLETED, is that to early? try { Thread.sleep(20); } catch (InterruptedException e) { log.error(getLogPrefix() + "Interrupted while waiting for ICE", e); } - if (agent.getState() == IceProcessingState.FAILED) {//TODO null pointer due to no agent? + if (agent.getState() == IceProcessingState.FAILED) { // TODO null pointer due to no agent? onConnectionLost(); return; } - - if(System.currentTimeMillis() - iceStartTime > 15_000) { + if (System.currentTimeMillis() - iceStartTime > 15_000) { log.error(getLogPrefix() + "ABORTING ICE DUE TO TIMEOUT"); onConnectionLost(); return; } } - log.debug(getLogPrefix() + "ICE terminated, connected, selected candidate pair: " + component.getSelectedPair().getLocalCandidate().getType().toString() + " <-> " + component.getSelectedPair().getRemoteCandidate().getType().toString()); + log.debug(getLogPrefix() + "ICE terminated, connected, selected candidate pair: " + + component.getSelectedPair().getLocalCandidate().getType().toString() + " <-> " + + component.getSelectedPair().getRemoteCandidate().getType().toString()); - //We are connected + // We are connected connected = true; RPCService.onConnected(IceAdapter.id, peer.getRemoteId(), true); setState(CONNECTED); if (component.getSelectedPair().getLocalCandidate().getType() == CandidateType.RELAYED_CANDIDATE) { - turnRefreshModule = new PeerTurnRefreshModule(this, (RelayedCandidate) component.getSelectedPair().getLocalCandidate()); + turnRefreshModule = new PeerTurnRefreshModule( + this, (RelayedCandidate) component.getSelectedPair().getLocalCandidate()); } if (peer.isLocalOffer()) { @@ -281,7 +331,7 @@ private void startIce() { public synchronized void onConnectionLost() { if (iceState == DISCONNECTED) { log.warn(getLogPrefix() + "Lost connection, albeit already in ice state disconnected"); - return;//TODO: will this kill the life cycle? + return; // TODO: will this kill the life cycle? } IceState previousState = getIceState(); @@ -291,7 +341,7 @@ public synchronized void onConnectionLost() { listenerThread = null; } - if(turnRefreshModule != null) { + if (turnRefreshModule != null) { turnRefreshModule.close(); turnRefreshModule = null; } @@ -315,12 +365,12 @@ public synchronized void onConnectionLost() { debug().peerStateChanged(this.peer); - if(peer.isClosing()) { + if (peer.isClosing()) { log.warn(getLogPrefix() + "Peer not connected anymore, aborting onConnectionLost of ICE"); return; } - if(peer.getGameSession().isGameEnded()) { + if (peer.getGameSession().isGameEnded()) { log.warn(getLogPrefix() + "GAME ENDED, ABORTING onConnectionLost of ICE for peer "); return; } @@ -330,16 +380,16 @@ public synchronized void onConnectionLost() { } if (previousState == CONNECTED && peer.isLocalOffer()) { - //We were connected before, retry immediately + // We were connected before, retry immediately Executor.executeDelayed(0, this::reinitIce); } else if (peer.isLocalOffer()) { - //Last ice attempt didn't succeed, so wait a bit + // Last ice attempt didn't succeed, so wait a bit Executor.executeDelayed(5000, this::reinitIce); } } private synchronized void reinitIce() { - if(peer.isClosing()) { + if (peer.isClosing()) { log.warn(getLogPrefix() + "Peer not connected anymore, aborting reinitiation of ICE"); return; } @@ -358,7 +408,6 @@ void onFaDataReceived(byte[] faData, int length) { sendViaIce(data, 0, data.length); } - /** * Send date via ice to the other peer * @param data @@ -368,7 +417,23 @@ void onFaDataReceived(byte[] faData, int length) { void sendViaIce(byte[] data, int offset, int length) { if (connected && component != null) { try { - component.getSelectedPair().getIceSocketWrapper().send(new DatagramPacket(data, offset, length, component.getSelectedPair().getRemoteCandidate().getTransportAddress().getAddress(), component.getSelectedPair().getRemoteCandidate().getTransportAddress().getPort())); + component + .getSelectedPair() + .getIceSocketWrapper() + .send(new DatagramPacket( + data, + offset, + length, + component + .getSelectedPair() + .getRemoteCandidate() + .getTransportAddress() + .getAddress(), + component + .getSelectedPair() + .getRemoteCandidate() + .getTransportAddress() + .getPort())); } catch (IOException e) { log.warn(getLogPrefix() + "Failed to send data via ICE", e); onConnectionLost(); @@ -385,33 +450,41 @@ public void listener() { log.debug(getLogPrefix() + "Now forwarding data from ICE to FA for peer"); Component localComponent = component; - byte[] data = new byte[65536];//64KiB = UDP MTU, in practice due to ethernet frames being <= 1500 B, this is often not used + byte[] data = new byte + [65536]; // 64KiB = UDP MTU, in practice due to ethernet frames being <= 1500 B, this is often not used while (IceAdapter.running && IceAdapter.gameSession == peer.getGameSession()) { try { DatagramPacket packet = new DatagramPacket(data, data.length); - localComponent.getSelectedPair().getIceSocketWrapper().getUDPSocket().receive(packet); + localComponent + .getSelectedPair() + .getIceSocketWrapper() + .getUDPSocket() + .receive(packet); if (packet.getLength() == 0) { continue; } if (data[0] == 'd') { - //Received data + // Received data peer.onIceDataReceived(data, 1, packet.getLength() - 1); } else if (data[0] == 'e') { - //Received echo req/res + // Received echo req/res if (peer.isLocalOffer()) { connectivityChecker.echoReceived(data, 0, packet.getLength()); } else { - sendViaIce(data, 0, packet.getLength());//Turn around, send echo back + sendViaIce(data, 0, packet.getLength()); // Turn around, send echo back } } else { - log.warn(getLogPrefix() + "Received invalid packet, first byte: 0x{}, length: {}", data[0], packet.getLength()); + log.warn( + getLogPrefix() + "Received invalid packet, first byte: 0x{}, length: {}", + data[0], + packet.getLength()); } - } catch (IOException e) {//TODO: nullpointer from localComponent.xxxx???? + } catch (IOException e) { // TODO: nullpointer from localComponent.xxxx???? log.warn(getLogPrefix() + "Error while reading from ICE adapter", e); - if(component == localComponent) { + if (component == localComponent) { onConnectionLost(); } return; @@ -422,20 +495,21 @@ public void listener() { } void close() { - if(turnRefreshModule != null) { + if (turnRefreshModule != null) { turnRefreshModule.close(); } - if(agent != null) { + if (agent != null) { agent.free(); } connectivityChecker.stop(); } public int getConnectivityAttempsInThePast(final long millis) { - //copy list to avoid concurrency issues - return (int) new ArrayList(connectivityAttemptTimes).stream() - .filter(time -> time > (System.currentTimeMillis() - millis)) - .count(); + // copy list to avoid concurrency issues + return (int) new ArrayList(connectivityAttemptTimes) + .stream() + .filter(time -> time > (System.currentTimeMillis() - millis)) + .count(); } public String getLogPrefix() { diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/ice/PeerTurnRefreshModule.java b/ice-adapter/src/main/java/com/faforever/iceadapter/ice/PeerTurnRefreshModule.java index c508302..0e8c1b3 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/ice/PeerTurnRefreshModule.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/ice/PeerTurnRefreshModule.java @@ -1,5 +1,9 @@ package com.faforever.iceadapter.ice; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.time.Duration; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.ice4j.ice.RelayedCandidate; @@ -9,81 +13,83 @@ import org.ice4j.message.Request; import org.ice4j.stack.TransactionID; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.time.Duration; - /** * Sends continuous refresh requests to the turn server */ @Slf4j public class PeerTurnRefreshModule { - private static final int REFRESH_INTERVAL = (int) Duration.ofMinutes(2).toMillis(); - - private static Field harvestField; - private static Method sendRequestMethod; - static { - try { - harvestField = RelayedCandidate.class.getDeclaredField("turnCandidateHarvest"); - harvestField.setAccessible(true); - sendRequestMethod = StunCandidateHarvest.class.getDeclaredMethod("sendRequest", Request.class, boolean.class, TransactionID.class); - sendRequestMethod.setAccessible(true); - } catch(NoSuchFieldException | NoSuchMethodException e) { - log.error("Could not initialize harvestField for turn refreshing.", e); - } - } - - @Getter private final PeerIceModule ice; - @Getter private final RelayedCandidate candidate; - - private TurnCandidateHarvest harvest = null; - - private Thread refreshThread; - private volatile boolean running = true; - - public PeerTurnRefreshModule(PeerIceModule ice, RelayedCandidate candidate) { - this.ice = ice; - this.candidate = candidate; - - try { - harvest = (TurnCandidateHarvest) harvestField.get(candidate); - } catch (IllegalAccessException e) { - log.error("Could not get harvest from candidate.", e); - } - - if(harvest != null) { - refreshThread = new Thread(this::refreshThread); - refreshThread.start(); - - log.info("Started turn refresh module for peer {}", ice.getPeer().getRemoteLogin()); - } - } - - private void refreshThread() { - while(running) { - - Request refreshRequest = MessageFactory.createRefreshRequest(600); //Maximum lifetime of turn is 600 seconds (10 minutes), server may limit this even further - - try { - TransactionID transactionID = (TransactionID) sendRequestMethod.invoke(harvest, refreshRequest, false, null); - - log.info("Sent turn refresh request."); - } catch (IllegalAccessException | InvocationTargetException e) { - log.error("Could not send turn refresh request!.", e); - } - - try { - Thread.sleep(REFRESH_INTERVAL); - } catch(InterruptedException e) { - log.warn("Sleeping refreshThread was interrupted"); - } - } - } - - public void close() { - running = false; - refreshThread.interrupt(); - } + private static final int REFRESH_INTERVAL = (int) Duration.ofMinutes(2).toMillis(); + + private static Field harvestField; + private static Method sendRequestMethod; + + static { + try { + harvestField = RelayedCandidate.class.getDeclaredField("turnCandidateHarvest"); + harvestField.setAccessible(true); + sendRequestMethod = StunCandidateHarvest.class.getDeclaredMethod( + "sendRequest", Request.class, boolean.class, TransactionID.class); + sendRequestMethod.setAccessible(true); + } catch (NoSuchFieldException | NoSuchMethodException e) { + log.error("Could not initialize harvestField for turn refreshing.", e); + } + } + + @Getter + private final PeerIceModule ice; + + @Getter + private final RelayedCandidate candidate; + + private TurnCandidateHarvest harvest = null; + + private Thread refreshThread; + private volatile boolean running = true; + + public PeerTurnRefreshModule(PeerIceModule ice, RelayedCandidate candidate) { + this.ice = ice; + this.candidate = candidate; + + try { + harvest = (TurnCandidateHarvest) harvestField.get(candidate); + } catch (IllegalAccessException e) { + log.error("Could not get harvest from candidate.", e); + } + + if (harvest != null) { + refreshThread = new Thread(this::refreshThread); + refreshThread.start(); + + log.info("Started turn refresh module for peer {}", ice.getPeer().getRemoteLogin()); + } + } + + private void refreshThread() { + while (running) { + + Request refreshRequest = MessageFactory.createRefreshRequest( + 600); // Maximum lifetime of turn is 600 seconds (10 minutes), server may limit this even further + + try { + TransactionID transactionID = + (TransactionID) sendRequestMethod.invoke(harvest, refreshRequest, false, null); + + log.info("Sent turn refresh request."); + } catch (IllegalAccessException | InvocationTargetException e) { + log.error("Could not send turn refresh request!.", e); + } + + try { + Thread.sleep(REFRESH_INTERVAL); + } catch (InterruptedException e) { + log.warn("Sleeping refreshThread was interrupted"); + } + } + } + + public void close() { + running = false; + refreshThread.interrupt(); + } } diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/rpc/RPCHandler.java b/ice-adapter/src/main/java/com/faforever/iceadapter/rpc/RPCHandler.java index 06cc216..ba10f4d 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/rpc/RPCHandler.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/rpc/RPCHandler.java @@ -9,6 +9,11 @@ import com.faforever.iceadapter.ice.Peer; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.ice4j.TransportAddress; @@ -17,12 +22,6 @@ import org.ice4j.ice.CandidateType; import org.ice4j.ice.Component; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; - /** * Handles calls from JsonRPC (the client) */ @@ -60,9 +59,9 @@ public void iceMsg(long remotePlayerId, Object msg) { boolean err = true; GameSession gameSession = IceAdapter.gameSession; - if (gameSession != null) {//This is highly unlikely, game session got created if JoinGame/HostGame came first + if (gameSession != null) { // This is highly unlikely, game session got created if JoinGame/HostGame came first Peer peer = gameSession.getPeers().get((int) remotePlayerId); - if (peer != null) {//This is highly unlikely, peer is present if connectToPeer was called first + if (peer != null) { // This is highly unlikely, peer is present if connectToPeer was called first try { peer.getIce().onIceMessageReceived(objectMapper.readValue((String) msg, CandidatesMessage.class)); err = false; @@ -77,7 +76,7 @@ public void iceMsg(long remotePlayerId, Object msg) { log.error("ICE MESSAGE IGNORED for id: {}", remotePlayerId); } - log.info("IceMsg received {}", msg); + log.info("IceMsg received {}", msg); } public void sendToGpgNet(String header, String... chunks) { @@ -95,7 +94,8 @@ public void setIceServers(List> iceServers) { @Deprecated(forRemoval = true) @SneakyThrows public String status() { - IceStatus.IceGPGNetState gpgpnet = new IceStatus.IceGPGNetState(IceAdapter.GPGNET_PORT, GPGNetServer.isConnected(), GPGNetServer.getGameStateString(), "-"); + IceStatus.IceGPGNetState gpgpnet = new IceStatus.IceGPGNetState( + IceAdapter.GPGNET_PORT, GPGNetServer.isConnected(), GPGNetServer.getGameStateString(), "-"); List relays = new ArrayList<>(); GameSession gameSession = IceAdapter.gameSession; @@ -103,20 +103,44 @@ public String status() { synchronized (gameSession.getPeers()) { gameSession.getPeers().values().stream() .map(peer -> { - IceStatus.IceRelay.IceRelayICEState iceRelayICEState = new IceStatus.IceRelay.IceRelayICEState( - peer.isLocalOffer(), - peer.getIce().getIceState().getMessage(), - "", - "", - peer.getIce().isConnected(), - Optional.ofNullable(peer.getIce().getComponent()).map(Component::getSelectedPair).map(CandidatePair::getLocalCandidate).map(Candidate::getHostAddress).map(TransportAddress::toString).orElse(""), - Optional.ofNullable(peer.getIce().getComponent()).map(Component::getSelectedPair).map(CandidatePair::getRemoteCandidate).map(Candidate::getHostAddress).map(TransportAddress::toString).orElse(""), - Optional.ofNullable(peer.getIce().getComponent()).map(Component::getSelectedPair).map(CandidatePair::getLocalCandidate).map(Candidate::getType).map(CandidateType::toString).orElse(""), - Optional.ofNullable(peer.getIce().getComponent()).map(Component::getSelectedPair).map(CandidatePair::getRemoteCandidate).map(Candidate::getType).map(CandidateType::toString).orElse(""), - -1.0 - ); - - return new IceStatus.IceRelay(peer.getRemoteId(), peer.getRemoteLogin(), peer.getFaSocket().getLocalPort(), iceRelayICEState); + IceStatus.IceRelay.IceRelayICEState iceRelayICEState = + new IceStatus.IceRelay.IceRelayICEState( + peer.isLocalOffer(), + peer.getIce().getIceState().getMessage(), + "", + "", + peer.getIce().isConnected(), + Optional.ofNullable(peer.getIce().getComponent()) + .map(Component::getSelectedPair) + .map(CandidatePair::getLocalCandidate) + .map(Candidate::getHostAddress) + .map(TransportAddress::toString) + .orElse(""), + Optional.ofNullable(peer.getIce().getComponent()) + .map(Component::getSelectedPair) + .map(CandidatePair::getRemoteCandidate) + .map(Candidate::getHostAddress) + .map(TransportAddress::toString) + .orElse(""), + Optional.ofNullable(peer.getIce().getComponent()) + .map(Component::getSelectedPair) + .map(CandidatePair::getLocalCandidate) + .map(Candidate::getType) + .map(CandidateType::toString) + .orElse(""), + Optional.ofNullable(peer.getIce().getComponent()) + .map(Component::getSelectedPair) + .map(CandidatePair::getRemoteCandidate) + .map(Candidate::getType) + .map(CandidateType::toString) + .orElse(""), + -1.0); + + return new IceStatus.IceRelay( + peer.getRemoteId(), + peer.getRemoteLogin(), + peer.getFaSocket().getLocalPort(), + iceRelayICEState); }) .forEach(relays::add); } @@ -124,13 +148,15 @@ public String status() { IceStatus status = new IceStatus( IceAdapter.VERSION, - GameSession.getIceServers().stream().mapToInt(s -> s.getTurnAddresses().size() + s.getStunAddresses().size()).sum(), + GameSession.getIceServers().stream() + .mapToInt(s -> s.getTurnAddresses().size() + + s.getStunAddresses().size()) + .sum(), IceAdapter.LOBBY_PORT, GPGNetServer.lobbyInitMode.getName(), new IceStatus.IceOptions(IceAdapter.id, IceAdapter.login, IceAdapter.RPC_PORT, IceAdapter.GPGNET_PORT), gpgpnet, - relays.toArray(new IceStatus.IceRelay[relays.size()]) - ); + relays.toArray(new IceStatus.IceRelay[relays.size()])); return objectMapper.writeValueAsString(status); } @@ -139,5 +165,4 @@ public void quit() { log.warn("Close requested, stopping..."); IceAdapter.close(); } - } diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/rpc/RPCService.java b/ice-adapter/src/main/java/com/faforever/iceadapter/rpc/RPCService.java index 05c3a52..f481363 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/rpc/RPCService.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/rpc/RPCService.java @@ -1,5 +1,7 @@ package com.faforever.iceadapter.rpc; +import static com.faforever.iceadapter.debug.Debug.debug; + import com.faforever.iceadapter.IceAdapter; import com.faforever.iceadapter.debug.Debug; import com.faforever.iceadapter.debug.InfoWindow; @@ -11,13 +13,10 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.nbarraille.jjsonrpc.JJsonPeer; import com.nbarraille.jjsonrpc.TcpServer; -import lombok.extern.slf4j.Slf4j; - import java.util.Arrays; import java.util.List; import java.util.concurrent.CompletableFuture; - -import static com.faforever.iceadapter.debug.Debug.debug; +import lombok.extern.slf4j.Slf4j; /** * Handles communication between client and adapter, opens a server for the client to connect to @@ -25,98 +24,107 @@ @Slf4j public class RPCService { - private final static ObjectMapper objectMapper = new ObjectMapper(); - - private static TcpServer tcpServer; - private static RPCHandler rpcHandler; - - private static volatile boolean skipRPCMessages = false; - - static { - objectMapper.registerModule(new JavaTimeModule()); - } - - public static void init() { - log.info("Creating RPC server on port {}", IceAdapter.RPC_PORT); - - rpcHandler = new RPCHandler(); - tcpServer = new TcpServer(IceAdapter.RPC_PORT, rpcHandler); - tcpServer.start(); - - debug().rpcStarted(tcpServer.getFirstPeer()); - tcpServer.getFirstPeer().thenAccept(firstPeer -> { - firstPeer.onConnectionLost(() -> { - GameState gameState = GPGNetServer.getGameState().orElse(null); - if (gameState == GameState.LAUNCHING) { - skipRPCMessages = true; - log.warn("Lost connection to first RPC Peer. GameState: LAUNCHING, NOT STOPPING!"); - if (InfoWindow.INSTANCE == null) { - Debug.ENABLE_INFO_WINDOW = true; - Debug.init(); - } - InfoWindow.INSTANCE.show(); - } else { - log.info("Lost connection to first RPC Peer. GameState: {}, Stopping adapter...", gameState.getName()); - IceAdapter.close(); - } - }); - }); - } - - public static void onConnectionStateChanged(String newState) { - if (!skipRPCMessages) { - getPeerOrWait().sendNotification("onConnectionStateChanged", Arrays.asList(newState)); - } - } - - public static void onGpgNetMessageReceived(String header, List chunks) { - if (!skipRPCMessages) { - getPeerOrWait().sendNotification("onGpgNetMessageReceived", Arrays.asList(header, chunks)); - } - } - - public static void onIceMsg(CandidatesMessage candidatesMessage) { - if (!skipRPCMessages) { - try { - getPeerOrWait().sendNotification("onIceMsg", Arrays.asList(candidatesMessage.srcId(), candidatesMessage.destId(), objectMapper.writeValueAsString(candidatesMessage))); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - } - } - - public static void onIceConnectionStateChanged(long localPlayerId, long remotePlayerId, String state) { - if (!skipRPCMessages) { - getPeerOrWait().sendNotification("onIceConnectionStateChanged", Arrays.asList(localPlayerId, remotePlayerId, state)); - } - } - - public static void onConnected(long localPlayerId, long remotePlayerId, boolean connected) { - if (!skipRPCMessages) { - getPeerOrWait().sendNotification("onConnected", Arrays.asList(localPlayerId, remotePlayerId, connected)); - } - } - - - /** - * Blocks until a peer is connected (the client) - * - * @return the currently connected peer (the client) - */ - public static JJsonPeer getPeerOrWait() { - try { - return tcpServer.getFirstPeer().get(); - } catch (Exception e) { - log.error("Error on fetching first peer", e); - } - return null; - } - - public static CompletableFuture getPeerFuture() { - return tcpServer.getFirstPeer(); - } - - public static void close() { - tcpServer.stop(); - } + private static final ObjectMapper objectMapper = new ObjectMapper(); + + private static TcpServer tcpServer; + private static RPCHandler rpcHandler; + + private static volatile boolean skipRPCMessages = false; + + static { + objectMapper.registerModule(new JavaTimeModule()); + } + + public static void init() { + log.info("Creating RPC server on port {}", IceAdapter.RPC_PORT); + + rpcHandler = new RPCHandler(); + tcpServer = new TcpServer(IceAdapter.RPC_PORT, rpcHandler); + tcpServer.start(); + + debug().rpcStarted(tcpServer.getFirstPeer()); + tcpServer.getFirstPeer().thenAccept(firstPeer -> { + firstPeer.onConnectionLost(() -> { + GameState gameState = GPGNetServer.getGameState().orElse(null); + if (gameState == GameState.LAUNCHING) { + skipRPCMessages = true; + log.warn("Lost connection to first RPC Peer. GameState: LAUNCHING, NOT STOPPING!"); + if (InfoWindow.INSTANCE == null) { + Debug.ENABLE_INFO_WINDOW = true; + Debug.init(); + } + InfoWindow.INSTANCE.show(); + } else { + log.info( + "Lost connection to first RPC Peer. GameState: {}, Stopping adapter...", + gameState.getName()); + IceAdapter.close(); + } + }); + }); + } + + public static void onConnectionStateChanged(String newState) { + if (!skipRPCMessages) { + getPeerOrWait().sendNotification("onConnectionStateChanged", Arrays.asList(newState)); + } + } + + public static void onGpgNetMessageReceived(String header, List chunks) { + if (!skipRPCMessages) { + getPeerOrWait().sendNotification("onGpgNetMessageReceived", Arrays.asList(header, chunks)); + } + } + + public static void onIceMsg(CandidatesMessage candidatesMessage) { + if (!skipRPCMessages) { + try { + getPeerOrWait() + .sendNotification( + "onIceMsg", + Arrays.asList( + candidatesMessage.srcId(), + candidatesMessage.destId(), + objectMapper.writeValueAsString(candidatesMessage))); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + } + + public static void onIceConnectionStateChanged(long localPlayerId, long remotePlayerId, String state) { + if (!skipRPCMessages) { + getPeerOrWait() + .sendNotification( + "onIceConnectionStateChanged", Arrays.asList(localPlayerId, remotePlayerId, state)); + } + } + + public static void onConnected(long localPlayerId, long remotePlayerId, boolean connected) { + if (!skipRPCMessages) { + getPeerOrWait().sendNotification("onConnected", Arrays.asList(localPlayerId, remotePlayerId, connected)); + } + } + + /** + * Blocks until a peer is connected (the client) + * + * @return the currently connected peer (the client) + */ + public static JJsonPeer getPeerOrWait() { + try { + return tcpServer.getFirstPeer().get(); + } catch (Exception e) { + log.error("Error on fetching first peer", e); + } + return null; + } + + public static CompletableFuture getPeerFuture() { + return tcpServer.getFirstPeer(); + } + + public static void close() { + tcpServer.stop(); + } } diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/ConnectToPeer.java b/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/ConnectToPeer.java index 05a9d21..c8d17d1 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/ConnectToPeer.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/ConnectToPeer.java @@ -2,6 +2,5 @@ import java.util.UUID; -public record ConnectToPeer(UUID messageId, int peerPlayerId, String peerName, - boolean localOffer) implements OutgoingMessageV1 { -} \ No newline at end of file +public record ConnectToPeer(UUID messageId, int peerPlayerId, String peerName, boolean localOffer) + implements OutgoingMessageV1 {} diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/CoturnServer.java b/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/CoturnServer.java index 5c7c792..fc37d86 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/CoturnServer.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/CoturnServer.java @@ -1,4 +1,3 @@ package com.faforever.iceadapter.telemetry; -public record CoturnServer(String region, String host, int port, Double averageRTT) { -} \ No newline at end of file +public record CoturnServer(String region, String host, int port, Double averageRTT) {} diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/DisconnectFromPeer.java b/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/DisconnectFromPeer.java index 9fd499e..8f0aa8d 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/DisconnectFromPeer.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/DisconnectFromPeer.java @@ -2,5 +2,4 @@ import java.util.UUID; -public record DisconnectFromPeer(UUID messageId, int peerPlayerId) implements OutgoingMessageV1 { -} \ No newline at end of file +public record DisconnectFromPeer(UUID messageId, int peerPlayerId) implements OutgoingMessageV1 {} diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/OutgoingMessageV1.java b/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/OutgoingMessageV1.java index 83e15cf..da882e6 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/OutgoingMessageV1.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/OutgoingMessageV1.java @@ -1,10 +1,9 @@ package com.faforever.iceadapter.telemetry; import com.fasterxml.jackson.annotation.JsonTypeInfo; - import java.util.UUID; @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "messageType") public interface OutgoingMessageV1 { UUID messageId(); -} \ No newline at end of file +} diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/RegisterAsPeer.java b/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/RegisterAsPeer.java index 1a2697d..e1eddc9 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/RegisterAsPeer.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/RegisterAsPeer.java @@ -2,6 +2,4 @@ import java.util.UUID; -public record RegisterAsPeer(UUID messageId, String adapterVersion, - String userName) implements OutgoingMessageV1 { -} \ No newline at end of file +public record RegisterAsPeer(UUID messageId, String adapterVersion, String userName) implements OutgoingMessageV1 {} diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/UpdateCoturnList.java b/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/UpdateCoturnList.java index 4bcb3a0..f5c064c 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/UpdateCoturnList.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/UpdateCoturnList.java @@ -3,6 +3,5 @@ import java.util.Collection; import java.util.UUID; -public record UpdateCoturnList(UUID messageId, String connectedHost, - Collection knownServers) implements OutgoingMessageV1 { -} \ No newline at end of file +public record UpdateCoturnList(UUID messageId, String connectedHost, Collection knownServers) + implements OutgoingMessageV1 {} diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/UpdateGameState.java b/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/UpdateGameState.java index 46f1201..2542c74 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/UpdateGameState.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/UpdateGameState.java @@ -1,8 +1,6 @@ package com.faforever.iceadapter.telemetry; import com.faforever.iceadapter.gpgnet.GameState; - import java.util.UUID; -public record UpdateGameState(UUID messageId, GameState newState) implements OutgoingMessageV1 { -} \ No newline at end of file +public record UpdateGameState(UUID messageId, GameState newState) implements OutgoingMessageV1 {} diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/UpdateGpgnetState.java b/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/UpdateGpgnetState.java index ccdead2..7b38d56 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/UpdateGpgnetState.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/UpdateGpgnetState.java @@ -2,5 +2,4 @@ import java.util.UUID; -public record UpdateGpgnetState(UUID messageId, String newState) implements OutgoingMessageV1 { -} \ No newline at end of file +public record UpdateGpgnetState(UUID messageId, String newState) implements OutgoingMessageV1 {} diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/UpdatePeerConnectivity.java b/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/UpdatePeerConnectivity.java index 0d93357..ad1d46e 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/UpdatePeerConnectivity.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/UpdatePeerConnectivity.java @@ -3,6 +3,5 @@ import java.time.Instant; import java.util.UUID; -public record UpdatePeerConnectivity(UUID messageId, int peerPlayerId, Float averageRTT, - Instant lastReceived) implements OutgoingMessageV1 { -} \ No newline at end of file +public record UpdatePeerConnectivity(UUID messageId, int peerPlayerId, Float averageRTT, Instant lastReceived) + implements OutgoingMessageV1 {} diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/UpdatePeerState.java b/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/UpdatePeerState.java index 40ae3f6..69483f4 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/UpdatePeerState.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/telemetry/UpdatePeerState.java @@ -1,11 +1,13 @@ package com.faforever.iceadapter.telemetry; import com.faforever.iceadapter.ice.IceState; -import org.ice4j.ice.CandidateType; - import java.util.UUID; +import org.ice4j.ice.CandidateType; public record UpdatePeerState( - UUID messageId, int peerPlayerId, IceState iceState, CandidateType localCandidate, - CandidateType remoteCandidate) implements OutgoingMessageV1 { -} \ No newline at end of file + UUID messageId, + int peerPlayerId, + IceState iceState, + CandidateType localCandidate, + CandidateType remoteCandidate) + implements OutgoingMessageV1 {} diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/util/CandidateUtil.java b/ice-adapter/src/main/java/com/faforever/iceadapter/util/CandidateUtil.java index b72af58..3c399e3 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/util/CandidateUtil.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/util/CandidateUtil.java @@ -2,6 +2,9 @@ import com.faforever.iceadapter.ice.CandidatePacket; import com.faforever.iceadapter.ice.CandidatesMessage; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import org.ice4j.Transport; import org.ice4j.TransportAddress; import org.ice4j.ice.Agent; @@ -11,15 +14,18 @@ import org.ice4j.ice.LocalCandidate; import org.ice4j.ice.RemoteCandidate; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - public class CandidateUtil { public static int candidateIDFactory = 0; - public static CandidatesMessage packCandidates(int srcId, int destId, Agent agent, Component component, boolean allowHost, boolean allowReflexive, boolean allowRelay) { + public static CandidatesMessage packCandidates( + int srcId, + int destId, + Agent agent, + Component component, + boolean allowHost, + boolean allowReflexive, + boolean allowRelay) { final List candidatePackets = new ArrayList<>(); for (LocalCandidate localCandidate : component.getLocalCandidates()) { @@ -41,8 +47,7 @@ public static CandidatesMessage packCandidates(int srcId, int destId, Agent agen agent.getGeneration(), String.valueOf(candidateIDFactory++), relAddr, - relPort - ); + relPort); if (isAllowedCandidate(allowHost, allowReflexive, allowRelay, localCandidate.getType())) { candidatePackets.add(candidatePacket); @@ -54,8 +59,15 @@ public static CandidatesMessage packCandidates(int srcId, int destId, Agent agen return new CandidatesMessage(srcId, destId, agent.getLocalPassword(), agent.getLocalUfrag(), candidatePackets); } - public static void unpackCandidates(CandidatesMessage remoteCandidatesMessage, Agent agent, Component component, IceMediaStream mediaStream, boolean allowHost, boolean allowReflexive, boolean allowRelay) { - //Set candidates + public static void unpackCandidates( + CandidatesMessage remoteCandidatesMessage, + Agent agent, + Component component, + IceMediaStream mediaStream, + boolean allowHost, + boolean allowReflexive, + boolean allowRelay) { + // Set candidates mediaStream.setRemotePassword(remoteCandidatesMessage.password()); mediaStream.setRemoteUfrag(remoteCandidatesMessage.ufrag()); @@ -63,38 +75,46 @@ public static void unpackCandidates(CandidatesMessage remoteCandidatesMessage, A .sorted() // just in case some ICE adapter implementation did not sort it yet .forEach(remoteCandidatePacket -> { if (remoteCandidatePacket.generation() == agent.getGeneration() - && remoteCandidatePacket.ip() != null && remoteCandidatePacket.port() > 0) { + && remoteCandidatePacket.ip() != null + && remoteCandidatePacket.port() > 0) { - TransportAddress mainAddress = new TransportAddress(remoteCandidatePacket.ip(), remoteCandidatePacket.port(), Transport.parse(remoteCandidatePacket.protocol().toLowerCase())); + TransportAddress mainAddress = new TransportAddress( + remoteCandidatePacket.ip(), + remoteCandidatePacket.port(), + Transport.parse(remoteCandidatePacket.protocol().toLowerCase())); RemoteCandidate relatedCandidate = null; if (remoteCandidatePacket.relAddr() != null && remoteCandidatePacket.relPort() > 0) { - TransportAddress relatedAddr = new TransportAddress(remoteCandidatePacket.relAddr(), remoteCandidatePacket.relPort(), Transport.parse(remoteCandidatePacket.protocol().toLowerCase())); + TransportAddress relatedAddr = new TransportAddress( + remoteCandidatePacket.relAddr(), + remoteCandidatePacket.relPort(), + Transport.parse( + remoteCandidatePacket.protocol().toLowerCase())); relatedCandidate = component.findRemoteCandidate(relatedAddr); } RemoteCandidate remoteCandidate = new RemoteCandidate( mainAddress, component, - remoteCandidatePacket.type(),//Expected to not return LOCAL or STUN (old names for host and srflx) + remoteCandidatePacket + .type(), // Expected to not return LOCAL or STUN (old names for host and srflx) remoteCandidatePacket.foundation(), remoteCandidatePacket.priority(), - relatedCandidate - ); + relatedCandidate); if (isAllowedCandidate(allowHost, allowReflexive, allowRelay, remoteCandidate.getType())) { component.addRemoteCandidate(remoteCandidate); } } - }); } - private static boolean isAllowedCandidate(boolean allowHost, boolean allowReflexive, boolean allowRelay, CandidateType candidateType) { + private static boolean isAllowedCandidate( + boolean allowHost, boolean allowReflexive, boolean allowRelay, CandidateType candidateType) { // Candidate types LOCAL and STUN can never occur as they are deprecated and not used boolean isAllowedHostCandidate = allowHost && candidateType == CandidateType.HOST_CANDIDATE; - boolean isAllowedReflexiveCandidate = allowReflexive && - (candidateType == CandidateType.SERVER_REFLEXIVE_CANDIDATE + boolean isAllowedReflexiveCandidate = allowReflexive + && (candidateType == CandidateType.SERVER_REFLEXIVE_CANDIDATE || candidateType == CandidateType.PEER_REFLEXIVE_CANDIDATE); boolean isAllowedRelayCandidate = allowRelay && candidateType == CandidateType.RELAYED_CANDIDATE; diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/util/Executor.java b/ice-adapter/src/main/java/com/faforever/iceadapter/util/Executor.java index 4fa6d17..f814d2d 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/util/Executor.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/util/Executor.java @@ -9,12 +9,12 @@ public class Executor { */ public static void executeDelayed(int timeMs, Runnable runnable) { new Thread(() -> { - try { - Thread.sleep(timeMs); - } catch (InterruptedException e) { - } - runnable.run(); - }).start(); + try { + Thread.sleep(timeMs); + } catch (InterruptedException e) { + } + runnable.run(); + }) + .start(); } - } diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/util/NetworkToolbox.java b/ice-adapter/src/main/java/com/faforever/iceadapter/util/NetworkToolbox.java index 27d693b..5f739bd 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/util/NetworkToolbox.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/util/NetworkToolbox.java @@ -1,12 +1,11 @@ package com.faforever.iceadapter.util; -import lombok.extern.slf4j.Slf4j; - import java.io.IOException; import java.net.DatagramSocket; import java.net.ServerSocket; import java.net.SocketException; import java.util.Random; +import lombok.extern.slf4j.Slf4j; @Slf4j public class NetworkToolbox { @@ -21,13 +20,13 @@ public class NetworkToolbox { */ public static int findFreeTCPPort(int min, int max) { - for(int i = 0;i < 10000;i++) { + for (int i = 0; i < 10000; i++) { int possiblePort = min + random.nextInt(max - min); try { ServerSocket serverSocket = new ServerSocket(possiblePort); serverSocket.close(); return possiblePort; - } catch(IOException e) { + } catch (IOException e) { continue; } } @@ -45,13 +44,13 @@ public static int findFreeTCPPort(int min, int max) { */ public static int findFreeUDPPort(int min, int max) { - for(int i = 0;i < 10000;i++) { + for (int i = 0; i < 10000; i++) { int possiblePort = min + random.nextInt(max - min); try { DatagramSocket socket = new DatagramSocket(possiblePort); socket.close(); return possiblePort; - } catch(SocketException e) { + } catch (SocketException e) { continue; } } diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/util/PingWrapper.java b/ice-adapter/src/main/java/com/faforever/iceadapter/util/PingWrapper.java index 712a5de..0e04013 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/util/PingWrapper.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/util/PingWrapper.java @@ -1,15 +1,13 @@ package com.faforever.iceadapter.util; import com.google.common.io.CharStreams; -import lombok.extern.slf4j.Slf4j; - import java.io.IOException; import java.io.InputStreamReader; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.regex.Matcher; import java.util.regex.Pattern; - +import lombok.extern.slf4j.Slf4j; /* * A wrapper around calling the system `ping` executable to query the latency of a host. @@ -17,7 +15,8 @@ @Slf4j public class PingWrapper { static final Pattern WINDOWS_OUTPUT_PATTERN = Pattern.compile("Average = (\\d+)ms", Pattern.MULTILINE); - static final Pattern GNU_OUTPUT_PATTERN = Pattern.compile("min/avg/max/mdev = [0-9.]+/([0-9.]+)/[0-9.]+/[0-9.]+", Pattern.MULTILINE); + static final Pattern GNU_OUTPUT_PATTERN = + Pattern.compile("min/avg/max/mdev = [0-9.]+/([0-9.]+)/[0-9.]+/[0-9.]+", Pattern.MULTILINE); /* * Get the round trip time to an address. diff --git a/ice-adapter/src/main/java/com/faforever/iceadapter/util/TrayIcon.java b/ice-adapter/src/main/java/com/faforever/iceadapter/util/TrayIcon.java index d2f61cb..a95a744 100644 --- a/ice-adapter/src/main/java/com/faforever/iceadapter/util/TrayIcon.java +++ b/ice-adapter/src/main/java/com/faforever/iceadapter/util/TrayIcon.java @@ -3,94 +3,93 @@ import com.faforever.iceadapter.debug.Debug; import com.faforever.iceadapter.debug.DebugWindow; import com.faforever.iceadapter.debug.InfoWindow; -import lombok.extern.slf4j.Slf4j; - -import javax.imageio.ImageIO; -import javax.swing.*; import java.awt.*; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.io.IOException; import java.net.URL; +import javax.imageio.ImageIO; +import javax.swing.*; +import lombok.extern.slf4j.Slf4j; @Slf4j public class TrayIcon { - public static final String FAF_LOGO_URL = "https://faforever.com/images/faf-logo.png"; - private static volatile java.awt.TrayIcon trayIcon; - - - public static void create() { - if (!isTrayIconSupported()) { - log.warn("Tray icon not supported"); - return; - } - - Image fafLogo = null; - try { - fafLogo = ImageIO.read(new URL(FAF_LOGO_URL)); - } catch (IOException e) { - log.error("Couldn't load FAF tray icon logo from URL"); - return; - } - - fafLogo = fafLogo.getScaledInstance(new java.awt.TrayIcon(fafLogo).getSize().width, new java.awt.TrayIcon(fafLogo).getSize().height, Image.SCALE_SMOOTH); - - trayIcon = new java.awt.TrayIcon(fafLogo, "FAForever Connection ICE Adapter"); - - trayIcon.addMouseListener(new MouseListener() { - @Override - public void mouseClicked(MouseEvent mouseEvent) { - } - - @Override - public void mousePressed(MouseEvent mouseEvent) { - new Thread(() -> { - if (InfoWindow.INSTANCE == null) { - log.info("Launching ICE adapter debug window"); - Debug.ENABLE_INFO_WINDOW = true; - DebugWindow.launchApplication(); - } else { - InfoWindow.INSTANCE.show(); - } - }).start(); - } - - @Override - public void mouseReleased(MouseEvent mouseEvent) { - } - - @Override - public void mouseEntered(MouseEvent mouseEvent) { - } - - @Override - public void mouseExited(MouseEvent mouseEvent) { - } - }); - - try { - SystemTray.getSystemTray().add(trayIcon); - } catch (AWTException e) { - log.error("Tray icon could not be added", e); - } - - log.info("Created tray icon"); - } - - public static void showMessage(String message) { - SwingUtilities.invokeLater(() -> { - if (trayIcon != null) { - trayIcon.displayMessage("FAForever Connection ICE Adapter", message, java.awt.TrayIcon.MessageType.INFO); - } - }); - } - - public static void close() { - SystemTray.getSystemTray().remove(trayIcon); - } - - public static boolean isTrayIconSupported() { - return SystemTray.isSupported(); - } + public static final String FAF_LOGO_URL = "https://faforever.com/images/faf-logo.png"; + private static volatile java.awt.TrayIcon trayIcon; + + public static void create() { + if (!isTrayIconSupported()) { + log.warn("Tray icon not supported"); + return; + } + + Image fafLogo = null; + try { + fafLogo = ImageIO.read(new URL(FAF_LOGO_URL)); + } catch (IOException e) { + log.error("Couldn't load FAF tray icon logo from URL"); + return; + } + + fafLogo = fafLogo.getScaledInstance( + new java.awt.TrayIcon(fafLogo).getSize().width, + new java.awt.TrayIcon(fafLogo).getSize().height, + Image.SCALE_SMOOTH); + + trayIcon = new java.awt.TrayIcon(fafLogo, "FAForever Connection ICE Adapter"); + + trayIcon.addMouseListener(new MouseListener() { + @Override + public void mouseClicked(MouseEvent mouseEvent) {} + + @Override + public void mousePressed(MouseEvent mouseEvent) { + new Thread(() -> { + if (InfoWindow.INSTANCE == null) { + log.info("Launching ICE adapter debug window"); + Debug.ENABLE_INFO_WINDOW = true; + DebugWindow.launchApplication(); + } else { + InfoWindow.INSTANCE.show(); + } + }) + .start(); + } + + @Override + public void mouseReleased(MouseEvent mouseEvent) {} + + @Override + public void mouseEntered(MouseEvent mouseEvent) {} + + @Override + public void mouseExited(MouseEvent mouseEvent) {} + }); + + try { + SystemTray.getSystemTray().add(trayIcon); + } catch (AWTException e) { + log.error("Tray icon could not be added", e); + } + + log.info("Created tray icon"); + } + + public static void showMessage(String message) { + SwingUtilities.invokeLater(() -> { + if (trayIcon != null) { + trayIcon.displayMessage( + "FAForever Connection ICE Adapter", message, java.awt.TrayIcon.MessageType.INFO); + } + }); + } + + public static void close() { + SystemTray.getSystemTray().remove(trayIcon); + } + + public static boolean isTrayIconSupported() { + return SystemTray.isSupported(); + } } diff --git a/ice-adapter/src/test/java/IceTest.java b/ice-adapter/src/test/java/IceTest.java index 6141bac..1fe726a 100644 --- a/ice-adapter/src/test/java/IceTest.java +++ b/ice-adapter/src/test/java/IceTest.java @@ -2,16 +2,6 @@ import com.faforever.iceadapter.ice.CandidatesMessage; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import lombok.extern.slf4j.Slf4j; -import org.ice4j.Transport; -import org.ice4j.TransportAddress; -import org.ice4j.ice.*; -import org.ice4j.ice.harvest.StunCandidateHarvester; -import org.ice4j.ice.harvest.TurnCandidateHarvester; -import org.ice4j.security.LongTermCredential; - -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; @@ -22,14 +12,23 @@ import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.*; +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import lombok.extern.slf4j.Slf4j; +import org.ice4j.Transport; +import org.ice4j.TransportAddress; +import org.ice4j.ice.*; +import org.ice4j.ice.harvest.StunCandidateHarvester; +import org.ice4j.ice.harvest.TurnCandidateHarvester; +import org.ice4j.security.LongTermCredential; @Slf4j public class IceTest { private static final String COTURN_HOST = "geosearchef.de"; private static final String COTURN_KEY = "B9UohFSnFeX1YQ7nQJsBe3MwWS4kx4FJ8TUBUDzYG23rLBCIeJMvgYfbRkeK"; -// private static final String COTURN_HOST = "vmrbg145.informatik.tu-muenchen.de"; -// private static final String COTURN_KEY = "banana"; + // private static final String COTURN_HOST = "vmrbg145.informatik.tu-muenchen.de"; + // private static final String COTURN_KEY = "banana"; private static final ObjectMapper objectMapper = new ObjectMapper(); @@ -48,7 +47,8 @@ public static void main(String args[]) throws IOException { byte[] secret = null; try { Mac mac = Mac.getInstance("HmacSHA1"); - mac.init(new SecretKeySpec(Charset.forName("cp1252").encode(COTURN_KEY).array(), "HmacSHA1")); + mac.init(new SecretKeySpec( + Charset.forName("cp1252").encode(COTURN_KEY).array(), "HmacSHA1")); secret = mac.doFinal(Charset.forName("cp1252").encode(tokenName).array()); } catch (NoSuchAlgorithmException | InvalidKeyException e) { @@ -62,24 +62,21 @@ public static void main(String args[]) throws IOException { map.put("credentialType", "token"); map.put("username", tokenName); - - -// int localPort + // int localPort TransportAddress[] turnAddresses = { - new TransportAddress(COTURN_HOST, 3478, Transport.TCP), - new TransportAddress(COTURN_HOST, 3478, Transport.UDP), -// String.format("turn:%s?transport=tcp", COTURN_HOST), -// String.format("turn:%s?transport=udp", COTURN_HOST) + new TransportAddress(COTURN_HOST, 3478, Transport.TCP), + new TransportAddress(COTURN_HOST, 3478, Transport.UDP), + // String.format("turn:%s?transport=tcp", COTURN_HOST), + // String.format("turn:%s?transport=udp", COTURN_HOST) }; TransportAddress[] stunAddresses = { - new TransportAddress(COTURN_HOST, 3478, Transport.UDP), -// new TransportAddress("stun3.l.google.com", 19302, Transport.UDP) -// String.format("stun:%s", COTURN_HOST) + new TransportAddress(COTURN_HOST, 3478, Transport.UDP), + // new TransportAddress("stun3.l.google.com", 19302, Transport.UDP) + // String.format("stun:%s", COTURN_HOST) }; - Agent agent = new Agent(); System.out.printf("Controlling?(true|false)\n"); @@ -88,26 +85,29 @@ public static void main(String args[]) throws IOException { Arrays.stream(turnAddresses) .map(a -> new TurnCandidateHarvester( a, - new LongTermCredential(/*String.format("%d:%s", ((System.currentTimeMillis() / 1000) + 3600*24), username)*/(String) map.get("username"), (String) map.get("credential")))) + new LongTermCredential( + /*String.format("%d:%s", ((System.currentTimeMillis() / 1000) + 3600*24), username)*/ (String) + map.get("username"), + (String) map.get("credential")))) .forEach(agent::addCandidateHarvester); Arrays.stream(stunAddresses).map(StunCandidateHarvester::new).forEach(agent::addCandidateHarvester); - System.out.printf("Preferred port?\n");//host port + System.out.printf("Preferred port?\n"); // host port int preferredPort = scan.nextInt(); IceMediaStream mediaStream = agent.createMediaStream("mainStream"); Component component = agent.createComponent(mediaStream, preferredPort, preferredPort, preferredPort + 100); - //------------------------------------------------------------ - //agent done - //------------------------------------------------------------ + // ------------------------------------------------------------ + // agent done + // ------------------------------------------------------------ - //print candidates - //may have to be done for multiple components + // print candidates + // may have to be done for multiple components int candidateIDFactory = 0; final List candidatePackets = new ArrayList<>(); - for(LocalCandidate localCandidate : component.getLocalCandidates()) { + for (LocalCandidate localCandidate : component.getLocalCandidates()) { String relAddr = null; int relPort = 0; @@ -126,19 +126,21 @@ public static void main(String args[]) throws IOException { agent.getGeneration(), String.valueOf(candidateIDFactory++), relAddr, - relPort - ); + relPort); candidatePackets.add(candidatePacket); } Collections.sort(candidatePackets); - CandidatesMessage localCandidatesMessage = new CandidatesMessage(0, 0/*mocked*/, agent.getLocalPassword(), agent.getLocalUfrag(), candidatePackets); + CandidatesMessage localCandidatesMessage = new CandidatesMessage( + 0, 0 /*mocked*/, agent.getLocalPassword(), agent.getLocalUfrag(), candidatePackets); - System.out.printf("------------------------------------\n%s\n------------------------------------\n", objectMapper.writeValueAsString(localCandidatesMessage)); + System.out.printf( + "------------------------------------\n%s\n------------------------------------\n", + objectMapper.writeValueAsString(localCandidatesMessage)); - //read candidates + // read candidates Socket socket = new Socket("localhost", 49456); DataOutputStream out = new DataOutputStream(socket.getOutputStream()); DataInputStream in = new DataInputStream(socket.getInputStream()); @@ -146,19 +148,26 @@ public static void main(String args[]) throws IOException { out.flush(); CandidatesMessage remoteCandidatesMessage = objectMapper.readValue(in.readUTF(), CandidatesMessage.class); - //Set candidates + // Set candidates mediaStream.setRemotePassword(remoteCandidatesMessage.password()); mediaStream.setRemoteUfrag(remoteCandidatesMessage.ufrag()); - for(CandidatePacket remoteCandidatePacket : remoteCandidatesMessage.candidates()) { + for (CandidatePacket remoteCandidatePacket : remoteCandidatesMessage.candidates()) { - if(remoteCandidatePacket.generation() == agent.getGeneration() - && remoteCandidatePacket.ip() != null && remoteCandidatePacket.port() > 0) { + if (remoteCandidatePacket.generation() == agent.getGeneration() + && remoteCandidatePacket.ip() != null + && remoteCandidatePacket.port() > 0) { - TransportAddress mainAddress = new TransportAddress(remoteCandidatePacket.ip(), remoteCandidatePacket.port(), Transport.parse(remoteCandidatePacket.protocol().toLowerCase())); + TransportAddress mainAddress = new TransportAddress( + remoteCandidatePacket.ip(), + remoteCandidatePacket.port(), + Transport.parse(remoteCandidatePacket.protocol().toLowerCase())); RemoteCandidate relatedCandidate = null; - if(remoteCandidatePacket.relAddr() != null && remoteCandidatePacket.relPort() > 0) { - TransportAddress relatedAddr = new TransportAddress(remoteCandidatePacket.relAddr(), remoteCandidatePacket.relPort(), Transport.parse(remoteCandidatePacket.protocol().toLowerCase())); + if (remoteCandidatePacket.relAddr() != null && remoteCandidatePacket.relPort() > 0) { + TransportAddress relatedAddr = new TransportAddress( + remoteCandidatePacket.relAddr(), + remoteCandidatePacket.relPort(), + Transport.parse(remoteCandidatePacket.protocol().toLowerCase())); relatedCandidate = component.findRemoteCandidate(relatedAddr); } @@ -168,30 +177,51 @@ public static void main(String args[]) throws IOException { CandidateType.parse(remoteCandidatePacket.type().toString()), remoteCandidatePacket.foundation(), remoteCandidatePacket.priority(), - relatedCandidate - ); + relatedCandidate); - if(remoteCandidate.getType().equals(CandidateType.RELAYED_CANDIDATE)) //DEBUGGING: turn only - component.addRemoteCandidate(remoteCandidate); + if (remoteCandidate.getType().equals(CandidateType.RELAYED_CANDIDATE)) // DEBUGGING: turn only + component.addRemoteCandidate(remoteCandidate); } } agent.startConnectivityEstablishment(); - while(agent.getState() != IceProcessingState.TERMINATED) {//TODO include more? - try { Thread.sleep(20); } catch(InterruptedException e) { e.printStackTrace(); } + while (agent.getState() != IceProcessingState.TERMINATED) { // TODO include more? + try { + Thread.sleep(20); + } catch (InterruptedException e) { + e.printStackTrace(); + } } - - while("".equals("")) { - component.getSelectedPair().getIceSocketWrapper().send(new DatagramPacket("Aeon is the worst faction on this planet!".getBytes(), 0, 4, InetAddress.getByName(component.getSelectedPair().getRemoteCandidate().getHostAddress().getHostAddress()), component.getSelectedPair().getRemoteCandidate().getHostAddress().getPort())); - byte[] data = new byte[1024]; - component.getSelectedPair().getIceSocketWrapper().receive(new DatagramPacket(data, data.length)); - System.out.println("Got data: " + new String(data)); - try {Thread.sleep(2500);} catch(InterruptedException e) {e.printStackTrace();} + while ("".isEmpty()) { + component + .getSelectedPair() + .getIceSocketWrapper() + .send(new DatagramPacket( + "Aeon is the worst faction on this planet!".getBytes(), + 0, + 4, + InetAddress.getByName(component + .getSelectedPair() + .getRemoteCandidate() + .getHostAddress() + .getHostAddress()), + component + .getSelectedPair() + .getRemoteCandidate() + .getHostAddress() + .getPort())); + byte[] data = new byte[1024]; + component.getSelectedPair().getIceSocketWrapper().receive(new DatagramPacket(data, data.length)); + System.out.println("Got data: " + new String(data)); + try { + Thread.sleep(2500); + } catch (InterruptedException e) { + e.printStackTrace(); + } } agent.free(); } - } diff --git a/ice-adapter/src/test/java/SignallingServer.java b/ice-adapter/src/test/java/SignallingServer.java index 7779738..d06fa4f 100644 --- a/ice-adapter/src/test/java/SignallingServer.java +++ b/ice-adapter/src/test/java/SignallingServer.java @@ -16,12 +16,11 @@ public static void main(String args[]) throws IOException { List messages = new ArrayList<>(); List sockets = new ArrayList<>(); - - while(true) { + while (true) { Socket socket = serverSocket.accept(); String s = new DataInputStream(socket.getInputStream()).readUTF(); - if(sockets.size() >= 2) { + if (sockets.size() >= 2) { sockets.clear(); messages.clear(); } @@ -29,7 +28,7 @@ public static void main(String args[]) throws IOException { messages.add(s); sockets.add(socket); - if(sockets.size() == 2) { + if (sockets.size() == 2) { DataOutputStream out1 = new DataOutputStream(sockets.get(0).getOutputStream()); out1.writeUTF(messages.get(1)); out1.flush(); @@ -38,7 +37,10 @@ public static void main(String args[]) throws IOException { out2.flush(); sockets.forEach(sock -> { - try { sock.close(); } catch(IOException e) {} + try { + sock.close(); + } catch (IOException e) { + } }); sockets.clear(); messages.clear();