package net.minecraft.server; import com.google.common.collect.Lists; import com.google.common.util.concurrent.ThreadFactoryBuilder; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelException; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.ServerChannel; import io.netty.channel.epoll.Epoll; import io.netty.channel.epoll.EpollEventLoopGroup; import io.netty.channel.epoll.EpollServerSocketChannel; import io.netty.channel.local.LocalEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.timeout.ReadTimeoutHandler; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GenericFutureListener; import java.io.IOException; import java.net.InetAddress; import java.util.Collections; import java.util.Iterator; import java.util.List; import org.apache.logging.log4j.Logger; import static org.torch.server.TorchServer.logger; public class ServerConnection { private static final Logger e = logger; public static final LazyInitVar<NioEventLoopGroup> a = new LazyInitVar<NioEventLoopGroup>() { @Override protected NioEventLoopGroup init() { return new NioEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Server IO #%d").setDaemon(true).build()); } }; public static final LazyInitVar<EpollEventLoopGroup> b = new LazyInitVar<EpollEventLoopGroup>() { @Override protected EpollEventLoopGroup init() { return new EpollEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Epoll Server IO #%d").setDaemon(true).build()); } }; public static final LazyInitVar<LocalEventLoopGroup> c = new LazyInitVar<LocalEventLoopGroup>() { @Override protected LocalEventLoopGroup init() { return new LocalEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Local Server IO #%d").setDaemon(true).build()); } }; private final MinecraftServer f; public volatile boolean d; private final List<ChannelFuture> g = Collections.synchronizedList(Lists.<ChannelFuture>newArrayList()); private final List<NetworkManager> h = Collections.synchronizedList(Lists.<NetworkManager>newArrayList()); // Paper start - prevent blocking on adding a new network manager while the server is ticking private final List<NetworkManager> pending = Collections.synchronizedList(Lists.<NetworkManager>newArrayList()); private void addPending() { synchronized (pending) { this.h.addAll(pending); // Paper - OBFHELPER - List of network managers pending.clear(); } } // Paper end public ServerConnection(MinecraftServer minecraftserver) { this.f = minecraftserver; this.d = true; } public void a(InetAddress inetaddress, int i) throws IOException { List list = this.g; synchronized (this.g) { Class<? extends ServerChannel> channel; LazyInitVar lazyinitvar; if (Epoll.isAvailable() && this.f.af()) { channel = EpollServerSocketChannel.class; lazyinitvar = ServerConnection.b; logger.info("Using epoll channel type"); } else { channel = NioServerSocketChannel.class; lazyinitvar = ServerConnection.a; logger.info("Using default channel type"); } this.g.add((new ServerBootstrap()).channel(channel).childHandler(new ChannelInitializer<Channel>() { @Override protected void initChannel(Channel channel) throws Exception { try { channel.config().setOption(ChannelOption.TCP_NODELAY, Boolean.valueOf(true)); } catch (ChannelException channelexception) { ; } channel.pipeline().addLast("timeout", new ReadTimeoutHandler(30)).addLast("legacy_query", new LegacyPingHandler(ServerConnection.this)).addLast("splitter", new PacketSplitter()).addLast("decoder", new PacketDecoder(EnumProtocolDirection.SERVERBOUND)).addLast("prepender", new PacketPrepender()).addLast("encoder", new PacketEncoder(EnumProtocolDirection.CLIENTBOUND)); NetworkManager networkmanager = new NetworkManager(EnumProtocolDirection.SERVERBOUND); pending.add(networkmanager); // Paper channel.pipeline().addLast("packet_handler", networkmanager); networkmanager.setPacketListener(new HandshakeListener(ServerConnection.this.f, networkmanager)); } }).group((EventLoopGroup) lazyinitvar.c()).localAddress(inetaddress, i).bind().syncUninterruptibly()); } } public void b() { this.d = false; Iterator iterator = this.g.iterator(); while (iterator.hasNext()) { ChannelFuture channelfuture = (ChannelFuture) iterator.next(); try { channelfuture.channel().close().sync(); } catch (InterruptedException interruptedexception) { logger.error("Interrupted whilst closing channel"); } } } public void c() { List list = this.h; synchronized (this.h) { // Spigot Start addPending(); // Paper // This prevents players from 'gaming' the server, and strategically relogging to increase their position in the tick order if ( org.spigotmc.SpigotConfig.playerShuffle > 0 && MinecraftServer.currentTick % org.spigotmc.SpigotConfig.playerShuffle == 0 ) { Collections.shuffle( this.h ); } // Spigot End Iterator iterator = this.h.iterator(); while (iterator.hasNext()) { final NetworkManager networkmanager = (NetworkManager) iterator.next(); if (!networkmanager.h()) { if (networkmanager.isConnected()) { try { networkmanager.a(); } catch (Exception exception) { if (networkmanager.isLocal()) { CrashReport crashreport = CrashReport.a(exception, "Ticking memory connection"); CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Ticking connection"); crashreportsystemdetails.a("Connection", new CrashReportCallable<String>() { @Override public String call() throws Exception { return networkmanager.toString(); } }); throw new ReportedException(crashreport); } logger.warn("Failed to handle packet for {}", new Object[] { networkmanager.getSocketAddress(), exception}); final ChatComponentText chatcomponenttext = new ChatComponentText("Internal server error"); networkmanager.sendPacket(new PacketPlayOutKickDisconnect(chatcomponenttext), new GenericFutureListener() { @Override public void operationComplete(Future future) throws Exception { networkmanager.close(chatcomponenttext); } }, new GenericFutureListener[0]); networkmanager.stopReading(); } } else { // Spigot Start // Fix a race condition where a NetworkManager could be unregistered just before connection. if (networkmanager.preparing) continue; // Spigot End iterator.remove(); networkmanager.handleDisconnection(); } } } } } public MinecraftServer d() { return this.f; } }