View Javadoc
1   /*
2    * Copyright 2014 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.handler.ssl;
17  
18  import static io.netty.util.internal.ObjectUtil.checkNotNull;
19  import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
20  import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
21  import io.netty.util.internal.PlatformDependent;
22  
23  import java.util.HashSet;
24  import java.util.List;
25  
26  import javax.net.ssl.SSLEngine;
27  import javax.net.ssl.SSLException;
28  
29  import org.eclipse.jetty.alpn.ALPN;
30  import org.eclipse.jetty.alpn.ALPN.ClientProvider;
31  import org.eclipse.jetty.alpn.ALPN.ServerProvider;
32  
33  final class JdkAlpnSslEngine extends JdkSslEngine {
34      private static boolean available;
35  
36      static boolean isAvailable() {
37          updateAvailability();
38          return available;
39      }
40  
41      private static void updateAvailability() {
42          if (available) {
43              return;
44          }
45  
46          try {
47              // Try to get the bootstrap class loader.
48              ClassLoader bootloader = ClassLoader.getSystemClassLoader().getParent();
49              if (bootloader == null) {
50                  // If failed, use the system class loader,
51                  // although it's not perfect to tell if APLN extension has been loaded.
52                  bootloader = ClassLoader.getSystemClassLoader();
53              }
54              Class.forName("sun.security.ssl.ALPNExtension", true, bootloader);
55              available = true;
56          } catch (Exception ignore) {
57              // alpn-boot was not loaded.
58          }
59      }
60  
61      JdkAlpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator, boolean server) {
62          super(engine);
63          checkNotNull(applicationNegotiator, "applicationNegotiator");
64  
65          if (server) {
66              final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory()
67                      .newSelector(this, new HashSet<String>(applicationNegotiator.protocols())), "protocolSelector");
68              ALPN.put(engine, new ServerProvider() {
69                  @Override
70                  public String select(List<String> protocols) {
71                      try {
72                          return protocolSelector.select(protocols);
73                      } catch (Throwable t) {
74                          PlatformDependent.throwException(t);
75                          return null;
76                      }
77                  }
78  
79                  @Override
80                  public void unsupported() {
81                      protocolSelector.unsupported();
82                  }
83              });
84          } else {
85              final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator
86                      .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()),
87                      "protocolListener");
88              ALPN.put(engine, new ClientProvider() {
89                  @Override
90                  public List<String> protocols() {
91                      return applicationNegotiator.protocols();
92                  }
93  
94                  @Override
95                  public void selected(String protocol) {
96                      try {
97                          protocolListener.selected(protocol);
98                      } catch (Throwable t) {
99                          PlatformDependent.throwException(t);
100                     }
101                 }
102 
103                 @Override
104                 public void unsupported() {
105                     protocolListener.unsupported();
106                 }
107             });
108         }
109     }
110 
111     @Override
112     public void closeInbound() throws SSLException {
113         ALPN.remove(getWrappedEngine());
114         super.closeInbound();
115     }
116 
117     @Override
118     public void closeOutbound() {
119         ALPN.remove(getWrappedEngine());
120         super.closeOutbound();
121     }
122 }