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     /**
283      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L176">
284      *     QUICHE_CC_RENO</a>.
285      */
286     static final int QUICHE_CC_RENO = QuicheNativeStaticallyReferencedJniMethods.quiche_cc_reno();
287 
288     /**
289      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L177">
290      *     QUICHE_CC_CUBIC</a>.
291      */
292     static final int QUICHE_CC_CUBIC = QuicheNativeStaticallyReferencedJniMethods.quiche_cc_cubic();
293 
294     /**
295      * See <a href="https://github.com/cloudflare/quiche/blob/0.16.0/quiche/include/quiche.h#L206">
296      *     QUICHE_CC_BBR</a>.
297      */
298     static final int QUICHE_CC_BBR = QuicheNativeStaticallyReferencedJniMethods.quiche_cc_bbr();
299 
300     static final int QUICHE_PATH_EVENT_NEW = QuicheNativeStaticallyReferencedJniMethods.quiche_path_event_new();
301     static final int QUICHE_PATH_EVENT_VALIDATED =
302             QuicheNativeStaticallyReferencedJniMethods.quiche_path_event_validated();
303     static final int QUICHE_PATH_EVENT_FAILED_VALIDATION =
304             QuicheNativeStaticallyReferencedJniMethods.quiche_path_event_failed_validation();
305     static final int QUICHE_PATH_EVENT_CLOSED = QuicheNativeStaticallyReferencedJniMethods.quiche_path_event_closed();
306     static final int QUICHE_PATH_EVENT_REUSED_SOURCE_CONNECTION_ID =
307             QuicheNativeStaticallyReferencedJniMethods.quiche_path_event_reused_source_connection_id();
308     static final int QUICHE_PATH_EVENT_PEER_MIGRATED =
309             QuicheNativeStaticallyReferencedJniMethods.quiche_path_event_peer_migrated();
310 
311     /**
312      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L105">quiche_version</a>.
313      */
314     @Nullable
315     static native String quiche_version();
316 
317     /**
318      * See
319      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L227">quiche_version_is_supported</a>.
320      */
321     static native boolean quiche_version_is_supported(int version);
322 
323     /**
324      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L215">quiche_negotiate_version</a>.
325      */
326     static native int quiche_negotiate_version(
327             long scidAddr, int scidLen, long dcidAddr, int dcidLen, long outAddr, int outLen);
328 
329     /**
330      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L220">quiche_retry</a>.
331      */
332     static native int quiche_retry(long scidAddr, int scidLen, long dcidAddr, int dcidLen, long newScidAddr,
333                                    int newScidLen, long tokenAddr, int tokenLen, int version, long outAddr, int outLen);
334 
335     /**
336      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L229">quiche_conn_new_with_tls</a>.
337      */
338     static native long quiche_conn_new_with_tls(long scidAddr, int scidLen, long odcidAddr, int odcidLen,
339                                                 long localAddr, int localLen,
340                                                 long peerAddr, int peerLen,
341                                                 long configAddr, long ssl, boolean isServer);
342 
343     /**
344      * See <a href="https://github.com/cloudflare/quiche/blob/master/include/quiche.h#L248">
345      *     quiche_conn_set_qlog_path</a>.
346      */
347     static native boolean quiche_conn_set_qlog_path(long connAddr, String path, String logTitle, String logDescription);
348 
349     /**
350      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L249">quiche_conn_recv</a>.
351      */
352     static native int quiche_conn_recv(long connAddr, long bufAddr, int bufLen, long infoAddr);
353 
354     /**
355      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L262">quiche_conn_send</a>.
356      */
357     static native int quiche_conn_send(long connAddr, long outAddr, int outLen, long infoAddr);
358 
359     /**
360      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L373">quiche_conn_free</a>.
361      */
362     static native void quiche_conn_free(long connAddr);
363 
364     @Nullable
365     static QuicConnectionCloseEvent quiche_conn_peer_error(long connAddr) {
366         Object[] error =  quiche_conn_peer_error0(connAddr);
367         if (error == null) {
368             return null;
369         }
370         return new QuicConnectionCloseEvent((Boolean) error[0], (Integer) error[1], (byte[]) error[2]);
371     }
372 
373     private static native Object @Nullable [] quiche_conn_peer_error0(long connAddr);
374 
375     /**
376      * See <a href="https://github.com/cloudflare/quiche/blob/0.7.0/include/quiche.h#L330">
377      *     quiche_conn_peer_streams_left_bidi</a>.
378      */
379     static native long quiche_conn_peer_streams_left_bidi(long connAddr);
380 
381     /**
382      * See <a href="https://github.com/cloudflare/quiche/blob/0.7.0/include/quiche.h#L334">
383      *     quiche_conn_peer_streams_left_uni</a>.
384      */
385     static native long quiche_conn_peer_streams_left_uni(long connAddr);
386 
387     /**
388      * See
389      * <a href="https://github.com/cloudflare/quiche/blob/0.7.0/include/quiche.h#L275">quiche_conn_stream_priority</a>.
390      */
391     static native int quiche_conn_stream_priority(
392             long connAddr, long streamId, byte urgency, boolean incremental);
393 
394     static native int quiche_conn_send_quantum(long connAddr);
395 
396     /**
397      * See <a href="https://github.com/cloudflare/quiche/blob/0.7.0/include/quiche.h#L309">quiche_conn_trace_id</a>.
398      */
399     static native byte @Nullable [] quiche_conn_trace_id(long connAddr);
400 
401     static native byte[] quiche_conn_source_id(long connAddr);
402 
403     static native byte[] quiche_conn_destination_id(long connAddr);
404 
405     /**
406      * See <a href="https://github.com/cloudflare/quiche/blob/0.24.5/quiche/include/quiche.h#L397">
407      *     quiche_conn_stream_recv</a>.
408      */
409     static native int quiche_conn_stream_recv(long connAddr, long streamId, long outAddr, int bufLen, long finAddr,
410                                               long outErrorCodeAddr);
411 
412     /**
413      * See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L262">quiche_conn_stream_send</a>.
414      */
415     static native int quiche_conn_stream_send(long connAddr, long streamId, long bufAddr, int bufLen, boolean fin);
416 
417     /**
418      * See
419      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L271">quiche_conn_stream_shutdown</a>.
420      */
421     static native int quiche_conn_stream_shutdown(long connAddr, long streamId, int direction, long err);
422 
423     /**
424      * See
425      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L274">quiche_conn_stream_capacity</a>.
426      */
427     static native long quiche_conn_stream_capacity(long connAddr, long streamId);
428 
429     /**
430      * See
431      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L277">quiche_conn_stream_finished</a>.
432      */
433     static native boolean quiche_conn_stream_finished(long connAddr, long streamId);
434 
435     /**
436      * See
437      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L297">quiche_conn_close</a>.
438      */
439     static native int quiche_conn_close(long connAddr, boolean app, long err, long reasonAddr, int reasonLen);
440 
441     /**
442      * See
443      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L305">quiche_conn_is_established</a>.
444      */
445     static native boolean quiche_conn_is_established(long connAddr);
446 
447     /**
448      * See
449      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L309">quiche_conn_is_in_early_data</a>.
450      */
451     static native boolean quiche_conn_is_in_early_data(long connAddr);
452 
453     /**
454      * See
455      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L312">quiche_conn_is_closed</a>.
456      */
457     static native boolean quiche_conn_is_closed(long connAddr);
458 
459     /**
460      * See
461      * <a href="https://github.com/cloudflare/quiche/blob/
462      * e9f59a55f5b56999d0e609a73aa8f1b450878a0c/include/quiche.h#L384">quiche_conn_is_timed_out</a>.
463      */
464     static native boolean quiche_conn_is_timed_out(long connAddr);
465 
466     /**
467      * See
468      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L361">quiche_conn_stats</a>.
469      * The implementation relies on all fields of
470      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L340">quiche_stats</a> being numerical.
471      * The assumption made allows passing primitive array rather than dealing with objects.
472      */
473     static native long @Nullable [] quiche_conn_stats(long connAddr);
474 
475     /**
476      * See
477      * <a href="https://github.com/cloudflare/quiche/blob/master/quiche/include/quiche.h#L567C65-L567C88">
478      *     quiche_conn_stats</a>.
479      */
480     static native long @Nullable [] quiche_conn_peer_transport_params(long connAddr);
481 
482     /**
483      * See
484      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L288">quiche_conn_timeout_as_nanos</a>.
485      */
486     static native long quiche_conn_timeout_as_nanos(long connAddr);
487 
488     /**
489      * See
490      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L294">quiche_conn_on_timeout</a>.
491      */
492     static native void quiche_conn_on_timeout(long connAddr);
493 
494     /**
495      * See
496      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L282">quiche_conn_readable</a>.
497      */
498     static native long quiche_conn_readable(long connAddr);
499 
500     /**
501      * See
502      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L285">quiche_conn_writable</a>.
503      */
504     static native long quiche_conn_writable(long connAddr);
505 
506     /**
507      * See
508      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L329">quiche_stream_iter_next</a>.
509      *
510      * This method will fill the {@code streamIds} array and return the number of streams that were filled into
511      * the array. If the number is the same as the length of the array you should call it again until it returns
512      * less to ensure you process all the streams later on.
513      */
514     static native int quiche_stream_iter_next(long iterAddr, long[] streamIds);
515 
516     /**
517      * See
518      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L332">quiche_stream_iter_free</a>.
519      *
520      */
521     static native void quiche_stream_iter_free(long iterAddr);
522 
523     /**
524      * See
525      * <a href="https://github.com/cloudflare/quiche/blob/0.20.0/quiche/include/quiche.h#L672">
526      *     quiche_conn_path_stats</a>.
527      */
528     static native Object @Nullable [] quiche_conn_path_stats(long connAddr, long streamIdx);
529 
530     /**
531      * See
532      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L358">
533      *     quiche_conn_dgram_max_writable_len</a>.
534      */
535     static native int quiche_conn_dgram_max_writable_len(long connAddr);
536 
537     /**
538      * See
539      * <a href=https://github.com/cloudflare/quiche/blob/
540      * 9d0c677ef1411b24d720b5c8b73bcc94b5535c29/include/quiche.h#L381">
541      *     quiche_conn_dgram_recv_front_len</a>.
542      */
543     static native int quiche_conn_dgram_recv_front_len(long connAddr);
544 
545     /**
546      * See
547      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L361">
548      *     quiche_conn_dgram_recv</a>.
549      */
550     static native int quiche_conn_dgram_recv(long connAddr, long buf, int size);
551 
552     /**
553      * See
554      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L3651">
555      *     quiche_conn_dgram_send</a>.
556      */
557     static native int quiche_conn_dgram_send(long connAddr, long buf, int size);
558 
559     /**
560      * See
561      * <a href="https://github.com/cloudflare/quiche/blob/0.10.0/include/quiche.h#L267">
562      *     quiche_conn_set_session</a>.
563      */
564     static native int quiche_conn_set_session(long connAddr, byte[] sessionBytes);
565 
566     /**
567      * See
568      * <a href="https://github.com/cloudflare/quiche/blob/0.10.0/include/quiche.h#L328">
569      *     quiche_conn_max_send_udp_payload_size</a>.
570      */
571     static native int quiche_conn_max_send_udp_payload_size(long connAddr);
572 
573     static native int quiche_conn_scids_left(long connAddr);
574 
575     static native long quiche_conn_new_scid(
576             long connAddr, long scidAddr, int scidLen, byte[] resetToken, boolean retire_if_needed, long seq);
577 
578     static native byte @Nullable [] quiche_conn_retired_scid_next(long connAddr);
579 
580     static native long quiche_conn_path_event_next(long connAddr);
581     static native int quiche_path_event_type(long pathEvent);
582     static native void quiche_path_event_free(long pathEvent);
583     static native Object[] quiche_path_event_new(long pathEvent);
584     static native Object[] quiche_path_event_validated(long pathEvent);
585     static native Object[] quiche_path_event_failed_validation(long pathEvent);
586     static native Object[]  quiche_path_event_closed(long pathEvent);
587     static native Object[] quiche_path_event_reused_source_connection_id(long pathEvent);
588     static native Object[] quiche_path_event_peer_migrated(long pathEvent);
589 
590     /**
591      * See
592      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L115">quiche_config_new</a>.
593      */
594     static native long quiche_config_new(int version);
595 
596     /**
597      * See
598      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#129">
599      *     quiche_config_grease</a>.
600      */
601     static native void quiche_config_grease(long configAddr, boolean value);
602 
603     /**
604      * See
605      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#143">
606      *     quiche_config_set_max_idle_timeout</a>.
607      */
608     static native void quiche_config_set_max_idle_timeout(long configAddr, long value);
609 
610     /**
611      * See
612      * <a href="https://github.com/cloudflare/quiche/blob/0.7.0/include/quiche.h#L150">
613      *     quiche_config_set_max_recv_udp_payload_size</a>.
614      */
615     static native void quiche_config_set_max_recv_udp_payload_size(long configAddr, long value);
616 
617     /**
618      * See
619      * <a href="https://github.com/cloudflare/quiche/blob/0.7.0/include/quiche.h#L153">
620      *     quiche_config_set_max_recv_udp_payload_size</a>.
621      */
622     static native void quiche_config_set_max_send_udp_payload_size(long configAddr, long value);
623 
624     /**
625      * See
626      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#149">
627      *     quiche_config_set_initial_max_data</a>.
628      */
629     static native void quiche_config_set_initial_max_data(long configAddr, long value);
630 
631     /**
632      * See
633      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#152">
634      *     quiche_config_set_initial_max_stream_data_bidi_local</a>.
635      */
636     static native void quiche_config_set_initial_max_stream_data_bidi_local(long configAddr, long value);
637 
638     /**
639      * See
640      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#155">
641      *     quiche_config_set_initial_max_stream_data_bidi_remote</a>.
642      */
643     static native void quiche_config_set_initial_max_stream_data_bidi_remote(long configAddr, long value);
644 
645     /**
646      * See
647      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#158">
648      *     quiche_config_set_initial_max_stream_data_uni</a>.
649      */
650     static native void quiche_config_set_initial_max_stream_data_uni(long configAddr, long value);
651 
652     /**
653      * See
654      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#161">
655      *     quiche_config_set_initial_max_streams_bidi</a>.
656      */
657     static native void quiche_config_set_initial_max_streams_bidi(long configAddr, long value);
658 
659     /**
660      * See
661      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#164">
662      *     quiche_config_set_initial_max_streams_uni</a>.
663      */
664     static native void quiche_config_set_initial_max_streams_uni(long configAddr, long value);
665 
666     /**
667      * See
668      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#167">
669      *     quiche_config_set_ack_delay_exponent</a>.
670      */
671     static native void quiche_config_set_ack_delay_exponent(long configAddr, long value);
672 
673     /**
674      * See
675      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#170">
676      *     quiche_config_set_max_ack_delay</a>.
677      */
678     static native void quiche_config_set_max_ack_delay(long configAddr, long value);
679 
680     /**
681      * See
682      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#173">
683      *     quiche_config_set_disable_active_migration</a>.
684      */
685     static native void quiche_config_set_disable_active_migration(long configAddr, boolean value);
686 
687     /**
688      * See
689      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#181">
690      *     quiche_config_set_cc_algorithm</a>.
691      */
692     static native void quiche_config_set_cc_algorithm(long configAddr, int algo);
693 
694     /**
695      * See
696      * <a href="https://github.com/cloudflare/quiche/blob/0.21.0/quiche/include/quiche.h#L222">
697      *     quiche_config_set_initial_congestion_window_packets</a>
698      *
699      */
700     static native void quiche_config_set_initial_congestion_window_packets(long configAddr, int numPackets);
701 
702     /**
703      * See
704      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#184">
705      *     quiche_config_enable_hystart</a>.
706      */
707     static native void quiche_config_enable_hystart(long configAddr, boolean value);
708 
709     /**
710      * See
711      * <a href="https://docs.rs/quiche/latest/quiche/struct.Config.html#method.discover_pmtu">
712      *     quiche_config_discover_pmtu</a>.
713      */
714     static native void quiche_config_discover_pmtu(long configAddr, boolean value);
715 
716     /**
717      * See
718      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L187">
719      *     quiche_config_enable_dgram</a>.
720      */
721     static native void quiche_config_enable_dgram(long configAddr, boolean enable,
722                                                   int recv_queue_len, int send_queue_len);
723 
724     // Sets the limit of active connection IDs.
725     static native void quiche_config_set_active_connection_id_limit(long configAddr, long value);
726 
727     // Sets the initial stateless reset token.
728     static native void quiche_config_set_stateless_reset_token(long configAddr, byte[] token);
729 
730     /**
731      * See
732      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#192">
733      *     quiche_config_free</a>.
734      */
735     static native void quiche_config_free(long configAddr);
736 
737     /**
738      * See
739      * <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L108">quiche_config_new</a>.
740      */
741     private static native void quiche_enable_debug_logging(QuicheLogger logger);
742 
743     private static native long buffer_memory_address(ByteBuffer buffer);
744 
745     static native int sockaddr_cmp(long addr, long addr2);
746 
747     /**
748      * Returns the memory address if the {@link ByteBuf} taking the readerIndex into account.
749      *
750      * @param buf   the {@link ByteBuf} of which we want to obtain the memory address
751      *              (taking its {@link ByteBuf#readerIndex()} into account).
752      * @return      the memory address of this {@link ByteBuf}s readerIndex.
753      */
754     static long readerMemoryAddress(ByteBuf buf) {
755         return memoryAddress(buf, buf.readerIndex(), buf.readableBytes());
756     }
757 
758     /**
759      * Returns the memory address if the {@link ByteBuf} taking the writerIndex into account.
760      *
761      * @param buf   the {@link ByteBuf} of which we want to obtain the memory address
762      *              (taking its {@link ByteBuf#writerIndex()} into account).
763      * @return      the memory address of this {@link ByteBuf}s writerIndex.
764      */
765     static long writerMemoryAddress(ByteBuf buf) {
766         return memoryAddress(buf, buf.writerIndex(), buf.writableBytes());
767     }
768 
769     /**
770      * Returns the memory address if the {@link ByteBuf} taking the offset into account.
771      *
772      * @param buf       the {@link ByteBuf} of which we want to obtain the memory address
773      *                  (taking the {@code offset} into account).
774      * @param offset    the offset of the memory address.
775      * @param len       the length of the {@link ByteBuf}.
776      * @return          the memory address of this {@link ByteBuf}s offset.
777      */
778     static long memoryAddress(ByteBuf buf, int offset, int len) {
779         assert buf.isDirect();
780         if (buf.hasMemoryAddress()) {
781             return buf.memoryAddress() + offset;
782         }
783         return memoryAddressWithPosition(buf.internalNioBuffer(offset, len));
784     }
785 
786     /**
787      * Returns the memory address of the given {@link ByteBuffer} taking its current {@link ByteBuffer#position()} into
788      * account.
789      *
790      * @param buf   the {@link ByteBuffer} of which we want to obtain the memory address
791      *              (taking its {@link ByteBuffer#position()} into account).
792      * @return      the memory address of this {@link ByteBuffer}s position.
793      */
794     static long memoryAddressWithPosition(ByteBuffer buf) {
795         assert buf.isDirect();
796         return buffer_memory_address(buf) + buf.position();
797     }
798 
799     @SuppressWarnings("deprecation")
800     static ByteBuf allocateNativeOrder(int capacity) {
801         // Just use Unpooled as the life-time of these buffers is long.
802         ByteBuf buffer = Unpooled.directBuffer(capacity);
803 
804         // As we use the buffers as pointers to int etc we need to ensure we use the right oder so we will
805         // see the right value when we read primitive values.
806         return PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? buffer : buffer.order(ByteOrder.LITTLE_ENDIAN);
807     }
808 
809     static boolean shouldClose(int res)  {
810         return res == Quiche.QUICHE_ERR_CRYPTO_FAIL || res == Quiche.QUICHE_ERR_TLS_FAIL;
811     }
812 
813     /**
814      * Returns {@code true} if both {@link ByteBuffer}s have the same {@code sock_addr} stored.
815      *
816      * @param memory    the first {@link ByteBuffer} which holds a {@code quiche_recv_info}.
817      * @param memory2   the second {@link ByteBuffer} which holds a {@code quiche_recv_info}.
818      * @return          {@code true} if both {@link ByteBuffer}s have the same {@code sock_addr} stored, {@code false}
819      *                  otherwise.
820      */
821     static boolean isSameAddress(ByteBuffer memory, ByteBuffer memory2, int addressOffset) {
822         long address1 = Quiche.memoryAddressWithPosition(memory) + addressOffset;
823         long address2 = Quiche.memoryAddressWithPosition(memory2) + addressOffset;
824         return SockaddrIn.cmp(address1, address2) == 0;
825     }
826 
827     static void setPrimitiveValue(ByteBuffer memory, int offset, int valueType, long value) {
828         switch (valueType) {
829             case 1:
830                 memory.put(offset, (byte) value);
831                 break;
832             case 2:
833                 memory.putShort(offset, (short) value);
834                 break;
835             case 4:
836                 memory.putInt(offset, (int) value);
837                 break;
838             case 8:
839                 memory.putLong(offset, value);
840                 break;
841             default:
842                 throw new IllegalStateException();
843         }
844     }
845 
846     static long getPrimitiveValue(ByteBuffer memory, int offset, int valueType) {
847         switch (valueType) {
848             case 1:
849                 return memory.get(offset);
850             case 2:
851                 return memory.getShort(offset);
852             case 4:
853                 return memory.getInt(offset);
854             case 8:
855                 return memory.getLong(offset);
856             default:
857                 throw new IllegalStateException();
858         }
859     }
860 
861     // See https://github.com/cloudflare/quiche/commit/1d00ee1bb2256dfd99ba0cb2dfac72fe1e59407f
862     static {
863         ERROR_MAPPINGS.put(QUICHE_ERR_DONE,
864                 new QuicTransportErrorHolder(QuicTransportError.NO_ERROR, "QUICHE_ERR_DONE"));
865         ERROR_MAPPINGS.put(QUICHE_ERR_INVALID_FRAME,
866                 new QuicTransportErrorHolder(QuicTransportError.FRAME_ENCODING_ERROR, "QUICHE_ERR_INVALID_FRAME"));
867         ERROR_MAPPINGS.put(QUICHE_ERR_INVALID_STREAM_STATE,
868                 new QuicTransportErrorHolder(QuicTransportError.STREAM_STATE_ERROR, "QUICHE_ERR_INVALID_STREAM_STATE"));
869         ERROR_MAPPINGS.put(QUICHE_ERR_INVALID_TRANSPORT_PARAM,
870                 new QuicTransportErrorHolder(QuicTransportError.TRANSPORT_PARAMETER_ERROR,
871                         "QUICHE_ERR_INVALID_TRANSPORT_PARAM"));
872         ERROR_MAPPINGS.put(QUICHE_ERR_FLOW_CONTROL,
873                 new QuicTransportErrorHolder(QuicTransportError.FLOW_CONTROL_ERROR, "QUICHE_ERR_FLOW_CONTROL"));
874         ERROR_MAPPINGS.put(QUICHE_ERR_STREAM_LIMIT,
875                 new QuicTransportErrorHolder(QuicTransportError.STREAM_LIMIT_ERROR, "QUICHE_ERR_STREAM_LIMIT"));
876         ERROR_MAPPINGS.put(QUICHE_ERR_ID_LIMIT,
877                 new QuicTransportErrorHolder(QuicTransportError.CONNECTION_ID_LIMIT_ERROR, "QUICHE_ERR_ID_LIMIT"));
878         ERROR_MAPPINGS.put(QUICHE_ERR_FINAL_SIZE,
879                 new QuicTransportErrorHolder(QuicTransportError.FINAL_SIZE_ERROR, "QUICHE_ERR_FINAL_SIZE"));
880         ERROR_MAPPINGS.put(QUICHE_ERR_CRYPTO_BUFFER_EXCEEDED,
881                 new QuicTransportErrorHolder(QuicTransportError.CRYPTO_BUFFER_EXCEEDED,
882                         "QUICHE_ERR_CRYPTO_BUFFER_EXCEEDED"));
883         ERROR_MAPPINGS.put(QUICHE_ERR_KEY_UPDATE,
884                 new QuicTransportErrorHolder(QuicTransportError.KEY_UPDATE_ERROR, "QUICHE_ERR_KEY_UPDATE"));
885 
886         // Should the code be something different ?
887         ERROR_MAPPINGS.put(QUICHE_ERR_TLS_FAIL,
888                 new QuicTransportErrorHolder(QuicTransportError.valueOf(0x0100), "QUICHE_ERR_TLS_FAIL"));
889         ERROR_MAPPINGS.put(QUICHE_ERR_CRYPTO_FAIL,
890                 new QuicTransportErrorHolder(QuicTransportError.valueOf(0x0100), "QUICHE_ERR_CRYPTO_FAIL"));
891 
892         ERROR_MAPPINGS.put(QUICHE_ERR_BUFFER_TOO_SHORT,
893                 new QuicTransportErrorHolder(QuicTransportError.PROTOCOL_VIOLATION, "QUICHE_ERR_BUFFER_TOO_SHORT"));
894         ERROR_MAPPINGS.put(QUICHE_ERR_UNKNOWN_VERSION,
895                 new QuicTransportErrorHolder(QuicTransportError.PROTOCOL_VIOLATION, "QUICHE_ERR_UNKNOWN_VERSION"));
896         ERROR_MAPPINGS.put(QUICHE_ERR_INVALID_PACKET,
897                 new QuicTransportErrorHolder(QuicTransportError.PROTOCOL_VIOLATION, "QUICHE_ERR_INVALID_PACKET"));
898         ERROR_MAPPINGS.put(QUICHE_ERR_INVALID_STATE,
899                 new QuicTransportErrorHolder(QuicTransportError.PROTOCOL_VIOLATION, "QUICHE_ERR_INVALID_STATE"));
900         ERROR_MAPPINGS.put(QUICHE_ERR_CONGESTION_CONTROL,
901                 new QuicTransportErrorHolder(QuicTransportError.PROTOCOL_VIOLATION, "QUICHE_ERR_CONGESTION_CONTROL"));
902         ERROR_MAPPINGS.put(QUICHE_ERR_STREAM_STOPPED,
903                 new QuicTransportErrorHolder(QuicTransportError.PROTOCOL_VIOLATION, "QUICHE_ERR_STREAM_STOPPED"));
904         ERROR_MAPPINGS.put(QUICHE_ERR_OUT_OF_IDENTIFIERS,
905                 new QuicTransportErrorHolder(QuicTransportError.PROTOCOL_VIOLATION, "QUICHE_ERR_OUT_OF_IDENTIFIERS"));
906     }
907 
908     static Exception convertToException(int result) {
909         return convertToException(result, -1);
910     }
911 
912     static Exception convertToException(int result, long code) {
913         QuicTransportErrorHolder holder = ERROR_MAPPINGS.get(result);
914         if (holder == null) {
915             // There is no mapping to a transport error, it's something internal so throw it directly.
916             QuicheError error = QuicheError.valueOf(result);
917             if (error == STREAM_RESET) {
918                 return new QuicStreamResetException(error.message(), code);
919             } else {
920                 return new QuicException(error.message());
921             }
922         }
923         Exception exception = new QuicException(holder.error + ": " + holder.quicheErrorName, holder.error);
924         if (result == QUICHE_ERR_TLS_FAIL) {
925             String lastSslError = BoringSSL.ERR_last_error();
926             final SSLHandshakeException sslExc = new SSLHandshakeException(lastSslError);
927             sslExc.initCause(exception);
928             return sslExc;
929         }
930         if (result == QUICHE_ERR_CRYPTO_FAIL) {
931             return new SSLException(exception);
932         }
933         return exception;
934     }
935 
936     private static final class QuicTransportErrorHolder {
937         private final QuicTransportError error;
938         private final String quicheErrorName;
939 
940         QuicTransportErrorHolder(QuicTransportError error, String quicheErrorName) {
941             this.error = error;
942             this.quicheErrorName = quicheErrorName;
943         }
944     }
945 
946     private Quiche() { }
947 }