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