Initial commit

This commit is contained in:
Minecon724 2024-12-09 19:38:45 +01:00
commit b4a3793d5d
Signed by: Minecon724
GPG key ID: 3CCC4D267742C8E8
13 changed files with 404 additions and 0 deletions

38
.gitignore vendored Normal file
View file

@ -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

3
.idea/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

7
.idea/encodings.xml Normal file
View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>

14
.idea/misc.xml Normal file
View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="temurin-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

6
.idea/vcs.xml Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

24
pom.xml Normal file
View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>eu.m724</groupId>
<artifactId>autopeerer</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
<version>1.5.7</version>
</dependency>
</dependencies>
</project>

View file

@ -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();
}
}

View file

@ -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) { }
}

View file

@ -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<ByteBuffer> 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());
});
}
}
}

View file

@ -0,0 +1,10 @@
package eu.m724.autopeerer.packet;
import java.nio.ByteBuffer;
public interface Packet<T extends Packet<T>> {
byte getId();
//T deserialize(ByteArrayInputStream inputStream) throws IOException;
ByteBuffer serialize();
}

View file

@ -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;
}
}

View file

@ -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<PingRequestPacket> {
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;
}
}

View file

@ -0,0 +1,61 @@
package eu.m724.autopeerer.packet;
import java.nio.ByteBuffer;
public class PingResponsePacket implements Packet<PingResponsePacket> {
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
}
}