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 io.netty.buffer.ByteBuf;
19  import io.netty.buffer.Unpooled;
20  import io.netty.util.collection.IntObjectHashMap;
21  import io.netty.util.internal.ClassInitializerUtil;
22  import io.netty.util.internal.NativeLibraryLoader;
23  import io.netty.util.internal.PlatformDependent;
24  import io.netty.util.internal.logging.InternalLogger;
25  import io.netty.util.internal.logging.InternalLoggerFactory;
26  import org.jetbrains.annotations.Nullable;
27  
28  import javax.net.ssl.SSLException;
29  import javax.net.ssl.SSLHandshakeException;
30  import java.nio.ByteBuffer;
31  import java.nio.ByteOrder;
32  
33  import static io.netty.handler.codec.quic.QuicheError.STREAM_RESET;
34  
35  final class Quiche {
36      private static final InternalLogger logger = InternalLoggerFactory.getInstance(Quiche.class);
37      private static final boolean TRACE_LOGGING_ENABLED = logger.isTraceEnabled();
38      private static final IntObjectHashMap<QuicTransportErrorHolder> ERROR_MAPPINGS = new IntObjectHashMap<>();
39  
40      static {
41          // Preload all classes that will be used in the OnLoad(...) function of JNI to eliminate the possibility of a
42          // class-loader deadlock. This is a workaround for https://github.com/netty/netty/issues/11209.
43  
44          // This needs to match all the classes that are loaded via NETTY_JNI_UTIL_LOAD_CLASS or looked up via
45          // NETTY_JNI_UTIL_FIND_CLASS.
46          ClassInitializerUtil.tryLoadClasses(Quiche.class,
47                  // netty_quic_boringssl
48                  byte[].class, String.class, BoringSSLCertificateCallback.class,
49                  BoringSSLCertificateVerifyCallback.class, BoringSSLHandshakeCompleteCallback.class,
50  
51                  //netty_quic_quiche
52                  QuicheLogger.class
53          );
54  
55          try {
56              // First, try calling a side-effect free JNI method to see if the library was already
57              // loaded by the application.
58              quiche_version();
59          } catch (UnsatisfiedLinkError ignore) {
60              // The library was not previously loaded, load it now.
61              loadNativeLibrary();
62          }
63  
64          // Let's enable debug logging for quiche if the TRACE level is enabled in our logger.
65          if (TRACE_LOGGING_ENABLED) {
66              quiche_enable_debug_logging(new QuicheLogger(logger));
67          }
68      }
69  
70      private static void loadNativeLibrary() {
71          // This needs to be kept in sync with what is defined in netty_quic_quiche.c
72          // and pom.xml as jniLibPrefix.
73          String libName = "netty_quiche42";
74          ClassLoader cl = PlatformDependent.getClassLoader(Quiche.class);
75  
76          if (!PlatformDependent.isAndroid()) {
77              libName += '_' + PlatformDependent.normalizedOs()
78                      + '_' + PlatformDependent.normalizedArch();
79          }
80  
81          try {
82              NativeLibraryLoader.load(libName, cl);
83          } catch (UnsatisfiedLinkError e) {
84              logger.debug("Failed to load {}", libName, e);
85              throw e;
86          }
87      }
88  
89      static final short AF_INET = (short) QuicheNativeStaticallyReferencedJniMethods.afInet();
90      static final short AF_INET6 = (short) QuicheNativeStaticallyReferencedJniMethods.afInet6();
91      static final int SIZEOF_SOCKADDR_STORAGE = QuicheNativeStaticallyReferencedJniMethods.sizeofSockaddrStorage();
92      static final int SIZEOF_SOCKADDR_IN = QuicheNativeStaticallyReferencedJniMethods.sizeofSockaddrIn();
93      static final int SIZEOF_SOCKADDR_IN6 = QuicheNativeStaticallyReferencedJniMethods.sizeofSockaddrIn6();
94      static final int SOCKADDR_IN_OFFSETOF_SIN_FAMILY =
95              QuicheNativeStaticallyReferencedJniMethods.sockaddrInOffsetofSinFamily();
96      static final int SOCKADDR_IN_OFFSETOF_SIN_PORT =
97              QuicheNativeStaticallyReferencedJniMethods.sockaddrInOffsetofSinPort();
98      static final int SOCKADDR_IN_OFFSETOF_SIN_ADDR =
99              QuicheNativeStaticallyReferencedJniMethods.sockaddrInOffsetofSinAddr();
100     static final int IN_ADDRESS_OFFSETOF_S_ADDR = QuicheNativeStaticallyReferencedJniMethods.inAddressOffsetofSAddr();
101     static final int SOCKADDR_IN6_OFFSETOF_SIN6_FAMILY =
102             QuicheNativeStaticallyReferencedJniMethods.sockaddrIn6OffsetofSin6Family();
103     static final int SOCKADDR_IN6_OFFSETOF_SIN6_PORT =
104             QuicheNativeStaticallyReferencedJniMethods.sockaddrIn6OffsetofSin6Port();
105     static final int SOCKADDR_IN6_OFFSETOF_SIN6_FLOWINFO =
106             QuicheNativeStaticallyReferencedJniMethods.sockaddrIn6OffsetofSin6Flowinfo();
107     static final int SOCKADDR_IN6_OFFSETOF_SIN6_ADDR =
108             QuicheNativeStaticallyReferencedJniMethods.sockaddrIn6OffsetofSin6Addr();
109     static final int SOCKADDR_IN6_OFFSETOF_SIN6_SCOPE_ID =
110             QuicheNativeStaticallyReferencedJniMethods.sockaddrIn6OffsetofSin6ScopeId();
111     static final int IN6_ADDRESS_OFFSETOF_S6_ADDR =
112             QuicheNativeStaticallyReferencedJniMethods.in6AddressOffsetofS6Addr();
113     static final int SIZEOF_SOCKLEN_T = QuicheNativeStaticallyReferencedJniMethods.sizeofSocklenT();
114     static final int SIZEOF_SIZE_T = QuicheNativeStaticallyReferencedJniMethods.sizeofSizeT();
115 
116     static final int SIZEOF_TIMESPEC = QuicheNativeStaticallyReferencedJniMethods.sizeofTimespec();
117 
118     static final int SIZEOF_TIME_T = QuicheNativeStaticallyReferencedJniMethods.sizeofTimeT();
119     static final int SIZEOF_LONG = QuicheNativeStaticallyReferencedJniMethods.sizeofLong();
120 
121     static final int TIMESPEC_OFFSETOF_TV_SEC =
122             QuicheNativeStaticallyReferencedJniMethods.timespecOffsetofTvSec();
123 
124     static final int TIMESPEC_OFFSETOF_TV_NSEC =
125             QuicheNativeStaticallyReferencedJniMethods.timespecOffsetofTvNsec();
126 
127     static final int QUICHE_RECV_INFO_OFFSETOF_FROM =
128             QuicheNativeStaticallyReferencedJniMethods.quicheRecvInfoOffsetofFrom();
129     static final int QUICHE_RECV_INFO_OFFSETOF_FROM_LEN =
130             QuicheNativeStaticallyReferencedJniMethods.quicheRecvInfoOffsetofFromLen();
131 
132     static final int QUICHE_RECV_INFO_OFFSETOF_TO =
133             QuicheNativeStaticallyReferencedJniMethods.quicheRecvInfoOffsetofTo();
134     static final int QUICHE_RECV_INFO_OFFSETOF_TO_LEN =
135             QuicheNativeStaticallyReferencedJniMethods.quicheRecvInfoOffsetofToLen();
136 
137     static final int SIZEOF_QUICHE_RECV_INFO = QuicheNativeStaticallyReferencedJniMethods.sizeofQuicheRecvInfo();
138     static final int QUICHE_SEND_INFO_OFFSETOF_TO =
139             QuicheNativeStaticallyReferencedJniMethods.quicheSendInfoOffsetofTo();
140     static final int QUICHE_SEND_INFO_OFFSETOF_TO_LEN =
141             QuicheNativeStaticallyReferencedJniMethods.quicheSendInfoOffsetofToLen();
142 
143     static final int QUICHE_SEND_INFO_OFFSETOF_FROM =
144             QuicheNativeStaticallyReferencedJniMethods.quicheSendInfoOffsetofFrom();
145     static final int QUICHE_SEND_INFO_OFFSETOF_FROM_LEN =
146             QuicheNativeStaticallyReferencedJniMethods.quicheSendInfoOffsetofFromLen();
147 
148     static final int QUICHE_SEND_INFO_OFFSETOF_AT =
149             QuicheNativeStaticallyReferencedJniMethods.quicheSendInfoOffsetofAt();
150     static final int SIZEOF_QUICHE_SEND_INFO = QuicheNativeStaticallyReferencedJniMethods.sizeofQuicheSendInfo();
151 
152     static final int QUICHE_PROTOCOL_VERSION = QuicheNativeStaticallyReferencedJniMethods.quiche_protocol_version();
153     static final int QUICHE_MAX_CONN_ID_LEN = QuicheNativeStaticallyReferencedJniMethods.quiche_max_conn_id_len();
154 
155     /**
156      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L266">QUICHE_SHUTDOWN_READ</a>.
157      */
158     static final int QUICHE_SHUTDOWN_READ = QuicheNativeStaticallyReferencedJniMethods.quiche_shutdown_read();
159 
160     /**
161      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L267">QUICHE_SHUTDOWN_WRITE</a>.
162      */
163     static final int QUICHE_SHUTDOWN_WRITE = QuicheNativeStaticallyReferencedJniMethods.quiche_shutdown_write();
164 
165     /**
166      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L59">QUICHE_ERR_DONE</a>.
167      */
168     static final int QUICHE_ERR_DONE = QuicheNativeStaticallyReferencedJniMethods.quiche_err_done();
169 
170     /**
171      * See
172      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L62">QUICHE_ERR_BUFFER_TOO_SHORT</a>.
173      */
174     static final int QUICHE_ERR_BUFFER_TOO_SHORT =
175             QuicheNativeStaticallyReferencedJniMethods.quiche_err_buffer_too_short();
176 
177     /**
178      * See
179      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L65">QUICHE_ERR_UNKNOWN_VERSION</a>.
180      */
181     static final int QUICHE_ERR_UNKNOWN_VERSION =
182             QuicheNativeStaticallyReferencedJniMethods.quiche_err_unknown_version();
183 
184     /**
185      * See
186      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L69">QUICHE_ERR_INVALID_FRAME</a>.
187      */
188     static final int QUICHE_ERR_INVALID_FRAME = QuicheNativeStaticallyReferencedJniMethods.quiche_err_invalid_frame();
189 
190     /**
191      * See
192      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L72">QUICHE_ERR_INVALID_PACKET</a>.
193      */
194     static final int QUICHE_ERR_INVALID_PACKET = QuicheNativeStaticallyReferencedJniMethods.quiche_err_invalid_packet();
195 
196     /**
197      * See
198      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L76">QUICHE_ERR_INVALID_STATE</a>.
199      */
200     static final int QUICHE_ERR_INVALID_STATE = QuicheNativeStaticallyReferencedJniMethods.quiche_err_invalid_state();
201 
202     /**
203      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L80">
204      *     QUICHE_ERR_INVALID_STREAM_STATE</a>.
205      */
206     static final int QUICHE_ERR_INVALID_STREAM_STATE =
207             QuicheNativeStaticallyReferencedJniMethods.quiche_err_invalid_stream_state();
208 
209     /**
210      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L83">
211      *     QUICHE_ERR_INVALID_TRANSPORT_PARAM</a>.
212      */
213     static final int QUICHE_ERR_INVALID_TRANSPORT_PARAM =
214             QuicheNativeStaticallyReferencedJniMethods.quiche_err_invalid_transport_param();
215 
216     /**
217      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L86">
218      *     QUICHE_ERR_CRYPTO_FAIL</a>.
219      */
220     static final int QUICHE_ERR_CRYPTO_FAIL = QuicheNativeStaticallyReferencedJniMethods.quiche_err_crypto_fail();
221 
222     /**
223      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L89">
224      *     QUICHE_ERR_TLS_FAIL</a>.
225      */
226     static final int QUICHE_ERR_TLS_FAIL = QuicheNativeStaticallyReferencedJniMethods.quiche_err_tls_fail();
227 
228     /**
229      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L92">
230      *     QUICHE_ERR_FLOW_CONTROL</a>.
231      */
232     static final int QUICHE_ERR_FLOW_CONTROL = QuicheNativeStaticallyReferencedJniMethods.quiche_err_flow_control();
233 
234     /**
235      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#95">
236      *     QUICHE_ERR_STREAM_LIMIT</a>.
237      */
238     static final int QUICHE_ERR_STREAM_LIMIT = QuicheNativeStaticallyReferencedJniMethods.quiche_err_stream_limit();
239 
240     /**
241      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#98">
242      *     QUICHE_ERR_FINAL_SIZE</a>.
243      */
244     static final int QUICHE_ERR_FINAL_SIZE = QuicheNativeStaticallyReferencedJniMethods.quiche_err_final_size();
245 
246     /**
247      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#101">
248      *     QUICHE_ERR_CONGESTION_CONTROL</a>.
249      */
250     static final int QUICHE_ERR_CONGESTION_CONTROL =
251             QuicheNativeStaticallyReferencedJniMethods.quiche_err_congestion_control();
252 
253     /**
254      * See <a href="https://github.com/cloudflare/quiche/blob/e179f2aa52d475e037fe47d7b8466b3afde12d76/
255      *        include/quiche.h#L101">QUICHE_ERR_STREAM_STOPPED</a>.
256      */
257     static final int QUICHE_ERR_STREAM_RESET =
258             QuicheNativeStaticallyReferencedJniMethods.quiche_err_stream_reset();
259 
260     /**
261      * See <a href="https://github.com/cloudflare/quiche/blob/0.7.0/include/quiche.h#L98">
262      *     QUICHE_ERR_STREAM_STOPPED</a>.
263      */
264     static final int QUICHE_ERR_STREAM_STOPPED =
265             QuicheNativeStaticallyReferencedJniMethods.quiche_err_stream_stopped();
266 
267     // Too many identifiers were provided.
268     static final int QUICHE_ERR_ID_LIMIT =
269             QuicheNativeStaticallyReferencedJniMethods.quiche_err_id_limit();
270 
271     // Not enough available identifiers.
272     static final int QUICHE_ERR_OUT_OF_IDENTIFIERS =
273             QuicheNativeStaticallyReferencedJniMethods.quiche_err_out_of_identifiers();
274 
275     // Error in key update.
276     static final int QUICHE_ERR_KEY_UPDATE =
277             QuicheNativeStaticallyReferencedJniMethods.quiche_err_key_update();
278 
279     static final int QUICHE_ERR_CRYPTO_BUFFER_EXCEEDED =
280             QuicheNativeStaticallyReferencedJniMethods.quiche_err_crypto_buffer_exceeded();
281 
282     static final int QUICHE_ERR_INVALID_DCID_INITIALIZATION =
283             QuicheNativeStaticallyReferencedJniMethods.quiche_err_invalid_dcid_initialization();
284 
285     /**
286      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L176">
287      *     QUICHE_CC_RENO</a>.
288      */
289     static final int QUICHE_CC_RENO = QuicheNativeStaticallyReferencedJniMethods.quiche_cc_reno();
290 
291     /**
292      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L177">
293      *     QUICHE_CC_CUBIC</a>.
294      */
295     static final int QUICHE_CC_CUBIC = QuicheNativeStaticallyReferencedJniMethods.quiche_cc_cubic();
296 
297     /**
298      * See <a href="https://github.com/cloudflare/quiche/blob/0.16.0/quiche/include/quiche.h#L206">
299      *     QUICHE_CC_BBR</a>.
300      */
301     static final int QUICHE_CC_BBR = QuicheNativeStaticallyReferencedJniMethods.quiche_cc_bbr();
302 
303     static final int QUICHE_PATH_EVENT_NEW = QuicheNativeStaticallyReferencedJniMethods.quiche_path_event_new();
304     static final int QUICHE_PATH_EVENT_VALIDATED =
305             QuicheNativeStaticallyReferencedJniMethods.quiche_path_event_validated();
306     static final int QUICHE_PATH_EVENT_FAILED_VALIDATION =
307             QuicheNativeStaticallyReferencedJniMethods.quiche_path_event_failed_validation();
308     static final int QUICHE_PATH_EVENT_CLOSED = QuicheNativeStaticallyReferencedJniMethods.quiche_path_event_closed();
309     static final int QUICHE_PATH_EVENT_REUSED_SOURCE_CONNECTION_ID =
310             QuicheNativeStaticallyReferencedJniMethods.quiche_path_event_reused_source_connection_id();
311     static final int QUICHE_PATH_EVENT_PEER_MIGRATED =
312             QuicheNativeStaticallyReferencedJniMethods.quiche_path_event_peer_migrated();
313 
314     /**
315      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L105">quiche_version</a>.
316      */
317     @Nullable
318     static native String quiche_version();
319 
320     /**
321      * See
322      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L227">quiche_version_is_supported</a>.
323      */
324     static native boolean quiche_version_is_supported(int version);
325 
326     /**
327      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L215">quiche_negotiate_version</a>.
328      */
329     static native int quiche_negotiate_version(
330             long scidAddr, int scidLen, long dcidAddr, int dcidLen, long outAddr, int outLen);
331 
332     /**
333      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L220">quiche_retry</a>.
334      */
335     static native int quiche_retry(long scidAddr, int scidLen, long dcidAddr, int dcidLen, long newScidAddr,
336                                    int newScidLen, long tokenAddr, int tokenLen, int version, long outAddr, int outLen);
337 
338     /**
339      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L229">quiche_conn_new_with_tls</a>.
340      */
341     static native long quiche_conn_new_with_tls(long scidAddr, int scidLen, long odcidAddr, int odcidLen,
342                                                 long localAddr, int localLen,
343                                                 long peerAddr, int peerLen,
344                                                 long configAddr, long ssl, boolean isServer);
345 
346     static native long quiche_conn_new_with_tls_and_client_dcid(long scidAddr, int scidLen, long odcidAddr,
347                                                                 int odcidLen, long localAddr, int localLen,
348                                                                 long peerAddr, int peerLen,
349                                                                 long configAddr, long ssl);
350 
351     /**
352      * See <a href="https://github.com/cloudflare/quiche/blob/master/include/quiche.h#L248">
353      *     quiche_conn_set_qlog_path</a>.
354      */
355     static native boolean quiche_conn_set_qlog_path(long connAddr, String path, String logTitle, String logDescription);
356 
357     /**
358      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L249">quiche_conn_recv</a>.
359      */
360     static native int quiche_conn_recv(long connAddr, long bufAddr, int bufLen, long infoAddr);
361 
362     /**
363      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L262">quiche_conn_send</a>.
364      */
365     static native int quiche_conn_send(long connAddr, long outAddr, int outLen, long infoAddr);
366 
367     /**
368      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L373">quiche_conn_free</a>.
369      */
370     static native void quiche_conn_free(long connAddr);
371 
372     @Nullable
373     static QuicConnectionCloseEvent quiche_conn_peer_error(long connAddr) {
374         Object[] error =  quiche_conn_peer_error0(connAddr);
375         if (error == null) {
376             return null;
377         }
378         return new QuicConnectionCloseEvent((Boolean) error[0], (Integer) error[1], (byte[]) error[2]);
379     }
380 
381     private static native Object @Nullable [] quiche_conn_peer_error0(long connAddr);
382 
383     /**
384      * See <a href="https://github.com/cloudflare/quiche/blob/0.7.0/include/quiche.h#L330">
385      *     quiche_conn_peer_streams_left_bidi</a>.
386      */
387     static native long quiche_conn_peer_streams_left_bidi(long connAddr);
388 
389     /**
390      * See <a href="https://github.com/cloudflare/quiche/blob/0.7.0/include/quiche.h#L334">
391      *     quiche_conn_peer_streams_left_uni</a>.
392      */
393     static native long quiche_conn_peer_streams_left_uni(long connAddr);
394 
395     /**
396      * See
397      * <a href="https://github.com/cloudflare/quiche/blob/0.7.0/include/quiche.h#L275">quiche_conn_stream_priority</a>.
398      */
399     static native int quiche_conn_stream_priority(
400             long connAddr, long streamId, byte urgency, boolean incremental);
401 
402     static native int quiche_conn_send_quantum(long connAddr);
403 
404     /**
405      * See <a href="https://github.com/cloudflare/quiche/blob/0.7.0/include/quiche.h#L309">quiche_conn_trace_id</a>.
406      */
407     static native byte @Nullable [] quiche_conn_trace_id(long connAddr);
408 
409     static native byte[] quiche_conn_source_id(long connAddr);
410 
411     static native byte[] quiche_conn_destination_id(long connAddr);
412 
413     /**
414      * See <a href="https://github.com/cloudflare/quiche/blob/0.24.5/quiche/include/quiche.h#L397">
415      *     quiche_conn_stream_recv</a>.
416      */
417     static native int quiche_conn_stream_recv(long connAddr, long streamId, long outAddr, int bufLen, long finAddr,
418                                               long outErrorCodeAddr);
419 
420     /**
421      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L262">quiche_conn_stream_send</a>.
422      */
423     static native int quiche_conn_stream_send(long connAddr, long streamId, long bufAddr, int bufLen, boolean fin);
424 
425     /**
426      * See
427      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L271">quiche_conn_stream_shutdown</a>.
428      */
429     static native int quiche_conn_stream_shutdown(long connAddr, long streamId, int direction, long err);
430 
431     /**
432      * See
433      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L274">quiche_conn_stream_capacity</a>.
434      */
435     static native long quiche_conn_stream_capacity(long connAddr, long streamId);
436 
437     /**
438      * See
439      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L277">quiche_conn_stream_finished</a>.
440      */
441     static native boolean quiche_conn_stream_finished(long connAddr, long streamId);
442 
443     /**
444      * See
445      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L297">quiche_conn_close</a>.
446      */
447     static native int quiche_conn_close(long connAddr, boolean app, long err, long reasonAddr, int reasonLen);
448 
449     /**
450      * See
451      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L305">quiche_conn_is_established</a>.
452      */
453     static native boolean quiche_conn_is_established(long connAddr);
454 
455     /**
456      * See
457      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L309">quiche_conn_is_in_early_data</a>.
458      */
459     static native boolean quiche_conn_is_in_early_data(long connAddr);
460 
461     /**
462      * See
463      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L312">quiche_conn_is_closed</a>.
464      */
465     static native boolean quiche_conn_is_closed(long connAddr);
466 
467     /**
468      * See
469      * <a href="https://github.com/cloudflare/quiche/blob/
470      * e9f59a55f5b56999d0e609a73aa8f1b450878a0c/include/quiche.h#L384">quiche_conn_is_timed_out</a>.
471      */
472     static native boolean quiche_conn_is_timed_out(long connAddr);
473 
474     /**
475      * See
476      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L361">quiche_conn_stats</a>.
477      * The implementation relies on all fields of
478      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L340">quiche_stats</a> being numerical.
479      * The assumption made allows passing primitive array rather than dealing with objects.
480      */
481     static native long @Nullable [] quiche_conn_stats(long connAddr);
482 
483     /**
484      * See
485      * <a href="https://github.com/cloudflare/quiche/blob/master/quiche/include/quiche.h#L567C65-L567C88">
486      *     quiche_conn_stats</a>.
487      */
488     static native long @Nullable [] quiche_conn_peer_transport_params(long connAddr);
489 
490     /**
491      * See
492      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L288">quiche_conn_timeout_as_nanos</a>.
493      */
494     static native long quiche_conn_timeout_as_nanos(long connAddr);
495 
496     /**
497      * See
498      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L294">quiche_conn_on_timeout</a>.
499      */
500     static native void quiche_conn_on_timeout(long connAddr);
501 
502     /**
503      * See
504      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L282">quiche_conn_readable</a>.
505      */
506     static native long quiche_conn_readable(long connAddr);
507 
508     /**
509      * See
510      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L285">quiche_conn_writable</a>.
511      */
512     static native long quiche_conn_writable(long connAddr);
513 
514     /**
515      * See
516      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L329">quiche_stream_iter_next</a>.
517      *
518      * This method will fill the {@code streamIds} array and return the number of streams that were filled into
519      * the array. If the number is the same as the length of the array you should call it again until it returns
520      * less to ensure you process all the streams later on.
521      */
522     static native int quiche_stream_iter_next(long iterAddr, long[] streamIds);
523 
524     /**
525      * See
526      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L332">quiche_stream_iter_free</a>.
527      *
528      */
529     static native void quiche_stream_iter_free(long iterAddr);
530 
531     /**
532      * See
533      * <a href="https://github.com/cloudflare/quiche/blob/0.20.0/quiche/include/quiche.h#L672">
534      *     quiche_conn_path_stats</a>.
535      */
536     static native Object @Nullable [] quiche_conn_path_stats(long connAddr, long streamIdx);
537 
538     /**
539      * See
540      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L358">
541      *     quiche_conn_dgram_max_writable_len</a>.
542      */
543     static native int quiche_conn_dgram_max_writable_len(long connAddr);
544 
545     /**
546      * See
547      * <a href=https://github.com/cloudflare/quiche/blob/
548      * 9d0c677ef1411b24d720b5c8b73bcc94b5535c29/include/quiche.h#L381">
549      *     quiche_conn_dgram_recv_front_len</a>.
550      */
551     static native int quiche_conn_dgram_recv_front_len(long connAddr);
552 
553     /**
554      * See
555      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L361">
556      *     quiche_conn_dgram_recv</a>.
557      */
558     static native int quiche_conn_dgram_recv(long connAddr, long buf, int size);
559 
560     /**
561      * See
562      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L3651">
563      *     quiche_conn_dgram_send</a>.
564      */
565     static native int quiche_conn_dgram_send(long connAddr, long buf, int size);
566 
567     /**
568      * See
569      * <a href="https://github.com/cloudflare/quiche/blob/0.10.0/include/quiche.h#L267">
570      *     quiche_conn_set_session</a>.
571      */
572     static native int quiche_conn_set_session(long connAddr, byte[] sessionBytes);
573 
574     /**
575      * See
576      * <a href="https://github.com/cloudflare/quiche/blob/0.10.0/include/quiche.h#L328">
577      *     quiche_conn_max_send_udp_payload_size</a>.
578      */
579     static native int quiche_conn_max_send_udp_payload_size(long connAddr);
580 
581     static native int quiche_conn_scids_left(long connAddr);
582 
583     static native long quiche_conn_new_scid(
584             long connAddr, long scidAddr, int scidLen, byte[] resetToken, boolean retire_if_needed, long seq);
585 
586     static native byte @Nullable [] quiche_conn_retired_scid_next(long connAddr);
587 
588     static native long quiche_conn_path_event_next(long connAddr);
589     static native int quiche_path_event_type(long pathEvent);
590     static native void quiche_path_event_free(long pathEvent);
591     static native Object[] quiche_path_event_new(long pathEvent);
592     static native Object[] quiche_path_event_validated(long pathEvent);
593     static native Object[] quiche_path_event_failed_validation(long pathEvent);
594     static native Object[]  quiche_path_event_closed(long pathEvent);
595     static native Object[] quiche_path_event_reused_source_connection_id(long pathEvent);
596     static native Object[] quiche_path_event_peer_migrated(long pathEvent);
597 
598     /**
599      * See
600      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L115">quiche_config_new</a>.
601      */
602     static native long quiche_config_new(int version);
603 
604     /**
605      * See
606      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#129">
607      *     quiche_config_grease</a>.
608      */
609     static native void quiche_config_grease(long configAddr, boolean value);
610 
611     /**
612      * See
613      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#143">
614      *     quiche_config_set_max_idle_timeout</a>.
615      */
616     static native void quiche_config_set_max_idle_timeout(long configAddr, long value);
617 
618     /**
619      * See
620      * <a href="https://github.com/cloudflare/quiche/blob/0.7.0/include/quiche.h#L150">
621      *     quiche_config_set_max_recv_udp_payload_size</a>.
622      */
623     static native void quiche_config_set_max_recv_udp_payload_size(long configAddr, long value);
624 
625     /**
626      * See
627      * <a href="https://github.com/cloudflare/quiche/blob/0.7.0/include/quiche.h#L153">
628      *     quiche_config_set_max_recv_udp_payload_size</a>.
629      */
630     static native void quiche_config_set_max_send_udp_payload_size(long configAddr, long value);
631 
632     /**
633      * See
634      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#149">
635      *     quiche_config_set_initial_max_data</a>.
636      */
637     static native void quiche_config_set_initial_max_data(long configAddr, long value);
638 
639     /**
640      * See
641      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#152">
642      *     quiche_config_set_initial_max_stream_data_bidi_local</a>.
643      */
644     static native void quiche_config_set_initial_max_stream_data_bidi_local(long configAddr, long value);
645 
646     /**
647      * See
648      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#155">
649      *     quiche_config_set_initial_max_stream_data_bidi_remote</a>.
650      */
651     static native void quiche_config_set_initial_max_stream_data_bidi_remote(long configAddr, long value);
652 
653     /**
654      * See
655      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#158">
656      *     quiche_config_set_initial_max_stream_data_uni</a>.
657      */
658     static native void quiche_config_set_initial_max_stream_data_uni(long configAddr, long value);
659 
660     /**
661      * See
662      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#161">
663      *     quiche_config_set_initial_max_streams_bidi</a>.
664      */
665     static native void quiche_config_set_initial_max_streams_bidi(long configAddr, long value);
666 
667     /**
668      * See
669      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#164">
670      *     quiche_config_set_initial_max_streams_uni</a>.
671      */
672     static native void quiche_config_set_initial_max_streams_uni(long configAddr, long value);
673 
674     /**
675      * See
676      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#167">
677      *     quiche_config_set_ack_delay_exponent</a>.
678      */
679     static native void quiche_config_set_ack_delay_exponent(long configAddr, long value);
680 
681     /**
682      * See
683      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#170">
684      *     quiche_config_set_max_ack_delay</a>.
685      */
686     static native void quiche_config_set_max_ack_delay(long configAddr, long value);
687 
688     /**
689      * See
690      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#173">
691      *     quiche_config_set_disable_active_migration</a>.
692      */
693     static native void quiche_config_set_disable_active_migration(long configAddr, boolean value);
694 
695     /**
696      * See
697      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#181">
698      *     quiche_config_set_cc_algorithm</a>.
699      */
700     static native void quiche_config_set_cc_algorithm(long configAddr, int algo);
701 
702     /**
703      * See
704      * <a href="https://github.com/cloudflare/quiche/blob/0.21.0/quiche/include/quiche.h#L222">
705      *     quiche_config_set_initial_congestion_window_packets</a>
706      *
707      */
708     static native void quiche_config_set_initial_congestion_window_packets(long configAddr, int numPackets);
709 
710     /**
711      * See
712      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#184">
713      *     quiche_config_enable_hystart</a>.
714      */
715     static native void quiche_config_enable_hystart(long configAddr, boolean value);
716 
717     /**
718      * See
719      * <a href="https://docs.rs/quiche/latest/quiche/struct.Config.html#method.discover_pmtu">
720      *     quiche_config_discover_pmtu</a>.
721      */
722     static native void quiche_config_discover_pmtu(long configAddr, boolean value);
723 
724     /**
725      * See
726      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L187">
727      *     quiche_config_enable_dgram</a>.
728      */
729     static native void quiche_config_enable_dgram(long configAddr, boolean enable,
730                                                   int recv_queue_len, int send_queue_len);
731 
732     // Sets the limit of active connection IDs.
733     static native void quiche_config_set_active_connection_id_limit(long configAddr, long value);
734 
735     // Sets the initial stateless reset token.
736     static native void quiche_config_set_stateless_reset_token(long configAddr, byte[] token);
737 
738     /**
739      * See
740      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#192">
741      *     quiche_config_free</a>.
742      */
743     static native void quiche_config_free(long configAddr);
744 
745     /**
746      * See
747      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L108">quiche_config_new</a>.
748      */
749     private static native void quiche_enable_debug_logging(QuicheLogger logger);
750 
751     private static native long buffer_memory_address(ByteBuffer buffer);
752 
753     static native int sockaddr_cmp(long addr, long addr2);
754 
755     /**
756      * Returns the memory address if the {@link ByteBuf} taking the readerIndex into account.
757      *
758      * @param buf   the {@link ByteBuf} of which we want to obtain the memory address
759      *              (taking its {@link ByteBuf#readerIndex()} into account).
760      * @return      the memory address of this {@link ByteBuf}s readerIndex.
761      */
762     static long readerMemoryAddress(ByteBuf buf) {
763         return memoryAddress(buf, buf.readerIndex(), buf.readableBytes());
764     }
765 
766     /**
767      * Returns the memory address if the {@link ByteBuf} taking the writerIndex into account.
768      *
769      * @param buf   the {@link ByteBuf} of which we want to obtain the memory address
770      *              (taking its {@link ByteBuf#writerIndex()} into account).
771      * @return      the memory address of this {@link ByteBuf}s writerIndex.
772      */
773     static long writerMemoryAddress(ByteBuf buf) {
774         return memoryAddress(buf, buf.writerIndex(), buf.writableBytes());
775     }
776 
777     /**
778      * Returns the memory address if the {@link ByteBuf} taking the offset into account.
779      *
780      * @param buf       the {@link ByteBuf} of which we want to obtain the memory address
781      *                  (taking the {@code offset} into account).
782      * @param offset    the offset of the memory address.
783      * @param len       the length of the {@link ByteBuf}.
784      * @return          the memory address of this {@link ByteBuf}s offset.
785      */
786     static long memoryAddress(ByteBuf buf, int offset, int len) {
787         assert buf.isDirect();
788         if (buf.hasMemoryAddress()) {
789             return buf.memoryAddress() + offset;
790         }
791         return memoryAddressWithPosition(buf.internalNioBuffer(offset, len));
792     }
793 
794     /**
795      * Returns the memory address of the given {@link ByteBuffer} taking its current {@link ByteBuffer#position()} into
796      * account.
797      *
798      * @param buf   the {@link ByteBuffer} of which we want to obtain the memory address
799      *              (taking its {@link ByteBuffer#position()} into account).
800      * @return      the memory address of this {@link ByteBuffer}s position.
801      */
802     static long memoryAddressWithPosition(ByteBuffer buf) {
803         assert buf.isDirect();
804         return buffer_memory_address(buf) + buf.position();
805     }
806 
807     @SuppressWarnings("deprecation")
808     static ByteBuf allocateNativeOrder(int capacity) {
809         // Just use Unpooled as the life-time of these buffers is long.
810         ByteBuf buffer = Unpooled.directBuffer(capacity);
811 
812         // As we use the buffers as pointers to int etc we need to ensure we use the right oder so we will
813         // see the right value when we read primitive values.
814         return PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? buffer : buffer.order(ByteOrder.LITTLE_ENDIAN);
815     }
816 
817     static boolean shouldClose(int res)  {
818         return res == Quiche.QUICHE_ERR_CRYPTO_FAIL || res == Quiche.QUICHE_ERR_TLS_FAIL;
819     }
820 
821     /**
822      * Returns {@code true} if both {@link ByteBuffer}s have the same {@code sock_addr} stored.
823      *
824      * @param memory    the first {@link ByteBuffer} which holds a {@code quiche_recv_info}.
825      * @param memory2   the second {@link ByteBuffer} which holds a {@code quiche_recv_info}.
826      * @return          {@code true} if both {@link ByteBuffer}s have the same {@code sock_addr} stored, {@code false}
827      *                  otherwise.
828      */
829     static boolean isSameAddress(ByteBuffer memory, ByteBuffer memory2, int addressOffset) {
830         long address1 = Quiche.memoryAddressWithPosition(memory) + addressOffset;
831         long address2 = Quiche.memoryAddressWithPosition(memory2) + addressOffset;
832         return SockaddrIn.cmp(address1, address2) == 0;
833     }
834 
835     static void setPrimitiveValue(ByteBuffer memory, int offset, int valueType, long value) {
836         switch (valueType) {
837             case 1:
838                 memory.put(offset, (byte) value);
839                 break;
840             case 2:
841                 memory.putShort(offset, (short) value);
842                 break;
843             case 4:
844                 memory.putInt(offset, (int) value);
845                 break;
846             case 8:
847                 memory.putLong(offset, value);
848                 break;
849             default:
850                 throw new IllegalStateException();
851         }
852     }
853 
854     static long getPrimitiveValue(ByteBuffer memory, int offset, int valueType) {
855         switch (valueType) {
856             case 1:
857                 return memory.get(offset);
858             case 2:
859                 return memory.getShort(offset);
860             case 4:
861                 return memory.getInt(offset);
862             case 8:
863                 return memory.getLong(offset);
864             default:
865                 throw new IllegalStateException();
866         }
867     }
868 
869     // See https://github.com/cloudflare/quiche/commit/1d00ee1bb2256dfd99ba0cb2dfac72fe1e59407f
870     static {
871         ERROR_MAPPINGS.put(QUICHE_ERR_DONE,
872                 new QuicTransportErrorHolder(QuicTransportError.NO_ERROR, "QUICHE_ERR_DONE"));
873         ERROR_MAPPINGS.put(QUICHE_ERR_INVALID_FRAME,
874                 new QuicTransportErrorHolder(QuicTransportError.FRAME_ENCODING_ERROR, "QUICHE_ERR_INVALID_FRAME"));
875         ERROR_MAPPINGS.put(QUICHE_ERR_INVALID_STREAM_STATE,
876                 new QuicTransportErrorHolder(QuicTransportError.STREAM_STATE_ERROR, "QUICHE_ERR_INVALID_STREAM_STATE"));
877         ERROR_MAPPINGS.put(QUICHE_ERR_INVALID_TRANSPORT_PARAM,
878                 new QuicTransportErrorHolder(QuicTransportError.TRANSPORT_PARAMETER_ERROR,
879                         "QUICHE_ERR_INVALID_TRANSPORT_PARAM"));
880         ERROR_MAPPINGS.put(QUICHE_ERR_FLOW_CONTROL,
881                 new QuicTransportErrorHolder(QuicTransportError.FLOW_CONTROL_ERROR, "QUICHE_ERR_FLOW_CONTROL"));
882         ERROR_MAPPINGS.put(QUICHE_ERR_STREAM_LIMIT,
883                 new QuicTransportErrorHolder(QuicTransportError.STREAM_LIMIT_ERROR, "QUICHE_ERR_STREAM_LIMIT"));
884         ERROR_MAPPINGS.put(QUICHE_ERR_ID_LIMIT,
885                 new QuicTransportErrorHolder(QuicTransportError.CONNECTION_ID_LIMIT_ERROR, "QUICHE_ERR_ID_LIMIT"));
886         ERROR_MAPPINGS.put(QUICHE_ERR_FINAL_SIZE,
887                 new QuicTransportErrorHolder(QuicTransportError.FINAL_SIZE_ERROR, "QUICHE_ERR_FINAL_SIZE"));
888         ERROR_MAPPINGS.put(QUICHE_ERR_CRYPTO_BUFFER_EXCEEDED,
889                 new QuicTransportErrorHolder(QuicTransportError.CRYPTO_BUFFER_EXCEEDED,
890                         "QUICHE_ERR_CRYPTO_BUFFER_EXCEEDED"));
891         ERROR_MAPPINGS.put(QUICHE_ERR_KEY_UPDATE,
892                 new QuicTransportErrorHolder(QuicTransportError.KEY_UPDATE_ERROR, "QUICHE_ERR_KEY_UPDATE"));
893 
894         // Should the code be something different ?
895         ERROR_MAPPINGS.put(QUICHE_ERR_TLS_FAIL,
896                 new QuicTransportErrorHolder(QuicTransportError.valueOf(0x0100), "QUICHE_ERR_TLS_FAIL"));
897         ERROR_MAPPINGS.put(QUICHE_ERR_CRYPTO_FAIL,
898                 new QuicTransportErrorHolder(QuicTransportError.valueOf(0x0100), "QUICHE_ERR_CRYPTO_FAIL"));
899 
900         ERROR_MAPPINGS.put(QUICHE_ERR_BUFFER_TOO_SHORT,
901                 new QuicTransportErrorHolder(QuicTransportError.PROTOCOL_VIOLATION, "QUICHE_ERR_BUFFER_TOO_SHORT"));
902         ERROR_MAPPINGS.put(QUICHE_ERR_UNKNOWN_VERSION,
903                 new QuicTransportErrorHolder(QuicTransportError.PROTOCOL_VIOLATION, "QUICHE_ERR_UNKNOWN_VERSION"));
904         ERROR_MAPPINGS.put(QUICHE_ERR_INVALID_PACKET,
905                 new QuicTransportErrorHolder(QuicTransportError.PROTOCOL_VIOLATION, "QUICHE_ERR_INVALID_PACKET"));
906         ERROR_MAPPINGS.put(QUICHE_ERR_INVALID_STATE,
907                 new QuicTransportErrorHolder(QuicTransportError.PROTOCOL_VIOLATION, "QUICHE_ERR_INVALID_STATE"));
908         ERROR_MAPPINGS.put(QUICHE_ERR_CONGESTION_CONTROL,
909                 new QuicTransportErrorHolder(QuicTransportError.PROTOCOL_VIOLATION, "QUICHE_ERR_CONGESTION_CONTROL"));
910         ERROR_MAPPINGS.put(QUICHE_ERR_STREAM_STOPPED,
911                 new QuicTransportErrorHolder(QuicTransportError.PROTOCOL_VIOLATION, "QUICHE_ERR_STREAM_STOPPED"));
912         ERROR_MAPPINGS.put(QUICHE_ERR_OUT_OF_IDENTIFIERS,
913                 new QuicTransportErrorHolder(QuicTransportError.PROTOCOL_VIOLATION, "QUICHE_ERR_OUT_OF_IDENTIFIERS"));
914         ERROR_MAPPINGS.put(QUICHE_ERR_INVALID_DCID_INITIALIZATION, new QuicTransportErrorHolder(
915                 QuicTransportError.PROTOCOL_VIOLATION, "QUICHE_ERR_INVALID_DCID_INITIALIZATION"));
916     }
917 
918     static Exception convertToException(int result) {
919         return convertToException(result, -1);
920     }
921 
922     static Exception convertToException(int result, long code) {
923         QuicTransportErrorHolder holder = ERROR_MAPPINGS.get(result);
924         if (holder == null) {
925             // There is no mapping to a transport error, it's something internal so throw it directly.
926             QuicheError error = QuicheError.valueOf(result);
927             if (error == STREAM_RESET) {
928                 return new QuicStreamResetException(error.message(), code);
929             } else {
930                 return new QuicException(error.message());
931             }
932         }
933         Exception exception = new QuicException(holder.error + ": " + holder.quicheErrorName, holder.error);
934         if (result == QUICHE_ERR_TLS_FAIL) {
935             String lastSslError = BoringSSL.ERR_last_error();
936             final SSLHandshakeException sslExc = new SSLHandshakeException(lastSslError);
937             sslExc.initCause(exception);
938             return sslExc;
939         }
940         if (result == QUICHE_ERR_CRYPTO_FAIL) {
941             return new SSLException(exception);
942         }
943         return exception;
944     }
945 
946     private static final class QuicTransportErrorHolder {
947         private final QuicTransportError error;
948         private final String quicheErrorName;
949 
950         QuicTransportErrorHolder(QuicTransportError error, String quicheErrorName) {
951             this.error = error;
952             this.quicheErrorName = quicheErrorName;
953         }
954     }
955 
956     private Quiche() { }
957 }