Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose ChannelInitializerHolder in protocol module #3776

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package net.md_5.bungee.protocol.channel;

import com.google.common.base.Preconditions;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

/*
* This class holds all minecraft related channel initializers. BungeeCord will set these values
* on startup, and they can be used by third party plugins to modify the channel pipeline.
*
* Please note that this API is unsafe and doesn't provide any guarantees about the stability of the
* channel pipeline. Use at your own risk.
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public abstract class BungeeChannelInitializer
{
/**
* Holds the channel initializer for incoming connections
*/
@Getter
private static BungeeChannelInitializer frontendHolder;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these shouldn't be static

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should i put the non static objects into BungeeCord.java and make them accessable via

ProxyServer.getInstance().unsafe()?

/**
* Holds the channel initializer for the connection to the backend server
*/
@Getter
private static BungeeChannelInitializer backendHolder;
/**
* Holds the channel initializer for server info requests to the backend server
*/
@Getter
private static BungeeChannelInitializer serverInfoHolder;

public abstract ChannelAcceptor getChannelAcceptor();
public abstract ChannelInitializer<Channel> getChannelInitializer();

/**
* Creates a new instance of BungeeChannelInitializer
*
* @param acceptor the {@link ChannelAcceptor} that will accept the channel and initializer the pipeline
* @return {@link BungeeChannelInitializer} containing a cached {@link ChannelInitializer} that will call the acceptor
*/
public static BungeeChannelInitializer create(ChannelAcceptor acceptor)
{
return new BungeeChannelInitializer()
{
@Getter
private final ChannelAcceptor channelAcceptor = acceptor;

@Getter // cache the ChannelInitializer
private final ChannelInitializer<Channel> channelInitializer = new ChannelInitializer<Channel>()
{
@Override
protected void initChannel(Channel channel) throws Exception
{
if ( !getChannelAcceptor().accept( channel ) )
{
channel.close();
}
}
};
};
}

public static void setFrontendHolder(BungeeChannelInitializer channelInitializer)
{
Preconditions.checkNotNull( channelInitializer, "channelInitializer" );
frontendHolder = channelInitializer;
}

public static void setBackendHolder(BungeeChannelInitializer channelInitializer)
{
Preconditions.checkNotNull( channelInitializer, "channelInitializer" );
backendHolder = channelInitializer;
}

public static void setServerInfoHolder(BungeeChannelInitializer channelInitializer)
{
Preconditions.checkNotNull( channelInitializer, "channelInitializer" );
serverInfoHolder = channelInitializer;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package net.md_5.bungee.protocol.channel;

import io.netty.channel.Channel;

@FunctionalInterface
public interface ChannelAcceptor
{
/**
* Inside this method the pipeline should be initialized.
*
* @param channel the channel to be accepted and initialized
* @return if the channel was accepted
*/
boolean accept(Channel channel);
}
3 changes: 2 additions & 1 deletion proxy/src/main/java/net/md_5/bungee/BungeeCord.java
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
import net.md_5.bungee.netty.PipelineUtils;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.ProtocolConstants;
import net.md_5.bungee.protocol.channel.BungeeChannelInitializer;
import net.md_5.bungee.protocol.packet.PluginMessage;
import net.md_5.bungee.query.RemoteQuery;
import net.md_5.bungee.scheduler.BungeeScheduler;
Expand Down Expand Up @@ -360,7 +361,7 @@ public void operationComplete(ChannelFuture future) throws Exception
.channel( PipelineUtils.getServerChannel( info.getSocketAddress() ) )
.option( ChannelOption.SO_REUSEADDR, true ) // TODO: Move this elsewhere!
.childAttr( PipelineUtils.LISTENER, info )
.childHandler( PipelineUtils.SERVER_CHILD )
.childHandler( BungeeChannelInitializer.getFrontendHolder().getChannelInitializer() )
.group( eventLoops )
.localAddress( info.getSocketAddress() )
.bind().addListener( listener );
Expand Down
3 changes: 2 additions & 1 deletion proxy/src/main/java/net/md_5/bungee/BungeeServerInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import net.md_5.bungee.netty.HandlerBoss;
import net.md_5.bungee.netty.PipelineUtils;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.channel.BungeeChannelInitializer;
import net.md_5.bungee.protocol.packet.PluginMessage;

// CHECKSTYLE:OFF
Expand Down Expand Up @@ -186,7 +187,7 @@ public void operationComplete(ChannelFuture future) throws Exception
new Bootstrap()
.channel( PipelineUtils.getChannel( socketAddress ) )
.group( BungeeCord.getInstance().eventLoops )
.handler( PipelineUtils.BASE_SERVERSIDE )
.handler( BungeeChannelInitializer.getServerInfoHolder().getChannelInitializer() )
.option( ChannelOption.CONNECT_TIMEOUT_MILLIS, BungeeCord.getInstance().getConfig().getRemotePingTimeout() )
.remoteAddress( socketAddress )
.connect()
Expand Down
1 change: 1 addition & 0 deletions proxy/src/main/java/net/md_5/bungee/ServerConnector.java
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ public void exception(Throwable t) throws Exception
@Override
public void connected(ChannelWrapper channel) throws Exception
{
channel.setVersion( user.getPendingConnection().getVersion() );
this.ch = channel;

this.handshakeHandler = new ForgeServerHandler( user, ch, target );
Expand Down
21 changes: 5 additions & 16 deletions proxy/src/main/java/net/md_5/bungee/UserConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.util.internal.PlatformDependent;
import java.net.InetSocketAddress;
Expand Down Expand Up @@ -50,11 +48,10 @@
import net.md_5.bungee.netty.HandlerBoss;
import net.md_5.bungee.netty.PipelineUtils;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.MinecraftDecoder;
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.ProtocolConstants;
import net.md_5.bungee.protocol.channel.BungeeChannelInitializer;
import net.md_5.bungee.protocol.packet.Chat;
import net.md_5.bungee.protocol.packet.ClientSettings;
import net.md_5.bungee.protocol.packet.Kick;
Expand Down Expand Up @@ -362,17 +359,6 @@ private void connect0(final ServerConnectRequest request)

pendingConnects.add( target );

ChannelInitializer initializer = new ChannelInitializer()
{
@Override
protected void initChannel(Channel ch) throws Exception
{
PipelineUtils.BASE_SERVERSIDE.initChannel( ch );
ch.pipeline().addAfter( PipelineUtils.FRAME_DECODER, PipelineUtils.PACKET_DECODER, new MinecraftDecoder( Protocol.HANDSHAKE, false, getPendingConnection().getVersion() ) );
ch.pipeline().addAfter( PipelineUtils.FRAME_PREPENDER, PipelineUtils.PACKET_ENCODER, new MinecraftEncoder( Protocol.HANDSHAKE, false, getPendingConnection().getVersion() ) );
ch.pipeline().get( HandlerBoss.class ).setHandler( new ServerConnector( bungee, UserConnection.this, target ) );
}
};
ChannelFutureListener listener = new ChannelFutureListener()
{
@Override
Expand Down Expand Up @@ -401,13 +387,16 @@ public void operationComplete(ChannelFuture future) throws Exception
{
sendMessage( bungee.getTranslation( "fallback_kick", connectionFailMessage( future.cause() ) ) );
}
} else
{
future.channel().pipeline().get( HandlerBoss.class ).setHandler( new ServerConnector( bungee, UserConnection.this, target ) );
}
}
};
Bootstrap b = new Bootstrap()
.channel( PipelineUtils.getChannel( target.getAddress() ) )
.group( ch.getHandle().eventLoop() )
.handler( initializer )
.handler( BungeeChannelInitializer.getBackendHolder().getChannelInitializer() )
.option( ChannelOption.CONNECT_TIMEOUT_MILLIS, request.getConnectTimeout() )
.remoteAddress( target.getAddress() );
// Windows is bugged, multi homed users will just have to live with random connecting IPs
Expand Down
44 changes: 29 additions & 15 deletions proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import io.netty.buffer.PooledByteBufAllocator;
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;
Expand Down Expand Up @@ -51,33 +50,33 @@
import net.md_5.bungee.protocol.Varint21FrameDecoder;
import net.md_5.bungee.protocol.Varint21LengthFieldExtraBufPrepender;
import net.md_5.bungee.protocol.Varint21LengthFieldPrepender;
import net.md_5.bungee.protocol.channel.BungeeChannelInitializer;
import net.md_5.bungee.protocol.channel.ChannelAcceptor;

public class PipelineUtils
{

public static final AttributeKey<ListenerInfo> LISTENER = AttributeKey.valueOf( "ListerInfo" );
public static final ChannelInitializer<Channel> SERVER_CHILD = new ChannelInitializer<Channel>()

private static void setChannelInitializerHolders()
{
@Override
protected void initChannel(Channel ch) throws Exception
BungeeChannelInitializer.setFrontendHolder( BungeeChannelInitializer.create( ch ->
{
SocketAddress remoteAddress = ( ch.remoteAddress() == null ) ? ch.parent().localAddress() : ch.remoteAddress();

if ( BungeeCord.getInstance().getConnectionThrottle() != null && BungeeCord.getInstance().getConnectionThrottle().throttle( remoteAddress ) )
{
ch.close();
return;
return false;
}

ListenerInfo listener = ch.attr( LISTENER ).get();

if ( BungeeCord.getInstance().getPluginManager().callEvent( new ClientConnectEvent( remoteAddress, listener ) ).isCancelled() )
{
ch.close();
return;
return false;
}

BASE.initChannel( ch );
BASE.accept( ch );
ch.pipeline().addBefore( FRAME_DECODER, LEGACY_DECODER, new LegacyDecoder() );
ch.pipeline().addAfter( FRAME_DECODER, PACKET_DECODER, new MinecraftDecoder( Protocol.HANDSHAKE, true, ProxyServer.getInstance().getProtocolVersion() ) );
ch.pipeline().addAfter( FRAME_PREPENDER, PACKET_ENCODER, new MinecraftEncoder( Protocol.HANDSHAKE, true, ProxyServer.getInstance().getProtocolVersion() ) );
Expand All @@ -88,10 +87,22 @@ protected void initChannel(Channel ch) throws Exception
{
ch.pipeline().addFirst( new HAProxyMessageDecoder() );
}
}
};
public static final Base BASE = new Base( false );
public static final Base BASE_SERVERSIDE = new Base( true );
return true;
} ) );

BungeeChannelInitializer.setBackendHolder( BungeeChannelInitializer.create( ch ->
{
PipelineUtils.BASE_SERVERSIDE.accept( ch );
ch.pipeline().addAfter( PipelineUtils.FRAME_DECODER, PipelineUtils.PACKET_DECODER, new MinecraftDecoder( Protocol.HANDSHAKE, false, ProxyServer.getInstance().getProtocolVersion() ) );
ch.pipeline().addAfter( PipelineUtils.FRAME_PREPENDER, PipelineUtils.PACKET_ENCODER, new MinecraftEncoder( Protocol.HANDSHAKE, false, ProxyServer.getInstance().getProtocolVersion() ) );
return true;
} ) );

BungeeChannelInitializer.setServerInfoHolder( BungeeChannelInitializer.create( BASE_SERVERSIDE ) );
}

private static final ChannelAcceptor BASE = new Base( false );
private static final ChannelAcceptor BASE_SERVERSIDE = new Base( true );
private static final KickStringWriter legacyKicker = new KickStringWriter();
private static final Varint21LengthFieldExtraBufPrepender serverFramePrepender = new Varint21LengthFieldExtraBufPrepender();
public static final String TIMEOUT_HANDLER = "timeout";
Expand Down Expand Up @@ -137,6 +148,8 @@ protected void initChannel(Channel ch) throws Exception
}
}
}

setChannelInitializerHolders();
}

public static EventLoopGroup newEventLoopGroup(int threads, ThreadFactory factory)
Expand Down Expand Up @@ -179,13 +192,13 @@ public static Class<? extends DatagramChannel> getDatagramChannel()

@NoArgsConstructor // for backwards compatibility
@AllArgsConstructor
public static final class Base extends ChannelInitializer<Channel>
public static final class Base implements ChannelAcceptor
{

private boolean toServer = false;

@Override
public void initChannel(Channel ch) throws Exception
public boolean accept(Channel ch)
{
try
{
Expand All @@ -204,6 +217,7 @@ public void initChannel(Channel ch) throws Exception
ch.pipeline().addLast( FRAME_PREPENDER, ( toServer ) ? serverFramePrepender : new Varint21LengthFieldPrepender() );

ch.pipeline().addLast( BOSS_HANDLER, new HandlerBoss() );
return true;
}
}
}