Rewritten NetworkSystem
This commit is contained in:
@@ -19,14 +19,16 @@ public class CreditCard {
|
||||
private final Random random;
|
||||
|
||||
public CreditCard(CardBrand cardBrand) {
|
||||
this.cardBrand = cardBrand;
|
||||
this.random = new Random();
|
||||
this.cardNumber = generateCardNumber();
|
||||
this(cardBrand, new Random());
|
||||
}
|
||||
|
||||
public CreditCard(CardBrand cardBrand, int seed) {
|
||||
this(cardBrand, new Random(seed));
|
||||
}
|
||||
|
||||
public CreditCard(CardBrand cardBrand, Random random) {
|
||||
this.cardBrand = cardBrand;
|
||||
this.random = new Random(seed);
|
||||
this.random = random;
|
||||
this.cardNumber = generateCardNumber();
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,52 +6,61 @@
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.client.events.packets.receive;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.client.NetworkClient;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.Packet;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.Transport;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.NetworkProtocol;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Fired when a packet was received by the client on a specific transport.
|
||||
* Fired when a packet was received by the client on a specific protocol.
|
||||
*/
|
||||
public final class C_PacketReceivedEvent extends Event {
|
||||
|
||||
private final NetworkClient networkClient;
|
||||
private final NetworkClient client;
|
||||
private final Packet packet;
|
||||
private final Transport transport;
|
||||
private final NetworkProtocol protocol;
|
||||
|
||||
/**
|
||||
* Creates a new packet received event.
|
||||
*
|
||||
* @param networkClient client instance
|
||||
* @param packet received packet
|
||||
* @param transport transport the packet was received on
|
||||
* @param client client instance
|
||||
* @param packet received packet
|
||||
* @param protocol protocol the packet was received on
|
||||
*/
|
||||
public C_PacketReceivedEvent(NetworkClient networkClient, Packet packet, Transport transport) {
|
||||
this.networkClient = networkClient;
|
||||
this.packet = packet;
|
||||
this.transport = transport;
|
||||
public C_PacketReceivedEvent(NetworkClient client, Packet packet, NetworkProtocol protocol) {
|
||||
this.client = Objects.requireNonNull(client, "client");
|
||||
this.packet = Objects.requireNonNull(packet, "packet");
|
||||
this.protocol = Objects.requireNonNull(protocol, "protocol");
|
||||
}
|
||||
|
||||
public NetworkClient getNetworkClient() {
|
||||
return networkClient;
|
||||
/**
|
||||
* Returns the client instance.
|
||||
*
|
||||
* @return client
|
||||
*/
|
||||
public NetworkClient getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the received packet.
|
||||
*
|
||||
* @return packet
|
||||
*/
|
||||
public Packet getPacket() {
|
||||
return packet;
|
||||
}
|
||||
|
||||
public Transport getTransport() {
|
||||
return transport;
|
||||
/**
|
||||
* Returns the protocol the packet was received on.
|
||||
*
|
||||
* @return protocol
|
||||
*/
|
||||
public NetworkProtocol getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,52 +6,79 @@
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.client.events.packets.receive;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.client.NetworkClient;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.Packet;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.Transport;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.NetworkProtocol;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Fired when a packet receive failed on the client on a specific transport.
|
||||
* Fired when receiving or decoding a packet failed on the client
|
||||
* for a specific protocol.
|
||||
*/
|
||||
public final class C_PacketReceivedFailedEvent extends Event {
|
||||
|
||||
private final NetworkClient networkClient;
|
||||
private final NetworkClient client;
|
||||
private final Packet packet;
|
||||
private final Transport transport;
|
||||
private final NetworkProtocol protocol;
|
||||
private final Exception error;
|
||||
|
||||
/**
|
||||
* Creates a new packet receive failed event.
|
||||
*
|
||||
* @param networkClient client instance
|
||||
* @param packet packet that failed to be read/handled
|
||||
* @param transport transport the packet was received on
|
||||
* @param client client instance
|
||||
* @param packet packet that failed to be processed (may be null if undecodable)
|
||||
* @param protocol protocol the failure happened on
|
||||
* @param error root cause
|
||||
*/
|
||||
public C_PacketReceivedFailedEvent(NetworkClient networkClient, Packet packet, Transport transport) {
|
||||
this.networkClient = networkClient;
|
||||
this.packet = packet;
|
||||
this.transport = transport;
|
||||
public C_PacketReceivedFailedEvent(
|
||||
NetworkClient client,
|
||||
Packet packet,
|
||||
NetworkProtocol protocol,
|
||||
Exception error
|
||||
) {
|
||||
this.client = Objects.requireNonNull(client, "client");
|
||||
this.packet = packet; // may be null
|
||||
this.protocol = Objects.requireNonNull(protocol, "protocol");
|
||||
this.error = Objects.requireNonNull(error, "error");
|
||||
}
|
||||
|
||||
public NetworkClient getNetworkClient() {
|
||||
return networkClient;
|
||||
/**
|
||||
* Returns the client instance.
|
||||
*
|
||||
* @return client
|
||||
*/
|
||||
public NetworkClient getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the packet that failed to be processed, if available.
|
||||
*
|
||||
* @return packet or null
|
||||
*/
|
||||
public Packet getPacket() {
|
||||
return packet;
|
||||
}
|
||||
|
||||
public Transport getTransport() {
|
||||
return transport;
|
||||
/**
|
||||
* Returns the protocol the failure occurred on.
|
||||
*
|
||||
* @return protocol
|
||||
*/
|
||||
public NetworkProtocol getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying error.
|
||||
*
|
||||
* @return error
|
||||
*/
|
||||
public Exception getError() {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,51 +6,65 @@
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.client.events.packets.receive;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.client.NetworkClient;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.Transport;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.Packet;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.NetworkProtocol;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Fired when an unknown object was received on a specific transport.
|
||||
* Fired when an unknown (non-packet) object was received on a specific protocol.
|
||||
*
|
||||
* <p>Note: In v2 the default transport is {@link dev.unlegitdqrk.unlegitlibrary.network.system.packets.PacketCodec}
|
||||
* based and typically produces {@link Packet}.
|
||||
* This event exists for backwards compatibility and for custom codecs/handlers.</p>
|
||||
*/
|
||||
public final class C_UnknownObjectReceivedEvent extends Event {
|
||||
|
||||
private final NetworkClient networkClient;
|
||||
private final NetworkClient client;
|
||||
private final Object received;
|
||||
private final Transport transport;
|
||||
private final NetworkProtocol protocol;
|
||||
|
||||
/**
|
||||
* Creates a new unknown object received event.
|
||||
*
|
||||
* @param networkClient client instance
|
||||
* @param received received object
|
||||
* @param transport transport the object was received on
|
||||
* @param client client instance
|
||||
* @param received received object
|
||||
* @param protocol protocol the object was received on
|
||||
*/
|
||||
public C_UnknownObjectReceivedEvent(NetworkClient networkClient, Object received, Transport transport) {
|
||||
this.networkClient = networkClient;
|
||||
this.received = received;
|
||||
this.transport = transport;
|
||||
public C_UnknownObjectReceivedEvent(NetworkClient client, Object received, NetworkProtocol protocol) {
|
||||
this.client = Objects.requireNonNull(client, "client");
|
||||
this.received = Objects.requireNonNull(received, "received");
|
||||
this.protocol = Objects.requireNonNull(protocol, "protocol");
|
||||
}
|
||||
|
||||
public NetworkClient getNetworkClient() {
|
||||
return networkClient;
|
||||
/**
|
||||
* Returns the client instance.
|
||||
*
|
||||
* @return client
|
||||
*/
|
||||
public NetworkClient getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the received object.
|
||||
*
|
||||
* @return received object
|
||||
*/
|
||||
public Object getReceived() {
|
||||
return received;
|
||||
}
|
||||
|
||||
public Transport getTransport() {
|
||||
return transport;
|
||||
/**
|
||||
* Returns the protocol the object was received on.
|
||||
*
|
||||
* @return protocol
|
||||
*/
|
||||
public NetworkProtocol getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,52 +6,71 @@
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.client.events.packets.send;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.client.NetworkClient;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.Packet;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.Transport;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.NetworkProtocol;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Fired when a packet was sent by the client on a specific transport.
|
||||
* Fired when a packet was successfully sent by the client on a specific protocol.
|
||||
*
|
||||
* <p>v2 mapping:
|
||||
* <ul>
|
||||
* <li>{@link NetworkProtocol#TCP} → TLS/TCP</li>
|
||||
* <li>{@link NetworkProtocol#UDP} → DTLS/UDP</li>
|
||||
* </ul>
|
||||
*/
|
||||
public final class C_PacketSendEvent extends Event {
|
||||
|
||||
private final NetworkClient networkClient;
|
||||
private final NetworkClient client;
|
||||
private final Packet packet;
|
||||
private final Transport transport;
|
||||
private final NetworkProtocol protocol;
|
||||
|
||||
/**
|
||||
* Creates a new packet send event.
|
||||
*
|
||||
* @param networkClient client instance
|
||||
* @param packet sent packet
|
||||
* @param transport used transport
|
||||
* @param client client instance
|
||||
* @param packet sent packet
|
||||
* @param protocol used protocol
|
||||
*/
|
||||
public C_PacketSendEvent(NetworkClient networkClient, Packet packet, Transport transport) {
|
||||
this.networkClient = networkClient;
|
||||
this.packet = packet;
|
||||
this.transport = transport;
|
||||
public C_PacketSendEvent(
|
||||
NetworkClient client,
|
||||
Packet packet,
|
||||
NetworkProtocol protocol
|
||||
) {
|
||||
this.client = Objects.requireNonNull(client, "client");
|
||||
this.packet = Objects.requireNonNull(packet, "packet");
|
||||
this.protocol = Objects.requireNonNull(protocol, "protocol");
|
||||
}
|
||||
|
||||
public NetworkClient getNetworkClient() {
|
||||
return networkClient;
|
||||
/**
|
||||
* Returns the client.
|
||||
*
|
||||
* @return client
|
||||
*/
|
||||
public NetworkClient getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sent packet.
|
||||
*
|
||||
* @return packet
|
||||
*/
|
||||
public Packet getPacket() {
|
||||
return packet;
|
||||
}
|
||||
|
||||
public Transport getTransport() {
|
||||
return transport;
|
||||
/**
|
||||
* Returns the protocol used.
|
||||
*
|
||||
* @return protocol
|
||||
*/
|
||||
public NetworkProtocol getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,52 +6,78 @@
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.client.events.packets.send;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.client.NetworkClient;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.Packet;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.Transport;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.NetworkProtocol;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Fired when a packet send failed on the client on a specific transport.
|
||||
* Fired when a packet send failed on the client on a specific protocol.
|
||||
*/
|
||||
public final class C_PacketSendFailedEvent extends Event {
|
||||
|
||||
private final NetworkClient networkClient;
|
||||
private final NetworkClient client;
|
||||
private final Packet packet;
|
||||
private final Transport transport;
|
||||
private final NetworkProtocol protocol;
|
||||
private final Exception error;
|
||||
|
||||
/**
|
||||
* Creates a new packet send failed event.
|
||||
*
|
||||
* @param networkClient client instance
|
||||
* @param packet packet that failed to be sent
|
||||
* @param transport intended transport
|
||||
* @param client client instance
|
||||
* @param packet packet that failed to be sent
|
||||
* @param protocol intended protocol
|
||||
* @param error root cause
|
||||
*/
|
||||
public C_PacketSendFailedEvent(NetworkClient networkClient, Packet packet, Transport transport) {
|
||||
this.networkClient = networkClient;
|
||||
this.packet = packet;
|
||||
this.transport = transport;
|
||||
public C_PacketSendFailedEvent(
|
||||
NetworkClient client,
|
||||
Packet packet,
|
||||
NetworkProtocol protocol,
|
||||
Exception error
|
||||
) {
|
||||
this.client = Objects.requireNonNull(client, "client");
|
||||
this.packet = Objects.requireNonNull(packet, "packet");
|
||||
this.protocol = Objects.requireNonNull(protocol, "protocol");
|
||||
this.error = Objects.requireNonNull(error, "error");
|
||||
}
|
||||
|
||||
public NetworkClient getNetworkClient() {
|
||||
return networkClient;
|
||||
/**
|
||||
* Returns the client.
|
||||
*
|
||||
* @return client
|
||||
*/
|
||||
public NetworkClient getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the packet that failed to be sent.
|
||||
*
|
||||
* @return packet
|
||||
*/
|
||||
public Packet getPacket() {
|
||||
return packet;
|
||||
}
|
||||
|
||||
public Transport getTransport() {
|
||||
return transport;
|
||||
/**
|
||||
* Returns the intended protocol.
|
||||
*
|
||||
* @return protocol
|
||||
*/
|
||||
public NetworkProtocol getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying error.
|
||||
*
|
||||
* @return error
|
||||
*/
|
||||
public Exception getError() {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,53 +6,37 @@
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.client.events.state.connect;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.client.NetworkClient;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.Transport;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.NetworkProtocol;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Fired when the client established a specific transport connection.
|
||||
* Fired when the client established a specific protocol connection.
|
||||
*
|
||||
* <p>This event is transport-specific:
|
||||
* <p>Protocol-specific:
|
||||
* <ul>
|
||||
* <li>{@link Transport#TCP}: after TLS handshake + TCP streams are ready</li>
|
||||
* <li>{@link Transport#UDP}: after DTLS handshake + UDP bind was initiated</li>
|
||||
* <li>{@link NetworkProtocol#TCP}: after TLS handshake + TCP streams are ready</li>
|
||||
* <li>{@link NetworkProtocol#UDP}: after DTLS handshake (channel/engine ready)</li>
|
||||
* </ul>
|
||||
*/
|
||||
public final class ClientConnectedEvent extends Event {
|
||||
|
||||
private final NetworkClient client;
|
||||
private final Transport transport;
|
||||
private final NetworkProtocol protocol;
|
||||
|
||||
/**
|
||||
* Creates a new client connected event.
|
||||
*
|
||||
* @param client client instance
|
||||
* @param transport connected transport
|
||||
* @param client client instance
|
||||
* @param protocol connected protocol
|
||||
*/
|
||||
public ClientConnectedEvent(NetworkClient client, Transport transport) {
|
||||
public ClientConnectedEvent(NetworkClient client, NetworkProtocol protocol) {
|
||||
this.client = Objects.requireNonNull(client, "client");
|
||||
this.transport = Objects.requireNonNull(transport, "transport");
|
||||
this.protocol = Objects.requireNonNull(protocol, "protocol");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,11 +49,11 @@ public final class ClientConnectedEvent extends Event {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the transport that was connected.
|
||||
* Returns the protocol that was connected.
|
||||
*
|
||||
* @return transport
|
||||
* @return protocol
|
||||
*/
|
||||
public Transport getTransport() {
|
||||
return transport;
|
||||
public NetworkProtocol getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,47 +6,38 @@
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.client.events.state.connect;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.client.NetworkClient;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.Transport;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.NetworkProtocol;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Fired when the client has fully established the configured transport policy.
|
||||
* Fired when the client satisfies its enabled protocol requirements.
|
||||
*
|
||||
* <p>For your setup this means: TCP (TLS) connected, ClientID received and UDP (DTLS) bound.</p>
|
||||
* <p>In v2 this typically means:
|
||||
* <ul>
|
||||
* <li>TCP is connected (TLS ok)</li>
|
||||
* <li>and if UDP is enabled: DTLS is established and the bind flow is completed</li>
|
||||
* </ul>
|
||||
*/
|
||||
public final class ClientFullyConnectedEvent extends Event {
|
||||
|
||||
private final NetworkClient client;
|
||||
private final Transport[] requiredTransports;
|
||||
private final EnumSet<NetworkProtocol> requiredProtocols;
|
||||
|
||||
/**
|
||||
* Creates a new event.
|
||||
*
|
||||
* @param client client instance
|
||||
* @param requiredTransports transports that are required and now satisfied
|
||||
* @param client client instance
|
||||
* @param requiredProtocols protocols that are required and now satisfied
|
||||
*/
|
||||
public ClientFullyConnectedEvent(NetworkClient client, Transport[] requiredTransports) {
|
||||
this.client = client;
|
||||
this.requiredTransports = requiredTransports;
|
||||
public ClientFullyConnectedEvent(NetworkClient client, EnumSet<NetworkProtocol> requiredProtocols) {
|
||||
this.client = Objects.requireNonNull(client, "client");
|
||||
this.requiredProtocols = EnumSet.copyOf(Objects.requireNonNull(requiredProtocols, "requiredProtocols"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,11 +50,11 @@ public final class ClientFullyConnectedEvent extends Event {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the required transports that are now established.
|
||||
* Returns the required protocols that are now established.
|
||||
*
|
||||
* @return required transports
|
||||
* @return required protocols (copy)
|
||||
*/
|
||||
public Transport[] getRequiredTransports() {
|
||||
return requiredTransports;
|
||||
public EnumSet<NetworkProtocol> getRequiredProtocols() {
|
||||
return EnumSet.copyOf(requiredProtocols);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,53 +6,37 @@
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.client.events.state.disconnect;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.client.NetworkClient;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.Transport;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.NetworkProtocol;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Fired when the client lost/closed a specific transport connection.
|
||||
* Fired when the client lost/closed a specific protocol connection.
|
||||
*
|
||||
* <p>This event is transport-specific:
|
||||
* <p>Protocol-specific:
|
||||
* <ul>
|
||||
* <li>{@link Transport#TCP}: TCP/TLS socket closed or receive loop ended</li>
|
||||
* <li>{@link Transport#UDP}: UDP channel/DTLS endpoint closed</li>
|
||||
* <li>{@link NetworkProtocol#TCP}: TCP/TLS socket closed or receive loop ended</li>
|
||||
* <li>{@link NetworkProtocol#UDP}: UDP channel/DTLS endpoint closed</li>
|
||||
* </ul>
|
||||
*/
|
||||
public final class ClientDisconnectedEvent extends Event {
|
||||
|
||||
private final NetworkClient client;
|
||||
private final Transport transport;
|
||||
private final NetworkProtocol protocol;
|
||||
|
||||
/**
|
||||
* Creates a new client disconnected event.
|
||||
*
|
||||
* @param client client instance
|
||||
* @param transport disconnected transport
|
||||
* @param client client instance
|
||||
* @param protocol disconnected protocol
|
||||
*/
|
||||
public ClientDisconnectedEvent(NetworkClient client, Transport transport) {
|
||||
public ClientDisconnectedEvent(NetworkClient client, NetworkProtocol protocol) {
|
||||
this.client = Objects.requireNonNull(client, "client");
|
||||
this.transport = Objects.requireNonNull(transport, "transport");
|
||||
this.protocol = Objects.requireNonNull(protocol, "protocol");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,11 +49,11 @@ public final class ClientDisconnectedEvent extends Event {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the transport that was disconnected.
|
||||
* Returns the protocol that was disconnected.
|
||||
*
|
||||
* @return transport
|
||||
* @return protocol
|
||||
*/
|
||||
public Transport getTransport() {
|
||||
return transport;
|
||||
public NetworkProtocol getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,51 +6,32 @@
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.client.events.state.disconnect;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.client.NetworkClient;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.Transport;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.NetworkProtocol;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Fired when the client was fully connected and then became fully disconnected.
|
||||
*
|
||||
* <p>For your policy (TCP+UDP required) this means:
|
||||
* previously: TCP+UDP connected and ClientID present,
|
||||
* now: not fully connected anymore (both transports are not satisfying the requirement).</p>
|
||||
* Fired when the client previously satisfied its required protocols and then stopped satisfying them.
|
||||
*/
|
||||
public final class ClientFullyDisconnectedEvent extends Event {
|
||||
|
||||
private final NetworkClient client;
|
||||
private final Transport[] requiredTransports;
|
||||
private final EnumSet<NetworkProtocol> requiredProtocols;
|
||||
|
||||
/**
|
||||
* Creates a new fully disconnected event.
|
||||
*
|
||||
* @param client client instance
|
||||
* @param requiredTransports required transports according to policy
|
||||
* @param client client instance
|
||||
* @param requiredProtocols protocols that were required for full connectivity
|
||||
*/
|
||||
public ClientFullyDisconnectedEvent(NetworkClient client, Transport[] requiredTransports) {
|
||||
public ClientFullyDisconnectedEvent(NetworkClient client, EnumSet<NetworkProtocol> requiredProtocols) {
|
||||
this.client = Objects.requireNonNull(client, "client");
|
||||
this.requiredTransports = Objects.requireNonNull(requiredTransports, "requiredTransports");
|
||||
this.requiredProtocols = EnumSet.copyOf(Objects.requireNonNull(requiredProtocols, "requiredProtocols"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,11 +44,11 @@ public final class ClientFullyDisconnectedEvent extends Event {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns transports that were required for full connectivity.
|
||||
* Returns protocols that were required for full connectivity.
|
||||
*
|
||||
* @return required transports
|
||||
* @return required protocols (copy)
|
||||
*/
|
||||
public Transport[] getRequiredTransports() {
|
||||
return requiredTransports;
|
||||
public EnumSet<NetworkProtocol> getRequiredProtocols() {
|
||||
return EnumSet.copyOf(requiredProtocols);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.packets;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
|
||||
/**
|
||||
* Base type for packets used by the v2 secure network system.
|
||||
*
|
||||
* <p>Packets are encoded as:
|
||||
* <pre>
|
||||
* [int packetId][payload bytes...]
|
||||
* </pre>
|
||||
* Payload is written/read by the packet itself through Java serialization streams.</p>
|
||||
*/
|
||||
public abstract class Packet {
|
||||
|
||||
private final int id;
|
||||
private final int packetId;
|
||||
|
||||
public Packet(int id) {
|
||||
this.id = id;
|
||||
/**
|
||||
* Creates a new packet.
|
||||
*
|
||||
* @param packetId unique packet id
|
||||
*/
|
||||
protected Packet(int packetId) {
|
||||
this.packetId = packetId;
|
||||
}
|
||||
|
||||
public final int getPacketID() {
|
||||
return id;
|
||||
/**
|
||||
* Returns the packet id.
|
||||
*
|
||||
* @return id
|
||||
*/
|
||||
public final int packetId() {
|
||||
return packetId;
|
||||
}
|
||||
|
||||
public abstract void write(PacketHandler packetHandler, ObjectOutputStream outputStream) throws IOException, ClassNotFoundException;
|
||||
/**
|
||||
* Writes payload fields to the stream.
|
||||
*
|
||||
* @param out output stream
|
||||
* @throws IOException on I/O errors
|
||||
*/
|
||||
public abstract void write(ObjectOutputStream out) throws IOException;
|
||||
|
||||
public abstract void read(PacketHandler packetHandler, ObjectInputStream outputStream) throws IOException, ClassNotFoundException;
|
||||
}
|
||||
/**
|
||||
* Reads payload fields from the stream.
|
||||
*
|
||||
* @param in input stream
|
||||
* @throws IOException on I/O errors
|
||||
* @throws ClassNotFoundException on deserialization errors
|
||||
*/
|
||||
public abstract void read(ObjectInputStream in) throws IOException, ClassNotFoundException;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.packets;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Encodes and decodes {@link Packet} instances for TCP (stream) and UDP (datagram).
|
||||
*
|
||||
* <p>Wire format (transport-agnostic):
|
||||
* <pre>
|
||||
* [int packetId][ObjectStream payload...]
|
||||
* </pre>
|
||||
*/
|
||||
public final class PacketCodec {
|
||||
|
||||
private final PacketRegistry registry;
|
||||
|
||||
/**
|
||||
* Creates a new codec.
|
||||
*
|
||||
* @param registry packet registry
|
||||
*/
|
||||
public PacketCodec(PacketRegistry registry) {
|
||||
this.registry = Objects.requireNonNull(registry, "registry");
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a packet into a byte buffer suitable for UDP/DTLS sending.
|
||||
*
|
||||
* @param packet packet to encode
|
||||
* @return encoded buffer (position=0, limit=length)
|
||||
* @throws IOException on serialization errors
|
||||
*/
|
||||
public ByteBuffer encodeToBuffer(Packet packet) throws IOException {
|
||||
Objects.requireNonNull(packet, "packet");
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(256);
|
||||
try (DataOutputStream dos = new DataOutputStream(baos)) {
|
||||
dos.writeInt(packet.packetId());
|
||||
try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
|
||||
packet.write(oos);
|
||||
oos.flush();
|
||||
}
|
||||
}
|
||||
return ByteBuffer.wrap(baos.toByteArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a packet from a received datagram buffer.
|
||||
*
|
||||
* @param buffer received buffer (position..limit)
|
||||
* @return decoded packet
|
||||
* @throws IOException on I/O errors
|
||||
* @throws ClassNotFoundException on deserialization errors
|
||||
*/
|
||||
public Packet decodeFromBuffer(ByteBuffer buffer) throws IOException, ClassNotFoundException {
|
||||
Objects.requireNonNull(buffer, "buffer");
|
||||
|
||||
ByteArrayInputStream bais =
|
||||
new ByteArrayInputStream(buffer.array(), buffer.position(), buffer.remaining());
|
||||
|
||||
int packetId;
|
||||
try (DataInputStream dis = new DataInputStream(bais)) {
|
||||
packetId = dis.readInt();
|
||||
}
|
||||
|
||||
Packet packet = registry.create(packetId);
|
||||
|
||||
try (ObjectInputStream ois = new ObjectInputStream(bais)) {
|
||||
packet.read(ois);
|
||||
}
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a packet over a TCP/TLS stream.
|
||||
*
|
||||
* @param packet packet
|
||||
* @param out output stream
|
||||
* @throws IOException on I/O errors
|
||||
*/
|
||||
public void sendToStream(Packet packet, ObjectOutputStream out) throws IOException {
|
||||
Objects.requireNonNull(packet, "packet");
|
||||
Objects.requireNonNull(out, "out");
|
||||
|
||||
out.writeInt(packet.packetId());
|
||||
packet.write(out);
|
||||
out.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives a packet from a TCP/TLS stream.
|
||||
*
|
||||
* @param in input stream
|
||||
* @return decoded packet
|
||||
* @throws IOException on I/O errors
|
||||
* @throws ClassNotFoundException on deserialization errors
|
||||
*/
|
||||
public Packet receiveFromStream(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
Objects.requireNonNull(in, "in");
|
||||
|
||||
int packetId = in.readInt();
|
||||
Packet packet = registry.create(packetId);
|
||||
packet.read(in);
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.packets;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.client.NetworkClient;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.NetworkServer;
|
||||
import dev.unlegitdqrk.unlegitlibrary.utils.DefaultMethodsOverrider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public final class PacketHandler extends DefaultMethodsOverrider {
|
||||
|
||||
private final Map<Integer, Packet> packets = new HashMap<>();
|
||||
|
||||
private NetworkClient clientInstance;
|
||||
private NetworkServer serverInstance;
|
||||
|
||||
public NetworkClient getClientInstance() {
|
||||
return clientInstance;
|
||||
}
|
||||
|
||||
public void setClientInstance(NetworkClient clientInstance) {
|
||||
if (this.clientInstance == null) this.clientInstance = clientInstance;
|
||||
}
|
||||
|
||||
public NetworkServer getServerInstance() {
|
||||
return serverInstance;
|
||||
}
|
||||
|
||||
public void setServerInstance(NetworkServer serverInstance) {
|
||||
if (this.serverInstance == null) this.serverInstance = serverInstance;
|
||||
}
|
||||
|
||||
public boolean isPacketIDRegistered(int id) {
|
||||
return packets.containsKey(id);
|
||||
}
|
||||
|
||||
public Packet getPacketByID(int id) {
|
||||
return packets.get(id);
|
||||
}
|
||||
|
||||
public boolean registerPacket(Packet packet) {
|
||||
int id = packet.getPacketID();
|
||||
|
||||
if (isPacketIDRegistered(id)) return false;
|
||||
|
||||
packets.put(id, packet);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean handlePacket(int id, Packet packet, ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
|
||||
if (!isPacketIDRegistered(id) || (packet != null && id != packet.getPacketID()) || (packet != null && !isPacketIDRegistered(packet.getPacketID())))
|
||||
return false;
|
||||
|
||||
packet.read(this, inputStream);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean sendPacket(Packet packet, ObjectOutputStream outputStream) throws IOException, ClassNotFoundException {
|
||||
int id = packet.getPacketID();
|
||||
if (!isPacketIDRegistered(id)) return false;
|
||||
|
||||
outputStream.writeObject(id);
|
||||
packet.write(this, outputStream);
|
||||
outputStream.flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.packets;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.impl.*;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Thread-safe registry that maps packet ids to factories creating new packet instances.
|
||||
*
|
||||
* <p>This avoids reusing the same packet instance across threads/connections.</p>
|
||||
*/
|
||||
public final class PacketRegistry {
|
||||
|
||||
private final Map<Integer, Supplier<? extends Packet>> factories = new ConcurrentHashMap<>();
|
||||
|
||||
public PacketRegistry() {
|
||||
register(ConnectionIdPacket::new);
|
||||
register(ProtocolRequirementsPacket::new);
|
||||
register(UdpBindAckPacket::new);
|
||||
register(UdpBindPacket::new);
|
||||
register(UdpHelloPacket::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a packet factory for the given id.
|
||||
*
|
||||
* @param factory instance factory
|
||||
* @return true if newly registered, false if id already present
|
||||
*/
|
||||
public boolean register(Supplier<? extends Packet> factory) {
|
||||
Objects.requireNonNull(factory, "factory");
|
||||
return factories.putIfAbsent(factory.get().packetId(), factory) == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a packet id is registered.
|
||||
*
|
||||
* @param packetId id
|
||||
* @return true if registered
|
||||
*/
|
||||
public boolean isRegistered(int packetId) {
|
||||
return factories.containsKey(packetId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new packet instance for the given id.
|
||||
*
|
||||
* @param packetId id
|
||||
* @return new packet instance
|
||||
* @throws IllegalArgumentException if id is not registered or factory returns null
|
||||
*/
|
||||
public Packet create(int packetId) {
|
||||
Supplier<? extends Packet> supplier = factories.get(packetId);
|
||||
if (supplier == null) {
|
||||
throw new IllegalArgumentException("Unknown packetId: " + packetId);
|
||||
}
|
||||
Packet p = supplier.get();
|
||||
if (p == null) {
|
||||
throw new IllegalArgumentException("Packet factory returned null for packetId: " + packetId);
|
||||
}
|
||||
if (p.packetId() != packetId) {
|
||||
throw new IllegalArgumentException("Packet factory produced mismatching id: expected="
|
||||
+ packetId + ", got=" + p.packetId());
|
||||
}
|
||||
return p;
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.packets.impl;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.Packet;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.PacketHandler;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.ClientID;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Transfers the server-assigned {@link ClientID} to the client.
|
||||
*/
|
||||
public final class ClientIDPacket extends Packet {
|
||||
|
||||
private ClientID clientId;
|
||||
|
||||
public ClientIDPacket() {
|
||||
super(0);
|
||||
}
|
||||
|
||||
public ClientIDPacket(ClientID clientId) {
|
||||
this();
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
public ClientID getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(PacketHandler packetHandler, ObjectOutputStream outputStream) throws IOException {
|
||||
if (clientId == null) throw new IOException("ClientIDPacket.clientId is null");
|
||||
UUID uuid = clientId.uuid();
|
||||
outputStream.writeLong(uuid.getMostSignificantBits());
|
||||
outputStream.writeLong(uuid.getLeastSignificantBits());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(PacketHandler packetHandler, ObjectInputStream inputStream) throws IOException {
|
||||
long msb = inputStream.readLong();
|
||||
long lsb = inputStream.readLong();
|
||||
this.clientId = new ClientID(new UUID(msb, lsb));
|
||||
|
||||
if (packetHandler.getClientInstance() != null) {
|
||||
packetHandler.getClientInstance().setClientId(this.clientId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.packets.impl;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.Packet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Server -> Client packet that assigns a server-side connection id.
|
||||
*
|
||||
* <p>This id is used to bind the DTLS/UDP endpoint to the already authenticated TCP/TLS connection
|
||||
* via {@link UdpBindPacket}.</p>
|
||||
*/
|
||||
public final class ConnectionIdPacket extends Packet {
|
||||
|
||||
private UUID connectionId;
|
||||
|
||||
/**
|
||||
* Creates an empty packet instance for decoding.
|
||||
*/
|
||||
public ConnectionIdPacket() {
|
||||
super(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a packet instance with a connection id for sending.
|
||||
*
|
||||
* @param connectionId connection id (must not be null)
|
||||
*/
|
||||
public ConnectionIdPacket(UUID connectionId) {
|
||||
this();
|
||||
this.connectionId = Objects.requireNonNull(connectionId, "connectionId");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the assigned connection id.
|
||||
*
|
||||
* @return connection id
|
||||
*/
|
||||
public UUID connectionId() {
|
||||
return connectionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ObjectOutputStream out) throws IOException {
|
||||
if (connectionId == null) {
|
||||
throw new IOException("ConnectionIdPacket.connectionId is null");
|
||||
}
|
||||
out.writeLong(connectionId.getMostSignificantBits());
|
||||
out.writeLong(connectionId.getLeastSignificantBits());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ObjectInputStream in) throws IOException {
|
||||
long msb = in.readLong();
|
||||
long lsb = in.readLong();
|
||||
this.connectionId = new UUID(msb, lsb);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.packets.impl;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.Packet;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.NetworkProtocol;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Server -> client packet containing the server-required protocol set.
|
||||
*
|
||||
* <p>This packet allows the client to evaluate "fully connected" based on the server policy.</p>
|
||||
*/
|
||||
public final class ProtocolRequirementsPacket extends Packet {
|
||||
|
||||
private EnumSet<NetworkProtocol> requiredProtocols = EnumSet.noneOf(NetworkProtocol.class);
|
||||
|
||||
/**
|
||||
* Constructs an empty packet for deserialization.
|
||||
*/
|
||||
public ProtocolRequirementsPacket() {
|
||||
super(2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the packet.
|
||||
*
|
||||
* @param requiredProtocols required protocol set
|
||||
*/
|
||||
public ProtocolRequirementsPacket(EnumSet<NetworkProtocol> requiredProtocols) {
|
||||
super(2);
|
||||
this.requiredProtocols = EnumSet.copyOf(Objects.requireNonNull(requiredProtocols, "requiredProtocols"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the required protocol set.
|
||||
*
|
||||
* @return required protocols
|
||||
*/
|
||||
public EnumSet<NetworkProtocol> requiredProtocols() {
|
||||
return EnumSet.copyOf(requiredProtocols);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ObjectOutputStream out) throws IOException {
|
||||
Objects.requireNonNull(out, "out");
|
||||
out.writeInt(toMask(requiredProtocols));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ObjectInputStream in) throws IOException {
|
||||
Objects.requireNonNull(in, "in");
|
||||
int mask = in.readInt();
|
||||
this.requiredProtocols = fromMask(mask);
|
||||
}
|
||||
|
||||
private static int toMask(EnumSet<NetworkProtocol> set) {
|
||||
int mask = 0;
|
||||
if (set.contains(NetworkProtocol.TCP)) mask |= 1;
|
||||
if (set.contains(NetworkProtocol.UDP)) mask |= 2;
|
||||
return mask;
|
||||
}
|
||||
|
||||
private static EnumSet<NetworkProtocol> fromMask(int mask) {
|
||||
EnumSet<NetworkProtocol> set = EnumSet.noneOf(NetworkProtocol.class);
|
||||
if ((mask & 1) != 0) set.add(NetworkProtocol.TCP);
|
||||
if ((mask & 2) != 0) set.add(NetworkProtocol.UDP);
|
||||
return set;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.packets.impl;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.Packet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Server -> client acknowledgement for {@link UdpBindPacket}.
|
||||
*
|
||||
* <p>The client must only consider UDP "bound/ready" after receiving this ACK with the matching connection id.</p>
|
||||
*
|
||||
* <p><strong>IMPORTANT:</strong> Ensure {@link #PACKET_ID} does not conflict with your other packet ids and
|
||||
* register it in {@code PacketRegistry}.</p>
|
||||
*/
|
||||
public final class UdpBindAckPacket extends Packet {
|
||||
|
||||
private UUID connectionId;
|
||||
|
||||
/**
|
||||
* Constructs an empty packet for deserialization.
|
||||
*/
|
||||
public UdpBindAckPacket() {
|
||||
super(3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the ACK packet.
|
||||
*
|
||||
* @param connectionId connection id being acknowledged
|
||||
*/
|
||||
public UdpBindAckPacket(UUID connectionId) {
|
||||
super(3);
|
||||
this.connectionId = Objects.requireNonNull(connectionId, "connectionId");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the acknowledged connection id.
|
||||
*
|
||||
* @return connection id
|
||||
*/
|
||||
public UUID connectionId() {
|
||||
return connectionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ObjectOutputStream out) throws IOException {
|
||||
Objects.requireNonNull(out, "out");
|
||||
out.writeLong(connectionId.getMostSignificantBits());
|
||||
out.writeLong(connectionId.getLeastSignificantBits());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ObjectInputStream in) throws IOException {
|
||||
Objects.requireNonNull(in, "in");
|
||||
long msb = in.readLong();
|
||||
long lsb = in.readLong();
|
||||
this.connectionId = new UUID(msb, lsb);
|
||||
}
|
||||
}
|
||||
@@ -9,54 +9,67 @@
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.packets.impl;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.Packet;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.PacketHandler;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.ClientID;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Binds a DTLS/UDP endpoint to the already assigned {@link ClientID}.
|
||||
* Client -> Server packet sent over UDP/DTLS to bind the DTLS remote address to an existing TCP/TLS connection.
|
||||
*
|
||||
* <p>Flow: TCP connect -> receive ClientID -> DTLS handshake -> send UdpBindPacket(clientId)</p>
|
||||
* <p>Flow:
|
||||
* <ol>
|
||||
* <li>Client connects via TCP/TLS</li>
|
||||
* <li>Server sends {@link ConnectionIdPacket} over TCP</li>
|
||||
* <li>Client completes DTLS handshake and sends {@link UdpBindPacket} over UDP/DTLS with the same connection id</li>
|
||||
* <li>Server attaches UDP remote to the matching {@code SecureConnection}</li>
|
||||
* </ol>
|
||||
*/
|
||||
public final class UdpBindPacket extends Packet {
|
||||
|
||||
public static final int PACKET_ID = 1;
|
||||
|
||||
private ClientID clientId;
|
||||
private UUID connectionId;
|
||||
|
||||
/**
|
||||
* Creates an empty packet instance for decoding.
|
||||
*/
|
||||
public UdpBindPacket() {
|
||||
super(PACKET_ID);
|
||||
super(4);
|
||||
}
|
||||
|
||||
public UdpBindPacket(ClientID clientId) {
|
||||
/**
|
||||
* Creates a bind packet for sending.
|
||||
*
|
||||
* @param connectionId server-assigned connection id (must not be null)
|
||||
*/
|
||||
public UdpBindPacket(UUID connectionId) {
|
||||
this();
|
||||
this.clientId = clientId;
|
||||
this.connectionId = Objects.requireNonNull(connectionId, "connectionId");
|
||||
}
|
||||
|
||||
public ClientID getClientId() {
|
||||
return clientId;
|
||||
/**
|
||||
* Returns the connection id this UDP endpoint wants to bind to.
|
||||
*
|
||||
* @return connection id
|
||||
*/
|
||||
public UUID connectionId() {
|
||||
return connectionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(PacketHandler packetHandler, ObjectOutputStream outputStream) throws IOException {
|
||||
if (clientId == null) throw new IOException("UdpBindPacket.clientId is null");
|
||||
UUID uuid = clientId.uuid();
|
||||
outputStream.writeLong(uuid.getMostSignificantBits());
|
||||
outputStream.writeLong(uuid.getLeastSignificantBits());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(PacketHandler packetHandler, ObjectInputStream inputStream) throws IOException {
|
||||
long msb = inputStream.readLong();
|
||||
long lsb = inputStream.readLong();
|
||||
this.clientId = new ClientID(new UUID(msb, lsb));
|
||||
// Server-side binding is handled by UDP receiver, because it knows the remote address.
|
||||
if (packetHandler.getClientInstance() != null) {
|
||||
packetHandler.getClientInstance().setClientId(this.clientId);
|
||||
public void write(ObjectOutputStream out) throws IOException {
|
||||
if (connectionId == null) {
|
||||
throw new IOException("UdpBindPacket.connectionId is null");
|
||||
}
|
||||
out.writeLong(connectionId.getMostSignificantBits());
|
||||
out.writeLong(connectionId.getLeastSignificantBits());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ObjectInputStream in) throws IOException {
|
||||
long msb = in.readLong();
|
||||
long lsb = in.readLong();
|
||||
this.connectionId = new UUID(msb, lsb);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.packets.impl;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.Packet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Client -> server packet used for UDP-only bootstrap.
|
||||
*
|
||||
* <p>The client sends this packet over UDP/DTLS to request the server to create/assign a connection id
|
||||
* and return bootstrap information (e.g. ConnectionIdPacket + ProtocolRequirementsPacket) over UDP.</p>
|
||||
*/
|
||||
public final class UdpHelloPacket extends Packet {
|
||||
|
||||
/**
|
||||
* Constructs an empty packet for serialization/deserialization.
|
||||
*/
|
||||
public UdpHelloPacket() {
|
||||
super(5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ObjectOutputStream out) throws IOException {
|
||||
Objects.requireNonNull(out, "out");
|
||||
// No payload.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ObjectInputStream in) throws IOException {
|
||||
Objects.requireNonNull(in, "in");
|
||||
// No payload.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,363 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://github.com/UnlegitDqrk
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.server;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.event.EventManager;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.PacketCodec;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.Packet;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.events.packets.send.S_PacketSendEvent;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.events.packets.send.S_PacketSendFailedEvent;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.DtlsEndpoint;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.NetworkProtocol;
|
||||
|
||||
import javax.net.ssl.SSLSocket;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.net.SocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.DatagramChannel;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* Represents one connected client on the server side, with optional TCP/TLS and/or UDP/DTLS channels.
|
||||
*
|
||||
* <p>Connection usability is defined by {@link ServerProtocolMode#required()}.</p>
|
||||
*/
|
||||
public final class ClientConnection {
|
||||
|
||||
private final UUID connectionId;
|
||||
private final PacketCodec codec;
|
||||
private final ServerProtocolMode protocolMode;
|
||||
private final EventManager eventManager;
|
||||
|
||||
// TCP (TLS) - optional
|
||||
private final SSLSocket tcpSocket;
|
||||
private final ObjectOutputStream tcpOut;
|
||||
private final ObjectInputStream tcpIn;
|
||||
|
||||
// UDP (DTLS) - optional
|
||||
private volatile SocketAddress udpRemote;
|
||||
private volatile DtlsEndpoint.DtlsSession udpSession;
|
||||
private volatile DtlsEndpoint dtlsEndpoint;
|
||||
private volatile DatagramChannel udpChannel;
|
||||
private volatile boolean udpBound;
|
||||
|
||||
private final AtomicBoolean closed = new AtomicBoolean(false);
|
||||
|
||||
/**
|
||||
* Creates a new connection with a predefined connection id.
|
||||
*
|
||||
* @param connectionId server-side unique connection id
|
||||
* @param codec packet codec
|
||||
* @param protocolMode server protocol mode (supported/required)
|
||||
* @param eventManager event manager used to dispatch server events
|
||||
* @param tcpSocket TLS socket (nullable for UDP-only)
|
||||
* @param tcpOut TCP output stream (nullable for UDP-only)
|
||||
* @param tcpIn TCP input stream (nullable for UDP-only)
|
||||
*/
|
||||
public ClientConnection(
|
||||
UUID connectionId,
|
||||
PacketCodec codec,
|
||||
ServerProtocolMode protocolMode,
|
||||
EventManager eventManager,
|
||||
SSLSocket tcpSocket,
|
||||
ObjectOutputStream tcpOut,
|
||||
ObjectInputStream tcpIn
|
||||
) {
|
||||
this.connectionId = Objects.requireNonNull(connectionId, "connectionId");
|
||||
this.codec = Objects.requireNonNull(codec, "codec");
|
||||
this.protocolMode = Objects.requireNonNull(protocolMode, "protocolMode");
|
||||
this.eventManager = Objects.requireNonNull(eventManager, "eventManager");
|
||||
this.tcpSocket = tcpSocket;
|
||||
this.tcpOut = tcpOut;
|
||||
this.tcpIn = tcpIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new TCP-accepted connection (TLS).
|
||||
*
|
||||
* @param codec packet codec
|
||||
* @param protocolMode server protocol mode (supported/required)
|
||||
* @param eventManager event manager used to dispatch server events
|
||||
* @param tcpSocket TLS socket
|
||||
* @param tcpOut TCP output stream
|
||||
* @param tcpIn TCP input stream
|
||||
* @return connection
|
||||
*/
|
||||
public static ClientConnection tcpAccepted(
|
||||
PacketCodec codec,
|
||||
ServerProtocolMode protocolMode,
|
||||
EventManager eventManager,
|
||||
SSLSocket tcpSocket,
|
||||
ObjectOutputStream tcpOut,
|
||||
ObjectInputStream tcpIn
|
||||
) {
|
||||
return new ClientConnection(
|
||||
UUID.randomUUID(),
|
||||
codec,
|
||||
protocolMode,
|
||||
eventManager,
|
||||
Objects.requireNonNull(tcpSocket, "tcpSocket"),
|
||||
Objects.requireNonNull(tcpOut, "tcpOut"),
|
||||
Objects.requireNonNull(tcpIn, "tcpIn")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new UDP-only connection.
|
||||
*
|
||||
* @param codec packet codec
|
||||
* @param protocolMode server protocol mode (supported/required)
|
||||
* @param eventManager event manager used to dispatch server events
|
||||
* @param connectionId pre-generated connection id
|
||||
* @return connection
|
||||
*/
|
||||
public static ClientConnection udpOnly(
|
||||
PacketCodec codec,
|
||||
ServerProtocolMode protocolMode,
|
||||
EventManager eventManager,
|
||||
UUID connectionId
|
||||
) {
|
||||
return new ClientConnection(
|
||||
Objects.requireNonNull(connectionId, "connectionId"),
|
||||
codec,
|
||||
protocolMode,
|
||||
eventManager,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a server-side unique connection id.
|
||||
*
|
||||
* @return connection id
|
||||
*/
|
||||
public UUID connectionId() {
|
||||
return connectionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns required protocols snapshot (server policy snapshot).
|
||||
*
|
||||
* @return required protocols
|
||||
*/
|
||||
public EnumSet<NetworkProtocol> requiredProtocols() {
|
||||
return protocolMode.required();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the TCP/TLS channel is currently connected.
|
||||
*
|
||||
* @return true if TCP connected
|
||||
*/
|
||||
public boolean isTcpConnected() {
|
||||
if (closed.get()) return false;
|
||||
SSLSocket s = tcpSocket;
|
||||
return s != null && !s.isClosed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the UDP/DTLS channel is currently connected and bound.
|
||||
*
|
||||
* @return true if UDP connected
|
||||
*/
|
||||
public boolean isUdpConnected() {
|
||||
if (closed.get()) return false;
|
||||
if (!udpBound) return false;
|
||||
if (udpRemote == null || dtlsEndpoint == null || udpSession == null) return false;
|
||||
return udpSession.isHandshakeComplete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this connection satisfies the server required protocol set.
|
||||
*
|
||||
* @return true if fully connected according to {@link ServerProtocolMode#required()}
|
||||
*/
|
||||
public boolean isFullyConnected() {
|
||||
EnumSet<NetworkProtocol> required = protocolMode.required();
|
||||
boolean tcpOk = !required.contains(NetworkProtocol.TCP) || isTcpConnected();
|
||||
boolean udpOk = !required.contains(NetworkProtocol.UDP) || isUdpConnected();
|
||||
return tcpOk && udpOk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently bound UDP remote, or null.
|
||||
*
|
||||
* @return udp remote
|
||||
*/
|
||||
public SocketAddress udpRemote() {
|
||||
return udpRemote;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether UDP is bound/acknowledged.
|
||||
*
|
||||
* @param udpBound bound flag
|
||||
*/
|
||||
public void setUdpBound(boolean udpBound) {
|
||||
this.udpBound = udpBound;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches the DTLS side (after bind/hello flow).
|
||||
*
|
||||
* @param udpRemote remote address
|
||||
* @param udpSession DTLS session
|
||||
* @param dtlsEndpoint DTLS endpoint
|
||||
* @param udpChannel UDP channel (server channel)
|
||||
*/
|
||||
public void attachUdp(
|
||||
SocketAddress udpRemote,
|
||||
DtlsEndpoint.DtlsSession udpSession,
|
||||
DtlsEndpoint dtlsEndpoint,
|
||||
DatagramChannel udpChannel
|
||||
) {
|
||||
this.udpRemote = Objects.requireNonNull(udpRemote, "udpRemote");
|
||||
this.udpSession = Objects.requireNonNull(udpSession, "udpSession");
|
||||
this.dtlsEndpoint = Objects.requireNonNull(dtlsEndpoint, "dtlsEndpoint");
|
||||
this.udpChannel = Objects.requireNonNull(udpChannel, "udpChannel");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a packet via the selected protocol (TCP/TLS or UDP/DTLS).
|
||||
*
|
||||
* <p>Emits:
|
||||
* <ul>
|
||||
* <li>{@link S_PacketSendEvent} on success</li>
|
||||
* <li>{@link S_PacketSendFailedEvent} on failure</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param packet packet to send
|
||||
* @param protocol protocol to use
|
||||
* @return true if sent, false if not possible/unsupported/not ready/closed
|
||||
* @throws IOException on I/O errors
|
||||
*/
|
||||
public boolean sendPacket(Packet packet, NetworkProtocol protocol) throws IOException {
|
||||
Objects.requireNonNull(packet, "packet");
|
||||
Objects.requireNonNull(protocol, "protocol");
|
||||
|
||||
if (closed.get()) return false;
|
||||
|
||||
try {
|
||||
boolean ok = switch (protocol) {
|
||||
case TCP -> sendTcp(packet);
|
||||
case UDP -> sendUdp(packet);
|
||||
};
|
||||
|
||||
if (ok) {
|
||||
eventManager.executeEvent(new S_PacketSendEvent(packet, this, protocol));
|
||||
} else {
|
||||
eventManager.executeEvent(new S_PacketSendFailedEvent(
|
||||
packet, this, protocol, new IllegalStateException("Packet not sent")
|
||||
));
|
||||
}
|
||||
|
||||
return ok;
|
||||
} catch (IOException | RuntimeException e) {
|
||||
eventManager.executeEvent(new S_PacketSendFailedEvent(packet, this, protocol, e));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives the next packet from the TCP stream.
|
||||
*
|
||||
* @return packet
|
||||
* @throws IOException on I/O errors
|
||||
* @throws ClassNotFoundException on deserialization errors
|
||||
*/
|
||||
public Packet receiveTcp() throws IOException, ClassNotFoundException {
|
||||
if (closed.get()) throw new IOException("Connection closed");
|
||||
if (tcpIn == null) throw new IOException("TCP not available for this connection");
|
||||
return codec.receiveFromStream(tcpIn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the TCP output stream (nullable).
|
||||
*
|
||||
* @return tcp output stream or null
|
||||
*/
|
||||
public ObjectOutputStream tcpOut() {
|
||||
return tcpOut;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the TCP input stream (nullable).
|
||||
*
|
||||
* @return tcp input stream or null
|
||||
*/
|
||||
public ObjectInputStream tcpIn() {
|
||||
return tcpIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this connection (TCP socket if present). UDP association is cleared.
|
||||
*
|
||||
* @throws IOException on close errors
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
if (!closed.compareAndSet(false, true)) return;
|
||||
|
||||
try {
|
||||
if (tcpOut != null) tcpOut.close();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
try {
|
||||
if (tcpIn != null) tcpIn.close();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
try {
|
||||
if (tcpSocket != null) tcpSocket.close();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
udpRemote = null;
|
||||
udpSession = null;
|
||||
dtlsEndpoint = null;
|
||||
udpChannel = null;
|
||||
udpBound = false;
|
||||
}
|
||||
|
||||
private boolean sendTcp(Packet packet) throws IOException {
|
||||
if (!isTcpConnected()) return false;
|
||||
if (tcpOut == null) return false;
|
||||
codec.sendToStream(packet, tcpOut);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean sendUdp(Packet packet) throws IOException {
|
||||
if (closed.get()) return false;
|
||||
|
||||
SocketAddress remote = udpRemote;
|
||||
DtlsEndpoint endpoint = dtlsEndpoint;
|
||||
if (remote == null || endpoint == null) return false;
|
||||
|
||||
// Allow sending bind/hello/ack even if udpBound==false (handshake must still be complete).
|
||||
DtlsEndpoint.DtlsSession s = udpSession;
|
||||
if (s == null || !s.isHandshakeComplete()) return false;
|
||||
|
||||
ByteBuffer buf = codec.encodeToBuffer(packet);
|
||||
endpoint.sendApplication(remote, buf);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,275 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.server;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.Packet;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.impl.ClientIDPacket;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.events.packets.receive.S_PacketReceivedEvent;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.events.packets.receive.S_PacketReceivedFailedEvent;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.events.packets.receive.S_UnknownObjectReceivedEvent;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.events.packets.send.S_PacketSendEvent;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.events.packets.send.S_PacketSendFailedEvent;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.events.state.connect.ConnectionHandlerConnectedEvent;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.events.state.disconnect.ConnectionHandlerDisconnectedEvent;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.events.state.disconnect.ConnectionHandlerFullyDisconnectedEvent;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.udp.DtlsEndpoint;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.udp.UdpPacketCodec;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.ClientID;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.Transport;
|
||||
|
||||
import javax.net.ssl.SSLSocket;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Handles one connected client socket and dispatches received packets.
|
||||
*
|
||||
* <p>Supports TCP (TLS) and UDP (DTLS). UDP is bound after TCP identity assignment.</p>
|
||||
*/
|
||||
public final class ConnectionHandler {
|
||||
|
||||
private final NetworkServer server;
|
||||
private final ClientID clientId;
|
||||
private final Thread receiveThread;
|
||||
private SSLSocket socket;
|
||||
private ObjectOutputStream outputStream;
|
||||
private ObjectInputStream inputStream;
|
||||
private volatile SocketAddress udpRemoteAddress;
|
||||
private volatile DtlsEndpoint.DtlsSession udpSession;
|
||||
private volatile DtlsEndpoint dtlsEndpoint;
|
||||
|
||||
/**
|
||||
* Creates a new connection handler for an already accepted SSL socket.
|
||||
*
|
||||
* @param server owning server
|
||||
* @param socket ssl socket
|
||||
* @param clientId server-assigned client identity
|
||||
* @throws IOException if stream creation fails
|
||||
* @throws ClassNotFoundException if packet serialization fails
|
||||
*/
|
||||
public ConnectionHandler(NetworkServer server, SSLSocket socket, ClientID clientId) throws IOException, ClassNotFoundException {
|
||||
this.server = Objects.requireNonNull(server, "server");
|
||||
this.socket = Objects.requireNonNull(socket, "socket");
|
||||
this.clientId = Objects.requireNonNull(clientId, "clientId");
|
||||
|
||||
this.outputStream = new ObjectOutputStream(socket.getOutputStream());
|
||||
this.inputStream = new ObjectInputStream(socket.getInputStream());
|
||||
|
||||
this.receiveThread = new Thread(this::receive, "ConnectionHandler-TCP-Receive-" + clientId.uuid());
|
||||
this.receiveThread.start();
|
||||
|
||||
// Send identity via TCP first.
|
||||
sendPacket(new ClientIDPacket(this.clientId), Transport.TCP);
|
||||
|
||||
// Transport-specific connect event (TCP)
|
||||
server.getEventManager().executeEvent(new ConnectionHandlerConnectedEvent(this, Transport.TCP));
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches a DTLS/UDP remote endpoint to this already TCP-authenticated connection.
|
||||
*
|
||||
* @param remote remote UDP address
|
||||
* @param session DTLS session for the remote
|
||||
* @param endpoint DTLS endpoint
|
||||
*/
|
||||
public void attachUdp(SocketAddress remote, DtlsEndpoint.DtlsSession session, DtlsEndpoint endpoint) {
|
||||
this.udpRemoteAddress = Objects.requireNonNull(remote, "remote");
|
||||
this.udpSession = Objects.requireNonNull(session, "session");
|
||||
this.dtlsEndpoint = Objects.requireNonNull(endpoint, "endpoint");
|
||||
|
||||
// Transport-specific connect event (UDP)
|
||||
server.getEventManager().executeEvent(new ConnectionHandlerConnectedEvent(this, Transport.UDP));
|
||||
}
|
||||
|
||||
public SocketAddress getUdpRemoteAddress() {
|
||||
return udpRemoteAddress;
|
||||
}
|
||||
|
||||
public boolean isUdpAttached() {
|
||||
return udpRemoteAddress != null && udpSession != null && udpSession.isHandshakeComplete();
|
||||
}
|
||||
|
||||
public boolean isFullyConnected() {
|
||||
boolean tcpOk = isConnected();
|
||||
boolean udpOk = isUdpAttached();
|
||||
|
||||
if (server.getTransportPolicy().required().contains(Transport.TCP) && !tcpOk) return false;
|
||||
return !server.getTransportPolicy().required().contains(Transport.UDP) || udpOk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof ConnectionHandler other)) return false;
|
||||
return clientId.equals(other.clientId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return clientId.hashCode();
|
||||
}
|
||||
|
||||
public SSLSocket getSocket() {
|
||||
return socket;
|
||||
}
|
||||
|
||||
public ObjectOutputStream getOutputStream() {
|
||||
return outputStream;
|
||||
}
|
||||
|
||||
public ObjectInputStream getInputStream() {
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
public NetworkServer getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public ClientID getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
return socket != null && socket.isConnected() && !socket.isClosed()
|
||||
&& receiveThread.isAlive() && !receiveThread.isInterrupted();
|
||||
}
|
||||
|
||||
public synchronized boolean disconnect() {
|
||||
boolean wasTcpConnected = isConnected();
|
||||
boolean wasUdpConnected = isUdpAttached();
|
||||
boolean wasFullyConnected = isFullyConnected();
|
||||
|
||||
if (!wasTcpConnected && !wasUdpConnected) {
|
||||
// still cleanup
|
||||
cleanup();
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
receiveThread.interrupt();
|
||||
|
||||
if (outputStream != null) outputStream.close();
|
||||
if (inputStream != null) inputStream.close();
|
||||
if (socket != null) socket.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
|
||||
// Emit transport-specific disconnect events
|
||||
if (wasUdpConnected) {
|
||||
server.getEventManager().executeEvent(new ConnectionHandlerDisconnectedEvent(this, Transport.UDP));
|
||||
}
|
||||
if (wasTcpConnected) {
|
||||
server.getEventManager().executeEvent(new ConnectionHandlerDisconnectedEvent(this, Transport.TCP));
|
||||
}
|
||||
|
||||
cleanup();
|
||||
|
||||
if (wasFullyConnected) {
|
||||
server.getEventManager().executeEvent(new ConnectionHandlerFullyDisconnectedEvent(
|
||||
this,
|
||||
server.getTransportPolicy().required().toArray(new Transport[0])
|
||||
));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void cleanup() {
|
||||
socket = null;
|
||||
outputStream = null;
|
||||
inputStream = null;
|
||||
|
||||
udpRemoteAddress = null;
|
||||
udpSession = null;
|
||||
dtlsEndpoint = null;
|
||||
|
||||
server.getConnectionHandlers().remove(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a packet via the selected transport.
|
||||
*
|
||||
* @param packet packet to send
|
||||
* @param transport target transport
|
||||
* @return true if sent, false if not possible
|
||||
* @throws IOException on I/O errors
|
||||
* @throws ClassNotFoundException on serialization errors
|
||||
*/
|
||||
public boolean sendPacket(Packet packet, Transport transport) throws IOException, ClassNotFoundException {
|
||||
Objects.requireNonNull(packet, "packet");
|
||||
Objects.requireNonNull(transport, "transport");
|
||||
|
||||
if (!server.getTransportPolicy().supported().contains(transport)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return switch (transport) {
|
||||
case TCP -> sendTcp(packet);
|
||||
case UDP -> sendUdp(packet);
|
||||
};
|
||||
}
|
||||
|
||||
private boolean sendTcp(Packet packet) throws IOException, ClassNotFoundException {
|
||||
if (!isConnected()) return false;
|
||||
|
||||
boolean sent = server.getPacketHandler().sendPacket(packet, outputStream);
|
||||
if (sent) server.getEventManager().executeEvent(new S_PacketSendEvent(packet, this, Transport.TCP));
|
||||
else server.getEventManager().executeEvent(new S_PacketSendFailedEvent(packet, this, Transport.TCP));
|
||||
return sent;
|
||||
}
|
||||
|
||||
private boolean sendUdp(Packet packet) throws IOException, ClassNotFoundException {
|
||||
if (!isUdpAttached()) return false;
|
||||
|
||||
DtlsEndpoint endpoint = dtlsEndpoint;
|
||||
if (endpoint == null) return false;
|
||||
|
||||
ByteBuffer encoded = UdpPacketCodec.encode(server.getPacketHandler(), packet);
|
||||
endpoint.sendApplication(udpRemoteAddress, encoded);
|
||||
|
||||
server.getEventManager().executeEvent(new S_PacketSendEvent(packet, this, Transport.UDP));
|
||||
return true;
|
||||
}
|
||||
|
||||
private void receive() {
|
||||
while (isConnected()) {
|
||||
try {
|
||||
Object received = inputStream.readObject();
|
||||
|
||||
if (received instanceof Integer id) {
|
||||
if (server.getPacketHandler().isPacketIDRegistered(id)) {
|
||||
Packet packet = server.getPacketHandler().getPacketByID(id);
|
||||
|
||||
boolean ok = server.getPacketHandler().handlePacket(id, packet, inputStream);
|
||||
if (ok)
|
||||
server.getEventManager().executeEvent(new S_PacketReceivedEvent(this, packet, Transport.TCP));
|
||||
else
|
||||
server.getEventManager().executeEvent(new S_PacketReceivedFailedEvent(this, packet, Transport.TCP));
|
||||
} else {
|
||||
server.getEventManager().executeEvent(new S_UnknownObjectReceivedEvent(received, this, Transport.TCP));
|
||||
}
|
||||
} else {
|
||||
server.getEventManager().executeEvent(new S_UnknownObjectReceivedEvent(received, this, Transport.TCP));
|
||||
}
|
||||
} catch (SocketException se) {
|
||||
disconnect();
|
||||
} catch (Exception ex) {
|
||||
if (server.getLogger() != null) {
|
||||
server.getLogger().exception("Receive thread exception for client " + clientId, ex);
|
||||
}
|
||||
disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.server;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.Packet;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.impl.UdpBindPacket;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.events.state.connect.ConnectionHandlerFullyConnectedEvent;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.events.packets.receive.S_PacketReceivedEvent;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.udp.DtlsEndpoint;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.udp.UdpPacketCodec;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.Transport;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Helper methods for server-side DTLS/UDP handling.
|
||||
*
|
||||
* <p>Drop this into your NetworkServer class (replace your existing onDtlsApplicationData).</p>
|
||||
*/
|
||||
final class NetworkServerUdpHooks {
|
||||
|
||||
private NetworkServerUdpHooks() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes decrypted DTLS application data.
|
||||
*
|
||||
* @param server server
|
||||
* @param remote remote address
|
||||
* @param data decrypted data
|
||||
*/
|
||||
static void onDtlsApplicationData(NetworkServer server, SocketAddress remote, ByteBuffer data) {
|
||||
Objects.requireNonNull(server, "server");
|
||||
Objects.requireNonNull(remote, "remote");
|
||||
Objects.requireNonNull(data, "data");
|
||||
|
||||
try {
|
||||
Packet decoded = UdpPacketCodec.decodeAndHandle(server.getPacketHandler(), data);
|
||||
if (decoded == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (decoded instanceof UdpBindPacket bind) {
|
||||
// Bind remote to existing TCP handler
|
||||
ConnectionHandler handler = server.getConnectionHandlerByClientId(bind.getClientId());
|
||||
if (handler == null) {
|
||||
return;
|
||||
}
|
||||
if (!handler.isConnected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DtlsEndpoint endpoint = server.getDtlsEndpoint();
|
||||
if (endpoint == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean wasFullyConnected = handler.isFullyConnected();
|
||||
handler.attachUdp(remote, endpoint.session(remote), endpoint);
|
||||
boolean nowFullyConnected = handler.isFullyConnected();
|
||||
|
||||
if (!wasFullyConnected && nowFullyConnected) {
|
||||
server.getEventManager().executeEvent(
|
||||
new ConnectionHandlerFullyConnectedEvent(handler, server.getTransportPolicy().required().toArray(new Transport[0]))
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// For normal UDP packets: route to the bound handler (if any)
|
||||
ConnectionHandler bound = server.findHandlerByUdpRemote(remote);
|
||||
if (bound != null) {
|
||||
server.getEventManager().executeEvent(new S_PacketReceivedEvent(bound, decoded, Transport.UDP));
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
// best effort: drop
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.server;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.NetworkProtocol;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Defines which network protocols a server requires for a connection to be considered usable.
|
||||
*
|
||||
* <p><strong>Note:</strong> This model exposes only {@link #required()}.
|
||||
* Therefore, "optional protocols" are not representable here. If you need optional transports,
|
||||
* the model must include a separate supported-set.</p>
|
||||
*/
|
||||
public final class ServerProtocolMode {
|
||||
|
||||
private final EnumSet<NetworkProtocol> required;
|
||||
|
||||
private ServerProtocolMode(EnumSet<NetworkProtocol> required) {
|
||||
this.required = EnumSet.copyOf(Objects.requireNonNull(required, "required"));
|
||||
if (this.required.isEmpty()) {
|
||||
throw new IllegalArgumentException("required must not be empty");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns required protocols.
|
||||
*
|
||||
* @return required protocols
|
||||
*/
|
||||
public EnumSet<NetworkProtocol> required() {
|
||||
return EnumSet.copyOf(required);
|
||||
}
|
||||
|
||||
/**
|
||||
* Server requires TCP only.
|
||||
*
|
||||
* @return mode
|
||||
*/
|
||||
public static ServerProtocolMode tcpOnly() {
|
||||
return new ServerProtocolMode(EnumSet.of(NetworkProtocol.TCP));
|
||||
}
|
||||
|
||||
/**
|
||||
* Server requires UDP only.
|
||||
*
|
||||
* @return mode
|
||||
*/
|
||||
public static ServerProtocolMode udpOnly() {
|
||||
return new ServerProtocolMode(EnumSet.of(NetworkProtocol.UDP));
|
||||
}
|
||||
|
||||
/**
|
||||
* Server requires both TCP and UDP.
|
||||
*
|
||||
* @return mode
|
||||
*/
|
||||
public static ServerProtocolMode bothRequired() {
|
||||
return new ServerProtocolMode(EnumSet.of(NetworkProtocol.TCP, NetworkProtocol.UDP));
|
||||
}
|
||||
}
|
||||
@@ -6,52 +6,61 @@
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.server.events.packets.receive;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.Packet;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.ConnectionHandler;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.Transport;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.NetworkProtocol;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.ClientConnection;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Fired when a packet was received on the server on a specific transport.
|
||||
* Fired when a packet was received on the server on a specific protocol.
|
||||
*/
|
||||
public final class S_PacketReceivedEvent extends Event {
|
||||
|
||||
private final ConnectionHandler connectionHandler;
|
||||
private final ClientConnection connection;
|
||||
private final Packet packet;
|
||||
private final Transport transport;
|
||||
private final NetworkProtocol protocol;
|
||||
|
||||
/**
|
||||
* Creates a new packet received event.
|
||||
*
|
||||
* @param connectionHandler handler
|
||||
* @param packet packet
|
||||
* @param transport transport used
|
||||
* @param connection connection
|
||||
* @param packet packet
|
||||
* @param protocol protocol used
|
||||
*/
|
||||
public S_PacketReceivedEvent(ConnectionHandler connectionHandler, Packet packet, Transport transport) {
|
||||
this.connectionHandler = connectionHandler;
|
||||
this.packet = packet;
|
||||
this.transport = transport;
|
||||
public S_PacketReceivedEvent(ClientConnection connection, Packet packet, NetworkProtocol protocol) {
|
||||
this.connection = Objects.requireNonNull(connection, "connection");
|
||||
this.packet = Objects.requireNonNull(packet, "packet");
|
||||
this.protocol = Objects.requireNonNull(protocol, "protocol");
|
||||
}
|
||||
|
||||
public ConnectionHandler getConnectionHandler() {
|
||||
return connectionHandler;
|
||||
/**
|
||||
* Returns the connection.
|
||||
*
|
||||
* @return connection
|
||||
*/
|
||||
public ClientConnection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the packet.
|
||||
*
|
||||
* @return packet
|
||||
*/
|
||||
public Packet getPacket() {
|
||||
return packet;
|
||||
}
|
||||
|
||||
public Transport getTransport() {
|
||||
return transport;
|
||||
/**
|
||||
* Returns the protocol the packet was received on.
|
||||
*
|
||||
* @return protocol
|
||||
*/
|
||||
public NetworkProtocol getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,52 +6,78 @@
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.server.events.packets.receive;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.Packet;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.ConnectionHandler;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.Transport;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.NetworkProtocol;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.ClientConnection;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Fired when a packet receive failed on the server on a specific transport.
|
||||
* Fired when receiving or decoding a packet failed on the server for a specific protocol.
|
||||
*/
|
||||
public final class S_PacketReceivedFailedEvent extends Event {
|
||||
|
||||
private final ConnectionHandler connectionHandler;
|
||||
private final ClientConnection connection;
|
||||
private final Packet packet;
|
||||
private final Transport transport;
|
||||
private final NetworkProtocol protocol;
|
||||
private final Exception error;
|
||||
|
||||
/**
|
||||
* Creates a new packet receive failed event.
|
||||
*
|
||||
* @param connectionHandler handler
|
||||
* @param packet packet
|
||||
* @param transport transport used
|
||||
* @param connection connection (may be null if not attributable)
|
||||
* @param packet packet that failed to be processed (may be null if undecodable)
|
||||
* @param protocol protocol the failure happened on
|
||||
* @param error root cause
|
||||
*/
|
||||
public S_PacketReceivedFailedEvent(ConnectionHandler connectionHandler, Packet packet, Transport transport) {
|
||||
this.connectionHandler = connectionHandler;
|
||||
this.packet = packet;
|
||||
this.transport = transport;
|
||||
public S_PacketReceivedFailedEvent(
|
||||
ClientConnection connection,
|
||||
Packet packet,
|
||||
NetworkProtocol protocol,
|
||||
Exception error
|
||||
) {
|
||||
this.connection = connection; // may be null
|
||||
this.packet = packet; // may be null
|
||||
this.protocol = Objects.requireNonNull(protocol, "protocol");
|
||||
this.error = Objects.requireNonNull(error, "error");
|
||||
}
|
||||
|
||||
public ConnectionHandler getConnectionHandler() {
|
||||
return connectionHandler;
|
||||
/**
|
||||
* Returns the connection, if attributable.
|
||||
*
|
||||
* @return connection or null
|
||||
*/
|
||||
public ClientConnection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the packet that failed to be processed, if available.
|
||||
*
|
||||
* @return packet or null
|
||||
*/
|
||||
public Packet getPacket() {
|
||||
return packet;
|
||||
}
|
||||
|
||||
public Transport getTransport() {
|
||||
return transport;
|
||||
/**
|
||||
* Returns the protocol the failure occurred on.
|
||||
*
|
||||
* @return protocol
|
||||
*/
|
||||
public NetworkProtocol getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying error.
|
||||
*
|
||||
* @return error
|
||||
*/
|
||||
public Exception getError() {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,51 +6,65 @@
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.server.events.packets.receive;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.ConnectionHandler;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.Transport;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.Packet;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.NetworkProtocol;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.ClientConnection;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Fired when an unknown object was received on a specific transport.
|
||||
* Fired when an unknown (non-packet) object was received on a specific protocol.
|
||||
*
|
||||
* <p>In v2 the default transport uses {@link dev.unlegitdqrk.unlegitlibrary.network.system.packets.PacketCodec}
|
||||
* and usually yields {@link Packet}. This event is kept
|
||||
* for custom/legacy decoding paths.</p>
|
||||
*/
|
||||
public final class S_UnknownObjectReceivedEvent extends Event {
|
||||
|
||||
private final Object received;
|
||||
private final ConnectionHandler connectionHandler;
|
||||
private final Transport transport;
|
||||
private final ClientConnection connection;
|
||||
private final NetworkProtocol protocol;
|
||||
|
||||
/**
|
||||
* Creates a new event.
|
||||
*
|
||||
* @param received received object
|
||||
* @param connectionHandler handler
|
||||
* @param transport transport
|
||||
* @param received received object
|
||||
* @param connection connection (may be null if not attributable)
|
||||
* @param protocol protocol
|
||||
*/
|
||||
public S_UnknownObjectReceivedEvent(Object received, ConnectionHandler connectionHandler, Transport transport) {
|
||||
this.received = received;
|
||||
this.connectionHandler = connectionHandler;
|
||||
this.transport = transport;
|
||||
public S_UnknownObjectReceivedEvent(Object received, ClientConnection connection, NetworkProtocol protocol) {
|
||||
this.received = Objects.requireNonNull(received, "received");
|
||||
this.connection = connection; // may be null
|
||||
this.protocol = Objects.requireNonNull(protocol, "protocol");
|
||||
}
|
||||
|
||||
public ConnectionHandler getConnectionHandler() {
|
||||
return connectionHandler;
|
||||
/**
|
||||
* Returns the connection, if attributable.
|
||||
*
|
||||
* @return connection or null
|
||||
*/
|
||||
public ClientConnection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the received object.
|
||||
*
|
||||
* @return received object
|
||||
*/
|
||||
public Object getReceived() {
|
||||
return received;
|
||||
}
|
||||
|
||||
public Transport getTransport() {
|
||||
return transport;
|
||||
/**
|
||||
* Returns the protocol.
|
||||
*
|
||||
* @return protocol
|
||||
*/
|
||||
public NetworkProtocol getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,52 +6,61 @@
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.server.events.packets.send;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.Packet;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.ConnectionHandler;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.Transport;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.NetworkProtocol;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.ClientConnection;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Fired when a packet was sent by the server on a specific transport.
|
||||
* Fired when a packet was successfully sent by the server on a specific protocol.
|
||||
*/
|
||||
public final class S_PacketSendEvent extends Event {
|
||||
|
||||
private final Packet packet;
|
||||
private final ConnectionHandler connectionHandler;
|
||||
private final Transport transport;
|
||||
private final ClientConnection connection;
|
||||
private final NetworkProtocol protocol;
|
||||
|
||||
/**
|
||||
* Creates a new packet send event.
|
||||
*
|
||||
* @param packet packet
|
||||
* @param connectionHandler handler
|
||||
* @param transport transport used
|
||||
* @param packet packet
|
||||
* @param connection connection
|
||||
* @param protocol protocol used
|
||||
*/
|
||||
public S_PacketSendEvent(Packet packet, ConnectionHandler connectionHandler, Transport transport) {
|
||||
this.packet = packet;
|
||||
this.connectionHandler = connectionHandler;
|
||||
this.transport = transport;
|
||||
public S_PacketSendEvent(Packet packet, ClientConnection connection, NetworkProtocol protocol) {
|
||||
this.packet = Objects.requireNonNull(packet, "packet");
|
||||
this.connection = Objects.requireNonNull(connection, "connection");
|
||||
this.protocol = Objects.requireNonNull(protocol, "protocol");
|
||||
}
|
||||
|
||||
public ConnectionHandler getConnectionHandler() {
|
||||
return connectionHandler;
|
||||
/**
|
||||
* Returns the connection.
|
||||
*
|
||||
* @return connection
|
||||
*/
|
||||
public ClientConnection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the packet.
|
||||
*
|
||||
* @return packet
|
||||
*/
|
||||
public Packet getPacket() {
|
||||
return packet;
|
||||
}
|
||||
|
||||
public Transport getTransport() {
|
||||
return transport;
|
||||
/**
|
||||
* Returns the protocol used.
|
||||
*
|
||||
* @return protocol
|
||||
*/
|
||||
public NetworkProtocol getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,52 +6,78 @@
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.server.events.packets.send;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.Packet;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.ConnectionHandler;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.Transport;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.NetworkProtocol;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.ClientConnection;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Fired when a packet send failed on the server on a specific transport.
|
||||
* Fired when a packet send failed on the server on a specific protocol.
|
||||
*/
|
||||
public final class S_PacketSendFailedEvent extends Event {
|
||||
|
||||
private final Packet packet;
|
||||
private final ConnectionHandler connectionHandler;
|
||||
private final Transport transport;
|
||||
private final ClientConnection connection;
|
||||
private final NetworkProtocol protocol;
|
||||
private final Exception error;
|
||||
|
||||
/**
|
||||
* Creates a new packet send failed event.
|
||||
*
|
||||
* @param packet packet
|
||||
* @param connectionHandler handler
|
||||
* @param transport intended transport
|
||||
* @param packet packet that failed to be sent
|
||||
* @param connection connection
|
||||
* @param protocol intended protocol
|
||||
* @param error root cause
|
||||
*/
|
||||
public S_PacketSendFailedEvent(Packet packet, ConnectionHandler connectionHandler, Transport transport) {
|
||||
this.packet = packet;
|
||||
this.connectionHandler = connectionHandler;
|
||||
this.transport = transport;
|
||||
public S_PacketSendFailedEvent(
|
||||
Packet packet,
|
||||
ClientConnection connection,
|
||||
NetworkProtocol protocol,
|
||||
Exception error
|
||||
) {
|
||||
this.packet = Objects.requireNonNull(packet, "packet");
|
||||
this.connection = Objects.requireNonNull(connection, "connection");
|
||||
this.protocol = Objects.requireNonNull(protocol, "protocol");
|
||||
this.error = Objects.requireNonNull(error, "error");
|
||||
}
|
||||
|
||||
public ConnectionHandler getConnectionHandler() {
|
||||
return connectionHandler;
|
||||
/**
|
||||
* Returns the connection.
|
||||
*
|
||||
* @return connection
|
||||
*/
|
||||
public ClientConnection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the packet.
|
||||
*
|
||||
* @return packet
|
||||
*/
|
||||
public Packet getPacket() {
|
||||
return packet;
|
||||
}
|
||||
|
||||
public Transport getTransport() {
|
||||
return transport;
|
||||
/**
|
||||
* Returns the intended protocol.
|
||||
*
|
||||
* @return protocol
|
||||
*/
|
||||
public NetworkProtocol getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying error.
|
||||
*
|
||||
* @return error
|
||||
*/
|
||||
public Exception getError() {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.server.events.state.connect;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.NetworkProtocol;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.ClientConnection;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Fired when a specific protocol becomes connected for a server-side connection.
|
||||
*
|
||||
* <p>Protocol-specific:
|
||||
* <ul>
|
||||
* <li>{@link NetworkProtocol#TCP}: connection created after TLS handshake</li>
|
||||
* <li>{@link NetworkProtocol#UDP}: connection received valid UDP bind and attached DTLS session</li>
|
||||
* </ul>
|
||||
*/
|
||||
public final class ClientConnectionConnectedEvent extends Event {
|
||||
|
||||
private final ClientConnection connection;
|
||||
private final NetworkProtocol protocol;
|
||||
|
||||
/**
|
||||
* Creates a new connection connected event.
|
||||
*
|
||||
* @param connection connection
|
||||
* @param protocol connected protocol
|
||||
*/
|
||||
public ClientConnectionConnectedEvent(ClientConnection connection, NetworkProtocol protocol) {
|
||||
this.connection = Objects.requireNonNull(connection, "connection");
|
||||
this.protocol = Objects.requireNonNull(protocol, "protocol");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the connection.
|
||||
*
|
||||
* @return connection
|
||||
*/
|
||||
public ClientConnection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the protocol that was connected.
|
||||
*
|
||||
* @return protocol
|
||||
*/
|
||||
public NetworkProtocol getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.server.events.state.connect;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.NetworkProtocol;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.ClientConnection;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Fired when a connection satisfies the server protocol requirements.
|
||||
*
|
||||
* <p>In v2 this typically means:
|
||||
* <ul>
|
||||
* <li>TCP is connected (TLS ok)</li>
|
||||
* <li>and if UDP is enabled: DTLS is established and the bind flow is completed</li>
|
||||
* </ul>
|
||||
*/
|
||||
public final class ClientConnectionFullyConnectedEvent extends Event {
|
||||
|
||||
private final ClientConnection connection;
|
||||
private final EnumSet<NetworkProtocol> requiredProtocols;
|
||||
|
||||
/**
|
||||
* Creates a new event.
|
||||
*
|
||||
* @param connection connection
|
||||
* @param requiredProtocols required protocols now established
|
||||
*/
|
||||
public ClientConnectionFullyConnectedEvent(ClientConnection connection, EnumSet<NetworkProtocol> requiredProtocols) {
|
||||
this.connection = Objects.requireNonNull(connection, "connection");
|
||||
this.requiredProtocols = EnumSet.copyOf(Objects.requireNonNull(requiredProtocols, "requiredProtocols"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the connection.
|
||||
*
|
||||
* @return connection
|
||||
*/
|
||||
public ClientConnection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the required protocols that are now established.
|
||||
*
|
||||
* @return required protocols (copy)
|
||||
*/
|
||||
public EnumSet<NetworkProtocol> getRequiredProtocols() {
|
||||
return EnumSet.copyOf(requiredProtocols);
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.server.events.state.connect;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.ConnectionHandler;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.Transport;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Fired when a specific transport becomes connected for a handler.
|
||||
*
|
||||
* <p>Transport-specific:
|
||||
* <ul>
|
||||
* <li>{@link Transport#TCP}: handler created after TLS handshake</li>
|
||||
* <li>{@link Transport#UDP}: handler received valid UDP bind and attached DTLS session</li>
|
||||
* </ul>
|
||||
*/
|
||||
public final class ConnectionHandlerConnectedEvent extends Event {
|
||||
|
||||
private final ConnectionHandler connectionHandler;
|
||||
private final Transport transport;
|
||||
|
||||
/**
|
||||
* Creates a new handler connected event.
|
||||
*
|
||||
* @param connectionHandler handler
|
||||
* @param transport connected transport
|
||||
*/
|
||||
public ConnectionHandlerConnectedEvent(ConnectionHandler connectionHandler, Transport transport) {
|
||||
this.connectionHandler = Objects.requireNonNull(connectionHandler, "connectionHandler");
|
||||
this.transport = Objects.requireNonNull(transport, "transport");
|
||||
}
|
||||
|
||||
public ConnectionHandler getConnectionHandler() {
|
||||
return connectionHandler;
|
||||
}
|
||||
|
||||
public Transport getTransport() {
|
||||
return transport;
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.server.events.state.connect;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.ConnectionHandler;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.Transport;
|
||||
|
||||
/**
|
||||
* Fired when a connection handler satisfies the server transport policy.
|
||||
*
|
||||
* <p>For your setup this means: TCP connected and UDP (DTLS) bound.</p>
|
||||
*/
|
||||
public final class ConnectionHandlerFullyConnectedEvent extends Event {
|
||||
|
||||
private final ConnectionHandler connectionHandler;
|
||||
private final Transport[] requiredTransports;
|
||||
|
||||
/**
|
||||
* Creates a new event.
|
||||
*
|
||||
* @param connectionHandler handler
|
||||
* @param requiredTransports required transports now established
|
||||
*/
|
||||
public ConnectionHandlerFullyConnectedEvent(ConnectionHandler connectionHandler, Transport[] requiredTransports) {
|
||||
this.connectionHandler = connectionHandler;
|
||||
this.requiredTransports = requiredTransports;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the handler.
|
||||
*
|
||||
* @return handler
|
||||
*/
|
||||
public ConnectionHandler getConnectionHandler() {
|
||||
return connectionHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the required transports that are now established.
|
||||
*
|
||||
* @return transports
|
||||
*/
|
||||
public Transport[] getRequiredTransports() {
|
||||
return requiredTransports;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.server.events.state.disconnect;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.NetworkProtocol;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.ClientConnection;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Fired when a specific protocol becomes disconnected for a server-side connection.
|
||||
*/
|
||||
public final class ClientConnectionDisconnectedEvent extends Event {
|
||||
|
||||
private final ClientConnection connection;
|
||||
private final NetworkProtocol protocol;
|
||||
|
||||
/**
|
||||
* Creates a new connection disconnected event.
|
||||
*
|
||||
* @param connection connection
|
||||
* @param protocol disconnected protocol
|
||||
*/
|
||||
public ClientConnectionDisconnectedEvent(ClientConnection connection, NetworkProtocol protocol) {
|
||||
this.connection = Objects.requireNonNull(connection, "connection");
|
||||
this.protocol = Objects.requireNonNull(protocol, "protocol");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the connection.
|
||||
*
|
||||
* @return connection
|
||||
*/
|
||||
public ClientConnection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the protocol that was disconnected.
|
||||
*
|
||||
* @return protocol
|
||||
*/
|
||||
public NetworkProtocol getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.server.events.state.disconnect;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.NetworkProtocol;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.ClientConnection;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Fired when a connection was fully connected and then became fully disconnected
|
||||
* (i.e., it no longer satisfies the required protocols).
|
||||
*/
|
||||
public final class ClientConnectionFullyDisconnectedEvent extends Event {
|
||||
|
||||
private final ClientConnection connection;
|
||||
private final EnumSet<NetworkProtocol> requiredProtocols;
|
||||
|
||||
/**
|
||||
* Creates a new fully disconnected event.
|
||||
*
|
||||
* @param connection connection
|
||||
* @param requiredProtocols required protocols according to policy
|
||||
*/
|
||||
public ClientConnectionFullyDisconnectedEvent(ClientConnection connection, EnumSet<NetworkProtocol> requiredProtocols) {
|
||||
this.connection = Objects.requireNonNull(connection, "connection");
|
||||
this.requiredProtocols = EnumSet.copyOf(Objects.requireNonNull(requiredProtocols, "requiredProtocols"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the connection.
|
||||
*
|
||||
* @return connection
|
||||
*/
|
||||
public ClientConnection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the protocols that were required for full connectivity.
|
||||
*
|
||||
* @return required protocols (copy)
|
||||
*/
|
||||
public EnumSet<NetworkProtocol> getRequiredProtocols() {
|
||||
return EnumSet.copyOf(requiredProtocols);
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.server.events.state.disconnect;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.ConnectionHandler;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.Transport;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Fired when a specific transport becomes disconnected for a handler.
|
||||
*/
|
||||
public final class ConnectionHandlerDisconnectedEvent extends Event {
|
||||
|
||||
private final ConnectionHandler connectionHandler;
|
||||
private final Transport transport;
|
||||
|
||||
/**
|
||||
* Creates a new handler disconnected event.
|
||||
*
|
||||
* @param connectionHandler handler
|
||||
* @param transport disconnected transport
|
||||
*/
|
||||
public ConnectionHandlerDisconnectedEvent(ConnectionHandler connectionHandler, Transport transport) {
|
||||
this.connectionHandler = Objects.requireNonNull(connectionHandler, "connectionHandler");
|
||||
this.transport = Objects.requireNonNull(transport, "transport");
|
||||
}
|
||||
|
||||
public ConnectionHandler getConnectionHandler() {
|
||||
return connectionHandler;
|
||||
}
|
||||
|
||||
public Transport getTransport() {
|
||||
return transport;
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.server.events.state.disconnect;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.ConnectionHandler;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.Transport;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Fired when a handler was fully connected and then became fully disconnected.
|
||||
*
|
||||
* <p>For your policy (TCP+UDP required) this means:
|
||||
* previously: TCP connected and UDP attached,
|
||||
* now: requirements are no longer satisfied.</p>
|
||||
*/
|
||||
public final class ConnectionHandlerFullyDisconnectedEvent extends Event {
|
||||
|
||||
private final ConnectionHandler connectionHandler;
|
||||
private final Transport[] requiredTransports;
|
||||
|
||||
/**
|
||||
* Creates a new fully disconnected event.
|
||||
*
|
||||
* @param connectionHandler handler
|
||||
* @param requiredTransports required transports according to policy
|
||||
*/
|
||||
public ConnectionHandlerFullyDisconnectedEvent(ConnectionHandler connectionHandler, Transport[] requiredTransports) {
|
||||
this.connectionHandler = Objects.requireNonNull(connectionHandler, "connectionHandler");
|
||||
this.requiredTransports = Objects.requireNonNull(requiredTransports, "requiredTransports");
|
||||
}
|
||||
|
||||
public ConnectionHandler getConnectionHandler() {
|
||||
return connectionHandler;
|
||||
}
|
||||
|
||||
public Transport[] getRequiredTransports() {
|
||||
return requiredTransports;
|
||||
}
|
||||
}
|
||||
@@ -10,22 +10,21 @@ package dev.unlegitdqrk.unlegitlibrary.network.system.server.events.state.incomi
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.CancellableEvent;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.NetworkServer;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.Transport;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.NetworkProtocol;
|
||||
|
||||
import javax.net.ssl.SSLSocket;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Fired when an incoming connection attempt reaches the server.
|
||||
* Fired when an incoming TCP/TLS connection attempt reaches the server.
|
||||
*
|
||||
* <p>Currently this event is emitted for TCP/TLS accept only (because UDP/DTLS is bound later via {@code UdpBindPacket}).
|
||||
* The {@link #getTransport()} field exists to keep the event model transport-aware and future-proof.</p>
|
||||
* <p>This event is emitted for TCP/TLS accept only. UDP/DTLS is bound later via the bind flow.</p>
|
||||
*/
|
||||
public final class TCPIncomingConnectionEvent extends CancellableEvent {
|
||||
|
||||
private final NetworkServer server;
|
||||
private final SSLSocket socket;
|
||||
private final Transport transport = Transport.TCP;
|
||||
private final NetworkProtocol protocol = NetworkProtocol.TCP;
|
||||
|
||||
/**
|
||||
* Creates a new incoming connection event.
|
||||
@@ -57,11 +56,11 @@ public final class TCPIncomingConnectionEvent extends CancellableEvent {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the transport associated with this incoming connection.
|
||||
* Returns the protocol associated with this incoming connection.
|
||||
*
|
||||
* @return transport
|
||||
* @return {@link NetworkProtocol#TCP}
|
||||
*/
|
||||
public Transport getTransport() {
|
||||
return transport;
|
||||
public NetworkProtocol getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,21 +10,20 @@ package dev.unlegitdqrk.unlegitlibrary.network.system.server.events.state.incomi
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.event.impl.CancellableEvent;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.NetworkServer;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.Transport;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.utils.NetworkProtocol;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Fired when an incoming UDP/DTLS datagram is received by the server
|
||||
* <b>before</b> it is bound to a {@link dev.unlegitdqrk.unlegitlibrary.network.system.server.ConnectionHandler}.
|
||||
* Fired when an incoming UDP datagram is received by the server before it is bound to a connection.
|
||||
*
|
||||
* <p>This event allows inspection or rejection of:
|
||||
* <ul>
|
||||
* <li>DTLS handshake traffic</li>
|
||||
* <li>{@code UdpBindPacket}</li>
|
||||
* <li>Any unbound UDP packet</li>
|
||||
* <li>bind packets</li>
|
||||
* <li>any unbound UDP packet</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>If cancelled, the datagram is silently dropped.</p>
|
||||
@@ -34,14 +33,14 @@ public final class UDPIncomingConnectionEvent extends CancellableEvent {
|
||||
private final NetworkServer server;
|
||||
private final SocketAddress remoteAddress;
|
||||
private final ByteBuffer rawData;
|
||||
private final Transport transport = Transport.UDP;
|
||||
private final NetworkProtocol protocol = NetworkProtocol.UDP;
|
||||
|
||||
/**
|
||||
* Creates a new incoming UDP connection/datagram event.
|
||||
* Creates a new incoming UDP datagram event.
|
||||
*
|
||||
* @param server server instance
|
||||
* @param remoteAddress remote UDP address
|
||||
* @param rawData raw received datagram (read-only duplicate recommended)
|
||||
* @param rawData raw received datagram (a read-only copy will be stored)
|
||||
*/
|
||||
public UDPIncomingConnectionEvent(
|
||||
NetworkServer server,
|
||||
@@ -74,7 +73,7 @@ public final class UDPIncomingConnectionEvent extends CancellableEvent {
|
||||
/**
|
||||
* Returns the raw UDP datagram payload.
|
||||
*
|
||||
* <p>The buffer is read-only and positioned at the start of the payload.</p>
|
||||
* <p>The buffer is read-only.</p>
|
||||
*
|
||||
* @return raw datagram data
|
||||
*/
|
||||
@@ -83,11 +82,11 @@ public final class UDPIncomingConnectionEvent extends CancellableEvent {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the transport type of this incoming connection.
|
||||
* Returns the protocol type of this incoming datagram.
|
||||
*
|
||||
* @return {@link Transport#UDP}
|
||||
* @return {@link NetworkProtocol#UDP}
|
||||
*/
|
||||
public Transport getTransport() {
|
||||
return transport;
|
||||
public NetworkProtocol getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.udp;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.Packet;
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.packets.PacketHandler;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Encodes/decodes packets for UDP transport.
|
||||
*
|
||||
* <p>Format:
|
||||
* <pre>
|
||||
* [int packetId][ObjectOutputStream payload bytes...]
|
||||
* </pre>
|
||||
*/
|
||||
public final class UdpPacketCodec {
|
||||
|
||||
private UdpPacketCodec() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a packet into a byte buffer ready for sending.
|
||||
*
|
||||
* @param handler packet handler
|
||||
* @param packet packet
|
||||
* @return encoded buffer (position=0, limit=length)
|
||||
* @throws IOException on I/O errors
|
||||
* @throws ClassNotFoundException on serialization errors
|
||||
*/
|
||||
public static ByteBuffer encode(PacketHandler handler, Packet packet) throws IOException, ClassNotFoundException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
|
||||
|
||||
try (DataOutputStream dos = new DataOutputStream(baos)) {
|
||||
dos.writeInt(packet.getPacketID());
|
||||
|
||||
// Keep your existing Packet API (ObjectOutputStream)
|
||||
try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
|
||||
packet.write(handler, oos);
|
||||
oos.flush();
|
||||
}
|
||||
}
|
||||
|
||||
byte[] bytes = baos.toByteArray();
|
||||
return ByteBuffer.wrap(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a packet id and lets the handler read the payload into a packet instance.
|
||||
*
|
||||
* @param handler packet handler
|
||||
* @param datagram datagram buffer (position=0, limit=length)
|
||||
* @return decoded packet instance (already read/filled), or {@code null} if unknown id
|
||||
* @throws IOException on errors
|
||||
* @throws ClassNotFoundException on errors
|
||||
*/
|
||||
public static Packet decodeAndHandle(PacketHandler handler, ByteBuffer datagram) throws IOException, ClassNotFoundException {
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(datagram.array(), datagram.position(), datagram.remaining());
|
||||
|
||||
int id;
|
||||
try (DataInputStream dis = new DataInputStream(bais)) {
|
||||
id = dis.readInt();
|
||||
}
|
||||
|
||||
if (!handler.isPacketIDRegistered(id)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Packet packet = handler.getPacketByID(id);
|
||||
|
||||
// Now decode remaining bytes with ObjectInputStream
|
||||
int payloadOffset = 4;
|
||||
ByteArrayInputStream payload = new ByteArrayInputStream(datagram.array(), datagram.position() + payloadOffset, datagram.remaining() - payloadOffset);
|
||||
|
||||
try (ObjectInputStream ois = new ObjectInputStream(payload)) {
|
||||
boolean ok = handler.handlePacket(id, packet, ois);
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.utils;
|
||||
|
||||
/**
|
||||
* Defines whether the server requires client certificates during the TLS handshake.
|
||||
*
|
||||
* <p>{@link #REQUIRED} enforces mutual TLS (mTLS): clients must present a certificate.</p>
|
||||
*
|
||||
* <p>{@link #OPTIONAL} allows clients without a certificate to connect (server will request a certificate,
|
||||
* but does not fail the handshake if none is provided).</p>
|
||||
*/
|
||||
public enum ClientAuthMode {
|
||||
|
||||
/**
|
||||
* Client certificate is mandatory (mTLS).
|
||||
*/
|
||||
REQUIRED,
|
||||
|
||||
/**
|
||||
* Client certificate is optional.
|
||||
*/
|
||||
OPTIONAL
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.utils;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Immutable identifier for a client (similar to a Minecraft player's UUID).
|
||||
*/
|
||||
public record ClientID(UUID uuid) implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ClientID}.
|
||||
*
|
||||
* @param uuid backing UUID (must not be {@code null})
|
||||
*/
|
||||
public ClientID(UUID uuid) {
|
||||
this.uuid = Objects.requireNonNull(uuid, "uuid");
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random {@link ClientID}.
|
||||
*
|
||||
* @return random client id
|
||||
*/
|
||||
public static ClientID random() {
|
||||
return new ClientID(UUID.randomUUID());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns backing UUID.
|
||||
*
|
||||
* @return UUID
|
||||
*/
|
||||
@Override
|
||||
public UUID uuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof ClientID other)) return false;
|
||||
return uuid.equals(other.uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClientID{uuid=" + uuid + "}";
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://github.com/UnlegitDqrk
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://github.com/UnlegitDqrk
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
@@ -6,47 +22,69 @@
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.udp;
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.utils;
|
||||
|
||||
import javax.net.ssl.*;
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLEngineResult;
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.SSLParameters;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.DatagramChannel;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Minimal DTLS endpoint using {@link SSLEngine} over {@link DatagramChannel}.
|
||||
* Minimal DTLS endpoint using {@link SSLEngine} over a datagram transport.
|
||||
*
|
||||
* <p>This implementation is designed for "best effort" UDP and focuses on:
|
||||
* <ul>
|
||||
* <li>DTLS handshake via SSLEngine</li>
|
||||
* <li>wrap/unwrap application data into datagrams</li>
|
||||
* <li>per remote address sessions</li>
|
||||
* <li>per-remote address sessions</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p><strong>Server mode note:</strong> A newly created DTLS session must enter handshake
|
||||
* ({@link SSLEngine#beginHandshake()}) immediately, otherwise initial client handshake datagrams
|
||||
* may not be processed and the client may time out.</p>
|
||||
*
|
||||
* <p><strong>Client certificate policy (server-side):</strong>
|
||||
* For {@link ClientAuthMode#REQUIRED} the presence of a peer certificate is enforced after handshake
|
||||
* completion (via {@link SSLEngine#getSession()} and {@code getPeerCertificates()}), because
|
||||
* {@link SSLParameters#setNeedClientAuth(boolean)} is not reliably enforced for {@link SSLEngine} across providers.</p>
|
||||
*/
|
||||
public final class DtlsEndpoint {
|
||||
|
||||
private final DatagramChannel channel;
|
||||
private static final ByteBuffer EMPTY = ByteBuffer.allocate(0);
|
||||
|
||||
private final java.nio.channels.DatagramChannel channel;
|
||||
private final SSLContext sslContext;
|
||||
private final boolean clientMode;
|
||||
private final int mtu;
|
||||
private final int timeoutMillis;
|
||||
private final ApplicationDataHandler appHandler;
|
||||
private final ClientAuthMode clientAuthMode;
|
||||
|
||||
private final Map<SocketAddress, DtlsSession> sessions = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Creates a DTLS endpoint.
|
||||
*
|
||||
* @param channel underlying datagram channel (bound for server, unbound or bound for client)
|
||||
* @param sslContext DTLS SSL context (created with "DTLS")
|
||||
* @param clientMode true for client sessions, false for server sessions
|
||||
* @param mtu maximum datagram size
|
||||
* @param timeoutMillis handshake/read timeout for polling
|
||||
* @param appHandler application data handler
|
||||
* @param channel underlying datagram channel (bound for server, connected or unconnected for client)
|
||||
* @param sslContext DTLS SSL context (created with "DTLS")
|
||||
* @param clientMode true for client sessions, false for server sessions
|
||||
* @param mtu maximum datagram size
|
||||
* @param timeoutMillis handshake/read timeout for polling
|
||||
* @param clientAuthMode server-side client auth policy (OPTIONAL/REQUIRED). Ignored for clientMode=true.
|
||||
* @param appHandler application data handler
|
||||
*/
|
||||
public DtlsEndpoint(
|
||||
DatagramChannel channel,
|
||||
@@ -54,21 +92,24 @@ public final class DtlsEndpoint {
|
||||
boolean clientMode,
|
||||
int mtu,
|
||||
int timeoutMillis,
|
||||
ClientAuthMode clientAuthMode,
|
||||
ApplicationDataHandler appHandler
|
||||
) {
|
||||
)
|
||||
{
|
||||
this.channel = Objects.requireNonNull(channel, "channel");
|
||||
this.sslContext = Objects.requireNonNull(sslContext, "sslContext");
|
||||
this.clientMode = clientMode;
|
||||
this.mtu = mtu;
|
||||
this.timeoutMillis = timeoutMillis;
|
||||
this.clientAuthMode = Objects.requireNonNull(clientAuthMode, "clientAuthMode");
|
||||
this.appHandler = Objects.requireNonNull(appHandler, "appHandler");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a DTLS SSLContext from an existing key+trust configuration.
|
||||
* Creates a DTLS {@link SSLContext} from an existing key+trust configuration.
|
||||
*
|
||||
* @param keyManagers key managers
|
||||
* @param trustManagers trust managers
|
||||
* @param keyManagers key managers (nullable)
|
||||
* @param trustManagers trust managers (nullable)
|
||||
* @return DTLS SSL context
|
||||
* @throws Exception on errors
|
||||
*/
|
||||
@@ -86,9 +127,17 @@ public final class DtlsEndpoint {
|
||||
* @throws SSLException if engine creation fails
|
||||
*/
|
||||
public DtlsSession session(SocketAddress remote) throws SSLException {
|
||||
Objects.requireNonNull(remote, "remote");
|
||||
return sessions.computeIfAbsent(remote, r -> {
|
||||
try {
|
||||
return new DtlsSession(createEngine(r), r, mtu);
|
||||
SSLEngine engine = createEngine(r);
|
||||
|
||||
// Critical: server-side sessions must enter handshake immediately.
|
||||
if (!clientMode) {
|
||||
engine.beginHandshake();
|
||||
}
|
||||
|
||||
return new DtlsSession(engine, r, mtu);
|
||||
} catch (SSLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@@ -98,9 +147,6 @@ public final class DtlsEndpoint {
|
||||
/**
|
||||
* Performs a DTLS handshake for a remote address.
|
||||
*
|
||||
* <p>Client: call this after creating a session and before sending app data.</p>
|
||||
* <p>Server: call this once you detect a new remote (first datagrams arrive) to complete handshake.</p>
|
||||
*
|
||||
* @param remote remote address
|
||||
* @throws IOException on I/O error
|
||||
* @throws SSLException on TLS error
|
||||
@@ -109,7 +155,10 @@ public final class DtlsEndpoint {
|
||||
DtlsSession s = session(remote);
|
||||
if (s.isHandshakeComplete()) return;
|
||||
|
||||
s.engine().beginHandshake();
|
||||
if (clientMode) {
|
||||
s.engine().beginHandshake();
|
||||
}
|
||||
|
||||
SSLEngineResult.HandshakeStatus hs = s.engine().getHandshakeStatus();
|
||||
|
||||
ByteBuffer netIn = ByteBuffer.allocate(mtu);
|
||||
@@ -126,9 +175,14 @@ public final class DtlsEndpoint {
|
||||
switch (hs) {
|
||||
case NEED_WRAP -> {
|
||||
netOut.clear();
|
||||
SSLEngineResult r = s.engine().wrap(ByteBuffer.allocate(0), netOut);
|
||||
|
||||
SSLEngineResult r = s.engine().wrap(EMPTY, netOut);
|
||||
hs = r.getHandshakeStatus();
|
||||
|
||||
if (r.getStatus() == SSLEngineResult.Status.CLOSED) {
|
||||
throw new SSLException("DTLS engine closed during handshake (wrap)");
|
||||
}
|
||||
|
||||
netOut.flip();
|
||||
if (netOut.hasRemaining()) {
|
||||
channel.send(netOut, remote);
|
||||
@@ -138,24 +192,23 @@ public final class DtlsEndpoint {
|
||||
netIn.clear();
|
||||
SocketAddress from = channel.receive(netIn);
|
||||
if (from == null) {
|
||||
// best effort: keep looping until timeout
|
||||
continue;
|
||||
}
|
||||
if (!from.equals(remote)) {
|
||||
// ignore other peers here; their sessions will be handled elsewhere
|
||||
continue;
|
||||
}
|
||||
|
||||
netIn.flip();
|
||||
app.clear();
|
||||
|
||||
SSLEngineResult r = s.engine().unwrap(netIn, app);
|
||||
hs = r.getHandshakeStatus();
|
||||
|
||||
if (r.getStatus() == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
|
||||
// wait for more datagrams
|
||||
continue;
|
||||
}
|
||||
if (r.getStatus() == SSLEngineResult.Status.CLOSED) {
|
||||
throw new SSLException("DTLS engine closed during handshake");
|
||||
throw new SSLException("DTLS engine closed during handshake (unwrap)");
|
||||
}
|
||||
}
|
||||
case NEED_TASK -> {
|
||||
@@ -165,7 +218,10 @@ public final class DtlsEndpoint {
|
||||
}
|
||||
hs = s.engine().getHandshakeStatus();
|
||||
}
|
||||
case FINISHED, NOT_HANDSHAKING -> s.setHandshakeComplete(true);
|
||||
case FINISHED, NOT_HANDSHAKING -> {
|
||||
s.setHandshakeComplete(true);
|
||||
enforceClientAuthIfRequired(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -179,6 +235,9 @@ public final class DtlsEndpoint {
|
||||
* @throws SSLException on TLS errors
|
||||
*/
|
||||
public void sendApplication(SocketAddress remote, ByteBuffer applicationData) throws IOException, SSLException {
|
||||
Objects.requireNonNull(remote, "remote");
|
||||
Objects.requireNonNull(applicationData, "applicationData");
|
||||
|
||||
DtlsSession s = session(remote);
|
||||
if (!s.isHandshakeComplete()) {
|
||||
handshake(remote);
|
||||
@@ -202,8 +261,6 @@ public final class DtlsEndpoint {
|
||||
/**
|
||||
* Polls UDP, unwraps DTLS records and dispatches decrypted application data.
|
||||
*
|
||||
* <p>Run this in a dedicated thread for server and client.</p>
|
||||
*
|
||||
* @throws IOException on I/O errors
|
||||
*/
|
||||
public void poll() throws IOException {
|
||||
@@ -224,27 +281,35 @@ public final class DtlsEndpoint {
|
||||
ByteBuffer app = ByteBuffer.allocate(s.engine().getSession().getApplicationBufferSize());
|
||||
|
||||
try {
|
||||
app.clear();
|
||||
SSLEngineResult r = s.engine().unwrap(netIn, app);
|
||||
|
||||
if (r.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK) {
|
||||
Runnable task;
|
||||
while ((task = s.engine().getDelegatedTask()) != null) task.run();
|
||||
while ((task = s.engine().getDelegatedTask()) != null) {
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
|
||||
if (r.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_WRAP) {
|
||||
// Respond to DTLS handshake flights if needed
|
||||
ByteBuffer netOut = ByteBuffer.allocate(mtu);
|
||||
netOut.clear();
|
||||
SSLEngineResult wr = s.engine().wrap(ByteBuffer.allocate(0), netOut);
|
||||
|
||||
SSLEngineResult wr = s.engine().wrap(EMPTY, netOut);
|
||||
if (wr.getStatus() != SSLEngineResult.Status.CLOSED) {
|
||||
netOut.flip();
|
||||
if (netOut.hasRemaining()) channel.send(netOut, from);
|
||||
if (netOut.hasRemaining()) {
|
||||
channel.send(netOut, from);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (r.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.FINISHED
|
||||
|| r.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
|
||||
s.setHandshakeComplete(true);
|
||||
if (!s.isHandshakeComplete()) {
|
||||
s.setHandshakeComplete(true);
|
||||
enforceClientAuthIfRequired(s);
|
||||
}
|
||||
}
|
||||
|
||||
if (r.getStatus() == SSLEngineResult.Status.CLOSED) {
|
||||
@@ -258,24 +323,49 @@ public final class DtlsEndpoint {
|
||||
appHandler.onApplicationData(from, app);
|
||||
}
|
||||
} catch (SSLException ignored) {
|
||||
// best effort: invalid record / handshake mismatch -> drop
|
||||
// Best effort: invalid record / handshake mismatch -> drop.
|
||||
} finally {
|
||||
netIn.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void enforceClientAuthIfRequired(DtlsSession s) throws SSLException {
|
||||
if (clientMode) return;
|
||||
if (clientAuthMode != ClientAuthMode.REQUIRED) return;
|
||||
|
||||
// If REQUIRED, ensure the peer presented a certificate.
|
||||
try {
|
||||
Certificate[] peer = s.engine().getSession().getPeerCertificates();
|
||||
if (peer == null || peer.length == 0) {
|
||||
sessions.remove(s.remote());
|
||||
throw new SSLException("Client certificate required but not provided");
|
||||
}
|
||||
} catch (javax.net.ssl.SSLPeerUnverifiedException e) {
|
||||
sessions.remove(s.remote());
|
||||
throw new SSLException("Client certificate required but peer unverified", e);
|
||||
}
|
||||
}
|
||||
|
||||
private SSLEngine createEngine(SocketAddress remote) throws SSLException {
|
||||
SSLEngine engine = sslContext.createSSLEngine();
|
||||
final SSLEngine engine;
|
||||
|
||||
if (remote instanceof InetSocketAddress isa) {
|
||||
// Host string may be an IP or hostname. Both are acceptable for SSLEngine identity.
|
||||
engine = sslContext.createSSLEngine(isa.getHostString(), isa.getPort());
|
||||
} else {
|
||||
engine = sslContext.createSSLEngine();
|
||||
}
|
||||
|
||||
engine.setUseClientMode(clientMode);
|
||||
|
||||
SSLParameters p = engine.getSSLParameters();
|
||||
// Prefer DTLSv1.2 (widest support in JSSE DTLS). If your environment supports DTLSv1.3, you can extend this.
|
||||
p.setProtocols(new String[]{"DTLSv1.2"});
|
||||
engine.setSSLParameters(p);
|
||||
|
||||
// For DTLS it's recommended to set a secure random
|
||||
engine.getSSLParameters();
|
||||
// Do NOT rely on setNeedClientAuth/setWantClientAuth for SSLEngine enforcement.
|
||||
// Enforce REQUIRED via post-handshake peer certificate check.
|
||||
|
||||
engine.setSSLParameters(p);
|
||||
return engine;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.utils;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents a network endpoint that may be defined by hostname or IP literal.
|
||||
*
|
||||
* <p>Fully supports IPv4 and IPv6 (including bracketed IPv6 literals).
|
||||
* Resolution is deterministic and configurable via {@link IpPreference}.</p>
|
||||
*/
|
||||
public final class Endpoint {
|
||||
|
||||
private final String host;
|
||||
private final int port;
|
||||
private final IpPreference ipPreference;
|
||||
|
||||
/**
|
||||
* Creates a new endpoint.
|
||||
*
|
||||
* @param host hostname or IP literal
|
||||
* @param port port (1–65535)
|
||||
* @param ipPreference IP selection preference
|
||||
*/
|
||||
public Endpoint(String host, int port, IpPreference ipPreference) {
|
||||
this.host = normalizeHost(host);
|
||||
this.port = validatePort(port);
|
||||
this.ipPreference = Objects.requireNonNull(ipPreference, "ipPreference");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new endpoint with {@link IpPreference#PREFER_IPV6}.
|
||||
*
|
||||
* @param host hostname or IP literal
|
||||
* @param port port
|
||||
*/
|
||||
public Endpoint(String host, int port) {
|
||||
this(host, port, IpPreference.PREFER_IPV6);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the host or IP literal.
|
||||
*
|
||||
* @return host
|
||||
*/
|
||||
public String host() {
|
||||
return host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the port.
|
||||
*
|
||||
* @return port
|
||||
*/
|
||||
public int port() {
|
||||
return port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves all addresses for this endpoint.
|
||||
*
|
||||
* @return resolved socket addresses
|
||||
* @throws UnknownHostException if resolution fails
|
||||
*/
|
||||
public List<InetSocketAddress> resolveAll() throws UnknownHostException {
|
||||
InetAddress[] addresses = InetAddress.getAllByName(host);
|
||||
if (addresses.length == 0) {
|
||||
throw new UnknownHostException("No addresses resolved for " + host);
|
||||
}
|
||||
|
||||
List<InetSocketAddress> result = new ArrayList<>(addresses.length);
|
||||
for (InetAddress a : addresses) {
|
||||
result.add(new InetSocketAddress(a, port));
|
||||
}
|
||||
|
||||
result.sort(Comparator.comparingInt(this::score));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the best address according to {@link IpPreference}.
|
||||
*
|
||||
* @return best socket address
|
||||
* @throws UnknownHostException if resolution fails
|
||||
*/
|
||||
public InetSocketAddress resolveBest() throws UnknownHostException {
|
||||
return resolveAll().get(0);
|
||||
}
|
||||
|
||||
private int score(InetSocketAddress addr) {
|
||||
boolean ipv6 = addr.getAddress() instanceof java.net.Inet6Address;
|
||||
boolean ipv4 = addr.getAddress() instanceof java.net.Inet4Address;
|
||||
|
||||
return switch (ipPreference) {
|
||||
case IPV6_ONLY -> ipv6 ? 0 : 100;
|
||||
case IPV4_ONLY -> ipv4 ? 0 : 100;
|
||||
case PREFER_IPV6 -> ipv6 ? 0 : 10;
|
||||
case PREFER_IPV4 -> ipv4 ? 0 : 10;
|
||||
case ANY -> 0;
|
||||
};
|
||||
}
|
||||
|
||||
private static String normalizeHost(String host) {
|
||||
Objects.requireNonNull(host, "host");
|
||||
String h = host.trim();
|
||||
if (h.isEmpty()) throw new IllegalArgumentException("host must not be empty");
|
||||
|
||||
// Remove IPv6 brackets if present
|
||||
if (h.startsWith("[") && h.endsWith("]") && h.length() > 2) {
|
||||
h = h.substring(1, h.length() - 1).trim();
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
private static int validatePort(int port) {
|
||||
if (port <= 0 || port > 65535) {
|
||||
throw new IllegalArgumentException("port out of range: " + port);
|
||||
}
|
||||
return port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls IP family selection when resolving hostnames.
|
||||
*/
|
||||
public enum IpPreference {
|
||||
ANY,
|
||||
PREFER_IPV6,
|
||||
PREFER_IPV4,
|
||||
IPV6_ONLY,
|
||||
IPV4_ONLY
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.utils;
|
||||
|
||||
import dev.unlegitdqrk.unlegitlibrary.network.system.server.ServerProtocolMode;
|
||||
|
||||
/**
|
||||
* Supported network protocols for packet transport.
|
||||
*
|
||||
* <p>This enum is used:
|
||||
* <ul>
|
||||
* <li>by client and server to declare supported/enabled protocols</li>
|
||||
* <li>when sending packets to explicitly choose the transport</li>
|
||||
* <li>by {@link ServerProtocolMode} to define server capabilities</li>
|
||||
* </ul>
|
||||
*/
|
||||
public enum NetworkProtocol {
|
||||
|
||||
/**
|
||||
* TCP transport secured via TLS.
|
||||
*/
|
||||
TCP,
|
||||
|
||||
/**
|
||||
* UDP transport secured via DTLS.
|
||||
*/
|
||||
UDP
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.utils;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
/**
|
||||
* Supported transport mechanisms for packet sending.
|
||||
*/
|
||||
public enum Transport {
|
||||
TCP,
|
||||
UDP;
|
||||
|
||||
/**
|
||||
* Returns a default transport set for a typical hybrid server/client.
|
||||
*
|
||||
* @return TCP + UDP set
|
||||
*/
|
||||
public static EnumSet<Transport> both() {
|
||||
return EnumSet.of(TCP, UDP);
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2026 UnlegitDqrk - All Rights Reserved
|
||||
*
|
||||
* You are unauthorized to remove this copyright.
|
||||
* You have to give Credits to the Author in your project and link this GitHub site: https://unlegitdqrk.dev/
|
||||
* See LICENSE-File if exists
|
||||
*/
|
||||
|
||||
package dev.unlegitdqrk.unlegitlibrary.network.system.utils;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
/**
|
||||
* Defines which transports a server supports and which are mandatory to be connected.
|
||||
*/
|
||||
public record TransportPolicy(EnumSet<Transport> supported, EnumSet<Transport> required) {
|
||||
|
||||
/**
|
||||
* Creates a new transport policy.
|
||||
*
|
||||
* @param supported transports supported by the server
|
||||
* @param required transports required for a connection to be considered "fully connected"
|
||||
*/
|
||||
public TransportPolicy(EnumSet<Transport> supported, EnumSet<Transport> required) {
|
||||
this.supported = EnumSet.copyOf(supported);
|
||||
this.required = EnumSet.copyOf(required);
|
||||
|
||||
if (!this.supported.containsAll(this.required)) {
|
||||
throw new IllegalArgumentException("Required transports must be a subset of supported transports.");
|
||||
}
|
||||
if (this.supported.isEmpty()) {
|
||||
throw new IllegalArgumentException("Supported transports cannot be empty.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience: TCP only.
|
||||
*/
|
||||
public static TransportPolicy tcpOnly() {
|
||||
return new TransportPolicy(EnumSet.of(Transport.TCP), EnumSet.of(Transport.TCP));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience: UDP only.
|
||||
*/
|
||||
public static TransportPolicy udpOnly() {
|
||||
return new TransportPolicy(EnumSet.of(Transport.UDP), EnumSet.of(Transport.UDP));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience: supports TCP+UDP and requires BOTH simultaneously (your chosen setting).
|
||||
*/
|
||||
public static TransportPolicy bothRequired() {
|
||||
return new TransportPolicy(EnumSet.of(Transport.TCP, Transport.UDP), EnumSet.of(Transport.TCP, Transport.UDP));
|
||||
}
|
||||
|
||||
/**
|
||||
* Supported transports.
|
||||
*
|
||||
* @return supported set
|
||||
*/
|
||||
@Override
|
||||
public EnumSet<Transport> supported() {
|
||||
return EnumSet.copyOf(supported);
|
||||
}
|
||||
|
||||
/**
|
||||
* Required transports.
|
||||
*
|
||||
* @return required set
|
||||
*/
|
||||
@Override
|
||||
public EnumSet<Transport> required() {
|
||||
return EnumSet.copyOf(required);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user