Improve Quality of Channel Close Code
* Don't double disconnect due to client exceptions * Add generic delayed close method * Properly format imports in changed files
This commit is contained in:
parent
24a65d8fa9
commit
5c551fd899
@ -11,17 +11,14 @@ import io.netty.channel.ChannelInitializer;
|
|||||||
import io.netty.channel.ChannelOption;
|
import io.netty.channel.ChannelOption;
|
||||||
import io.netty.util.internal.PlatformDependent;
|
import io.netty.util.internal.PlatformDependent;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
@ -59,8 +56,6 @@ import net.md_5.bungee.protocol.packet.Kick;
|
|||||||
import net.md_5.bungee.protocol.packet.PlayerListHeaderFooter;
|
import net.md_5.bungee.protocol.packet.PlayerListHeaderFooter;
|
||||||
import net.md_5.bungee.protocol.packet.PluginMessage;
|
import net.md_5.bungee.protocol.packet.PluginMessage;
|
||||||
import net.md_5.bungee.protocol.packet.SetCompression;
|
import net.md_5.bungee.protocol.packet.SetCompression;
|
||||||
import net.md_5.bungee.tab.Global;
|
|
||||||
import net.md_5.bungee.tab.GlobalPing;
|
|
||||||
import net.md_5.bungee.tab.ServerUnique;
|
import net.md_5.bungee.tab.ServerUnique;
|
||||||
import net.md_5.bungee.tab.TabList;
|
import net.md_5.bungee.tab.TabList;
|
||||||
import net.md_5.bungee.util.CaseInsensitiveSet;
|
import net.md_5.bungee.util.CaseInsensitiveSet;
|
||||||
@ -364,31 +359,26 @@ public final class UserConnection implements ProxiedPlayer
|
|||||||
|
|
||||||
public void disconnect0(final BaseComponent... reason)
|
public void disconnect0(final BaseComponent... reason)
|
||||||
{
|
{
|
||||||
if ( !ch.isClosed() )
|
if ( !ch.isClosing() )
|
||||||
{
|
{
|
||||||
bungee.getLogger().log( Level.INFO, "[{0}] disconnected with: {1}", new Object[]
|
bungee.getLogger().log( Level.INFO, "[{0}] disconnected with: {1}", new Object[]
|
||||||
{
|
{
|
||||||
getName(), BaseComponent.toLegacyText( reason )
|
getName(), BaseComponent.toLegacyText( reason )
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// Why do we have to delay this you might ask? Well the simple reason is MOJANG.
|
ch.delayedClose( new Runnable()
|
||||||
// Despite many a bug report posted, ever since the 1.7 protocol rewrite, the client STILL has a race condition upon switching protocols.
|
|
||||||
// As such, despite the protocol switch packets already having been sent, there is the possibility of a client side exception
|
|
||||||
// To help combat this we will wait half a second before actually sending the disconnected packet so that whoever is on the other
|
|
||||||
// end has a somewhat better chance of receiving the proper packet.
|
|
||||||
ch.getHandle().eventLoop().schedule( new Runnable()
|
|
||||||
{
|
{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run()
|
public void run()
|
||||||
{
|
{
|
||||||
unsafe().sendPacket( new Kick( ComponentSerializer.toString( reason ) ) );
|
unsafe().sendPacket( new Kick( ComponentSerializer.toString( reason ) ) );
|
||||||
ch.close();
|
|
||||||
}
|
}
|
||||||
}, 500, TimeUnit.MILLISECONDS );
|
} );
|
||||||
|
|
||||||
if ( server != null )
|
if ( server != null )
|
||||||
{
|
{
|
||||||
|
server.setObsolete( true );
|
||||||
server.disconnect( "Quitting" );
|
server.disconnect( "Quitting" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,19 +2,24 @@ package net.md_5.bungee.connection;
|
|||||||
|
|
||||||
import com.google.common.base.Charsets;
|
import com.google.common.base.Charsets;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.google.gson.Gson;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
import com.google.gson.Gson;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import net.md_5.bungee.*;
|
import net.md_5.bungee.BungeeCord;
|
||||||
|
import net.md_5.bungee.BungeeServerInfo;
|
||||||
|
import net.md_5.bungee.EncryptionUtil;
|
||||||
|
import net.md_5.bungee.UserConnection;
|
||||||
|
import net.md_5.bungee.Util;
|
||||||
|
import net.md_5.bungee.api.AbstractReconnectHandler;
|
||||||
import net.md_5.bungee.api.Callback;
|
import net.md_5.bungee.api.Callback;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.Favicon;
|
import net.md_5.bungee.api.Favicon;
|
||||||
@ -23,37 +28,37 @@ import net.md_5.bungee.api.chat.BaseComponent;
|
|||||||
import net.md_5.bungee.api.chat.TextComponent;
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
import net.md_5.bungee.api.config.ListenerInfo;
|
import net.md_5.bungee.api.config.ListenerInfo;
|
||||||
import net.md_5.bungee.api.config.ServerInfo;
|
import net.md_5.bungee.api.config.ServerInfo;
|
||||||
|
import net.md_5.bungee.api.connection.Connection.Unsafe;
|
||||||
import net.md_5.bungee.api.connection.PendingConnection;
|
import net.md_5.bungee.api.connection.PendingConnection;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
import net.md_5.bungee.api.event.LoginEvent;
|
import net.md_5.bungee.api.event.LoginEvent;
|
||||||
|
import net.md_5.bungee.api.event.PlayerHandshakeEvent;
|
||||||
import net.md_5.bungee.api.event.PostLoginEvent;
|
import net.md_5.bungee.api.event.PostLoginEvent;
|
||||||
|
import net.md_5.bungee.api.event.PreLoginEvent;
|
||||||
import net.md_5.bungee.api.event.ProxyPingEvent;
|
import net.md_5.bungee.api.event.ProxyPingEvent;
|
||||||
import net.md_5.bungee.chat.ComponentSerializer;
|
import net.md_5.bungee.chat.ComponentSerializer;
|
||||||
import net.md_5.bungee.http.HttpClient;
|
import net.md_5.bungee.http.HttpClient;
|
||||||
import net.md_5.bungee.netty.HandlerBoss;
|
import net.md_5.bungee.jni.cipher.BungeeCipher;
|
||||||
import net.md_5.bungee.netty.ChannelWrapper;
|
import net.md_5.bungee.netty.ChannelWrapper;
|
||||||
|
import net.md_5.bungee.netty.HandlerBoss;
|
||||||
import net.md_5.bungee.netty.PacketHandler;
|
import net.md_5.bungee.netty.PacketHandler;
|
||||||
import net.md_5.bungee.netty.PipelineUtils;
|
import net.md_5.bungee.netty.PipelineUtils;
|
||||||
import net.md_5.bungee.netty.cipher.CipherDecoder;
|
import net.md_5.bungee.netty.cipher.CipherDecoder;
|
||||||
import net.md_5.bungee.netty.cipher.CipherEncoder;
|
import net.md_5.bungee.netty.cipher.CipherEncoder;
|
||||||
import net.md_5.bungee.protocol.DefinedPacket;
|
import net.md_5.bungee.protocol.DefinedPacket;
|
||||||
import net.md_5.bungee.protocol.PacketWrapper;
|
import net.md_5.bungee.protocol.PacketWrapper;
|
||||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
|
||||||
import net.md_5.bungee.protocol.packet.Handshake;
|
|
||||||
import net.md_5.bungee.protocol.packet.PluginMessage;
|
|
||||||
import net.md_5.bungee.protocol.packet.EncryptionResponse;
|
|
||||||
import net.md_5.bungee.protocol.packet.EncryptionRequest;
|
|
||||||
import net.md_5.bungee.protocol.packet.Kick;
|
|
||||||
import net.md_5.bungee.api.AbstractReconnectHandler;
|
|
||||||
import net.md_5.bungee.api.event.PlayerHandshakeEvent;
|
|
||||||
import net.md_5.bungee.api.event.PreLoginEvent;
|
|
||||||
import net.md_5.bungee.jni.cipher.BungeeCipher;
|
|
||||||
import net.md_5.bungee.protocol.Protocol;
|
import net.md_5.bungee.protocol.Protocol;
|
||||||
|
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||||
|
import net.md_5.bungee.protocol.packet.EncryptionRequest;
|
||||||
|
import net.md_5.bungee.protocol.packet.EncryptionResponse;
|
||||||
|
import net.md_5.bungee.protocol.packet.Handshake;
|
||||||
|
import net.md_5.bungee.protocol.packet.Kick;
|
||||||
import net.md_5.bungee.protocol.packet.LegacyHandshake;
|
import net.md_5.bungee.protocol.packet.LegacyHandshake;
|
||||||
import net.md_5.bungee.protocol.packet.LegacyPing;
|
import net.md_5.bungee.protocol.packet.LegacyPing;
|
||||||
import net.md_5.bungee.protocol.packet.LoginRequest;
|
import net.md_5.bungee.protocol.packet.LoginRequest;
|
||||||
import net.md_5.bungee.protocol.packet.LoginSuccess;
|
import net.md_5.bungee.protocol.packet.LoginSuccess;
|
||||||
import net.md_5.bungee.protocol.packet.PingPacket;
|
import net.md_5.bungee.protocol.packet.PingPacket;
|
||||||
|
import net.md_5.bungee.protocol.packet.PluginMessage;
|
||||||
import net.md_5.bungee.protocol.packet.StatusRequest;
|
import net.md_5.bungee.protocol.packet.StatusRequest;
|
||||||
import net.md_5.bungee.protocol.packet.StatusResponse;
|
import net.md_5.bungee.protocol.packet.StatusResponse;
|
||||||
import net.md_5.bungee.util.BoundedArrayList;
|
import net.md_5.bungee.util.BoundedArrayList;
|
||||||
@ -96,12 +101,11 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
|||||||
private boolean legacy;
|
private boolean legacy;
|
||||||
@Getter
|
@Getter
|
||||||
private String extraDataInHandshake = "";
|
private String extraDataInHandshake = "";
|
||||||
private boolean disconnecting;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldHandle(PacketWrapper packet) throws Exception
|
public boolean shouldHandle(PacketWrapper packet) throws Exception
|
||||||
{
|
{
|
||||||
return !disconnecting;
|
return !ch.isClosing();
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum State
|
private enum State
|
||||||
@ -534,15 +538,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
|||||||
@Override
|
@Override
|
||||||
public void disconnect(final BaseComponent... reason)
|
public void disconnect(final BaseComponent... reason)
|
||||||
{
|
{
|
||||||
if ( !disconnecting || !ch.isClosed() )
|
ch.delayedClose( new Runnable()
|
||||||
{
|
|
||||||
disconnecting = true;
|
|
||||||
// Why do we have to delay this you might ask? Well the simple reason is MOJANG.
|
|
||||||
// Despite many a bug report posted, ever since the 1.7 protocol rewrite, the client STILL has a race condition upon switching protocols.
|
|
||||||
// As such, despite the protocol switch packets already having been sent, there is the possibility of a client side exception
|
|
||||||
// To help combat this we will wait half a second before actually sending the disconnected packet so that whoever is on the other
|
|
||||||
// end has a somewhat better chance of receiving the proper packet.
|
|
||||||
ch.getHandle().eventLoop().schedule( new Runnable()
|
|
||||||
{
|
{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -552,10 +548,8 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
|||||||
{
|
{
|
||||||
unsafe().sendPacket( new Kick( ComponentSerializer.toString( reason ) ) );
|
unsafe().sendPacket( new Kick( ComponentSerializer.toString( reason ) ) );
|
||||||
}
|
}
|
||||||
ch.close();
|
|
||||||
}
|
|
||||||
}, 500, TimeUnit.MILLISECONDS );
|
|
||||||
}
|
}
|
||||||
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
package net.md_5.bungee.netty;
|
package net.md_5.bungee.netty;
|
||||||
|
|
||||||
import net.md_5.bungee.compress.PacketCompressor;
|
|
||||||
import net.md_5.bungee.compress.PacketDecompressor;
|
|
||||||
import net.md_5.bungee.protocol.PacketWrapper;
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.channel.ChannelHandler;
|
import io.netty.channel.ChannelHandler;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import net.md_5.bungee.compress.PacketCompressor;
|
||||||
|
import net.md_5.bungee.compress.PacketDecompressor;
|
||||||
import net.md_5.bungee.protocol.MinecraftDecoder;
|
import net.md_5.bungee.protocol.MinecraftDecoder;
|
||||||
import net.md_5.bungee.protocol.MinecraftEncoder;
|
import net.md_5.bungee.protocol.MinecraftEncoder;
|
||||||
|
import net.md_5.bungee.protocol.PacketWrapper;
|
||||||
import net.md_5.bungee.protocol.Protocol;
|
import net.md_5.bungee.protocol.Protocol;
|
||||||
|
|
||||||
public class ChannelWrapper
|
public class ChannelWrapper
|
||||||
@ -18,6 +19,8 @@ public class ChannelWrapper
|
|||||||
private final Channel ch;
|
private final Channel ch;
|
||||||
@Getter
|
@Getter
|
||||||
private volatile boolean closed;
|
private volatile boolean closed;
|
||||||
|
@Getter
|
||||||
|
private volatile boolean closing;
|
||||||
|
|
||||||
public ChannelWrapper(ChannelHandlerContext ctx)
|
public ChannelWrapper(ChannelHandlerContext ctx)
|
||||||
{
|
{
|
||||||
@ -56,12 +59,41 @@ public class ChannelWrapper
|
|||||||
{
|
{
|
||||||
if ( !closed )
|
if ( !closed )
|
||||||
{
|
{
|
||||||
closed = true;
|
closed = closing = true;
|
||||||
ch.flush();
|
ch.flush();
|
||||||
ch.close();
|
ch.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void delayedClose(final Runnable runnable)
|
||||||
|
{
|
||||||
|
Preconditions.checkArgument( runnable != null, "runnable" );
|
||||||
|
|
||||||
|
if ( !closing )
|
||||||
|
{
|
||||||
|
closing = true;
|
||||||
|
|
||||||
|
// Minecraft client can take some time to switch protocols.
|
||||||
|
// Sending the wrong disconnect packet whilst a protocol switch is in progress will crash it.
|
||||||
|
// Delay 500ms to ensure that the protocol switch (if any) has definitely taken place.
|
||||||
|
ch.eventLoop().schedule( new Runnable()
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
runnable.run();
|
||||||
|
} finally
|
||||||
|
{
|
||||||
|
ChannelWrapper.this.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 500, TimeUnit.MILLISECONDS );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void addBefore(String baseName, String name, ChannelHandler handler)
|
public void addBefore(String baseName, String name, ChannelHandler handler)
|
||||||
{
|
{
|
||||||
Preconditions.checkState( ch.eventLoop().inEventLoop(), "cannot add handler outside of event loop" );
|
Preconditions.checkState( ch.eventLoop().inEventLoop(), "cannot add handler outside of event loop" );
|
||||||
|
Loading…
Reference in New Issue
Block a user