Add Java server querying! (:
Some checks failed
Deploy API / docker (17, 3.8.5) (push) Has been cancelled
Some checks failed
Deploy API / docker (17, 3.8.5) (push) Has been cancelled
This commit is contained in:
parent
345e1532a4
commit
c689434ec4
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2024 Braydon (Rainnny).
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package me.braydon.mc.common.packet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* @author Braydon
|
||||
*/
|
||||
public abstract class JavaQueryPacket extends UDPPacket {
|
||||
protected static byte[] MAGIC = { (byte) 0xFE, (byte) 0xFD };
|
||||
|
||||
protected final byte[] padArrayEnd(byte[] array, int amount) {
|
||||
byte[] result = new byte[array.length + amount];
|
||||
System.arraycopy(array, 0, result, 0, array.length);
|
||||
for (int i = array.length; i < result.length; i++) {
|
||||
result[i] = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected final byte[] intToBytes(int input) {
|
||||
return new byte[] {
|
||||
(byte) (input >>> 24 & 0xFF),
|
||||
(byte) (input >>> 16 & 0xFF),
|
||||
(byte) (input >>> 8 & 0xFF),
|
||||
(byte) (input & 0xFF)
|
||||
};
|
||||
}
|
||||
|
||||
protected final byte[] trim(byte[] arr) {
|
||||
int begin = 0, end = arr.length;
|
||||
for (int i = 0; i < arr.length; i++) { // find the first non-null byte{
|
||||
if (arr[i] != 0) {
|
||||
begin = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int i = arr.length - 1; i >= 0; i--) { //find the last non-null byte
|
||||
if (arr[i] != 0) {
|
||||
end = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return subarray(arr, begin, end);
|
||||
}
|
||||
|
||||
protected final byte[] subarray(byte[] in, int a, int b) {
|
||||
if (b - a > in.length) {
|
||||
return in;
|
||||
}
|
||||
byte[] out = new byte[(b - a) + 1];
|
||||
if (b + 1 - a >= 0) {
|
||||
System.arraycopy(in, a, out, 0, b + 1 - a);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
protected final byte[][] split(byte[] input) {
|
||||
ArrayList<byte[]> temp = new ArrayList<>();
|
||||
int index_cache = 0;
|
||||
for (int i = 0; i < input.length; i++) {
|
||||
if (input[i] == 0x00) {
|
||||
byte[] b = subarray(input, index_cache, i - 1);
|
||||
temp.add(b);
|
||||
index_cache = i + 1;//note, this is the index *after* the null byte
|
||||
}
|
||||
}
|
||||
//get the remaining part
|
||||
if (index_cache != 0) { //prevent duplication if there are no null bytes
|
||||
byte[] b = subarray(input, index_cache, input.length - 1);
|
||||
temp.add(b);
|
||||
}
|
||||
byte[][] output = new byte[temp.size()][input.length];
|
||||
for (int i = 0; i < temp.size(); i++) {
|
||||
output[i] = temp.get(i);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
@ -36,7 +36,7 @@ import java.io.IOException;
|
||||
* @author Braydon
|
||||
* @see <a href="https://wiki.vg/Protocol">Protocol Docs</a>
|
||||
*/
|
||||
public abstract class MinecraftJavaPacket {
|
||||
public abstract class TCPPacket {
|
||||
/**
|
||||
* Process this packet.
|
||||
*
|
@ -35,12 +35,12 @@ import java.net.DatagramSocket;
|
||||
* @author Braydon
|
||||
* @see <a href="https://wiki.vg/Raknet_Protocol">Protocol Docs</a>
|
||||
*/
|
||||
public interface MinecraftBedrockPacket {
|
||||
public abstract class UDPPacket {
|
||||
/**
|
||||
* Process this packet.
|
||||
*
|
||||
* @param socket the socket to process the packet for
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
void process(@NonNull DatagramSocket socket) throws IOException;
|
||||
public abstract void process(@NonNull DatagramSocket socket) throws IOException;
|
||||
}
|
@ -24,7 +24,7 @@
|
||||
package me.braydon.mc.common.packet.impl.bedrock;
|
||||
|
||||
import lombok.NonNull;
|
||||
import me.braydon.mc.common.packet.MinecraftBedrockPacket;
|
||||
import me.braydon.mc.common.packet.UDPPacket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
@ -40,7 +40,7 @@ import java.nio.ByteOrder;
|
||||
* @author Braydon
|
||||
* @see <a href="https://wiki.vg/Raknet_Protocol#Unconnected_Ping">Protocol Docs</a>
|
||||
*/
|
||||
public final class BedrockPacketUnconnectedPing implements MinecraftBedrockPacket {
|
||||
public final class BedrockUnconnectedPingPacket extends UDPPacket {
|
||||
private static final byte ID = 0x01; // The ID of the packet
|
||||
private static final byte[] MAGIC = { 0, -1, -1, 0, -2, -2, -2, -2, -3, -3, -3, -3, 18, 52, 86, 120 };
|
||||
|
@ -25,7 +25,7 @@ package me.braydon.mc.common.packet.impl.bedrock;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import me.braydon.mc.common.packet.MinecraftBedrockPacket;
|
||||
import me.braydon.mc.common.packet.UDPPacket;
|
||||
import me.braydon.mc.model.server.BedrockMinecraftServer;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -37,13 +37,13 @@ import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* This packet is sent by the server to the client in
|
||||
* response to the {@link BedrockPacketUnconnectedPing}.
|
||||
* response to the {@link BedrockUnconnectedPingPacket}.
|
||||
*
|
||||
* @author Braydon
|
||||
* @see <a href="https://wiki.vg/Raknet_Protocol#Unconnected_Pong">Protocol Docs</a>
|
||||
*/
|
||||
@Getter
|
||||
public final class BedrockPacketUnconnectedPong implements MinecraftBedrockPacket {
|
||||
public final class BedrockUnconnectedPongPacket extends UDPPacket {
|
||||
private static final byte ID = 0x1C; // The ID of the packet
|
||||
|
||||
/**
|
@ -21,12 +21,12 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package me.braydon.mc.common.packet.impl.java;
|
||||
package me.braydon.mc.common.packet.impl.java.tcp;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
import me.braydon.mc.common.packet.MinecraftJavaPacket;
|
||||
import me.braydon.mc.common.packet.TCPPacket;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
@ -41,7 +41,7 @@ import java.io.IOException;
|
||||
* @see <a href="https://wiki.vg/Protocol#Handshake">Protocol Docs</a>
|
||||
*/
|
||||
@AllArgsConstructor @ToString
|
||||
public final class JavaPacketHandshakingInSetProtocol extends MinecraftJavaPacket {
|
||||
public final class JavaHandshakingInSetProtocolPacket extends TCPPacket {
|
||||
private static final byte ID = 0x00; // The ID of the packet
|
||||
private static final int STATUS_HANDSHAKE = 1; // The status handshake ID
|
||||
|
@ -21,11 +21,11 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package me.braydon.mc.common.packet.impl.java;
|
||||
package me.braydon.mc.common.packet.impl.java.tcp;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import me.braydon.mc.common.packet.MinecraftJavaPacket;
|
||||
import me.braydon.mc.common.packet.TCPPacket;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
@ -40,7 +40,7 @@ import java.io.IOException;
|
||||
* @see <a href="https://wiki.vg/Protocol#Status_Request">Protocol Docs</a>
|
||||
*/
|
||||
@Getter
|
||||
public final class JavaPacketStatusInStart extends MinecraftJavaPacket {
|
||||
public final class JavaStatusInStartPacket extends TCPPacket {
|
||||
private static final byte ID = 0x00; // The ID of the packet
|
||||
|
||||
/**
|
75
API/src/main/java/me/braydon/mc/common/packet/impl/java/udp/JavaQueryFullStatRequestPacket.java
Normal file
75
API/src/main/java/me/braydon/mc/common/packet/impl/java/udp/JavaQueryFullStatRequestPacket.java
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2024 Braydon (Rainnny).
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package me.braydon.mc.common.packet.impl.java.udp;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.NonNull;
|
||||
import me.braydon.mc.common.packet.JavaQueryPacket;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
|
||||
/**
|
||||
* This packet is sent by the client to the server to request the
|
||||
* full stats of the server. The server will respond with a payload
|
||||
* containing the server's stats.
|
||||
*
|
||||
* @author Braydon
|
||||
* @see <a href="https://wiki.vg/Query#Request_3">Query Protocol Docs</a>
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
public final class JavaQueryFullStatRequestPacket extends JavaQueryPacket {
|
||||
private static final int ID = 0; // The ID of the packet
|
||||
|
||||
/**
|
||||
* The response from the {@link JavaQueryHandshakeRequestPacket}.
|
||||
*/
|
||||
private final byte[] handshakeResponse;
|
||||
|
||||
/**
|
||||
* Process this packet.
|
||||
*
|
||||
* @param socket the socket to process the packet for
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public void process(@NonNull DatagramSocket socket) throws IOException {
|
||||
try (
|
||||
ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream(1460);
|
||||
DataOutputStream dataOutputStream = new DataOutputStream(arrayOutputStream)
|
||||
) {
|
||||
dataOutputStream.write(MAGIC);
|
||||
dataOutputStream.write(ID); // Packet ID
|
||||
dataOutputStream.writeInt(1); // Session ID
|
||||
dataOutputStream.write(padArrayEnd(handshakeResponse, 4)); // The handshake response payload
|
||||
|
||||
// Send the packet
|
||||
byte[] bytes = arrayOutputStream.toByteArray();
|
||||
socket.send(new DatagramPacket(bytes, bytes.length));
|
||||
}
|
||||
}
|
||||
}
|
79
API/src/main/java/me/braydon/mc/common/packet/impl/java/udp/JavaQueryFullStatResponsePacket.java
Normal file
79
API/src/main/java/me/braydon/mc/common/packet/impl/java/udp/JavaQueryFullStatResponsePacket.java
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2024 Braydon (Rainnny).
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package me.braydon.mc.common.packet.impl.java.udp;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import me.braydon.mc.common.packet.JavaQueryPacket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This packet is sent by the server to the client in
|
||||
* response to the {@link JavaQueryFullStatRequestPacket}.
|
||||
*
|
||||
* @author Braydon
|
||||
* @see <a href="https://wiki.vg/Query#Response_3">Query Protocol Docs</a>
|
||||
*/
|
||||
@Getter
|
||||
public final class JavaQueryFullStatResponsePacket extends JavaQueryPacket {
|
||||
/**
|
||||
* The response from the server, null if none.
|
||||
*/
|
||||
private Map<String, String> response;
|
||||
|
||||
/**
|
||||
* Process this packet.
|
||||
*
|
||||
* @param socket the socket to process the packet for
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public void process(@NonNull DatagramSocket socket) throws IOException {
|
||||
// Handle receiving of the packet
|
||||
byte[] receiveData = new byte[1024];
|
||||
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
|
||||
socket.receive(receivePacket);
|
||||
|
||||
// Construct a response from the received packet.
|
||||
Map<String, String> response = new HashMap<>();
|
||||
|
||||
String previousEntry = null;
|
||||
for (byte[] bytes : split(trim(receivePacket.getData()))) {
|
||||
String entry = new String(bytes); // The entry
|
||||
|
||||
if (previousEntry != null) {
|
||||
response.put(previousEntry, entry);
|
||||
previousEntry = null;
|
||||
continue;
|
||||
}
|
||||
previousEntry = entry;
|
||||
}
|
||||
this.response = response;
|
||||
}
|
||||
}
|
70
API/src/main/java/me/braydon/mc/common/packet/impl/java/udp/JavaQueryHandshakeRequestPacket.java
Normal file
70
API/src/main/java/me/braydon/mc/common/packet/impl/java/udp/JavaQueryHandshakeRequestPacket.java
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2024 Braydon (Rainnny).
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package me.braydon.mc.common.packet.impl.java.udp;
|
||||
|
||||
import lombok.NonNull;
|
||||
import me.braydon.mc.common.packet.JavaQueryPacket;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
|
||||
/**
|
||||
* This packet is sent by the client to the
|
||||
* server to request a handshake. This will
|
||||
* then allow us to send further packets such
|
||||
* as {@link JavaQueryFullStatRequestPacket}.
|
||||
*
|
||||
* @author Braydon
|
||||
* @see <a href="https://wiki.vg/Query#Request">Query Protocol Docs</a>
|
||||
*/
|
||||
public final class JavaQueryHandshakeRequestPacket extends JavaQueryPacket {
|
||||
private static final int ID = 9; // The ID of the packet
|
||||
|
||||
/**
|
||||
* Process this packet.
|
||||
*
|
||||
* @param socket the socket to process the packet for
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public void process(@NonNull DatagramSocket socket) throws IOException {
|
||||
try (
|
||||
ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream(1460);
|
||||
DataOutputStream dataOutputStream = new DataOutputStream(arrayOutputStream)
|
||||
) {
|
||||
dataOutputStream.write(MAGIC);
|
||||
dataOutputStream.write(ID); // Packet ID
|
||||
dataOutputStream.writeInt(1); // Session ID
|
||||
dataOutputStream.write(new byte[] {}); // No payload data
|
||||
|
||||
// Send the packet
|
||||
byte[] bytes = arrayOutputStream.toByteArray();
|
||||
bytes = padArrayEnd(bytes, 11 - bytes.length);
|
||||
socket.send(new DatagramPacket(bytes, bytes.length));
|
||||
}
|
||||
}
|
||||
}
|
64
API/src/main/java/me/braydon/mc/common/packet/impl/java/udp/JavaQueryHandshakeResponsePacket.java
Normal file
64
API/src/main/java/me/braydon/mc/common/packet/impl/java/udp/JavaQueryHandshakeResponsePacket.java
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2024 Braydon (Rainnny).
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package me.braydon.mc.common.packet.impl.java.udp;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import me.braydon.mc.common.packet.JavaQueryPacket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
|
||||
/**
|
||||
* This packet is sent by the server to the client in
|
||||
* response to the {@link JavaQueryHandshakeRequestPacket}.
|
||||
*
|
||||
* @author Braydon
|
||||
* @see <a href="https://wiki.vg/Query#Response">Query Protocol Docs</a>
|
||||
*/
|
||||
@Getter
|
||||
public final class JavaQueryHandshakeResponsePacket extends JavaQueryPacket {
|
||||
/**
|
||||
* The response from the server.
|
||||
*/
|
||||
private byte[] response;
|
||||
|
||||
/**
|
||||
* Process this packet.
|
||||
*
|
||||
* @param socket the socket to process the packet for
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public void process(@NonNull DatagramSocket socket) throws IOException {
|
||||
// Handle receiving of the packet
|
||||
byte[] receiveData = new byte[1024];
|
||||
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
|
||||
socket.receive(receivePacket);
|
||||
|
||||
// Set the response to the integer value of the received data
|
||||
response = intToBytes(Integer.parseInt(new String(receivePacket.getData()).trim()));
|
||||
}
|
||||
}
|
@ -29,11 +29,16 @@ import me.braydon.mc.common.JavaMinecraftVersion;
|
||||
import me.braydon.mc.config.AppConfig;
|
||||
import me.braydon.mc.model.MinecraftServer;
|
||||
import me.braydon.mc.model.dns.DNSRecord;
|
||||
import me.braydon.mc.model.token.JavaServerChallengeStatusToken;
|
||||
import me.braydon.mc.model.token.JavaServerStatusToken;
|
||||
import me.braydon.mc.service.MojangService;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.chat.ComponentSerializer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A Java edition {@link MinecraftServer}.
|
||||
*
|
||||
@ -51,6 +56,12 @@ public final class JavaMinecraftServer extends MinecraftServer {
|
||||
*/
|
||||
private final Favicon favicon;
|
||||
|
||||
/**
|
||||
* The plugins on this server, present if
|
||||
* query is on and plugins are present.
|
||||
*/
|
||||
private final Plugin[] plugins;
|
||||
|
||||
/**
|
||||
* The Forge mod information for this server, null if none.
|
||||
* <p>
|
||||
@ -67,6 +78,16 @@ public final class JavaMinecraftServer extends MinecraftServer {
|
||||
*/
|
||||
private final ForgeData forgeData;
|
||||
|
||||
/**
|
||||
* The main world of this server, present if query is on.
|
||||
*/
|
||||
private final String world;
|
||||
|
||||
/**
|
||||
* Does this server support querying?
|
||||
*/
|
||||
private final boolean queryEnabled;
|
||||
|
||||
/**
|
||||
* Does this server preview chat?
|
||||
*
|
||||
@ -98,13 +119,16 @@ public final class JavaMinecraftServer extends MinecraftServer {
|
||||
private boolean mojangBanned;
|
||||
|
||||
private JavaMinecraftServer(@NonNull String hostname, String ip, int port, @NonNull DNSRecord[] records, @NonNull Version version,
|
||||
@NonNull Players players, @NonNull MOTD motd, Favicon favicon, ModInfo modInfo, ForgeData forgeData,
|
||||
boolean previewsChat, boolean enforcesSecureChat, boolean preventsChatReports, boolean mojangBanned) {
|
||||
@NonNull Players players, @NonNull MOTD motd, Favicon favicon, Plugin[] plugins, ModInfo modInfo, ForgeData forgeData,
|
||||
String world, boolean queryEnabled, boolean previewsChat, boolean enforcesSecureChat, boolean preventsChatReports, boolean mojangBanned) {
|
||||
super(hostname, ip, port, records, players, motd);
|
||||
this.version = version;
|
||||
this.favicon = favicon;
|
||||
this.plugins = plugins;
|
||||
this.modInfo = modInfo;
|
||||
this.forgeData = forgeData;
|
||||
this.world = world;
|
||||
this.queryEnabled = queryEnabled;
|
||||
this.previewsChat = previewsChat;
|
||||
this.enforcesSecureChat = enforcesSecureChat;
|
||||
this.preventsChatReports = preventsChatReports;
|
||||
@ -118,19 +142,33 @@ public final class JavaMinecraftServer extends MinecraftServer {
|
||||
* @param ip the IP address of the server
|
||||
* @param port the port of the server
|
||||
* @param records the DNS records of the server
|
||||
* @param token the status token
|
||||
* @param statusToken the status token
|
||||
* @param challengeStatusToken the challenge status token, null if none
|
||||
* @return the Java Minecraft server
|
||||
*/
|
||||
@NonNull
|
||||
public static JavaMinecraftServer create(@NonNull String hostname, String ip, int port,
|
||||
@NonNull DNSRecord[] records, @NonNull JavaServerStatusToken token) {
|
||||
String motdString = token.getDescription() instanceof String ? (String) token.getDescription() : null;
|
||||
public static JavaMinecraftServer create(@NonNull String hostname, String ip, int port, @NonNull DNSRecord[] records,
|
||||
@NonNull JavaServerStatusToken statusToken, JavaServerChallengeStatusToken challengeStatusToken) {
|
||||
String motdString = statusToken.getDescription() instanceof String ? (String) statusToken.getDescription() : null;
|
||||
if (motdString == null) { // Not a string motd, convert from Json
|
||||
motdString = new TextComponent(ComponentSerializer.parse(AppConfig.GSON.toJson(token.getDescription()))).toLegacyText();
|
||||
motdString = new TextComponent(ComponentSerializer.parse(AppConfig.GSON.toJson(statusToken.getDescription()))).toLegacyText();
|
||||
}
|
||||
return new JavaMinecraftServer(hostname, ip, port, records, token.getVersion().detailedCopy(), Players.create(token.getPlayers()),
|
||||
MOTD.create(motdString), Favicon.create(token.getFavicon(), hostname), token.getModInfo(), token.getForgeData(),
|
||||
token.isPreviewsChat(), token.isEnforcesSecureChat(), token.isPreventsChatReports(), false
|
||||
|
||||
// Get the plugins from the challenge token
|
||||
Plugin[] plugins = null;
|
||||
if (challengeStatusToken != null) {
|
||||
List<Plugin> list = new ArrayList<>();
|
||||
for (Map.Entry<String, String> entry : challengeStatusToken.getPlugins().entrySet()) {
|
||||
list.add(new Plugin(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
plugins = list.toArray(new Plugin[0]);
|
||||
}
|
||||
String world = challengeStatusToken == null ? null : challengeStatusToken.getMap();
|
||||
|
||||
return new JavaMinecraftServer(hostname, ip, port, records, statusToken.getVersion().detailedCopy(), Players.create(statusToken.getPlayers()),
|
||||
MOTD.create(motdString), Favicon.create(statusToken.getFavicon(), hostname), plugins, statusToken.getModInfo(), statusToken.getForgeData(),
|
||||
world, challengeStatusToken != null, statusToken.isPreviewsChat(), statusToken.isEnforcesSecureChat(),
|
||||
statusToken.isPreventsChatReports(), false
|
||||
);
|
||||
}
|
||||
|
||||
@ -220,6 +258,22 @@ public final class JavaMinecraftServer extends MinecraftServer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A plugin for a server.
|
||||
*/
|
||||
@AllArgsConstructor @Getter @ToString
|
||||
public static class Plugin {
|
||||
/**
|
||||
* The name of this plugin.
|
||||
*/
|
||||
@NonNull private final String name;
|
||||
|
||||
/**
|
||||
* The version of this plugin.
|
||||
*/
|
||||
@NonNull private final String version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forge mod information for a server.
|
||||
* <p>
|
||||
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2024 Braydon (Rainnny).
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package me.braydon.mc.model.token;
|
||||
|
||||
import lombok.*;
|
||||
import me.braydon.mc.model.server.JavaMinecraftServer;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A token representing the response from
|
||||
* sending a challenge request via UDP to
|
||||
* a {@link JavaMinecraftServer} using the
|
||||
* query.
|
||||
*
|
||||
* @author Braydon
|
||||
*/
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE) @Getter @ToString
|
||||
public final class JavaServerChallengeStatusToken {
|
||||
/**
|
||||
* The map (world) of this server.
|
||||
*/
|
||||
@NonNull private final String map;
|
||||
|
||||
/**
|
||||
* The plugins of this server.
|
||||
*/
|
||||
private final Map<String, String> plugins;
|
||||
|
||||
/**
|
||||
* Create a new challenge token
|
||||
* from the given raw data.
|
||||
*
|
||||
* @param rawData the raw data
|
||||
* @return the challenge token
|
||||
*/
|
||||
@NonNull
|
||||
public static JavaServerChallengeStatusToken create(@NonNull Map<String, String> rawData) {
|
||||
Map<String, String> plugins = new HashMap<>();
|
||||
for (String plugin : rawData.get("plugins").split(": ")[1].split("; ")) {
|
||||
String[] split = plugin.split(" ");
|
||||
plugins.put(split[0], split[1]);
|
||||
}
|
||||
return new JavaServerChallengeStatusToken(rawData.get("map"), plugins);
|
||||
}
|
||||
}
|
@ -431,11 +431,11 @@ public final class MojangService {
|
||||
}
|
||||
|
||||
// Check the cache for the server
|
||||
Optional<CachedMinecraftServer> cached = minecraftServerCache.findById("%s-%s".formatted(platform.name(), lookupHostname));
|
||||
if (cached.isPresent()) { // Respond with the cache if present
|
||||
log.info("Found server in cache: {}", hostname);
|
||||
return cached.get();
|
||||
}
|
||||
// Optional<CachedMinecraftServer> cached = minecraftServerCache.findById("%s-%s".formatted(platform.name(), lookupHostname));
|
||||
// if (cached.isPresent()) { // Respond with the cache if present
|
||||
// log.info("Found server in cache: {}", hostname);
|
||||
// return cached.get();
|
||||
// }
|
||||
List<DNSRecord> records = new ArrayList<>(); // The resolved DNS records for the server
|
||||
|
||||
SRVRecord srvRecord = platform == MinecraftServer.Platform.JAVA ? DNSUtils.resolveSRV(hostname) : null; // Resolve the SRV record
|
||||
@ -467,7 +467,7 @@ public final class MojangService {
|
||||
((JavaMinecraftServer) minecraftServer.getValue()).setMojangBanned(isServerBlocked(hostname));
|
||||
}
|
||||
|
||||
minecraftServerCache.save(minecraftServer);
|
||||
// minecraftServerCache.save(minecraftServer);
|
||||
log.info("Cached server: {}", hostname);
|
||||
minecraftServer.setCached(-1L); // Set to -1 to indicate it's not cached in the response
|
||||
return minecraftServer;
|
||||
|
@ -25,8 +25,8 @@ package me.braydon.mc.service.pinger.impl;
|
||||
|
||||
import lombok.NonNull;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import me.braydon.mc.common.packet.impl.bedrock.BedrockPacketUnconnectedPing;
|
||||
import me.braydon.mc.common.packet.impl.bedrock.BedrockPacketUnconnectedPong;
|
||||
import me.braydon.mc.common.packet.impl.bedrock.BedrockUnconnectedPingPacket;
|
||||
import me.braydon.mc.common.packet.impl.bedrock.BedrockUnconnectedPongPacket;
|
||||
import me.braydon.mc.exception.impl.BadRequestException;
|
||||
import me.braydon.mc.exception.impl.ResourceNotFoundException;
|
||||
import me.braydon.mc.model.dns.DNSRecord;
|
||||
@ -60,7 +60,7 @@ public final class BedrockMinecraftServerPinger implements MinecraftServerPinger
|
||||
*/
|
||||
@Override
|
||||
public BedrockMinecraftServer ping(@NonNull String hostname, String ip, int port, @NonNull DNSRecord[] records) {
|
||||
log.info("Pinging {}:{}...", hostname, port);
|
||||
log.info("Opening UDP connection to {}:{}...", hostname, port);
|
||||
long before = System.currentTimeMillis(); // Timestamp before pinging
|
||||
|
||||
// Open a socket connection to the server
|
||||
@ -69,13 +69,13 @@ public final class BedrockMinecraftServerPinger implements MinecraftServerPinger
|
||||
socket.connect(new InetSocketAddress(hostname, port));
|
||||
|
||||
long ping = System.currentTimeMillis() - before; // Calculate the ping
|
||||
log.info("Pinged {}:{} in {}ms", hostname, port, ping);
|
||||
log.info("UDP Connection to {}:{} opened. Ping: {}ms", hostname, port, ping);
|
||||
|
||||
// Send the unconnected ping packet
|
||||
new BedrockPacketUnconnectedPing().process(socket);
|
||||
new BedrockUnconnectedPingPacket().process(socket);
|
||||
|
||||
// Handle the received unconnected pong packet
|
||||
BedrockPacketUnconnectedPong unconnectedPong = new BedrockPacketUnconnectedPong();
|
||||
BedrockUnconnectedPongPacket unconnectedPong = new BedrockUnconnectedPongPacket();
|
||||
unconnectedPong.process(socket);
|
||||
String response = unconnectedPong.getResponse();
|
||||
if (response == null) { // No pong response
|
||||
|
@ -26,13 +26,18 @@ package me.braydon.mc.service.pinger.impl;
|
||||
import lombok.NonNull;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import me.braydon.mc.common.JavaMinecraftVersion;
|
||||
import me.braydon.mc.common.packet.impl.java.JavaPacketHandshakingInSetProtocol;
|
||||
import me.braydon.mc.common.packet.impl.java.JavaPacketStatusInStart;
|
||||
import me.braydon.mc.common.packet.impl.java.tcp.JavaHandshakingInSetProtocolPacket;
|
||||
import me.braydon.mc.common.packet.impl.java.tcp.JavaStatusInStartPacket;
|
||||
import me.braydon.mc.common.packet.impl.java.udp.JavaQueryFullStatRequestPacket;
|
||||
import me.braydon.mc.common.packet.impl.java.udp.JavaQueryFullStatResponsePacket;
|
||||
import me.braydon.mc.common.packet.impl.java.udp.JavaQueryHandshakeRequestPacket;
|
||||
import me.braydon.mc.common.packet.impl.java.udp.JavaQueryHandshakeResponsePacket;
|
||||
import me.braydon.mc.config.AppConfig;
|
||||
import me.braydon.mc.exception.impl.BadRequestException;
|
||||
import me.braydon.mc.exception.impl.ResourceNotFoundException;
|
||||
import me.braydon.mc.model.dns.DNSRecord;
|
||||
import me.braydon.mc.model.server.JavaMinecraftServer;
|
||||
import me.braydon.mc.model.token.JavaServerChallengeStatusToken;
|
||||
import me.braydon.mc.model.token.JavaServerStatusToken;
|
||||
import me.braydon.mc.service.pinger.MinecraftServerPinger;
|
||||
|
||||
@ -43,7 +48,7 @@ import java.net.*;
|
||||
|
||||
/**
|
||||
* The {@link MinecraftServerPinger} for pinging
|
||||
* {@link JavaMinecraftServer}'s over TCP.
|
||||
* {@link JavaMinecraftServer}'s over TCP/UDP.
|
||||
*
|
||||
* @author Braydon
|
||||
*/
|
||||
@ -63,33 +68,25 @@ public final class JavaMinecraftServerPinger implements MinecraftServerPinger<Ja
|
||||
@Override
|
||||
public JavaMinecraftServer ping(@NonNull String hostname, String ip, int port, @NonNull DNSRecord[] records) {
|
||||
log.info("Pinging {}:{}...", hostname, port);
|
||||
long before = System.currentTimeMillis(); // Timestamp before pinging
|
||||
|
||||
// Open a socket connection to the server
|
||||
try (Socket socket = new Socket()) {
|
||||
socket.setTcpNoDelay(true);
|
||||
socket.connect(new InetSocketAddress(hostname, port), TIMEOUT);
|
||||
|
||||
long ping = System.currentTimeMillis() - before; // Calculate the ping
|
||||
log.info("Pinged {}:{} in {}ms", hostname, port, ping);
|
||||
|
||||
// Open data streams to begin packet transaction
|
||||
try (DataInputStream inputStream = new DataInputStream(socket.getInputStream());
|
||||
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream())) {
|
||||
// Begin handshaking with the server
|
||||
new JavaPacketHandshakingInSetProtocol(hostname, port, JavaMinecraftVersion.getMinimumVersion().getProtocol())
|
||||
.process(inputStream, outputStream);
|
||||
|
||||
// Send the status request to the server, and await back the response
|
||||
JavaPacketStatusInStart packetStatusInStart = new JavaPacketStatusInStart();
|
||||
packetStatusInStart.process(inputStream, outputStream);
|
||||
String response = packetStatusInStart.getResponse();
|
||||
if (response == null) { // No response
|
||||
throw new ResourceNotFoundException("Server didn't respond to status request");
|
||||
try {
|
||||
// Ping the server and retrieve both the status token, and the challenge status token
|
||||
JavaServerStatusToken statusToken = retrieveStatusToken(hostname, port);
|
||||
JavaServerChallengeStatusToken challengeStatusToken = null;
|
||||
try {
|
||||
challengeStatusToken = retrieveChallengeStatusToken(hostname, port);
|
||||
} catch (Exception ex) {
|
||||
// An exception will be raised if querying
|
||||
// is disabled on the server. If the exception
|
||||
// is not caused by querying being disabled, we
|
||||
// want to log the error.
|
||||
if (!(ex instanceof IOException)) {
|
||||
log.error("Failed retrieving challenge status token for %s:%s:".formatted(hostname, port), ex);
|
||||
}
|
||||
JavaServerStatusToken token = AppConfig.GSON.fromJson(response, JavaServerStatusToken.class);
|
||||
return JavaMinecraftServer.create(hostname, ip, port, records, token); // Return the server
|
||||
}
|
||||
|
||||
// Return the server
|
||||
return JavaMinecraftServer.create(hostname, ip, port, records, statusToken, challengeStatusToken);
|
||||
} catch (IOException ex) {
|
||||
if (ex instanceof UnknownHostException) {
|
||||
throw new BadRequestException("Unknown hostname: %s".formatted(hostname));
|
||||
@ -100,4 +97,73 @@ public final class JavaMinecraftServerPinger implements MinecraftServerPinger<Ja
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ping a server and retrieve its response.
|
||||
*
|
||||
* @param hostname the hostname to ping
|
||||
* @param port the port to ping
|
||||
* @return the status token
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws ResourceNotFoundException if the server didn't respond
|
||||
*/
|
||||
@NonNull
|
||||
private JavaServerStatusToken retrieveStatusToken(@NonNull String hostname, int port) throws IOException, ResourceNotFoundException {
|
||||
log.info("Opening TCP connection to {}:{}...", hostname, port);
|
||||
long before = System.currentTimeMillis(); // Timestamp before pinging
|
||||
|
||||
// Open a socket connection to the server
|
||||
try (Socket socket = new Socket()) {
|
||||
socket.setTcpNoDelay(true);
|
||||
socket.connect(new InetSocketAddress(hostname, port), TIMEOUT);
|
||||
|
||||
long ping = System.currentTimeMillis() - before; // Calculate the ping
|
||||
log.info("TCP Connection to {}:{} opened. Ping: {}ms", hostname, port, ping);
|
||||
|
||||
// Begin packet transaction
|
||||
try (DataInputStream inputStream = new DataInputStream(socket.getInputStream());
|
||||
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream())) {
|
||||
// Begin handshaking with the server
|
||||
new JavaHandshakingInSetProtocolPacket(hostname, port, JavaMinecraftVersion.getMinimumVersion().getProtocol())
|
||||
.process(inputStream, outputStream);
|
||||
|
||||
// Send the status request to the server, and await back the response
|
||||
JavaStatusInStartPacket packetStatusInStart = new JavaStatusInStartPacket();
|
||||
packetStatusInStart.process(inputStream, outputStream);
|
||||
String response = packetStatusInStart.getResponse();
|
||||
if (response == null) { // No response
|
||||
throw new ResourceNotFoundException("Server didn't respond to status request");
|
||||
}
|
||||
return AppConfig.GSON.fromJson(response, JavaServerStatusToken.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private JavaServerChallengeStatusToken retrieveChallengeStatusToken(@NonNull String hostname, int port) throws IOException {
|
||||
log.info("Opening UDP connection to {}:{}...", hostname, port);
|
||||
long before = System.currentTimeMillis(); // Timestamp before pinging
|
||||
|
||||
// Open a socket connection to the server
|
||||
try (DatagramSocket socket = new DatagramSocket()) {
|
||||
socket.setSoTimeout(500);
|
||||
socket.connect(new InetSocketAddress(hostname, port));
|
||||
|
||||
long ping = System.currentTimeMillis() - before; // Calculate the ping
|
||||
log.info("UDP Connection to {}:{} opened. Ping: {}ms", hostname, port, ping);
|
||||
|
||||
// Begin handshaking with the server
|
||||
new JavaQueryHandshakeRequestPacket().process(socket);
|
||||
JavaQueryHandshakeResponsePacket handshakeResponse = new JavaQueryHandshakeResponsePacket();
|
||||
handshakeResponse.process(socket);
|
||||
|
||||
// Send the full stats request to the server, and await back the response
|
||||
new JavaQueryFullStatRequestPacket(handshakeResponse.getResponse()).process(socket);
|
||||
JavaQueryFullStatResponsePacket fullStatResponse = new JavaQueryFullStatResponsePacket();
|
||||
fullStatResponse.process(socket);
|
||||
|
||||
// Return the challenge token
|
||||
return JavaServerChallengeStatusToken.create(fullStatResponse.getResponse());
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user