diff --git a/pom.xml b/pom.xml
index cd686d3c1..3b77c86a1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -64,7 +64,7 @@
unknown
- 4.0.19.Final
+ 4.0.20.Final
UTF-8
diff --git a/proxy/pom.xml b/proxy/pom.xml
index f5e40c474..7fe39226b 100644
--- a/proxy/pom.xml
+++ b/proxy/pom.xml
@@ -29,6 +29,12 @@
${netty.version}
compile
+
+ io.netty
+ netty-transport-native-epoll
+ ${netty.version}
+ compile
+
jline
jline
diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java
index 2f49735ae..484671f91 100644
--- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java
+++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java
@@ -21,9 +21,7 @@ import io.netty.channel.Channel;
import io.netty.channel.ChannelException;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
-import io.netty.channel.MultithreadEventLoopGroup;
-import io.netty.channel.nio.NioEventLoopGroup;
-import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.channel.EventLoopGroup;
import io.netty.util.ResourceLeakDetector;
import net.md_5.bungee.conf.Configuration;
import java.io.File;
@@ -33,7 +31,6 @@ import java.net.InetSocketAddress;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.Collections;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
@@ -97,7 +94,7 @@ public class BungeeCord extends ProxyServer
* Localization bundle.
*/
public ResourceBundle bundle;
- public MultithreadEventLoopGroup eventLoops;
+ public EventLoopGroup eventLoops;
/**
* locations.yml save thread.
*/
@@ -206,7 +203,7 @@ public class BungeeCord extends ProxyServer
System.setProperty( "io.netty.selectorAutoRebuildThreshold", "0" ); // Seems to cause Bungee to stop accepting connections
ResourceLeakDetector.setEnabled( false ); // Eats performance
- eventLoops = new NioEventLoopGroup( 0, new ThreadFactoryBuilder().setNameFormat( "Netty IO Thread #%1$d" ).build() );
+ eventLoops = PipelineUtils.newEventLoopGroup(0, new ThreadFactoryBuilder().setNameFormat( "Netty IO Thread #%1$d" ).build() );
File moduleDirectory = new File( "modules" );
moduleManager.load( this, moduleDirectory );
@@ -259,7 +256,7 @@ public class BungeeCord extends ProxyServer
}
};
new ServerBootstrap()
- .channel( NioServerSocketChannel.class )
+ .channel( PipelineUtils.getServerChannel() )
.childAttr( PipelineUtils.LISTENER, info )
.childHandler( PipelineUtils.SERVER_CHILD )
.group( eventLoops )
diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeServerInfo.java b/proxy/src/main/java/net/md_5/bungee/BungeeServerInfo.java
index 6613016cd..2c3bb9187 100644
--- a/proxy/src/main/java/net/md_5/bungee/BungeeServerInfo.java
+++ b/proxy/src/main/java/net/md_5/bungee/BungeeServerInfo.java
@@ -5,7 +5,6 @@ import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelOption;
-import io.netty.channel.socket.nio.NioSocketChannel;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collection;
@@ -131,7 +130,7 @@ public class BungeeServerInfo implements ServerInfo
}
};
new Bootstrap()
- .channel( NioSocketChannel.class )
+ .channel( PipelineUtils.getChannel() )
.group( BungeeCord.getInstance().eventLoops )
.handler( PipelineUtils.BASE )
.option( ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000 ) // TODO: Configurable
diff --git a/proxy/src/main/java/net/md_5/bungee/UserConnection.java b/proxy/src/main/java/net/md_5/bungee/UserConnection.java
index 5b06bf88d..10e732e66 100644
--- a/proxy/src/main/java/net/md_5/bungee/UserConnection.java
+++ b/proxy/src/main/java/net/md_5/bungee/UserConnection.java
@@ -7,7 +7,6 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
-import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.internal.PlatformDependent;
import java.net.InetSocketAddress;
import java.util.Collection;
@@ -261,7 +260,7 @@ public final class UserConnection implements ProxiedPlayer
}
};
Bootstrap b = new Bootstrap()
- .channel( NioSocketChannel.class )
+ .channel( PipelineUtils.getChannel() )
.group( ch.getHandle().eventLoop() )
.handler( initializer )
.option( ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000 ) // TODO: Configurable
diff --git a/proxy/src/main/java/net/md_5/bungee/http/HttpClient.java b/proxy/src/main/java/net/md_5/bungee/http/HttpClient.java
index e1f2c1b60..c8e4af867 100644
--- a/proxy/src/main/java/net/md_5/bungee/http/HttpClient.java
+++ b/proxy/src/main/java/net/md_5/bungee/http/HttpClient.java
@@ -8,7 +8,6 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoop;
-import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
@@ -21,6 +20,7 @@ import java.util.concurrent.TimeUnit;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import net.md_5.bungee.api.Callback;
+import net.md_5.bungee.netty.PipelineUtils;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class HttpClient
@@ -90,7 +90,7 @@ public class HttpClient
}
};
- new Bootstrap().channel( NioSocketChannel.class ).group( eventLoop ).handler( new HttpInitializer( callback, ssl ) ).
+ new Bootstrap().channel( PipelineUtils.getChannel() ).group( eventLoop ).handler( new HttpInitializer( callback, ssl ) ).
option( ChannelOption.CONNECT_TIMEOUT_MILLIS, TIMEOUT ).remoteAddress( inetHost, port ).connect().addListener( future );
}
}
diff --git a/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java b/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java
index 24261072b..8239799fa 100644
--- a/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java
+++ b/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java
@@ -5,13 +5,25 @@ import io.netty.channel.Channel;
import io.netty.channel.ChannelException;
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.EpollEventLoopGroup;
+import io.netty.channel.epoll.EpollServerSocketChannel;
+import io.netty.channel.epoll.EpollSocketChannel;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.util.AttributeKey;
+import io.netty.util.internal.PlatformDependent;
import java.net.InetSocketAddress;
+import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
import net.md_5.bungee.BungeeCord;
import net.md_5.bungee.BungeeServerInfo;
import net.md_5.bungee.UserConnection;
+import net.md_5.bungee.Util;
import net.md_5.bungee.connection.InitialHandler;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.config.ListenerInfo;
@@ -62,6 +74,47 @@ public class PipelineUtils
public static String LEGACY_DECODER = "legacy-decoder";
public static String LEGACY_KICKER = "legacy-kick";
+ private static boolean epoll;
+
+ static
+ {
+ if ( !PlatformDependent.isWindows() )
+ {
+ ProxyServer.getInstance().getLogger().info( "Not on Windows, attempting to use enhanced EpollEventLoop" );
+ EpollEventLoopGroup testGroup = null;
+ try
+ {
+ testGroup = new EpollEventLoopGroup( 1 );
+ epoll = true;
+ ProxyServer.getInstance().getLogger().info( "Epoll is working, utilising it!" );
+ } catch ( Throwable t )
+ {
+ ProxyServer.getInstance().getLogger().log( Level.WARNING, "Event though Epoll should be supported, it is not working, falling back to NIO: {0}", Util.exception( t ) );
+ } finally
+ {
+ if ( testGroup != null )
+ {
+ testGroup.shutdownGracefully();
+ }
+ }
+ }
+ }
+
+ public static EventLoopGroup newEventLoopGroup(int threads, ThreadFactory factory)
+ {
+ return epoll ? new EpollEventLoopGroup( threads, factory ) : new NioEventLoopGroup( threads, factory );
+ }
+
+ public static Class extends ServerChannel> getServerChannel()
+ {
+ return epoll ? EpollServerSocketChannel.class : NioServerSocketChannel.class;
+ }
+
+ public static Class extends Channel> getChannel()
+ {
+ return epoll ? EpollSocketChannel.class : NioSocketChannel.class;
+ }
+
public final static class Base extends ChannelInitializer
{