All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.netty.incubator.codec.quic.Quiche Maven / Gradle / Ivy

There is a newer version: 0.0.69.Final
Show newest version
/*
 * Copyright 2020 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package io.netty.incubator.codec.quic;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.util.collection.IntObjectHashMap;
import io.netty.util.internal.ClassInitializerUtil;
import io.netty.util.internal.NativeLibraryLoader;
import io.netty.util.internal.PlatformDependent;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import org.jetbrains.annotations.Nullable;

import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

final class Quiche {
    private static final InternalLogger logger = InternalLoggerFactory.getInstance(Quiche.class);
    private static final boolean DEBUG_LOGGING_ENABLED = logger.isDebugEnabled();
    private static final IntObjectHashMap ERROR_MAPPINGS = new IntObjectHashMap<>();

    static {
        // Preload all classes that will be used in the OnLoad(...) function of JNI to eliminate the possibility of a
        // class-loader deadlock. This is a workaround for https://github.com/netty/netty/issues/11209.

        // This needs to match all the classes that are loaded via NETTY_JNI_UTIL_LOAD_CLASS or looked up via
        // NETTY_JNI_UTIL_FIND_CLASS.
        ClassInitializerUtil.tryLoadClasses(Quiche.class,
                // netty_quic_boringssl
                byte[].class, String.class, BoringSSLCertificateCallback.class,
                BoringSSLCertificateVerifyCallback.class, BoringSSLHandshakeCompleteCallback.class,

                //netty_quic_quiche
                QuicheLogger.class
        );

        try {
            // First, try calling a side-effect free JNI method to see if the library was already
            // loaded by the application.
            quiche_version();
        } catch (UnsatisfiedLinkError ignore) {
            // The library was not previously loaded, load it now.
            loadNativeLibrary();
        }

        // Let's enable debug logging for quiche if its enabled in our logger.
        if (DEBUG_LOGGING_ENABLED) {
            quiche_enable_debug_logging(new QuicheLogger(logger));
        }
    }

    private static void loadNativeLibrary() {
        // This needs to be kept in sync with what is defined in netty_quic_quiche.c
        String libName = "netty_quiche";
        ClassLoader cl = PlatformDependent.getClassLoader(Quiche.class);

        if (!PlatformDependent.isAndroid()) {
            libName += '_' + PlatformDependent.normalizedOs()
                    + '_' + PlatformDependent.normalizedArch();
        }

        try {
            NativeLibraryLoader.load(libName, cl);
        } catch (UnsatisfiedLinkError e) {
            logger.debug("Failed to load {}", libName, e);
            throw e;
        }
    }

    static final short AF_INET = (short) QuicheNativeStaticallyReferencedJniMethods.afInet();
    static final short AF_INET6 = (short) QuicheNativeStaticallyReferencedJniMethods.afInet6();
    static final int SIZEOF_SOCKADDR_STORAGE = QuicheNativeStaticallyReferencedJniMethods.sizeofSockaddrStorage();
    static final int SIZEOF_SOCKADDR_IN = QuicheNativeStaticallyReferencedJniMethods.sizeofSockaddrIn();
    static final int SIZEOF_SOCKADDR_IN6 = QuicheNativeStaticallyReferencedJniMethods.sizeofSockaddrIn6();
    static final int SOCKADDR_IN_OFFSETOF_SIN_FAMILY =
            QuicheNativeStaticallyReferencedJniMethods.sockaddrInOffsetofSinFamily();
    static final int SOCKADDR_IN_OFFSETOF_SIN_PORT =
            QuicheNativeStaticallyReferencedJniMethods.sockaddrInOffsetofSinPort();
    static final int SOCKADDR_IN_OFFSETOF_SIN_ADDR =
            QuicheNativeStaticallyReferencedJniMethods.sockaddrInOffsetofSinAddr();
    static final int IN_ADDRESS_OFFSETOF_S_ADDR = QuicheNativeStaticallyReferencedJniMethods.inAddressOffsetofSAddr();
    static final int SOCKADDR_IN6_OFFSETOF_SIN6_FAMILY =
            QuicheNativeStaticallyReferencedJniMethods.sockaddrIn6OffsetofSin6Family();
    static final int SOCKADDR_IN6_OFFSETOF_SIN6_PORT =
            QuicheNativeStaticallyReferencedJniMethods.sockaddrIn6OffsetofSin6Port();
    static final int SOCKADDR_IN6_OFFSETOF_SIN6_FLOWINFO =
            QuicheNativeStaticallyReferencedJniMethods.sockaddrIn6OffsetofSin6Flowinfo();
    static final int SOCKADDR_IN6_OFFSETOF_SIN6_ADDR =
            QuicheNativeStaticallyReferencedJniMethods.sockaddrIn6OffsetofSin6Addr();
    static final int SOCKADDR_IN6_OFFSETOF_SIN6_SCOPE_ID =
            QuicheNativeStaticallyReferencedJniMethods.sockaddrIn6OffsetofSin6ScopeId();
    static final int IN6_ADDRESS_OFFSETOF_S6_ADDR =
            QuicheNativeStaticallyReferencedJniMethods.in6AddressOffsetofS6Addr();
    static final int SIZEOF_SOCKLEN_T = QuicheNativeStaticallyReferencedJniMethods.sizeofSocklenT();
    static final int SIZEOF_SIZE_T = QuicheNativeStaticallyReferencedJniMethods.sizeofSizeT();

    static final int SIZEOF_TIMESPEC = QuicheNativeStaticallyReferencedJniMethods.sizeofTimespec();

    static final int SIZEOF_TIME_T = QuicheNativeStaticallyReferencedJniMethods.sizeofTimeT();
    static final int SIZEOF_LONG = QuicheNativeStaticallyReferencedJniMethods.sizeofLong();

    static final int TIMESPEC_OFFSETOF_TV_SEC =
            QuicheNativeStaticallyReferencedJniMethods.timespecOffsetofTvSec();

    static final int TIMESPEC_OFFSETOF_TV_NSEC =
            QuicheNativeStaticallyReferencedJniMethods.timespecOffsetofTvNsec();

    static final int QUICHE_RECV_INFO_OFFSETOF_FROM =
            QuicheNativeStaticallyReferencedJniMethods.quicheRecvInfoOffsetofFrom();
    static final int QUICHE_RECV_INFO_OFFSETOF_FROM_LEN =
            QuicheNativeStaticallyReferencedJniMethods.quicheRecvInfoOffsetofFromLen();

    static final int QUICHE_RECV_INFO_OFFSETOF_TO =
            QuicheNativeStaticallyReferencedJniMethods.quicheRecvInfoOffsetofTo();
    static final int QUICHE_RECV_INFO_OFFSETOF_TO_LEN =
            QuicheNativeStaticallyReferencedJniMethods.quicheRecvInfoOffsetofToLen();

    static final int SIZEOF_QUICHE_RECV_INFO = QuicheNativeStaticallyReferencedJniMethods.sizeofQuicheRecvInfo();
    static final int QUICHE_SEND_INFO_OFFSETOF_TO =
            QuicheNativeStaticallyReferencedJniMethods.quicheSendInfoOffsetofTo();
    static final int QUICHE_SEND_INFO_OFFSETOF_TO_LEN =
            QuicheNativeStaticallyReferencedJniMethods.quicheSendInfoOffsetofToLen();

    static final int QUICHE_SEND_INFO_OFFSETOF_FROM =
            QuicheNativeStaticallyReferencedJniMethods.quicheSendInfoOffsetofFrom();
    static final int QUICHE_SEND_INFO_OFFSETOF_FROM_LEN =
            QuicheNativeStaticallyReferencedJniMethods.quicheSendInfoOffsetofFromLen();

    static final int QUICHE_SEND_INFO_OFFSETOF_AT =
            QuicheNativeStaticallyReferencedJniMethods.quicheSendInfoOffsetofAt();
    static final int SIZEOF_QUICHE_SEND_INFO = QuicheNativeStaticallyReferencedJniMethods.sizeofQuicheSendInfo();

    static final int QUICHE_PROTOCOL_VERSION = QuicheNativeStaticallyReferencedJniMethods.quiche_protocol_version();
    static final int QUICHE_MAX_CONN_ID_LEN = QuicheNativeStaticallyReferencedJniMethods.quiche_max_conn_id_len();

    /**
     * See QUICHE_SHUTDOWN_READ.
     */
    static final int QUICHE_SHUTDOWN_READ = QuicheNativeStaticallyReferencedJniMethods.quiche_shutdown_read();

    /**
     * See QUICHE_SHUTDOWN_WRITE.
     */
    static final int QUICHE_SHUTDOWN_WRITE = QuicheNativeStaticallyReferencedJniMethods.quiche_shutdown_write();

    /**
     * See QUICHE_ERR_DONE.
     */
    static final int QUICHE_ERR_DONE = QuicheNativeStaticallyReferencedJniMethods.quiche_err_done();

    /**
     * See
     * QUICHE_ERR_BUFFER_TOO_SHORT.
     */
    static final int QUICHE_ERR_BUFFER_TOO_SHORT =
            QuicheNativeStaticallyReferencedJniMethods.quiche_err_buffer_too_short();

    /**
     * See
     * QUICHE_ERR_UNKNOWN_VERSION.
     */
    static final int QUICHE_ERR_UNKNOWN_VERSION =
            QuicheNativeStaticallyReferencedJniMethods.quiche_err_unknown_version();

    /**
     * See
     * QUICHE_ERR_INVALID_FRAME.
     */
    static final int QUICHE_ERR_INVALID_FRAME = QuicheNativeStaticallyReferencedJniMethods.quiche_err_invalid_frame();

    /**
     * See
     * QUICHE_ERR_INVALID_PACKET.
     */
    static final int QUICHE_ERR_INVALID_PACKET = QuicheNativeStaticallyReferencedJniMethods.quiche_err_invalid_packet();

    /**
     * See
     * QUICHE_ERR_INVALID_STATE.
     */
    static final int QUICHE_ERR_INVALID_STATE = QuicheNativeStaticallyReferencedJniMethods.quiche_err_invalid_state();

    /**
     * See 
     *     QUICHE_ERR_INVALID_STREAM_STATE.
     */
    static final int QUICHE_ERR_INVALID_STREAM_STATE =
            QuicheNativeStaticallyReferencedJniMethods.quiche_err_invalid_stream_state();

    /**
     * See 
     *     QUICHE_ERR_INVALID_TRANSPORT_PARAM.
     */
    static final int QUICHE_ERR_INVALID_TRANSPORT_PARAM =
            QuicheNativeStaticallyReferencedJniMethods.quiche_err_invalid_transport_param();

    /**
     * See 
     *     QUICHE_ERR_CRYPTO_FAIL.
     */
    static final int QUICHE_ERR_CRYPTO_FAIL = QuicheNativeStaticallyReferencedJniMethods.quiche_err_crypto_fail();

    /**
     * See 
     *     QUICHE_ERR_TLS_FAIL.
     */
    static final int QUICHE_ERR_TLS_FAIL = QuicheNativeStaticallyReferencedJniMethods.quiche_err_tls_fail();

    /**
     * See 
     *     QUICHE_ERR_FLOW_CONTROL.
     */
    static final int QUICHE_ERR_FLOW_CONTROL = QuicheNativeStaticallyReferencedJniMethods.quiche_err_flow_control();

    /**
     * See 
     *     QUICHE_ERR_STREAM_LIMIT.
     */
    static final int QUICHE_ERR_STREAM_LIMIT = QuicheNativeStaticallyReferencedJniMethods.quiche_err_stream_limit();

    /**
     * See 
     *     QUICHE_ERR_FINAL_SIZE.
     */
    static final int QUICHE_ERR_FINAL_SIZE = QuicheNativeStaticallyReferencedJniMethods.quiche_err_final_size();

    /**
     * See 
     *     QUICHE_ERR_CONGESTION_CONTROL.
     */
    static final int QUICHE_ERR_CONGESTION_CONTROL =
            QuicheNativeStaticallyReferencedJniMethods.quiche_err_congestion_control();

    /**
     * See QUICHE_ERR_STREAM_STOPPED.
     */
    static final int QUICHE_ERR_STREAM_RESET =
            QuicheNativeStaticallyReferencedJniMethods.quiche_err_stream_reset();

    /**
     * See 
     *     QUICHE_ERR_STREAM_STOPPED.
     */
    static final int QUICHE_ERR_STREAM_STOPPED =
            QuicheNativeStaticallyReferencedJniMethods.quiche_err_stream_stopped();


    // Too many identifiers were provided.
    static final int QUICHE_ERR_ID_LIMIT =
            QuicheNativeStaticallyReferencedJniMethods.quiche_err_id_limit();

    // Not enough available identifiers.
    static final int QUICHE_ERR_OUT_OF_IDENTIFIERS =
            QuicheNativeStaticallyReferencedJniMethods.quiche_err_out_of_identifiers();

    // Error in key update.
    static final int QUICHE_ERR_KEY_UPDATE =
            QuicheNativeStaticallyReferencedJniMethods.quiche_err_key_update();

    static final int QUICHE_ERR_CRYPTO_BUFFER_EXCEEDED =
            QuicheNativeStaticallyReferencedJniMethods.quiche_err_crypto_buffer_exceeded();

    /**
     * See 
     *     QUICHE_CC_RENO.
     */
    static final int QUICHE_CC_RENO = QuicheNativeStaticallyReferencedJniMethods.quiche_cc_reno();

    /**
     * See 
     *     QUICHE_CC_CUBIC.
     */
    static final int QUICHE_CC_CUBIC = QuicheNativeStaticallyReferencedJniMethods.quiche_cc_cubic();

    /**
     * See 
     *     QUICHE_CC_BBR.
     */
    static final int QUICHE_CC_BBR = QuicheNativeStaticallyReferencedJniMethods.quiche_cc_bbr();

    static final int QUICHE_PATH_EVENT_NEW = QuicheNativeStaticallyReferencedJniMethods.quiche_path_event_new();
    static final int QUICHE_PATH_EVENT_VALIDATED = QuicheNativeStaticallyReferencedJniMethods.quiche_path_event_validated();
    static final int QUICHE_PATH_EVENT_FAILED_VALIDATION = QuicheNativeStaticallyReferencedJniMethods.quiche_path_event_failed_validation();
    static final int QUICHE_PATH_EVENT_CLOSED = QuicheNativeStaticallyReferencedJniMethods.quiche_path_event_closed();
    static final int QUICHE_PATH_EVENT_REUSED_SOURCE_CONNECTION_ID = QuicheNativeStaticallyReferencedJniMethods.quiche_path_event_reused_source_connection_id();
    static final int QUICHE_PATH_EVENT_PEER_MIGRATED = QuicheNativeStaticallyReferencedJniMethods.quiche_path_event_peer_migrated();

    /**
     * See quiche_version.
     */
    @Nullable
    static native String quiche_version();

    /**
     * See
     * quiche_version_is_supported.
     */
    static native boolean quiche_version_is_supported(int version);

    /**
     * See quiche_header_info.
     */
    static native int quiche_header_info(long bufAddr, int bufLength, int dcil, long versionAddr, long typeAddr,
                                         long scidAddr, long scidLenAddr, long dcidAddr, long dcidLenAddr,
                                         long tokenAddr, long tokenLenAddr);
    /**
     * See quiche_negotiate_version.
     */
    static native int quiche_negotiate_version(
            long scidAddr, int scidLen, long dcidAddr, int dcidLen, long outAddr, int outLen);

    /**
     * See quiche_retry.
     */
    static native int quiche_retry(long scidAddr, int scidLen, long dcidAddr, int dcidLen, long newScidAddr,
                                   int newScidLen, long tokenAddr, int tokenLen, int version, long outAddr, int outLen);

    /**
     * See quiche_conn_new_with_tls.
     */
    static native long quiche_conn_new_with_tls(long scidAddr, int scidLen, long odcidAddr, int odcidLen,
                                                long localAddr, int localLen,
                                                long peerAddr, int peerLen,
                                                long configAddr, long ssl, boolean isServer);

    /**
     * See 
     *     quiche_conn_set_qlog_path.
     */
    static native boolean quiche_conn_set_qlog_path(long connAddr, String path, String logTitle, String logDescription);

    /**
     * See quiche_conn_recv.
     */
    static native int quiche_conn_recv(long connAddr, long bufAddr, int bufLen, long infoAddr);

    /**
     * See quiche_conn_send.
     */
    static native int quiche_conn_send(long connAddr, long outAddr, int outLen, long infoAddr);

    /**
     * See quiche_conn_free.
     */
    static native void quiche_conn_free(long connAddr);

    @Nullable
    static QuicConnectionCloseEvent quiche_conn_peer_error(long connAddr) {
        Object[] error =  quiche_conn_peer_error0(connAddr);
        if (error == null) {
            return null;
        }
        return new QuicConnectionCloseEvent((Boolean) error[0], (Integer) error[1], (byte[]) error[2]);
    }

    private static native Object @Nullable [] quiche_conn_peer_error0(long connAddr);

    /**
     * See 
     *     quiche_conn_peer_streams_left_bidi.
     */
    static native long quiche_conn_peer_streams_left_bidi(long connAddr);

    /**
     * See 
     *     quiche_conn_peer_streams_left_uni.
     */
    static native long quiche_conn_peer_streams_left_uni(long connAddr);

    /**
     * See
     * quiche_conn_stream_priority.
     */
    static native int quiche_conn_stream_priority(
            long connAddr, long streamId, byte urgency, boolean incremental);

    static native int quiche_conn_send_quantum(long connAddr);

    /**
     * See quiche_conn_trace_id.
     */
    static native byte @Nullable [] quiche_conn_trace_id(long connAddr);

    static native byte[] quiche_conn_source_id(long connAddr);

    static native byte[] quiche_conn_destination_id(long connAddr);

    /**
     * See quiche_conn_stream_recv.
     */
    static native int quiche_conn_stream_recv(long connAddr, long streamId, long outAddr, int bufLen, long finAddr);

    /**
     * See quiche_conn_stream_send.
     */
    static native int quiche_conn_stream_send(long connAddr, long streamId, long bufAddr, int bufLen, boolean fin);

    /**
     * See
     * quiche_conn_stream_shutdown.
     */
    static native int quiche_conn_stream_shutdown(long connAddr, long streamId, int direction, long err);

    /**
     * See
     * quiche_conn_stream_capacity.
     */
    static native int quiche_conn_stream_capacity(long connAddr, long streamId);

    /**
     * See
     * quiche_conn_stream_finished.
     */
    static native boolean quiche_conn_stream_finished(long connAddr, long streamId);

    /**
     * See
     * quiche_conn_close.
     */
    static native int quiche_conn_close(long connAddr, boolean app, long err, long reasonAddr, int reasonLen);

    /**
     * See
     * quiche_conn_is_established.
     */
    static native boolean quiche_conn_is_established(long connAddr);

    /**
     * See
     * quiche_conn_is_in_early_data.
     */
    static native boolean quiche_conn_is_in_early_data(long connAddr);

    /**
     * See
     * quiche_conn_is_closed.
     */
    static native boolean quiche_conn_is_closed(long connAddr);

    /**
     * See
     * quiche_conn_is_timed_out.
     */
    static native boolean quiche_conn_is_timed_out(long connAddr);

    /**
     * See
     * quiche_conn_stats.
     * The implementation relies on all fields of
     * quiche_stats being numerical.
     * The assumption made allows passing primitive array rather than dealing with objects.
     */
    static native long @Nullable [] quiche_conn_stats(long connAddr);

    /**
     * See
     * 
     *     quiche_conn_stats.
     */
    static native long @Nullable [] quiche_conn_peer_transport_params(long connAddr);

    /**
     * See
     * quiche_conn_timeout_as_nanos.
     */
    static native long quiche_conn_timeout_as_nanos(long connAddr);

    /**
     * See
     * quiche_conn_on_timeout.
     */
    static native void quiche_conn_on_timeout(long connAddr);

    /**
     * See
     * quiche_conn_readable.
     */
    static native long quiche_conn_readable(long connAddr);

    /**
     * See
     * quiche_conn_writable.
     */
    static native long quiche_conn_writable(long connAddr);

    /**
     * See
     * quiche_stream_iter_next.
     *
     * This method will fill the {@code streamIds} array and return the number of streams that were filled into
     * the array. If the number is the same as the length of the array you should call it again until it returns
     * less to ensure you process all the streams later on.
     */
    static native int quiche_stream_iter_next(long iterAddr, long[] streamIds);

    /**
     * See
     * quiche_stream_iter_free.
     *
     */
    static native void quiche_stream_iter_free(long iterAddr);


    /**
     * See
     * quiche_conn_path_stats.
     */
    static native Object @Nullable [] quiche_conn_path_stats(long connAddr, long streamIdx);

    /**
     * See
     * 
     *     quiche_conn_dgram_max_writable_len.
     */
    static native int quiche_conn_dgram_max_writable_len(long connAddr);

    /**
     * See
     * 
     *     quiche_conn_dgram_recv_front_len.
     */
    static native int quiche_conn_dgram_recv_front_len(long connAddr);

    /**
     * See
     * 
     *     quiche_conn_dgram_recv.
     */
    static native int quiche_conn_dgram_recv(long connAddr, long buf, int size);

    /**
     * See
     * 
     *     quiche_conn_dgram_send.
     */
    static native int quiche_conn_dgram_send(long connAddr, long buf, int size);

    /**
     * See
     * 
     *     quiche_conn_set_session.
     */
    static native int quiche_conn_set_session(long connAddr, byte[] sessionBytes);

    /**
     * See
     * 
     *     quiche_conn_max_send_udp_payload_size.
     */
    static native int quiche_conn_max_send_udp_payload_size(long connAddr);

    static native int quiche_conn_scids_left(long connAddr);

    static native long quiche_conn_new_scid(long connAddr, long scidAddr, int scidLen, byte[] resetToken, boolean retire_if_needed, long seq);

    static native byte @Nullable [] quiche_conn_retired_scid_next(long connAddr);

    static native long quiche_conn_path_event_next(long connAddr);
    static native int quiche_path_event_type(long pathEvent);
    static native void quiche_path_event_free(long pathEvent);
    static native Object[] quiche_path_event_new(long pathEvent);
    static native Object[] quiche_path_event_validated(long pathEvent);
    static native Object[] quiche_path_event_failed_validation(long pathEvent);
    static native Object[]  quiche_path_event_closed(long pathEvent);
    static native Object[] quiche_path_event_reused_source_connection_id(long pathEvent);
    static native Object[] quiche_path_event_peer_migrated(long pathEvent);

    /**
     * See
     * quiche_config_new.
     */
    static native long quiche_config_new(int version);

    /**
     * See
     * 
     *     quiche_config_grease.
     */
    static native void quiche_config_grease(long configAddr, boolean value);

    /**
     * See
     * 
     *     quiche_config_set_max_idle_timeout.
     */
    static native void quiche_config_set_max_idle_timeout(long configAddr, long value);

    /**
     * See
     * 
     *     quiche_config_set_max_recv_udp_payload_size.
     */
    static native void quiche_config_set_max_recv_udp_payload_size(long configAddr, long value);

    /**
     * See
     * 
     *     quiche_config_set_max_recv_udp_payload_size.
     */
    static native void quiche_config_set_max_send_udp_payload_size(long configAddr, long value);

    /**
     * See
     * 
     *     quiche_config_set_initial_max_data.
     */
    static native void quiche_config_set_initial_max_data(long configAddr, long value);

    /**
     * See
     * 
     *     quiche_config_set_initial_max_stream_data_bidi_local.
     */
    static native void quiche_config_set_initial_max_stream_data_bidi_local(long configAddr, long value);

    /**
     * See
     * 
     *     quiche_config_set_initial_max_stream_data_bidi_remote.
     */
    static native void quiche_config_set_initial_max_stream_data_bidi_remote(long configAddr, long value);

    /**
     * See
     * 
     *     quiche_config_set_initial_max_stream_data_uni.
     */
    static native void quiche_config_set_initial_max_stream_data_uni(long configAddr, long value);

    /**
     * See
     * 
     *     quiche_config_set_initial_max_streams_bidi.
     */
    static native void quiche_config_set_initial_max_streams_bidi(long configAddr, long value);

    /**
     * See
     * 
     *     quiche_config_set_initial_max_streams_uni.
     */
    static native void quiche_config_set_initial_max_streams_uni(long configAddr, long value);

    /**
     * See
     * 
     *     quiche_config_set_ack_delay_exponent.
     */
    static native void quiche_config_set_ack_delay_exponent(long configAddr, long value);

    /**
     * See
     * 
     *     quiche_config_set_max_ack_delay.
     */
    static native void quiche_config_set_max_ack_delay(long configAddr, long value);

    /**
     * See
     * 
     *     quiche_config_set_disable_active_migration.
     */
    static native void quiche_config_set_disable_active_migration(long configAddr, boolean value);

    /**
     * See
     * 
     *     quiche_config_set_cc_algorithm.
     */
    static native void quiche_config_set_cc_algorithm(long configAddr, int algo);

    /**
     * See
     * 
     *     quiche_config_enable_hystart.
     */
    static native void quiche_config_enable_hystart(long configAddr, boolean value);

    /**
     * See
     * 
     *     quiche_config_enable_dgram.
     */
    static native void quiche_config_enable_dgram(long configAddr, boolean enable,
                                                  int recv_queue_len, int send_queue_len);

    // Sets the limit of active connection IDs.
    static native void quiche_config_set_active_connection_id_limit(long configAddr, long value);

    // Sets the initial stateless reset token.
    static native void quiche_config_set_stateless_reset_token(long configAddr, byte[] token);

    /**
     * See
     * 
     *     quiche_config_free.
     */
    static native void quiche_config_free(long configAddr);

    /**
     * See
     * quiche_config_new.
     */
    private static native void quiche_enable_debug_logging(QuicheLogger logger);

    private static native long buffer_memory_address(ByteBuffer buffer);

    static native int sockaddr_cmp(long addr, long addr2);

    /**
     * Returns the memory address if the {@link ByteBuf} taking the readerIndex into account.
     *
     * @param buf   the {@link ByteBuf} of which we want to obtain the memory address
     *              (taking its {@link ByteBuf#readerIndex()} into account).
     * @return      the memory address of this {@link ByteBuf}s readerIndex.
     */
    static long readerMemoryAddress(ByteBuf buf) {
        return memoryAddress(buf, buf.readerIndex(), buf.readableBytes());
    }

    /**
     * Returns the memory address if the {@link ByteBuf} taking the writerIndex into account.
     *
     * @param buf   the {@link ByteBuf} of which we want to obtain the memory address
     *              (taking its {@link ByteBuf#writerIndex()} into account).
     * @return      the memory address of this {@link ByteBuf}s writerIndex.
     */
    static long writerMemoryAddress(ByteBuf buf) {
        return memoryAddress(buf, buf.writerIndex(), buf.writableBytes());
    }

    /**
     * Returns the memory address if the {@link ByteBuf} taking the offset into account.
     *
     * @param buf       the {@link ByteBuf} of which we want to obtain the memory address
     *                  (taking the {@code offset} into account).
     * @param offset    the offset of the memory address.
     * @param len       the length of the {@link ByteBuf}.
     * @return          the memory address of this {@link ByteBuf}s offset.
     */
    static long memoryAddress(ByteBuf buf, int offset, int len) {
        assert buf.isDirect();
        if (buf.hasMemoryAddress()) {
            return buf.memoryAddress() + offset;
        }
        return memoryAddressWithPosition(buf.internalNioBuffer(offset, len));
    }

    /**
     * Returns the memory address of the given {@link ByteBuffer} taking its current {@link ByteBuffer#position()} into
     * account.
     *
     * @param buf   the {@link ByteBuffer} of which we want to obtain the memory address
     *              (taking its {@link ByteBuffer#position()} into account).
     * @return      the memory address of this {@link ByteBuffer}s position.
     */
    static long memoryAddressWithPosition(ByteBuffer buf) {
        assert buf.isDirect();
        return buffer_memory_address(buf) + buf.position();
    }

    @SuppressWarnings("deprecation")
    static ByteBuf allocateNativeOrder(int capacity) {
        // Just use Unpooled as the life-time of these buffers is long.
        ByteBuf buffer = Unpooled.directBuffer(capacity);

        // As we use the buffers as pointers to int etc we need to ensure we use the right oder so we will
        // see the right value when we read primitive values.
        return PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? buffer : buffer.order(ByteOrder.LITTLE_ENDIAN);
    }

    static boolean shouldClose(int res)  {
        return res == Quiche.QUICHE_ERR_CRYPTO_FAIL || res == Quiche.QUICHE_ERR_TLS_FAIL;
    }

    /**
     * Returns {@code true} if both {@link ByteBuffer}s have the same {@code sock_addr} stored.
     *
     * @param memory    the first {@link ByteBuffer} which holds a {@code quiche_recv_info}.
     * @param memory2   the second {@link ByteBuffer} which holds a {@code quiche_recv_info}.
     * @return          {@code true} if both {@link ByteBuffer}s have the same {@code sock_addr} stored, {@code false}
     *                  otherwise.
     */
    static boolean isSameAddress(ByteBuffer memory, ByteBuffer memory2, int addressOffset) {
        long address1 = Quiche.memoryAddressWithPosition(memory) + addressOffset;
        long address2 = Quiche.memoryAddressWithPosition(memory2) + addressOffset;
        return SockaddrIn.cmp(address1, address2) == 0;
    }

    static void setPrimitiveValue(ByteBuffer memory, int offset, int valueType, long value) {
        switch (valueType) {
            case 1:
                memory.put(offset, (byte) value);
                break;
            case 2:
                memory.putShort(offset, (short) value);
                break;
            case 4:
                memory.putInt(offset, (int) value);
                break;
            case 8:
                memory.putLong(offset, value);
                break;
            default:
                throw new IllegalStateException();
        }
    }

    static long getPrimitiveValue(ByteBuffer memory, int offset, int valueType) {
        switch (valueType) {
            case 1:
                return memory.get(offset);
            case 2:
                return memory.getShort(offset);
            case 4:
                return memory.getInt(offset);
            case 8:
                return memory.getLong(offset);
            default:
                throw new IllegalStateException();
        }
    }

    // See https://github.com/cloudflare/quiche/commit/1d00ee1bb2256dfd99ba0cb2dfac72fe1e59407f
    static {
        ERROR_MAPPINGS.put(QUICHE_ERR_DONE,
                new QuicTransportErrorHolder(QuicTransportError.NO_ERROR, "QUICHE_ERR_DONE"));
        ERROR_MAPPINGS.put(QUICHE_ERR_INVALID_FRAME,
                new QuicTransportErrorHolder(QuicTransportError.FRAME_ENCODING_ERROR, "QUICHE_ERR_INVALID_FRAME"));
        ERROR_MAPPINGS.put(QUICHE_ERR_INVALID_STREAM_STATE,
                new QuicTransportErrorHolder(QuicTransportError.STREAM_STATE_ERROR, "QUICHE_ERR_INVALID_STREAM_STATE"));
        ERROR_MAPPINGS.put(QUICHE_ERR_INVALID_TRANSPORT_PARAM,
                new QuicTransportErrorHolder(QuicTransportError.TRANSPORT_PARAMETER_ERROR, "QUICHE_ERR_INVALID_TRANSPORT_PARAM"));
        ERROR_MAPPINGS.put(QUICHE_ERR_FLOW_CONTROL,
                new QuicTransportErrorHolder(QuicTransportError.FLOW_CONTROL_ERROR, "QUICHE_ERR_FLOW_CONTROL"));
        ERROR_MAPPINGS.put(QUICHE_ERR_STREAM_LIMIT,
                new QuicTransportErrorHolder(QuicTransportError.STREAM_LIMIT_ERROR, "QUICHE_ERR_STREAM_LIMIT"));
        ERROR_MAPPINGS.put(QUICHE_ERR_ID_LIMIT,
                new QuicTransportErrorHolder(QuicTransportError.CONNECTION_ID_LIMIT_ERROR, "QUICHE_ERR_ID_LIMIT"));
        ERROR_MAPPINGS.put(QUICHE_ERR_FINAL_SIZE,
                new QuicTransportErrorHolder(QuicTransportError.FINAL_SIZE_ERROR, "QUICHE_ERR_FINAL_SIZE"));
        ERROR_MAPPINGS.put(QUICHE_ERR_CRYPTO_BUFFER_EXCEEDED,
                new QuicTransportErrorHolder(QuicTransportError.CRYPTO_BUFFER_EXCEEDED, "QUICHE_ERR_CRYPTO_BUFFER_EXCEEDED"));
        ERROR_MAPPINGS.put(QUICHE_ERR_KEY_UPDATE,
                new QuicTransportErrorHolder(QuicTransportError.KEY_UPDATE_ERROR, "QUICHE_ERR_KEY_UPDATE"));

        // Should the code be something different ?
        ERROR_MAPPINGS.put(QUICHE_ERR_TLS_FAIL,
                new QuicTransportErrorHolder(QuicTransportError.valueOf(0x0100), "QUICHE_ERR_TLS_FAIL"));
        ERROR_MAPPINGS.put(QUICHE_ERR_CRYPTO_FAIL,
                new QuicTransportErrorHolder(QuicTransportError.valueOf(0x0100), "QUICHE_ERR_CRYPTO_FAIL"));

        ERROR_MAPPINGS.put(QUICHE_ERR_BUFFER_TOO_SHORT,
                new QuicTransportErrorHolder(QuicTransportError.PROTOCOL_VIOLATION, "QUICHE_ERR_BUFFER_TOO_SHORT"));
        ERROR_MAPPINGS.put(QUICHE_ERR_UNKNOWN_VERSION, new QuicTransportErrorHolder(QuicTransportError.PROTOCOL_VIOLATION, "QUICHE_ERR_UNKNOWN_VERSION"));
        ERROR_MAPPINGS.put(QUICHE_ERR_INVALID_PACKET, new QuicTransportErrorHolder(QuicTransportError.PROTOCOL_VIOLATION, "QUICHE_ERR_INVALID_PACKET"));
        ERROR_MAPPINGS.put(QUICHE_ERR_INVALID_STATE, new QuicTransportErrorHolder(QuicTransportError.PROTOCOL_VIOLATION, "QUICHE_ERR_INVALID_STATE"));
        ERROR_MAPPINGS.put(QUICHE_ERR_CONGESTION_CONTROL, new QuicTransportErrorHolder(QuicTransportError.PROTOCOL_VIOLATION, "QUICHE_ERR_CONGESTION_CONTROL"));
        ERROR_MAPPINGS.put(QUICHE_ERR_STREAM_STOPPED, new QuicTransportErrorHolder(QuicTransportError.PROTOCOL_VIOLATION, "QUICHE_ERR_STREAM_STOPPED"));
        ERROR_MAPPINGS.put(QUICHE_ERR_OUT_OF_IDENTIFIERS, new QuicTransportErrorHolder(QuicTransportError.PROTOCOL_VIOLATION, "QUICHE_ERR_OUT_OF_IDENTIFIERS"));
    }

    static Exception convertToException(int result) {
        QuicTransportErrorHolder holder = ERROR_MAPPINGS.get(result);
        assert holder != null;
        Exception exception = new QuicException(holder.error + ": " + holder.quicheErrorName, holder.error);
        if (result == QUICHE_ERR_TLS_FAIL) {
            String lastSslError = BoringSSL.ERR_last_error();
            final SSLHandshakeException sslExc = new SSLHandshakeException(lastSslError);
            sslExc.initCause(exception);
            return sslExc;
        }
        if (result == QUICHE_ERR_CRYPTO_FAIL) {
            return new SSLException(exception);
        }
        return exception;
    }

    private static final class QuicTransportErrorHolder {
        private final QuicTransportError error;
        private final String quicheErrorName;

        QuicTransportErrorHolder(QuicTransportError error, String quicheErrorName) {
            this.error = error;
            this.quicheErrorName = quicheErrorName;
        }
    }

    private Quiche() { }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy