View Javadoc
1   /*
2    * Copyright 2021 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    *   https://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.codec.quic;
17  
18  import io.netty.util.internal.EmptyArrays;
19  import io.netty.util.internal.logging.InternalLogger;
20  import io.netty.util.internal.logging.InternalLoggerFactory;
21  import org.jetbrains.annotations.Nullable;
22  
23  import java.io.ByteArrayOutputStream;
24  import java.io.DataOutputStream;
25  import java.io.IOException;
26  import java.util.Arrays;
27  import java.util.concurrent.TimeUnit;
28  
29  final class BoringSSLSessionCallback {
30      private static final InternalLogger logger = InternalLoggerFactory.getInstance(BoringSSLSessionCallback.class);
31      private final QuicClientSessionCache sessionCache;
32      private final QuicheQuicSslEngineMap engineMap;
33  
34      BoringSSLSessionCallback(QuicheQuicSslEngineMap engineMap, @Nullable QuicClientSessionCache sessionCache) {
35          this.engineMap = engineMap;
36          this.sessionCache = sessionCache;
37      }
38  
39      @SuppressWarnings("unused")
40      void newSession(long ssl, long creationTime, long timeout, byte[] session, boolean isSingleUse,
41                      byte @Nullable [] peerParams) {
42          if (sessionCache == null) {
43              return;
44          }
45  
46          QuicheQuicSslEngine engine = engineMap.get(ssl);
47          if (engine == null) {
48              logger.warn("engine is null ssl: {}", ssl);
49              return;
50          }
51  
52          if (peerParams == null) {
53              peerParams = EmptyArrays.EMPTY_BYTES;
54          }
55          if (logger.isDebugEnabled()) {
56              logger.debug("ssl: {}, session: {}, peerParams: {}", ssl, Arrays.toString(session),
57                      Arrays.toString(peerParams));
58          }
59          byte[] quicSession = toQuicheQuicSession(session, peerParams);
60          if (quicSession != null) {
61              logger.debug("save session host={}, port={}",
62                      engine.getSession().getPeerHost(), engine.getSession().getPeerPort());
63              sessionCache.saveSession(engine.getSession().getPeerHost(), engine.getSession().getPeerPort(),
64                      TimeUnit.SECONDS.toMillis(creationTime), TimeUnit.SECONDS.toMillis(timeout),
65                      quicSession, isSingleUse);
66          }
67      }
68  
69      // Mimic the encoding of quiche: https://github.com/cloudflare/quiche/blob/0.10.0/src/lib.rs#L1668
70      private static byte @Nullable [] toQuicheQuicSession(byte @Nullable [] sslSession, byte @Nullable [] peerParams) {
71          if (sslSession != null && peerParams != null) {
72              try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
73                   DataOutputStream dos = new DataOutputStream(bos)) {
74                  dos.writeLong(sslSession.length);
75                  dos.write(sslSession);
76                  dos.writeLong(peerParams.length);
77                  dos.write(peerParams);
78                  return bos.toByteArray();
79              } catch (IOException e) {
80                  return null;
81              }
82          }
83          return null;
84      }
85  }