public void connect(ServerInfo info, final Callback<Boolean> callback, final boolean retry) { Preconditions.checkNotNull(info, "info"); ServerConnectEvent event = new ServerConnectEvent(this, info); if (bungee.getPluginManager().callEvent(event).isCancelled()) { return; } final BungeeServerInfo target = (BungeeServerInfo) event.getTarget(); // Update in case the event changed target if (getServer() != null && Objects.equals(getServer().getInfo(), target)) { sendMessage(bungee.getTranslation("already_connected")); return; } if (pendingConnects.contains(target)) { sendMessage(bungee.getTranslation("already_connecting")); return; } pendingConnects.add(target); ChannelInitializer initializer = new ChannelInitializer() { @Override protected void initChannel(Channel ch) throws Exception { PipelineUtils.BASE.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 public void operationComplete(ChannelFuture future) throws Exception { if (callback != null) { callback.done(future.isSuccess(), future.cause()); } if (!future.isSuccess()) { future.channel().close(); pendingConnects.remove(target); ServerInfo def = ProxyServer.getInstance() .getServers() .get(getPendingConnection().getListener().getFallbackServer()); if (retry && target != def && (getServer() == null || def != getServer().getInfo())) { sendMessage(bungee.getTranslation("fallback_lobby")); connect(def, null, false); } else { if (dimensionChange) { disconnect( bungee.getTranslation("fallback_kick") + future.cause().getClass().getName()); } else { sendMessage( bungee.getTranslation("fallback_kick") + future.cause().getClass().getName()); } } } } }; Bootstrap b = new Bootstrap() .channel(NioSocketChannel.class) .group(ch.getHandle().eventLoop()) .handler(initializer) .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000) // TODO: Configurable .remoteAddress(target.getAddress()); // Windows is bugged, multi homed users will just have to live with random connecting IPs if (getPendingConnection().getListener().isSetLocalAddress() && !PlatformDependent.isWindows()) { b.localAddress(getPendingConnection().getListener().getHost().getHostString(), 0); } b.connect().addListener(listener); }
@Override public Future<PCEPSession> createClient( @Nonnull final InetSocketAddress remoteAddress, @Nonnull final long reconnectTime, @Nonnull final PCEPSessionListenerFactory listenerFactory, @Nonnull final PCEPSessionNegotiatorFactory negotiatorFactory, @Nonnull final KeyMapping keys, @Nullable final InetSocketAddress localAddress, @Nonnull final BigInteger dbVersion) { final Bootstrap b = new Bootstrap(); b.group(this.workerGroup); b.localAddress(localAddress); setChannelFactory(b, keys); b.option(ChannelOption.SO_KEEPALIVE, true); b.option(ChannelOption.MAX_MESSAGES_PER_READ, 1); final ReconnectStrategyFactory reconnectStrategy = reconnectTime == -1 ? getNeverReconnectStrategyFactory() : getTimedReconnectStrategyFactory(reconnectTime); final PCCReconnectPromise promise = new PCCReconnectPromise(remoteAddress, reconnectStrategy, b); final ChannelInitializer<SocketChannel> channelInitializer = new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(final SocketChannel ch) throws Exception { ch.pipeline().addLast(PCCDispatcherImpl.this.factory.getDecoders()); ch.pipeline() .addLast( "negotiator", negotiatorFactory.getSessionNegotiator( listenerFactory, ch, promise, new PCCPeerProposal(dbVersion))); ch.pipeline().addLast(PCCDispatcherImpl.this.factory.getEncoders()); ch.pipeline() .addLast( new ChannelInboundHandlerAdapter() { @Override public void channelInactive(final ChannelHandlerContext ctx) throws Exception { if (promise.isCancelled()) { return; } if (!promise.isInitialConnectFinished()) { LOG.debug( "Connection to {} was dropped during negotiation, reattempting", remoteAddress); return; } LOG.debug("Reconnecting after connection to {} was dropped", remoteAddress); PCCDispatcherImpl.this.createClient( remoteAddress, reconnectTime, listenerFactory, negotiatorFactory, keys, localAddress, dbVersion); } }); } }; b.handler(channelInitializer); promise.connect(); return promise; }