Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
bator.netty-incubator-codec-native-quic.0.0.69.Final.source-code.netty_quic_quiche.c Maven / Gradle / Ivy
/*
* 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.
*/
#include
#include
#include
#include
#include
#ifdef _WIN32
#include
#include
// This needs to be included for quiche_recv_info and quiche_send_info structs.
#include
#else
#include
#include
#include
// This needs to be included for quiche_recv_info and quiche_send_info structs.
#include
#endif // _WIN32
#include
#include "netty_jni_util.h"
#include "netty_quic_boringssl.h"
#include "netty_quic.h"
// Add define if NETTY_QUIC_BUILD_STATIC is defined so it is picked up in netty_jni_util.c
#ifdef NETTY_QUIC_BUILD_STATIC
#define NETTY_JNI_UTIL_BUILD_STATIC
#endif
#define STATICALLY_CLASSNAME "io/netty/incubator/codec/quic/QuicheNativeStaticallyReferencedJniMethods"
#define QUICHE_CLASSNAME "io/netty/incubator/codec/quic/Quiche"
#define LIBRARYNAME "netty_quiche"
static jweak quiche_logger_class_weak = NULL;
static jmethodID quiche_logger_class_log = NULL;
static jobject quiche_logger = NULL;
static JavaVM *global_vm = NULL;
static jclass integer_class = NULL;
static jmethodID integer_class_valueof = NULL;
static jclass boolean_class = NULL;
static jmethodID boolean_class_valueof = NULL;
static jclass long_class = NULL;
static jmethodID long_class_valueof = NULL;
static jclass inet4address_class = NULL;
static jmethodID inet4address_class_get_by_address = NULL;
static jclass inet6address_class = NULL;
static jmethodID inet6address_class_get_by_address = NULL;
static jclass inetsocketaddress_class = NULL;
static jmethodID inetsocketaddress_class_constructor = NULL;
static jclass object_class = NULL;
static char const* staticPackagePrefix = NULL;
jint quic_get_java_env(JNIEnv **env)
{
return (*global_vm)->GetEnv(global_vm, (void **)env, NETTY_JNI_UTIL_JNI_VERSION);
}
static jint netty_quiche_afInet(JNIEnv* env, jclass clazz) {
return AF_INET;
}
static jint netty_quiche_afInet6(JNIEnv* env, jclass clazz) {
return AF_INET6;
}
static jint netty_quiche_sizeofSockaddrIn(JNIEnv* env, jclass clazz) {
return sizeof(struct sockaddr_in);
}
static jint netty_quiche_sizeofSockaddrIn6(JNIEnv* env, jclass clazz) {
return sizeof(struct sockaddr_in6);
}
static jint netty_quiche_sockaddrInOffsetofSinFamily(JNIEnv* env, jclass clazz) {
return offsetof(struct sockaddr_in, sin_family);
}
static jint netty_quiche_sockaddrInOffsetofSinPort(JNIEnv* env, jclass clazz) {
return offsetof(struct sockaddr_in, sin_port);
}
static jint netty_quiche_sockaddrInOffsetofSinAddr(JNIEnv* env, jclass clazz) {
return offsetof(struct sockaddr_in, sin_addr);
}
static jint netty_quiche_inAddressOffsetofSAddr(JNIEnv* env, jclass clazz) {
return offsetof(struct in_addr, s_addr);
}
static jint netty_quiche_sockaddrIn6OffsetofSin6Family(JNIEnv* env, jclass clazz) {
return offsetof(struct sockaddr_in6, sin6_family);
}
static jint netty_quiche_sockaddrIn6OffsetofSin6Port(JNIEnv* env, jclass clazz) {
return offsetof(struct sockaddr_in6, sin6_port);
}
static jint netty_quiche_sockaddrIn6OffsetofSin6Flowinfo(JNIEnv* env, jclass clazz) {
return offsetof(struct sockaddr_in6, sin6_flowinfo);
}
static jint netty_quiche_sockaddrIn6OffsetofSin6Addr(JNIEnv* env, jclass clazz) {
return offsetof(struct sockaddr_in6, sin6_addr);
}
static jint netty_quiche_sockaddrIn6OffsetofSin6ScopeId(JNIEnv* env, jclass clazz) {
return offsetof(struct sockaddr_in6, sin6_scope_id);
}
static jint netty_quiche_in6AddressOffsetofS6Addr(JNIEnv* env, jclass clazz) {
return offsetof(struct in6_addr, s6_addr);
}
static jint netty_quiche_sizeofSockaddrStorage(JNIEnv* env, jclass clazz) {
return sizeof(struct sockaddr_storage);
}
static jint netty_quiche_sizeofSizeT(JNIEnv* env, jclass clazz) {
return sizeof(size_t);
}
static jint netty_quiche_sizeofSocklenT(JNIEnv* env, jclass clazz) {
return sizeof(socklen_t);
}
static jint netty_quiche_sizeofTimespec(JNIEnv* env, jclass clazz) {
return sizeof(struct timespec);
}
static jint netty_quiche_sizeofTimeT(JNIEnv* env, jclass clazz) {
return sizeof(time_t);
}
static jint netty_quiche_sizeofLong(JNIEnv* env, jclass clazz) {
return sizeof(long);
}
static jint netty_quiche_timespecOffsetofTvSec(JNIEnv* env, jclass clazz) {
return offsetof(struct timespec, tv_sec);
}
static jint timespecOffsetofTvNsec(JNIEnv* env, jclass clazz) {
return offsetof(struct timespec, tv_nsec);
}
static jint netty_quicheRecvInfoOffsetofFrom(JNIEnv* env, jclass clazz) {
return offsetof(quiche_recv_info, from);
}
static jint netty_quicheRecvInfoOffsetofFromLen(JNIEnv* env, jclass clazz) {
return offsetof(quiche_recv_info, from_len);
}
static jint netty_quicheRecvInfoOffsetofTo(JNIEnv* env, jclass clazz) {
return offsetof(quiche_recv_info, to);
}
static jint netty_quicheRecvInfoOffsetofToLen(JNIEnv* env, jclass clazz) {
return offsetof(quiche_recv_info, to_len);
}
static jint netty_sizeofQuicheRecvInfo(JNIEnv* env, jclass clazz) {
return sizeof(quiche_recv_info);
}
static jint netty_quicheSendInfoOffsetofTo(JNIEnv* env, jclass clazz) {
return offsetof(quiche_send_info, to);
}
static jint netty_quicheSendInfoOffsetofToLen(JNIEnv* env, jclass clazz) {
return offsetof(quiche_send_info, to_len);
}
static jint netty_quicheSendInfoOffsetofFrom(JNIEnv* env, jclass clazz) {
return offsetof(quiche_send_info, from);
}
static jint netty_quicheSendInfoOffsetofFromLen(JNIEnv* env, jclass clazz) {
return offsetof(quiche_send_info, from_len);
}
static jint netty_quicheSendInfoOffsetofAt(JNIEnv* env, jclass clazz) {
return offsetof(quiche_send_info, at);
}
static jint netty_sizeofQuicheSendInfo(JNIEnv* env, jclass clazz) {
return sizeof(quiche_send_info);
}
static jint netty_quiche_max_conn_id_len(JNIEnv* env, jclass clazz) {
return QUICHE_MAX_CONN_ID_LEN;
}
static jint netty_quiche_protocol_version(JNIEnv* env, jclass clazz) {
return QUICHE_PROTOCOL_VERSION;
}
static jint netty_quiche_shutdown_read(JNIEnv* env, jclass clazz) {
return QUICHE_SHUTDOWN_READ;
}
static jint netty_quiche_shutdown_write(JNIEnv* env, jclass clazz) {
return QUICHE_SHUTDOWN_WRITE;
}
static jint netty_quiche_err_done(JNIEnv* env, jclass clazz) {
return QUICHE_ERR_DONE;
}
static jint netty_quiche_err_buffer_too_short(JNIEnv* env, jclass clazz) {
return QUICHE_ERR_BUFFER_TOO_SHORT;
}
static jint netty_quiche_err_unknown_version(JNIEnv* env, jclass clazz) {
return QUICHE_ERR_UNKNOWN_VERSION;
}
static jint netty_quiche_err_invalid_frame(JNIEnv* env, jclass clazz) {
return QUICHE_ERR_INVALID_FRAME;
}
static jint netty_quiche_err_invalid_packet(JNIEnv* env, jclass clazz) {
return QUICHE_ERR_INVALID_PACKET;
}
static jint netty_quiche_err_invalid_state(JNIEnv* env, jclass clazz) {
return QUICHE_ERR_INVALID_STATE;
}
static jint netty_quiche_err_invalid_stream_state(JNIEnv* env, jclass clazz) {
return QUICHE_ERR_INVALID_STREAM_STATE;
}
static jint netty_quiche_err_invalid_transport_param(JNIEnv* env, jclass clazz) {
return QUICHE_ERR_INVALID_TRANSPORT_PARAM;
}
static jint netty_quiche_err_crypto_fail(JNIEnv* env, jclass clazz) {
return QUICHE_ERR_CRYPTO_FAIL;
}
static jint netty_quiche_err_tls_fail(JNIEnv* env, jclass clazz) {
return QUICHE_ERR_TLS_FAIL;
}
static jint netty_quiche_err_flow_control(JNIEnv* env, jclass clazz) {
return QUICHE_ERR_FLOW_CONTROL;
}
static jint netty_quiche_err_stream_limit(JNIEnv* env, jclass clazz) {
return QUICHE_ERR_STREAM_LIMIT;
}
static jint netty_quiche_err_final_size(JNIEnv* env, jclass clazz) {
return QUICHE_ERR_FINAL_SIZE;
}
static jint netty_quiche_err_stream_reset(JNIEnv* env, jclass clazz) {
return QUICHE_ERR_STREAM_RESET;
}
static jint netty_quiche_err_stream_stopped(JNIEnv* env, jclass clazz) {
return QUICHE_ERR_STREAM_STOPPED;
}
static jint netty_quiche_err_congestion_control(JNIEnv* env, jclass clazz) {
return QUICHE_ERR_CONGESTION_CONTROL;
}
static jint netty_quiche_err_id_limit(JNIEnv* env, jclass clazz) {
return QUICHE_ERR_ID_LIMIT;
}
static jint netty_quiche_err_out_of_identifiers(JNIEnv* env, jclass clazz) {
return QUICHE_ERR_OUT_OF_IDENTIFIERS;
}
static jint netty_quiche_err_key_update(JNIEnv* env, jclass clazz) {
return QUICHE_ERR_KEY_UPDATE;
}
static jint netty_quiche_err_crypto_buffer_exceeded(JNIEnv* env, jclass clazz) {
return QUICHE_ERR_CRYPTO_BUFFER_EXCEEDED;
}
static jint netty_quiche_cc_reno(JNIEnv* env, jclass clazz) {
return QUICHE_CC_RENO;
}
static jint netty_quiche_cc_cubic(JNIEnv* env, jclass clazz) {
return QUICHE_CC_CUBIC;
}
static jint netty_quiche_cc_bbr(JNIEnv* env, jclass clazz) {
return QUICHE_CC_BBR;
}
static jint netty_quiche_path_event_type_new(JNIEnv* env, jclass clazz) {
return QUICHE_PATH_EVENT_NEW;
}
static jint netty_quiche_path_event_type_validated(JNIEnv* env, jclass clazz) {
return QUICHE_PATH_EVENT_VALIDATED;
}
static jint netty_quiche_path_event_type_failed_validation(JNIEnv* env, jclass clazz) {
return QUICHE_PATH_EVENT_FAILED_VALIDATION;
}
static jint netty_quiche_path_event_type_closed(JNIEnv* env, jclass clazz) {
return QUICHE_PATH_EVENT_CLOSED;
}
static jint netty_quiche_path_event_type_reused_source_connection_id(JNIEnv* env, jclass clazz) {
return QUICHE_PATH_EVENT_REUSED_SOURCE_CONNECTION_ID;
}
static jint netty_quiche_path_event_type_peer_migrated(JNIEnv* env, jclass clazz) {
return QUICHE_PATH_EVENT_PEER_MIGRATED;
}
static jstring netty_quiche_version(JNIEnv* env, jclass clazz) {
return (*env)->NewStringUTF(env, quiche_version());
}
static jboolean netty_quiche_version_is_supported(JNIEnv* env, jclass clazz, jint version) {
return quiche_version_is_supported(version) == true ? JNI_TRUE : JNI_FALSE;
}
static jboolean netty_quiche_conn_set_qlog_path(JNIEnv* env, jclass clazz, jlong conn, jstring path,
jstring log_title, jstring log_desc) {
const char *nativePath = (*env)->GetStringUTFChars(env, path, 0);
const char *nativeLogTitle = (*env)->GetStringUTFChars(env, log_title, 0);
const char *nativeLogDesc = (*env)->GetStringUTFChars(env, log_desc, 0);
bool ret = quiche_conn_set_qlog_path((quiche_conn *) conn, nativePath,
nativeLogTitle, nativeLogDesc);
(*env)->ReleaseStringUTFChars(env, path, nativePath);
(*env)->ReleaseStringUTFChars(env, log_title, nativeLogTitle);
(*env)->ReleaseStringUTFChars(env, log_desc, nativeLogDesc);
return ret == true ? JNI_TRUE : JNI_FALSE;
}
static jint netty_quiche_header_info(JNIEnv* env, jclass clazz, jlong buf, jint buf_len, jint dcil, jlong version,
jlong type, jlong scid, jlong scid_len, jlong dcid, jlong dcid_len, jlong token, jlong token_len) {
return (jint) quiche_header_info((const uint8_t *) buf, (size_t) buf_len, (size_t) dcil,
(uint32_t *) version, (uint8_t *) type,
(uint8_t *) scid, (size_t *) scid_len,
(uint8_t *) dcid, (size_t *) dcid_len,
(uint8_t *) token, (size_t *) token_len);
}
static jint netty_quiche_negotiate_version(JNIEnv* env, jclass clazz, jlong scid, jint scid_len, jlong dcid, jint dcid_len, jlong out, jint out_len) {
return (jint) quiche_negotiate_version((const uint8_t *) scid, (size_t) scid_len,
(const uint8_t *) dcid, (size_t) dcid_len,
(uint8_t *)out, (size_t) out_len);
}
static jint netty_quiche_retry(JNIEnv* env, jclass clazz, jlong scid, jint scid_len, jlong dcid, jint dcid_len,
jlong new_scid, jint new_scid_len, jlong token, jint token_len, jint version, jlong out, jint out_len) {
return (jint) quiche_retry((const uint8_t *) scid, (size_t) scid_len,
(const uint8_t *) dcid, (size_t) dcid_len,
(const uint8_t *) new_scid, (size_t) new_scid_len,
(const uint8_t *) token, (size_t) token_len,
(uint32_t) version, (uint8_t *) out, (size_t) out_len);
}
static jlong netty_quiche_conn_new_with_tls(JNIEnv* env, jclass clazz, jlong scid, jint scid_len, jlong odcid, jint odcid_len, jlong local, jint local_len, jlong peer, jint peer_len, jlong config, jlong ssl, jboolean isServer) {
const uint8_t * odcid_pointer = NULL;
if (odcid_len != -1) {
odcid_pointer = (const uint8_t *) odcid;
}
const struct sockaddr *local_pointer = (const struct sockaddr*) local;
const struct sockaddr *peer_pointer = (const struct sockaddr*) peer;
quiche_conn *conn = quiche_conn_new_with_tls((const uint8_t *) scid, (size_t) scid_len,
odcid_pointer, (size_t) odcid_len,
local_pointer, (socklen_t) local_len,
peer_pointer, (socklen_t) peer_len,
(quiche_config *) config, (void*) ssl, isServer == JNI_TRUE ? true : false);
if (conn == NULL) {
return -1;
}
return (jlong) conn;
}
static jbyteArray to_byte_array(JNIEnv* env, const uint8_t* bytes, size_t len) {
if (bytes == NULL || len == 0) {
return NULL;
}
jbyteArray array = (*env)->NewByteArray(env, len);
if (array == NULL) {
return NULL;
}
(*env)->SetByteArrayRegion(env,array, 0, len, (jbyte*) bytes);
return array;
}
static jint netty_quiche_conn_send_quantum(JNIEnv* env, jclass clazz, jlong conn) {
return (jint) quiche_conn_send_quantum((quiche_conn *) conn);
}
static jbyteArray netty_quiche_conn_trace_id(JNIEnv* env, jclass clazz, jlong conn) {
const uint8_t *trace_id = NULL;
size_t trace_id_len = 0;
quiche_conn_trace_id((quiche_conn *) conn, &trace_id, &trace_id_len);
return to_byte_array(env, trace_id, trace_id_len);
}
static jbyteArray netty_quiche_conn_source_id(JNIEnv* env, jclass clazz, jlong conn) {
const uint8_t *id = NULL;
size_t len = 0;
quiche_conn_source_id((quiche_conn *) conn, &id, &len);
return to_byte_array(env, id, len);
}
static jbyteArray netty_quiche_conn_destination_id(JNIEnv* env, jclass clazz, jlong conn) {
const uint8_t *id = NULL;
size_t len = 0;
quiche_conn_destination_id((quiche_conn *) conn, &id, &len);
return to_byte_array(env, id, len);
}
static jint netty_quiche_conn_recv(JNIEnv* env, jclass clazz, jlong conn, jlong buf, jint buf_len, jlong info) {
return (jint) quiche_conn_recv((quiche_conn *) conn, (uint8_t *) buf, (size_t) buf_len, (quiche_recv_info*) info);
}
static jint netty_quiche_conn_send(JNIEnv* env, jclass clazz, jlong conn, jlong out, jint out_len, jlong info) {
return (jint) quiche_conn_send((quiche_conn *) conn, (uint8_t *) out, (size_t) out_len, (quiche_send_info*) info);
}
static void netty_quiche_conn_free(JNIEnv* env, jclass clazz, jlong conn) {
quiche_conn_free((quiche_conn *) conn);
}
static jobjectArray netty_quiche_conn_peer_error0(JNIEnv* env, jclass clazz, jlong conn) {
bool is_app = false;
uint64_t error_code = 0;
const uint8_t *reason = NULL;
size_t reason_len = 0;
bool peer_error = quiche_conn_peer_error((quiche_conn *) conn,
&is_app,
&error_code,
&reason,
&reason_len);
if (peer_error) {
jobjectArray array = (*env)->NewObjectArray(env, 3, object_class, NULL);
if (array == NULL) {
return NULL;
}
(*env)->SetObjectArrayElement(env, array, 0, (*env)->CallStaticObjectMethod(env, boolean_class, boolean_class_valueof, is_app ? JNI_TRUE : JNI_FALSE));
(*env)->SetObjectArrayElement(env, array, 1, (*env)->CallStaticObjectMethod(env, integer_class, integer_class_valueof, (jint) error_code));
(*env)->SetObjectArrayElement(env, array, 2, to_byte_array(env, reason, reason_len));
return array;
}
return NULL;
}
static jlong netty_quiche_conn_peer_streams_left_bidi(JNIEnv* env, jclass clazz, jlong conn) {
return (jlong) quiche_conn_peer_streams_left_bidi((quiche_conn *) conn);
}
static jlong netty_quiche_conn_peer_streams_left_uni(JNIEnv* env, jclass clazz, jlong conn) {
return (jlong) quiche_conn_peer_streams_left_uni((quiche_conn *) conn);
}
static jint netty_quiche_conn_stream_priority(JNIEnv* env, jclass clazz, jlong conn, jlong stream_id, jbyte urgency, jboolean incremental) {
return (jint) quiche_conn_stream_priority((quiche_conn *) conn, (uint64_t) stream_id, (uint8_t) urgency, incremental == JNI_TRUE ? true : false);
}
static jint netty_quiche_conn_stream_recv(JNIEnv* env, jclass clazz, jlong conn, jlong stream_id, jlong out, int buf_len, jlong finAddr) {
uint64_t error_code;
return (jint) quiche_conn_stream_recv((quiche_conn *) conn, (uint64_t) stream_id, (uint8_t *) out, (size_t) buf_len, (bool *) finAddr, &error_code);
}
static jint netty_quiche_conn_stream_send(JNIEnv* env, jclass clazz, jlong conn, jlong stream_id, jlong buf, int buf_len, jboolean fin) {
uint64_t error_code;
return (jint) quiche_conn_stream_send((quiche_conn *) conn, (uint64_t) stream_id, (uint8_t *) buf, (size_t) buf_len, fin == JNI_TRUE ? true : false, &error_code);
}
static jint netty_quiche_conn_stream_shutdown(JNIEnv* env, jclass clazz, jlong conn, jlong stream_id, jint direction, jlong err) {
return (jint) quiche_conn_stream_shutdown((quiche_conn *) conn, (uint64_t) stream_id, (enum quiche_shutdown) direction, (uint64_t) err);
}
static jint netty_quiche_conn_stream_capacity(JNIEnv* env, jclass clazz, jlong conn, jlong stream_id) {
return (jint) quiche_conn_stream_capacity((quiche_conn *) conn, (uint64_t) stream_id);
}
static jboolean netty_quiche_conn_stream_finished(JNIEnv* env, jclass clazz, jlong conn, jlong stream_id) {
return quiche_conn_stream_finished((quiche_conn *) conn, (uint64_t) stream_id) == true ? JNI_TRUE : JNI_FALSE;
}
static jint netty_quiche_conn_close(JNIEnv* env, jclass clazz, jlong conn, jboolean app, jlong err, jlong reason, jint reason_len) {
return quiche_conn_close((quiche_conn *) conn, app == JNI_TRUE ? true : false, err, (const uint8_t *) reason, (size_t) reason_len);
}
static jboolean netty_quiche_conn_is_established(JNIEnv* env, jclass clazz, jlong conn) {
return quiche_conn_is_established((quiche_conn *) conn) == true ? JNI_TRUE : JNI_FALSE;
}
static jboolean netty_quiche_conn_is_in_early_data(JNIEnv* env, jclass clazz, jlong conn) {
return quiche_conn_is_in_early_data((quiche_conn *) conn) == true ? JNI_TRUE : JNI_FALSE;
}
static jboolean netty_quiche_conn_is_closed(JNIEnv* env, jclass clazz, jlong conn) {
return quiche_conn_is_closed((quiche_conn *) conn) == true ? JNI_TRUE : JNI_FALSE;
}
static jboolean netty_quiche_conn_is_timed_out(JNIEnv* env, jclass clazz, jlong conn) {
return quiche_conn_is_timed_out((quiche_conn *) conn) == true ? JNI_TRUE : JNI_FALSE;
}
static jlongArray netty_quiche_conn_stats(JNIEnv* env, jclass clazz, jlong conn) {
// See https://github.com/cloudflare/quiche/blob/master/quiche/include/quiche.h#L467
quiche_stats stats = {0,0,0,0,0,0,0,0,0};
quiche_conn_stats((quiche_conn *) conn, &stats);
jlongArray statsArray = (*env)->NewLongArray(env, 9);
if (statsArray == NULL) {
// This will put an OOME on the stack
return NULL;
}
jlong statsArrayElements[] = {
(jlong)stats.recv,
(jlong)stats.sent,
(jlong)stats.lost,
(jlong)stats.retrans,
(jlong)stats.sent_bytes,
(jlong)stats.recv_bytes,
(jlong)stats.lost_bytes,
(jlong)stats.stream_retrans_bytes,
(jlong)stats.paths_count
};
(*env)->SetLongArrayRegion(env, statsArray, 0, 9, statsArrayElements);
return statsArray;
}
static jlongArray netty_quiche_conn_peer_transport_params(JNIEnv* env, jclass clazz, jlong conn) {
// See https://github.com/cloudflare/quiche/blob/master/quiche/include/quiche.h#L563
quiche_transport_params params = {0,0,0,0,0,0,0,0,0,0,false,0,0};
if (!quiche_conn_peer_transport_params((quiche_conn *) conn, ¶ms)) {
return NULL;
}
jlongArray paramsArray = (*env)->NewLongArray(env, 13);
if (paramsArray == NULL) {
// This will put an OOME on the stack
return NULL;
}
jlong paramsArrayElements[] = {
(jlong)params.peer_max_idle_timeout,
(jlong)params.peer_max_udp_payload_size,
(jlong)params.peer_initial_max_data,
(jlong)params.peer_initial_max_stream_data_bidi_local,
(jlong)params.peer_initial_max_stream_data_bidi_remote,
(jlong)params.peer_initial_max_stream_data_uni,
(jlong)params.peer_initial_max_streams_bidi,
(jlong)params.peer_initial_max_streams_uni,
(jlong)params.peer_ack_delay_exponent,
(jlong)params.peer_disable_active_migration ? 1: 0,
(jlong)params.peer_active_conn_id_limit,
(jlong)params.peer_max_datagram_frame_size
};
(*env)->SetLongArrayRegion(env, paramsArray, 0, 13, paramsArrayElements);
return paramsArray;
}
static jlong netty_quiche_conn_timeout_as_nanos(JNIEnv* env, jclass clazz, jlong conn) {
return quiche_conn_timeout_as_nanos((quiche_conn *) conn);
}
static void netty_quiche_conn_on_timeout(JNIEnv* env, jclass clazz, jlong conn) {
quiche_conn_on_timeout((quiche_conn *) conn);
}
static jlong netty_quiche_conn_readable(JNIEnv* env, jclass clazz, jlong conn) {
quiche_stream_iter* iter = quiche_conn_readable((quiche_conn *) conn);
if (iter == NULL) {
return -1;
}
return (jlong) iter;
}
static jlong netty_quiche_conn_writable(JNIEnv* env, jclass clazz, jlong conn) {
quiche_stream_iter* iter = quiche_conn_writable((quiche_conn *) conn);
if (iter == NULL) {
return -1;
}
return (jlong) iter;
}
static void netty_quiche_stream_iter_free(JNIEnv* env, jclass clazz, jlong iter) {
quiche_stream_iter_free((quiche_stream_iter*) iter);
}
static jint netty_quiche_stream_iter_next(JNIEnv* env, jclass clazz, jlong iter, jlongArray streams) {
quiche_stream_iter* it = (quiche_stream_iter*) iter;
if (it == NULL) {
return 0;
}
int len = (*env)->GetArrayLength(env, streams);
if (len == 0) {
return 0;
}
jlong* elements = (*env)->GetLongArrayElements(env, streams, NULL);
int i = 0;
while (i < len && quiche_stream_iter_next(it, (uint64_t*) elements + i)) {
i++;
}
(*env)->ReleaseLongArrayElements(env, streams, elements, 0);
return i;
}
static jint netty_quiche_conn_dgram_max_writable_len(JNIEnv* env, jclass clazz, jlong conn) {
return (jint) quiche_conn_dgram_max_writable_len((quiche_conn *) conn);
}
static jint netty_quiche_conn_dgram_recv_front_len(JNIEnv* env, jclass clazz, jlong conn) {
return (jint) quiche_conn_dgram_recv_front_len((quiche_conn*) conn);
}
static jint netty_quiche_conn_dgram_recv(JNIEnv* env, jclass clazz, jlong conn, jlong buf, jint buf_len) {
return (jint) quiche_conn_dgram_recv((quiche_conn *) conn, (uint8_t *) buf, (size_t) buf_len);
}
static jint netty_quiche_conn_dgram_send(JNIEnv* env, jclass clazz, jlong conn, jlong buf, jint buf_len) {
return (jint) quiche_conn_dgram_send((quiche_conn *) conn, (uint8_t *) buf, (size_t) buf_len);
}
static jint netty_quiche_conn_set_session(JNIEnv* env, jclass clazz, jlong conn, jbyteArray sessionBytes) {
int buf_len = (*env)->GetArrayLength(env, sessionBytes);
uint8_t* buf = (uint8_t*) (*env)->GetByteArrayElements(env, sessionBytes, 0);
int result = (jint) quiche_conn_set_session((quiche_conn *) conn, (uint8_t *) buf, (size_t) buf_len);
(*env)->ReleaseByteArrayElements(env, sessionBytes, (jbyte*) buf, JNI_ABORT);
return result;
}
static jint netty_quiche_conn_max_send_udp_payload_size(JNIEnv* env, jclass clazz, jlong conn) {
return (jint) quiche_conn_max_send_udp_payload_size((quiche_conn *) conn);
}
static jint netty_quiche_conn_scids_left(JNIEnv* env, jclass clazz, jlong conn) {
return (jint) quiche_conn_scids_left((quiche_conn *) conn);
}
static jlong netty_quiche_conn_new_scid(JNIEnv* env, jclass clazz, jlong conn, jlong scid, jint scid_len, jbyteArray reset_token, jboolean retire_if_needed, jlong sequenceAddr) {
uint8_t* buf = (uint8_t*) (*env)->GetByteArrayElements(env, reset_token, 0);
uint64_t* seq;
if (sequenceAddr < 0) {
uint64_t tmp;
seq = &tmp;
} else {
seq = (uint64_t *) sequenceAddr;
}
jlong ret = quiche_conn_new_scid((quiche_conn *) conn, (const uint8_t *) scid, scid_len, buf, retire_if_needed == JNI_TRUE ? true : false, seq);
(*env)->ReleaseByteArrayElements(env, reset_token, (jbyte*)buf, JNI_ABORT);
return ret;
}
static jbyteArray netty_quiche_conn_retired_scid_next(JNIEnv* env, jclass clazz, jlong conn) {
const uint8_t *id = NULL;
size_t len = 0;
if (quiche_conn_retired_scid_next((quiche_conn *) conn, &id, &len)) {
return to_byte_array(env, id, len);
}
return NULL;
}
static jlong netty_quiche_conn_path_event_next(JNIEnv* env, jclass clazz, jlong conn) {
const struct quiche_path_event *ev = quiche_conn_path_event_next((quiche_conn *) conn);
if (ev == NULL) {
return -1;
}
return (jlong) ev;
}
static jint netty_quiche_path_event_type(JNIEnv* env, jclass clazz, jlong ev) {
return (jint) quiche_path_event_type((quiche_path_event *) ev);
}
static jobject netty_new_socket_address(JNIEnv* env, const struct sockaddr_storage* addr) {
jobject address = NULL;
jint port;
if (addr->ss_family == AF_INET) {
struct sockaddr_in* s = (struct sockaddr_in*) addr;
port = ntohs(s->sin_port);
jbyteArray array = to_byte_array(env, (uint8_t*) &s->sin_addr.s_addr, (size_t) 4);
address = (*env)->CallStaticObjectMethod(env, inet4address_class, inet4address_class_get_by_address, array);
} else {
struct sockaddr_in6* s = (struct sockaddr_in6*) addr;
port = ntohs(s->sin6_port);
jbyteArray array = to_byte_array(env, (uint8_t*) &s->sin6_addr.s6_addr, (size_t) 16);
address = (*env)->CallStaticObjectMethod(env, inet6address_class, inet6address_class_get_by_address, NULL, array, (jint) s->sin6_scope_id);
}
return (*env)->NewObject(env, inetsocketaddress_class, inetsocketaddress_class_constructor, address, port);
}
static jobjectArray netty_quiche_conn_path_stats(JNIEnv* env, jclass clazz, jlong conn, jlong idx) {
quiche_path_stats stats = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
if (quiche_conn_path_stats((quiche_conn *) conn, idx, &stats) != 0) {
// The idx is not valid.
return NULL;
}
jobject localAddr = netty_new_socket_address(env, &stats.local_addr);
if (localAddr == NULL) {
return NULL;
}
jobject peerAddr = netty_new_socket_address(env, &stats.peer_addr);
if (peerAddr == NULL) {
return NULL;
}
jobjectArray array = (*env)->NewObjectArray(env, 16, object_class, NULL);
if (array == NULL) {
return NULL;
}
(*env)->SetObjectArrayElement(env, array, 0, localAddr);
(*env)->SetObjectArrayElement(env, array, 1, peerAddr);
(*env)->SetObjectArrayElement(env, array, 2, (*env)->CallStaticObjectMethod(env, long_class, long_class_valueof, (jlong) stats.validation_state));
(*env)->SetObjectArrayElement(env, array, 3, (*env)->CallStaticObjectMethod(env, boolean_class, boolean_class_valueof, stats.active ? JNI_TRUE : JNI_FALSE));
(*env)->SetObjectArrayElement(env, array, 4, (*env)->CallStaticObjectMethod(env, long_class, long_class_valueof, (jlong) stats.recv));
(*env)->SetObjectArrayElement(env, array, 5, (*env)->CallStaticObjectMethod(env, long_class, long_class_valueof, (jlong) stats.sent));
(*env)->SetObjectArrayElement(env, array, 6, (*env)->CallStaticObjectMethod(env, long_class, long_class_valueof, (jlong) stats.lost));
(*env)->SetObjectArrayElement(env, array, 7, (*env)->CallStaticObjectMethod(env, long_class, long_class_valueof, (jlong) stats.retrans));
(*env)->SetObjectArrayElement(env, array, 8, (*env)->CallStaticObjectMethod(env, long_class, long_class_valueof, (jlong) stats.rtt));
(*env)->SetObjectArrayElement(env, array, 9, (*env)->CallStaticObjectMethod(env, long_class, long_class_valueof, (jlong) stats.cwnd));
(*env)->SetObjectArrayElement(env, array, 10, (*env)->CallStaticObjectMethod(env, long_class, long_class_valueof, (jlong) stats.sent_bytes));
(*env)->SetObjectArrayElement(env, array, 11, (*env)->CallStaticObjectMethod(env, long_class, long_class_valueof, (jlong) stats.recv_bytes));
(*env)->SetObjectArrayElement(env, array, 12, (*env)->CallStaticObjectMethod(env, long_class, long_class_valueof, (jlong) stats.lost_bytes));
(*env)->SetObjectArrayElement(env, array, 13, (*env)->CallStaticObjectMethod(env, long_class, long_class_valueof, (jlong) stats.stream_retrans_bytes));
(*env)->SetObjectArrayElement(env, array, 14, (*env)->CallStaticObjectMethod(env, long_class, long_class_valueof, (jlong) stats.pmtu));
(*env)->SetObjectArrayElement(env, array, 15, (*env)->CallStaticObjectMethod(env, long_class, long_class_valueof, (jlong) stats.delivery_rate));
return array;
}
static jobjectArray netty_quiche_path_event_new(JNIEnv* env, jclass clazz, jlong ev) {
struct sockaddr_storage local;
socklen_t local_len;
struct sockaddr_storage peer;
socklen_t peer_len;
quiche_path_event_new((quiche_path_event *) ev, &local, &local_len, &peer, &peer_len);
jobject localAddr = netty_new_socket_address(env, &local);
if (localAddr == NULL) {
return NULL;
}
jobject peerAddr = netty_new_socket_address(env, &peer);
if (peerAddr == NULL) {
return NULL;
}
jobjectArray array = (*env)->NewObjectArray(env, 2, object_class, NULL);
if (array == NULL) {
return NULL;
}
(*env)->SetObjectArrayElement(env, array, 0, localAddr);
(*env)->SetObjectArrayElement(env, array, 1, peerAddr);
return array;
}
static jobjectArray netty_quiche_path_event_validated(JNIEnv* env, jclass clazz, jlong ev) {
struct sockaddr_storage local;
socklen_t local_len;
struct sockaddr_storage peer;
socklen_t peer_len;
quiche_path_event_validated((quiche_path_event *) ev, &local, &local_len, &peer, &peer_len);
jobject localAddr = netty_new_socket_address(env, &local);
if (localAddr == NULL) {
return NULL;
}
jobject peerAddr = netty_new_socket_address(env, &peer);
if (peerAddr == NULL) {
return NULL;
}
jobjectArray array = (*env)->NewObjectArray(env, 2, object_class, NULL);
if (array == NULL) {
return NULL;
}
(*env)->SetObjectArrayElement(env, array, 0, localAddr);
(*env)->SetObjectArrayElement(env, array, 1, peerAddr);
return array;
}
static jobjectArray netty_quiche_path_event_failed_validation(JNIEnv* env, jclass clazz, jlong ev) {
struct sockaddr_storage local;
socklen_t local_len;
struct sockaddr_storage peer;
socklen_t peer_len;
quiche_path_event_failed_validation((quiche_path_event *) ev, &local, &local_len, &peer, &peer_len);
jobject localAddr = netty_new_socket_address(env, &local);
if (localAddr == NULL) {
return NULL;
}
jobject peerAddr = netty_new_socket_address(env, &peer);
if (peerAddr == NULL) {
return NULL;
}
jobjectArray array = (*env)->NewObjectArray(env, 2, object_class, NULL);
if (array == NULL) {
return NULL;
}
(*env)->SetObjectArrayElement(env, array, 0, localAddr);
(*env)->SetObjectArrayElement(env, array, 1, peerAddr);
return array;
}
static jobjectArray netty_quiche_path_event_closed(JNIEnv* env, jclass clazz, jlong ev) {
struct sockaddr_storage local;
socklen_t local_len;
struct sockaddr_storage peer;
socklen_t peer_len;
quiche_path_event_closed((quiche_path_event *) ev, &local, &local_len, &peer, &peer_len);
jobject localAddr = netty_new_socket_address(env, &local);
if (localAddr == NULL) {
return NULL;
}
jobject peerAddr = netty_new_socket_address(env, &peer);
if (peerAddr == NULL) {
return NULL;
}
jobjectArray array = (*env)->NewObjectArray(env, 2, object_class, NULL);
if (array == NULL) {
return NULL;
}
(*env)->SetObjectArrayElement(env, array, 0, localAddr);
(*env)->SetObjectArrayElement(env, array, 1, peerAddr);
return array;
}
static jobjectArray netty_quiche_path_event_reused_source_connection_id(JNIEnv* env, jclass clazz, jlong ev) {
uint64_t id;
struct sockaddr_storage local_old;
socklen_t local_old_len;
struct sockaddr_storage peer_old;
socklen_t peer_old_len;
struct sockaddr_storage local;
socklen_t local_len;
struct sockaddr_storage peer;
socklen_t peer_len;
quiche_path_event_reused_source_connection_id((quiche_path_event *) ev, &id, &local_old, &local_old_len, &peer_old, &peer_old_len, &local, &local_len, &peer, &peer_len);
jobject localOldAddr = netty_new_socket_address(env, &local_old);
if (localOldAddr == NULL) {
return NULL;
}
jobject peerOldAddr = netty_new_socket_address(env, &peer_old);
if (peerOldAddr == NULL) {
return NULL;
}
jobject localAddr = netty_new_socket_address(env, &local);
if (localAddr == NULL) {
return NULL;
}
jobject peerAddr = netty_new_socket_address(env, &peer);
if (peerAddr == NULL) {
return NULL;
}
jobjectArray array = (*env)->NewObjectArray(env, 5, object_class, NULL);
if (array == NULL) {
return NULL;
}
(*env)->SetObjectArrayElement(env, array, 0, (*env)->CallStaticObjectMethod(env, long_class, long_class_valueof, (jlong) id));
(*env)->SetObjectArrayElement(env, array, 1, localOldAddr);
(*env)->SetObjectArrayElement(env, array, 2, peerOldAddr);
(*env)->SetObjectArrayElement(env, array, 3, localAddr);
(*env)->SetObjectArrayElement(env, array, 4, peerAddr);
return array;
}
static jobjectArray netty_quiche_path_event_peer_migrated(JNIEnv* env, jclass clazz, jlong ev) {
struct sockaddr_storage local;
socklen_t local_len;
struct sockaddr_storage peer;
socklen_t peer_len;
quiche_path_event_peer_migrated((quiche_path_event *) ev, &local, &local_len, &peer, &peer_len);
jobject localAddr = netty_new_socket_address(env, &local);
if (localAddr == NULL) {
return NULL;
}
jobject peerAddr = netty_new_socket_address(env, &peer);
if (peerAddr == NULL) {
return NULL;
}
jobjectArray array = (*env)->NewObjectArray(env, 2, object_class, NULL);
if (array == NULL) {
return NULL;
}
(*env)->SetObjectArrayElement(env, array, 0, localAddr);
(*env)->SetObjectArrayElement(env, array, 1, peerAddr);
return array;
}
static void netty_quiche_path_event_free(JNIEnv* env, jclass clazz, jlong ev) {
quiche_path_event_free((quiche_path_event *) ev);
}
static jlong netty_quiche_config_new(JNIEnv* env, jclass clazz, jint version) {
quiche_config* config = quiche_config_new((uint32_t) version);
return config == NULL ? -1 : (jlong) config;
}
static void netty_quiche_config_enable_dgram(JNIEnv* env, jclass clazz, jlong config, jboolean enabled, jint recv_queue_len, jint send_queue_len) {
quiche_config_enable_dgram((quiche_config*) config, enabled == JNI_TRUE ? true : false, (size_t) recv_queue_len, (size_t) send_queue_len);
}
static void netty_quiche_config_grease(JNIEnv* env, jclass clazz, jlong config, jboolean value) {
quiche_config_grease((quiche_config*) config, value == JNI_TRUE ? true : false);
}
static void netty_quiche_config_set_max_idle_timeout(JNIEnv* env, jclass clazz, jlong config, jlong value) {
quiche_config_set_max_idle_timeout((quiche_config*) config, (uint64_t) value);
}
static void netty_quiche_config_set_max_recv_udp_payload_size(JNIEnv* env, jclass clazz, jlong config, jlong value) {
quiche_config_set_max_recv_udp_payload_size((quiche_config*) config, (uint64_t) value);
}
static void netty_quiche_config_set_max_send_udp_payload_size(JNIEnv* env, jclass clazz, jlong config, jlong value) {
quiche_config_set_max_send_udp_payload_size((quiche_config*) config, (uint64_t) value);
}
static void netty_quiche_config_set_initial_max_data(JNIEnv* env, jclass clazz, jlong config, jlong value) {
quiche_config_set_initial_max_data((quiche_config*) config, (uint64_t) value);
}
static void netty_quiche_config_set_initial_max_stream_data_bidi_local(JNIEnv* env, jclass clazz, jlong config, jlong value) {
quiche_config_set_initial_max_stream_data_bidi_local((quiche_config*) config, (uint64_t) value);
}
static void netty_quiche_config_set_initial_max_stream_data_bidi_remote(JNIEnv* env, jclass clazz, jlong config, jlong value) {
quiche_config_set_initial_max_stream_data_bidi_remote((quiche_config*) config, (uint64_t) value);
}
static void netty_quiche_config_set_initial_max_stream_data_uni(JNIEnv* env, jclass clazz, jlong config, jlong value) {
quiche_config_set_initial_max_stream_data_uni((quiche_config*) config, (uint64_t) value);
}
static void netty_quiche_config_set_initial_max_streams_bidi(JNIEnv* env, jclass clazz, jlong config, jlong value) {
quiche_config_set_initial_max_streams_bidi((quiche_config*) config, (uint64_t) value);
}
static void netty_quiche_config_set_initial_max_streams_uni(JNIEnv* env, jclass clazz, jlong config, jlong value) {
quiche_config_set_initial_max_streams_uni((quiche_config*) config, (uint64_t) value);
}
static void netty_quiche_config_set_ack_delay_exponent(JNIEnv* env, jclass clazz, jlong config, jlong value) {
quiche_config_set_ack_delay_exponent((quiche_config*) config, (uint64_t) value);
}
static void netty_quiche_config_set_max_ack_delay(JNIEnv* env, jclass clazz, jlong config, jlong value) {
quiche_config_set_max_ack_delay((quiche_config*) config, (uint64_t) value);
}
static void netty_quiche_config_set_disable_active_migration(JNIEnv* env, jclass clazz, jlong config, jboolean value) {
quiche_config_set_disable_active_migration((quiche_config*) config, value == JNI_TRUE ? true : false);
}
static void netty_quiche_config_set_cc_algorithm(JNIEnv* env, jclass clazz, jlong config, jint algo) {
quiche_config_set_cc_algorithm((quiche_config*) config, (enum quiche_cc_algorithm) algo);
}
static void netty_quiche_config_set_initial_congestion_window_packets(JNIEnv* env, jclass clazz, jlong config, jint value) {
quiche_config_set_initial_congestion_window_packets((quiche_config*) config, (size_t) value);
}
static void netty_quiche_config_enable_hystart(JNIEnv* env, jclass clazz, jlong config, jboolean value) {
quiche_config_enable_hystart((quiche_config*) config, value == JNI_TRUE ? true : false);
}
static void netty_quiche_config_set_active_connection_id_limit(JNIEnv* env, jclass clazz, jlong config, jlong value) {
quiche_config_set_active_connection_id_limit((quiche_config*) config, (uint64_t) value);
}
static void netty_quiche_config_set_stateless_reset_token(JNIEnv* env, jclass clazz, jlong config, jbyteArray token) {
uint8_t* buf = (uint8_t*) (*env)->GetByteArrayElements(env, token, 0);
quiche_config_set_stateless_reset_token((quiche_config*) config, buf);
(*env)->ReleaseByteArrayElements(env, token, (jbyte*)buf, JNI_ABORT);
}
static void netty_quiche_config_free(JNIEnv* env, jclass clazz, jlong config) {
quiche_config_free((quiche_config*) config);
}
static void log_to_java(const char *line, void *argp) {
JNIEnv* env = NULL;
quic_get_java_env(&env);
if (env == NULL) {
return;
}
jstring message = (*env)->NewStringUTF(env, line);
if (message == NULL) {
// out of memory.
return;
}
(*env)->CallVoidMethod(env, quiche_logger, quiche_logger_class_log, message);
}
static void netty_quiche_enable_debug_logging(JNIEnv* env, jclass clazz, jobject logger) {
if (quiche_logger != NULL) {
return;
}
if ((quiche_logger = (*env)->NewGlobalRef(env, logger)) == NULL) {
return;
}
quiche_enable_debug_logging(log_to_java, NULL);
}
static jlong netty_buffer_memory_address(JNIEnv* env, jclass clazz, jobject buffer) {
return (jlong) (*env)->GetDirectBufferAddress(env, buffer);
}
// Based on https://gist.github.com/kazuho/45eae4f92257daceb73e.
static jint netty_sockaddr_cmp(JNIEnv* env, jclass clazz, jlong addr1, jlong addr2) {
struct sockaddr* x = (struct sockaddr*) addr1;
struct sockaddr* y = (struct sockaddr*) addr2;
if (x == NULL && y == NULL) {
return 0;
}
if (x != NULL && y == NULL) {
return 1;
}
if (x == NULL && y != NULL) {
return -1;
}
#define CMP(a, b) if (a != b) return a < b ? -1 : 1
CMP(x->sa_family, y->sa_family);
if (x->sa_family == AF_INET) {
struct sockaddr_in *xin = (void*)x, *yin = (void*)y;
CMP(ntohl(xin->sin_addr.s_addr), ntohl(yin->sin_addr.s_addr));
CMP(ntohs(xin->sin_port), ntohs(yin->sin_port));
} else if (x->sa_family == AF_INET6) {
struct sockaddr_in6 *xin6 = (void*)x, *yin6 = (void*)y;
int r = memcmp(xin6->sin6_addr.s6_addr, yin6->sin6_addr.s6_addr, sizeof(xin6->sin6_addr.s6_addr));
if (r != 0)
return r;
CMP(ntohs(xin6->sin6_port), ntohs(yin6->sin6_port));
CMP(xin6->sin6_flowinfo, yin6->sin6_flowinfo);
CMP(xin6->sin6_scope_id, yin6->sin6_scope_id);
}
#undef CMP
return 0;
}
// JNI Registered Methods End
// JNI Method Registration Table Begin
static const JNINativeMethod statically_referenced_fixed_method_table[] = {
{ "afInet", "()I", (void *) netty_quiche_afInet },
{ "afInet6", "()I", (void *) netty_quiche_afInet6 },
{ "sizeofSockaddrIn", "()I", (void *) netty_quiche_sizeofSockaddrIn },
{ "sizeofSockaddrIn6", "()I", (void *) netty_quiche_sizeofSockaddrIn6 },
{ "sockaddrInOffsetofSinFamily", "()I", (void *) netty_quiche_sockaddrInOffsetofSinFamily },
{ "sockaddrInOffsetofSinPort", "()I", (void *) netty_quiche_sockaddrInOffsetofSinPort },
{ "sockaddrInOffsetofSinAddr", "()I", (void *) netty_quiche_sockaddrInOffsetofSinAddr },
{ "inAddressOffsetofSAddr", "()I", (void *) netty_quiche_inAddressOffsetofSAddr },
{ "sockaddrIn6OffsetofSin6Family", "()I", (void *) netty_quiche_sockaddrIn6OffsetofSin6Family },
{ "sockaddrIn6OffsetofSin6Port", "()I", (void *) netty_quiche_sockaddrIn6OffsetofSin6Port },
{ "sockaddrIn6OffsetofSin6Flowinfo", "()I", (void *) netty_quiche_sockaddrIn6OffsetofSin6Flowinfo },
{ "sockaddrIn6OffsetofSin6Addr", "()I", (void *) netty_quiche_sockaddrIn6OffsetofSin6Addr },
{ "sockaddrIn6OffsetofSin6ScopeId", "()I", (void *) netty_quiche_sockaddrIn6OffsetofSin6ScopeId },
{ "in6AddressOffsetofS6Addr", "()I", (void *) netty_quiche_in6AddressOffsetofS6Addr },
{ "sizeofSockaddrStorage", "()I", (void *) netty_quiche_sizeofSockaddrStorage },
{ "sizeofSizeT", "()I", (void *) netty_quiche_sizeofSizeT },
{ "sizeofSocklenT", "()I", (void *) netty_quiche_sizeofSocklenT },
{ "quicheRecvInfoOffsetofFrom", "()I", (void *) netty_quicheRecvInfoOffsetofFrom },
{ "quicheRecvInfoOffsetofFromLen", "()I", (void *) netty_quicheRecvInfoOffsetofFromLen },
{ "quicheRecvInfoOffsetofTo", "()I", (void *) netty_quicheRecvInfoOffsetofTo },
{ "quicheRecvInfoOffsetofToLen", "()I", (void *) netty_quicheRecvInfoOffsetofToLen },
{ "sizeofQuicheRecvInfo", "()I", (void *) netty_sizeofQuicheRecvInfo },
{ "quicheSendInfoOffsetofTo", "()I", (void *) netty_quicheSendInfoOffsetofTo },
{ "quicheSendInfoOffsetofToLen", "()I", (void *) netty_quicheSendInfoOffsetofToLen },
{ "quicheSendInfoOffsetofFrom", "()I", (void *) netty_quicheSendInfoOffsetofFrom },
{ "quicheSendInfoOffsetofFromLen", "()I", (void *) netty_quicheSendInfoOffsetofFromLen },
{ "quicheSendInfoOffsetofAt", "()I", (void *) netty_quicheSendInfoOffsetofAt },
{ "sizeofQuicheSendInfo", "()I", (void *) netty_sizeofQuicheSendInfo },
{ "sizeofTimespec", "()I", (void *) netty_quiche_sizeofTimespec },
{ "sizeofTimeT", "()I", (void *) netty_quiche_sizeofTimeT },
{ "sizeofLong", "()I", (void *) netty_quiche_sizeofLong },
{ "timespecOffsetofTvSec", "()I", (void *) netty_quiche_timespecOffsetofTvSec },
{ "timespecOffsetofTvNsec", "()I", (void *) timespecOffsetofTvNsec },
{ "quiche_protocol_version", "()I", (void *) netty_quiche_protocol_version },
{ "quiche_max_conn_id_len", "()I", (void *) netty_quiche_max_conn_id_len },
{ "quiche_shutdown_read", "()I", (void *) netty_quiche_shutdown_read },
{ "quiche_shutdown_write", "()I", (void *) netty_quiche_shutdown_write },
{ "quiche_err_done", "()I", (void *) netty_quiche_err_done },
{ "quiche_err_buffer_too_short", "()I", (void *) netty_quiche_err_buffer_too_short },
{ "quiche_err_unknown_version", "()I", (void *) netty_quiche_err_unknown_version },
{ "quiche_err_invalid_frame", "()I", (void *) netty_quiche_err_invalid_frame },
{ "quiche_err_invalid_packet", "()I", (void *) netty_quiche_err_invalid_packet },
{ "quiche_err_invalid_state", "()I", (void *) netty_quiche_err_invalid_state },
{ "quiche_err_invalid_stream_state", "()I", (void *) netty_quiche_err_invalid_stream_state },
{ "quiche_err_invalid_transport_param", "()I", (void *) netty_quiche_err_invalid_transport_param },
{ "quiche_err_crypto_fail", "()I", (void *) netty_quiche_err_crypto_fail },
{ "quiche_err_tls_fail", "()I", (void *) netty_quiche_err_tls_fail },
{ "quiche_err_flow_control", "()I", (void *) netty_quiche_err_flow_control },
{ "quiche_err_stream_limit", "()I", (void *) netty_quiche_err_stream_limit },
{ "quiche_err_final_size", "()I", (void *) netty_quiche_err_final_size },
{ "quiche_err_stream_stopped", "()I", (void *) netty_quiche_err_stream_stopped },
{ "quiche_err_stream_reset", "()I", (void *) netty_quiche_err_stream_reset },
{ "quiche_err_congestion_control", "()I", (void *) netty_quiche_err_congestion_control },
{ "quiche_err_id_limit", "()I", (void *) netty_quiche_err_id_limit },
{ "quiche_err_out_of_identifiers", "()I", (void *) netty_quiche_err_out_of_identifiers },
{ "quiche_err_key_update", "()I", (void *) netty_quiche_err_key_update },
{ "quiche_err_crypto_buffer_exceeded", "()I", (void *) netty_quiche_err_crypto_buffer_exceeded },
{ "quiche_cc_reno", "()I", (void *) netty_quiche_cc_reno },
{ "quiche_cc_cubic", "()I", (void *) netty_quiche_cc_cubic },
{ "quiche_cc_bbr", "()I", (void *) netty_quiche_cc_bbr },
{ "quiche_path_event_new", "()I", (void *) netty_quiche_path_event_type_new },
{ "quiche_path_event_validated", "()I", (void *) netty_quiche_path_event_type_validated },
{ "quiche_path_event_failed_validation", "()I", (void *) netty_quiche_path_event_type_failed_validation },
{ "quiche_path_event_closed", "()I", (void *) netty_quiche_path_event_type_closed },
{ "quiche_path_event_reused_source_connection_id", "()I", (void *) netty_quiche_path_event_type_reused_source_connection_id },
{ "quiche_path_event_peer_migrated", "()I", (void *) netty_quiche_path_event_type_peer_migrated }
};
static const jint statically_referenced_fixed_method_table_size = sizeof(statically_referenced_fixed_method_table) / sizeof(statically_referenced_fixed_method_table[0]);
static const JNINativeMethod fixed_method_table[] = {
{ "quiche_version", "()Ljava/lang/String;", (void *) netty_quiche_version },
{ "quiche_version_is_supported", "(I)Z", (void *) netty_quiche_version_is_supported },
{ "quiche_header_info", "(JIIJJJJJJJJ)I", (void *) netty_quiche_header_info },
{ "quiche_negotiate_version", "(JIJIJI)I", (void *) netty_quiche_negotiate_version },
{ "quiche_retry", "(JIJIJIJIIJI)I", (void *) netty_quiche_retry },
{ "quiche_conn_set_qlog_path", "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z", (void *) netty_quiche_conn_set_qlog_path },
{ "quiche_conn_send_quantum", "(J)I", (void *) netty_quiche_conn_send_quantum },
{ "quiche_conn_trace_id", "(J)[B", (void *) netty_quiche_conn_trace_id },
{ "quiche_conn_source_id", "(J)[B", (void *) netty_quiche_conn_source_id },
{ "quiche_conn_destination_id", "(J)[B", (void *) netty_quiche_conn_destination_id },
{ "quiche_conn_new_with_tls", "(JIJIJIJIJJZ)J", (void *) netty_quiche_conn_new_with_tls },
{ "quiche_conn_recv", "(JJIJ)I", (void *) netty_quiche_conn_recv },
{ "quiche_conn_send", "(JJIJ)I", (void *) netty_quiche_conn_send },
{ "quiche_conn_free", "(J)V", (void *) netty_quiche_conn_free },
{ "quiche_conn_peer_error0", "(J)[Ljava/lang/Object;", (void *) netty_quiche_conn_peer_error0 },
{ "quiche_conn_peer_streams_left_bidi", "(J)J", (void *) netty_quiche_conn_peer_streams_left_bidi },
{ "quiche_conn_peer_streams_left_uni", "(J)J", (void *) netty_quiche_conn_peer_streams_left_uni },
{ "quiche_conn_stream_priority", "(JJBZ)I", (void *) netty_quiche_conn_stream_priority },
{ "quiche_conn_stream_recv", "(JJJIJ)I", (void *) netty_quiche_conn_stream_recv },
{ "quiche_conn_stream_send", "(JJJIZ)I", (void *) netty_quiche_conn_stream_send },
{ "quiche_conn_stream_shutdown", "(JJIJ)I", (void *) netty_quiche_conn_stream_shutdown },
{ "quiche_conn_stream_capacity", "(JJ)I", (void *) netty_quiche_conn_stream_capacity },
{ "quiche_conn_stream_finished", "(JJ)Z", (void *) netty_quiche_conn_stream_finished },
{ "quiche_conn_close", "(JZJJI)I", (void *) netty_quiche_conn_close },
{ "quiche_conn_is_established", "(J)Z", (void *) netty_quiche_conn_is_established },
{ "quiche_conn_is_in_early_data", "(J)Z", (void *) netty_quiche_conn_is_in_early_data },
{ "quiche_conn_is_closed", "(J)Z", (void *) netty_quiche_conn_is_closed },
{ "quiche_conn_is_timed_out", "(J)Z", (void *) netty_quiche_conn_is_timed_out },
{ "quiche_conn_stats", "(J)[J", (void *) netty_quiche_conn_stats },
{ "quiche_conn_peer_transport_params", "(J)[J", (void *) netty_quiche_conn_peer_transport_params },
{ "quiche_conn_timeout_as_nanos", "(J)J", (void *) netty_quiche_conn_timeout_as_nanos },
{ "quiche_conn_on_timeout", "(J)V", (void *) netty_quiche_conn_on_timeout },
{ "quiche_conn_readable", "(J)J", (void *) netty_quiche_conn_readable },
{ "quiche_conn_writable", "(J)J", (void *) netty_quiche_conn_writable },
{ "quiche_stream_iter_free", "(J)V", (void *) netty_quiche_stream_iter_free },
{ "quiche_stream_iter_next", "(J[J)I", (void *) netty_quiche_stream_iter_next },
{ "quiche_conn_dgram_max_writable_len", "(J)I", (void* ) netty_quiche_conn_dgram_max_writable_len },
{ "quiche_conn_dgram_recv_front_len", "(J)I", (void* ) netty_quiche_conn_dgram_recv_front_len },
{ "quiche_conn_dgram_recv", "(JJI)I", (void* ) netty_quiche_conn_dgram_recv },
{ "quiche_conn_dgram_send", "(JJI)I", (void* ) netty_quiche_conn_dgram_send },
{ "quiche_conn_set_session", "(J[B)I", (void* ) netty_quiche_conn_set_session },
{ "quiche_conn_max_send_udp_payload_size", "(J)I", (void* ) netty_quiche_conn_max_send_udp_payload_size },
{ "quiche_conn_scids_left", "(J)I", (void* ) netty_quiche_conn_scids_left },
{ "quiche_conn_new_scid", "(JJI[BZJ)J", (void* ) netty_quiche_conn_new_scid },
{ "quiche_conn_retired_scid_next", "(J)[B", (void* ) netty_quiche_conn_retired_scid_next },
{ "quiche_config_new", "(I)J", (void *) netty_quiche_config_new },
{ "quiche_config_enable_dgram", "(JZII)V", (void *) netty_quiche_config_enable_dgram },
{ "quiche_config_grease", "(JZ)V", (void *) netty_quiche_config_grease },
{ "quiche_config_set_max_idle_timeout", "(JJ)V", (void *) netty_quiche_config_set_max_idle_timeout },
{ "quiche_config_set_max_recv_udp_payload_size", "(JJ)V", (void *) netty_quiche_config_set_max_recv_udp_payload_size },
{ "quiche_config_set_max_send_udp_payload_size", "(JJ)V", (void *) netty_quiche_config_set_max_send_udp_payload_size },
{ "quiche_config_set_initial_max_data", "(JJ)V", (void *) netty_quiche_config_set_initial_max_data },
{ "quiche_config_set_initial_max_stream_data_bidi_local", "(JJ)V", (void *) netty_quiche_config_set_initial_max_stream_data_bidi_local },
{ "quiche_config_set_initial_max_stream_data_bidi_remote", "(JJ)V", (void *) netty_quiche_config_set_initial_max_stream_data_bidi_remote },
{ "quiche_config_set_initial_max_stream_data_uni", "(JJ)V", (void *) netty_quiche_config_set_initial_max_stream_data_uni },
{ "quiche_config_set_initial_max_streams_bidi", "(JJ)V", (void *) netty_quiche_config_set_initial_max_streams_bidi },
{ "quiche_config_set_initial_max_streams_uni", "(JJ)V", (void *) netty_quiche_config_set_initial_max_streams_uni },
{ "quiche_config_set_ack_delay_exponent", "(JJ)V", (void *) netty_quiche_config_set_ack_delay_exponent },
{ "quiche_config_set_max_ack_delay", "(JJ)V", (void *) netty_quiche_config_set_max_ack_delay },
{ "quiche_config_set_disable_active_migration", "(JZ)V", (void *) netty_quiche_config_set_disable_active_migration },
{ "quiche_config_set_cc_algorithm", "(JI)V", (void *) netty_quiche_config_set_cc_algorithm },
{ "quiche_config_set_initial_congestion_window_packets", "(JI)V", (void *) netty_quiche_config_set_initial_congestion_window_packets },
{ "quiche_config_enable_hystart", "(JZ)V", (void *) netty_quiche_config_enable_hystart },
{ "quiche_config_set_active_connection_id_limit", "(JJ)V", (void *) netty_quiche_config_set_active_connection_id_limit },
{ "quiche_config_set_stateless_reset_token", "(J[B)V", (void *) netty_quiche_config_set_stateless_reset_token },
{ "quiche_config_free", "(J)V", (void *) netty_quiche_config_free },
{ "buffer_memory_address", "(Ljava/nio/ByteBuffer;)J", (void *) netty_buffer_memory_address},
{ "sockaddr_cmp", "(JJ)I", (void *) netty_sockaddr_cmp},
{ "quiche_conn_path_event_next", "(J)J", (void *) netty_quiche_conn_path_event_next },
{ "quiche_path_event_type", "(J)I", (void *) netty_quiche_path_event_type },
{ "quiche_conn_path_stats", "(JJ)[Ljava/lang/Object;", (void *) netty_quiche_conn_path_stats },
{ "quiche_path_event_new", "(J)[Ljava/lang/Object;", (void *) netty_quiche_path_event_new },
{ "quiche_path_event_validated", "(J)[Ljava/lang/Object;", (void *) netty_quiche_path_event_validated },
{ "quiche_path_event_failed_validation", "(J)[Ljava/lang/Object;", (void *) netty_quiche_path_event_failed_validation },
{ "quiche_path_event_closed", "(J)[Ljava/lang/Object;", (void *) netty_quiche_path_event_closed },
{ "quiche_path_event_reused_source_connection_id", "(J)[Ljava/lang/Object;", (void *) netty_quiche_path_event_reused_source_connection_id },
{ "quiche_path_event_peer_migrated", "(J)[Ljava/lang/Object;", (void *) netty_quiche_path_event_peer_migrated },
{ "quiche_path_event_free", "(J)V", (void *) netty_quiche_path_event_free }
};
static const jint fixed_method_table_size = sizeof(fixed_method_table) / sizeof(fixed_method_table[0]);
static jint dynamicMethodsTableSize() {
return fixed_method_table_size + 1;
}
static JNINativeMethod* createDynamicMethodsTable(const char* packagePrefix) {
char* dynamicTypeName = NULL;
int len = sizeof(JNINativeMethod) * dynamicMethodsTableSize();
JNINativeMethod* dynamicMethods = malloc(len);
if (dynamicMethods == NULL) {
goto error;
}
memset(dynamicMethods, 0, len);
memcpy(dynamicMethods, fixed_method_table, sizeof(fixed_method_table));
JNINativeMethod* dynamicMethod = &dynamicMethods[fixed_method_table_size];
NETTY_JNI_UTIL_PREPEND(packagePrefix, "io/netty/incubator/codec/quic/QuicheLogger;)V", dynamicTypeName, error);
NETTY_JNI_UTIL_PREPEND("(L", dynamicTypeName, dynamicMethod->signature, error);
netty_jni_util_free_dynamic_name(&dynamicTypeName);
dynamicMethod->name = "quiche_enable_debug_logging";
dynamicMethod->fnPtr = (void *) netty_quiche_enable_debug_logging;
return dynamicMethods;
error:
netty_jni_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize());
free(dynamicTypeName);
return NULL;
}
// JNI Method Registration Table End
// IMPORTANT: If you add any NETTY_JNI_UTIL_LOAD_CLASS or NETTY_JNI_UTIL_FIND_CLASS calls you also need to update
// Quiche to reflect that.
static jint netty_quiche_JNI_OnLoad(JNIEnv* env, char const* packagePrefix) {
int ret = JNI_ERR;
int staticallyRegistered = 0;
int nativeRegistered = 0;
int boringsslLoaded = 0;
jclass quiche_logger_class = NULL;
char* name = NULL;
// We must register the statically referenced methods first!
if (netty_jni_util_register_natives(env,
packagePrefix,
STATICALLY_CLASSNAME,
statically_referenced_fixed_method_table,
statically_referenced_fixed_method_table_size) != 0) {
goto done;
}
staticallyRegistered = 1;
JNINativeMethod* dynamicMethods = createDynamicMethodsTable(packagePrefix);
if (dynamicMethods == NULL) {
goto done;
}
if (netty_jni_util_register_natives(env,
packagePrefix,
QUICHE_CLASSNAME,
dynamicMethods,
dynamicMethodsTableSize()) != 0) {
goto done;
}
nativeRegistered = 1;
NETTY_JNI_UTIL_LOAD_CLASS(env, integer_class, "java/lang/Integer", done);
if ((integer_class_valueof = (*env)->GetStaticMethodID(env, integer_class, "valueOf", "(I)Ljava/lang/Integer;")) == NULL) {
goto done;
}
NETTY_JNI_UTIL_LOAD_CLASS(env, boolean_class, "java/lang/Boolean", done);
if ((boolean_class_valueof = (*env)->GetStaticMethodID(env, boolean_class, "valueOf", "(Z)Ljava/lang/Boolean;")) == NULL) {
goto done;
}
NETTY_JNI_UTIL_LOAD_CLASS(env, long_class, "java/lang/Long", done);
if ((long_class_valueof = (*env)->GetStaticMethodID(env, long_class, "valueOf", "(J)Ljava/lang/Long;")) == NULL) {
goto done;
}
NETTY_JNI_UTIL_LOAD_CLASS(env, inet4address_class, "java/net/Inet4Address", done);
if ((inet4address_class_get_by_address = (*env)->GetStaticMethodID(env, inet4address_class, "getByAddress", "([B)Ljava/net/InetAddress;")) == NULL) {
goto done;
}
NETTY_JNI_UTIL_LOAD_CLASS(env, inet6address_class, "java/net/Inet6Address", done);
if ((inet6address_class_get_by_address = (*env)->GetStaticMethodID(env, inet6address_class, "getByAddress", "(Ljava/lang/String;[BI)Ljava/net/Inet6Address;")) == NULL) {
goto done;
}
NETTY_JNI_UTIL_LOAD_CLASS(env, inetsocketaddress_class, "java/net/InetSocketAddress", done);
NETTY_JNI_UTIL_GET_METHOD(env, inetsocketaddress_class, inetsocketaddress_class_constructor, "", "(Ljava/net/InetAddress;I)V", done);
NETTY_JNI_UTIL_LOAD_CLASS(env, object_class, "java/lang/Object", done);
NETTY_JNI_UTIL_PREPEND(packagePrefix, "io/netty/incubator/codec/quic/QuicheLogger", name, done);
NETTY_JNI_UTIL_LOAD_CLASS_WEAK(env, quiche_logger_class_weak, name, done);
NETTY_JNI_UTIL_NEW_LOCAL_FROM_WEAK(env, quiche_logger_class, quiche_logger_class_weak, done);
NETTY_JNI_UTIL_GET_METHOD(env, quiche_logger_class, quiche_logger_class_log, "log", "(Ljava/lang/String;)V", done);
// Initialize this module
// Load all c modules that we depend upon
if (netty_boringssl_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
goto done;
}
boringsslLoaded = 1;
staticPackagePrefix = packagePrefix;
ret = NETTY_JNI_UTIL_JNI_VERSION;
done:
if (ret == JNI_ERR) {
if (staticallyRegistered == 1) {
netty_jni_util_unregister_natives(env, packagePrefix, STATICALLY_CLASSNAME);
}
if (nativeRegistered == 1) {
netty_jni_util_unregister_natives(env, packagePrefix, QUICHE_CLASSNAME);
}
if (boringsslLoaded == 1) {
netty_boringssl_JNI_OnUnload(env, packagePrefix);
}
NETTY_JNI_UTIL_UNLOAD_CLASS_WEAK(env, quiche_logger_class_weak);
NETTY_JNI_UTIL_UNLOAD_CLASS(env, integer_class);
NETTY_JNI_UTIL_UNLOAD_CLASS(env, boolean_class);
NETTY_JNI_UTIL_UNLOAD_CLASS(env, long_class);
NETTY_JNI_UTIL_UNLOAD_CLASS(env, inet4address_class);
NETTY_JNI_UTIL_UNLOAD_CLASS(env, inet6address_class);
NETTY_JNI_UTIL_UNLOAD_CLASS(env, inetsocketaddress_class);
NETTY_JNI_UTIL_UNLOAD_CLASS(env, object_class);
netty_jni_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize());
}
NETTY_JNI_UTIL_DELETE_LOCAL(env, quiche_logger_class);
return ret;
}
static void netty_quiche_JNI_OnUnload(JNIEnv* env) {
netty_boringssl_JNI_OnUnload(env, staticPackagePrefix);
NETTY_JNI_UTIL_UNLOAD_CLASS_WEAK(env, quiche_logger_class_weak);
NETTY_JNI_UTIL_UNLOAD_CLASS(env, integer_class);
NETTY_JNI_UTIL_UNLOAD_CLASS(env, boolean_class);
NETTY_JNI_UTIL_UNLOAD_CLASS(env, long_class);
NETTY_JNI_UTIL_UNLOAD_CLASS(env, inet4address_class);
NETTY_JNI_UTIL_UNLOAD_CLASS(env, inet6address_class);
NETTY_JNI_UTIL_UNLOAD_CLASS(env, inetsocketaddress_class);
NETTY_JNI_UTIL_UNLOAD_CLASS(env, object_class);
netty_jni_util_unregister_natives(env, staticPackagePrefix, STATICALLY_CLASSNAME);
netty_jni_util_unregister_natives(env, staticPackagePrefix, QUICHE_CLASSNAME);
if (quiche_logger != NULL) {
(*env)->DeleteGlobalRef(env, quiche_logger);
quiche_logger = NULL;
}
free((void*) staticPackagePrefix);
staticPackagePrefix = NULL;
}
// Invoked by the JVM when statically linked
// We build with -fvisibility=hidden so ensure we mark everything that needs to be visible with JNIEXPORT
// https://mail.openjdk.java.net/pipermail/core-libs-dev/2013-February/014549.html
// Invoked by the JVM when statically linked
JNIEXPORT jint JNI_OnLoad_netty_quiche(JavaVM* vm, void* reserved) {
global_vm = vm;
return netty_jni_util_JNI_OnLoad(vm, reserved, LIBRARYNAME, netty_quiche_JNI_OnLoad);
}
// Invoked by the JVM when statically linked
JNIEXPORT void JNI_OnUnload_netty_quiche(JavaVM* vm, void* reserved) {
netty_jni_util_JNI_OnUnload(vm, reserved, netty_quiche_JNI_OnUnload);
global_vm = NULL;
}
#ifndef NETTY_QUIC_BUILD_STATIC
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
global_vm = vm;
return netty_jni_util_JNI_OnLoad(vm, reserved, LIBRARYNAME, netty_quiche_JNI_OnLoad);
}
JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved) {
netty_jni_util_JNI_OnUnload(vm, reserved, netty_quiche_JNI_OnUnload);
global_vm = NULL;
}
#endif /* NETTY_QUIC_BUILD_STATIC */