From b4a3793d5d6f3d76bb9af670bc7e960d2bd5b303 Mon Sep 17 00:00:00 2001 From: Minecon724 Date: Mon, 9 Dec 2024 19:38:45 +0100 Subject: [PATCH] Initial commit --- .gitignore | 38 ++++++++++ .idea/.gitignore | 3 + .idea/encodings.xml | 7 ++ .idea/misc.xml | 14 ++++ .idea/vcs.xml | 6 ++ pom.xml | 24 ++++++ .../java/eu/m724/autopeerer/client/Main.java | 16 ++++ .../autopeerer/client/MyWebsocketClient.java | 66 +++++++++++++++++ .../m724/autopeerer/client/PacketHandler.java | 74 +++++++++++++++++++ .../eu/m724/autopeerer/packet/Packet.java | 10 +++ .../eu/m724/autopeerer/packet/Packets.java | 41 ++++++++++ .../autopeerer/packet/PingRequestPacket.java | 44 +++++++++++ .../autopeerer/packet/PingResponsePacket.java | 61 +++++++++++++++ 13 files changed, 404 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/encodings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/vcs.xml create mode 100644 pom.xml create mode 100644 src/main/java/eu/m724/autopeerer/client/Main.java create mode 100644 src/main/java/eu/m724/autopeerer/client/MyWebsocketClient.java create mode 100644 src/main/java/eu/m724/autopeerer/client/PacketHandler.java create mode 100644 src/main/java/eu/m724/autopeerer/packet/Packet.java create mode 100644 src/main/java/eu/m724/autopeerer/packet/Packets.java create mode 100644 src/main/java/eu/m724/autopeerer/packet/PingRequestPacket.java create mode 100644 src/main/java/eu/m724/autopeerer/packet/PingResponsePacket.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..e74481f --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..b19f677 --- /dev/null +++ b/pom.xml @@ -0,0 +1,24 @@ + + + 4.0.0 + + eu.m724 + autopeerer + 1.0-SNAPSHOT + + + 17 + 17 + UTF-8 + + + + + org.java-websocket + Java-WebSocket + 1.5.7 + + + \ No newline at end of file diff --git a/src/main/java/eu/m724/autopeerer/client/Main.java b/src/main/java/eu/m724/autopeerer/client/Main.java new file mode 100644 index 0000000..5faa6f0 --- /dev/null +++ b/src/main/java/eu/m724/autopeerer/client/Main.java @@ -0,0 +1,16 @@ +package eu.m724.autopeerer.client; + +import java.net.URI; + +public class Main { + public static void main(String[] args) throws InterruptedException { + System.out.println("Hello world!"); + + URI serverUri = URI.create("wss://echo.websocket.org/"); + + var packetHandler = new PacketHandler(); + var client = new MyWebsocketClient(serverUri, packetHandler); + + client.connectBlocking(); + } +} \ No newline at end of file diff --git a/src/main/java/eu/m724/autopeerer/client/MyWebsocketClient.java b/src/main/java/eu/m724/autopeerer/client/MyWebsocketClient.java new file mode 100644 index 0000000..93e69f5 --- /dev/null +++ b/src/main/java/eu/m724/autopeerer/client/MyWebsocketClient.java @@ -0,0 +1,66 @@ +package eu.m724.autopeerer.client; + +import eu.m724.autopeerer.packet.Packets; +import eu.m724.autopeerer.packet.PingRequestPacket; +import org.java_websocket.client.WebSocketClient; +import org.java_websocket.handshake.ServerHandshake; + +import java.net.InetAddress; +import java.net.URI; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; + +public class MyWebsocketClient extends WebSocketClient { + private final PacketHandler packetHandler; + private long connectStart; + + public MyWebsocketClient(URI serverUri, PacketHandler packetHandler) { + super(serverUri); + this.packetHandler = packetHandler; + packetHandler.sender = this::send; + } + + @Override + public void connect() { + super.connect(); + connectStart = System.nanoTime(); + } + + @Override + public void onOpen(ServerHandshake serverHandshake) { + double connectTime = (System.nanoTime() - connectStart) / 1000000.0; + System.out.printf("Connected in %.3f ms\n", connectTime); + + try { + for (int i=0; i<10; i++) { + send(Packets.compose(new PingRequestPacket((short)i, InetAddress.getByName("1.1.1." + i)))); + } + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + } + + @Override + public void onMessage(ByteBuffer bytes) { + packetHandler.handle(bytes); + } + + @Override + public void onClose(int code, String reason, boolean remote) { + if (remote) { + System.out.println("Closed by remote: " + code + " " + reason); + } else { + System.out.println("Closed by client: " + code + " " + reason); + } + } + + @Override + public void onError(Exception e) { + System.err.println("WS error: "); + e.printStackTrace(); + } + + // we don't do String + @Override + public void onMessage(String s) { } +} diff --git a/src/main/java/eu/m724/autopeerer/client/PacketHandler.java b/src/main/java/eu/m724/autopeerer/client/PacketHandler.java new file mode 100644 index 0000000..96addd1 --- /dev/null +++ b/src/main/java/eu/m724/autopeerer/client/PacketHandler.java @@ -0,0 +1,74 @@ +package eu.m724.autopeerer.client; + +import eu.m724.autopeerer.packet.Packet; +import eu.m724.autopeerer.packet.Packets; +import eu.m724.autopeerer.packet.PingRequestPacket; +import eu.m724.autopeerer.packet.PingResponsePacket; + +import java.io.BufferedReader; +import java.io.IOException; +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.util.Base64; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; + +public class PacketHandler { + Consumer sender; + + void handle(ByteBuffer bytes) { + Packet p; + try { + p = Packets.parseClient(bytes); + } catch (BufferUnderflowException e) { + bytes.rewind(); + byte[] bytez = new byte[bytes.remaining()]; + bytes.get(bytez); + + System.err.println("Received too short packet"); + System.err.println("> Length: " + bytez.length); + System.err.println("> Packet: " + Base64.getEncoder().encodeToString(bytez)); + + return; + } catch (Exception e) { + throw new RuntimeException(e); + } + + if (p instanceof PingRequestPacket packet) {System.out.printf("Ping request #%d to %s\n", packet.requestId, packet.target.getHostAddress()); + + CompletableFuture.runAsync(() -> { + float average = -1, meanDeviation = -1; + var status = PingResponsePacket.PingResponseStatus.ERROR; + + try { + Process process = Runtime.getRuntime().exec(new String[] { "ping", "-3Ac", "10", packet.target.getHostAddress() }); + + try (BufferedReader reader = process.inputReader()) { + for (String l : reader.lines().toList()) { + boolean error = l.startsWith("From"); // indicates an error + boolean end = l.startsWith("rtt"); + + if (error) { + status = PingResponsePacket.PingResponseStatus.UNREACHABLE; + break; + } + + if (end) { + String[] results = l.split(" ")[3].split("/"); + average = Float.parseFloat(results[1]); + meanDeviation = Float.parseFloat(results[3]); + status = PingResponsePacket.PingResponseStatus.OK; + } + } + } + } catch (IOException e) { + System.err.println("Error pinging"); + e.printStackTrace(); + } + + System.out.printf("Ping request #%d to %s - %s avg %.3f / mdev %.3f ms\n", packet.requestId, packet.target.getHostAddress(), status, average, meanDeviation); + sender.accept(new PingResponsePacket(packet.requestId, status, average, meanDeviation).serialize()); + }); + } + } +} diff --git a/src/main/java/eu/m724/autopeerer/packet/Packet.java b/src/main/java/eu/m724/autopeerer/packet/Packet.java new file mode 100644 index 0000000..2ba1ebe --- /dev/null +++ b/src/main/java/eu/m724/autopeerer/packet/Packet.java @@ -0,0 +1,10 @@ +package eu.m724.autopeerer.packet; + +import java.nio.ByteBuffer; + +public interface Packet> { + byte getId(); + + //T deserialize(ByteArrayInputStream inputStream) throws IOException; + ByteBuffer serialize(); +} diff --git a/src/main/java/eu/m724/autopeerer/packet/Packets.java b/src/main/java/eu/m724/autopeerer/packet/Packets.java new file mode 100644 index 0000000..31b9eaa --- /dev/null +++ b/src/main/java/eu/m724/autopeerer/packet/Packets.java @@ -0,0 +1,41 @@ +package eu.m724.autopeerer.packet; + +import java.nio.ByteBuffer; + +public class Packets { + public static Packet parseClient(ByteBuffer buffer) throws Exception { + byte id = buffer.get(); + + Packet packet = null; + + if (id == 1) { + packet = PingRequestPacket.deserialize(buffer); + } + + return packet; + } + + public static Packet parseServer(ByteBuffer buffer) throws Exception { + byte id = buffer.get(); + + Packet packet = null; + + if (id == 1) { + PingResponsePacket.deserialize(buffer); + } + + return packet; + } + + public static ByteBuffer compose(Packet packet) { + ByteBuffer packetBuffer = packet.serialize(); + packetBuffer.rewind(); + + var bb = ByteBuffer.allocate(1 + packetBuffer.remaining()); + bb.put(packet.getId()); + bb.put(packetBuffer); + bb.rewind(); + + return bb; + } +} diff --git a/src/main/java/eu/m724/autopeerer/packet/PingRequestPacket.java b/src/main/java/eu/m724/autopeerer/packet/PingRequestPacket.java new file mode 100644 index 0000000..5c29024 --- /dev/null +++ b/src/main/java/eu/m724/autopeerer/packet/PingRequestPacket.java @@ -0,0 +1,44 @@ +package eu.m724.autopeerer.packet; + +import java.net.Inet6Address; +import java.net.InetAddress; +import java.nio.ByteBuffer; + +public class PingRequestPacket implements Packet { + public final short requestId; + public final InetAddress target; + + public PingRequestPacket(short requestId,InetAddress target) { + this.requestId = requestId; + this.target = target; + } + + @Override + public byte getId() { + return 1; + } + + public static PingRequestPacket deserialize(ByteBuffer buffer) throws Exception { + var requestId = buffer.getShort(); + var ipv6 = buffer.get() == 1; + + byte[] addr = new byte[ipv6 ? 16 : 4]; + buffer.get(addr); + InetAddress target = InetAddress.getByAddress(addr); + + return new PingRequestPacket(requestId, target); + } + + @Override + public ByteBuffer serialize() { + boolean ipv6 = target instanceof Inet6Address; + int bytes = 3 + (ipv6 ? 16 : 4); + + var buffer = ByteBuffer.allocate(bytes); + buffer.putShort(requestId); + buffer.put((byte) (ipv6 ? 1 : 0)); + buffer.put(target.getAddress()); + + return buffer; + } +} diff --git a/src/main/java/eu/m724/autopeerer/packet/PingResponsePacket.java b/src/main/java/eu/m724/autopeerer/packet/PingResponsePacket.java new file mode 100644 index 0000000..a27c000 --- /dev/null +++ b/src/main/java/eu/m724/autopeerer/packet/PingResponsePacket.java @@ -0,0 +1,61 @@ +package eu.m724.autopeerer.packet; + +import java.nio.ByteBuffer; + +public class PingResponsePacket implements Packet { + public final short requestId; + public final PingResponseStatus status; + public final float average; + public final float meanDeviation; + + public PingResponsePacket(short requestId, PingResponseStatus status, float average, float meanDeviation) { + this.requestId = requestId; + this.status = status; + this.average = average; + this.meanDeviation = meanDeviation; + } + + @Override + public byte getId() { + return 1; + } + + public static PingResponsePacket deserialize(ByteBuffer buffer) { + var requestId = buffer.getShort(); + var average = buffer.getFloat(); + var meanDeviation = buffer.getFloat(); + + var status = PingResponseStatus.OK; + + if (average == -1) { + status = meanDeviation == 0 ? PingResponseStatus.UNREACHABLE : PingResponseStatus.ERROR; + } + + return new PingResponsePacket(requestId, status, average, meanDeviation); + } + + @Override + public ByteBuffer serialize() { + var bb = ByteBuffer.allocate(9); + bb.putShort(requestId); + switch (status) { + case OK -> { + bb.putFloat(average); + bb.putFloat(meanDeviation); + } + case UNREACHABLE -> { + bb.putFloat(-1); + bb.putFloat(0); + } + case ERROR -> { + bb.putFloat(-1); + bb.putFloat(-1); + } + } + return bb; + } + + public enum PingResponseStatus { + OK, UNREACHABLE, ERROR + } +}