View Javadoc
1   /*
2    * Copyright 2020 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 org.jetbrains.annotations.Nullable;
19  
20  final class QuicheConfig {
21      private final boolean isDatagramSupported;
22      private long config = -1;
23  
24      QuicheConfig(int version,
25                   @Nullable Boolean grease,
26                   @Nullable Long maxIdleTimeout,
27                   @Nullable Long maxSendUdpPayloadSize,
28                   @Nullable Long maxRecvUdpPayloadSize,
29                   @Nullable Long initialMaxData,
30                   @Nullable Long initialMaxStreamDataBidiLocal,
31                   @Nullable Long initialMaxStreamDataBidiRemote,
32                   @Nullable Long initialMaxStreamDataUni,
33                   @Nullable Long initialMaxStreamsBidi,
34                   @Nullable Long initialMaxStreamsUni,
35                   @Nullable Long ackDelayExponent,
36                   @Nullable Long maxAckDelay,
37                   @Nullable Boolean disableActiveMigration,
38                   @Nullable Boolean enableHystart,
39                   @Nullable QuicCongestionControlAlgorithm congestionControlAlgorithm,
40                   @Nullable Integer initialCongestionWindowPackets,
41                   @Nullable Integer recvQueueLen,
42                   @Nullable Integer sendQueueLen,
43                   @Nullable Long activeConnectionIdLimit,
44                   byte @Nullable [] statelessResetToken) {
45          long config = Quiche.quiche_config_new(version);
46          try {
47              if (grease != null) {
48                  Quiche.quiche_config_grease(config, grease);
49              }
50              if (maxIdleTimeout != null) {
51                  Quiche.quiche_config_set_max_idle_timeout(config, maxIdleTimeout);
52              }
53              if (maxSendUdpPayloadSize != null) {
54                  Quiche.quiche_config_set_max_send_udp_payload_size(config, maxSendUdpPayloadSize);
55              }
56              if (maxRecvUdpPayloadSize != null) {
57                  Quiche.quiche_config_set_max_recv_udp_payload_size(config, maxRecvUdpPayloadSize);
58              }
59              if (initialMaxData != null) {
60                  Quiche.quiche_config_set_initial_max_data(config, initialMaxData);
61              }
62              if (initialMaxStreamDataBidiLocal != null) {
63                  Quiche.quiche_config_set_initial_max_stream_data_bidi_local(config, initialMaxStreamDataBidiLocal);
64              }
65              if (initialMaxStreamDataBidiRemote != null) {
66                  Quiche.quiche_config_set_initial_max_stream_data_bidi_remote(config, initialMaxStreamDataBidiRemote);
67              }
68              if (initialMaxStreamDataUni != null) {
69                  Quiche.quiche_config_set_initial_max_stream_data_uni(config, initialMaxStreamDataUni);
70              }
71              if (initialMaxStreamsBidi != null) {
72                  Quiche.quiche_config_set_initial_max_streams_bidi(config, initialMaxStreamsBidi);
73              }
74              if (initialMaxStreamsUni != null) {
75                  Quiche.quiche_config_set_initial_max_streams_uni(config, initialMaxStreamsUni);
76              }
77              if (ackDelayExponent != null) {
78                  Quiche.quiche_config_set_ack_delay_exponent(config, ackDelayExponent);
79              }
80              if (maxAckDelay != null) {
81                  Quiche.quiche_config_set_max_ack_delay(config, maxAckDelay);
82              }
83              if (disableActiveMigration != null) {
84                  Quiche.quiche_config_set_disable_active_migration(config, disableActiveMigration);
85              }
86              if (enableHystart != null) {
87                  Quiche.quiche_config_enable_hystart(config, enableHystart);
88              }
89              if (congestionControlAlgorithm != null) {
90                  switch (congestionControlAlgorithm) {
91                      case RENO:
92                          Quiche.quiche_config_set_cc_algorithm(config, Quiche.QUICHE_CC_RENO);
93                          break;
94                      case CUBIC:
95                          Quiche.quiche_config_set_cc_algorithm(config, Quiche.QUICHE_CC_CUBIC);
96                          break;
97                      case BBR:
98                          Quiche.quiche_config_set_cc_algorithm(config, Quiche.QUICHE_CC_BBR);
99                          break;
100                     default:
101                         throw new IllegalArgumentException(
102                                 "Unknown congestionControlAlgorithm: " + congestionControlAlgorithm);
103                 }
104             }
105             if (initialCongestionWindowPackets != null) {
106                 Quiche.quiche_config_set_initial_congestion_window_packets(config, initialCongestionWindowPackets);
107             }
108             if (recvQueueLen != null && sendQueueLen != null) {
109                 isDatagramSupported = true;
110                 Quiche.quiche_config_enable_dgram(config, true, recvQueueLen, sendQueueLen);
111             } else {
112                 isDatagramSupported = false;
113             }
114             if (activeConnectionIdLimit != null) {
115                 Quiche.quiche_config_set_active_connection_id_limit(config, activeConnectionIdLimit);
116             }
117             if (statelessResetToken != null) {
118                 Quiche.quiche_config_set_stateless_reset_token(config, statelessResetToken);
119             }
120             this.config = config;
121         } catch (Throwable cause) {
122             Quiche.quiche_config_free(config);
123             throw cause;
124         }
125     }
126 
127     boolean isDatagramSupported() {
128         return isDatagramSupported;
129     }
130 
131     long nativeAddress() {
132         return config;
133     }
134 
135     // Let's override finalize() as we want to ensure we never leak memory even if the user will miss to close
136     // Channel that uses this handler that used the config and just let it get GC'ed.
137     @Override
138     protected void finalize() throws Throwable {
139         try {
140             free();
141         } finally {
142             super.finalize();
143         }
144     }
145 
146     void free() {
147         if (config != -1) {
148             try {
149                 Quiche.quiche_config_free(config);
150             } finally {
151                 config = -1;
152             }
153         }
154     }
155 }