use of org.lanternpowered.server.network.status.LanternStatusResponse in project LanternServer by LanternPowered.
the class HandlerStatusRequest method handle.
@Override
public void handle(NetworkContext context, MessageStatusInRequest message) {
final NetworkSession session = context.getSession();
final LanternServer server = session.getServer();
final Gson gson = new Gson();
final Text description = server.getMotd();
final InetSocketAddress address = session.getAddress();
final InetSocketAddress virtualAddress = session.getVirtualHost();
final int protocol = session.getProtocolVersion();
final MinecraftVersion clientVersion = Lantern.getGame().getMinecraftVersionCache().getVersionOrUnknown(protocol, false);
if (clientVersion == LanternMinecraftVersion.UNKNOWN) {
Lantern.getLogger().debug("Client with unknown protocol version {} pinged the server.", protocol);
}
final LanternStatusClient client = new LanternStatusClient(address, clientVersion, virtualAddress);
final ClientPingServerEvent.Response.Players players = LanternStatusHelper.createPlayers(server);
final LanternStatusResponse response = new LanternStatusResponse(Lantern.getGame().getPlatform().getMinecraftVersion(), server.getFavicon(), description, players);
final Cause cause = Cause.of(EventContext.empty(), new WrappedRemoteConnection(session));
final ClientPingServerEvent event = SpongeEventFactory.createClientPingServerEvent(cause, client, response);
Sponge.getEventManager().post(event);
// Cancelled, we are done here
if (event.isCancelled()) {
context.getChannel().close();
return;
}
final JsonObject rootObject = new JsonObject();
final JsonObject versionObject = new JsonObject();
checkState(response.getVersion() instanceof LanternMinecraftVersion);
final LanternMinecraftVersion serverVersion = (LanternMinecraftVersion) response.getVersion();
versionObject.addProperty("name", serverVersion.getName());
versionObject.addProperty("protocol", serverVersion.getProtocol());
if (response.getPlayers().isPresent()) {
final JsonObject playersObject = new JsonObject();
playersObject.addProperty("max", players.getMax());
playersObject.addProperty("online", players.getOnline());
List<GameProfile> profiles = players.getProfiles();
if (!profiles.isEmpty()) {
final JsonArray array = new JsonArray();
for (GameProfile profile : profiles) {
Optional<String> optName = profile.getName();
if (!optName.isPresent()) {
continue;
}
final JsonObject profileObject = new JsonObject();
profileObject.addProperty("name", optName.get());
profileObject.addProperty("id", profile.getUniqueId().toString());
array.add(profileObject);
}
playersObject.add("sample", array);
}
rootObject.add("players", playersObject);
}
rootObject.add("version", versionObject);
rootObject.add("description", ((LanternJsonTextSerializer) TextSerializers.JSON).getGson().toJsonTree(response.getDescription()));
response.getFavicon().ifPresent(icon -> rootObject.addProperty("favicon", ((LanternFavicon) icon).getEncoded()));
final JsonObject fmlObject = new JsonObject();
// Trick the client that the server is fml, we support fml channels anyway
fmlObject.addProperty("type", "FML");
// The client shouldn't know the plugins (mods) list
fmlObject.add("modList", new JsonArray());
// Add the fml info
rootObject.add("modinfo", fmlObject);
session.send(new MessageStatusOutResponse(gson.toJson(rootObject)));
}
use of org.lanternpowered.server.network.status.LanternStatusResponse in project LanternServer by LanternPowered.
the class LegacyProtocolHandler method channelRead.
@Override
public void channelRead(ChannelHandlerContext ctx, Object object) throws Exception {
final LanternServer server = this.session.getServer();
final ByteBuf buf = (ByteBuf) object;
buf.markReaderIndex();
// Whether it was a valid legacy message
boolean legacy = false;
try {
final int messageId = buf.readUnsignedByte();
// they don't attempt to login
if (messageId == 0x02) {
// Protocol version
int protocol = buf.readByte();
int value = buf.readShort();
// Check the length
if (value < 0 || value > 16) {
return;
}
// Username
buf.readBytes(value << 1);
value = buf.readShort();
// Check the length
if (value < 0 || value > 255) {
return;
}
// Host address
buf.readBytes(value << 1);
// Port
buf.readInt();
if (buf.readableBytes() > 0) {
return;
}
legacy = true;
sendDisconnectMessage(ctx, LanternTexts.toPlain(t("multiplayer.disconnect.outdated_client", Lantern.getGame().getPlatform().getMinecraftVersion().getName())));
final MinecraftVersion clientVersion = Lantern.getGame().getMinecraftVersionCache().getVersionOrUnknown(protocol, true);
if (clientVersion == LanternMinecraftVersion.UNKNOWN_LEGACY) {
Lantern.getLogger().debug("Client with unknown legacy protocol version {} attempted to join the server.", protocol);
} else {
Lantern.getLogger().debug("Client with legacy protocol version {} (mc-version {}) attempted to join the server.", protocol, clientVersion.getName());
}
return;
}
// Check for the ping message id.
if (messageId != 0xfe) {
return;
}
int readable = buf.readableBytes();
boolean full = false;
// The version used to ping the server
int protocol = V1_3_2_PROTOCOL;
// Versions 1.4 - 1.5.x + 1.6 - Can request full data.
if (readable > 0) {
// Is always 1
if (buf.readUnsignedByte() != 1) {
return;
}
full = true;
protocol = V1_5_2_PROTOCOL;
}
// The virtual address that was used to join the server
InetSocketAddress virtualAddress = null;
// Version 1.6 - Used extra data.
if (readable > 1) {
if (buf.readUnsignedByte() != 0xfa) {
return;
}
byte[] bytes = new byte[buf.readShort() << 1];
buf.readBytes(bytes);
if (!new String(bytes, StandardCharsets.UTF_16BE).equals("MC|PingHost")) {
return;
}
// Not used
buf.readShort();
// The protocol version is present
protocol = buf.readUnsignedByte();
// There is extra host and port data
if (protocol >= 73) {
bytes = new byte[buf.readShort() << 1];
buf.readBytes(bytes);
final String host = new String(bytes, StandardCharsets.UTF_16BE);
final int port = buf.readInt();
virtualAddress = InetSocketAddress.createUnresolved(host, port);
}
readable = buf.readableBytes();
if (readable > 0) {
Lantern.getLogger().warn("Trailing bytes on a legacy ping message: {}b", readable);
}
}
// The message was successfully decoded as a legacy one
legacy = true;
final boolean full1 = full;
final int protocol1 = protocol;
final InetSocketAddress virtualAddress1 = virtualAddress;
// Call the event in the main thread
Lantern.getScheduler().callSync(() -> {
final MinecraftVersion clientVersion = Lantern.getGame().getMinecraftVersionCache().getVersionOrUnknown(protocol1, true);
if (clientVersion == LanternMinecraftVersion.UNKNOWN) {
Lantern.getLogger().debug("Client with unknown legacy protocol version {} pinged the server.", protocol1);
}
final MinecraftVersion serverVersion = Lantern.getGame().getPlatform().getMinecraftVersion();
Text description = server.getMotd();
final InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress();
final LanternStatusClient client = new LanternStatusClient(address, clientVersion, virtualAddress1);
final ClientPingServerEvent.Response.Players players = LanternStatusHelper.createPlayers(server);
final LanternStatusResponse response = new LanternStatusResponse(serverVersion, server.getFavicon(), description, players);
final SimpleRemoteConnection connection = new SimpleRemoteConnection(address, virtualAddress1);
final Cause cause = Cause.of(EventContext.empty(), connection);
final ClientPingServerEvent event = SpongeEventFactory.createClientPingServerEvent(cause, client, response);
Sponge.getEventManager().post(event);
// Cancelled, we are done here
if (event.isCancelled()) {
ctx.channel().close();
return;
}
description = response.getDescription();
int online = players.getOnline();
final int max = players.getMax();
// with ???
if (!response.getPlayers().isPresent()) {
online = -1;
}
final String data;
if (full1) {
final String description0 = getFirstLine(TextSerializers.LEGACY_FORMATTING_CODE.serialize(description));
// 1. This value is always 1.
// 2. The protocol version, just use a value out of range
// of the available ones.
// 3. The version/name string of the server.
// 4. The motd of the server. In legacy format.
// 5. The online players
// 6. The maximum amount of players
data = String.format("\u00A7%s\u0000%s\u0000%s\u0000%s\u0000%s\u0000%s", 1, 127, response.getVersion().getName(), description0, online, max);
} else {
final String description0 = getFirstLine(TextSerializers.PLAIN.serialize(description));
// 1. The motd of the server. In legacy format.
// 2. The online players
// 3. The maximum amount of players
data = String.format("%s\u00A7%s\u00A7%s", description0, online, max);
}
sendDisconnectMessage(ctx, data);
});
} catch (Exception ignore) {
} finally {
if (legacy) {
buf.release();
} else {
buf.resetReaderIndex();
ctx.channel().pipeline().remove(this);
ctx.fireChannelRead(buf);
}
}
}
Aggregations