diff --git a/netty/src/main/java/io/grpc/netty/NettyServerTransport.java b/netty/src/main/java/io/grpc/netty/NettyServerTransport.java index 41e79f3f1c..7fb37a6b36 100644 --- a/netty/src/main/java/io/grpc/netty/NettyServerTransport.java +++ b/netty/src/main/java/io/grpc/netty/NettyServerTransport.java @@ -38,6 +38,7 @@ import io.grpc.internal.ServerTransportListener; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandler; import io.netty.handler.codec.http2.DefaultHttp2Connection; import io.netty.handler.codec.http2.DefaultHttp2FrameReader; import io.netty.handler.codec.http2.DefaultHttp2FrameWriter; @@ -84,19 +85,20 @@ class NettyServerTransport implements ServerTransport { this.listener = listener; // Create the Netty handler for the pipeline. - final NettyServerHandler handler = createHandler(listener); + final NettyServerHandler grpcHandler = createHandler(listener); // Notify when the channel closes. channel.closeFuture().addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { - notifyTerminated(handler.connectionError()); + notifyTerminated(grpcHandler.connectionError()); } }); + ChannelHandler handler = grpcHandler; if (sslContext != null) { SSLEngine sslEngine = sslContext.newEngine(channel.alloc()); - channel.pipeline().addLast(ProtocolNegotiators.serverTls(sslEngine)); + handler = ProtocolNegotiators.serverTls(sslEngine, grpcHandler); } channel.pipeline().addLast(handler); } diff --git a/netty/src/main/java/io/grpc/netty/ProtocolNegotiators.java b/netty/src/main/java/io/grpc/netty/ProtocolNegotiators.java index 20e54f44f1..801a4c0851 100644 --- a/netty/src/main/java/io/grpc/netty/ProtocolNegotiators.java +++ b/netty/src/main/java/io/grpc/netty/ProtocolNegotiators.java @@ -76,7 +76,7 @@ public final class ProtocolNegotiators { /** * Create a TLS handler for HTTP/2 capable of using ALPN/NPN. */ - public static ChannelHandler serverTls(SSLEngine sslEngine) { + public static ChannelHandler serverTls(SSLEngine sslEngine, final ChannelHandler grpcHandler) { Preconditions.checkNotNull(sslEngine, "sslEngine"); final SslHandler sslHandler = new SslHandler(sslEngine, false); @@ -97,11 +97,11 @@ public final class ProtocolNegotiators { if (evt instanceof SslHandshakeCompletionEvent) { SslHandshakeCompletionEvent handshakeEvent = (SslHandshakeCompletionEvent) evt; if (handshakeEvent.isSuccess()) { - if (applicationProtocol(ctx) != null) { - // Successfully negotiated the protocol. - ctx.pipeline().remove(this); + if (sslHandler(ctx).applicationProtocol() != null) { + // Successfully negotiated the protocol. Replace this handler with + // the GRPC handler. + ctx.pipeline().replace(this, null, grpcHandler); } else { - fail(ctx, new Exception( "Failed protocol negotiation: Unable to find compatible protocol.")); } @@ -113,34 +113,16 @@ public final class ProtocolNegotiators { } private void fail(ChannelHandlerContext ctx, Throwable exception) { - log.log(Level.FINE, errorMessage(ctx), exception); + Level level = Level.FINE; + if (log.isLoggable(level)) { + log.log(level, errorMessage(ctx), exception); + } ctx.close(); } private String errorMessage(ChannelHandlerContext ctx) { - StringBuilder builder = new StringBuilder("TLS negotiation failed for new client. "); - SSLEngine engine = sslHandler(ctx).engine(); - if (engine instanceof OpenSslEngine) { - builder.append("OpenSSL version: "); - builder.append("0x").append(Integer.toHexString(OpenSsl.version())); - builder.append(" [").append(OpenSsl.versionString()).append(']'); - builder.append(". ALPN supported: ").append(OpenSsl.isAlpnSupported()).append(". "); - } else if (JettyTlsUtil.isJettyAlpnConfigured()) { - builder.append("Jetty ALPN configured. "); - } else if (JettyTlsUtil.isJettyNpnConfigured()) { - builder.append("Jetty NPN configured. "); - } - builder.append("Enabled ciphers="); - builder.append(Arrays.toString(enabledCiphers(ctx))).append(". "); - return builder.toString(); - } - - private String applicationProtocol(ChannelHandlerContext ctx) { - return sslHandler(ctx).applicationProtocol(); - } - - private String[] enabledCiphers(ChannelHandlerContext ctx) { - return sslHandler(ctx).engine().getEnabledCipherSuites(); + StringBuilder builder = new StringBuilder("TLS negotiation failed for new client.\n"); + return sslEngineDetails(sslHandler(ctx), builder).toString(); } private SslHandler sslHandler(ChannelHandlerContext ctx) { @@ -213,6 +195,39 @@ public final class ProtocolNegotiators { return Status.UNAVAILABLE.withDescription(msg).asRuntimeException(); } + private static StringBuilder sslEngineDetails(SslHandler sslHandler, StringBuilder builder) { + SSLEngine engine = sslHandler.engine(); + builder.append("SSLEngine Details: [\n"); + if (engine instanceof OpenSslEngine) { + builder.append(" OpenSSL, "); + builder.append("Version: 0x").append(Integer.toHexString(OpenSsl.version())); + builder.append(" (").append(OpenSsl.versionString()).append("), "); + builder.append("ALPN supported: ").append(OpenSsl.isAlpnSupported()); + } else if (JettyTlsUtil.isJettyAlpnConfigured()) { + builder.append(" Jetty ALPN"); + } else if (JettyTlsUtil.isJettyNpnConfigured()) { + builder.append(" Jetty NPN"); + } + builder.append("\n TLS Protocol: "); + builder.append(engine.getSession().getProtocol()); + builder.append("\n Application Protocol: "); + builder.append(sslHandler.applicationProtocol()); + builder.append("\n Need Client Auth: " ); + builder.append(engine.getNeedClientAuth()); + builder.append("\n Want Client Auth: "); + builder.append(engine.getWantClientAuth()); + builder.append("\n Supported protocols="); + builder.append(Arrays.toString(engine.getSupportedProtocols())); + builder.append("\n Enabled protocols="); + builder.append(Arrays.toString(engine.getEnabledProtocols())); + builder.append("\n Supported ciphers="); + builder.append(Arrays.toString(engine.getSupportedCipherSuites())); + builder.append("\n Enabled ciphers="); + builder.append(Arrays.toString(engine.getEnabledCipherSuites())); + builder.append("\n]"); + return builder; + } + /** * Buffers all writes until either {@link #writeBufferedAndRemove(ChannelHandlerContext)} or * {@link #fail(ChannelHandlerContext, Throwable)} is called. This handler allows us to