package net.minecraft.server;
import com.google.common.collect.Queues;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.local.LocalChannel;
import io.netty.channel.local.LocalEventLoopGroup;
import io.netty.channel.local.LocalServerChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.handler.timeout.TimeoutException;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import java.net.SocketAddress;
import java.util.Queue;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.annotation.Nullable;
import javax.crypto.SecretKey;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.Validate;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
import org.torch.api.Async;
public class NetworkManager extends SimpleChannelInboundHandler<Packet<?>> {
private static final Logger g = LogManager.getLogger();
public static final Marker a = MarkerManager.getMarker("NETWORK");
public static final Marker b = MarkerManager.getMarker("NETWORK_PACKETS", NetworkManager.a);
public static final AttributeKey<EnumProtocol> c = AttributeKey.valueOf("protocol");
public static final LazyInitVar<NioEventLoopGroup> d = new LazyInitVar() {
protected NioEventLoopGroup a() {
return new NioEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Client IO #%d").setDaemon(true).build());
}
@Override
protected Object init() {
return this.a();
}
};
public static final LazyInitVar<EpollEventLoopGroup> e = new LazyInitVar() {
protected EpollEventLoopGroup a() {
return new EpollEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Epoll Client IO #%d").setDaemon(true).build());
}
@Override
protected Object init() {
return this.a();
}
};
public static final LazyInitVar<LocalEventLoopGroup> f = new LazyInitVar() {
protected LocalEventLoopGroup a() {
return new LocalEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Local Client IO #%d").setDaemon(true).build());
}
@Override
protected Object init() {
return this.a();
}
};
private final EnumProtocolDirection h;
// private final Queue<NetworkManager.QueuedPacket> i = Queues.newConcurrentLinkedQueue(); // Paper
// private final ReentrantReadWriteLock j = new ReentrantReadWriteLock(); // Paper
public Channel channel;
// Spigot Start // PAIL
public SocketAddress l;
public java.util.UUID spoofedUUID;
public com.mojang.authlib.properties.Property[] spoofedProfile;
public boolean preparing = true;
// Spigot End
private PacketListener m;
private IChatBaseComponent n;
private boolean o;
private boolean p;
public NetworkManager(EnumProtocolDirection enumprotocoldirection) {
this.h = enumprotocoldirection;
}
@Override
public void channelActive(ChannelHandlerContext channelhandlercontext) throws Exception {
super.channelActive(channelhandlercontext);
this.channel = channelhandlercontext.channel();
this.l = this.channel.remoteAddress();
// Spigot Start
this.preparing = false;
// Spigot End
try {
this.setProtocol(EnumProtocol.HANDSHAKING);
} catch (Throwable throwable) {
NetworkManager.g.fatal(throwable);
}
}
public void setProtocol(EnumProtocol enumprotocol) {
this.channel.attr(NetworkManager.c).set(enumprotocol);
this.channel.config().setAutoRead(true);
NetworkManager.g.debug("Enabled auto read");
}
@Override
public void channelInactive(ChannelHandlerContext channelhandlercontext) throws Exception {
this.close(new ChatMessage("disconnect.endOfStream", new Object[0]));
}
@Override
public void exceptionCaught(ChannelHandlerContext channelhandlercontext, Throwable throwable) throws Exception {
ChatMessage chatmessage;
if (throwable instanceof TimeoutException) {
chatmessage = new ChatMessage("disconnect.timeout", new Object[0]);
} else {
chatmessage = new ChatMessage("disconnect.genericReason", new Object[] { "Internal Exception: " + throwable});
}
NetworkManager.g.debug(throwable);
this.close(chatmessage);
if (MinecraftServer.getServer().isDebugging()) throwable.printStackTrace(); // Spigot
}
protected void a(ChannelHandlerContext channelhandlercontext, Packet<?> packet) throws Exception {
if (this.channel.isOpen()) {
try {
((Packet) packet).a(this.m); // CraftBukkit - decompile error
} catch (CancelledPacketHandleException cancelledpackethandleexception) {
;
}
}
}
public void setPacketListener(PacketListener packetlistener) {
Validate.notNull(packetlistener, "packetListener", new Object[0]);
NetworkManager.g.debug("Set listener of {} to {}", new Object[] { this, packetlistener});
this.m = packetlistener;
}
@Async
public void sendPacket(Packet<?> packet) {
if (this.isConnected()) {
this.m();
this.a(packet, (GenericFutureListener[]) null);
}
// Paper start - Remove but force a conflict
// else {
// this.j.writeLock().lock();
//
// try {
// this.i.add(new NetworkManager.QueuedPacket(packet, (GenericFutureListener[]) null));
// } finally {
// this.j.writeLock().unlock();
// }
// }
// Paper end
}
@Async
public void sendPacket(Packet<?> packet, GenericFutureListener<? extends Future<? super Void>> genericfuturelistener, GenericFutureListener<? extends Future<? super Void>>... agenericfuturelistener) {
if (this.isConnected()) {
this.m();
this.a(packet, ArrayUtils.add(agenericfuturelistener, 0, genericfuturelistener));
}
// Paper start - Remove but force a conflict
// else {
// this.j.writeLock().lock();
//
// try {
// this.i.add(new NetworkManager.QueuedPacket(packet, (GenericFutureListener[]) ArrayUtils.add(agenericfuturelistener, 0, genericfuturelistener)));
// } finally {
// this.j.writeLock().unlock();
// }
// }
// Paper end
}
@Async
private void a(final Packet<?> packet, @Nullable final GenericFutureListener<? extends Future<? super Void>>[] agenericfuturelistener) {
final EnumProtocol enumprotocol = EnumProtocol.a(packet);
final EnumProtocol enumprotocol1 = this.channel.attr(NetworkManager.c).get();
if (enumprotocol1 != enumprotocol) {
NetworkManager.g.debug("Disabled auto read");
this.channel.config().setAutoRead(false);
}
if (this.channel.eventLoop().inEventLoop()) {
if (enumprotocol != enumprotocol1) {
this.setProtocol(enumprotocol);
}
ChannelFuture channelfuture = this.channel.writeAndFlush(packet);
if (agenericfuturelistener != null) {
channelfuture.addListeners(agenericfuturelistener);
}
channelfuture.addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
} else {
this.channel.eventLoop().execute(new Runnable() {
@Override
public void run() {
if (enumprotocol != enumprotocol1) {
NetworkManager.this.setProtocol(enumprotocol);
}
ChannelFuture channelfuture = NetworkManager.this.channel.writeAndFlush(packet);
if (agenericfuturelistener != null) {
channelfuture.addListeners(agenericfuturelistener);
}
channelfuture.addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
}
});
}
}
private void m() {
// Paper start - Remove but force a conflict
// if (this.channel != null && this.channel.isOpen()) {
// this.j.readLock().lock();
//
// try {
// while (!this.i.isEmpty()) {
// NetworkManager.QueuedPacket networkmanager_queuedpacket = (NetworkManager.QueuedPacket) this.i.poll();
//
// this.a(networkmanager_queuedpacket.a, networkmanager_queuedpacket.b);
// }
// } finally {
// this.j.readLock().unlock();
// }
//
// }
// Paper end
}
public void a() {
this.m();
if (this.m instanceof ITickable) {
((ITickable) this.m).F_();
}
this.channel.flush();
}
public SocketAddress getSocketAddress() {
return this.l;
}
public void close(IChatBaseComponent ichatbasecomponent) {
// Spigot Start
this.preparing = false;
// Spigot End
if (this.channel.isOpen()) {
this.channel.close(); // We can't wait as this may be called from an event loop.
this.n = ichatbasecomponent;
}
}
public boolean isLocal() {
return this.channel instanceof LocalChannel || this.channel instanceof LocalServerChannel;
}
public void a(SecretKey secretkey) {
this.o = true;
this.channel.pipeline().addBefore("splitter", "decrypt", new PacketDecrypter(MinecraftEncryption.a(2, secretkey)));
this.channel.pipeline().addBefore("prepender", "encrypt", new PacketEncrypter(MinecraftEncryption.a(1, secretkey)));
}
public boolean isConnected() {
return this.channel != null && this.channel.isOpen();
}
public boolean h() {
return this.channel == null;
}
public PacketListener i() {
return this.m;
}
public IChatBaseComponent j() {
return this.n;
}
public void stopReading() {
this.channel.config().setAutoRead(false);
}
public void setCompressionLevel(int i) {
if (i >= 0) {
if (this.channel.pipeline().get("decompress") instanceof PacketDecompressor) {
((PacketDecompressor) this.channel.pipeline().get("decompress")).a(i);
} else {
this.channel.pipeline().addBefore("decoder", "decompress", new PacketDecompressor(i));
}
if (this.channel.pipeline().get("compress") instanceof PacketCompressor) {
((PacketCompressor) this.channel.pipeline().get("compress")).a(i);
} else {
this.channel.pipeline().addBefore("encoder", "compress", new PacketCompressor(i));
}
} else {
if (this.channel.pipeline().get("decompress") instanceof PacketDecompressor) {
this.channel.pipeline().remove("decompress");
}
if (this.channel.pipeline().get("compress") instanceof PacketCompressor) {
this.channel.pipeline().remove("compress");
}
}
}
public void handleDisconnection() {
if (this.channel != null && !this.channel.isOpen()) {
if (this.p) {
NetworkManager.g.warn("handleDisconnection() called twice");
} else {
this.p = true;
if (this.j() != null) {
this.i().a(this.j());
} else if (this.i() != null) {
this.i().a(new ChatComponentText("Disconnected"));
}
// this.i.clear(); // Free up packet queue. // Paper - remove unneeded packet queue
}
}
}
@Override
protected void channelRead0(ChannelHandlerContext channelhandlercontext, Packet object) throws Exception { // CraftBukkit - fix decompile error
this.a(channelhandlercontext, object);
}
static class QueuedPacket {
private final Packet<?> a;
private final GenericFutureListener<? extends Future<? super Void>>[] b;
public QueuedPacket(Packet<?> packet, GenericFutureListener<? extends Future<? super Void>>... agenericfuturelistener) {
this.a = packet;
this.b = agenericfuturelistener;
}
}
// Spigot Start
public SocketAddress getRawAddress()
{
return this.channel.remoteAddress();
}
// Spigot End
}