diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..60a8142
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+SOURCES/netty-4.0.28.Final.tar.gz
diff --git a/.rh-java-common-netty.metadata b/.rh-java-common-netty.metadata
new file mode 100644
index 0000000..cf488fa
--- /dev/null
+++ b/.rh-java-common-netty.metadata
@@ -0,0 +1 @@
+b2fe0c498f7bb85f5f98c4992ffef082bc62cfc2 SOURCES/netty-4.0.28.Final.tar.gz
diff --git a/README.md b/README.md
deleted file mode 100644
index 98f42b4..0000000
--- a/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-The master branch has no content
-
-Look at the c7 branch if you are working with CentOS-7, or the c4/c5/c6 branch for CentOS-4, 5 or 6
-If you find this file in a distro specific branch, it means that no content has been checked in yet
diff --git a/SOURCES/netty-old-jzlib.patch b/SOURCES/netty-old-jzlib.patch
new file mode 100644
index 0000000..45db8de
--- /dev/null
+++ b/SOURCES/netty-old-jzlib.patch
@@ -0,0 +1,91 @@
+--- codec/src/main/java/io/netty/handler/codec/compression/JZlibEncoder.java.orig 2015-07-03 11:47:23.545978767 +0100
++++ codec/src/main/java/io/netty/handler/codec/compression/JZlibEncoder.java 2015-07-03 11:47:33.284855182 +0100
+@@ -140,8 +140,7 @@
+ }
+
+ int resultCode = z.init(
+- compressionLevel, windowBits, memLevel,
+- ZlibUtil.convertWrapperType(wrapper));
++ compressionLevel, windowBits, memLevel);
+ if (resultCode != JZlib.Z_OK) {
+ ZlibUtil.fail(z, "initialization failure", resultCode);
+ }
+@@ -225,8 +225,7 @@
+ }
+ int resultCode;
+ resultCode = z.deflateInit(
+- compressionLevel, windowBits, memLevel,
+- JZlib.W_ZLIB); // Default: ZLIB format
++ compressionLevel, windowBits, memLevel);
+ if (resultCode != JZlib.Z_OK) {
+ ZlibUtil.fail(z, "initialization failure", resultCode);
+ } else {
+--- codec/src/main/java/io/netty/handler/codec/compression/JZlibDecoder.java.orig 2015-07-03 11:45:12.040647549 +0100
++++ codec/src/main/java/io/netty/handler/codec/compression/JZlibDecoder.java 2015-07-03 11:45:42.114265920 +0100
+@@ -47,7 +47,7 @@
+ throw new NullPointerException("wrapper");
+ }
+
+- int resultCode = z.init(ZlibUtil.convertWrapperType(wrapper));
++ int resultCode = z.init();
+ if (resultCode != JZlib.Z_OK) {
+ ZlibUtil.fail(z, "initialization failure", resultCode);
+ }
+@@ -67,7 +67,7 @@
+ this.dictionary = dictionary;
+
+ int resultCode;
+- resultCode = z.inflateInit(JZlib.W_ZLIB);
++ resultCode = z.inflateInit();
+ if (resultCode != JZlib.Z_OK) {
+ ZlibUtil.fail(z, "initialization failure", resultCode);
+ }
+--- codec/src/main/java/io/netty/handler/codec/compression/ZlibUtil.java.orig 2015-07-03 11:51:33.209807700 +0100
++++ codec/src/main/java/io/netty/handler/codec/compression/ZlibUtil.java 2015-07-03 11:58:07.594767969 +0100
+@@ -17,7 +17,6 @@
+
+ import com.jcraft.jzlib.Deflater;
+ import com.jcraft.jzlib.Inflater;
+-import com.jcraft.jzlib.JZlib;
+
+ /**
+ * Utility methods used by {@link JZlibEncoder} and {@link JZlibDecoder}.
+@@ -40,27 +39,6 @@
+ return new CompressionException(message + " (" + resultCode + ')' + (z.msg != null? ": " + z.msg : ""));
+ }
+
+- static JZlib.WrapperType convertWrapperType(ZlibWrapper wrapper) {
+- JZlib.WrapperType convertedWrapperType;
+- switch (wrapper) {
+- case NONE:
+- convertedWrapperType = JZlib.W_NONE;
+- break;
+- case ZLIB:
+- convertedWrapperType = JZlib.W_ZLIB;
+- break;
+- case GZIP:
+- convertedWrapperType = JZlib.W_GZIP;
+- break;
+- case ZLIB_OR_NONE:
+- convertedWrapperType = JZlib.W_ANY;
+- break;
+- default:
+- throw new Error();
+- }
+- return convertedWrapperType;
+- }
+-
+ static int wrapperOverhead(ZlibWrapper wrapper) {
+ int overhead;
+ switch (wrapper) {
+--- codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHeaderBlockJZlibEncoder.java.orig 2015-07-03 12:04:31.063867729 +0100
++++ codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHeaderBlockJZlibEncoder.java 2015-07-03 12:04:39.829755712 +0100
+@@ -47,7 +47,7 @@
+ }
+
+ int resultCode = z.deflateInit(
+- compressionLevel, windowBits, memLevel, JZlib.W_ZLIB);
++ compressionLevel, windowBits, memLevel);
+ if (resultCode != JZlib.Z_OK) {
+ throw new CompressionException(
+ "failed to initialize an SPDY header block deflater: " + resultCode);
diff --git a/SOURCES/npn_alpn_ssl_fixes.patch b/SOURCES/npn_alpn_ssl_fixes.patch
new file mode 100644
index 0000000..48c4842
--- /dev/null
+++ b/SOURCES/npn_alpn_ssl_fixes.patch
@@ -0,0 +1,4384 @@
+commit b654e334d8df083dca71f330c6d9d7306ab78649
+Author: Severin Gehwolf
+Date: Wed May 20 13:19:37 2015 +0200
+
+ Remove optional NPN/ALPN/OpenSSL handlers.
+
+diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
+deleted file mode 100644
+index aaaf5b7..0000000
+--- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
++++ /dev/null
+@@ -1,120 +0,0 @@
+-/*
+- * Copyright 2014 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import javax.net.ssl.SSLEngine;
+-
+-/**
+- * The {@link JdkApplicationProtocolNegotiator} to use if you need ALPN and are using {@link SslProvider#JDK}.
+- */
+-public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator {
+- private static final SslEngineWrapperFactory ALPN_WRAPPER = new SslEngineWrapperFactory() {
+- {
+- if (!JdkAlpnSslEngine.isAvailable()) {
+- throw new RuntimeException("ALPN unsupported. Is your classpatch configured correctly?"
+- + " See http://www.eclipse.org/jetty/documentation/current/alpn-chapter.html#alpn-starting");
+- }
+- }
+-
+- @Override
+- public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator,
+- boolean isServer) {
+- return new JdkAlpnSslEngine(engine, applicationNegotiator, isServer);
+- }
+- };
+-
+- /**
+- * Create a new instance.
+- * @param protocols The order of iteration determines the preference of support for protocols.
+- */
+- public JdkAlpnApplicationProtocolNegotiator(Iterable protocols) {
+- this(false, protocols);
+- }
+-
+- /**
+- * Create a new instance.
+- * @param protocols The order of iteration determines the preference of support for protocols.
+- */
+- public JdkAlpnApplicationProtocolNegotiator(String... protocols) {
+- this(false, protocols);
+- }
+-
+- /**
+- * Create a new instance.
+- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected.
+- * @param protocols The order of iteration determines the preference of support for protocols.
+- */
+- public JdkAlpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, Iterable protocols) {
+- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols);
+- }
+-
+- /**
+- * Create a new instance.
+- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected.
+- * @param protocols The order of iteration determines the preference of support for protocols.
+- */
+- public JdkAlpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, String... protocols) {
+- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols);
+- }
+-
+- /**
+- * Create a new instance.
+- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected.
+- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected.
+- * @param protocols The order of iteration determines the preference of support for protocols.
+- */
+- public JdkAlpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols,
+- boolean serverFailIfNoCommonProtocols, Iterable protocols) {
+- this(serverFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY,
+- clientFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY,
+- protocols);
+- }
+-
+- /**
+- * Create a new instance.
+- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected.
+- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected.
+- * @param protocols The order of iteration determines the preference of support for protocols.
+- */
+- public JdkAlpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols,
+- boolean serverFailIfNoCommonProtocols, String... protocols) {
+- this(serverFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY,
+- clientFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY,
+- protocols);
+- }
+-
+- /**
+- * Create a new instance.
+- * @param selectorFactory The factory which provides classes responsible for selecting the protocol.
+- * @param listenerFactory The factory which provides to be notified of which protocol was selected.
+- * @param protocols The order of iteration determines the preference of support for protocols.
+- */
+- public JdkAlpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory,
+- ProtocolSelectionListenerFactory listenerFactory, Iterable protocols) {
+- super(ALPN_WRAPPER, selectorFactory, listenerFactory, protocols);
+- }
+-
+- /**
+- * Create a new instance.
+- * @param selectorFactory The factory which provides classes responsible for selecting the protocol.
+- * @param listenerFactory The factory which provides to be notified of which protocol was selected.
+- * @param protocols The order of iteration determines the preference of support for protocols.
+- */
+- public JdkAlpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory,
+- ProtocolSelectionListenerFactory listenerFactory, String... protocols) {
+- super(ALPN_WRAPPER, selectorFactory, listenerFactory, protocols);
+- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnSslEngine.java
+deleted file mode 100644
+index 6cfacb8..0000000
+--- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnSslEngine.java
++++ /dev/null
+@@ -1,117 +0,0 @@
+-/*
+- * Copyright 2014 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import static io.netty.util.internal.ObjectUtil.checkNotNull;
+-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
+-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
+-import io.netty.util.internal.PlatformDependent;
+-
+-import java.util.LinkedHashSet;
+-import java.util.List;
+-
+-import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.SSLException;
+-
+-import org.eclipse.jetty.alpn.ALPN;
+-import org.eclipse.jetty.alpn.ALPN.ClientProvider;
+-import org.eclipse.jetty.alpn.ALPN.ServerProvider;
+-
+-final class JdkAlpnSslEngine extends JdkSslEngine {
+- private static boolean available;
+-
+- static boolean isAvailable() {
+- updateAvailability();
+- return available;
+- }
+-
+- private static void updateAvailability() {
+- if (available) {
+- return;
+- }
+-
+- try {
+- // Always use bootstrap class loader.
+- Class.forName("sun.security.ssl.ALPNExtension", true, null);
+- available = true;
+- } catch (Exception ignore) {
+- // alpn-boot was not loaded.
+- }
+- }
+-
+- JdkAlpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator, boolean server) {
+- super(engine);
+- checkNotNull(applicationNegotiator, "applicationNegotiator");
+-
+- if (server) {
+- final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory()
+- .newSelector(this, new LinkedHashSet(applicationNegotiator.protocols())),
+- "protocolSelector");
+- ALPN.put(engine, new ServerProvider() {
+- @Override
+- public String select(List protocols) {
+- try {
+- return protocolSelector.select(protocols);
+- } catch (Throwable t) {
+- PlatformDependent.throwException(t);
+- return null;
+- }
+- }
+-
+- @Override
+- public void unsupported() {
+- protocolSelector.unsupported();
+- }
+- });
+- } else {
+- final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator
+- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()),
+- "protocolListener");
+- ALPN.put(engine, new ClientProvider() {
+- @Override
+- public List protocols() {
+- return applicationNegotiator.protocols();
+- }
+-
+- @Override
+- public void selected(String protocol) {
+- try {
+- protocolListener.selected(protocol);
+- } catch (Throwable t) {
+- PlatformDependent.throwException(t);
+- }
+- }
+-
+- @Override
+- public void unsupported() {
+- protocolListener.unsupported();
+- }
+- });
+- }
+- }
+-
+- @Override
+- public void closeInbound() throws SSLException {
+- ALPN.remove(getWrappedEngine());
+- super.closeInbound();
+- }
+-
+- @Override
+- public void closeOutbound() {
+- ALPN.remove(getWrappedEngine());
+- super.closeOutbound();
+- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
+deleted file mode 100644
+index c893f05..0000000
+--- a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
++++ /dev/null
+@@ -1,120 +0,0 @@
+-/*
+- * Copyright 2014 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import javax.net.ssl.SSLEngine;
+-
+-/**
+- * The {@link JdkApplicationProtocolNegotiator} to use if you need NPN and are using {@link SslProvider#JDK}.
+- */
+-public final class JdkNpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator {
+- private static final SslEngineWrapperFactory NPN_WRAPPER = new SslEngineWrapperFactory() {
+- {
+- if (!JdkNpnSslEngine.isAvailable()) {
+- throw new RuntimeException("NPN unsupported. Is your classpatch configured correctly?"
+- + " See http://www.eclipse.org/jetty/documentation/current/npn-chapter.html#npn-starting");
+- }
+- }
+-
+- @Override
+- public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator,
+- boolean isServer) {
+- return new JdkNpnSslEngine(engine, applicationNegotiator, isServer);
+- }
+- };
+-
+- /**
+- * Create a new instance.
+- * @param protocols The order of iteration determines the preference of support for protocols.
+- */
+- public JdkNpnApplicationProtocolNegotiator(Iterable protocols) {
+- this(false, protocols);
+- }
+-
+- /**
+- * Create a new instance.
+- * @param protocols The order of iteration determines the preference of support for protocols.
+- */
+- public JdkNpnApplicationProtocolNegotiator(String... protocols) {
+- this(false, protocols);
+- }
+-
+- /**
+- * Create a new instance.
+- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected.
+- * @param protocols The order of iteration determines the preference of support for protocols.
+- */
+- public JdkNpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, Iterable protocols) {
+- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols);
+- }
+-
+- /**
+- * Create a new instance.
+- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected.
+- * @param protocols The order of iteration determines the preference of support for protocols.
+- */
+- public JdkNpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, String... protocols) {
+- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols);
+- }
+-
+- /**
+- * Create a new instance.
+- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected.
+- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected.
+- * @param protocols The order of iteration determines the preference of support for protocols.
+- */
+- public JdkNpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols,
+- boolean serverFailIfNoCommonProtocols, Iterable protocols) {
+- this(clientFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY,
+- serverFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY,
+- protocols);
+- }
+-
+- /**
+- * Create a new instance.
+- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected.
+- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected.
+- * @param protocols The order of iteration determines the preference of support for protocols.
+- */
+- public JdkNpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols,
+- boolean serverFailIfNoCommonProtocols, String... protocols) {
+- this(clientFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY,
+- serverFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY,
+- protocols);
+- }
+-
+- /**
+- * Create a new instance.
+- * @param selectorFactory The factory which provides classes responsible for selecting the protocol.
+- * @param listenerFactory The factory which provides to be notified of which protocol was selected.
+- * @param protocols The order of iteration determines the preference of support for protocols.
+- */
+- public JdkNpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory,
+- ProtocolSelectionListenerFactory listenerFactory, Iterable protocols) {
+- super(NPN_WRAPPER, selectorFactory, listenerFactory, protocols);
+- }
+-
+- /**
+- * Create a new instance.
+- * @param selectorFactory The factory which provides classes responsible for selecting the protocol.
+- * @param listenerFactory The factory which provides to be notified of which protocol was selected.
+- * @param protocols The order of iteration determines the preference of support for protocols.
+- */
+- public JdkNpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory,
+- ProtocolSelectionListenerFactory listenerFactory, String... protocols) {
+- super(NPN_WRAPPER, selectorFactory, listenerFactory, protocols);
+- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkNpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/JdkNpnSslEngine.java
+deleted file mode 100644
+index 422727a..0000000
+--- a/handler/src/main/java/io/netty/handler/ssl/JdkNpnSslEngine.java
++++ /dev/null
+@@ -1,122 +0,0 @@
+-/*
+- * Copyright 2014 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-
+-package io.netty.handler.ssl;
+-
+-import static io.netty.util.internal.ObjectUtil.checkNotNull;
+-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
+-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
+-import io.netty.util.internal.PlatformDependent;
+-
+-import java.util.LinkedHashSet;
+-import java.util.List;
+-
+-import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.SSLException;
+-
+-import org.eclipse.jetty.npn.NextProtoNego;
+-import org.eclipse.jetty.npn.NextProtoNego.ClientProvider;
+-import org.eclipse.jetty.npn.NextProtoNego.ServerProvider;
+-
+-final class JdkNpnSslEngine extends JdkSslEngine {
+- private static boolean available;
+-
+- static boolean isAvailable() {
+- updateAvailability();
+- return available;
+- }
+-
+- private static void updateAvailability() {
+- if (available) {
+- return;
+- }
+- try {
+- // Always use bootstrap class loader.
+- Class.forName("sun.security.ssl.NextProtoNegoExtension", true, null);
+- available = true;
+- } catch (Exception ignore) {
+- // npn-boot was not loaded.
+- }
+- }
+-
+- JdkNpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator, boolean server) {
+- super(engine);
+- checkNotNull(applicationNegotiator, "applicationNegotiator");
+-
+- if (server) {
+- final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator
+- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()),
+- "protocolListener");
+- NextProtoNego.put(engine, new ServerProvider() {
+- @Override
+- public void unsupported() {
+- protocolListener.unsupported();
+- }
+-
+- @Override
+- public List protocols() {
+- return applicationNegotiator.protocols();
+- }
+-
+- @Override
+- public void protocolSelected(String protocol) {
+- try {
+- protocolListener.selected(protocol);
+- } catch (Throwable t) {
+- PlatformDependent.throwException(t);
+- }
+- }
+- });
+- } else {
+- final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory()
+- .newSelector(this, new LinkedHashSet(applicationNegotiator.protocols())),
+- "protocolSelector");
+- NextProtoNego.put(engine, new ClientProvider() {
+- @Override
+- public boolean supports() {
+- return true;
+- }
+-
+- @Override
+- public void unsupported() {
+- protocolSelector.unsupported();
+- }
+-
+- @Override
+- public String selectProtocol(List protocols) {
+- try {
+- return protocolSelector.select(protocols);
+- } catch (Throwable t) {
+- PlatformDependent.throwException(t);
+- return null;
+- }
+- }
+- });
+- }
+- }
+-
+- @Override
+- public void closeInbound() throws SSLException {
+- NextProtoNego.remove(getWrappedEngine());
+- super.closeInbound();
+- }
+-
+- @Override
+- public void closeOutbound() {
+- NextProtoNego.remove(getWrappedEngine());
+- super.closeOutbound();
+- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java
+index 54ee2be..e3ffb67 100644
+--- a/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java
++++ b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java
+@@ -220,50 +220,6 @@ public abstract class JdkSslContext extends SslContext {
+ switch(config.protocol()) {
+ case NONE:
+ return JdkDefaultApplicationProtocolNegotiator.INSTANCE;
+- case ALPN:
+- if (isServer) {
+- switch(config.selectorFailureBehavior()) {
+- case FATAL_ALERT:
+- return new JdkAlpnApplicationProtocolNegotiator(true, config.supportedProtocols());
+- case NO_ADVERTISE:
+- return new JdkAlpnApplicationProtocolNegotiator(false, config.supportedProtocols());
+- default:
+- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ")
+- .append(config.selectorFailureBehavior()).append(" failure behavior").toString());
+- }
+- } else {
+- switch(config.selectedListenerFailureBehavior()) {
+- case ACCEPT:
+- return new JdkAlpnApplicationProtocolNegotiator(false, config.supportedProtocols());
+- case FATAL_ALERT:
+- return new JdkAlpnApplicationProtocolNegotiator(true, config.supportedProtocols());
+- default:
+- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ")
+- .append(config.selectedListenerFailureBehavior()).append(" failure behavior").toString());
+- }
+- }
+- case NPN:
+- if (isServer) {
+- switch(config.selectedListenerFailureBehavior()) {
+- case ACCEPT:
+- return new JdkNpnApplicationProtocolNegotiator(false, config.supportedProtocols());
+- case FATAL_ALERT:
+- return new JdkNpnApplicationProtocolNegotiator(true, config.supportedProtocols());
+- default:
+- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ")
+- .append(config.selectedListenerFailureBehavior()).append(" failure behavior").toString());
+- }
+- } else {
+- switch(config.selectorFailureBehavior()) {
+- case FATAL_ALERT:
+- return new JdkNpnApplicationProtocolNegotiator(true, config.supportedProtocols());
+- case NO_ADVERTISE:
+- return new JdkNpnApplicationProtocolNegotiator(false, config.supportedProtocols());
+- default:
+- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ")
+- .append(config.selectorFailureBehavior()).append(" failure behavior").toString());
+- }
+- }
+ default:
+ throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ")
+ .append(config.protocol()).append(" protocol").toString());
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java b/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java
+deleted file mode 100644
+index 619768a..0000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java
++++ /dev/null
+@@ -1,194 +0,0 @@
+-/*
+- * Copyright 2014 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-
+-package io.netty.handler.ssl;
+-
+-import io.netty.util.internal.NativeLibraryLoader;
+-import io.netty.util.internal.logging.InternalLogger;
+-import io.netty.util.internal.logging.InternalLoggerFactory;
+-import org.apache.tomcat.jni.Library;
+-import org.apache.tomcat.jni.Pool;
+-import org.apache.tomcat.jni.SSL;
+-import org.apache.tomcat.jni.SSLContext;
+-
+-import java.util.Collections;
+-import java.util.LinkedHashSet;
+-import java.util.Set;
+-
+-/**
+- * Tells if {@code netty-tcnative} and its OpenSSL support
+- * are available.
+- */
+-public final class OpenSsl {
+-
+- private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSsl.class);
+- private static final Throwable UNAVAILABILITY_CAUSE;
+-
+- private static final Set AVAILABLE_CIPHER_SUITES;
+-
+- static {
+- Throwable cause = null;
+-
+- // Test if netty-tcnative is in the classpath first.
+- try {
+- Class.forName("org.apache.tomcat.jni.SSL", false, OpenSsl.class.getClassLoader());
+- } catch (ClassNotFoundException t) {
+- cause = t;
+- logger.debug(
+- "netty-tcnative not in the classpath; " +
+- OpenSslEngine.class.getSimpleName() + " will be unavailable.");
+- }
+-
+- // If in the classpath, try to load the native library and initialize netty-tcnative.
+- if (cause == null) {
+- try {
+- NativeLibraryLoader.load("netty-tcnative", SSL.class.getClassLoader());
+- Library.initialize("provided");
+- SSL.initialize(null);
+- } catch (Throwable t) {
+- cause = t;
+- logger.debug(
+- "Failed to load netty-tcnative; " +
+- OpenSslEngine.class.getSimpleName() + " will be unavailable. " +
+- "See http://netty.io/wiki/forked-tomcat-native.html for more information.", t);
+- }
+- }
+-
+- UNAVAILABILITY_CAUSE = cause;
+-
+- if (cause == null) {
+- final Set availableCipherSuites = new LinkedHashSet(128);
+- final long aprPool = Pool.create(0);
+- try {
+- final long sslCtx = SSLContext.make(aprPool, SSL.SSL_PROTOCOL_ALL, SSL.SSL_MODE_SERVER);
+- try {
+- SSLContext.setOptions(sslCtx, SSL.SSL_OP_ALL);
+- SSLContext.setCipherSuite(sslCtx, "ALL");
+- final long ssl = SSL.newSSL(sslCtx, true);
+- try {
+- for (String c: SSL.getCiphers(ssl)) {
+- // Filter out bad input.
+- if (c == null || c.length() == 0 || availableCipherSuites.contains(c)) {
+- continue;
+- }
+- availableCipherSuites.add(c);
+- }
+- } finally {
+- SSL.freeSSL(ssl);
+- }
+- } finally {
+- SSLContext.free(sslCtx);
+- }
+- } catch (Exception e) {
+- logger.warn("Failed to get the list of available OpenSSL cipher suites.", e);
+- } finally {
+- Pool.destroy(aprPool);
+- }
+-
+- AVAILABLE_CIPHER_SUITES = Collections.unmodifiableSet(availableCipherSuites);
+- } else {
+- AVAILABLE_CIPHER_SUITES = Collections.emptySet();
+- }
+- }
+-
+- /**
+- * Returns {@code true} if and only if
+- * {@code netty-tcnative} and its OpenSSL support
+- * are available.
+- */
+- public static boolean isAvailable() {
+- return UNAVAILABILITY_CAUSE == null;
+- }
+-
+- /**
+- * Returns {@code true} if the used version of openssl supports
+- * ALPN.
+- */
+- public static boolean isAlpnSupported() {
+- return version() >= 0x10002000L;
+- }
+-
+- /**
+- * Returns the version of the used available OpenSSL library or {@code -1} if {@link #isAvailable()}
+- * returns {@code false}.
+- */
+- public static int version() {
+- if (isAvailable()) {
+- return SSL.version();
+- }
+- return -1;
+- }
+-
+- /**
+- * Returns the version string of the used available OpenSSL library or {@code null} if {@link #isAvailable()}
+- * returns {@code false}.
+- */
+- public static String versionString() {
+- if (isAvailable()) {
+- return SSL.versionString();
+- }
+- return null;
+- }
+-
+- /**
+- * Ensure that {@code netty-tcnative} and
+- * its OpenSSL support are available.
+- *
+- * @throws UnsatisfiedLinkError if unavailable
+- */
+- public static void ensureAvailability() {
+- if (UNAVAILABILITY_CAUSE != null) {
+- throw (Error) new UnsatisfiedLinkError(
+- "failed to load the required native library").initCause(UNAVAILABILITY_CAUSE);
+- }
+- }
+-
+- /**
+- * Returns the cause of unavailability of
+- * {@code netty-tcnative} and its OpenSSL support.
+- *
+- * @return the cause if unavailable. {@code null} if available.
+- */
+- public static Throwable unavailabilityCause() {
+- return UNAVAILABILITY_CAUSE;
+- }
+-
+- /**
+- * Returns all the available OpenSSL cipher suites.
+- * Please note that the returned array may include the cipher suites that are insecure or non-functional.
+- */
+- public static Set availableCipherSuites() {
+- return AVAILABLE_CIPHER_SUITES;
+- }
+-
+- /**
+- * Returns {@code true} if and only if the specified cipher suite is available in OpenSSL.
+- * Both Java-style cipher suite and OpenSSL-style cipher suite are accepted.
+- */
+- public static boolean isCipherSuiteAvailable(String cipherSuite) {
+- String converted = CipherSuiteConverter.toOpenSsl(cipherSuite);
+- if (converted != null) {
+- cipherSuite = converted;
+- }
+- return AVAILABLE_CIPHER_SUITES.contains(cipherSuite);
+- }
+-
+- static boolean isError(long errorCode) {
+- return errorCode != SSL.SSL_ERROR_NONE;
+- }
+-
+- private OpenSsl() { }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java
+deleted file mode 100644
+index 85f15d1..0000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java
++++ /dev/null
+@@ -1,333 +0,0 @@
+-/*
+- * Copyright 2014 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import io.netty.buffer.ByteBuf;
+-import io.netty.buffer.ByteBufInputStream;
+-import org.apache.tomcat.jni.SSL;
+-import org.apache.tomcat.jni.SSLContext;
+-
+-import javax.net.ssl.KeyManagerFactory;
+-import javax.net.ssl.SSLException;
+-import javax.net.ssl.TrustManager;
+-import javax.net.ssl.TrustManagerFactory;
+-import javax.net.ssl.X509ExtendedTrustManager;
+-import javax.net.ssl.X509TrustManager;
+-import javax.security.auth.x500.X500Principal;
+-import java.io.File;
+-import java.io.IOException;
+-import java.security.KeyStore;
+-import java.security.KeyStoreException;
+-import java.security.NoSuchAlgorithmException;
+-import java.security.cert.CertificateException;
+-import java.security.cert.X509Certificate;
+-
+-/**
+- * A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
+- */
+-public final class OpenSslClientContext extends OpenSslContext {
+- private final OpenSslSessionContext sessionContext;
+-
+- /**
+- * Creates a new instance.
+- */
+- public OpenSslClientContext() throws SSLException {
+- this(null, null, null, null, null, null, null, IdentityCipherSuiteFilter.INSTANCE, null, 0, 0);
+- }
+-
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format.
+- * {@code null} to use the system default
+- */
+- public OpenSslClientContext(File certChainFile) throws SSLException {
+- this(certChainFile, null);
+- }
+-
+- /**
+- * Creates a new instance.
+- *
+- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
+- * that verifies the certificates sent from servers.
+- * {@code null} to use the default.
+- */
+- public OpenSslClientContext(TrustManagerFactory trustManagerFactory) throws SSLException {
+- this(null, trustManagerFactory);
+- }
+-
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format.
+- * {@code null} to use the system default
+- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
+- * that verifies the certificates sent from servers.
+- * {@code null} to use the default.
+- */
+- public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory) throws SSLException {
+- this(certChainFile, trustManagerFactory, null, null, null, null, null,
+- IdentityCipherSuiteFilter.INSTANCE, null, 0, 0);
+- }
+-
+- /**
+- * @deprecated use {@link #OpenSslClientContext(File, TrustManagerFactory, Iterable,
+- * CipherSuiteFilter, ApplicationProtocolConfig, long, long)}
+- *
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
+- * that verifies the certificates sent from servers.
+- * {@code null} to use the default..
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param apn Provides a means to configure parameters related to application protocol negotiation.
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- */
+- @Deprecated
+- public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory, Iterable ciphers,
+- ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout)
+- throws SSLException {
+- this(certChainFile, trustManagerFactory, null, null, null, null, ciphers, IdentityCipherSuiteFilter.INSTANCE,
+- apn, sessionCacheSize, sessionTimeout);
+- }
+-
+- /**
+- * @deprecated use {@link #OpenSslClientContext(File, TrustManagerFactory, File, File, String,
+- * KeyManagerFactory, Iterable, CipherSuiteFilter, ApplicationProtocolConfig,long, long)}
+- *
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
+- * that verifies the certificates sent from servers.
+- * {@code null} to use the default..
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param cipherFilter a filter to apply over the supplied list of ciphers
+- * @param apn Provides a means to configure parameters related to application protocol negotiation.
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- */
+- @Deprecated
+- public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory, Iterable ciphers,
+- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(certChainFile, trustManagerFactory, null, null, null, null,
+- ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout);
+- }
+-
+- /**
+- * Creates a new instance.
+- * @param trustCertChainFile an X.509 certificate chain file in PEM format.
+- * {@code null} to use the system default
+- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
+- * that verifies the certificates sent from servers.
+- * {@code null} to use the default or the results of parsing {@code trustCertChainFile}
+- * @param keyCertChainFile an X.509 certificate chain file in PEM format.
+- * This provides the public key for mutual authentication.
+- * {@code null} to use the system default
+- * @param keyFile a PKCS#8 private key file in PEM format.
+- * This provides the private key for mutual authentication.
+- * {@code null} for no mutual authentication.
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * Ignored if {@code keyFile} is {@code null}.
+- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link javax.net.ssl.KeyManager}s
+- * that is used to encrypt data being sent to servers.
+- * {@code null} to use the default or the results of parsing
+- * {@code keyCertChainFile} and {@code keyFile}.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param cipherFilter a filter to apply over the supplied list of ciphers
+- * @param apn Application Protocol Negotiator object.
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- */
+- public OpenSslClientContext(File trustCertChainFile, TrustManagerFactory trustManagerFactory,
+- File keyCertChainFile, File keyFile, String keyPassword,
+- KeyManagerFactory keyManagerFactory, Iterable ciphers,
+- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
+- long sessionCacheSize, long sessionTimeout)
+- throws SSLException {
+- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT);
+- boolean success = false;
+- try {
+- if (trustCertChainFile != null && !trustCertChainFile.isFile()) {
+- throw new IllegalArgumentException("trustCertChainFile is not a file: " + trustCertChainFile);
+- }
+-
+- if (keyCertChainFile != null && !keyCertChainFile.isFile()) {
+- throw new IllegalArgumentException("keyCertChainFile is not a file: " + keyCertChainFile);
+- }
+-
+- if (keyFile != null && !keyFile.isFile()) {
+- throw new IllegalArgumentException("keyFile is not a file: " + keyFile);
+- }
+- if (keyFile == null && keyCertChainFile != null || keyFile != null && keyCertChainFile == null) {
+- throw new IllegalArgumentException(
+- "Either both keyCertChainFile and keyFile needs to be null or none of them");
+- }
+- synchronized (OpenSslContext.class) {
+- if (trustCertChainFile != null) {
+- /* Load the certificate chain. We must skip the first cert when server mode */
+- if (!SSLContext.setCertificateChainFile(ctx, trustCertChainFile.getPath(), true)) {
+- long error = SSL.getLastErrorNumber();
+- if (OpenSsl.isError(error)) {
+- throw new SSLException(
+- "failed to set certificate chain: "
+- + trustCertChainFile + " (" + SSL.getErrorString(error) + ')');
+- }
+- }
+- }
+- if (keyCertChainFile != null && keyFile != null) {
+- /* Load the certificate file and private key. */
+- try {
+- if (!SSLContext.setCertificate(
+- ctx, keyCertChainFile.getPath(), keyFile.getPath(), keyPassword, SSL.SSL_AIDX_RSA)) {
+- long error = SSL.getLastErrorNumber();
+- if (OpenSsl.isError(error)) {
+- throw new SSLException("failed to set certificate: " +
+- keyCertChainFile + " and " + keyFile +
+- " (" + SSL.getErrorString(error) + ')');
+- }
+- }
+- } catch (SSLException e) {
+- throw e;
+- } catch (Exception e) {
+- throw new SSLException("failed to set certificate: " + keyCertChainFile + " and " + keyFile, e);
+- }
+- }
+-
+- SSLContext.setVerify(ctx, SSL.SSL_VERIFY_NONE, VERIFY_DEPTH);
+-
+- try {
+- // Set up trust manager factory to use our key store.
+- if (trustManagerFactory == null) {
+- trustManagerFactory = TrustManagerFactory.getInstance(
+- TrustManagerFactory.getDefaultAlgorithm());
+- }
+- initTrustManagerFactory(trustCertChainFile, trustManagerFactory);
+- final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers());
+-
+- // Use this to prevent an error when running on java < 7
+- if (useExtendedTrustManager(manager)) {
+- final X509ExtendedTrustManager extendedManager = (X509ExtendedTrustManager) manager;
+- SSLContext.setCertVerifyCallback(ctx, new AbstractCertificateVerifier() {
+- @Override
+- void verify(OpenSslEngine engine, X509Certificate[] peerCerts, String auth)
+- throws Exception {
+- extendedManager.checkServerTrusted(peerCerts, auth, engine);
+- }
+- });
+- } else {
+- SSLContext.setCertVerifyCallback(ctx, new AbstractCertificateVerifier() {
+- @Override
+- void verify(OpenSslEngine engine, X509Certificate[] peerCerts, String auth)
+- throws Exception {
+- manager.checkServerTrusted(peerCerts, auth);
+- }
+- });
+- }
+- } catch (Exception e) {
+- throw new SSLException("unable to setup trustmanager", e);
+- }
+- }
+- sessionContext = new OpenSslClientSessionContext(ctx);
+- success = true;
+- } finally {
+- if (!success) {
+- destroyPools();
+- }
+- }
+- }
+-
+- private static void initTrustManagerFactory(File certChainFile, TrustManagerFactory trustManagerFactory)
+- throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
+- KeyStore ks = KeyStore.getInstance("JKS");
+- ks.load(null, null);
+- if (certChainFile != null) {
+- ByteBuf[] certs = PemReader.readCertificates(certChainFile);
+- try {
+- for (ByteBuf buf: certs) {
+- X509Certificate cert = (X509Certificate) X509_CERT_FACTORY.generateCertificate(
+- new ByteBufInputStream(buf));
+- X500Principal principal = cert.getSubjectX500Principal();
+- ks.setCertificateEntry(principal.getName("RFC2253"), cert);
+- }
+- } finally {
+- for (ByteBuf buf: certs) {
+- buf.release();
+- }
+- }
+- }
+- trustManagerFactory.init(ks);
+- }
+-
+- @Override
+- public OpenSslSessionContext sessionContext() {
+- return sessionContext;
+- }
+-
+- // No cache is currently supported for client side mode.
+- private static final class OpenSslClientSessionContext extends OpenSslSessionContext {
+- private OpenSslClientSessionContext(long context) {
+- super(context);
+- }
+-
+- @Override
+- public void setSessionTimeout(int seconds) {
+- if (seconds < 0) {
+- throw new IllegalArgumentException();
+- }
+- }
+-
+- @Override
+- public int getSessionTimeout() {
+- return 0;
+- }
+-
+- @Override
+- public void setSessionCacheSize(int size) {
+- if (size < 0) {
+- throw new IllegalArgumentException();
+- }
+- }
+-
+- @Override
+- public int getSessionCacheSize() {
+- return 0;
+- }
+-
+- @Override
+- public void setSessionCacheEnabled(boolean enabled) {
+- // ignored
+- }
+-
+- @Override
+- public boolean isSessionCacheEnabled() {
+- return false;
+- }
+- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java
+deleted file mode 100644
+index 6cfdc57..0000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java
++++ /dev/null
+@@ -1,456 +0,0 @@
+-/*
+- * Copyright 2014 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import io.netty.buffer.ByteBufAllocator;
+-import io.netty.util.internal.PlatformDependent;
+-import io.netty.util.internal.SystemPropertyUtil;
+-import io.netty.util.internal.logging.InternalLogger;
+-import io.netty.util.internal.logging.InternalLoggerFactory;
+-import org.apache.tomcat.jni.CertificateVerifier;
+-import org.apache.tomcat.jni.Pool;
+-import org.apache.tomcat.jni.SSL;
+-import org.apache.tomcat.jni.SSLContext;
+-
+-import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.SSLException;
+-import javax.net.ssl.SSLHandshakeException;
+-import javax.net.ssl.TrustManager;
+-import javax.net.ssl.X509ExtendedTrustManager;
+-import javax.net.ssl.X509TrustManager;
+-import java.security.cert.X509Certificate;
+-import java.util.ArrayList;
+-import java.util.Arrays;
+-import java.util.Collections;
+-import java.util.List;
+-import java.util.Map;
+-import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
+-
+-import static io.netty.util.internal.ObjectUtil.checkNotNull;
+-import static io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
+-import static io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
+-
+-public abstract class OpenSslContext extends SslContext {
+-
+- private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSslContext.class);
+- /**
+- * To make it easier for users to replace JDK implemention with OpenSsl version we also use
+- * {@code jdk.tls.rejectClientInitiatedRenegotiation} to allow disabling client initiated renegotiation.
+- * Java8+ uses this system property as well.
+- *
+- * See also
+- * Significant SSL/TLS improvements in Java 8
+- */
+- private static final boolean JDK_REJECT_CLIENT_INITIATED_RENEGOTIATION =
+- SystemPropertyUtil.getBoolean("jdk.tls.rejectClientInitiatedRenegotiation", false);
+- private static final List DEFAULT_CIPHERS;
+- private static final AtomicIntegerFieldUpdater DESTROY_UPDATER;
+-
+- // TODO: Maybe make configurable ?
+- protected static final int VERIFY_DEPTH = 10;
+-
+- private final long aprPool;
+- @SuppressWarnings({ "unused", "FieldMayBeFinal" })
+- private volatile int aprPoolDestroyed;
+- private volatile boolean rejectRemoteInitiatedRenegotiation;
+- private final List unmodifiableCiphers;
+- private final long sessionCacheSize;
+- private final long sessionTimeout;
+- private final OpenSslEngineMap engineMap = new DefaultOpenSslEngineMap();
+-
+- private final OpenSslApplicationProtocolNegotiator apn;
+- /** The OpenSSL SSL_CTX object */
+- protected final long ctx;
+- private final int mode;
+-
+- static final OpenSslApplicationProtocolNegotiator NONE_PROTOCOL_NEGOTIATOR =
+- new OpenSslApplicationProtocolNegotiator() {
+- @Override
+- public ApplicationProtocolConfig.Protocol protocol() {
+- return ApplicationProtocolConfig.Protocol.NONE;
+- }
+-
+- @Override
+- public List protocols() {
+- return Collections.emptyList();
+- }
+-
+- @Override
+- public SelectorFailureBehavior selectorFailureBehavior() {
+- return SelectorFailureBehavior.CHOOSE_MY_LAST_PROTOCOL;
+- }
+-
+- @Override
+- public SelectedListenerFailureBehavior selectedListenerFailureBehavior() {
+- return SelectedListenerFailureBehavior.ACCEPT;
+- }
+- };
+-
+- static {
+- List ciphers = new ArrayList();
+- // XXX: Make sure to sync this list with JdkSslEngineFactory.
+- Collections.addAll(
+- ciphers,
+- "ECDHE-RSA-AES128-GCM-SHA256",
+- "ECDHE-RSA-AES128-SHA",
+- "ECDHE-RSA-AES256-SHA",
+- "AES128-GCM-SHA256",
+- "AES128-SHA",
+- "AES256-SHA",
+- "DES-CBC3-SHA",
+- "RC4-SHA");
+- DEFAULT_CIPHERS = Collections.unmodifiableList(ciphers);
+-
+- if (logger.isDebugEnabled()) {
+- logger.debug("Default cipher suite (OpenSSL): " + ciphers);
+- }
+-
+- AtomicIntegerFieldUpdater updater =
+- PlatformDependent.newAtomicIntegerFieldUpdater(OpenSslContext.class, "aprPoolDestroyed");
+- if (updater == null) {
+- updater = AtomicIntegerFieldUpdater.newUpdater(OpenSslContext.class, "aprPoolDestroyed");
+- }
+- DESTROY_UPDATER = updater;
+- }
+-
+- OpenSslContext(Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apnCfg,
+- long sessionCacheSize, long sessionTimeout, int mode) throws SSLException {
+- this(ciphers, cipherFilter, toNegotiator(apnCfg), sessionCacheSize, sessionTimeout, mode);
+- }
+-
+- OpenSslContext(Iterable ciphers, CipherSuiteFilter cipherFilter,
+- OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize,
+- long sessionTimeout, int mode) throws SSLException {
+- OpenSsl.ensureAvailability();
+-
+- if (mode != SSL.SSL_MODE_SERVER && mode != SSL.SSL_MODE_CLIENT) {
+- throw new IllegalArgumentException("mode most be either SSL.SSL_MODE_SERVER or SSL.SSL_MODE_CLIENT");
+- }
+- this.mode = mode;
+-
+- if (mode == SSL.SSL_MODE_SERVER) {
+- rejectRemoteInitiatedRenegotiation =
+- JDK_REJECT_CLIENT_INITIATED_RENEGOTIATION;
+- }
+- final List convertedCiphers;
+- if (ciphers == null) {
+- convertedCiphers = null;
+- } else {
+- convertedCiphers = new ArrayList();
+- for (String c: ciphers) {
+- if (c == null) {
+- break;
+- }
+-
+- String converted = CipherSuiteConverter.toOpenSsl(c);
+- if (converted != null) {
+- c = converted;
+- }
+- convertedCiphers.add(c);
+- }
+- }
+-
+- unmodifiableCiphers = Arrays.asList(checkNotNull(cipherFilter, "cipherFilter").filterCipherSuites(
+- convertedCiphers, DEFAULT_CIPHERS, OpenSsl.availableCipherSuites()));
+-
+- this.apn = checkNotNull(apn, "apn");
+-
+- // Allocate a new APR pool.
+- aprPool = Pool.create(0);
+-
+- // Create a new SSL_CTX and configure it.
+- boolean success = false;
+- try {
+- synchronized (OpenSslContext.class) {
+- try {
+- ctx = SSLContext.make(aprPool, SSL.SSL_PROTOCOL_ALL, mode);
+- } catch (Exception e) {
+- throw new SSLException("failed to create an SSL_CTX", e);
+- }
+-
+- SSLContext.setOptions(ctx, SSL.SSL_OP_ALL);
+- SSLContext.setOptions(ctx, SSL.SSL_OP_NO_SSLv2);
+- SSLContext.setOptions(ctx, SSL.SSL_OP_NO_SSLv3);
+- SSLContext.setOptions(ctx, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE);
+- SSLContext.setOptions(ctx, SSL.SSL_OP_SINGLE_ECDH_USE);
+- SSLContext.setOptions(ctx, SSL.SSL_OP_SINGLE_DH_USE);
+- SSLContext.setOptions(ctx, SSL.SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
+-
+- /* List the ciphers that are permitted to negotiate. */
+- try {
+- SSLContext.setCipherSuite(ctx, CipherSuiteConverter.toOpenSsl(unmodifiableCiphers));
+- } catch (SSLException e) {
+- throw e;
+- } catch (Exception e) {
+- throw new SSLException("failed to set cipher suite: " + unmodifiableCiphers, e);
+- }
+-
+- List nextProtoList = apn.protocols();
+- /* Set next protocols for next protocol negotiation extension, if specified */
+- if (!nextProtoList.isEmpty()) {
+- String[] protocols = nextProtoList.toArray(new String[nextProtoList.size()]);
+- int selectorBehavior = opensslSelectorFailureBehavior(apn.selectorFailureBehavior());
+-
+- switch (apn.protocol()) {
+- case NPN:
+- SSLContext.setNpnProtos(ctx, protocols, selectorBehavior);
+- break;
+- case ALPN:
+- SSLContext.setAlpnProtos(ctx, protocols, selectorBehavior);
+- break;
+- case NPN_AND_ALPN:
+- SSLContext.setNpnProtos(ctx, protocols, selectorBehavior);
+- SSLContext.setAlpnProtos(ctx, protocols, selectorBehavior);
+- break;
+- default:
+- throw new Error();
+- }
+- }
+-
+- /* Set session cache size, if specified */
+- if (sessionCacheSize > 0) {
+- this.sessionCacheSize = sessionCacheSize;
+- SSLContext.setSessionCacheSize(ctx, sessionCacheSize);
+- } else {
+- // Get the default session cache size using SSLContext.setSessionCacheSize()
+- this.sessionCacheSize = sessionCacheSize = SSLContext.setSessionCacheSize(ctx, 20480);
+- // Revert the session cache size to the default value.
+- SSLContext.setSessionCacheSize(ctx, sessionCacheSize);
+- }
+-
+- /* Set session timeout, if specified */
+- if (sessionTimeout > 0) {
+- this.sessionTimeout = sessionTimeout;
+- SSLContext.setSessionCacheTimeout(ctx, sessionTimeout);
+- } else {
+- // Get the default session timeout using SSLContext.setSessionCacheTimeout()
+- this.sessionTimeout = sessionTimeout = SSLContext.setSessionCacheTimeout(ctx, 300);
+- // Revert the session timeout to the default value.
+- SSLContext.setSessionCacheTimeout(ctx, sessionTimeout);
+- }
+- }
+- success = true;
+- } finally {
+- if (!success) {
+- destroyPools();
+- }
+- }
+- }
+-
+- private static int opensslSelectorFailureBehavior(SelectorFailureBehavior behavior) {
+- switch (behavior) {
+- case NO_ADVERTISE:
+- return SSL.SSL_SELECTOR_FAILURE_NO_ADVERTISE;
+- case CHOOSE_MY_LAST_PROTOCOL:
+- return SSL.SSL_SELECTOR_FAILURE_CHOOSE_MY_LAST_PROTOCOL;
+- default:
+- throw new Error();
+- }
+- }
+-
+- @Override
+- public final List cipherSuites() {
+- return unmodifiableCiphers;
+- }
+-
+- @Override
+- public final long sessionCacheSize() {
+- return sessionCacheSize;
+- }
+-
+- @Override
+- public final long sessionTimeout() {
+- return sessionTimeout;
+- }
+-
+- @Override
+- public ApplicationProtocolNegotiator applicationProtocolNegotiator() {
+- return apn;
+- }
+-
+- @Override
+- public final boolean isClient() {
+- return mode == SSL.SSL_MODE_CLIENT;
+- }
+-
+- @Override
+- public final SSLEngine newEngine(ByteBufAllocator alloc, String peerHost, int peerPort) {
+- throw new UnsupportedOperationException();
+- }
+-
+- /**
+- * Returns a new server-side {@link javax.net.ssl.SSLEngine} with the current configuration.
+- */
+- @Override
+- public final SSLEngine newEngine(ByteBufAllocator alloc) {
+- final OpenSslEngine engine = new OpenSslEngine(
+- ctx, alloc, isClient(), sessionContext(), apn, engineMap, rejectRemoteInitiatedRenegotiation);
+- engineMap.add(engine);
+- return engine;
+- }
+-
+- /**
+- * Returns the {@code SSL_CTX} object of this context.
+- */
+- public final long context() {
+- return ctx;
+- }
+-
+- /**
+- * Returns the stats of this context.
+- * @deprecated use {@link #sessionContext#stats()}
+- */
+- @Deprecated
+- public final OpenSslSessionStats stats() {
+- return sessionContext().stats();
+- }
+-
+- /**
+- * Specify if remote initiated renegotiation is supported or not. If not supported and the remote side tries
+- * to initiate a renegotiation a {@link SSLHandshakeException} will be thrown during decoding.
+- */
+- public void setRejectRemoteInitiatedRenegotiation(boolean rejectRemoteInitiatedRenegotiation) {
+- this.rejectRemoteInitiatedRenegotiation = rejectRemoteInitiatedRenegotiation;
+- }
+-
+- @Override
+- @SuppressWarnings("FinalizeDeclaration")
+- protected final void finalize() throws Throwable {
+- super.finalize();
+- synchronized (OpenSslContext.class) {
+- if (ctx != 0) {
+- SSLContext.free(ctx);
+- }
+- }
+-
+- destroyPools();
+- }
+-
+- /**
+- * Sets the SSL session ticket keys of this context.
+- * @deprecated use {@link OpenSslSessionContext#setTicketKeys(byte[])}
+- */
+- @Deprecated
+- public final void setTicketKeys(byte[] keys) {
+- sessionContext().setTicketKeys(keys);
+- }
+-
+- @Override
+- public abstract OpenSslSessionContext sessionContext();
+-
+- protected final void destroyPools() {
+- // Guard against multiple destroyPools() calls triggered by construction exception and finalize() later
+- if (aprPool != 0 && DESTROY_UPDATER.compareAndSet(this, 0, 1)) {
+- Pool.destroy(aprPool);
+- }
+- }
+-
+- protected static X509Certificate[] certificates(byte[][] chain) {
+- X509Certificate[] peerCerts = new X509Certificate[chain.length];
+- for (int i = 0; i < peerCerts.length; i++) {
+- peerCerts[i] = new OpenSslX509Certificate(chain[i]);
+- }
+- return peerCerts;
+- }
+-
+- protected static X509TrustManager chooseTrustManager(TrustManager[] managers) {
+- for (TrustManager m : managers) {
+- if (m instanceof X509TrustManager) {
+- return (X509TrustManager) m;
+- }
+- }
+- throw new IllegalStateException("no X509TrustManager found");
+- }
+-
+- /**
+- * Translate a {@link ApplicationProtocolConfig} object to a
+- * {@link OpenSslApplicationProtocolNegotiator} object.
+- * @param config The configuration which defines the translation
+- * @return The results of the translation
+- */
+- static OpenSslApplicationProtocolNegotiator toNegotiator(ApplicationProtocolConfig config) {
+- if (config == null) {
+- return NONE_PROTOCOL_NEGOTIATOR;
+- }
+-
+- switch (config.protocol()) {
+- case NONE:
+- return NONE_PROTOCOL_NEGOTIATOR;
+- case ALPN:
+- case NPN:
+- case NPN_AND_ALPN:
+- switch (config.selectedListenerFailureBehavior()) {
+- case CHOOSE_MY_LAST_PROTOCOL:
+- case ACCEPT:
+- switch (config.selectorFailureBehavior()) {
+- case CHOOSE_MY_LAST_PROTOCOL:
+- case NO_ADVERTISE:
+- return new OpenSslDefaultApplicationProtocolNegotiator(
+- config);
+- default:
+- throw new UnsupportedOperationException(
+- new StringBuilder("OpenSSL provider does not support ")
+- .append(config.selectorFailureBehavior())
+- .append(" behavior").toString());
+- }
+- default:
+- throw new UnsupportedOperationException(
+- new StringBuilder("OpenSSL provider does not support ")
+- .append(config.selectedListenerFailureBehavior())
+- .append(" behavior").toString());
+- }
+- default:
+- throw new Error();
+- }
+- }
+-
+- static boolean useExtendedTrustManager(X509TrustManager trustManager) {
+- return PlatformDependent.javaVersion() >= 7 && trustManager instanceof X509ExtendedTrustManager;
+- }
+-
+- abstract class AbstractCertificateVerifier implements CertificateVerifier {
+- @Override
+- public final boolean verify(long ssl, byte[][] chain, String auth) {
+- X509Certificate[] peerCerts = certificates(chain);
+- final OpenSslEngine engine = engineMap.remove(ssl);
+- try {
+- verify(engine, peerCerts, auth);
+- return true;
+- } catch (Throwable cause) {
+- logger.debug("verification of certificate failed", cause);
+- SSLHandshakeException e = new SSLHandshakeException("General OpenSslEngine problem");
+- e.initCause(cause);
+- engine.handshakeException = e;
+- }
+- return false;
+- }
+-
+- abstract void verify(OpenSslEngine engine, X509Certificate[] peerCerts, String auth) throws Exception;
+- }
+-
+- private static final class DefaultOpenSslEngineMap implements OpenSslEngineMap {
+- private final Map engines = PlatformDependent.newConcurrentHashMap();
+- @Override
+- public OpenSslEngine remove(long ssl) {
+- return engines.remove(ssl);
+- }
+-
+- @Override
+- public void add(OpenSslEngine engine) {
+- engines.put(engine.ssl(), engine);
+- }
+- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java
+deleted file mode 100644
+index b5c8e6c..0000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java
++++ /dev/null
+@@ -1,1525 +0,0 @@
+-/*
+- * Copyright 2014 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import io.netty.buffer.ByteBuf;
+-import io.netty.buffer.ByteBufAllocator;
+-import io.netty.buffer.Unpooled;
+-import io.netty.util.internal.EmptyArrays;
+-import io.netty.util.internal.PlatformDependent;
+-import io.netty.util.internal.StringUtil;
+-import io.netty.util.internal.logging.InternalLogger;
+-import io.netty.util.internal.logging.InternalLoggerFactory;
+-import org.apache.tomcat.jni.Buffer;
+-import org.apache.tomcat.jni.SSL;
+-
+-import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.SSLEngineResult;
+-import javax.net.ssl.SSLException;
+-import javax.net.ssl.SSLHandshakeException;
+-import javax.net.ssl.SSLPeerUnverifiedException;
+-import javax.net.ssl.SSLSession;
+-import javax.net.ssl.SSLSessionBindingEvent;
+-import javax.net.ssl.SSLSessionBindingListener;
+-import javax.net.ssl.SSLSessionContext;
+-import javax.security.cert.CertificateException;
+-import javax.security.cert.X509Certificate;
+-import java.nio.ByteBuffer;
+-import java.nio.ReadOnlyBufferException;
+-import java.security.Principal;
+-import java.security.cert.Certificate;
+-import java.util.ArrayList;
+-import java.util.Arrays;
+-import java.util.HashMap;
+-import java.util.HashSet;
+-import java.util.List;
+-import java.util.Map;
+-import java.util.Set;
+-import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
+-
+-import static io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
+-import static io.netty.util.internal.ObjectUtil.checkNotNull;
+-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.*;
+-import static javax.net.ssl.SSLEngineResult.Status.*;
+-
+-/**
+- * Implements a {@link SSLEngine} using
+- * OpenSSL BIO abstractions.
+- */
+-public final class OpenSslEngine extends SSLEngine {
+-
+- private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSslEngine.class);
+-
+- private static final Certificate[] EMPTY_CERTIFICATES = EmptyArrays.EMPTY_CERTIFICATES;
+- private static final X509Certificate[] EMPTY_X509_CERTIFICATES = EmptyArrays.EMPTY_JAVAX_X509_CERTIFICATES;
+-
+- private static final SSLException ENGINE_CLOSED = new SSLException("engine closed");
+- private static final SSLException RENEGOTIATION_UNSUPPORTED = new SSLException("renegotiation unsupported");
+- private static final SSLException ENCRYPTED_PACKET_OVERSIZED = new SSLException("encrypted packet oversized");
+- static {
+- ENGINE_CLOSED.setStackTrace(EmptyArrays.EMPTY_STACK_TRACE);
+- RENEGOTIATION_UNSUPPORTED.setStackTrace(EmptyArrays.EMPTY_STACK_TRACE);
+- ENCRYPTED_PACKET_OVERSIZED.setStackTrace(EmptyArrays.EMPTY_STACK_TRACE);
+-
+- AtomicIntegerFieldUpdater destroyedUpdater =
+- PlatformDependent.newAtomicIntegerFieldUpdater(OpenSslEngine.class, "destroyed");
+- if (destroyedUpdater == null) {
+- destroyedUpdater = AtomicIntegerFieldUpdater.newUpdater(OpenSslEngine.class, "destroyed");
+- }
+- DESTROYED_UPDATER = destroyedUpdater;
+- }
+-
+- private static final int MAX_PLAINTEXT_LENGTH = 16 * 1024; // 2^14
+- private static final int MAX_COMPRESSED_LENGTH = MAX_PLAINTEXT_LENGTH + 1024;
+- private static final int MAX_CIPHERTEXT_LENGTH = MAX_COMPRESSED_LENGTH + 1024;
+-
+- // Protocols
+- private static final String PROTOCOL_SSL_V2_HELLO = "SSLv2Hello";
+- private static final String PROTOCOL_SSL_V2 = "SSLv2";
+- private static final String PROTOCOL_SSL_V3 = "SSLv3";
+- private static final String PROTOCOL_TLS_V1 = "TLSv1";
+- private static final String PROTOCOL_TLS_V1_1 = "TLSv1.1";
+- private static final String PROTOCOL_TLS_V1_2 = "TLSv1.2";
+-
+- private static final String[] SUPPORTED_PROTOCOLS = {
+- PROTOCOL_SSL_V2_HELLO,
+- PROTOCOL_SSL_V2,
+- PROTOCOL_SSL_V3,
+- PROTOCOL_TLS_V1,
+- PROTOCOL_TLS_V1_1,
+- PROTOCOL_TLS_V1_2
+- };
+- private static final Set SUPPORTED_PROTOCOLS_SET = new HashSet(Arrays.asList(SUPPORTED_PROTOCOLS));
+-
+- // Header (5) + Data (2^14) + Compression (1024) + Encryption (1024) + MAC (20) + Padding (256)
+- static final int MAX_ENCRYPTED_PACKET_LENGTH = MAX_CIPHERTEXT_LENGTH + 5 + 20 + 256;
+-
+- static final int MAX_ENCRYPTION_OVERHEAD_LENGTH = MAX_ENCRYPTED_PACKET_LENGTH - MAX_PLAINTEXT_LENGTH;
+-
+- enum ClientAuthMode {
+- NONE,
+- OPTIONAL,
+- REQUIRE,
+- }
+-
+- private static final AtomicIntegerFieldUpdater DESTROYED_UPDATER;
+-
+- private static final String INVALID_CIPHER = "SSL_NULL_WITH_NULL_NULL";
+-
+- private static final long EMPTY_ADDR = Buffer.address(Unpooled.EMPTY_BUFFER.nioBuffer());
+-
+- private static final SSLEngineResult NEED_UNWRAP_OK = new SSLEngineResult(OK, NEED_UNWRAP, 0, 0);
+- private static final SSLEngineResult NEED_UNWRAP_CLOSED = new SSLEngineResult(CLOSED, NEED_UNWRAP, 0, 0);
+- private static final SSLEngineResult NEED_WRAP_OK = new SSLEngineResult(OK, NEED_WRAP, 0, 0);
+- private static final SSLEngineResult NEED_WRAP_CLOSED = new SSLEngineResult(CLOSED, NEED_WRAP, 0, 0);
+- private static final SSLEngineResult CLOSED_NOT_HANDSHAKING = new SSLEngineResult(CLOSED, NOT_HANDSHAKING, 0, 0);
+-
+- // OpenSSL state
+- private long ssl;
+- private long networkBIO;
+-
+- /**
+- * 0 - not accepted, 1 - accepted implicitly via wrap()/unwrap(), 2 - accepted explicitly via beginHandshake() call
+- */
+- private int accepted;
+- private boolean handshakeFinished;
+- private boolean receivedShutdown;
+- @SuppressWarnings("UnusedDeclaration")
+- private volatile int destroyed;
+-
+- // Use an invalid cipherSuite until the handshake is completed
+- // See http://docs.oracle.com/javase/7/docs/api/javax/net/ssl/SSLEngine.html#getSession()
+- private volatile String cipher;
+- private volatile String applicationProtocol;
+-
+- // We store this outside of the SslSession so we not need to create an instance during verifyCertificates(...)
+- private volatile Certificate[] peerCerts;
+- private volatile ClientAuthMode clientAuth = ClientAuthMode.NONE;
+-
+- // SSL Engine status variables
+- private boolean isInboundDone;
+- private boolean isOutboundDone;
+- private boolean engineClosed;
+-
+- private final boolean clientMode;
+- private final ByteBufAllocator alloc;
+- private final OpenSslSessionContext sessionContext;
+- private final OpenSslEngineMap engineMap;
+- private final OpenSslApplicationProtocolNegotiator apn;
+- private final boolean rejectRemoteInitiatedRenegation;
+- private final SSLSession session = new OpenSslSession();
+-
+- // This is package-private as we set it from OpenSslContext if an exception is thrown during
+- // the verification step.
+- SSLHandshakeException handshakeException;
+-
+- /**
+- * Creates a new instance
+- *
+- * @param sslCtx an OpenSSL {@code SSL_CTX} object
+- * @param alloc the {@link ByteBufAllocator} that will be used by this engine
+- */
+- @Deprecated
+- public OpenSslEngine(long sslCtx, ByteBufAllocator alloc,
+- @SuppressWarnings("unused") String fallbackApplicationProtocol) {
+- this(sslCtx, alloc, false, null, OpenSslContext.NONE_PROTOCOL_NEGOTIATOR, OpenSslEngineMap.EMPTY, false);
+- }
+-
+- /**
+- * Creates a new instance
+- *
+- * @param sslCtx an OpenSSL {@code SSL_CTX} object
+- * @param alloc the {@link ByteBufAllocator} that will be used by this engine
+- * @param clientMode {@code true} if this is used for clients, {@code false} otherwise
+- * @param sessionContext the {@link OpenSslSessionContext} this {@link SSLEngine} belongs to.
+- */
+- OpenSslEngine(long sslCtx, ByteBufAllocator alloc,
+- boolean clientMode, OpenSslSessionContext sessionContext,
+- OpenSslApplicationProtocolNegotiator apn, OpenSslEngineMap engineMap,
+- boolean rejectRemoteInitiatedRenegation) {
+- OpenSsl.ensureAvailability();
+- if (sslCtx == 0) {
+- throw new NullPointerException("sslCtx");
+- }
+-
+- this.alloc = checkNotNull(alloc, "alloc");
+- this.apn = checkNotNull(apn, "apn");
+- ssl = SSL.newSSL(sslCtx, !clientMode);
+- networkBIO = SSL.makeNetworkBIO(ssl);
+- this.clientMode = clientMode;
+- this.sessionContext = sessionContext;
+- this.engineMap = engineMap;
+- this.rejectRemoteInitiatedRenegation = rejectRemoteInitiatedRenegation;
+- }
+-
+- @Override
+- public SSLSession getHandshakeSession() {
+- if (accepted > 0) {
+- // handshake started we are able to return the session.
+- return session;
+- }
+- // As stated by the javadocs of getHandshakeSession() we should return null if the handshake not started yet.
+- return null;
+- }
+-
+- long ssl() {
+- return ssl;
+- }
+-
+- /**
+- * Destroys this engine.
+- */
+- public synchronized void shutdown() {
+- if (DESTROYED_UPDATER.compareAndSet(this, 0, 1)) {
+- engineMap.remove(ssl);
+- SSL.freeSSL(ssl);
+- SSL.freeBIO(networkBIO);
+- ssl = networkBIO = 0;
+-
+- // internal errors can cause shutdown without marking the engine closed
+- isInboundDone = isOutboundDone = engineClosed = true;
+- }
+- }
+-
+- /**
+- * Write plaintext data to the OpenSSL internal BIO
+- *
+- * Calling this function with src.remaining == 0 is undefined.
+- */
+- private int writePlaintextData(final ByteBuffer src) {
+- final int pos = src.position();
+- final int limit = src.limit();
+- final int len = Math.min(limit - pos, MAX_PLAINTEXT_LENGTH);
+- final int sslWrote;
+-
+- if (src.isDirect()) {
+- final long addr = Buffer.address(src) + pos;
+- sslWrote = SSL.writeToSSL(ssl, addr, len);
+- if (sslWrote > 0) {
+- src.position(pos + sslWrote);
+- return sslWrote;
+- }
+- } else {
+- ByteBuf buf = alloc.directBuffer(len);
+- try {
+- final long addr = memoryAddress(buf);
+-
+- src.limit(pos + len);
+-
+- buf.setBytes(0, src);
+- src.limit(limit);
+-
+- sslWrote = SSL.writeToSSL(ssl, addr, len);
+- if (sslWrote > 0) {
+- src.position(pos + sslWrote);
+- return sslWrote;
+- } else {
+- src.position(pos);
+- }
+- } finally {
+- buf.release();
+- }
+- }
+-
+- throw new IllegalStateException("SSL.writeToSSL() returned a non-positive value: " + sslWrote);
+- }
+-
+- /**
+- * Write encrypted data to the OpenSSL network BIO.
+- */
+- private int writeEncryptedData(final ByteBuffer src) {
+- final int pos = src.position();
+- final int len = src.remaining();
+- if (src.isDirect()) {
+- final long addr = Buffer.address(src) + pos;
+- final int netWrote = SSL.writeToBIO(networkBIO, addr, len);
+- if (netWrote >= 0) {
+- src.position(pos + netWrote);
+- return netWrote;
+- }
+- } else {
+- final ByteBuf buf = alloc.directBuffer(len);
+- try {
+- final long addr = memoryAddress(buf);
+-
+- buf.setBytes(0, src);
+-
+- final int netWrote = SSL.writeToBIO(networkBIO, addr, len);
+- if (netWrote >= 0) {
+- src.position(pos + netWrote);
+- return netWrote;
+- } else {
+- src.position(pos);
+- }
+- } finally {
+- buf.release();
+- }
+- }
+-
+- return -1;
+- }
+-
+- /**
+- * Read plaintext data from the OpenSSL internal BIO
+- */
+- private int readPlaintextData(final ByteBuffer dst) {
+- if (dst.isDirect()) {
+- final int pos = dst.position();
+- final long addr = Buffer.address(dst) + pos;
+- final int len = dst.limit() - pos;
+- final int sslRead = SSL.readFromSSL(ssl, addr, len);
+- if (sslRead > 0) {
+- dst.position(pos + sslRead);
+- return sslRead;
+- }
+- } else {
+- final int pos = dst.position();
+- final int limit = dst.limit();
+- final int len = Math.min(MAX_ENCRYPTED_PACKET_LENGTH, limit - pos);
+- final ByteBuf buf = alloc.directBuffer(len);
+- try {
+- final long addr = memoryAddress(buf);
+-
+- final int sslRead = SSL.readFromSSL(ssl, addr, len);
+- if (sslRead > 0) {
+- dst.limit(pos + sslRead);
+- buf.getBytes(0, dst);
+- dst.limit(limit);
+- return sslRead;
+- }
+- } finally {
+- buf.release();
+- }
+- }
+-
+- return 0;
+- }
+-
+- /**
+- * Read encrypted data from the OpenSSL network BIO
+- */
+- private int readEncryptedData(final ByteBuffer dst, final int pending) {
+- if (dst.isDirect() && dst.remaining() >= pending) {
+- final int pos = dst.position();
+- final long addr = Buffer.address(dst) + pos;
+- final int bioRead = SSL.readFromBIO(networkBIO, addr, pending);
+- if (bioRead > 0) {
+- dst.position(pos + bioRead);
+- return bioRead;
+- }
+- } else {
+- final ByteBuf buf = alloc.directBuffer(pending);
+- try {
+- final long addr = memoryAddress(buf);
+-
+- final int bioRead = SSL.readFromBIO(networkBIO, addr, pending);
+- if (bioRead > 0) {
+- int oldLimit = dst.limit();
+- dst.limit(dst.position() + bioRead);
+- buf.getBytes(0, dst);
+- dst.limit(oldLimit);
+- return bioRead;
+- }
+- } finally {
+- buf.release();
+- }
+- }
+-
+- return 0;
+- }
+-
+- @Override
+- public synchronized SSLEngineResult wrap(
+- final ByteBuffer[] srcs, final int offset, final int length, final ByteBuffer dst) throws SSLException {
+-
+- // Check to make sure the engine has not been closed
+- if (destroyed != 0) {
+- return CLOSED_NOT_HANDSHAKING;
+- }
+-
+- // Throw required runtime exceptions
+- if (srcs == null) {
+- throw new IllegalArgumentException("srcs is null");
+- }
+- if (dst == null) {
+- throw new IllegalArgumentException("dst is null");
+- }
+-
+- if (offset >= srcs.length || offset + length > srcs.length) {
+- throw new IndexOutOfBoundsException(
+- "offset: " + offset + ", length: " + length +
+- " (expected: offset <= offset + length <= srcs.length (" + srcs.length + "))");
+- }
+-
+- if (dst.isReadOnly()) {
+- throw new ReadOnlyBufferException();
+- }
+-
+- // Prepare OpenSSL to work in server mode and receive handshake
+- if (accepted == 0) {
+- beginHandshakeImplicitly();
+- }
+-
+- // In handshake or close_notify stages, check if call to wrap was made
+- // without regard to the handshake status.
+- SSLEngineResult.HandshakeStatus handshakeStatus = handshakeStatus0();
+-
+- if (handshakeStatus == NEED_UNWRAP) {
+- if (!handshakeFinished) {
+- return NEED_UNWRAP_OK;
+- }
+- if (engineClosed) {
+- return NEED_UNWRAP_CLOSED;
+- }
+- }
+-
+- int bytesProduced = 0;
+- int pendingNet;
+-
+- // Check for pending data in the network BIO
+- pendingNet = SSL.pendingWrittenBytesInBIO(networkBIO);
+- if (pendingNet > 0) {
+- // Do we have enough room in dst to write encrypted data?
+- int capacity = dst.remaining();
+- if (capacity < pendingNet) {
+- return new SSLEngineResult(BUFFER_OVERFLOW, handshakeStatus, 0, bytesProduced);
+- }
+-
+- // Write the pending data from the network BIO into the dst buffer
+- try {
+- bytesProduced += readEncryptedData(dst, pendingNet);
+- } catch (Exception e) {
+- throw new SSLException(e);
+- }
+-
+- // If isOuboundDone is set, then the data from the network BIO
+- // was the close_notify message -- we are not required to wait
+- // for the receipt the peer's close_notify message -- shutdown.
+- if (isOutboundDone) {
+- shutdown();
+- }
+-
+- return new SSLEngineResult(getEngineStatus(), handshakeStatus0(), 0, bytesProduced);
+- }
+-
+- // There was no pending data in the network BIO -- encrypt any application data
+- int bytesConsumed = 0;
+- int endOffset = offset + length;
+- for (int i = offset; i < endOffset; ++ i) {
+- final ByteBuffer src = srcs[i];
+- if (src == null) {
+- throw new IllegalArgumentException("srcs[" + i + "] is null");
+- }
+- while (src.hasRemaining()) {
+-
+- // Write plaintext application data to the SSL engine
+- try {
+- bytesConsumed += writePlaintextData(src);
+- } catch (Exception e) {
+- throw new SSLException(e);
+- }
+-
+- // Check to see if the engine wrote data into the network BIO
+- pendingNet = SSL.pendingWrittenBytesInBIO(networkBIO);
+- if (pendingNet > 0) {
+- // Do we have enough room in dst to write encrypted data?
+- int capacity = dst.remaining();
+- if (capacity < pendingNet) {
+- return new SSLEngineResult(
+- BUFFER_OVERFLOW, handshakeStatus0(), bytesConsumed, bytesProduced);
+- }
+-
+- // Write the pending data from the network BIO into the dst buffer
+- try {
+- bytesProduced += readEncryptedData(dst, pendingNet);
+- } catch (Exception e) {
+- throw new SSLException(e);
+- }
+-
+- return new SSLEngineResult(getEngineStatus(), handshakeStatus0(), bytesConsumed, bytesProduced);
+- }
+- }
+- }
+-
+- return new SSLEngineResult(getEngineStatus(), handshakeStatus0(), bytesConsumed, bytesProduced);
+- }
+-
+- private SSLException newSSLException(String msg) {
+- if (!handshakeFinished) {
+- return new SSLHandshakeException(msg);
+- }
+- return new SSLException(msg);
+- }
+-
+- private void checkPendingHandshakeException() throws SSLHandshakeException {
+- if (handshakeException != null) {
+- SSLHandshakeException exception = handshakeException;
+- handshakeException = null;
+- shutdown();
+- throw exception;
+- }
+- }
+-
+- public synchronized SSLEngineResult unwrap(
+- final ByteBuffer[] srcs, int srcsOffset, final int srcsLength,
+- final ByteBuffer[] dsts, final int dstsOffset, final int dstsLength) throws SSLException {
+-
+- // Check to make sure the engine has not been closed
+- if (destroyed != 0) {
+- return CLOSED_NOT_HANDSHAKING;
+- }
+-
+- // Throw requried runtime exceptions
+- if (srcs == null) {
+- throw new NullPointerException("srcs");
+- }
+- if (srcsOffset >= srcs.length
+- || srcsOffset + srcsLength > srcs.length) {
+- throw new IndexOutOfBoundsException(
+- "offset: " + srcsOffset + ", length: " + srcsLength +
+- " (expected: offset <= offset + length <= srcs.length (" + srcs.length + "))");
+- }
+- if (dsts == null) {
+- throw new IllegalArgumentException("dsts is null");
+- }
+- if (dstsOffset >= dsts.length || dstsOffset + dstsLength > dsts.length) {
+- throw new IndexOutOfBoundsException(
+- "offset: " + dstsOffset + ", length: " + dstsLength +
+- " (expected: offset <= offset + length <= dsts.length (" + dsts.length + "))");
+- }
+- int capacity = 0;
+- final int endOffset = dstsOffset + dstsLength;
+- for (int i = dstsOffset; i < endOffset; i ++) {
+- ByteBuffer dst = dsts[i];
+- if (dst == null) {
+- throw new IllegalArgumentException("dsts[" + i + "] is null");
+- }
+- if (dst.isReadOnly()) {
+- throw new ReadOnlyBufferException();
+- }
+- capacity += dst.remaining();
+- }
+-
+- // Prepare OpenSSL to work in server mode and receive handshake
+- if (accepted == 0) {
+- beginHandshakeImplicitly();
+- }
+-
+- // In handshake or close_notify stages, check if call to unwrap was made
+- // without regard to the handshake status.
+- SSLEngineResult.HandshakeStatus handshakeStatus = handshakeStatus0();
+- if (handshakeStatus == NEED_WRAP) {
+- if (!handshakeFinished) {
+- return NEED_WRAP_OK;
+- }
+- if (engineClosed) {
+- return NEED_WRAP_CLOSED;
+- }
+- }
+-
+- final int srcsEndOffset = srcsOffset + srcsLength;
+- int len = 0;
+- for (int i = srcsOffset; i < srcsEndOffset; i++) {
+- ByteBuffer src = srcs[i];
+- if (src == null) {
+- throw new IllegalArgumentException("srcs[" + i + "] is null");
+- }
+- len += src.remaining();
+- }
+-
+- // protect against protocol overflow attack vector
+- if (len > MAX_ENCRYPTED_PACKET_LENGTH) {
+- isInboundDone = true;
+- isOutboundDone = true;
+- engineClosed = true;
+- shutdown();
+- throw ENCRYPTED_PACKET_OVERSIZED;
+- }
+-
+- // Write encrypted data to network BIO
+- int bytesConsumed = -1;
+- try {
+- while (srcsOffset < srcsEndOffset) {
+- ByteBuffer src = srcs[srcsOffset];
+- int remaining = src.remaining();
+- int written = writeEncryptedData(src);
+- if (written >= 0) {
+- if (bytesConsumed == -1) {
+- bytesConsumed = written;
+- } else {
+- bytesConsumed += written;
+- }
+- if (written == remaining) {
+- srcsOffset ++;
+- } else if (written == 0) {
+- break;
+- }
+- } else {
+- break;
+- }
+- }
+- } catch (Exception e) {
+- throw new SSLException(e);
+- }
+- if (bytesConsumed >= 0) {
+- int lastPrimingReadResult = SSL.readFromSSL(ssl, EMPTY_ADDR, 0); // priming read
+-
+- // check if SSL_read returned <= 0. In this case we need to check the error and see if it was something
+- // fatal.
+- if (lastPrimingReadResult <= 0) {
+- // Check for OpenSSL errors caused by the priming read
+- long error = SSL.getLastErrorNumber();
+- if (OpenSsl.isError(error)) {
+- String err = SSL.getErrorString(error);
+- if (logger.isDebugEnabled()) {
+- logger.debug(
+- "SSL_read failed: primingReadResult: " + lastPrimingReadResult +
+- "; OpenSSL error: '" + err + '\'');
+- }
+-
+- // There was an internal error -- shutdown
+- shutdown();
+- throw newSSLException(err);
+- } else {
+- checkPendingHandshakeException();
+- }
+- }
+-
+- rejectRemoteInitiatedRenegation();
+- } else {
+- // Reset to 0 as -1 is used to signal that nothing was written and no priming read needs to be done
+- bytesConsumed = 0;
+- }
+-
+- // There won't be any application data until we're done handshaking
+- //
+- // We first check handshakeFinished to eliminate the overhead of extra JNI call if possible.
+- int pendingApp = (handshakeFinished || SSL.isInInit(ssl) == 0) ? SSL.pendingReadableBytesInSSL(ssl) : 0;
+- int bytesProduced = 0;
+-
+- if (pendingApp > 0) {
+- // Do we have enough room in dsts to write decrypted data?
+- if (capacity < pendingApp) {
+- return new SSLEngineResult(BUFFER_OVERFLOW, handshakeStatus0(), bytesConsumed, 0);
+- }
+-
+- // Write decrypted data to dsts buffers
+- int idx = dstsOffset;
+- while (idx < endOffset) {
+- ByteBuffer dst = dsts[idx];
+- if (!dst.hasRemaining()) {
+- idx ++;
+- continue;
+- }
+-
+- if (pendingApp <= 0) {
+- break;
+- }
+-
+- int bytesRead;
+- try {
+- bytesRead = readPlaintextData(dst);
+- } catch (Exception e) {
+- throw new SSLException(e);
+- }
+-
+- rejectRemoteInitiatedRenegation();
+-
+- if (bytesRead == 0) {
+- break;
+- }
+- bytesProduced += bytesRead;
+- pendingApp -= bytesRead;
+-
+- if (!dst.hasRemaining()) {
+- idx ++;
+- }
+- }
+- }
+-
+- // Check to see if we received a close_notify message from the peer
+- if (!receivedShutdown && (SSL.getShutdown(ssl) & SSL.SSL_RECEIVED_SHUTDOWN) == SSL.SSL_RECEIVED_SHUTDOWN) {
+- receivedShutdown = true;
+- closeOutbound();
+- closeInbound();
+- }
+-
+- return new SSLEngineResult(getEngineStatus(), handshakeStatus0(), bytesConsumed, bytesProduced);
+- }
+-
+- private void rejectRemoteInitiatedRenegation() throws SSLHandshakeException {
+- if (rejectRemoteInitiatedRenegation && SSL.getHandshakeCount(ssl) > 1) {
+- // TODO: In future versions me may also want to send a fatal_alert to the client and so notify it
+- // that the renegotiation failed.
+- shutdown();
+- throw new SSLHandshakeException("remote-initiated renegotation not allowed");
+- }
+- }
+-
+- public SSLEngineResult unwrap(final ByteBuffer[] srcs, final ByteBuffer[] dsts) throws SSLException {
+- return unwrap(srcs, 0, srcs.length, dsts, 0, dsts.length);
+- }
+-
+- @Override
+- public SSLEngineResult unwrap(
+- final ByteBuffer src, final ByteBuffer[] dsts, final int offset, final int length) throws SSLException {
+- return unwrap(new ByteBuffer[] { src }, 0, 1, dsts, offset, length);
+- }
+-
+- @Override
+- public Runnable getDelegatedTask() {
+- // Currently, we do not delegate SSL computation tasks
+- // TODO: in the future, possibly create tasks to do encrypt / decrypt async
+-
+- return null;
+- }
+-
+- @Override
+- public synchronized void closeInbound() throws SSLException {
+- if (isInboundDone) {
+- return;
+- }
+-
+- isInboundDone = true;
+- engineClosed = true;
+-
+- shutdown();
+-
+- if (accepted != 0 && !receivedShutdown) {
+- throw new SSLException(
+- "Inbound closed before receiving peer's close_notify: possible truncation attack?");
+- }
+- }
+-
+- @Override
+- public synchronized boolean isInboundDone() {
+- return isInboundDone || engineClosed;
+- }
+-
+- @Override
+- public synchronized void closeOutbound() {
+- if (isOutboundDone) {
+- return;
+- }
+-
+- isOutboundDone = true;
+- engineClosed = true;
+-
+- if (accepted != 0 && destroyed == 0) {
+- int mode = SSL.getShutdown(ssl);
+- if ((mode & SSL.SSL_SENT_SHUTDOWN) != SSL.SSL_SENT_SHUTDOWN) {
+- SSL.shutdownSSL(ssl);
+- }
+- } else {
+- // engine closing before initial handshake
+- shutdown();
+- }
+- }
+-
+- @Override
+- public synchronized boolean isOutboundDone() {
+- return isOutboundDone;
+- }
+-
+- @Override
+- public String[] getSupportedCipherSuites() {
+- Set availableCipherSuites = OpenSsl.availableCipherSuites();
+- return availableCipherSuites.toArray(new String[availableCipherSuites.size()]);
+- }
+-
+- @Override
+- public String[] getEnabledCipherSuites() {
+- final String[] enabled;
+- synchronized (this) {
+- if (destroyed == 0) {
+- enabled = SSL.getCiphers(ssl);
+- } else {
+- return EmptyArrays.EMPTY_STRINGS;
+- }
+- }
+- if (enabled == null) {
+- return EmptyArrays.EMPTY_STRINGS;
+- } else {
+- for (int i = 0; i < enabled.length; i++) {
+- String mapped = toJavaCipherSuite(enabled[i]);
+- if (mapped != null) {
+- enabled[i] = mapped;
+- }
+- }
+- return enabled;
+- }
+- }
+-
+- @Override
+- public void setEnabledCipherSuites(String[] cipherSuites) {
+- checkNotNull(cipherSuites, "cipherSuites");
+-
+- final StringBuilder buf = new StringBuilder();
+- for (String c: cipherSuites) {
+- if (c == null) {
+- break;
+- }
+-
+- String converted = CipherSuiteConverter.toOpenSsl(c);
+- if (converted == null) {
+- converted = c;
+- }
+-
+- if (!OpenSsl.isCipherSuiteAvailable(converted)) {
+- throw new IllegalArgumentException("unsupported cipher suite: " + c + '(' + converted + ')');
+- }
+-
+- buf.append(converted);
+- buf.append(':');
+- }
+-
+- if (buf.length() == 0) {
+- throw new IllegalArgumentException("empty cipher suites");
+- }
+- buf.setLength(buf.length() - 1);
+-
+- final String cipherSuiteSpec = buf.toString();
+-
+- synchronized (this) {
+- if (destroyed == 0) {
+- try {
+- SSL.setCipherSuites(ssl, cipherSuiteSpec);
+- } catch (Exception e) {
+- throw new IllegalStateException("failed to enable cipher suites: " + cipherSuiteSpec, e);
+- }
+- } else {
+- throw new IllegalStateException("failed to enable cipher suites: " + cipherSuiteSpec);
+- }
+- }
+- }
+-
+- @Override
+- public String[] getSupportedProtocols() {
+- return SUPPORTED_PROTOCOLS.clone();
+- }
+-
+- @Override
+- public String[] getEnabledProtocols() {
+- List enabled = new ArrayList();
+- // Seems like there is no way to explict disable SSLv2Hello in openssl so it is always enabled
+- enabled.add(PROTOCOL_SSL_V2_HELLO);
+-
+- int opts;
+- synchronized (this) {
+- if (destroyed == 0) {
+- opts = SSL.getOptions(ssl);
+- } else {
+- return enabled.toArray(new String[1]);
+- }
+- }
+- if ((opts & SSL.SSL_OP_NO_TLSv1) == 0) {
+- enabled.add(PROTOCOL_TLS_V1);
+- }
+- if ((opts & SSL.SSL_OP_NO_TLSv1_1) == 0) {
+- enabled.add(PROTOCOL_TLS_V1_1);
+- }
+- if ((opts & SSL.SSL_OP_NO_TLSv1_2) == 0) {
+- enabled.add(PROTOCOL_TLS_V1_2);
+- }
+- if ((opts & SSL.SSL_OP_NO_SSLv2) == 0) {
+- enabled.add(PROTOCOL_SSL_V2);
+- }
+- if ((opts & SSL.SSL_OP_NO_SSLv3) == 0) {
+- enabled.add(PROTOCOL_SSL_V3);
+- }
+- return enabled.toArray(new String[enabled.size()]);
+- }
+-
+- @Override
+- public void setEnabledProtocols(String[] protocols) {
+- if (protocols == null) {
+- // This is correct from the API docs
+- throw new IllegalArgumentException();
+- }
+- boolean sslv2 = false;
+- boolean sslv3 = false;
+- boolean tlsv1 = false;
+- boolean tlsv1_1 = false;
+- boolean tlsv1_2 = false;
+- for (String p: protocols) {
+- if (!SUPPORTED_PROTOCOLS_SET.contains(p)) {
+- throw new IllegalArgumentException("Protocol " + p + " is not supported.");
+- }
+- if (p.equals(PROTOCOL_SSL_V2)) {
+- sslv2 = true;
+- } else if (p.equals(PROTOCOL_SSL_V3)) {
+- sslv3 = true;
+- } else if (p.equals(PROTOCOL_TLS_V1)) {
+- tlsv1 = true;
+- } else if (p.equals(PROTOCOL_TLS_V1_1)) {
+- tlsv1_1 = true;
+- } else if (p.equals(PROTOCOL_TLS_V1_2)) {
+- tlsv1_2 = true;
+- }
+- }
+- synchronized (this) {
+- if (destroyed == 0) {
+- // Enable all and then disable what we not want
+- SSL.setOptions(ssl, SSL.SSL_OP_ALL);
+-
+- if (!sslv2) {
+- SSL.setOptions(ssl, SSL.SSL_OP_NO_SSLv2);
+- }
+- if (!sslv3) {
+- SSL.setOptions(ssl, SSL.SSL_OP_NO_SSLv3);
+- }
+- if (!tlsv1) {
+- SSL.setOptions(ssl, SSL.SSL_OP_NO_TLSv1);
+- }
+- if (!tlsv1_1) {
+- SSL.setOptions(ssl, SSL.SSL_OP_NO_TLSv1_1);
+- }
+- if (!tlsv1_2) {
+- SSL.setOptions(ssl, SSL.SSL_OP_NO_TLSv1_2);
+- }
+- } else {
+- throw new IllegalStateException("failed to enable protocols: " + protocols);
+- }
+- }
+- }
+-
+- @Override
+- public SSLSession getSession() {
+- return session;
+- }
+-
+- @Override
+- public synchronized void beginHandshake() throws SSLException {
+- if (engineClosed || destroyed != 0) {
+- throw ENGINE_CLOSED;
+- }
+- switch (accepted) {
+- case 0:
+- handshake();
+- accepted = 2;
+- break;
+- case 1:
+- // A user did not start handshake by calling this method by him/herself,
+- // but handshake has been started already by wrap() or unwrap() implicitly.
+- // Because it's the user's first time to call this method, it is unfair to
+- // raise an exception. From the user's standpoint, he or she never asked
+- // for renegotiation.
+-
+- accepted = 2; // Next time this method is invoked by the user, we should raise an exception.
+- break;
+- case 2:
+- throw RENEGOTIATION_UNSUPPORTED;
+- default:
+- throw new Error();
+- }
+- }
+-
+- private void beginHandshakeImplicitly() throws SSLException {
+- if (engineClosed || destroyed != 0) {
+- throw ENGINE_CLOSED;
+- }
+-
+- if (accepted == 0) {
+- handshake();
+- accepted = 1;
+- }
+- }
+-
+- private void handshake() throws SSLException {
+- int code = SSL.doHandshake(ssl);
+- if (code <= 0) {
+- // Check for OpenSSL errors caused by the handshake
+- long error = SSL.getLastErrorNumber();
+- if (OpenSsl.isError(error)) {
+- String err = SSL.getErrorString(error);
+- if (logger.isDebugEnabled()) {
+- logger.debug(
+- "SSL_do_handshake failed: OpenSSL error: '" + err + '\'');
+- }
+-
+- // There was an internal error -- shutdown
+- shutdown();
+- throw newSSLException(err);
+- }
+- checkPendingHandshakeException();
+- } else {
+- // if SSL_do_handshake returns > 0 it means the handshake was finished. This means we can update
+- // handshakeFinished directly and so eliminate uncessary calls to SSL.isInInit(...)
+- handshakeFinished();
+- }
+- }
+-
+- private static long memoryAddress(ByteBuf buf) {
+- if (buf.hasMemoryAddress()) {
+- return buf.memoryAddress();
+- } else {
+- return Buffer.address(buf.nioBuffer());
+- }
+- }
+-
+- private void handshakeFinished() throws SSLException {
+- SelectedListenerFailureBehavior behavior = apn.selectedListenerFailureBehavior();
+- List protocols = apn.protocols();
+- String applicationProtocol;
+- switch (apn.protocol()) {
+- case NONE:
+- break;
+- // We always need to check for applicationProtocol == null as the remote peer may not support
+- // the TLS extension or may have returned an empty selection.
+- case ALPN:
+- applicationProtocol = SSL.getAlpnSelected(ssl);
+- if (applicationProtocol != null) {
+- this.applicationProtocol = selectApplicationProtocol(protocols, behavior, applicationProtocol);
+- }
+- break;
+- case NPN:
+- applicationProtocol = SSL.getNextProtoNegotiated(ssl);
+- if (applicationProtocol != null) {
+- this.applicationProtocol = selectApplicationProtocol(protocols, behavior, applicationProtocol);
+- }
+- break;
+- case NPN_AND_ALPN:
+- applicationProtocol = SSL.getAlpnSelected(ssl);
+- if (applicationProtocol == null) {
+- applicationProtocol = SSL.getNextProtoNegotiated(ssl);
+- }
+- if (applicationProtocol != null) {
+- this.applicationProtocol = selectApplicationProtocol(protocols, behavior, applicationProtocol);
+- }
+- break;
+- default:
+- throw new Error();
+- }
+- handshakeFinished = true;
+- }
+-
+- private static String selectApplicationProtocol(List protocols,
+- SelectedListenerFailureBehavior behavior,
+- String applicationProtocol) throws SSLException {
+- applicationProtocol = applicationProtocol.replace(':', '_');
+- if (behavior == SelectedListenerFailureBehavior.ACCEPT) {
+- return applicationProtocol;
+- } else {
+- int size = protocols.size();
+- assert size > 0;
+- if (protocols.contains(applicationProtocol)) {
+- return applicationProtocol;
+- } else {
+- if (behavior == SelectedListenerFailureBehavior.CHOOSE_MY_LAST_PROTOCOL) {
+- return protocols.get(size - 1);
+- } else {
+- throw new SSLException("Unknown protocol " + applicationProtocol);
+- }
+- }
+- }
+- }
+-
+- private SSLEngineResult.Status getEngineStatus() {
+- return engineClosed? CLOSED : OK;
+- }
+-
+- private SSLEngineResult.HandshakeStatus handshakeStatus0() throws SSLException {
+- SSLEngineResult.HandshakeStatus status = getHandshakeStatus();
+- if (status == FINISHED) {
+- handshakeFinished();
+- }
+- checkPendingHandshakeException();
+-
+- return status;
+- }
+-
+- @Override
+- public synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() {
+- if (accepted == 0 || destroyed != 0) {
+- return NOT_HANDSHAKING;
+- }
+-
+- // Check if we are in the initial handshake phase
+- if (!handshakeFinished) {
+- // There is pending data in the network BIO -- call wrap
+- if (SSL.pendingWrittenBytesInBIO(networkBIO) != 0) {
+- return NEED_WRAP;
+- }
+-
+- // No pending data to be sent to the peer
+- // Check to see if we have finished handshaking
+- if (SSL.isInInit(ssl) == 0) {
+- return FINISHED;
+- }
+-
+- // No pending data and still handshaking
+- // Must be waiting on the peer to send more data
+- return NEED_UNWRAP;
+- }
+-
+- // Check if we are in the shutdown phase
+- if (engineClosed) {
+- // Waiting to send the close_notify message
+- if (SSL.pendingWrittenBytesInBIO(networkBIO) != 0) {
+- return NEED_WRAP;
+- }
+-
+- // Must be waiting to receive the close_notify message
+- return NEED_UNWRAP;
+- }
+-
+- return NOT_HANDSHAKING;
+- }
+-
+- /**
+- * Converts the specified OpenSSL cipher suite to the Java cipher suite.
+- */
+- private String toJavaCipherSuite(String openSslCipherSuite) {
+- if (openSslCipherSuite == null) {
+- return null;
+- }
+-
+- String prefix = toJavaCipherSuitePrefix(SSL.getVersion(ssl));
+- return CipherSuiteConverter.toJava(openSslCipherSuite, prefix);
+- }
+-
+- /**
+- * Converts the protocol version string returned by {@link SSL#getVersion(long)} to protocol family string.
+- */
+- private static String toJavaCipherSuitePrefix(String protocolVersion) {
+- final char c;
+- if (protocolVersion == null || protocolVersion.length() == 0) {
+- c = 0;
+- } else {
+- c = protocolVersion.charAt(0);
+- }
+-
+- switch (c) {
+- case 'T':
+- return "TLS";
+- case 'S':
+- return "SSL";
+- default:
+- return "UNKNOWN";
+- }
+- }
+-
+- @Override
+- public void setUseClientMode(boolean clientMode) {
+- if (clientMode != this.clientMode) {
+- throw new UnsupportedOperationException();
+- }
+- }
+-
+- @Override
+- public boolean getUseClientMode() {
+- return clientMode;
+- }
+-
+- @Override
+- public void setNeedClientAuth(boolean b) {
+- setClientAuth(b ? ClientAuthMode.REQUIRE : ClientAuthMode.NONE);
+- }
+-
+- @Override
+- public boolean getNeedClientAuth() {
+- return clientAuth == ClientAuthMode.REQUIRE;
+- }
+-
+- @Override
+- public void setWantClientAuth(boolean b) {
+- setClientAuth(b ? ClientAuthMode.OPTIONAL : ClientAuthMode.NONE);
+- }
+-
+- @Override
+- public boolean getWantClientAuth() {
+- return clientAuth == ClientAuthMode.OPTIONAL;
+- }
+-
+- private void setClientAuth(ClientAuthMode mode) {
+- if (clientMode) {
+- return;
+- }
+- synchronized (this) {
+- if (clientAuth == mode) {
+- // No need to issue any JNI calls if the mode is the same
+- return;
+- }
+- switch (mode) {
+- case NONE:
+- SSL.setVerify(ssl, SSL.SSL_CVERIFY_NONE, OpenSslContext.VERIFY_DEPTH);
+- break;
+- case REQUIRE:
+- SSL.setVerify(ssl, SSL.SSL_CVERIFY_REQUIRE, OpenSslContext.VERIFY_DEPTH);
+- break;
+- case OPTIONAL:
+- SSL.setVerify(ssl, SSL.SSL_CVERIFY_OPTIONAL, OpenSslContext.VERIFY_DEPTH);
+- break;
+- }
+- clientAuth = mode;
+- }
+- }
+-
+- @Override
+- public void setEnableSessionCreation(boolean b) {
+- if (b) {
+- throw new UnsupportedOperationException();
+- }
+- }
+-
+- @Override
+- public boolean getEnableSessionCreation() {
+- return false;
+- }
+-
+- @Override
+- @SuppressWarnings("FinalizeDeclaration")
+- protected void finalize() throws Throwable {
+- super.finalize();
+- // Call shutdown as the user may have created the OpenSslEngine and not used it at all.
+- shutdown();
+- }
+-
+- private final class OpenSslSession implements SSLSession {
+- // SSLSession implementation seems to not need to be thread-safe so no need for volatile etc.
+- private X509Certificate[] x509PeerCerts;
+-
+- // lazy init for memory reasons
+- private Map values;
+-
+- @Override
+- public byte[] getId() {
+- final byte[] id;
+- synchronized (OpenSslEngine.this) {
+- if (destroyed == 0) {
+- id = SSL.getSessionId(ssl);
+- } else {
+- id = EmptyArrays.EMPTY_BYTES;
+- }
+- }
+- // We don't cache that to keep memory usage to a minimum.
+- if (id == null) {
+- // The id should never be null, if it was null then the SESSION itself was not valid.
+- throw new IllegalStateException("SSL session ID not available");
+- }
+- return id;
+- }
+-
+- @Override
+- public SSLSessionContext getSessionContext() {
+- return sessionContext;
+- }
+-
+- @Override
+- public long getCreationTime() {
+- synchronized (OpenSslEngine.this) {
+- if (destroyed == 0) {
+- // We need ot multiple by 1000 as openssl uses seconds and we need milli-seconds.
+- return SSL.getTime(ssl) * 1000L;
+- }
+- return 0;
+- }
+- }
+-
+- @Override
+- public long getLastAccessedTime() {
+- // TODO: Add proper implementation
+- return getCreationTime();
+- }
+-
+- @Override
+- public void invalidate() {
+- // NOOP
+- }
+-
+- @Override
+- public boolean isValid() {
+- return false;
+- }
+-
+- @Override
+- public void putValue(String name, Object value) {
+- if (name == null) {
+- throw new NullPointerException("name");
+- }
+- if (value == null) {
+- throw new NullPointerException("value");
+- }
+- Map values = this.values;
+- if (values == null) {
+- // Use size of 2 to keep the memory overhead small
+- values = this.values = new HashMap(2);
+- }
+- Object old = values.put(name, value);
+- if (value instanceof SSLSessionBindingListener) {
+- ((SSLSessionBindingListener) value).valueBound(new SSLSessionBindingEvent(this, name));
+- }
+- notifyUnbound(old, name);
+- }
+-
+- @Override
+- public Object getValue(String name) {
+- if (name == null) {
+- throw new NullPointerException("name");
+- }
+- if (values == null) {
+- return null;
+- }
+- return values.get(name);
+- }
+-
+- @Override
+- public void removeValue(String name) {
+- if (name == null) {
+- throw new NullPointerException("name");
+- }
+- Map values = this.values;
+- if (values == null) {
+- return;
+- }
+- Object old = values.remove(name);
+- notifyUnbound(old, name);
+- }
+-
+- @Override
+- public String[] getValueNames() {
+- Map values = this.values;
+- if (values == null || values.isEmpty()) {
+- return EmptyArrays.EMPTY_STRINGS;
+- }
+- return values.keySet().toArray(new String[values.size()]);
+- }
+-
+- private void notifyUnbound(Object value, String name) {
+- if (value instanceof SSLSessionBindingListener) {
+- ((SSLSessionBindingListener) value).valueUnbound(new SSLSessionBindingEvent(this, name));
+- }
+- }
+-
+- @Override
+- public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
+- // these are lazy created to reduce memory overhead
+- Certificate[] c = peerCerts;
+- if (c == null) {
+- synchronized (OpenSslEngine.this) {
+- if (destroyed == 0) {
+- if (SSL.isInInit(ssl) != 0) {
+- throw new SSLPeerUnverifiedException("peer not verified");
+- }
+- c = peerCerts = initPeerCertChain();
+- } else {
+- c = peerCerts = EMPTY_CERTIFICATES;
+- }
+- }
+- }
+- return c;
+- }
+-
+- @Override
+- public Certificate[] getLocalCertificates() {
+- // TODO: Find out how to get these
+- return EMPTY_CERTIFICATES;
+- }
+-
+- @Override
+- public X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException {
+- // these are lazy created to reduce memory overhead
+- X509Certificate[] c = x509PeerCerts;
+- if (c == null) {
+- final byte[][] chain;
+- synchronized (OpenSslEngine.this) {
+- if (destroyed == 0) {
+- if (SSL.isInInit(ssl) != 0) {
+- throw new SSLPeerUnverifiedException("peer not verified");
+- }
+- chain = SSL.getPeerCertChain(ssl);
+- } else {
+- c = x509PeerCerts = EMPTY_X509_CERTIFICATES;
+- return c;
+- }
+- }
+- if (chain == null) {
+- throw new SSLPeerUnverifiedException("peer not verified");
+- }
+- X509Certificate[] peerCerts = new X509Certificate[chain.length];
+- for (int i = 0; i < peerCerts.length; i++) {
+- try {
+- peerCerts[i] = X509Certificate.getInstance(chain[i]);
+- } catch (CertificateException e) {
+- throw new IllegalStateException(e);
+- }
+- }
+- c = x509PeerCerts = peerCerts;
+- }
+- return c;
+- }
+-
+- @Override
+- public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
+- Certificate[] peer = getPeerCertificates();
+- if (peer == null || peer.length == 0) {
+- return null;
+- }
+- return principal(peer);
+- }
+-
+- @Override
+- public Principal getLocalPrincipal() {
+- Certificate[] local = getLocalCertificates();
+- if (local == null || local.length == 0) {
+- return null;
+- }
+- return principal(local);
+- }
+-
+- private Principal principal(Certificate[] certs) {
+- return ((java.security.cert.X509Certificate) certs[0]).getIssuerX500Principal();
+- }
+-
+- @Override
+- public String getCipherSuite() {
+- if (!handshakeFinished) {
+- return INVALID_CIPHER;
+- }
+- if (cipher == null) {
+- final String c;
+- synchronized (OpenSslEngine.this) {
+- if (destroyed == 0) {
+- c = toJavaCipherSuite(SSL.getCipherForSSL(ssl));
+- } else {
+- c = INVALID_CIPHER;
+- }
+- }
+- if (c != null) {
+- cipher = c;
+- }
+- }
+- return cipher;
+- }
+-
+- @Override
+- public String getProtocol() {
+- String applicationProtocol = OpenSslEngine.this.applicationProtocol;
+- final String version;
+- synchronized (OpenSslEngine.this) {
+- if (destroyed == 0) {
+- version = SSL.getVersion(ssl);
+- } else {
+- return StringUtil.EMPTY_STRING;
+- }
+- }
+- if (applicationProtocol == null || applicationProtocol.isEmpty()) {
+- return version;
+- } else {
+- return version + ':' + applicationProtocol;
+- }
+- }
+-
+- @Override
+- public String getPeerHost() {
+- return null;
+- }
+-
+- @Override
+- public int getPeerPort() {
+- return 0;
+- }
+-
+- @Override
+- public int getPacketBufferSize() {
+- return MAX_ENCRYPTED_PACKET_LENGTH;
+- }
+-
+- @Override
+- public int getApplicationBufferSize() {
+- return MAX_PLAINTEXT_LENGTH;
+- }
+-
+- private Certificate[] initPeerCertChain() throws SSLPeerUnverifiedException {
+- byte[][] chain = SSL.getPeerCertChain(ssl);
+- final byte[] clientCert;
+- if (!clientMode) {
+- // if used on the server side SSL_get_peer_cert_chain(...) will not include the remote peer certificate.
+- // We use SSL_get_peer_certificate to get it in this case and add it to our array later.
+- //
+- // See https://www.openssl.org/docs/ssl/SSL_get_peer_cert_chain.html
+- clientCert = SSL.getPeerCertificate(ssl);
+- } else {
+- clientCert = null;
+- }
+-
+- if (chain == null && clientCert == null) {
+- throw new SSLPeerUnverifiedException("peer not verified");
+- }
+- int len = 0;
+- if (chain != null) {
+- len += chain.length;
+- }
+-
+- int i = 0;
+- Certificate[] peerCerts;
+- if (clientCert != null) {
+- len++;
+- peerCerts = new Certificate[len];
+- peerCerts[i++] = new OpenSslX509Certificate(clientCert);
+- } else {
+- peerCerts = new Certificate[len];
+- }
+- if (chain != null) {
+- int a = 0;
+- for (; i < peerCerts.length; i++) {
+- peerCerts[i] = new OpenSslX509Certificate(chain[a++]);
+- }
+- }
+- return peerCerts;
+- }
+- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java
+deleted file mode 100644
+index 382a28d..0000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java
++++ /dev/null
+@@ -1,42 +0,0 @@
+-/*
+- * Copyright 2014 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-interface OpenSslEngineMap {
+-
+- OpenSslEngineMap EMPTY = new OpenSslEngineMap() {
+- @Override
+- public OpenSslEngine remove(long ssl) {
+- return null;
+- }
+-
+- @Override
+- public void add(OpenSslEngine engine) {
+- // NOOP
+- }
+- };
+-
+- /**
+- * Remove the {@link OpenSslEngine} with the given {@code ssl} address and
+- * return it.
+- */
+- OpenSslEngine remove(long ssl);
+-
+- /**
+- * Add a {@link OpenSslEngine} to this {@link OpenSslEngineMap}.
+- */
+- void add(OpenSslEngine engine);
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java
+deleted file mode 100644
+index 83ee505..0000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java
++++ /dev/null
+@@ -1,418 +0,0 @@
+-/*
+- * Copyright 2014 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import io.netty.util.internal.EmptyArrays;
+-import org.apache.tomcat.jni.SSL;
+-import org.apache.tomcat.jni.SSLContext;
+-
+-import javax.net.ssl.KeyManager;
+-import javax.net.ssl.KeyManagerFactory;
+-import javax.net.ssl.SSLException;
+-import javax.net.ssl.TrustManager;
+-import javax.net.ssl.TrustManagerFactory;
+-import javax.net.ssl.X509ExtendedTrustManager;
+-import javax.net.ssl.X509TrustManager;
+-import java.io.File;
+-import java.security.KeyStore;
+-import java.security.cert.X509Certificate;
+-
+-import static io.netty.util.internal.ObjectUtil.*;
+-
+-/**
+- * A server-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
+- */
+-public final class OpenSslServerContext extends OpenSslContext {
+- private final OpenSslServerSessionContext sessionContext;
+-
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- */
+- public OpenSslServerContext(File certChainFile, File keyFile) throws SSLException {
+- this(certChainFile, keyFile, null);
+- }
+-
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- */
+- public OpenSslServerContext(File certChainFile, File keyFile, String keyPassword) throws SSLException {
+- this(certChainFile, keyFile, keyPassword, null, IdentityCipherSuiteFilter.INSTANCE,
+- ApplicationProtocolConfig.DISABLED, 0, 0);
+- }
+-
+- /**
+- * @deprecated use {@link #OpenSslServerContext(
+- * File, File, String, Iterable, CipherSuiteFilter, ApplicationProtocolConfig, long, long)}
+- *
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param apn Provides a means to configure parameters related to application protocol negotiation.
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File certChainFile, File keyFile, String keyPassword,
+- Iterable ciphers, ApplicationProtocolConfig apn,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(certChainFile, keyFile, keyPassword, ciphers, IdentityCipherSuiteFilter.INSTANCE,
+- apn, sessionCacheSize, sessionTimeout);
+- }
+-
+- /**
+- * @deprecated Use the constructors that accepts {@link ApplicationProtocolConfig} or
+- * {@link ApplicationProtocolNegotiator} instead.
+- *
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param nextProtocols the application layer protocols to accept, in the order of preference.
+- * {@code null} to disable TLS NPN/ALPN extension.
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File certChainFile, File keyFile, String keyPassword,
+- Iterable ciphers, Iterable nextProtocols,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(certChainFile, keyFile, keyPassword, ciphers,
+- toApplicationProtocolConfig(nextProtocols), sessionCacheSize, sessionTimeout);
+- }
+-
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param config Application protocol config.
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link #OpenSslServerContext(File, TrustManagerFactory, File, File, String, KeyManagerFactory,
+- * Iterable, CipherSuiteFilter, ApplicationProtocolConfig, long, long)}
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory,
+- Iterable ciphers, ApplicationProtocolConfig config,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(certChainFile, keyFile, keyPassword, trustManagerFactory, ciphers,
+- toNegotiator(config), sessionCacheSize, sessionTimeout);
+- }
+-
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param apn Application protocol negotiator.
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link #OpenSslServerContext(File, TrustManagerFactory, File, File, String, KeyManagerFactory,
+- * Iterable, CipherSuiteFilter, ApplicationProtocolConfig, long, long)}
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory,
+- Iterable ciphers, OpenSslApplicationProtocolNegotiator apn,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null,
+- ciphers, null, apn, sessionCacheSize, sessionTimeout);
+- }
+-
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param cipherFilter a filter to apply over the supplied list of ciphers
+- * @param apn Provides a means to configure parameters related to application protocol negotiation.
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- */
+- public OpenSslServerContext(
+- File certChainFile, File keyFile, String keyPassword,
+- Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(null, null, certChainFile, keyFile, keyPassword, null,
+- ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout);
+- }
+-
+- /**
+- * Creates a new instance.
+- *
+- * @param trustCertChainFile an X.509 certificate chain file in PEM format.
+- * This provides the certificate chains used for mutual authentication.
+- * {@code null} to use the system default
+- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
+- * that verifies the certificates sent from clients.
+- * {@code null} to use the default or the results of parsing {@code trustCertChainFile}.
+- * @param keyCertChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link KeyManager}s
+- * that is used to encrypt data being sent to clients.
+- * {@code null} to use the default or the results of parsing
+- * {@code keyCertChainFile} and {@code keyFile}.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param cipherFilter a filter to apply over the supplied list of ciphers
+- * Only required if {@code provider} is {@link SslProvider#JDK}
+- * @param config Provides a means to configure parameters related to application protocol negotiation.
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- */
+- public OpenSslServerContext(
+- File trustCertChainFile, TrustManagerFactory trustManagerFactory,
+- File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory,
+- Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig config,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(trustCertChainFile, trustManagerFactory, keyCertChainFile, keyFile, keyPassword, keyManagerFactory,
+- ciphers, cipherFilter, toNegotiator(config), sessionCacheSize, sessionTimeout);
+- }
+-
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param cipherFilter a filter to apply over the supplied list of ciphers
+- * @param config Application protocol config.
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- */
+- @Deprecated
+- public OpenSslServerContext(File certChainFile, File keyFile, String keyPassword,
+- TrustManagerFactory trustManagerFactory, Iterable ciphers,
+- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig config,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null, ciphers, cipherFilter,
+- toNegotiator(config), sessionCacheSize, sessionTimeout);
+- }
+-
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param cipherFilter a filter to apply over the supplied list of ciphers
+- * @param apn Application protocol negotiator.
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link #OpenSslServerContext(File, TrustManagerFactory, File, File, String, KeyManagerFactory,
+- * Iterable, CipherSuiteFilter, OpenSslApplicationProtocolNegotiator, long, long)}
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory,
+- Iterable ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null, ciphers, cipherFilter,
+- apn, sessionCacheSize, sessionTimeout);
+- }
+-
+- /**
+- * Creates a new instance.
+- *
+- *
+- * @param trustCertChainFile an X.509 certificate chain file in PEM format.
+- * This provides the certificate chains used for mutual authentication.
+- * {@code null} to use the system default
+- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
+- * that verifies the certificates sent from clients.
+- * {@code null} to use the default or the results of parsing {@code trustCertChainFile}.
+- * @param keyCertChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link KeyManager}s
+- * that is used to encrypt data being sent to clients.
+- * {@code null} to use the default or the results of parsing
+- * {@code keyCertChainFile} and {@code keyFile}.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param cipherFilter a filter to apply over the supplied list of ciphers
+- * Only required if {@code provider} is {@link SslProvider#JDK}
+- * @param apn Application Protocol Negotiator object
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- */
+- public OpenSslServerContext(
+- File trustCertChainFile, TrustManagerFactory trustManagerFactory,
+- File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory,
+- Iterable ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER);
+- OpenSsl.ensureAvailability();
+-
+- checkNotNull(keyCertChainFile, "keyCertChainFile");
+- if (!keyCertChainFile.isFile()) {
+- throw new IllegalArgumentException("keyCertChainFile is not a file: " + keyCertChainFile);
+- }
+- checkNotNull(keyFile, "keyFile");
+- if (!keyFile.isFile()) {
+- throw new IllegalArgumentException("keyFile is not a file: " + keyFile);
+- }
+- if (keyPassword == null) {
+- keyPassword = "";
+- }
+-
+- // Create a new SSL_CTX and configure it.
+- boolean success = false;
+- try {
+- synchronized (OpenSslContext.class) {
+- /* Set certificate verification policy. */
+- SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_NONE, VERIFY_DEPTH);
+-
+- /* Load the certificate chain. We must skip the first cert when server mode */
+- if (!SSLContext.setCertificateChainFile(ctx, keyCertChainFile.getPath(), true)) {
+- long error = SSL.getLastErrorNumber();
+- if (OpenSsl.isError(error)) {
+- String err = SSL.getErrorString(error);
+- throw new SSLException(
+- "failed to set certificate chain: " + keyCertChainFile + " (" + err + ')');
+- }
+- }
+-
+- /* Load the certificate file and private key. */
+- try {
+- if (!SSLContext.setCertificate(
+- ctx, keyCertChainFile.getPath(), keyFile.getPath(), keyPassword, SSL.SSL_AIDX_RSA)) {
+- long error = SSL.getLastErrorNumber();
+- if (OpenSsl.isError(error)) {
+- String err = SSL.getErrorString(error);
+- throw new SSLException("failed to set certificate: " +
+- keyCertChainFile + " and " + keyFile + " (" + err + ')');
+- }
+- }
+- } catch (SSLException e) {
+- throw e;
+- } catch (Exception e) {
+- throw new SSLException("failed to set certificate: " + keyCertChainFile + " and " + keyFile, e);
+- }
+- try {
+- if (trustManagerFactory == null) {
+- // Mimic the way SSLContext.getInstance(KeyManager[], null, null) works
+- trustManagerFactory = TrustManagerFactory.getInstance(
+- TrustManagerFactory.getDefaultAlgorithm());
+- }
+- if (trustCertChainFile != null) {
+- trustManagerFactory = buildTrustManagerFactory(trustCertChainFile, trustManagerFactory);
+- } else {
+- char[] keyPasswordChars =
+- keyPassword == null ? EmptyArrays.EMPTY_CHARS : keyPassword.toCharArray();
+-
+- KeyStore ks = buildKeyStore(keyCertChainFile, keyFile, keyPasswordChars);
+- trustManagerFactory.init(ks);
+- }
+-
+- final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers());
+-
+- // Use this to prevent an error when running on java < 7
+- if (useExtendedTrustManager(manager)) {
+- final X509ExtendedTrustManager extendedManager = (X509ExtendedTrustManager) manager;
+- SSLContext.setCertVerifyCallback(ctx, new AbstractCertificateVerifier() {
+- @Override
+- void verify(OpenSslEngine engine, X509Certificate[] peerCerts, String auth)
+- throws Exception {
+- extendedManager.checkClientTrusted(peerCerts, auth, engine);
+- }
+- });
+- } else {
+- SSLContext.setCertVerifyCallback(ctx, new AbstractCertificateVerifier() {
+- @Override
+- void verify(OpenSslEngine engine, X509Certificate[] peerCerts, String auth)
+- throws Exception {
+- manager.checkClientTrusted(peerCerts, auth);
+- }
+- });
+- }
+- } catch (Exception e) {
+- throw new SSLException("unable to setup trustmanager", e);
+- }
+- }
+- sessionContext = new OpenSslServerSessionContext(ctx);
+- success = true;
+- } finally {
+- if (!success) {
+- destroyPools();
+- }
+- }
+- }
+-
+- @Override
+- public OpenSslServerSessionContext sessionContext() {
+- return sessionContext;
+- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java
+deleted file mode 100644
+index 693801f..0000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java
++++ /dev/null
+@@ -1,79 +0,0 @@
+-/*
+- * Copyright 2014 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import org.apache.tomcat.jni.SSL;
+-import org.apache.tomcat.jni.SSLContext;
+-
+-
+-/**
+- * {@link OpenSslSessionContext} implementation which offers extra methods which are only useful for the server-side.
+- */
+-public final class OpenSslServerSessionContext extends OpenSslSessionContext {
+- OpenSslServerSessionContext(long context) {
+- super(context);
+- }
+-
+- @Override
+- public void setSessionTimeout(int seconds) {
+- if (seconds < 0) {
+- throw new IllegalArgumentException();
+- }
+- SSLContext.setSessionCacheTimeout(context, seconds);
+- }
+-
+- @Override
+- public int getSessionTimeout() {
+- return (int) SSLContext.getSessionCacheTimeout(context);
+- }
+-
+- @Override
+- public void setSessionCacheSize(int size) {
+- if (size < 0) {
+- throw new IllegalArgumentException();
+- }
+- SSLContext.setSessionCacheSize(context, size);
+- }
+-
+- @Override
+- public int getSessionCacheSize() {
+- return (int) SSLContext.getSessionCacheSize(context);
+- }
+-
+- @Override
+- public void setSessionCacheEnabled(boolean enabled) {
+- long mode = enabled ? SSL.SSL_SESS_CACHE_SERVER : SSL.SSL_SESS_CACHE_OFF;
+- SSLContext.setSessionCacheMode(context, mode);
+- }
+-
+- @Override
+- public boolean isSessionCacheEnabled() {
+- return SSLContext.getSessionCacheMode(context) == SSL.SSL_SESS_CACHE_SERVER;
+- }
+-
+- /**
+- * Set the context within which session be reused (server side only)
+- * See
+- * man SSL_CTX_set_session_id_context
+- *
+- * @param sidCtx can be any kind of binary data, it is therefore possible to use e.g. the name
+- * of the application and/or the hostname and/or service name
+- * @return {@code true} if success, {@code false} otherwise.
+- */
+- public boolean setSessionIdContext(byte[] sidCtx) {
+- return SSLContext.setSessionIdContext(context, sidCtx);
+- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java
+deleted file mode 100644
+index fd17821..0000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java
++++ /dev/null
+@@ -1,90 +0,0 @@
+-/*
+- * Copyright 2014 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import org.apache.tomcat.jni.SSLContext;
+-
+-import javax.net.ssl.SSLSession;
+-import javax.net.ssl.SSLSessionContext;
+-import java.util.Enumeration;
+-import java.util.NoSuchElementException;
+-
+-/**
+- * OpenSSL specific {@link SSLSessionContext} implementation.
+- */
+-public abstract class OpenSslSessionContext implements SSLSessionContext {
+- private static final Enumeration EMPTY = new EmptyEnumeration();
+-
+- private final OpenSslSessionStats stats;
+- final long context;
+-
+- OpenSslSessionContext(long context) {
+- this.context = context;
+- stats = new OpenSslSessionStats(context);
+- }
+-
+- @Override
+- public SSLSession getSession(byte[] bytes) {
+- if (bytes == null) {
+- throw new NullPointerException("bytes");
+- }
+- return null;
+- }
+-
+- @Override
+- public Enumeration getIds() {
+- return EMPTY;
+- }
+-
+- /**
+- * Sets the SSL session ticket keys of this context.
+- */
+- public void setTicketKeys(byte[] keys) {
+- if (keys == null) {
+- throw new NullPointerException("keys");
+- }
+- SSLContext.setSessionTicketKeys(context, keys);
+- }
+-
+- /**
+- * Enable or disable caching of SSL sessions.
+- */
+- public abstract void setSessionCacheEnabled(boolean enabled);
+-
+- /**
+- * Return {@code true} if caching of SSL sessions is enabled, {@code false} otherwise.
+- */
+- public abstract boolean isSessionCacheEnabled();
+-
+- /**
+- * Returns the stats of this context.
+- */
+- public OpenSslSessionStats stats() {
+- return stats;
+- }
+-
+- private static final class EmptyEnumeration implements Enumeration {
+- @Override
+- public boolean hasMoreElements() {
+- return false;
+- }
+-
+- @Override
+- public byte[] nextElement() {
+- throw new NoSuchElementException();
+- }
+- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java
+deleted file mode 100644
+index 2ec5146..0000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java
++++ /dev/null
+@@ -1,122 +0,0 @@
+-/*
+- * Copyright 2014 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-
+-package io.netty.handler.ssl;
+-
+-import org.apache.tomcat.jni.SSLContext;
+-
+-/**
+- * Stats exposed by an OpenSSL session context.
+- *
+- * @see SSL_CTX_sess_number
+- */
+-public final class OpenSslSessionStats {
+-
+- private final long context;
+-
+- OpenSslSessionStats(long context) {
+- this.context = context;
+- }
+-
+- /**
+- * Returns the current number of sessions in the internal session cache.
+- */
+- public long number() {
+- return SSLContext.sessionNumber(context);
+- }
+-
+- /**
+- * Returns the number of started SSL/TLS handshakes in client mode.
+- */
+- public long connect() {
+- return SSLContext.sessionConnect(context);
+- }
+-
+- /**
+- * Returns the number of successfully established SSL/TLS sessions in client mode.
+- */
+- public long connectGood() {
+- return SSLContext.sessionConnectGood(context);
+- }
+-
+- /**
+- * Returns the number of start renegotiations in client mode.
+- */
+- public long connectRenegotiate() {
+- return SSLContext.sessionConnectRenegotiate(context);
+- }
+-
+- /**
+- * Returns the number of started SSL/TLS handshakes in server mode.
+- */
+- public long accept() {
+- return SSLContext.sessionAccept(context);
+- }
+-
+- /**
+- * Returns the number of successfully established SSL/TLS sessions in server mode.
+- */
+- public long acceptGood() {
+- return SSLContext.sessionAcceptGood(context);
+- }
+-
+- /**
+- * Returns the number of start renegotiations in server mode.
+- */
+- public long acceptRenegotiate() {
+- return SSLContext.sessionAcceptRenegotiate(context);
+- }
+-
+- /**
+- * Returns the number of successfully reused sessions. In client mode, a session set with {@code SSL_set_session}
+- * successfully reused is counted as a hit. In server mode, a session successfully retrieved from internal or
+- * external cache is counted as a hit.
+- */
+- public long hits() {
+- return SSLContext.sessionHits(context);
+- }
+-
+- /**
+- * Returns the number of successfully retrieved sessions from the external session cache in server mode.
+- */
+- public long cbHits() {
+- return SSLContext.sessionCbHits(context);
+- }
+-
+- /**
+- * Returns the number of sessions proposed by clients that were not found in the internal session cache
+- * in server mode.
+- */
+- public long misses() {
+- return SSLContext.sessionMisses(context);
+- }
+-
+- /**
+- * Returns the number of sessions proposed by clients and either found in the internal or external session cache
+- * in server mode, but that were invalid due to timeout. These sessions are not included in the {@link #hits()}
+- * count.
+- */
+- public long timeouts() {
+- return SSLContext.sessionTimeouts(context);
+- }
+-
+- /**
+- * Returns the number of sessions that were removed because the maximum session cache size was exceeded.
+- */
+- public long cacheFull() {
+- return SSLContext.sessionCacheFull(context);
+- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/SslContext.java b/handler/src/main/java/io/netty/handler/ssl/SslContext.java
+index 890b362..42abc14 100644
+--- a/handler/src/main/java/io/netty/handler/ssl/SslContext.java
++++ b/handler/src/main/java/io/netty/handler/ssl/SslContext.java
+@@ -110,11 +110,7 @@ public abstract class SslContext {
+ }
+
+ private static SslProvider defaultProvider() {
+- if (OpenSsl.isAvailable()) {
+- return SslProvider.OPENSSL;
+- } else {
+- return SslProvider.JDK;
+- }
++ return SslProvider.JDK;
+ }
+
+ /**
+@@ -399,10 +395,6 @@ public abstract class SslContext {
+ return new JdkSslServerContext(
+ trustCertChainFile, trustManagerFactory, keyCertChainFile, keyFile, keyPassword,
+ keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout);
+- case OPENSSL:
+- return new OpenSslServerContext(
+- trustCertChainFile, trustManagerFactory, keyCertChainFile, keyFile, keyPassword,
+- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout);
+ default:
+ throw new Error(provider.toString());
+ }
+@@ -729,10 +721,6 @@ public abstract class SslContext {
+ return new JdkSslClientContext(
+ trustCertChainFile, trustManagerFactory, keyCertChainFile, keyFile, keyPassword,
+ keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout);
+- case OPENSSL:
+- return new OpenSslClientContext(
+- trustCertChainFile, trustManagerFactory, keyCertChainFile, keyFile, keyPassword,
+- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout);
+ }
+ // Should never happen!!
+ throw new Error();
+diff --git a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
+index a3b1716..c492dc4 100644
+--- a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
++++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
+@@ -161,6 +161,15 @@ import java.util.regex.Pattern;
+ */
+ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundHandler {
+
++ private static final int MAX_PLAINTEXT_LENGTH = 16 * 1024; // 2^14
++ private static final int MAX_COMPRESSED_LENGTH = MAX_PLAINTEXT_LENGTH + 1024;
++ private static final int MAX_CIPHERTEXT_LENGTH = MAX_COMPRESSED_LENGTH + 1024;
++
++ // Header (5) + Data (2^14) + Compression (1024) + Encryption (1024) + MAC (20) + Padding (256)
++ static final int MAX_ENCRYPTED_PACKET_LENGTH = MAX_CIPHERTEXT_LENGTH + 5 + 20 + 256;
++
++ static final int MAX_ENCRYPTION_OVERHEAD_LENGTH = MAX_ENCRYPTED_PACKET_LENGTH - MAX_PLAINTEXT_LENGTH;
++
+ private static final InternalLogger logger =
+ InternalLoggerFactory.getInstance(SslHandler.class);
+
+@@ -290,7 +299,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
+ this.startTls = startTls;
+ maxPacketBufferSize = engine.getSession().getPacketBufferSize();
+
+- boolean opensslEngine = engine instanceof OpenSslEngine;
++ boolean opensslEngine = false;
+ wantsDirectBuffer = opensslEngine;
+ wantsLargeOutboundNetworkBuffer = !opensslEngine;
+
+@@ -883,7 +892,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
+
+ boolean nonSslRecord = false;
+
+- while (totalLength < OpenSslEngine.MAX_ENCRYPTED_PACKET_LENGTH) {
++ while (totalLength < MAX_ENCRYPTED_PACKET_LENGTH) {
+ final int readableBytes = endOffset - offset;
+ if (readableBytes < 5) {
+ break;
+@@ -904,7 +913,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
+ }
+
+ int newTotalLength = totalLength + packetLength;
+- if (newTotalLength > OpenSslEngine.MAX_ENCRYPTED_PACKET_LENGTH) {
++ if (newTotalLength > MAX_ENCRYPTED_PACKET_LENGTH) {
+ // Don't read too much.
+ break;
+ }
+@@ -1077,47 +1086,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
+ private SSLEngineResult unwrap(
+ SSLEngine engine, ByteBuf in, int readerIndex, int len, ByteBuf out) throws SSLException {
+ int nioBufferCount = in.nioBufferCount();
+- if (engine instanceof OpenSslEngine && nioBufferCount > 1) {
+- /**
+- * If {@link OpenSslEngine} is in use,
+- * we can use a special {@link OpenSslEngine#unwrap(ByteBuffer[], ByteBuffer[])} method
+- * that accepts multiple {@link ByteBuffer}s without additional memory copies.
+- */
+- OpenSslEngine opensslEngine = (OpenSslEngine) engine;
+- int overflows = 0;
+- ByteBuffer[] in0 = in.nioBuffers(readerIndex, len);
+- try {
+- for (;;) {
+- int writerIndex = out.writerIndex();
+- int writableBytes = out.writableBytes();
+- ByteBuffer out0;
+- if (out.nioBufferCount() == 1) {
+- out0 = out.internalNioBuffer(writerIndex, writableBytes);
+- } else {
+- out0 = out.nioBuffer(writerIndex, writableBytes);
+- }
+- singleBuffer[0] = out0;
+- SSLEngineResult result = opensslEngine.unwrap(in0, singleBuffer);
+- out.writerIndex(out.writerIndex() + result.bytesProduced());
+- switch (result.getStatus()) {
+- case BUFFER_OVERFLOW:
+- int max = engine.getSession().getApplicationBufferSize();
+- switch (overflows ++) {
+- case 0:
+- out.ensureWritable(Math.min(max, in.readableBytes()));
+- break;
+- default:
+- out.ensureWritable(max);
+- }
+- break;
+- default:
+- return result;
+- }
+- }
+- } finally {
+- singleBuffer[0] = null;
+- }
+- } else {
++
+ int overflows = 0;
+ ByteBuffer in0;
+ if (nioBufferCount == 1) {
+@@ -1154,7 +1123,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
+ return result;
+ }
+ }
+- }
+ }
+
+ /**
+@@ -1514,7 +1482,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
+ return allocate(ctx, maxPacketBufferSize);
+ } else {
+ return allocate(ctx, Math.min(
+- pendingBytes + OpenSslEngine.MAX_ENCRYPTION_OVERHEAD_LENGTH,
++ pendingBytes + MAX_ENCRYPTION_OVERHEAD_LENGTH,
+ maxPacketBufferSize));
+ }
+ }
+diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
+deleted file mode 100644
+index 9482f2b..0000000
+--- a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
++++ /dev/null
+@@ -1,349 +0,0 @@
+-/*
+- * Copyright 2014 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import static org.junit.Assert.assertNull;
+-import static org.junit.Assert.assertTrue;
+-import static org.junit.Assume.assumeNoException;
+-import io.netty.bootstrap.Bootstrap;
+-import io.netty.bootstrap.ServerBootstrap;
+-import io.netty.channel.Channel;
+-import io.netty.channel.ChannelFuture;
+-import io.netty.channel.ChannelHandlerAdapter;
+-import io.netty.channel.ChannelHandlerContext;
+-import io.netty.channel.ChannelInitializer;
+-import io.netty.channel.ChannelPipeline;
+-import io.netty.channel.nio.NioEventLoopGroup;
+-import io.netty.channel.socket.nio.NioServerSocketChannel;
+-import io.netty.channel.socket.nio.NioSocketChannel;
+-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
+-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectorFactory;
+-import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
+-import io.netty.handler.ssl.util.SelfSignedCertificate;
+-import io.netty.util.NetUtil;
+-
+-import java.net.InetSocketAddress;
+-import java.security.cert.CertificateException;
+-import java.util.List;
+-import java.util.Set;
+-import java.util.concurrent.TimeUnit;
+-
+-import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.SSLException;
+-import javax.net.ssl.SSLHandshakeException;
+-
+-import org.junit.Test;
+-
+-public class JdkSslEngineTest extends SSLEngineTest {
+- private static final String PREFERRED_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http2";
+- private static final String FALLBACK_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http1_1";
+- private static final String APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE = "my-protocol-FOO";
+-
+- @Test
+- public void testNpn() throws Exception {
+- try {
+- // Typical code will not have to check this, but will get a initialization error on class load.
+- // Check in this test just in case we have multiple tests that just the class and we already ignored the
+- // initialization error.
+- if (!JdkNpnSslEngine.isAvailable()) {
+- throw new RuntimeException("NPN not on classpath");
+- }
+- JdkApplicationProtocolNegotiator apn = new JdkNpnApplicationProtocolNegotiator(true, true,
+- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
+- mySetup(apn);
+- runTest();
+- } catch (RuntimeException e) {
+- // NPN availability is dependent on the java version. If NPN is not available because of
+- // java version incompatibility don't fail the test, but instead just skip the test
+- assumeNoException(e);
+- }
+- }
+-
+- @Test
+- public void testNpnNoCompatibleProtocolsNoHandshakeFailure() throws Exception {
+- try {
+- // Typical code will not have to check this, but will get a initialization error on class load.
+- // Check in this test just in case we have multiple tests that just the class and we already ignored the
+- // initialization error.
+- if (!JdkNpnSslEngine.isAvailable()) {
+- throw new RuntimeException("NPN not on classpath");
+- }
+- JdkApplicationProtocolNegotiator clientApn = new JdkNpnApplicationProtocolNegotiator(false, false,
+- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
+- JdkApplicationProtocolNegotiator serverApn = new JdkNpnApplicationProtocolNegotiator(false, false,
+- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
+- mySetup(serverApn, clientApn);
+- runTest(null);
+- } catch (Exception e) {
+- // ALPN availability is dependent on the java version. If ALPN is not available because of
+- // java version incompatibility don't fail the test, but instead just skip the test
+- assumeNoException(e);
+- }
+- }
+-
+- @Test
+- public void testNpnNoCompatibleProtocolsClientHandshakeFailure() throws Exception {
+- try {
+- // Typical code will not have to check this, but will get a initialization error on class load.
+- // Check in this test just in case we have multiple tests that just the class and we already ignored the
+- // initialization error.
+- if (!JdkNpnSslEngine.isAvailable()) {
+- throw new RuntimeException("NPN not on classpath");
+- }
+- JdkApplicationProtocolNegotiator clientApn = new JdkNpnApplicationProtocolNegotiator(true, true,
+- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
+- JdkApplicationProtocolNegotiator serverApn = new JdkNpnApplicationProtocolNegotiator(false, false,
+- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
+- mySetup(serverApn, clientApn);
+- assertTrue(clientLatch.await(2, TimeUnit.SECONDS));
+- assertTrue(clientException instanceof SSLHandshakeException);
+- } catch (RuntimeException e) {
+- // NPN availability is dependent on the java version. If NPN is not available because of
+- // java version incompatibility don't fail the test, but instead just skip the test
+- assumeNoException(e);
+- }
+- }
+-
+- @Test
+- public void testNpnNoCompatibleProtocolsServerHandshakeFailure() throws Exception {
+- try {
+- // Typical code will not have to check this, but will get a initialization error on class load.
+- // Check in this test just in case we have multiple tests that just the class and we already ignored the
+- // initialization error.
+- if (!JdkNpnSslEngine.isAvailable()) {
+- throw new RuntimeException("NPN not on classpath");
+- }
+- JdkApplicationProtocolNegotiator clientApn = new JdkNpnApplicationProtocolNegotiator(false, false,
+- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
+- JdkApplicationProtocolNegotiator serverApn = new JdkNpnApplicationProtocolNegotiator(true, true,
+- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
+- mySetup(serverApn, clientApn);
+- assertTrue(serverLatch.await(2, TimeUnit.SECONDS));
+- assertTrue(serverException instanceof SSLHandshakeException);
+- } catch (RuntimeException e) {
+- // NPN availability is dependent on the java version. If NPN is not available because of
+- // java version incompatibility don't fail the test, but instead just skip the test
+- assumeNoException(e);
+- }
+- }
+-
+- @Test
+- public void testAlpn() throws Exception {
+- try {
+- // Typical code will not have to check this, but will get a initialization error on class load.
+- // Check in this test just in case we have multiple tests that just the class and we already ignored the
+- // initialization error.
+- if (!JdkAlpnSslEngine.isAvailable()) {
+- throw new RuntimeException("ALPN not on classpath");
+- }
+- JdkApplicationProtocolNegotiator apn = new JdkAlpnApplicationProtocolNegotiator(true, true,
+- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
+- mySetup(apn);
+- runTest();
+- } catch (Exception e) {
+- // ALPN availability is dependent on the java version. If ALPN is not available because of
+- // java version incompatibility don't fail the test, but instead just skip the test
+- assumeNoException(e);
+- }
+- }
+-
+- @Test
+- public void testAlpnNoCompatibleProtocolsNoHandshakeFailure() throws Exception {
+- try {
+- // Typical code will not have to check this, but will get a initialization error on class load.
+- // Check in this test just in case we have multiple tests that just the class and we already ignored the
+- // initialization error.
+- if (!JdkAlpnSslEngine.isAvailable()) {
+- throw new RuntimeException("ALPN not on classpath");
+- }
+- JdkApplicationProtocolNegotiator clientApn = new JdkAlpnApplicationProtocolNegotiator(false, false,
+- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
+- JdkApplicationProtocolNegotiator serverApn = new JdkAlpnApplicationProtocolNegotiator(false, false,
+- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
+- mySetup(serverApn, clientApn);
+- runTest(null);
+- } catch (Exception e) {
+- // ALPN availability is dependent on the java version. If ALPN is not available because of
+- // java version incompatibility don't fail the test, but instead just skip the test
+- assumeNoException(e);
+- }
+- }
+-
+- @Test
+- public void testAlpnNoCompatibleProtocolsServerHandshakeFailure() throws Exception {
+- try {
+- // Typical code will not have to check this, but will get a initialization error on class load.
+- // Check in this test just in case we have multiple tests that just the class and we already ignored the
+- // initialization error.
+- if (!JdkAlpnSslEngine.isAvailable()) {
+- throw new RuntimeException("ALPN not on classpath");
+- }
+- JdkApplicationProtocolNegotiator clientApn = new JdkAlpnApplicationProtocolNegotiator(false, false,
+- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
+- JdkApplicationProtocolNegotiator serverApn = new JdkAlpnApplicationProtocolNegotiator(true, true,
+- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
+- mySetup(serverApn, clientApn);
+- assertTrue(serverLatch.await(2, TimeUnit.SECONDS));
+- assertTrue(serverException instanceof SSLHandshakeException);
+- } catch (Exception e) {
+- // ALPN availability is dependent on the java version. If ALPN is not available because of
+- // java version incompatibility don't fail the test, but instead just skip the test
+- assumeNoException(e);
+- }
+- }
+-
+- @Test
+- public void testAlpnCompatibleProtocolsDifferentClientOrder() throws Exception {
+- try {
+- // Typical code will not have to check this, but will get a initialization error on class load.
+- // Check in this test just in case we have multiple tests that just the class and we already ignored the
+- // initialization error.
+- if (!JdkAlpnSslEngine.isAvailable()) {
+- throw new RuntimeException("ALPN not on classpath");
+- }
+- // Even the preferred application protocol appears second in the client's list, it will be picked
+- // because it's the first one on server's list.
+- JdkApplicationProtocolNegotiator clientApn = new JdkAlpnApplicationProtocolNegotiator(false, false,
+- FALLBACK_APPLICATION_LEVEL_PROTOCOL, PREFERRED_APPLICATION_LEVEL_PROTOCOL);
+- JdkApplicationProtocolNegotiator serverApn = new JdkAlpnApplicationProtocolNegotiator(true, true,
+- PREFERRED_APPLICATION_LEVEL_PROTOCOL, FALLBACK_APPLICATION_LEVEL_PROTOCOL);
+- mySetup(serverApn, clientApn);
+- assertNull(serverException);
+- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL);
+- } catch (Exception e) {
+- // ALPN availability is dependent on the java version. If ALPN is not available because of
+- // java version incompatibility don't fail the test, but instead just skip the test
+- assumeNoException(e);
+- }
+- }
+-
+- @Test
+- public void testAlpnNoCompatibleProtocolsClientHandshakeFailure() throws Exception {
+- try {
+- // Typical code will not have to check this, but will get a initialization error on class load.
+- // Check in this test just in case we have multiple tests that just the class and we already ignored the
+- // initialization error.
+- if (!JdkAlpnSslEngine.isAvailable()) {
+- throw new RuntimeException("ALPN not on classpath");
+- }
+- JdkApplicationProtocolNegotiator clientApn = new JdkAlpnApplicationProtocolNegotiator(true, true,
+- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
+- JdkApplicationProtocolNegotiator serverApn = new JdkAlpnApplicationProtocolNegotiator(
+- new ProtocolSelectorFactory() {
+- @Override
+- public ProtocolSelector newSelector(SSLEngine engine, Set supportedProtocols) {
+- return new ProtocolSelector() {
+- @Override
+- public void unsupported() {
+- }
+-
+- @Override
+- public String select(List protocols) {
+- return APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE;
+- }
+- };
+- }
+- }, JdkBaseApplicationProtocolNegotiator.FAIL_SELECTION_LISTENER_FACTORY,
+- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
+- mySetup(serverApn, clientApn);
+- assertTrue(clientLatch.await(2, TimeUnit.SECONDS));
+- assertTrue(clientException instanceof SSLHandshakeException);
+- } catch (Exception e) {
+- // ALPN availability is dependent on the java version. If ALPN is not available because of
+- // java version incompatibility don't fail the test, but instead just skip the test
+- assumeNoException(e);
+- }
+- }
+-
+- private void mySetup(JdkApplicationProtocolNegotiator apn) throws InterruptedException, SSLException,
+- CertificateException {
+- mySetup(apn, apn);
+- }
+-
+- private void mySetup(JdkApplicationProtocolNegotiator serverApn, JdkApplicationProtocolNegotiator clientApn)
+- throws InterruptedException, SSLException, CertificateException {
+- SelfSignedCertificate ssc = new SelfSignedCertificate();
+- serverSslCtx = new JdkSslServerContext(ssc.certificate(), ssc.privateKey(), null, null,
+- IdentityCipherSuiteFilter.INSTANCE, serverApn, 0, 0);
+- clientSslCtx = new JdkSslClientContext(null, InsecureTrustManagerFactory.INSTANCE, null,
+- IdentityCipherSuiteFilter.INSTANCE, clientApn, 0, 0);
+-
+- serverConnectedChannel = null;
+- sb = new ServerBootstrap();
+- cb = new Bootstrap();
+-
+- sb.group(new NioEventLoopGroup(), new NioEventLoopGroup());
+- sb.channel(NioServerSocketChannel.class);
+- sb.childHandler(new ChannelInitializer() {
+- @Override
+- protected void initChannel(Channel ch) throws Exception {
+- ChannelPipeline p = ch.pipeline();
+- p.addLast(serverSslCtx.newHandler(ch.alloc()));
+- p.addLast(new MessageDelegatorChannelHandler(serverReceiver, serverLatch));
+- p.addLast(new ChannelHandlerAdapter() {
+- @Override
+- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+- if (cause.getCause() instanceof SSLHandshakeException) {
+- serverException = cause.getCause();
+- serverLatch.countDown();
+- } else {
+- ctx.fireExceptionCaught(cause);
+- }
+- }
+- });
+- serverConnectedChannel = ch;
+- }
+- });
+-
+- cb.group(new NioEventLoopGroup());
+- cb.channel(NioSocketChannel.class);
+- cb.handler(new ChannelInitializer() {
+- @Override
+- protected void initChannel(Channel ch) throws Exception {
+- ChannelPipeline p = ch.pipeline();
+- p.addLast(clientSslCtx.newHandler(ch.alloc()));
+- p.addLast(new MessageDelegatorChannelHandler(clientReceiver, clientLatch));
+- p.addLast(new ChannelHandlerAdapter() {
+- @Override
+- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+- if (cause.getCause() instanceof SSLHandshakeException) {
+- clientException = cause.getCause();
+- clientLatch.countDown();
+- } else {
+- ctx.fireExceptionCaught(cause);
+- }
+- }
+- });
+- }
+- });
+-
+- serverChannel = sb.bind(new InetSocketAddress(0)).sync().channel();
+- int port = ((InetSocketAddress) serverChannel.localAddress()).getPort();
+-
+- ChannelFuture ccf = cb.connect(new InetSocketAddress(NetUtil.LOCALHOST, port));
+- assertTrue(ccf.awaitUninterruptibly().isSuccess());
+- clientChannel = ccf.channel();
+- }
+-
+- private void runTest() throws Exception {
+- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL);
+- }
+-
+- @Override
+- protected SslProvider sslProvider() {
+- return SslProvider.JDK;
+- }
+-}
diff --git a/SOURCES/remove-bc-dependency.patch b/SOURCES/remove-bc-dependency.patch
new file mode 100644
index 0000000..cf66e1b
--- /dev/null
+++ b/SOURCES/remove-bc-dependency.patch
@@ -0,0 +1,140 @@
+diff --git a/handler/pom.xml b/handler/pom.xml
+index 978aa2f..1b8ef3a 100644
+--- a/handler/pom.xml
++++ b/handler/pom.xml
+@@ -51,11 +51,6 @@
+ true
+
+
+- org.bouncycastle
+- bcpkix-jdk15on
+- true
+-
+-
+ org.eclipse.jetty.npn
+ npn-api
+ true
+diff --git a/handler/src/main/java/io/netty/handler/ssl/util/BouncyCastleSelfSignedCertGenerator.java b/handler/src/main/java/io/netty/handler/ssl/util/BouncyCastleSelfSignedCertGenerator.java
+deleted file mode 100644
+index 88a7c9d..0000000
+--- a/handler/src/main/java/io/netty/handler/ssl/util/BouncyCastleSelfSignedCertGenerator.java
++++ /dev/null
+@@ -1,61 +0,0 @@
+-/*
+- * Copyright 2014 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-
+-package io.netty.handler.ssl.util;
+-
+-import org.bouncycastle.asn1.x500.X500Name;
+-import org.bouncycastle.cert.X509CertificateHolder;
+-import org.bouncycastle.cert.X509v3CertificateBuilder;
+-import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+-import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
+-import org.bouncycastle.jce.provider.BouncyCastleProvider;
+-import org.bouncycastle.operator.ContentSigner;
+-import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+-
+-import java.math.BigInteger;
+-import java.security.KeyPair;
+-import java.security.PrivateKey;
+-import java.security.Provider;
+-import java.security.SecureRandom;
+-import java.security.cert.X509Certificate;
+-
+-import static io.netty.handler.ssl.util.SelfSignedCertificate.*;
+-
+-/**
+- * Generates a self-signed certificate using Bouncy Castle.
+- */
+-final class BouncyCastleSelfSignedCertGenerator {
+-
+- private static final Provider PROVIDER = new BouncyCastleProvider();
+-
+- static String[] generate(String fqdn, KeyPair keypair, SecureRandom random) throws Exception {
+- PrivateKey key = keypair.getPrivate();
+-
+- // Prepare the information required for generating an X.509 certificate.
+- X500Name owner = new X500Name("CN=" + fqdn);
+- X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(
+- owner, new BigInteger(64, random), NOT_BEFORE, NOT_AFTER, owner, keypair.getPublic());
+-
+- ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSAEncryption").build(key);
+- X509CertificateHolder certHolder = builder.build(signer);
+- X509Certificate cert = new JcaX509CertificateConverter().setProvider(PROVIDER).getCertificate(certHolder);
+- cert.verify(keypair.getPublic());
+-
+- return newSelfSignedCertificate(fqdn, key, cert);
+- }
+-
+- private BouncyCastleSelfSignedCertGenerator() { }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/util/SelfSignedCertificate.java b/handler/src/main/java/io/netty/handler/ssl/util/SelfSignedCertificate.java
+index 54257a7..074764f 100644
+--- a/handler/src/main/java/io/netty/handler/ssl/util/SelfSignedCertificate.java
++++ b/handler/src/main/java/io/netty/handler/ssl/util/SelfSignedCertificate.java
+@@ -48,8 +48,7 @@ import java.util.Date;
+ * {@link java.io.File#createTempFile(String, String)}, and they are deleted when the JVM exits using
+ * {@link java.io.File#deleteOnExit()}.
+ *
+- * At first, this method tries to use OpenJDK's X.509 implementation (the {@code sun.security.x509} package).
+- * If it fails, it tries to use Bouncy Castle as a fallback.
++ * This method tries to use OpenJDK's X.509 implementation (the {@code sun.security.x509} package).
+ *
+ */
+ public final class SelfSignedCertificate {
+@@ -107,15 +106,9 @@ public final class SelfSignedCertificate {
+ paths = OpenJdkSelfSignedCertGenerator.generate(fqdn, keypair, random);
+ } catch (Throwable t) {
+ logger.debug("Failed to generate a self-signed X.509 certificate using sun.security.x509:", t);
+- try {
+- // Try Bouncy Castle if the current JVM didn't have sun.security.x509.
+- paths = BouncyCastleSelfSignedCertGenerator.generate(fqdn, keypair, random);
+- } catch (Throwable t2) {
+- logger.debug("Failed to generate a self-signed X.509 certificate using Bouncy Castle:", t2);
+- throw new CertificateException(
+- "No provider succeeded to generate a self-signed certificate. " +
+- "See debug log for the root cause.");
+- }
++ throw new CertificateException(
++ "No provider succeeded to generate a self-signed certificate. " +
++ "See debug log for the root cause.");
+ }
+
+ certificate = new File(paths[0]);
+diff --git a/pom.xml b/pom.xml
+index b68f446..4a5cbd4 100644
+--- a/pom.xml
++++ b/pom.xml
+@@ -677,19 +677,6 @@
+ true
+
+
+-
+-
+- org.bouncycastle
+- bcpkix-jdk15on
+- 1.50
+- compile
+- true
+-
+-
+
+ com.jcraft
+ jzlib
diff --git a/SOURCES/transport-native-epoll-configure-fix.patch b/SOURCES/transport-native-epoll-configure-fix.patch
new file mode 100644
index 0000000..08e8489
--- /dev/null
+++ b/SOURCES/transport-native-epoll-configure-fix.patch
@@ -0,0 +1,14 @@
+diff --git a/netty-netty-4.0.27.Final/transport-native-epoll/pom.xml b/netty-netty-4.0.27.Final/transport-native-epoll/pom.xml
+index c9c7b25..b489b3f 100644
+--- a/netty-netty-4.0.27.Final/transport-native-epoll/pom.xml
++++ b/netty-netty-4.0.27.Final/transport-native-epoll/pom.xml
+@@ -73,9 +73,6 @@
+ .
+ true
+ true
+-
+- ${jni.compiler.args}
+-
+
+
+ generate
diff --git a/SPECS/netty.spec b/SPECS/netty.spec
new file mode 100644
index 0000000..7bc8571
--- /dev/null
+++ b/SPECS/netty.spec
@@ -0,0 +1,303 @@
+%{?scl:%scl_package netty}
+%{!?scl:%global pkg_name %{name}}
+%{?java_common_find_provides_and_requires}
+
+# Disable generation of debuginfo package
+%global debug_package %{nil}
+%global namedreltag .Final
+%global namedversion %{version}%{?namedreltag}
+
+Name: %{?scl_prefix}netty
+Version: 4.0.28
+Release: 2.3%{?dist}
+Summary: An asynchronous event-driven network application framework and tools for Java
+License: ASL 2.0
+URL: https://netty.io/
+Source0: https://github.com/netty/netty/archive/netty-%{namedversion}.tar.gz
+Patch0: npn_alpn_ssl_fixes.patch
+Patch1: transport-native-epoll-configure-fix.patch
+Patch2: netty-old-jzlib.patch
+Patch3: remove-bc-dependency.patch
+
+BuildRequires: %{?scl_prefix}maven-local
+BuildRequires: %{?scl_prefix_maven}mvn(ant-contrib:ant-contrib)
+BuildRequires: %{?scl_prefix}mvn(com.jcraft:jzlib)
+BuildRequires: %{?scl_prefix}mvn(commons-logging:commons-logging)
+BuildRequires: %{?scl_prefix}mvn(junit:junit)
+BuildRequires: %{?scl_prefix}mvn(log4j:log4j)
+BuildRequires: %{?scl_prefix_maven}mvn(org.apache.felix:maven-bundle-plugin)
+BuildRequires: %{?scl_prefix_maven}mvn(org.apache.maven.plugins:maven-antrun-plugin)
+BuildRequires: %{?scl_prefix_maven}mvn(org.apache.maven.plugins:maven-clean-plugin)
+BuildRequires: %{?scl_prefix_maven}mvn(org.apache.maven.plugins:maven-dependency-plugin)
+BuildRequires: %{?scl_prefix_maven}mvn(org.apache.maven.plugins:maven-deploy-plugin)
+BuildRequires: %{?scl_prefix_maven}mvn(org.apache.maven.plugins:maven-jxr-plugin)
+BuildRequires: %{?scl_prefix_maven}mvn(org.apache.maven.plugins:maven-release-plugin)
+BuildRequires: %{?scl_prefix_maven}mvn(org.apache.maven.plugins:maven-source-plugin)
+BuildRequires: %{?scl_prefix_maven}mvn(org.apache.maven.scm:maven-scm-api)
+BuildRequires: %{?scl_prefix_maven}mvn(org.apache.maven.scm:maven-scm-provider-gitexe)
+BuildRequires: %{?scl_prefix_maven}mvn(org.codehaus.mojo:build-helper-maven-plugin)
+BuildRequires: %{?scl_prefix}mvn(org.easymock:easymock:3)
+BuildRequires: %{?scl_prefix}mvn(org.fusesource.hawtjni:maven-hawtjni-plugin)
+BuildRequires: %{?scl_prefix}mvn(org.javassist:javassist)
+BuildRequires: %{?scl_prefix}mvn(org.slf4j:slf4j-api)
+BuildRequires: %{?scl_prefix_maven}mvn(org.sonatype.oss:oss-parent:pom:)
+
+BuildArch: noarch
+
+%description
+Netty is a NIO client server framework which enables quick and easy
+development of network applications such as protocol servers and
+clients. It greatly simplifies and streamlines network programming
+such as TCP and UDP socket server.
+
+'Quick and easy' doesn't mean that a resulting application will suffer
+from a maintainability or a performance issue. Netty has been designed
+carefully with the experiences earned from the implementation of a lot
+of protocols such as FTP, SMTP, HTTP, and various binary and
+text-based legacy protocols. As a result, Netty has succeeded to find
+a way to achieve ease of development, performance, stability, and
+flexibility without a compromise.
+
+%package javadoc
+Summary: API documentation for %{pkg_name}
+
+%description javadoc
+%{summary}.
+
+%prep
+%{?scl:scl enable %{scl_maven} %{scl} - << "EOF"}
+%setup -q -n netty-netty-%{namedversion}
+
+%patch0 -p1
+%patch1 -p2
+%patch2 -p0
+%patch3 -p1
+
+%pom_disable_module "transport-native-epoll"
+%pom_remove_dep ":netty-transport-native-epoll" all
+# Missing Mavenized rxtx
+%pom_disable_module "transport-rxtx"
+%pom_remove_dep ":netty-transport-rxtx" all
+# Missing com.barchart.udt:barchart-udt-bundle:jar:2.3.0
+%pom_disable_module "transport-udt"
+%pom_remove_dep ":netty-transport-udt" all
+%pom_remove_dep ":netty-build" all
+# Not needed
+%pom_xpath_remove "pom:build/pom:extensions"
+%pom_disable_module "example"
+%pom_remove_dep ":netty-example" all
+%pom_disable_module "testsuite"
+%pom_disable_module "testsuite-osgi"
+%pom_disable_module "tarball"
+%pom_disable_module "microbench"
+%pom_remove_plugin :maven-checkstyle-plugin
+%pom_remove_plugin :animal-sniffer-maven-plugin
+%pom_remove_plugin :maven-enforcer-plugin
+%pom_remove_plugin :maven-antrun-plugin
+%pom_remove_plugin :maven-dependency-plugin
+# Optional things we don't ship
+%pom_remove_dep ":netty-tcnative"
+%pom_remove_dep ":netty-tcnative" handler
+%pom_remove_dep "org.eclipse.jetty.npn:npn-api"
+%pom_remove_dep "org.eclipse.jetty.npn:npn-api" handler
+%pom_remove_dep "org.mortbay.jetty.npn:npn-boot"
+%pom_remove_dep "org.mortbay.jetty.npn:npn-boot" handler
+%pom_remove_dep "org.eclipse.jetty.alpn:alpn-api"
+%pom_remove_dep "org.eclipse.jetty.alpn:alpn-api" handler
+%pom_remove_dep "org.mortbay.jetty.alpn:alpn-boot"
+%pom_remove_dep "org.mortbay.jetty.alpn:alpn-boot" handler
+%pom_remove_dep "com.google.protobuf:protobuf-java"
+%pom_remove_dep "com.google.protobuf:protobuf-java" codec
+%pom_remove_dep "com.google.protobuf:protobuf-java" all
+rm codec/src/main/java/io/netty/handler/codec/protobuf/*
+%pom_remove_dep "org.jboss.marshalling:jboss-marshalling"
+%pom_remove_dep "org.jboss.marshalling:jboss-marshalling" codec
+%pom_remove_dep "org.jboss.marshalling:jboss-marshalling" all
+rm codec/src/main/java/io/netty/handler/codec/marshalling/*
+
+# Remove runtime dep on optional javassist
+%pom_xpath_set "pom:dependency[pom:artifactId[text()='javassist']]/pom:scope" "provided" common
+
+sed -i 's|taskdef|taskdef classpathref="maven.plugin.classpath"|' all/pom.xml
+
+%pom_xpath_inject "pom:plugins/pom:plugin[pom:artifactId = 'maven-antrun-plugin']" 'ant-contribant-contrib1.0b3' all/pom.xml
+%pom_xpath_inject "pom:execution[pom:id = 'build-native-lib']/pom:configuration" 'true' transport-native-epoll/pom.xml
+
+# Tell xmvn to install attached artifact, which it does not
+# do by default. In this case install all attached artifacts with
+# the linux classifier.
+%mvn_package ":::linux*:"
+%{?scl:EOF}
+
+
+%build
+%{?scl:scl enable %{scl_maven} %{scl} - << "EOF"}
+export CFLAGS="$RPM_OPT_FLAGS" LDFLAGS="$RPM_LD_FLAGS"
+%mvn_build -f
+%{?scl:EOF}
+
+
+%install
+%{?scl:scl enable %{scl_maven} %{scl} - << "EOF"}
+%mvn_install
+%{?scl:EOF}
+
+
+%files -f .mfiles
+%doc LICENSE.txt NOTICE.txt
+%dir %{_javadir}/netty
+%dir %{_mavenpomdir}/netty
+
+%files javadoc -f .mfiles-javadoc
+%doc LICENSE.txt NOTICE.txt
+
+%changelog
+* Tue Feb 16 2016 Michal Srb - 4.0.28-2.3
+- Move to rh-java-common SCL
+
+* Mon Jul 13 2015 Mat Booth - 4.0.28-2.2
+- Fix unowned directories
+
+* Fri Jul 03 2015 Mat Booth - 4.0.28-2.1
+- Import latest from Fedora
+
+* Wed Jun 17 2015 Fedora Release Engineering - 4.0.28-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild
+
+* Wed May 20 2015 Severin Gehwolf - 4.0.28-1
+- Update to upstream 4.0.28 release.
+- Fixes CVE-2015-2156 (HttpOnly cookie bypass).
+- Resolves RHBZ#1111502
+
+* Wed May 20 2015 Severin Gehwolf - 4.0.27-1
+- Update to upstream 4.0.27 release.
+
+* Wed Apr 01 2015 Severin Gehwolf - 4.0.19-3
+- Drop mvn(org.easymock:easymockclassextension) BR.
+ Resolves: RHBZ#1207991
+
+* Sun Aug 17 2014 Fedora Release Engineering - 4.0.19-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild
+
+* Mon Jun 9 2014 Mikolaj Izdebski - 4.0.19-1
+- Update to upstream version 4.0.19
+- Convert to arch-specific package
+
+* Sat Jun 07 2014 Fedora Release Engineering - 4.0.14-5
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
+
+* Tue Mar 04 2014 Stanislav Ochotnicky - 4.0.14-4
+- Use Requires: java-headless rebuild (#1067528)
+
+* Mon Jan 13 2014 Marek Goldmann - 4.0.14-3
+- Enable netty-all.jar artifact
+
+* Mon Jan 13 2014 Marek Goldmann - 4.0.14-2
+- Bump the release, so Obsoletes work properly
+
+* Mon Dec 30 2013 Marek Goldmann - 4.0.14-1
+- Upstream release 4.0.14.Final
+
+* Sat Aug 03 2013 Fedora Release Engineering - 3.6.6-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild
+
+* Thu May 16 2013 Mikolaj Izdebski - 3.6.6-1
+- Update to upstream version 3.6.6
+
+* Wed Apr 10 2013 Mikolaj Izdebski - 3.6.5-1
+- Update to upstream version 3.6.5
+
+* Mon Apr 8 2013 Mikolaj Izdebski - 3.6.4-1
+- Update to upstream version 3.6.4
+
+* Wed Feb 27 2013 Mikolaj Izdebski - 3.6.3-3
+- Set scope of optional compile dependencies to 'provided'
+
+* Wed Feb 27 2013 Mikolaj Izdebski - 3.6.3-2
+- Drop dependency on OSGi
+- Resolves: rhbz#916139
+
+* Mon Feb 25 2013 Mikolaj Izdebski - 3.6.3-1
+- Update to upstream version 3.6.3
+
+* Thu Feb 14 2013 Fedora Release Engineering - 3.6.2-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild
+
+* Wed Feb 06 2013 Java SIG - 3.6.2-2
+- Update for https://fedoraproject.org/wiki/Fedora_19_Maven_Rebuild
+- Replace maven BuildRequires with maven-local
+
+* Wed Jan 16 2013 Mikolaj Izdebski - 3.6.2-1
+- Update to upstream version 3.6.2
+
+* Tue Jan 15 2013 Mikolaj Izdebski - 3.6.1-1
+- Update to upstream version 3.6.1
+
+* Thu Dec 13 2012 Mikolaj Izdebski - 3.5.11-2
+- Use system jzlib instead of bundled jzlib
+- Resolves: rhbz#878391
+
+* Mon Dec 3 2012 Mikolaj Izdebski - 3.5.11-1
+- Update to upstream version 3.5.11
+
+* Mon Nov 12 2012 Mikolaj Izdebski - 3.5.10-1
+- Update to upstream version 3.5.10
+
+* Thu Oct 25 2012 Mikolaj Izdebski - 3.5.9-1
+- Update to upstream version 3.5.9
+
+* Fri Oct 5 2012 Mikolaj Izdebski - 3.5.8-1
+- Update to upstream version 3.5.8
+
+* Fri Sep 7 2012 Mikolaj Izdebski - 3.5.7-1
+- Update to upstream version 3.5.7
+
+* Mon Sep 3 2012 Mikolaj Izdebski - 3.5.6-1
+- Update to upstream version 3.5.6
+
+* Thu Aug 23 2012 Mikolaj Izdebski - 3.5.5-1
+- Update to upstream version 3.5.5
+
+* Wed Aug 15 2012 Tomas Rohovsky - 3.5.4-1
+- Update to upstream version 3.5.4
+
+* Tue Jul 24 2012 Mikolaj Izdebski - 3.5.3-1
+- Update to upstream version 3.5.3
+
+* Fri Jul 20 2012 Fedora Release Engineering - 3.5.2-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild
+
+* Mon Jul 16 2012 Mikolaj Izdebski - 3.5.2-2
+- Add additional depmap for org.jboss.netty:netty
+- Fixes #840301
+
+* Thu Jul 12 2012 Mikolaj Izdebski - 3.5.2-1
+- Update to upstream version 3.5.2
+- Convert patches to POM macros
+- Enable jboss-logging
+
+* Fri May 18 2012 Stanislav Ochotnicky - 3.2.4-4
+- Add enforcer-plugin to BR
+
+* Wed Apr 18 2012 Stanislav Ochotnicky - 3.2.4-3
+- Remove eclipse plugin from BuildRequires
+
+* Fri Jan 13 2012 Fedora Release Engineering - 3.2.4-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild
+
+* Mon Dec 5 2011 Stanislav Ochotnicky - 3.2.4-1
+- Update to latest upstream version
+
+* Mon Jul 4 2011 Alexander Kurtakov 3.2.3-4
+- Fix FTBFS.
+- Adapt to current guidelines.
+
+* Tue Feb 08 2011 Fedora Release Engineering - 3.2.3-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild
+
+* Mon Jan 17 2011 Stanislav Ochotnicky - 3.2.3-2
+- Use maven 3 to build
+- Drop ant-contrib depmap (no longer needed)
+
+* Thu Jan 13 2011 Stanislav Ochotnicky - 3.2.3-1
+- Initial version of the package