parent
5874e8b47e
commit
b3752fd4ae
27 changed files with 504 additions and 306 deletions
|
@ -1,3 +0,0 @@
|
|||
key=AAAAAAAAAAA=
|
||||
name="Node Number One"
|
||||
host=example.com
|
5
pom.xml
5
pom.xml
|
@ -15,11 +15,6 @@
|
|||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.java-websocket</groupId>
|
||||
<artifactId>Java-WebSocket</artifactId>
|
||||
<version>1.5.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.json</groupId>
|
||||
<artifactId>json</artifactId>
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
package eu.m724.autopeerer.client;
|
||||
|
||||
public class ClientPrefs {
|
||||
private static ClientPrefs INSTANCE;
|
||||
|
||||
private final boolean ipv4, restricted4, ipv6, restricted6;
|
||||
|
||||
private ClientPrefs( boolean ipv4, boolean restricted4, boolean ipv6, boolean restricted6) {
|
||||
this.ipv4 = ipv4;
|
||||
this.restricted4 = restricted4;
|
||||
this.ipv6 = ipv6;
|
||||
this.restricted6 = restricted6;
|
||||
}
|
||||
|
||||
public static void init(ClientConfiguration configuration) {
|
||||
var ipv4 = configuration.getString("stack.ipv4");
|
||||
var ipv6 = configuration.getString("stack.ipv6");
|
||||
|
||||
INSTANCE = new ClientPrefs(
|
||||
ipv4.equalsIgnoreCase("yes") || ipv4.equalsIgnoreCase("restricted"),
|
||||
ipv4.equalsIgnoreCase("restricted"),
|
||||
ipv6.equalsIgnoreCase("yes") || ipv6.equalsIgnoreCase("restricted"),
|
||||
ipv6.equalsIgnoreCase("restricted")
|
||||
);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
public static boolean ipv4Supported() {
|
||||
return INSTANCE.ipv4;
|
||||
}
|
||||
|
||||
public static boolean ipv6Supported() {
|
||||
return INSTANCE.ipv6;
|
||||
}
|
||||
|
||||
public static boolean ipv4Restricted() {
|
||||
return INSTANCE.restricted4;
|
||||
}
|
||||
|
||||
public static boolean ipv6Restricted() {
|
||||
return INSTANCE.restricted6;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,16 +1,18 @@
|
|||
package eu.m724.autopeerer.client;
|
||||
|
||||
import eu.m724.autopeerer.client.bird.BirdLive;
|
||||
import eu.m724.autopeerer.client.connectivity.Connectivity;
|
||||
import eu.m724.autopeerer.client.wireguard.WireGuardLive;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
System.out.println("Hello world!");
|
||||
|
||||
public static void main(String[] args) {
|
||||
var config = new ClientConfiguration();
|
||||
try {
|
||||
config.load();
|
||||
|
@ -23,16 +25,34 @@ public class Main {
|
|||
return;
|
||||
}
|
||||
|
||||
ClientPrefs.init(config);
|
||||
System.out.print("Checking connectivity");
|
||||
Connectivity.check();
|
||||
|
||||
URI serverUri = URI.create(config.getString("remote"));
|
||||
var list = new ArrayList<String>();
|
||||
|
||||
if (Connectivity.ipv6()) list.add("IPv6");
|
||||
if (Connectivity.ipv4()) list.add("IPv4");
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
System.out.println(": " + String.join(" + ", list));
|
||||
} else {
|
||||
System.err.println(": You have no internet");
|
||||
}
|
||||
|
||||
var remote = config.getString("remote").split(":");
|
||||
var serverAddress = new InetSocketAddress(remote[0], Integer.parseInt(remote[1]));
|
||||
|
||||
var wireGuardLive = new WireGuardLive(new File(config.getString("wireguard.directory")));
|
||||
var birdLive = new BirdLive(new File(config.getString("bird.directory")));
|
||||
|
||||
var packetHandler = new PacketHandler(wireGuardLive, birdLive, config.getString("link-local"));
|
||||
var client = new MyWebsocketClient(serverUri, packetHandler);
|
||||
var packetHandler = new PacketHandler(wireGuardLive, birdLive);
|
||||
var client = new MyTcpClient(serverAddress, config.getString("key"), packetHandler);
|
||||
|
||||
client.connect();
|
||||
try {
|
||||
client.connect();
|
||||
} catch (IOException e) {
|
||||
System.err.println("Error connecting");
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
64
src/main/java/eu/m724/autopeerer/client/MyTcpClient.java
Normal file
64
src/main/java/eu/m724/autopeerer/client/MyTcpClient.java
Normal file
|
@ -0,0 +1,64 @@
|
|||
package eu.m724.autopeerer.client;
|
||||
|
||||
import eu.m724.autopeerer.common.packet.PacketReaderImpl;
|
||||
import eu.m724.autopeerer.common.packet.PacketReaderRunnable;
|
||||
import eu.m724.autopeerer.common.packet.Packets;
|
||||
import eu.m724.autopeerer.common.packet.c2s.LoginPacket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Base64;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class MyTcpClient {
|
||||
private final InetSocketAddress serverAddress;
|
||||
private final byte[] key;
|
||||
private final PacketHandler packetHandler;
|
||||
|
||||
private Socket socket;
|
||||
|
||||
public MyTcpClient(InetSocketAddress serverAddress, String key, PacketHandler packetHandler) {
|
||||
this.serverAddress = serverAddress;
|
||||
this.key = Base64.getDecoder().decode(key);
|
||||
this.packetHandler = packetHandler;
|
||||
}
|
||||
|
||||
public void connect() throws IOException {
|
||||
var connectStart = System.nanoTime();
|
||||
|
||||
this.socket = new Socket(serverAddress.getAddress(), serverAddress.getPort());
|
||||
|
||||
double connectTime = (System.nanoTime() - connectStart) / 1000000.0;
|
||||
System.out.printf("Connected in %.3f ms\n", connectTime);
|
||||
|
||||
packetHandler.outputStream = socket.getOutputStream();
|
||||
Packets.send(new LoginPacket(key), socket.getOutputStream());
|
||||
|
||||
Executors.newSingleThreadExecutor().execute(new PacketReaderRunnable(socket, new PacketReaderImpl() {
|
||||
@Override
|
||||
public void onPacket(ByteBuffer byteBuffer) {
|
||||
try {
|
||||
packetHandler.handle(byteBuffer);
|
||||
} catch (IOException e) {
|
||||
System.err.println("Error handling packet");
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception exception) {
|
||||
System.err.println("Connection error:");
|
||||
exception.printStackTrace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose() {
|
||||
System.out.println("Connection closed");
|
||||
}
|
||||
}));
|
||||
|
||||
while (socket.isConnected()) { } // TODO
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
package eu.m724.autopeerer.client;
|
||||
|
||||
import eu.m724.autopeerer.common.packet.Packets;
|
||||
import eu.m724.autopeerer.common.packet.c2s.LoginPacket;
|
||||
import org.java_websocket.client.WebSocketClient;
|
||||
import org.java_websocket.handshake.ServerHandshake;
|
||||
|
||||
import java.net.URI;
|
||||
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);
|
||||
|
||||
Packets.send(new LoginPacket(new byte[8]), this::send);
|
||||
}
|
||||
|
||||
@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) { }
|
||||
}
|
|
@ -2,12 +2,14 @@ package eu.m724.autopeerer.client;
|
|||
|
||||
import eu.m724.autopeerer.client.bird.BirdLive;
|
||||
import eu.m724.autopeerer.client.bird.BirdSession;
|
||||
import eu.m724.autopeerer.client.connectivity.Connectivity;
|
||||
import eu.m724.autopeerer.client.wireguard.WireGuardKeys;
|
||||
import eu.m724.autopeerer.client.wireguard.WireGuardLive;
|
||||
import eu.m724.autopeerer.client.wireguard.WireGuardSession;
|
||||
import eu.m724.autopeerer.common.AddressTools;
|
||||
import eu.m724.autopeerer.common.packet.Packet;
|
||||
import eu.m724.autopeerer.common.packet.Packets;
|
||||
import eu.m724.autopeerer.common.packet.s2c.LoginResponsePacket;
|
||||
import eu.m724.autopeerer.common.packet.s2c.PingRequestPacket;
|
||||
import eu.m724.autopeerer.common.packet.s2c.SessionRequestPacket;
|
||||
import eu.m724.autopeerer.common.packet.c2s.PingResponsePacket;
|
||||
|
@ -15,6 +17,8 @@ import eu.m724.autopeerer.common.packet.c2s.SessionResponsePacket;
|
|||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
@ -22,22 +26,22 @@ import java.nio.file.FileAlreadyExistsException;
|
|||
import java.util.Base64;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class PacketHandler {
|
||||
Consumer<ByteBuffer> sender;
|
||||
OutputStream outputStream;
|
||||
private boolean loggedIn;
|
||||
|
||||
private InetAddress linkLocal;
|
||||
|
||||
private final WireGuardLive wireGuardLive;
|
||||
private final BirdLive birdLive;
|
||||
private final String serverLinkLocal;
|
||||
|
||||
public PacketHandler(WireGuardLive wireGuardLive, BirdLive birdLive, String serverLinkLocal) {
|
||||
public PacketHandler(WireGuardLive wireGuardLive, BirdLive birdLive) {
|
||||
this.wireGuardLive = wireGuardLive;
|
||||
this.birdLive = birdLive;
|
||||
this.serverLinkLocal = serverLinkLocal;
|
||||
}
|
||||
|
||||
void handle(ByteBuffer bytes) {
|
||||
void handle(ByteBuffer bytes) throws IOException {
|
||||
Packet<?> p;
|
||||
try {
|
||||
p = Packets.parseClient(bytes);
|
||||
|
@ -55,10 +59,18 @@ public class PacketHandler {
|
|||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
if (p instanceof PingRequestPacket packet) {
|
||||
handlePingRequest(packet);
|
||||
} else if (p instanceof SessionRequestPacket packet) {
|
||||
handleSessionRequest(packet);
|
||||
if (loggedIn) {
|
||||
if (p instanceof PingRequestPacket packet) {
|
||||
handlePingRequest(packet);
|
||||
} else if (p instanceof SessionRequestPacket packet) {
|
||||
handleSessionRequest(packet);
|
||||
}
|
||||
} else {
|
||||
if (p instanceof LoginResponsePacket packet) {
|
||||
this.linkLocal = packet.linkLocal;
|
||||
System.out.println("Logged in as " + packet.nodeId);
|
||||
loggedIn = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,32 +99,33 @@ public class PacketHandler {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
System.out.printf("Ping request #%d to %s - %s avg %.3f / mdev %.3f ms\n", packet.requestId, packet.target.getHostAddress(), status, average, meanDeviation);
|
||||
Packets.send(new PingResponsePacket(packet.requestId, status, average, meanDeviation), outputStream);
|
||||
} catch (IOException e) {
|
||||
System.err.println("Error pinging");
|
||||
System.err.println("Error executing ping request");
|
||||
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);
|
||||
Packets.send(new PingResponsePacket(packet.requestId, status, average, meanDeviation), sender);
|
||||
});
|
||||
}
|
||||
|
||||
private void handleSessionRequest(SessionRequestPacket packet) {
|
||||
private void handleSessionRequest(SessionRequestPacket packet) throws IOException {
|
||||
// validate endpoint
|
||||
var resolved = false;
|
||||
try {
|
||||
if (ClientPrefs.ipv6Supported()) {
|
||||
if (Connectivity.ipv6()) {
|
||||
var res = AddressTools.resolve(packet.endpointHost, true);
|
||||
resolved = res != null;
|
||||
}
|
||||
if (!resolved && ClientPrefs.ipv4Supported()) {
|
||||
if (!resolved && Connectivity.ipv4()) {
|
||||
var res = AddressTools.resolve(packet.endpointHost, true);
|
||||
resolved = res != null;
|
||||
}
|
||||
} catch (UnknownHostException | AddressTools.MultipleRecordsException ignored) { }
|
||||
|
||||
if (!resolved) {
|
||||
Packets.send(new SessionResponsePacket(packet.asn, SessionResponsePacket.SessionResult.ERROR_RESOLVE, -1, null), sender);
|
||||
Packets.send(new SessionResponsePacket(packet.asn, SessionResponsePacket.SessionResult.ERROR_RESOLVE, -1, null), outputStream);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -124,22 +137,43 @@ public class PacketHandler {
|
|||
port = (int) (packet.asn % 10000);
|
||||
}
|
||||
|
||||
var wireGuardSession = new WireGuardSession(port, privateKey, serverLinkLocal, packet.linkLocal.getHostAddress(), packet.endpointHost + ":" + packet.endpointPort, packet.publicKey);
|
||||
var birdSession = new BirdSession(packet.asn, packet.linkLocal.getHostAddress());
|
||||
var wireGuardSession = new WireGuardSession(
|
||||
port,
|
||||
privateKey,
|
||||
linkLocal.getHostAddress(),
|
||||
packet.linkLocal.getHostAddress(),
|
||||
packet.endpointHost + ":" + packet.endpointPort,
|
||||
packet.publicKey
|
||||
);
|
||||
|
||||
var birdSession = new BirdSession(
|
||||
packet.asn,
|
||||
packet.linkLocal.getHostAddress()
|
||||
);
|
||||
|
||||
try {
|
||||
wireGuardLive.saveSession(packet.asn, wireGuardSession);
|
||||
birdLive.saveSession(birdSession);
|
||||
|
||||
System.out.printf("Created session AS%d to %s\n", packet.asn, packet.endpointHost);
|
||||
Packets.send(new SessionResponsePacket(packet.asn, SessionResponsePacket.SessionResult.OK, wireGuardSession.listenPort(), publicKey), sender);
|
||||
Packets.send(new SessionResponsePacket(packet.asn, SessionResponsePacket.SessionResult.OK, wireGuardSession.listenPort(), publicKey), outputStream);
|
||||
} catch (FileAlreadyExistsException e) {
|
||||
System.err.println("Tried to create a session which already exists: AS" + packet.asn);
|
||||
Packets.send(new SessionResponsePacket(packet.asn, SessionResponsePacket.SessionResult.ERROR_DUPLICATE, -1, null), sender);
|
||||
Packets.send(new SessionResponsePacket(packet.asn, SessionResponsePacket.SessionResult.ERROR_DUPLICATE, -1, null), outputStream);
|
||||
} catch (IOException e) {
|
||||
Packets.send(new SessionResponsePacket(packet.asn, SessionResponsePacket.SessionResult.ERROR_OTHER, -1, null), sender);
|
||||
System.err.println("Failed to save session");
|
||||
throw new RuntimeException(e);
|
||||
Packets.send(new SessionResponsePacket(packet.asn, SessionResponsePacket.SessionResult.ERROR_OTHER, -1, null), outputStream);
|
||||
|
||||
var ex = new RuntimeException("Failed to save session", e);
|
||||
|
||||
// clean up
|
||||
try {
|
||||
wireGuardLive.removeSession(packet.asn);
|
||||
birdLive.removeSession(packet.asn);
|
||||
} catch (Exception e1) {
|
||||
ex = new RuntimeException("Failed to clean up after failing to save session", ex);
|
||||
}
|
||||
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,11 @@ public class BirdLive {
|
|||
Files.writeString(file.toPath(), session.config(), StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE);
|
||||
}
|
||||
|
||||
public void removeSession(long asn) throws IOException {
|
||||
File file = new File(configsPath, "ap_" + asn + ".conf");
|
||||
Files.delete(file.toPath());
|
||||
}
|
||||
|
||||
public BirdSession getSession(long asn) throws IOException {
|
||||
File file = new File(configsPath, "ap_" + asn + ".conf");
|
||||
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package eu.m724.autopeerer.client.connectivity;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class Connectivity {
|
||||
private static boolean ipv4, ipv6;
|
||||
|
||||
public static boolean ipv4() {
|
||||
return ipv4;
|
||||
}
|
||||
|
||||
public static boolean ipv6() {
|
||||
return ipv6;
|
||||
}
|
||||
|
||||
public static void check() {
|
||||
var client = HttpClient.newHttpClient();
|
||||
|
||||
var future4 = composeRequest(client, false);
|
||||
var future6 = composeRequest(client, true);
|
||||
|
||||
ipv4 = future4.join();
|
||||
ipv6 = future6.join();
|
||||
}
|
||||
|
||||
private static CompletableFuture<Boolean> composeRequest(HttpClient client, boolean ipv6) {
|
||||
var request = HttpRequest
|
||||
.newBuilder(URI.create("https://ipv%d.google.com/generate_204".formatted(ipv6 ? 6 : 4)))
|
||||
.timeout(Duration.ofSeconds(5))
|
||||
.build();
|
||||
|
||||
return client.sendAsync(request, HttpResponse.BodyHandlers.discarding()).handle((r, ex) -> ex == null);
|
||||
}
|
||||
}
|
|
@ -17,6 +17,11 @@ public class WireGuardLive {
|
|||
Files.writeString(file.toPath(), session.config(), StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE);
|
||||
}
|
||||
|
||||
public void removeSession(long asn) throws IOException {
|
||||
File file = new File(configsPath, "ap_" + asn + ".conf");
|
||||
Files.delete(file.toPath());
|
||||
}
|
||||
|
||||
public WireGuardSession getSession(long asn) throws IOException {
|
||||
File file = new File(configsPath, "ap_" + asn + ".conf");
|
||||
|
||||
|
|
|
@ -17,10 +17,10 @@ public class AddressTools {
|
|||
* @return whether it's IPv6 and link local
|
||||
*/
|
||||
public static boolean isLinkLocal(InetAddress address) {
|
||||
if (isIp(address, true)) return false;
|
||||
if (!isIp(address, true)) return false;
|
||||
var bytes = address.getAddress();
|
||||
|
||||
return bytes[0] == -2 && bytes[1] >= 0 && bytes[1] <= 63;
|
||||
return bytes[0] == -2 && bytes[1] <= -65;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
14
src/main/java/eu/m724/autopeerer/common/NodeProfile.java
Normal file
14
src/main/java/eu/m724/autopeerer/common/NodeProfile.java
Normal file
|
@ -0,0 +1,14 @@
|
|||
package eu.m724.autopeerer.common;
|
||||
|
||||
import java.net.Inet6Address;
|
||||
|
||||
public record NodeProfile(
|
||||
String label,
|
||||
String hostname,
|
||||
Inet6Address linkLocal,
|
||||
boolean supportsIpv4,
|
||||
boolean supportsIpv6,
|
||||
boolean restrictedIpv4,
|
||||
boolean restrictedIpv6
|
||||
) {
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package eu.m724.autopeerer.common.packet;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public interface PacketReaderImpl {
|
||||
void onPacket(ByteBuffer byteBuffer);
|
||||
void onError(Exception exception);
|
||||
void onClose();
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package eu.m724.autopeerer.common.packet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class PacketReaderRunnable implements Runnable {
|
||||
private final Socket socket;
|
||||
private final PacketReaderImpl impl;
|
||||
|
||||
public PacketReaderRunnable(Socket socket, PacketReaderImpl impl) {
|
||||
this.socket = socket;
|
||||
this.impl = impl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
while (socket.isConnected()) {
|
||||
loop();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
impl.onError(e);
|
||||
}
|
||||
|
||||
impl.onClose();
|
||||
}
|
||||
|
||||
private void loop() throws IOException {
|
||||
var is = socket.getInputStream();
|
||||
|
||||
var bs = is.readNBytes(2);
|
||||
var length = bs[0] << 8 | bs[1];
|
||||
|
||||
var buffer = ByteBuffer.wrap(is.readNBytes(length)); // packets are small
|
||||
impl.onPacket(buffer);
|
||||
}
|
||||
}
|
|
@ -7,12 +7,14 @@ import eu.m724.autopeerer.common.packet.s2c.LoginResponsePacket;
|
|||
import eu.m724.autopeerer.common.packet.c2s.PingResponsePacket;
|
||||
import eu.m724.autopeerer.common.packet.c2s.SessionResponsePacket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class Packets {
|
||||
public static Packet<?> parseClient(ByteBuffer buffer) throws Exception {
|
||||
byte id = buffer.get();
|
||||
var id = buffer.get();
|
||||
|
||||
Packet<?> packet = null;
|
||||
|
||||
|
@ -28,7 +30,7 @@ public class Packets {
|
|||
}
|
||||
|
||||
public static Packet<?> parseServer(ByteBuffer buffer) throws Exception {
|
||||
byte id = buffer.get();
|
||||
var id = buffer.get();
|
||||
|
||||
Packet<?> packet = null;
|
||||
|
||||
|
@ -47,7 +49,10 @@ public class Packets {
|
|||
ByteBuffer packetBuffer = packet.serialize();
|
||||
packetBuffer.rewind();
|
||||
|
||||
var bb = ByteBuffer.allocate(1 + packetBuffer.remaining());
|
||||
var packetLength = 1 + packetBuffer.remaining();
|
||||
|
||||
var bb = ByteBuffer.allocate(2 + packetLength);
|
||||
bb.putShort((short) packetLength);
|
||||
bb.put(packet.getId());
|
||||
bb.put(packetBuffer);
|
||||
bb.rewind();
|
||||
|
@ -59,4 +64,8 @@ public class Packets {
|
|||
sender.accept(compose(packet));
|
||||
}
|
||||
|
||||
public static void send(Packet<?> packet, OutputStream outputStream) throws IOException {
|
||||
outputStream.write(compose(packet).array());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
package eu.m724.autopeerer.common.packet.c2s;
|
||||
|
||||
import eu.m724.autopeerer.common.NodeProfile;
|
||||
import eu.m724.autopeerer.common.packet.Packet;
|
||||
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class LoginPacket implements Packet<LoginPacket> {
|
||||
|
@ -21,6 +25,7 @@ public class LoginPacket implements Packet<LoginPacket> {
|
|||
public ByteBuffer serialize() {
|
||||
var buffer = ByteBuffer.allocate(8);
|
||||
buffer.put(key);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +1,20 @@
|
|||
package eu.m724.autopeerer.common.packet.s2c;
|
||||
|
||||
import eu.m724.autopeerer.common.AddressTools;
|
||||
import eu.m724.autopeerer.common.packet.Packet;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class LoginResponsePacket implements Packet<LoginResponsePacket> {
|
||||
public final String nodeId;
|
||||
public final InetAddress linkLocal;
|
||||
|
||||
public LoginResponsePacket(String nodeId) {
|
||||
public LoginResponsePacket(String nodeId, InetAddress linkLocal) {
|
||||
this.nodeId = nodeId;
|
||||
this.linkLocal = linkLocal;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -20,9 +25,13 @@ public class LoginResponsePacket implements Packet<LoginResponsePacket> {
|
|||
@Override
|
||||
public ByteBuffer serialize() {
|
||||
var nodeIdEncoded = nodeId.getBytes(StandardCharsets.UTF_8);
|
||||
var buffer = ByteBuffer.allocate(1 + nodeIdEncoded.length);
|
||||
var buffer = ByteBuffer.allocate(1 + nodeIdEncoded.length + 16);
|
||||
|
||||
buffer.put((byte) nodeIdEncoded.length);
|
||||
buffer.put(nodeIdEncoded);
|
||||
|
||||
buffer.put(linkLocal.getAddress());
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
@ -31,6 +40,20 @@ public class LoginResponsePacket implements Packet<LoginResponsePacket> {
|
|||
var nodeIdEncoded = new byte[size];
|
||||
buffer.get(nodeIdEncoded);
|
||||
|
||||
return new LoginResponsePacket(new String(nodeIdEncoded, StandardCharsets.UTF_8));
|
||||
var ll = new byte[16];
|
||||
buffer.get(ll);
|
||||
InetAddress linkLocal;
|
||||
try {
|
||||
linkLocal = InetAddress.getByAddress(ll);
|
||||
} catch (UnknownHostException e) {
|
||||
linkLocal = null;
|
||||
}
|
||||
|
||||
assert AddressTools.isLinkLocal(linkLocal);
|
||||
|
||||
return new LoginResponsePacket(
|
||||
new String(nodeIdEncoded, StandardCharsets.UTF_8),
|
||||
linkLocal
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,67 +4,37 @@ import eu.m724.autopeerer.common.packet.Packet;
|
|||
import eu.m724.autopeerer.common.packet.Packets;
|
||||
import eu.m724.autopeerer.common.packet.c2s.PingResponsePacket;
|
||||
import eu.m724.autopeerer.common.packet.c2s.SessionResponsePacket;
|
||||
import eu.m724.autopeerer.common.packet.s2c.PingRequestPacket;
|
||||
import eu.m724.autopeerer.common.packet.s2c.SessionRequestPacket;
|
||||
import org.java_websocket.WebSocket;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class ClientState {
|
||||
public boolean authenticated = false;
|
||||
public final int clientId;
|
||||
public final WebSocket socket;
|
||||
public final Socket socket;
|
||||
Node node;
|
||||
|
||||
private final Consumer<ByteBuffer> sender;
|
||||
|
||||
public ClientState(int clientId, WebSocket socket) {
|
||||
public ClientState(int clientId, Socket socket) {
|
||||
this.clientId = clientId;
|
||||
this.socket = socket;
|
||||
this.sender = socket::send;
|
||||
}
|
||||
|
||||
void send(Packet<?> packet) {
|
||||
Packets.send(packet, sender);
|
||||
void send(Packet<?> packet) throws IOException {
|
||||
Packets.send(packet, socket.getOutputStream());
|
||||
}
|
||||
|
||||
void end() {
|
||||
void end() throws IOException {
|
||||
socket.close();
|
||||
}
|
||||
|
||||
CompletableFuture<PingResponsePacket> ping(InetAddress host) {
|
||||
var future = new CompletableFuture<PingResponsePacket>();
|
||||
|
||||
var id = (short) (ThreadLocalRandom.current().nextInt() & 0xFFFF);
|
||||
|
||||
pingConsumers.put(id, future::complete);
|
||||
send(new PingRequestPacket(id, host));
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
CompletableFuture<SessionResponsePacket> session(long asn, InetAddress linkLocal, String publicKey, String endpointHost, int endpointPort) {
|
||||
var future = new CompletableFuture<SessionResponsePacket>();
|
||||
|
||||
sessionConsumers.put(asn, future::complete);
|
||||
send(new SessionRequestPacket(
|
||||
asn, linkLocal, publicKey, endpointHost, endpointPort
|
||||
));
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
|
||||
/* Packet functions */
|
||||
|
||||
private final Map<Short, Consumer<PingResponsePacket>> pingConsumers = new HashMap<>();
|
||||
private final Map<Long, Consumer<SessionResponsePacket>> sessionConsumers = new HashMap<>();
|
||||
final Map<Short, Consumer<PingResponsePacket>> pingConsumers = new HashMap<>();
|
||||
final Map<Long, Consumer<SessionResponsePacket>> sessionConsumers = new HashMap<>();
|
||||
|
||||
void onPacketReceived(Packet<?> p) {
|
||||
if (p instanceof PingResponsePacket packet) {
|
||||
|
|
|
@ -31,7 +31,7 @@ public class Main {
|
|||
|
||||
var packetHandler = new PacketHandler(nodes);
|
||||
|
||||
var server = new MyWebsocketServer(
|
||||
var server = new MyTcpServer(
|
||||
new InetSocketAddress(config.getString("socket.address"), config.getInt("socket.port")),
|
||||
packetHandler
|
||||
);
|
||||
|
|
|
@ -53,10 +53,14 @@ public class MyHttpHandler implements HttpHandler {
|
|||
|
||||
var json = new JSONObject();
|
||||
nodes.forEach(node -> {
|
||||
var prof = node.getNodeProfile();
|
||||
var val = new JSONObject()
|
||||
.put("name", node.name())
|
||||
.put("host", node.host())
|
||||
.put("online", node.connected());
|
||||
.put("label", node.getNodeProfile().label())
|
||||
.put("host", node.getNodeProfile().hostname())
|
||||
.put("linkLocal", node.getNodeProfile().linkLocal().getHostAddress())
|
||||
.put("ipv4", prof.supportsIpv4() ? (prof.restrictedIpv4() ? "restricted" : true) : false)
|
||||
.put("ipv6", prof.supportsIpv6() ? (prof.restrictedIpv6() ? "restricted" : true) : false)
|
||||
.put("online", node.isConnected());
|
||||
json.put(node.id(), val);
|
||||
});
|
||||
|
||||
|
@ -88,7 +92,7 @@ public class MyHttpHandler implements HttpHandler {
|
|||
var futures = new HashSet<CompletableFuture<Void>>();
|
||||
|
||||
for (Node node : selectedNodes) {
|
||||
if (!node.connected()) { // node is offline
|
||||
if (!node.isConnected()) { // node is offline
|
||||
var response = new JSONObject()
|
||||
.put("node", node.id())
|
||||
.put("status", "OFFLINE");
|
||||
|
@ -96,7 +100,7 @@ public class MyHttpHandler implements HttpHandler {
|
|||
continue;
|
||||
}
|
||||
|
||||
var future = node.getClient().ping(target).handle((result, ex) -> {
|
||||
var future = node.ping(target).handle((result, ex) -> {
|
||||
try {
|
||||
if (ex != null) {
|
||||
sendResponse(exchange, 500);
|
||||
|
@ -160,7 +164,7 @@ public class MyHttpHandler implements HttpHandler {
|
|||
CompletableFuture<SessionResponsePacket> future = null;
|
||||
|
||||
try {
|
||||
future = node.getClient().session(
|
||||
future = node.session(
|
||||
json.getLong("asn"),
|
||||
InetAddress.getByName(json.getString("linkLocal")),
|
||||
json.getString("publicKey"),
|
||||
|
|
84
src/main/java/eu/m724/autopeerer/server/MyTcpServer.java
Normal file
84
src/main/java/eu/m724/autopeerer/server/MyTcpServer.java
Normal file
|
@ -0,0 +1,84 @@
|
|||
package eu.m724.autopeerer.server;
|
||||
|
||||
import eu.m724.autopeerer.common.packet.PacketReaderImpl;
|
||||
import eu.m724.autopeerer.common.packet.PacketReaderRunnable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class MyTcpServer {
|
||||
private final InetSocketAddress address;
|
||||
private final PacketHandler handler;
|
||||
|
||||
private ServerSocket socket;
|
||||
private int id = 0;
|
||||
|
||||
private final Map<Integer, ClientState> states = new HashMap<>();
|
||||
|
||||
public MyTcpServer(InetSocketAddress address, PacketHandler packetHandler) throws IOException {
|
||||
this.address = address;
|
||||
this.handler = packetHandler;
|
||||
}
|
||||
|
||||
public void start() throws IOException {
|
||||
this.socket = new ServerSocket(address.getPort(), 50, address.getAddress());
|
||||
System.out.printf("TCP server started on %s:%d\n", address.getAddress().getHostAddress(), address.getPort());
|
||||
|
||||
Executors.newSingleThreadExecutor().execute(() -> {
|
||||
try {
|
||||
loop();
|
||||
} catch (IOException e) {
|
||||
System.err.println("Error in TCP loop");
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void loop() throws IOException {
|
||||
while (!socket.isClosed()) {
|
||||
Socket client = socket.accept();
|
||||
var id = ++this.id;
|
||||
|
||||
var state = new ClientState(id, client);
|
||||
states.put(id, state);
|
||||
System.out.printf("[%d] Connected: %s\n", id, client.getRemoteSocketAddress());
|
||||
|
||||
Executors.newSingleThreadExecutor().execute(
|
||||
new PacketReaderRunnable(client, new PacketReaderImpl() {
|
||||
@Override
|
||||
public void onPacket(ByteBuffer byteBuffer) {
|
||||
try {
|
||||
handler.handle(state, byteBuffer);
|
||||
} catch (IOException e) {
|
||||
System.err.println("Error handling packet");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception exception) {
|
||||
// TODO
|
||||
System.err.printf("[%d] Error\n", state.clientId);
|
||||
exception.printStackTrace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose() {
|
||||
var state = states.remove(id);
|
||||
state.node.setClient(null);
|
||||
var id = state.authenticated ? state.node.id() : client.getRemoteSocketAddress();
|
||||
System.out.printf("[%d] Disconnected: %s\n", state.clientId, id);
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
this.socket.close();
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
package eu.m724.autopeerer.server;
|
||||
|
||||
import org.java_websocket.WebSocket;
|
||||
import org.java_websocket.handshake.ClientHandshake;
|
||||
import org.java_websocket.server.WebSocketServer;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class MyWebsocketServer extends WebSocketServer {
|
||||
private final PacketHandler packetHandler;
|
||||
|
||||
private final Map<WebSocket, ClientState> states = new HashMap<>();
|
||||
|
||||
private int id = 0;
|
||||
|
||||
public MyWebsocketServer(InetSocketAddress address, PacketHandler packetHandler) {
|
||||
super(address);
|
||||
this.setReuseAddr(true);
|
||||
|
||||
this.packetHandler = packetHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(WebSocket conn, ClientHandshake handshake) {
|
||||
var state = new ClientState(++id, conn);
|
||||
states.put(conn, state);
|
||||
System.out.printf("[%d] Connected: %s\n", id, conn.getRemoteSocketAddress().getHostString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(WebSocket conn, int code, String reason, boolean remote) {
|
||||
var state = states.remove(conn);
|
||||
state.node.setClient(null);
|
||||
var id = state.authenticated ? state.node.id() : conn.getRemoteSocketAddress().getHostString();
|
||||
System.out.printf("[%d] Disconnected: %s\n", state.clientId, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(WebSocket conn, ByteBuffer message) {
|
||||
packetHandler.handle(states.get(conn), message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(WebSocket conn, Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
System.out.printf("Websocket server started on %s:%d\n", getAddress().getHostString(), getPort());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(WebSocket conn, String message) {
|
||||
}
|
||||
}
|
|
@ -1,54 +1,80 @@
|
|||
package eu.m724.autopeerer.server;
|
||||
|
||||
import eu.m724.autopeerer.common.AddressTools;
|
||||
import eu.m724.autopeerer.common.NodeProfile;
|
||||
import eu.m724.autopeerer.common.packet.Packet;
|
||||
import eu.m724.autopeerer.common.packet.Packets;
|
||||
import eu.m724.autopeerer.common.packet.c2s.PingResponsePacket;
|
||||
import eu.m724.autopeerer.common.packet.c2s.SessionResponsePacket;
|
||||
import eu.m724.autopeerer.common.packet.s2c.PingRequestPacket;
|
||||
import eu.m724.autopeerer.common.packet.s2c.SessionRequestPacket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Base64;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public final class Node {
|
||||
private final String id;
|
||||
private final byte[] key;
|
||||
private final String name;
|
||||
private final String host;
|
||||
|
||||
private final NodeProfile nodeProfile;
|
||||
|
||||
private ClientState client;
|
||||
|
||||
public Node(
|
||||
String id,
|
||||
byte[] key,
|
||||
String name,
|
||||
String host
|
||||
NodeProfile nodeProfile
|
||||
) {
|
||||
this.id = id;
|
||||
this.key = key;
|
||||
this.name = name;
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
void setClient(ClientState client) {
|
||||
this.client = client;
|
||||
this.nodeProfile = nodeProfile;
|
||||
}
|
||||
|
||||
ClientState getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
boolean connected() {
|
||||
NodeProfile getNodeProfile() {
|
||||
return nodeProfile;
|
||||
}
|
||||
|
||||
void setClient(ClientState client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
boolean isConnected() {
|
||||
return client != null;
|
||||
}
|
||||
|
||||
void send(Packet<?> packet) {
|
||||
void send(Packet<?> packet) throws IOException {
|
||||
client.send(packet);
|
||||
}
|
||||
|
||||
static Node fromProperties(String id, Properties properties) {
|
||||
static Node fromProperties(String id, Properties properties) throws UnknownHostException {
|
||||
var ipv4 = properties.getProperty("stack.ipv4");
|
||||
var ipv6 = properties.getProperty("stack.ipv6");
|
||||
|
||||
Inet6Address linkLocal = (Inet6Address) InetAddress.getByName(properties.getProperty("link-local"));
|
||||
if (!AddressTools.isLinkLocal(linkLocal)) throw new UnknownHostException();
|
||||
|
||||
return new Node(
|
||||
id,
|
||||
Base64.getDecoder().decode(properties.getProperty("key")),
|
||||
properties.getProperty("name"),
|
||||
properties.getProperty("host")
|
||||
new NodeProfile(
|
||||
properties.getProperty("label"),
|
||||
properties.getProperty("hostname"),
|
||||
linkLocal,
|
||||
ipv4.equalsIgnoreCase("yes") || ipv4.equalsIgnoreCase("restricted"),
|
||||
ipv4.equalsIgnoreCase("restricted"),
|
||||
ipv6.equalsIgnoreCase("yes") || ipv6.equalsIgnoreCase("restricted"),
|
||||
ipv6.equalsIgnoreCase("restricted")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -60,37 +86,48 @@ public final class Node {
|
|||
return key;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String host() {
|
||||
return host;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
if (obj == null || obj.getClass() != this.getClass()) return false;
|
||||
var that = (Node) obj;
|
||||
return Objects.equals(this.id, that.id) &&
|
||||
Objects.equals(this.key, that.key) &&
|
||||
Objects.equals(this.name, that.name) &&
|
||||
Objects.equals(this.host, that.host);
|
||||
Objects.equals(this.key, that.key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, key, name, host);
|
||||
return Objects.hash(id, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Node[" +
|
||||
"id=" + id + ", " +
|
||||
"key=" + key + ", " +
|
||||
"name=" + name + ", " +
|
||||
"host=" + host + ']';
|
||||
return "Node[id=" + id + "]";
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
|
||||
CompletableFuture<PingResponsePacket> ping(InetAddress host) throws IOException {
|
||||
var future = new CompletableFuture<PingResponsePacket>();
|
||||
|
||||
var id = (short) (ThreadLocalRandom.current().nextInt() & 0xFFFF);
|
||||
|
||||
client.pingConsumers.put(id, future::complete);
|
||||
send(new PingRequestPacket(id, host));
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
CompletableFuture<SessionResponsePacket> session(long asn, InetAddress linkLocal, String publicKey, String endpointHost, int endpointPort) throws IOException {
|
||||
var future = new CompletableFuture<SessionResponsePacket>();
|
||||
|
||||
client.sessionConsumers.put(asn, future::complete);
|
||||
send(new SessionRequestPacket(
|
||||
asn, linkLocal, publicKey, endpointHost, endpointPort
|
||||
));
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,7 +5,9 @@ import eu.m724.autopeerer.common.packet.Packets;
|
|||
import eu.m724.autopeerer.common.packet.c2s.LoginPacket;
|
||||
import eu.m724.autopeerer.common.packet.c2s.PingResponsePacket;
|
||||
import eu.m724.autopeerer.common.packet.c2s.SessionResponsePacket;
|
||||
import eu.m724.autopeerer.common.packet.s2c.LoginResponsePacket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.*;
|
||||
|
@ -17,7 +19,7 @@ public class PacketHandler {
|
|||
nodes.forEach(n -> this.nodes.put(n, null));
|
||||
}
|
||||
|
||||
void handle(ClientState state, ByteBuffer bytes) {
|
||||
void handle(ClientState state, ByteBuffer bytes) throws IOException {
|
||||
// TODO this is not safe but enough for now
|
||||
Packet<?> p;
|
||||
try {
|
||||
|
@ -60,22 +62,24 @@ public class PacketHandler {
|
|||
.ifPresent(e -> nodes.remove(e.getKey()));
|
||||
}
|
||||
|
||||
private void handleLogin(ClientState state, LoginPacket packet) {
|
||||
private void handleLogin(ClientState state, LoginPacket packet) throws IOException {
|
||||
var node = nodes.entrySet().stream().filter(e -> Arrays.equals(e.getKey().key(), packet.key)).findFirst().orElse(null);
|
||||
if (node != null) {
|
||||
if (node.getValue() != null) {
|
||||
if (node.getValue().socket.isOpen()) { // if there WAS a connection
|
||||
if (node.getValue().socket.isConnected()) { // if there WAS a connection
|
||||
System.out.printf("[%d] Tried to log in as %s, but is already logged in\n", state.clientId, node.getKey().id());
|
||||
state.end();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
System.out.printf("[%d] Logged in as %s\n", state.clientId, node.getKey().id());
|
||||
nodes.put(node.getKey(), state);
|
||||
node.getKey().setClient(state);
|
||||
state.authenticated = true;
|
||||
state.node = node.getKey();
|
||||
|
||||
System.out.printf("[%d] Logged in as %s\n", state.clientId, node.getKey().id());
|
||||
state.send(new LoginResponsePacket(node.getKey().id(), node.getKey().getNodeProfile().linkLocal()));
|
||||
} else {
|
||||
System.out.printf("[%d] Tried to log in with invalid key\n", state.clientId);
|
||||
state.end();
|
||||
|
|
|
@ -7,6 +7,7 @@ import java.io.FileInputStream;
|
|||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashSet;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
@ -21,9 +22,9 @@ public class ServerConfiguration extends Configuration {
|
|||
|
||||
if (!nd.exists()) {
|
||||
nd.mkdir();
|
||||
var f = new File(nd, "node1.properties");
|
||||
try (var is = getClass().getClassLoader().getResourceAsStream(f.getName())) {
|
||||
Files.write(f.toPath(), is.readAllBytes());
|
||||
|
||||
try (var is = getClass().getClassLoader().getResourceAsStream("nodes/node1.properties")) {
|
||||
Files.write(Path.of(nd.getPath(),"node1.properties"), is.readAllBytes());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
# The server websocket
|
||||
remote=ws://127.0.0.1:8002
|
||||
remote=127.0.0.1:8002
|
||||
key=AAAAAAAAAAA=
|
||||
|
||||
# Where are WG and BIRD configs located
|
||||
wireguard.directory=config/wg
|
||||
bird.directory=config/bird
|
||||
|
||||
# Link local used for peering
|
||||
link-local=fe80::129:0
|
||||
# Is IPv4 available? Yes, no, restricted
|
||||
stack.ipv4=yes
|
||||
# Is IPv6 available? Yes, no, restricted
|
||||
stack.ipv6=yes
|
||||
# Other stuff is configured on the server
|
|
@ -1,3 +1,10 @@
|
|||
key=AAAAAAAAAAA=
|
||||
name="Node Number One"
|
||||
host=example.com
|
||||
label="Node Number One"
|
||||
# The hostname used as WireGuard endpoint
|
||||
hostname=example.com
|
||||
# Link local used for peering
|
||||
link-local=fe80::129:0
|
||||
# Is IPv4 available? Yes, no, restricted
|
||||
stack.ipv4=yes
|
||||
# Is IPv6 available? Yes, no, restricted
|
||||
stack.ipv6=yes
|
Loading…
Reference in a new issue