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