1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
42
43
44
45
46 ClassInitializerUtil.tryLoadClasses(Quiche.class,
47
48 byte[].class, String.class, BoringSSLCertificateCallback.class,
49 BoringSSLCertificateVerifyCallback.class, BoringSSLHandshakeCompleteCallback.class,
50
51
52 QuicheLogger.class
53 );
54
55 try {
56
57
58 quiche_version();
59 } catch (UnsatisfiedLinkError ignore) {
60
61 loadNativeLibrary();
62 }
63
64
65 if (TRACE_LOGGING_ENABLED) {
66 quiche_enable_debug_logging(new QuicheLogger(logger));
67 }
68 }
69
70 private static void loadNativeLibrary() {
71
72
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
157
158 static final int QUICHE_SHUTDOWN_READ = QuicheNativeStaticallyReferencedJniMethods.quiche_shutdown_read();
159
160
161
162
163 static final int QUICHE_SHUTDOWN_WRITE = QuicheNativeStaticallyReferencedJniMethods.quiche_shutdown_write();
164
165
166
167
168 static final int QUICHE_ERR_DONE = QuicheNativeStaticallyReferencedJniMethods.quiche_err_done();
169
170
171
172
173
174 static final int QUICHE_ERR_BUFFER_TOO_SHORT =
175 QuicheNativeStaticallyReferencedJniMethods.quiche_err_buffer_too_short();
176
177
178
179
180
181 static final int QUICHE_ERR_UNKNOWN_VERSION =
182 QuicheNativeStaticallyReferencedJniMethods.quiche_err_unknown_version();
183
184
185
186
187
188 static final int QUICHE_ERR_INVALID_FRAME = QuicheNativeStaticallyReferencedJniMethods.quiche_err_invalid_frame();
189
190
191
192
193
194 static final int QUICHE_ERR_INVALID_PACKET = QuicheNativeStaticallyReferencedJniMethods.quiche_err_invalid_packet();
195
196
197
198
199
200 static final int QUICHE_ERR_INVALID_STATE = QuicheNativeStaticallyReferencedJniMethods.quiche_err_invalid_state();
201
202
203
204
205
206 static final int QUICHE_ERR_INVALID_STREAM_STATE =
207 QuicheNativeStaticallyReferencedJniMethods.quiche_err_invalid_stream_state();
208
209
210
211
212
213 static final int QUICHE_ERR_INVALID_TRANSPORT_PARAM =
214 QuicheNativeStaticallyReferencedJniMethods.quiche_err_invalid_transport_param();
215
216
217
218
219
220 static final int QUICHE_ERR_CRYPTO_FAIL = QuicheNativeStaticallyReferencedJniMethods.quiche_err_crypto_fail();
221
222
223
224
225
226 static final int QUICHE_ERR_TLS_FAIL = QuicheNativeStaticallyReferencedJniMethods.quiche_err_tls_fail();
227
228
229
230
231
232 static final int QUICHE_ERR_FLOW_CONTROL = QuicheNativeStaticallyReferencedJniMethods.quiche_err_flow_control();
233
234
235
236
237
238 static final int QUICHE_ERR_STREAM_LIMIT = QuicheNativeStaticallyReferencedJniMethods.quiche_err_stream_limit();
239
240
241
242
243
244 static final int QUICHE_ERR_FINAL_SIZE = QuicheNativeStaticallyReferencedJniMethods.quiche_err_final_size();
245
246
247
248
249
250 static final int QUICHE_ERR_CONGESTION_CONTROL =
251 QuicheNativeStaticallyReferencedJniMethods.quiche_err_congestion_control();
252
253
254
255
256
257 static final int QUICHE_ERR_STREAM_RESET =
258 QuicheNativeStaticallyReferencedJniMethods.quiche_err_stream_reset();
259
260
261
262
263
264 static final int QUICHE_ERR_STREAM_STOPPED =
265 QuicheNativeStaticallyReferencedJniMethods.quiche_err_stream_stopped();
266
267
268 static final int QUICHE_ERR_ID_LIMIT =
269 QuicheNativeStaticallyReferencedJniMethods.quiche_err_id_limit();
270
271
272 static final int QUICHE_ERR_OUT_OF_IDENTIFIERS =
273 QuicheNativeStaticallyReferencedJniMethods.quiche_err_out_of_identifiers();
274
275
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
284
285
286 static final int QUICHE_CC_RENO = QuicheNativeStaticallyReferencedJniMethods.quiche_cc_reno();
287
288
289
290
291
292 static final int QUICHE_CC_CUBIC = QuicheNativeStaticallyReferencedJniMethods.quiche_cc_cubic();
293
294
295
296
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
313
314 @Nullable
315 static native String quiche_version();
316
317
318
319
320
321 static native boolean quiche_version_is_supported(int version);
322
323
324
325
326 static native int quiche_negotiate_version(
327 long scidAddr, int scidLen, long dcidAddr, int dcidLen, long outAddr, int outLen);
328
329
330
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
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
345
346
347 static native boolean quiche_conn_set_qlog_path(long connAddr, String path, String logTitle, String logDescription);
348
349
350
351
352 static native int quiche_conn_recv(long connAddr, long bufAddr, int bufLen, long infoAddr);
353
354
355
356
357 static native int quiche_conn_send(long connAddr, long outAddr, int outLen, long infoAddr);
358
359
360
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
377
378
379 static native long quiche_conn_peer_streams_left_bidi(long connAddr);
380
381
382
383
384
385 static native long quiche_conn_peer_streams_left_uni(long connAddr);
386
387
388
389
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
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
407
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
414
415 static native int quiche_conn_stream_send(long connAddr, long streamId, long bufAddr, int bufLen, boolean fin);
416
417
418
419
420
421 static native int quiche_conn_stream_shutdown(long connAddr, long streamId, int direction, long err);
422
423
424
425
426
427 static native long quiche_conn_stream_capacity(long connAddr, long streamId);
428
429
430
431
432
433 static native boolean quiche_conn_stream_finished(long connAddr, long streamId);
434
435
436
437
438
439 static native int quiche_conn_close(long connAddr, boolean app, long err, long reasonAddr, int reasonLen);
440
441
442
443
444
445 static native boolean quiche_conn_is_established(long connAddr);
446
447
448
449
450
451 static native boolean quiche_conn_is_in_early_data(long connAddr);
452
453
454
455
456
457 static native boolean quiche_conn_is_closed(long connAddr);
458
459
460
461
462
463
464 static native boolean quiche_conn_is_timed_out(long connAddr);
465
466
467
468
469
470
471
472
473 static native long @Nullable [] quiche_conn_stats(long connAddr);
474
475
476
477
478
479
480 static native long @Nullable [] quiche_conn_peer_transport_params(long connAddr);
481
482
483
484
485
486 static native long quiche_conn_timeout_as_nanos(long connAddr);
487
488
489
490
491
492 static native void quiche_conn_on_timeout(long connAddr);
493
494
495
496
497
498 static native long quiche_conn_readable(long connAddr);
499
500
501
502
503
504 static native long quiche_conn_writable(long connAddr);
505
506
507
508
509
510
511
512
513
514 static native int quiche_stream_iter_next(long iterAddr, long[] streamIds);
515
516
517
518
519
520
521 static native void quiche_stream_iter_free(long iterAddr);
522
523
524
525
526
527
528 static native Object @Nullable [] quiche_conn_path_stats(long connAddr, long streamIdx);
529
530
531
532
533
534
535 static native int quiche_conn_dgram_max_writable_len(long connAddr);
536
537
538
539
540
541
542
543 static native int quiche_conn_dgram_recv_front_len(long connAddr);
544
545
546
547
548
549
550 static native int quiche_conn_dgram_recv(long connAddr, long buf, int size);
551
552
553
554
555
556
557 static native int quiche_conn_dgram_send(long connAddr, long buf, int size);
558
559
560
561
562
563
564 static native int quiche_conn_set_session(long connAddr, byte[] sessionBytes);
565
566
567
568
569
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
592
593
594 static native long quiche_config_new(int version);
595
596
597
598
599
600
601 static native void quiche_config_grease(long configAddr, boolean value);
602
603
604
605
606
607
608 static native void quiche_config_set_max_idle_timeout(long configAddr, long value);
609
610
611
612
613
614
615 static native void quiche_config_set_max_recv_udp_payload_size(long configAddr, long value);
616
617
618
619
620
621
622 static native void quiche_config_set_max_send_udp_payload_size(long configAddr, long value);
623
624
625
626
627
628
629 static native void quiche_config_set_initial_max_data(long configAddr, long value);
630
631
632
633
634
635
636 static native void quiche_config_set_initial_max_stream_data_bidi_local(long configAddr, long value);
637
638
639
640
641
642
643 static native void quiche_config_set_initial_max_stream_data_bidi_remote(long configAddr, long value);
644
645
646
647
648
649
650 static native void quiche_config_set_initial_max_stream_data_uni(long configAddr, long value);
651
652
653
654
655
656
657 static native void quiche_config_set_initial_max_streams_bidi(long configAddr, long value);
658
659
660
661
662
663
664 static native void quiche_config_set_initial_max_streams_uni(long configAddr, long value);
665
666
667
668
669
670
671 static native void quiche_config_set_ack_delay_exponent(long configAddr, long value);
672
673
674
675
676
677
678 static native void quiche_config_set_max_ack_delay(long configAddr, long value);
679
680
681
682
683
684
685 static native void quiche_config_set_disable_active_migration(long configAddr, boolean value);
686
687
688
689
690
691
692 static native void quiche_config_set_cc_algorithm(long configAddr, int algo);
693
694
695
696
697
698
699
700 static native void quiche_config_set_initial_congestion_window_packets(long configAddr, int numPackets);
701
702
703
704
705
706
707 static native void quiche_config_enable_hystart(long configAddr, boolean value);
708
709
710
711
712
713
714 static native void quiche_config_discover_pmtu(long configAddr, boolean value);
715
716
717
718
719
720
721 static native void quiche_config_enable_dgram(long configAddr, boolean enable,
722 int recv_queue_len, int send_queue_len);
723
724
725 static native void quiche_config_set_active_connection_id_limit(long configAddr, long value);
726
727
728 static native void quiche_config_set_stateless_reset_token(long configAddr, byte[] token);
729
730
731
732
733
734
735 static native void quiche_config_free(long configAddr);
736
737
738
739
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
749
750
751
752
753
754 static long readerMemoryAddress(ByteBuf buf) {
755 return memoryAddress(buf, buf.readerIndex(), buf.readableBytes());
756 }
757
758
759
760
761
762
763
764
765 static long writerMemoryAddress(ByteBuf buf) {
766 return memoryAddress(buf, buf.writerIndex(), buf.writableBytes());
767 }
768
769
770
771
772
773
774
775
776
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
788
789
790
791
792
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
802 ByteBuf buffer = Unpooled.directBuffer(capacity);
803
804
805
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
815
816
817
818
819
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
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
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
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 }