Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion src/main/java/com/zenith/network/SKeepAliveTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
import org.geysermc.mcprotocollib.protocol.data.ProtocolState;
import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ClientboundKeepAlivePacket;

import java.util.concurrent.TimeUnit;

import static com.zenith.Globals.CONFIG;
import static com.zenith.Globals.SERVER_LOG;

public class SKeepAliveTask implements Runnable {
private final ServerSession session;
Expand All @@ -16,9 +19,24 @@ public SKeepAliveTask(ServerSession session) {

@Override
public void run() {
if (!session.isSpectator() && CONFIG.client.keepAliveHandling.keepAliveMode != KeepAliveMode.INDEPENDENT) return;
var state = session.getPacketProtocol().getOutboundState();
if (state != ProtocolState.CONFIGURATION && state != ProtocolState.GAME) return;
// detect half-open connections that are no longer responding to keep alives
// e.g. a controlling player whose internet connection has silently dropped
// disconnecting them lets the bot take over and resync teleports before the destination server kicks us
if (isKeepAliveTimedOut()) {
SERVER_LOG.info("[{}] Disconnecting session that has not responded to keep alives", session.getName());
session.disconnect("Timed out");
return;
}
if (!session.isSpectator() && CONFIG.client.keepAliveHandling.keepAliveMode != KeepAliveMode.INDEPENDENT) return;
this.session.send(new ClientboundKeepAlivePacket(System.currentTimeMillis()));
}

private boolean isKeepAliveTimedOut() {
if (!CONFIG.server.extra.timeout.enable) return false;
if (!session.isLoggedIn()) return false;
var elapsed = System.currentTimeMillis() - session.getLastKeepAliveResponseTime();
return elapsed > TimeUnit.SECONDS.toMillis(CONFIG.server.extra.timeout.seconds);
}
}
4 changes: 4 additions & 0 deletions src/main/java/com/zenith/network/server/ServerSession.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ public class ServerSession extends TcpServerSession {
protected long ping = 0L;
protected long lastKeepAliveId = 0L;
protected long lastKeepAliveTime = 0L;
// last time we received a keep alive response from this session
// used to detect and disconnect half-open connections, e.g. after a controller's internet outage
protected volatile long lastKeepAliveResponseTime = System.currentTimeMillis();

protected boolean whitelistChecked = false;
protected boolean isPlayer = false;
Expand Down Expand Up @@ -290,6 +293,7 @@ public void disconnect(@Nullable final Component reason, final Throwable cause)

public void setLoggedIn() {
this.isLoggedIn = true;
this.lastKeepAliveResponseTime = System.currentTimeMillis();
if (!Proxy.getInstance().getActiveConnections().contains(this))
Proxy.getInstance().getActiveConnections().add(this);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public class SPlayerKeepAliveHandler implements PacketHandler<ServerboundKeepAli
public static final SPlayerKeepAliveHandler INSTANCE = new SPlayerKeepAliveHandler();
@Override
public ServerboundKeepAlivePacket apply(final ServerboundKeepAlivePacket packet, final ServerSession session) {
session.setLastKeepAliveResponseTime(System.currentTimeMillis());
if (packet.getPingId() == session.getLastKeepAliveId()) {
session.setPing(System.currentTimeMillis() - session.getLastKeepAliveTime());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public class KeepAliveSpectatorHandler implements PacketHandler<ServerboundKeepA
public static final KeepAliveSpectatorHandler INSTANCE = new KeepAliveSpectatorHandler();
@Override
public ServerboundKeepAlivePacket apply(final ServerboundKeepAlivePacket packet, final ServerSession session) {
session.setLastKeepAliveResponseTime(System.currentTimeMillis());
if (packet.getPingId() == session.getLastKeepAliveId()) {
session.setPing(System.currentTimeMillis() - session.getLastKeepAliveTime());
}
Expand Down