diff --git a/build.gradle b/build.gradle index ad080fc..04605a4 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,6 @@ plugins { id 'signing' id "io.github.gradle-nexus.publish-plugin" version "2.0.0-rc-1" id "com.google.osdetector" version "1.7.3" - id 'org.xbib.gradle.plugin.c' version '3.1.0' } wrapper { @@ -32,9 +31,7 @@ ext { apply plugin: 'com.google.osdetector' subprojects { - if (it.name.endsWith('-native')) { - apply from: rootProject.file('gradle/compile/c.gradle') - } else { + if (!it.name.endsWith('-native')) { apply from: rootProject.file('gradle/repositories/maven.gradle') apply from: rootProject.file('gradle/compile/java.gradle') apply from: rootProject.file('gradle/test/junit5.gradle') diff --git a/gradle/compile/cmake.gradle b/gradle/compile/cmake.gradle new file mode 100644 index 0000000..c36e740 --- /dev/null +++ b/gradle/compile/cmake.gradle @@ -0,0 +1 @@ +apply plugin: 'org.xbib.gradle.plugin.cmake' diff --git a/gradle/test/junit5.gradle b/gradle/test/junit5.gradle index d47aa30..d984d4a 100644 --- a/gradle/test/junit5.gradle +++ b/gradle/test/junit5.gradle @@ -11,10 +11,9 @@ dependencies { test { useJUnitPlatform() failFast = false - testLogging { - events 'STARTED', 'PASSED', 'FAILED', 'SKIPPED' - showStandardStreams = true - } + ignoreFailures = true + minHeapSize = "1g" // initial heap size + maxHeapSize = "2g" // maximum heap size jvmArgs '--add-exports=java.base/jdk.internal=ALL-UNNAMED', '--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED', '--add-exports=java.base/sun.nio.ch=ALL-UNNAMED', @@ -28,6 +27,10 @@ test { '--add-opens=jdk.unsupported/sun.misc=ALL-UNNAMED', '-Dio.netty.bootstrap.extensions=serviceload' systemProperty 'java.util.logging.config.file', 'src/test/resources/logging.properties' + testLogging { + events 'STARTED', 'PASSED', 'FAILED', 'SKIPPED' + showStandardStreams = true + } afterSuite { desc, result -> if (!desc.parent) { println "\nTest result: ${result.resultType}" diff --git a/netty-channel-epoll-native/build.gradle b/netty-channel-epoll-native/build.gradle index f526963..7a638b7 100644 --- a/netty-channel-epoll-native/build.gradle +++ b/netty-channel-epoll-native/build.gradle @@ -1,4 +1,7 @@ +/* currently we do not build our C code natively, but we provide copies of the binaries in META-INF/native */ + +apply plugin: 'base' task nettyEpollLinuxX8664(type: Jar) { destinationDirectory.set(project.layout.buildDirectory.dir('libs')) @@ -16,13 +19,13 @@ configurations { 'linux-x86_64' { canBeConsumed = true canBeResolved = false - attributes { + /*attributes { attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category, Category.LIBRARY)) attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage, Usage.JAVA_RUNTIME)) attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling, Bundling.EXTERNAL)) attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, JavaVersion.current().majorVersion.toInteger()) attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements, 'linux-x86_64')) - } + }*/ } } @@ -76,4 +79,4 @@ publishing { } } } -} \ No newline at end of file +} diff --git a/netty-channel-unix-native/CNakeFile.txt b/netty-channel-unix-native/CNakeFile.txt deleted file mode 100644 index c70d8c6..0000000 --- a/netty-channel-unix-native/CNakeFile.txt +++ /dev/null @@ -1,40 +0,0 @@ -cmake_minimum_required(VERSION 3.13 FATAL_ERROR) - -project(netty-channel-unix-native VERSION 4.1.104 LANGUAGES CXX) - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) - -include(GNUInstallDirs) -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}) - -# jvm -find_package(Java REQUIRED) -# https://stackoverflow.com/questions/51047978/cmake-could-not-find-jni -set(JAVA_AWT_LIBRARY NotNeeded) -set(JAVA_JVM_LIBRARY NotNeeded) -find_package(JNI REQUIRED) - -include_directories(${JNI_INCLUDE_DIRS}) - -# force off-tree build -if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) - message(FATAL_ERROR "CMake generation is not allowed within the source directory! - Remove the CMakeCache.txt file and try again from another folder, e.g.: - mkdir build && cd build - cmake .. - ") -endif() - -# default to Release build -if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Release CACHE STRING - "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." - FORCE) -endif() - -include_directories(src/main/include) -add_subdirectory(src/main/c) \ No newline at end of file diff --git a/netty-channel-unix-native/build.gradle b/netty-channel-unix-native/build.gradle index d0cf5d5..9f08e7d 100644 --- a/netty-channel-unix-native/build.gradle +++ b/netty-channel-unix-native/build.gradle @@ -1,10 +1,3 @@ +/* currently we do not build our C code natively, but we provide copies of the binaries in META-INF/native */ -tasks.register("compile", org.xbib.gradle.plugin.c.tasks.ExtendedCCompile) { - group = "build" - source(layout.projectDirectory.files("src/main/c").asFileTree) - includes(layout.projectDirectory.files("src/main/headers")) - toolChain.set(c.localTool("12.3.1", "/usr/bin/gcc", ".o")) - compilerArgs.addAll('-v', '-O3', '-Werror', '-Wno-attributes', '-fPIC', '-fno-omit-frame-pointer', '-Wunused-variable', '-fvisibility=hidden') - targetPlatform.set(c.platform()) - objectFileDir.set(layout.buildDirectory.dir("libs")) -} +/* the static library is included in other native builds, so nothing is provided here */ diff --git a/netty-channel-unix-native/src/main/headers/jni.h b/netty-channel-unix-native/src/main/headers/jni.h deleted file mode 100644 index c85da1b..0000000 --- a/netty-channel-unix-native/src/main/headers/jni.h +++ /dev/null @@ -1,2001 +0,0 @@ -/* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * We used part of Netscape's Java Runtime Interface (JRI) as the starting - * point of our design and implementation. - */ - -/****************************************************************************** - * Java Runtime Interface - * Copyright (c) 1996 Netscape Communications Corporation. All rights reserved. - *****************************************************************************/ - -#ifndef _JAVASOFT_JNI_H_ -#define _JAVASOFT_JNI_H_ - -#include -#include - -/* jni_md.h contains the machine-dependent typedefs for jbyte, jint - and jlong */ - -#include "jni_md.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * JNI Types - */ - -#ifndef JNI_TYPES_ALREADY_DEFINED_IN_JNI_MD_H - -typedef unsigned char jboolean; -typedef unsigned short jchar; -typedef short jshort; -typedef float jfloat; -typedef double jdouble; - -typedef jint jsize; - -#ifdef __cplusplus - -class _jobject {}; -class _jclass : public _jobject {}; -class _jthrowable : public _jobject {}; -class _jstring : public _jobject {}; -class _jarray : public _jobject {}; -class _jbooleanArray : public _jarray {}; -class _jbyteArray : public _jarray {}; -class _jcharArray : public _jarray {}; -class _jshortArray : public _jarray {}; -class _jintArray : public _jarray {}; -class _jlongArray : public _jarray {}; -class _jfloatArray : public _jarray {}; -class _jdoubleArray : public _jarray {}; -class _jobjectArray : public _jarray {}; - -typedef _jobject *jobject; -typedef _jclass *jclass; -typedef _jthrowable *jthrowable; -typedef _jstring *jstring; -typedef _jarray *jarray; -typedef _jbooleanArray *jbooleanArray; -typedef _jbyteArray *jbyteArray; -typedef _jcharArray *jcharArray; -typedef _jshortArray *jshortArray; -typedef _jintArray *jintArray; -typedef _jlongArray *jlongArray; -typedef _jfloatArray *jfloatArray; -typedef _jdoubleArray *jdoubleArray; -typedef _jobjectArray *jobjectArray; - -#else - -struct _jobject; - -typedef struct _jobject *jobject; -typedef jobject jclass; -typedef jobject jthrowable; -typedef jobject jstring; -typedef jobject jarray; -typedef jarray jbooleanArray; -typedef jarray jbyteArray; -typedef jarray jcharArray; -typedef jarray jshortArray; -typedef jarray jintArray; -typedef jarray jlongArray; -typedef jarray jfloatArray; -typedef jarray jdoubleArray; -typedef jarray jobjectArray; - -#endif - -typedef jobject jweak; - -typedef union jvalue { - jboolean z; - jbyte b; - jchar c; - jshort s; - jint i; - jlong j; - jfloat f; - jdouble d; - jobject l; -} jvalue; - -struct _jfieldID; -typedef struct _jfieldID *jfieldID; - -struct _jmethodID; -typedef struct _jmethodID *jmethodID; - -/* Return values from jobjectRefType */ -typedef enum _jobjectType { - JNIInvalidRefType = 0, - JNILocalRefType = 1, - JNIGlobalRefType = 2, - JNIWeakGlobalRefType = 3 -} jobjectRefType; - - -#endif /* JNI_TYPES_ALREADY_DEFINED_IN_JNI_MD_H */ - -/* - * jboolean constants - */ - -#define JNI_FALSE 0 -#define JNI_TRUE 1 - -/* - * possible return values for JNI functions. - */ - -#define JNI_OK 0 /* success */ -#define JNI_ERR (-1) /* unknown error */ -#define JNI_EDETACHED (-2) /* thread detached from the VM */ -#define JNI_EVERSION (-3) /* JNI version error */ -#define JNI_ENOMEM (-4) /* not enough memory */ -#define JNI_EEXIST (-5) /* VM already created */ -#define JNI_EINVAL (-6) /* invalid arguments */ - -/* - * used in ReleaseScalarArrayElements - */ - -#define JNI_COMMIT 1 -#define JNI_ABORT 2 - -/* - * used in RegisterNatives to describe native method name, signature, - * and function pointer. - */ - -typedef struct { - char *name; - char *signature; - void *fnPtr; -} JNINativeMethod; - -/* - * JNI Native Method Interface. - */ - -struct JNINativeInterface_; - -struct JNIEnv_; - -#ifdef __cplusplus -typedef JNIEnv_ JNIEnv; -#else -typedef const struct JNINativeInterface_ *JNIEnv; -#endif - -/* - * JNI Invocation Interface. - */ - -struct JNIInvokeInterface_; - -struct JavaVM_; - -#ifdef __cplusplus -typedef JavaVM_ JavaVM; -#else -typedef const struct JNIInvokeInterface_ *JavaVM; -#endif - -struct JNINativeInterface_ { - void *reserved0; - void *reserved1; - void *reserved2; - - void *reserved3; - jint (JNICALL *GetVersion)(JNIEnv *env); - - jclass (JNICALL *DefineClass) - (JNIEnv *env, const char *name, jobject loader, const jbyte *buf, - jsize len); - jclass (JNICALL *FindClass) - (JNIEnv *env, const char *name); - - jmethodID (JNICALL *FromReflectedMethod) - (JNIEnv *env, jobject method); - jfieldID (JNICALL *FromReflectedField) - (JNIEnv *env, jobject field); - - jobject (JNICALL *ToReflectedMethod) - (JNIEnv *env, jclass cls, jmethodID methodID, jboolean isStatic); - - jclass (JNICALL *GetSuperclass) - (JNIEnv *env, jclass sub); - jboolean (JNICALL *IsAssignableFrom) - (JNIEnv *env, jclass sub, jclass sup); - - jobject (JNICALL *ToReflectedField) - (JNIEnv *env, jclass cls, jfieldID fieldID, jboolean isStatic); - - jint (JNICALL *Throw) - (JNIEnv *env, jthrowable obj); - jint (JNICALL *ThrowNew) - (JNIEnv *env, jclass clazz, const char *msg); - jthrowable (JNICALL *ExceptionOccurred) - (JNIEnv *env); - void (JNICALL *ExceptionDescribe) - (JNIEnv *env); - void (JNICALL *ExceptionClear) - (JNIEnv *env); - void (JNICALL *FatalError) - (JNIEnv *env, const char *msg); - - jint (JNICALL *PushLocalFrame) - (JNIEnv *env, jint capacity); - jobject (JNICALL *PopLocalFrame) - (JNIEnv *env, jobject result); - - jobject (JNICALL *NewGlobalRef) - (JNIEnv *env, jobject lobj); - void (JNICALL *DeleteGlobalRef) - (JNIEnv *env, jobject gref); - void (JNICALL *DeleteLocalRef) - (JNIEnv *env, jobject obj); - jboolean (JNICALL *IsSameObject) - (JNIEnv *env, jobject obj1, jobject obj2); - jobject (JNICALL *NewLocalRef) - (JNIEnv *env, jobject ref); - jint (JNICALL *EnsureLocalCapacity) - (JNIEnv *env, jint capacity); - - jobject (JNICALL *AllocObject) - (JNIEnv *env, jclass clazz); - jobject (JNICALL *NewObject) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jobject (JNICALL *NewObjectV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jobject (JNICALL *NewObjectA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - jclass (JNICALL *GetObjectClass) - (JNIEnv *env, jobject obj); - jboolean (JNICALL *IsInstanceOf) - (JNIEnv *env, jobject obj, jclass clazz); - - jmethodID (JNICALL *GetMethodID) - (JNIEnv *env, jclass clazz, const char *name, const char *sig); - - jobject (JNICALL *CallObjectMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - jobject (JNICALL *CallObjectMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - jobject (JNICALL *CallObjectMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args); - - jboolean (JNICALL *CallBooleanMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - jboolean (JNICALL *CallBooleanMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - jboolean (JNICALL *CallBooleanMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args); - - jbyte (JNICALL *CallByteMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - jbyte (JNICALL *CallByteMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - jbyte (JNICALL *CallByteMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); - - jchar (JNICALL *CallCharMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - jchar (JNICALL *CallCharMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - jchar (JNICALL *CallCharMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); - - jshort (JNICALL *CallShortMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - jshort (JNICALL *CallShortMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - jshort (JNICALL *CallShortMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); - - jint (JNICALL *CallIntMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - jint (JNICALL *CallIntMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - jint (JNICALL *CallIntMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); - - jlong (JNICALL *CallLongMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - jlong (JNICALL *CallLongMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - jlong (JNICALL *CallLongMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); - - jfloat (JNICALL *CallFloatMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - jfloat (JNICALL *CallFloatMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - jfloat (JNICALL *CallFloatMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); - - jdouble (JNICALL *CallDoubleMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - jdouble (JNICALL *CallDoubleMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - jdouble (JNICALL *CallDoubleMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); - - void (JNICALL *CallVoidMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - void (JNICALL *CallVoidMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - void (JNICALL *CallVoidMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args); - - jobject (JNICALL *CallNonvirtualObjectMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - jobject (JNICALL *CallNonvirtualObjectMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - jobject (JNICALL *CallNonvirtualObjectMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue * args); - - jboolean (JNICALL *CallNonvirtualBooleanMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - jboolean (JNICALL *CallNonvirtualBooleanMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - jboolean (JNICALL *CallNonvirtualBooleanMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue * args); - - jbyte (JNICALL *CallNonvirtualByteMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - jbyte (JNICALL *CallNonvirtualByteMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - jbyte (JNICALL *CallNonvirtualByteMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue *args); - - jchar (JNICALL *CallNonvirtualCharMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - jchar (JNICALL *CallNonvirtualCharMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - jchar (JNICALL *CallNonvirtualCharMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue *args); - - jshort (JNICALL *CallNonvirtualShortMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - jshort (JNICALL *CallNonvirtualShortMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - jshort (JNICALL *CallNonvirtualShortMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue *args); - - jint (JNICALL *CallNonvirtualIntMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - jint (JNICALL *CallNonvirtualIntMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - jint (JNICALL *CallNonvirtualIntMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue *args); - - jlong (JNICALL *CallNonvirtualLongMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - jlong (JNICALL *CallNonvirtualLongMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - jlong (JNICALL *CallNonvirtualLongMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue *args); - - jfloat (JNICALL *CallNonvirtualFloatMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - jfloat (JNICALL *CallNonvirtualFloatMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - jfloat (JNICALL *CallNonvirtualFloatMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue *args); - - jdouble (JNICALL *CallNonvirtualDoubleMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - jdouble (JNICALL *CallNonvirtualDoubleMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - jdouble (JNICALL *CallNonvirtualDoubleMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue *args); - - void (JNICALL *CallNonvirtualVoidMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - void (JNICALL *CallNonvirtualVoidMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - void (JNICALL *CallNonvirtualVoidMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue * args); - - jfieldID (JNICALL *GetFieldID) - (JNIEnv *env, jclass clazz, const char *name, const char *sig); - - jobject (JNICALL *GetObjectField) - (JNIEnv *env, jobject obj, jfieldID fieldID); - jboolean (JNICALL *GetBooleanField) - (JNIEnv *env, jobject obj, jfieldID fieldID); - jbyte (JNICALL *GetByteField) - (JNIEnv *env, jobject obj, jfieldID fieldID); - jchar (JNICALL *GetCharField) - (JNIEnv *env, jobject obj, jfieldID fieldID); - jshort (JNICALL *GetShortField) - (JNIEnv *env, jobject obj, jfieldID fieldID); - jint (JNICALL *GetIntField) - (JNIEnv *env, jobject obj, jfieldID fieldID); - jlong (JNICALL *GetLongField) - (JNIEnv *env, jobject obj, jfieldID fieldID); - jfloat (JNICALL *GetFloatField) - (JNIEnv *env, jobject obj, jfieldID fieldID); - jdouble (JNICALL *GetDoubleField) - (JNIEnv *env, jobject obj, jfieldID fieldID); - - void (JNICALL *SetObjectField) - (JNIEnv *env, jobject obj, jfieldID fieldID, jobject val); - void (JNICALL *SetBooleanField) - (JNIEnv *env, jobject obj, jfieldID fieldID, jboolean val); - void (JNICALL *SetByteField) - (JNIEnv *env, jobject obj, jfieldID fieldID, jbyte val); - void (JNICALL *SetCharField) - (JNIEnv *env, jobject obj, jfieldID fieldID, jchar val); - void (JNICALL *SetShortField) - (JNIEnv *env, jobject obj, jfieldID fieldID, jshort val); - void (JNICALL *SetIntField) - (JNIEnv *env, jobject obj, jfieldID fieldID, jint val); - void (JNICALL *SetLongField) - (JNIEnv *env, jobject obj, jfieldID fieldID, jlong val); - void (JNICALL *SetFloatField) - (JNIEnv *env, jobject obj, jfieldID fieldID, jfloat val); - void (JNICALL *SetDoubleField) - (JNIEnv *env, jobject obj, jfieldID fieldID, jdouble val); - - jmethodID (JNICALL *GetStaticMethodID) - (JNIEnv *env, jclass clazz, const char *name, const char *sig); - - jobject (JNICALL *CallStaticObjectMethod) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jobject (JNICALL *CallStaticObjectMethodV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jobject (JNICALL *CallStaticObjectMethodA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - jboolean (JNICALL *CallStaticBooleanMethod) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jboolean (JNICALL *CallStaticBooleanMethodV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jboolean (JNICALL *CallStaticBooleanMethodA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - jbyte (JNICALL *CallStaticByteMethod) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jbyte (JNICALL *CallStaticByteMethodV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jbyte (JNICALL *CallStaticByteMethodA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - jchar (JNICALL *CallStaticCharMethod) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jchar (JNICALL *CallStaticCharMethodV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jchar (JNICALL *CallStaticCharMethodA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - jshort (JNICALL *CallStaticShortMethod) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jshort (JNICALL *CallStaticShortMethodV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jshort (JNICALL *CallStaticShortMethodA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - jint (JNICALL *CallStaticIntMethod) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jint (JNICALL *CallStaticIntMethodV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jint (JNICALL *CallStaticIntMethodA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - jlong (JNICALL *CallStaticLongMethod) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jlong (JNICALL *CallStaticLongMethodV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jlong (JNICALL *CallStaticLongMethodA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - jfloat (JNICALL *CallStaticFloatMethod) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jfloat (JNICALL *CallStaticFloatMethodV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jfloat (JNICALL *CallStaticFloatMethodA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - jdouble (JNICALL *CallStaticDoubleMethod) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jdouble (JNICALL *CallStaticDoubleMethodV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jdouble (JNICALL *CallStaticDoubleMethodA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - void (JNICALL *CallStaticVoidMethod) - (JNIEnv *env, jclass cls, jmethodID methodID, ...); - void (JNICALL *CallStaticVoidMethodV) - (JNIEnv *env, jclass cls, jmethodID methodID, va_list args); - void (JNICALL *CallStaticVoidMethodA) - (JNIEnv *env, jclass cls, jmethodID methodID, const jvalue * args); - - jfieldID (JNICALL *GetStaticFieldID) - (JNIEnv *env, jclass clazz, const char *name, const char *sig); - jobject (JNICALL *GetStaticObjectField) - (JNIEnv *env, jclass clazz, jfieldID fieldID); - jboolean (JNICALL *GetStaticBooleanField) - (JNIEnv *env, jclass clazz, jfieldID fieldID); - jbyte (JNICALL *GetStaticByteField) - (JNIEnv *env, jclass clazz, jfieldID fieldID); - jchar (JNICALL *GetStaticCharField) - (JNIEnv *env, jclass clazz, jfieldID fieldID); - jshort (JNICALL *GetStaticShortField) - (JNIEnv *env, jclass clazz, jfieldID fieldID); - jint (JNICALL *GetStaticIntField) - (JNIEnv *env, jclass clazz, jfieldID fieldID); - jlong (JNICALL *GetStaticLongField) - (JNIEnv *env, jclass clazz, jfieldID fieldID); - jfloat (JNICALL *GetStaticFloatField) - (JNIEnv *env, jclass clazz, jfieldID fieldID); - jdouble (JNICALL *GetStaticDoubleField) - (JNIEnv *env, jclass clazz, jfieldID fieldID); - - void (JNICALL *SetStaticObjectField) - (JNIEnv *env, jclass clazz, jfieldID fieldID, jobject value); - void (JNICALL *SetStaticBooleanField) - (JNIEnv *env, jclass clazz, jfieldID fieldID, jboolean value); - void (JNICALL *SetStaticByteField) - (JNIEnv *env, jclass clazz, jfieldID fieldID, jbyte value); - void (JNICALL *SetStaticCharField) - (JNIEnv *env, jclass clazz, jfieldID fieldID, jchar value); - void (JNICALL *SetStaticShortField) - (JNIEnv *env, jclass clazz, jfieldID fieldID, jshort value); - void (JNICALL *SetStaticIntField) - (JNIEnv *env, jclass clazz, jfieldID fieldID, jint value); - void (JNICALL *SetStaticLongField) - (JNIEnv *env, jclass clazz, jfieldID fieldID, jlong value); - void (JNICALL *SetStaticFloatField) - (JNIEnv *env, jclass clazz, jfieldID fieldID, jfloat value); - void (JNICALL *SetStaticDoubleField) - (JNIEnv *env, jclass clazz, jfieldID fieldID, jdouble value); - - jstring (JNICALL *NewString) - (JNIEnv *env, const jchar *unicode, jsize len); - jsize (JNICALL *GetStringLength) - (JNIEnv *env, jstring str); - const jchar *(JNICALL *GetStringChars) - (JNIEnv *env, jstring str, jboolean *isCopy); - void (JNICALL *ReleaseStringChars) - (JNIEnv *env, jstring str, const jchar *chars); - - jstring (JNICALL *NewStringUTF) - (JNIEnv *env, const char *utf); - jsize (JNICALL *GetStringUTFLength) - (JNIEnv *env, jstring str); - const char* (JNICALL *GetStringUTFChars) - (JNIEnv *env, jstring str, jboolean *isCopy); - void (JNICALL *ReleaseStringUTFChars) - (JNIEnv *env, jstring str, const char* chars); - - - jsize (JNICALL *GetArrayLength) - (JNIEnv *env, jarray array); - - jobjectArray (JNICALL *NewObjectArray) - (JNIEnv *env, jsize len, jclass clazz, jobject init); - jobject (JNICALL *GetObjectArrayElement) - (JNIEnv *env, jobjectArray array, jsize index); - void (JNICALL *SetObjectArrayElement) - (JNIEnv *env, jobjectArray array, jsize index, jobject val); - - jbooleanArray (JNICALL *NewBooleanArray) - (JNIEnv *env, jsize len); - jbyteArray (JNICALL *NewByteArray) - (JNIEnv *env, jsize len); - jcharArray (JNICALL *NewCharArray) - (JNIEnv *env, jsize len); - jshortArray (JNICALL *NewShortArray) - (JNIEnv *env, jsize len); - jintArray (JNICALL *NewIntArray) - (JNIEnv *env, jsize len); - jlongArray (JNICALL *NewLongArray) - (JNIEnv *env, jsize len); - jfloatArray (JNICALL *NewFloatArray) - (JNIEnv *env, jsize len); - jdoubleArray (JNICALL *NewDoubleArray) - (JNIEnv *env, jsize len); - - jboolean * (JNICALL *GetBooleanArrayElements) - (JNIEnv *env, jbooleanArray array, jboolean *isCopy); - jbyte * (JNICALL *GetByteArrayElements) - (JNIEnv *env, jbyteArray array, jboolean *isCopy); - jchar * (JNICALL *GetCharArrayElements) - (JNIEnv *env, jcharArray array, jboolean *isCopy); - jshort * (JNICALL *GetShortArrayElements) - (JNIEnv *env, jshortArray array, jboolean *isCopy); - jint * (JNICALL *GetIntArrayElements) - (JNIEnv *env, jintArray array, jboolean *isCopy); - jlong * (JNICALL *GetLongArrayElements) - (JNIEnv *env, jlongArray array, jboolean *isCopy); - jfloat * (JNICALL *GetFloatArrayElements) - (JNIEnv *env, jfloatArray array, jboolean *isCopy); - jdouble * (JNICALL *GetDoubleArrayElements) - (JNIEnv *env, jdoubleArray array, jboolean *isCopy); - - void (JNICALL *ReleaseBooleanArrayElements) - (JNIEnv *env, jbooleanArray array, jboolean *elems, jint mode); - void (JNICALL *ReleaseByteArrayElements) - (JNIEnv *env, jbyteArray array, jbyte *elems, jint mode); - void (JNICALL *ReleaseCharArrayElements) - (JNIEnv *env, jcharArray array, jchar *elems, jint mode); - void (JNICALL *ReleaseShortArrayElements) - (JNIEnv *env, jshortArray array, jshort *elems, jint mode); - void (JNICALL *ReleaseIntArrayElements) - (JNIEnv *env, jintArray array, jint *elems, jint mode); - void (JNICALL *ReleaseLongArrayElements) - (JNIEnv *env, jlongArray array, jlong *elems, jint mode); - void (JNICALL *ReleaseFloatArrayElements) - (JNIEnv *env, jfloatArray array, jfloat *elems, jint mode); - void (JNICALL *ReleaseDoubleArrayElements) - (JNIEnv *env, jdoubleArray array, jdouble *elems, jint mode); - - void (JNICALL *GetBooleanArrayRegion) - (JNIEnv *env, jbooleanArray array, jsize start, jsize l, jboolean *buf); - void (JNICALL *GetByteArrayRegion) - (JNIEnv *env, jbyteArray array, jsize start, jsize len, jbyte *buf); - void (JNICALL *GetCharArrayRegion) - (JNIEnv *env, jcharArray array, jsize start, jsize len, jchar *buf); - void (JNICALL *GetShortArrayRegion) - (JNIEnv *env, jshortArray array, jsize start, jsize len, jshort *buf); - void (JNICALL *GetIntArrayRegion) - (JNIEnv *env, jintArray array, jsize start, jsize len, jint *buf); - void (JNICALL *GetLongArrayRegion) - (JNIEnv *env, jlongArray array, jsize start, jsize len, jlong *buf); - void (JNICALL *GetFloatArrayRegion) - (JNIEnv *env, jfloatArray array, jsize start, jsize len, jfloat *buf); - void (JNICALL *GetDoubleArrayRegion) - (JNIEnv *env, jdoubleArray array, jsize start, jsize len, jdouble *buf); - - void (JNICALL *SetBooleanArrayRegion) - (JNIEnv *env, jbooleanArray array, jsize start, jsize l, const jboolean *buf); - void (JNICALL *SetByteArrayRegion) - (JNIEnv *env, jbyteArray array, jsize start, jsize len, const jbyte *buf); - void (JNICALL *SetCharArrayRegion) - (JNIEnv *env, jcharArray array, jsize start, jsize len, const jchar *buf); - void (JNICALL *SetShortArrayRegion) - (JNIEnv *env, jshortArray array, jsize start, jsize len, const jshort *buf); - void (JNICALL *SetIntArrayRegion) - (JNIEnv *env, jintArray array, jsize start, jsize len, const jint *buf); - void (JNICALL *SetLongArrayRegion) - (JNIEnv *env, jlongArray array, jsize start, jsize len, const jlong *buf); - void (JNICALL *SetFloatArrayRegion) - (JNIEnv *env, jfloatArray array, jsize start, jsize len, const jfloat *buf); - void (JNICALL *SetDoubleArrayRegion) - (JNIEnv *env, jdoubleArray array, jsize start, jsize len, const jdouble *buf); - - jint (JNICALL *RegisterNatives) - (JNIEnv *env, jclass clazz, const JNINativeMethod *methods, - jint nMethods); - jint (JNICALL *UnregisterNatives) - (JNIEnv *env, jclass clazz); - - jint (JNICALL *MonitorEnter) - (JNIEnv *env, jobject obj); - jint (JNICALL *MonitorExit) - (JNIEnv *env, jobject obj); - - jint (JNICALL *GetJavaVM) - (JNIEnv *env, JavaVM **vm); - - void (JNICALL *GetStringRegion) - (JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf); - void (JNICALL *GetStringUTFRegion) - (JNIEnv *env, jstring str, jsize start, jsize len, char *buf); - - void * (JNICALL *GetPrimitiveArrayCritical) - (JNIEnv *env, jarray array, jboolean *isCopy); - void (JNICALL *ReleasePrimitiveArrayCritical) - (JNIEnv *env, jarray array, void *carray, jint mode); - - const jchar * (JNICALL *GetStringCritical) - (JNIEnv *env, jstring string, jboolean *isCopy); - void (JNICALL *ReleaseStringCritical) - (JNIEnv *env, jstring string, const jchar *cstring); - - jweak (JNICALL *NewWeakGlobalRef) - (JNIEnv *env, jobject obj); - void (JNICALL *DeleteWeakGlobalRef) - (JNIEnv *env, jweak ref); - - jboolean (JNICALL *ExceptionCheck) - (JNIEnv *env); - - jobject (JNICALL *NewDirectByteBuffer) - (JNIEnv* env, void* address, jlong capacity); - void* (JNICALL *GetDirectBufferAddress) - (JNIEnv* env, jobject buf); - jlong (JNICALL *GetDirectBufferCapacity) - (JNIEnv* env, jobject buf); - - /* New JNI 1.6 Features */ - - jobjectRefType (JNICALL *GetObjectRefType) - (JNIEnv* env, jobject obj); - - /* Module Features */ - - jobject (JNICALL *GetModule) - (JNIEnv* env, jclass clazz); - - /* Virtual threads */ - - jboolean (JNICALL *IsVirtualThread) - (JNIEnv* env, jobject obj); -}; - -/* - * We use inlined functions for C++ so that programmers can write: - * - * env->FindClass("java/lang/String") - * - * in C++ rather than: - * - * (*env)->FindClass(env, "java/lang/String") - * - * in C. - */ - -struct JNIEnv_ { - const struct JNINativeInterface_ *functions; -#ifdef __cplusplus - - jint GetVersion() { - return functions->GetVersion(this); - } - jclass DefineClass(const char *name, jobject loader, const jbyte *buf, - jsize len) { - return functions->DefineClass(this, name, loader, buf, len); - } - jclass FindClass(const char *name) { - return functions->FindClass(this, name); - } - jmethodID FromReflectedMethod(jobject method) { - return functions->FromReflectedMethod(this,method); - } - jfieldID FromReflectedField(jobject field) { - return functions->FromReflectedField(this,field); - } - - jobject ToReflectedMethod(jclass cls, jmethodID methodID, jboolean isStatic) { - return functions->ToReflectedMethod(this, cls, methodID, isStatic); - } - - jclass GetSuperclass(jclass sub) { - return functions->GetSuperclass(this, sub); - } - jboolean IsAssignableFrom(jclass sub, jclass sup) { - return functions->IsAssignableFrom(this, sub, sup); - } - - jobject ToReflectedField(jclass cls, jfieldID fieldID, jboolean isStatic) { - return functions->ToReflectedField(this,cls,fieldID,isStatic); - } - - jint Throw(jthrowable obj) { - return functions->Throw(this, obj); - } - jint ThrowNew(jclass clazz, const char *msg) { - return functions->ThrowNew(this, clazz, msg); - } - jthrowable ExceptionOccurred() { - return functions->ExceptionOccurred(this); - } - void ExceptionDescribe() { - functions->ExceptionDescribe(this); - } - void ExceptionClear() { - functions->ExceptionClear(this); - } - void FatalError(const char *msg) { - functions->FatalError(this, msg); - } - - jint PushLocalFrame(jint capacity) { - return functions->PushLocalFrame(this,capacity); - } - jobject PopLocalFrame(jobject result) { - return functions->PopLocalFrame(this,result); - } - - jobject NewGlobalRef(jobject lobj) { - return functions->NewGlobalRef(this,lobj); - } - void DeleteGlobalRef(jobject gref) { - functions->DeleteGlobalRef(this,gref); - } - void DeleteLocalRef(jobject obj) { - functions->DeleteLocalRef(this, obj); - } - - jboolean IsSameObject(jobject obj1, jobject obj2) { - return functions->IsSameObject(this,obj1,obj2); - } - - jobject NewLocalRef(jobject ref) { - return functions->NewLocalRef(this,ref); - } - jint EnsureLocalCapacity(jint capacity) { - return functions->EnsureLocalCapacity(this,capacity); - } - - jobject AllocObject(jclass clazz) { - return functions->AllocObject(this,clazz); - } - jobject NewObject(jclass clazz, jmethodID methodID, ...) { - va_list args; - jobject result; - va_start(args, methodID); - result = functions->NewObjectV(this,clazz,methodID,args); - va_end(args); - return result; - } - jobject NewObjectV(jclass clazz, jmethodID methodID, - va_list args) { - return functions->NewObjectV(this,clazz,methodID,args); - } - jobject NewObjectA(jclass clazz, jmethodID methodID, - const jvalue *args) { - return functions->NewObjectA(this,clazz,methodID,args); - } - - jclass GetObjectClass(jobject obj) { - return functions->GetObjectClass(this,obj); - } - jboolean IsInstanceOf(jobject obj, jclass clazz) { - return functions->IsInstanceOf(this,obj,clazz); - } - - jmethodID GetMethodID(jclass clazz, const char *name, - const char *sig) { - return functions->GetMethodID(this,clazz,name,sig); - } - - jobject CallObjectMethod(jobject obj, jmethodID methodID, ...) { - va_list args; - jobject result; - va_start(args,methodID); - result = functions->CallObjectMethodV(this,obj,methodID,args); - va_end(args); - return result; - } - jobject CallObjectMethodV(jobject obj, jmethodID methodID, - va_list args) { - return functions->CallObjectMethodV(this,obj,methodID,args); - } - jobject CallObjectMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - return functions->CallObjectMethodA(this,obj,methodID,args); - } - - jboolean CallBooleanMethod(jobject obj, - jmethodID methodID, ...) { - va_list args; - jboolean result; - va_start(args,methodID); - result = functions->CallBooleanMethodV(this,obj,methodID,args); - va_end(args); - return result; - } - jboolean CallBooleanMethodV(jobject obj, jmethodID methodID, - va_list args) { - return functions->CallBooleanMethodV(this,obj,methodID,args); - } - jboolean CallBooleanMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - return functions->CallBooleanMethodA(this,obj,methodID, args); - } - - jbyte CallByteMethod(jobject obj, jmethodID methodID, ...) { - va_list args; - jbyte result; - va_start(args,methodID); - result = functions->CallByteMethodV(this,obj,methodID,args); - va_end(args); - return result; - } - jbyte CallByteMethodV(jobject obj, jmethodID methodID, - va_list args) { - return functions->CallByteMethodV(this,obj,methodID,args); - } - jbyte CallByteMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - return functions->CallByteMethodA(this,obj,methodID,args); - } - - jchar CallCharMethod(jobject obj, jmethodID methodID, ...) { - va_list args; - jchar result; - va_start(args,methodID); - result = functions->CallCharMethodV(this,obj,methodID,args); - va_end(args); - return result; - } - jchar CallCharMethodV(jobject obj, jmethodID methodID, - va_list args) { - return functions->CallCharMethodV(this,obj,methodID,args); - } - jchar CallCharMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - return functions->CallCharMethodA(this,obj,methodID,args); - } - - jshort CallShortMethod(jobject obj, jmethodID methodID, ...) { - va_list args; - jshort result; - va_start(args,methodID); - result = functions->CallShortMethodV(this,obj,methodID,args); - va_end(args); - return result; - } - jshort CallShortMethodV(jobject obj, jmethodID methodID, - va_list args) { - return functions->CallShortMethodV(this,obj,methodID,args); - } - jshort CallShortMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - return functions->CallShortMethodA(this,obj,methodID,args); - } - - jint CallIntMethod(jobject obj, jmethodID methodID, ...) { - va_list args; - jint result; - va_start(args,methodID); - result = functions->CallIntMethodV(this,obj,methodID,args); - va_end(args); - return result; - } - jint CallIntMethodV(jobject obj, jmethodID methodID, - va_list args) { - return functions->CallIntMethodV(this,obj,methodID,args); - } - jint CallIntMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - return functions->CallIntMethodA(this,obj,methodID,args); - } - - jlong CallLongMethod(jobject obj, jmethodID methodID, ...) { - va_list args; - jlong result; - va_start(args,methodID); - result = functions->CallLongMethodV(this,obj,methodID,args); - va_end(args); - return result; - } - jlong CallLongMethodV(jobject obj, jmethodID methodID, - va_list args) { - return functions->CallLongMethodV(this,obj,methodID,args); - } - jlong CallLongMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - return functions->CallLongMethodA(this,obj,methodID,args); - } - - jfloat CallFloatMethod(jobject obj, jmethodID methodID, ...) { - va_list args; - jfloat result; - va_start(args,methodID); - result = functions->CallFloatMethodV(this,obj,methodID,args); - va_end(args); - return result; - } - jfloat CallFloatMethodV(jobject obj, jmethodID methodID, - va_list args) { - return functions->CallFloatMethodV(this,obj,methodID,args); - } - jfloat CallFloatMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - return functions->CallFloatMethodA(this,obj,methodID,args); - } - - jdouble CallDoubleMethod(jobject obj, jmethodID methodID, ...) { - va_list args; - jdouble result; - va_start(args,methodID); - result = functions->CallDoubleMethodV(this,obj,methodID,args); - va_end(args); - return result; - } - jdouble CallDoubleMethodV(jobject obj, jmethodID methodID, - va_list args) { - return functions->CallDoubleMethodV(this,obj,methodID,args); - } - jdouble CallDoubleMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - return functions->CallDoubleMethodA(this,obj,methodID,args); - } - - void CallVoidMethod(jobject obj, jmethodID methodID, ...) { - va_list args; - va_start(args,methodID); - functions->CallVoidMethodV(this,obj,methodID,args); - va_end(args); - } - void CallVoidMethodV(jobject obj, jmethodID methodID, - va_list args) { - functions->CallVoidMethodV(this,obj,methodID,args); - } - void CallVoidMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - functions->CallVoidMethodA(this,obj,methodID,args); - } - - jobject CallNonvirtualObjectMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - jobject result; - va_start(args,methodID); - result = functions->CallNonvirtualObjectMethodV(this,obj,clazz, - methodID,args); - va_end(args); - return result; - } - jobject CallNonvirtualObjectMethodV(jobject obj, jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallNonvirtualObjectMethodV(this,obj,clazz, - methodID,args); - } - jobject CallNonvirtualObjectMethodA(jobject obj, jclass clazz, - jmethodID methodID, const jvalue * args) { - return functions->CallNonvirtualObjectMethodA(this,obj,clazz, - methodID,args); - } - - jboolean CallNonvirtualBooleanMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - jboolean result; - va_start(args,methodID); - result = functions->CallNonvirtualBooleanMethodV(this,obj,clazz, - methodID,args); - va_end(args); - return result; - } - jboolean CallNonvirtualBooleanMethodV(jobject obj, jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallNonvirtualBooleanMethodV(this,obj,clazz, - methodID,args); - } - jboolean CallNonvirtualBooleanMethodA(jobject obj, jclass clazz, - jmethodID methodID, const jvalue * args) { - return functions->CallNonvirtualBooleanMethodA(this,obj,clazz, - methodID, args); - } - - jbyte CallNonvirtualByteMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - jbyte result; - va_start(args,methodID); - result = functions->CallNonvirtualByteMethodV(this,obj,clazz, - methodID,args); - va_end(args); - return result; - } - jbyte CallNonvirtualByteMethodV(jobject obj, jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallNonvirtualByteMethodV(this,obj,clazz, - methodID,args); - } - jbyte CallNonvirtualByteMethodA(jobject obj, jclass clazz, - jmethodID methodID, const jvalue * args) { - return functions->CallNonvirtualByteMethodA(this,obj,clazz, - methodID,args); - } - - jchar CallNonvirtualCharMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - jchar result; - va_start(args,methodID); - result = functions->CallNonvirtualCharMethodV(this,obj,clazz, - methodID,args); - va_end(args); - return result; - } - jchar CallNonvirtualCharMethodV(jobject obj, jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallNonvirtualCharMethodV(this,obj,clazz, - methodID,args); - } - jchar CallNonvirtualCharMethodA(jobject obj, jclass clazz, - jmethodID methodID, const jvalue * args) { - return functions->CallNonvirtualCharMethodA(this,obj,clazz, - methodID,args); - } - - jshort CallNonvirtualShortMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - jshort result; - va_start(args,methodID); - result = functions->CallNonvirtualShortMethodV(this,obj,clazz, - methodID,args); - va_end(args); - return result; - } - jshort CallNonvirtualShortMethodV(jobject obj, jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallNonvirtualShortMethodV(this,obj,clazz, - methodID,args); - } - jshort CallNonvirtualShortMethodA(jobject obj, jclass clazz, - jmethodID methodID, const jvalue * args) { - return functions->CallNonvirtualShortMethodA(this,obj,clazz, - methodID,args); - } - - jint CallNonvirtualIntMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - jint result; - va_start(args,methodID); - result = functions->CallNonvirtualIntMethodV(this,obj,clazz, - methodID,args); - va_end(args); - return result; - } - jint CallNonvirtualIntMethodV(jobject obj, jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallNonvirtualIntMethodV(this,obj,clazz, - methodID,args); - } - jint CallNonvirtualIntMethodA(jobject obj, jclass clazz, - jmethodID methodID, const jvalue * args) { - return functions->CallNonvirtualIntMethodA(this,obj,clazz, - methodID,args); - } - - jlong CallNonvirtualLongMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - jlong result; - va_start(args,methodID); - result = functions->CallNonvirtualLongMethodV(this,obj,clazz, - methodID,args); - va_end(args); - return result; - } - jlong CallNonvirtualLongMethodV(jobject obj, jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallNonvirtualLongMethodV(this,obj,clazz, - methodID,args); - } - jlong CallNonvirtualLongMethodA(jobject obj, jclass clazz, - jmethodID methodID, const jvalue * args) { - return functions->CallNonvirtualLongMethodA(this,obj,clazz, - methodID,args); - } - - jfloat CallNonvirtualFloatMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - jfloat result; - va_start(args,methodID); - result = functions->CallNonvirtualFloatMethodV(this,obj,clazz, - methodID,args); - va_end(args); - return result; - } - jfloat CallNonvirtualFloatMethodV(jobject obj, jclass clazz, - jmethodID methodID, - va_list args) { - return functions->CallNonvirtualFloatMethodV(this,obj,clazz, - methodID,args); - } - jfloat CallNonvirtualFloatMethodA(jobject obj, jclass clazz, - jmethodID methodID, - const jvalue * args) { - return functions->CallNonvirtualFloatMethodA(this,obj,clazz, - methodID,args); - } - - jdouble CallNonvirtualDoubleMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - jdouble result; - va_start(args,methodID); - result = functions->CallNonvirtualDoubleMethodV(this,obj,clazz, - methodID,args); - va_end(args); - return result; - } - jdouble CallNonvirtualDoubleMethodV(jobject obj, jclass clazz, - jmethodID methodID, - va_list args) { - return functions->CallNonvirtualDoubleMethodV(this,obj,clazz, - methodID,args); - } - jdouble CallNonvirtualDoubleMethodA(jobject obj, jclass clazz, - jmethodID methodID, - const jvalue * args) { - return functions->CallNonvirtualDoubleMethodA(this,obj,clazz, - methodID,args); - } - - void CallNonvirtualVoidMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - va_start(args,methodID); - functions->CallNonvirtualVoidMethodV(this,obj,clazz,methodID,args); - va_end(args); - } - void CallNonvirtualVoidMethodV(jobject obj, jclass clazz, - jmethodID methodID, - va_list args) { - functions->CallNonvirtualVoidMethodV(this,obj,clazz,methodID,args); - } - void CallNonvirtualVoidMethodA(jobject obj, jclass clazz, - jmethodID methodID, - const jvalue * args) { - functions->CallNonvirtualVoidMethodA(this,obj,clazz,methodID,args); - } - - jfieldID GetFieldID(jclass clazz, const char *name, - const char *sig) { - return functions->GetFieldID(this,clazz,name,sig); - } - - jobject GetObjectField(jobject obj, jfieldID fieldID) { - return functions->GetObjectField(this,obj,fieldID); - } - jboolean GetBooleanField(jobject obj, jfieldID fieldID) { - return functions->GetBooleanField(this,obj,fieldID); - } - jbyte GetByteField(jobject obj, jfieldID fieldID) { - return functions->GetByteField(this,obj,fieldID); - } - jchar GetCharField(jobject obj, jfieldID fieldID) { - return functions->GetCharField(this,obj,fieldID); - } - jshort GetShortField(jobject obj, jfieldID fieldID) { - return functions->GetShortField(this,obj,fieldID); - } - jint GetIntField(jobject obj, jfieldID fieldID) { - return functions->GetIntField(this,obj,fieldID); - } - jlong GetLongField(jobject obj, jfieldID fieldID) { - return functions->GetLongField(this,obj,fieldID); - } - jfloat GetFloatField(jobject obj, jfieldID fieldID) { - return functions->GetFloatField(this,obj,fieldID); - } - jdouble GetDoubleField(jobject obj, jfieldID fieldID) { - return functions->GetDoubleField(this,obj,fieldID); - } - - void SetObjectField(jobject obj, jfieldID fieldID, jobject val) { - functions->SetObjectField(this,obj,fieldID,val); - } - void SetBooleanField(jobject obj, jfieldID fieldID, - jboolean val) { - functions->SetBooleanField(this,obj,fieldID,val); - } - void SetByteField(jobject obj, jfieldID fieldID, - jbyte val) { - functions->SetByteField(this,obj,fieldID,val); - } - void SetCharField(jobject obj, jfieldID fieldID, - jchar val) { - functions->SetCharField(this,obj,fieldID,val); - } - void SetShortField(jobject obj, jfieldID fieldID, - jshort val) { - functions->SetShortField(this,obj,fieldID,val); - } - void SetIntField(jobject obj, jfieldID fieldID, - jint val) { - functions->SetIntField(this,obj,fieldID,val); - } - void SetLongField(jobject obj, jfieldID fieldID, - jlong val) { - functions->SetLongField(this,obj,fieldID,val); - } - void SetFloatField(jobject obj, jfieldID fieldID, - jfloat val) { - functions->SetFloatField(this,obj,fieldID,val); - } - void SetDoubleField(jobject obj, jfieldID fieldID, - jdouble val) { - functions->SetDoubleField(this,obj,fieldID,val); - } - - jmethodID GetStaticMethodID(jclass clazz, const char *name, - const char *sig) { - return functions->GetStaticMethodID(this,clazz,name,sig); - } - - jobject CallStaticObjectMethod(jclass clazz, jmethodID methodID, - ...) { - va_list args; - jobject result; - va_start(args,methodID); - result = functions->CallStaticObjectMethodV(this,clazz,methodID,args); - va_end(args); - return result; - } - jobject CallStaticObjectMethodV(jclass clazz, jmethodID methodID, - va_list args) { - return functions->CallStaticObjectMethodV(this,clazz,methodID,args); - } - jobject CallStaticObjectMethodA(jclass clazz, jmethodID methodID, - const jvalue *args) { - return functions->CallStaticObjectMethodA(this,clazz,methodID,args); - } - - jboolean CallStaticBooleanMethod(jclass clazz, - jmethodID methodID, ...) { - va_list args; - jboolean result; - va_start(args,methodID); - result = functions->CallStaticBooleanMethodV(this,clazz,methodID,args); - va_end(args); - return result; - } - jboolean CallStaticBooleanMethodV(jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallStaticBooleanMethodV(this,clazz,methodID,args); - } - jboolean CallStaticBooleanMethodA(jclass clazz, - jmethodID methodID, const jvalue *args) { - return functions->CallStaticBooleanMethodA(this,clazz,methodID,args); - } - - jbyte CallStaticByteMethod(jclass clazz, - jmethodID methodID, ...) { - va_list args; - jbyte result; - va_start(args,methodID); - result = functions->CallStaticByteMethodV(this,clazz,methodID,args); - va_end(args); - return result; - } - jbyte CallStaticByteMethodV(jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallStaticByteMethodV(this,clazz,methodID,args); - } - jbyte CallStaticByteMethodA(jclass clazz, - jmethodID methodID, const jvalue *args) { - return functions->CallStaticByteMethodA(this,clazz,methodID,args); - } - - jchar CallStaticCharMethod(jclass clazz, - jmethodID methodID, ...) { - va_list args; - jchar result; - va_start(args,methodID); - result = functions->CallStaticCharMethodV(this,clazz,methodID,args); - va_end(args); - return result; - } - jchar CallStaticCharMethodV(jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallStaticCharMethodV(this,clazz,methodID,args); - } - jchar CallStaticCharMethodA(jclass clazz, - jmethodID methodID, const jvalue *args) { - return functions->CallStaticCharMethodA(this,clazz,methodID,args); - } - - jshort CallStaticShortMethod(jclass clazz, - jmethodID methodID, ...) { - va_list args; - jshort result; - va_start(args,methodID); - result = functions->CallStaticShortMethodV(this,clazz,methodID,args); - va_end(args); - return result; - } - jshort CallStaticShortMethodV(jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallStaticShortMethodV(this,clazz,methodID,args); - } - jshort CallStaticShortMethodA(jclass clazz, - jmethodID methodID, const jvalue *args) { - return functions->CallStaticShortMethodA(this,clazz,methodID,args); - } - - jint CallStaticIntMethod(jclass clazz, - jmethodID methodID, ...) { - va_list args; - jint result; - va_start(args,methodID); - result = functions->CallStaticIntMethodV(this,clazz,methodID,args); - va_end(args); - return result; - } - jint CallStaticIntMethodV(jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallStaticIntMethodV(this,clazz,methodID,args); - } - jint CallStaticIntMethodA(jclass clazz, - jmethodID methodID, const jvalue *args) { - return functions->CallStaticIntMethodA(this,clazz,methodID,args); - } - - jlong CallStaticLongMethod(jclass clazz, - jmethodID methodID, ...) { - va_list args; - jlong result; - va_start(args,methodID); - result = functions->CallStaticLongMethodV(this,clazz,methodID,args); - va_end(args); - return result; - } - jlong CallStaticLongMethodV(jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallStaticLongMethodV(this,clazz,methodID,args); - } - jlong CallStaticLongMethodA(jclass clazz, - jmethodID methodID, const jvalue *args) { - return functions->CallStaticLongMethodA(this,clazz,methodID,args); - } - - jfloat CallStaticFloatMethod(jclass clazz, - jmethodID methodID, ...) { - va_list args; - jfloat result; - va_start(args,methodID); - result = functions->CallStaticFloatMethodV(this,clazz,methodID,args); - va_end(args); - return result; - } - jfloat CallStaticFloatMethodV(jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallStaticFloatMethodV(this,clazz,methodID,args); - } - jfloat CallStaticFloatMethodA(jclass clazz, - jmethodID methodID, const jvalue *args) { - return functions->CallStaticFloatMethodA(this,clazz,methodID,args); - } - - jdouble CallStaticDoubleMethod(jclass clazz, - jmethodID methodID, ...) { - va_list args; - jdouble result; - va_start(args,methodID); - result = functions->CallStaticDoubleMethodV(this,clazz,methodID,args); - va_end(args); - return result; - } - jdouble CallStaticDoubleMethodV(jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallStaticDoubleMethodV(this,clazz,methodID,args); - } - jdouble CallStaticDoubleMethodA(jclass clazz, - jmethodID methodID, const jvalue *args) { - return functions->CallStaticDoubleMethodA(this,clazz,methodID,args); - } - - void CallStaticVoidMethod(jclass cls, jmethodID methodID, ...) { - va_list args; - va_start(args,methodID); - functions->CallStaticVoidMethodV(this,cls,methodID,args); - va_end(args); - } - void CallStaticVoidMethodV(jclass cls, jmethodID methodID, - va_list args) { - functions->CallStaticVoidMethodV(this,cls,methodID,args); - } - void CallStaticVoidMethodA(jclass cls, jmethodID methodID, - const jvalue * args) { - functions->CallStaticVoidMethodA(this,cls,methodID,args); - } - - jfieldID GetStaticFieldID(jclass clazz, const char *name, - const char *sig) { - return functions->GetStaticFieldID(this,clazz,name,sig); - } - jobject GetStaticObjectField(jclass clazz, jfieldID fieldID) { - return functions->GetStaticObjectField(this,clazz,fieldID); - } - jboolean GetStaticBooleanField(jclass clazz, jfieldID fieldID) { - return functions->GetStaticBooleanField(this,clazz,fieldID); - } - jbyte GetStaticByteField(jclass clazz, jfieldID fieldID) { - return functions->GetStaticByteField(this,clazz,fieldID); - } - jchar GetStaticCharField(jclass clazz, jfieldID fieldID) { - return functions->GetStaticCharField(this,clazz,fieldID); - } - jshort GetStaticShortField(jclass clazz, jfieldID fieldID) { - return functions->GetStaticShortField(this,clazz,fieldID); - } - jint GetStaticIntField(jclass clazz, jfieldID fieldID) { - return functions->GetStaticIntField(this,clazz,fieldID); - } - jlong GetStaticLongField(jclass clazz, jfieldID fieldID) { - return functions->GetStaticLongField(this,clazz,fieldID); - } - jfloat GetStaticFloatField(jclass clazz, jfieldID fieldID) { - return functions->GetStaticFloatField(this,clazz,fieldID); - } - jdouble GetStaticDoubleField(jclass clazz, jfieldID fieldID) { - return functions->GetStaticDoubleField(this,clazz,fieldID); - } - - void SetStaticObjectField(jclass clazz, jfieldID fieldID, - jobject value) { - functions->SetStaticObjectField(this,clazz,fieldID,value); - } - void SetStaticBooleanField(jclass clazz, jfieldID fieldID, - jboolean value) { - functions->SetStaticBooleanField(this,clazz,fieldID,value); - } - void SetStaticByteField(jclass clazz, jfieldID fieldID, - jbyte value) { - functions->SetStaticByteField(this,clazz,fieldID,value); - } - void SetStaticCharField(jclass clazz, jfieldID fieldID, - jchar value) { - functions->SetStaticCharField(this,clazz,fieldID,value); - } - void SetStaticShortField(jclass clazz, jfieldID fieldID, - jshort value) { - functions->SetStaticShortField(this,clazz,fieldID,value); - } - void SetStaticIntField(jclass clazz, jfieldID fieldID, - jint value) { - functions->SetStaticIntField(this,clazz,fieldID,value); - } - void SetStaticLongField(jclass clazz, jfieldID fieldID, - jlong value) { - functions->SetStaticLongField(this,clazz,fieldID,value); - } - void SetStaticFloatField(jclass clazz, jfieldID fieldID, - jfloat value) { - functions->SetStaticFloatField(this,clazz,fieldID,value); - } - void SetStaticDoubleField(jclass clazz, jfieldID fieldID, - jdouble value) { - functions->SetStaticDoubleField(this,clazz,fieldID,value); - } - - jstring NewString(const jchar *unicode, jsize len) { - return functions->NewString(this,unicode,len); - } - jsize GetStringLength(jstring str) { - return functions->GetStringLength(this,str); - } - const jchar *GetStringChars(jstring str, jboolean *isCopy) { - return functions->GetStringChars(this,str,isCopy); - } - void ReleaseStringChars(jstring str, const jchar *chars) { - functions->ReleaseStringChars(this,str,chars); - } - - jstring NewStringUTF(const char *utf) { - return functions->NewStringUTF(this,utf); - } - jsize GetStringUTFLength(jstring str) { - return functions->GetStringUTFLength(this,str); - } - const char* GetStringUTFChars(jstring str, jboolean *isCopy) { - return functions->GetStringUTFChars(this,str,isCopy); - } - void ReleaseStringUTFChars(jstring str, const char* chars) { - functions->ReleaseStringUTFChars(this,str,chars); - } - - jsize GetArrayLength(jarray array) { - return functions->GetArrayLength(this,array); - } - - jobjectArray NewObjectArray(jsize len, jclass clazz, - jobject init) { - return functions->NewObjectArray(this,len,clazz,init); - } - jobject GetObjectArrayElement(jobjectArray array, jsize index) { - return functions->GetObjectArrayElement(this,array,index); - } - void SetObjectArrayElement(jobjectArray array, jsize index, - jobject val) { - functions->SetObjectArrayElement(this,array,index,val); - } - - jbooleanArray NewBooleanArray(jsize len) { - return functions->NewBooleanArray(this,len); - } - jbyteArray NewByteArray(jsize len) { - return functions->NewByteArray(this,len); - } - jcharArray NewCharArray(jsize len) { - return functions->NewCharArray(this,len); - } - jshortArray NewShortArray(jsize len) { - return functions->NewShortArray(this,len); - } - jintArray NewIntArray(jsize len) { - return functions->NewIntArray(this,len); - } - jlongArray NewLongArray(jsize len) { - return functions->NewLongArray(this,len); - } - jfloatArray NewFloatArray(jsize len) { - return functions->NewFloatArray(this,len); - } - jdoubleArray NewDoubleArray(jsize len) { - return functions->NewDoubleArray(this,len); - } - - jboolean * GetBooleanArrayElements(jbooleanArray array, jboolean *isCopy) { - return functions->GetBooleanArrayElements(this,array,isCopy); - } - jbyte * GetByteArrayElements(jbyteArray array, jboolean *isCopy) { - return functions->GetByteArrayElements(this,array,isCopy); - } - jchar * GetCharArrayElements(jcharArray array, jboolean *isCopy) { - return functions->GetCharArrayElements(this,array,isCopy); - } - jshort * GetShortArrayElements(jshortArray array, jboolean *isCopy) { - return functions->GetShortArrayElements(this,array,isCopy); - } - jint * GetIntArrayElements(jintArray array, jboolean *isCopy) { - return functions->GetIntArrayElements(this,array,isCopy); - } - jlong * GetLongArrayElements(jlongArray array, jboolean *isCopy) { - return functions->GetLongArrayElements(this,array,isCopy); - } - jfloat * GetFloatArrayElements(jfloatArray array, jboolean *isCopy) { - return functions->GetFloatArrayElements(this,array,isCopy); - } - jdouble * GetDoubleArrayElements(jdoubleArray array, jboolean *isCopy) { - return functions->GetDoubleArrayElements(this,array,isCopy); - } - - void ReleaseBooleanArrayElements(jbooleanArray array, - jboolean *elems, - jint mode) { - functions->ReleaseBooleanArrayElements(this,array,elems,mode); - } - void ReleaseByteArrayElements(jbyteArray array, - jbyte *elems, - jint mode) { - functions->ReleaseByteArrayElements(this,array,elems,mode); - } - void ReleaseCharArrayElements(jcharArray array, - jchar *elems, - jint mode) { - functions->ReleaseCharArrayElements(this,array,elems,mode); - } - void ReleaseShortArrayElements(jshortArray array, - jshort *elems, - jint mode) { - functions->ReleaseShortArrayElements(this,array,elems,mode); - } - void ReleaseIntArrayElements(jintArray array, - jint *elems, - jint mode) { - functions->ReleaseIntArrayElements(this,array,elems,mode); - } - void ReleaseLongArrayElements(jlongArray array, - jlong *elems, - jint mode) { - functions->ReleaseLongArrayElements(this,array,elems,mode); - } - void ReleaseFloatArrayElements(jfloatArray array, - jfloat *elems, - jint mode) { - functions->ReleaseFloatArrayElements(this,array,elems,mode); - } - void ReleaseDoubleArrayElements(jdoubleArray array, - jdouble *elems, - jint mode) { - functions->ReleaseDoubleArrayElements(this,array,elems,mode); - } - - void GetBooleanArrayRegion(jbooleanArray array, - jsize start, jsize len, jboolean *buf) { - functions->GetBooleanArrayRegion(this,array,start,len,buf); - } - void GetByteArrayRegion(jbyteArray array, - jsize start, jsize len, jbyte *buf) { - functions->GetByteArrayRegion(this,array,start,len,buf); - } - void GetCharArrayRegion(jcharArray array, - jsize start, jsize len, jchar *buf) { - functions->GetCharArrayRegion(this,array,start,len,buf); - } - void GetShortArrayRegion(jshortArray array, - jsize start, jsize len, jshort *buf) { - functions->GetShortArrayRegion(this,array,start,len,buf); - } - void GetIntArrayRegion(jintArray array, - jsize start, jsize len, jint *buf) { - functions->GetIntArrayRegion(this,array,start,len,buf); - } - void GetLongArrayRegion(jlongArray array, - jsize start, jsize len, jlong *buf) { - functions->GetLongArrayRegion(this,array,start,len,buf); - } - void GetFloatArrayRegion(jfloatArray array, - jsize start, jsize len, jfloat *buf) { - functions->GetFloatArrayRegion(this,array,start,len,buf); - } - void GetDoubleArrayRegion(jdoubleArray array, - jsize start, jsize len, jdouble *buf) { - functions->GetDoubleArrayRegion(this,array,start,len,buf); - } - - void SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, - const jboolean *buf) { - functions->SetBooleanArrayRegion(this,array,start,len,buf); - } - void SetByteArrayRegion(jbyteArray array, jsize start, jsize len, - const jbyte *buf) { - functions->SetByteArrayRegion(this,array,start,len,buf); - } - void SetCharArrayRegion(jcharArray array, jsize start, jsize len, - const jchar *buf) { - functions->SetCharArrayRegion(this,array,start,len,buf); - } - void SetShortArrayRegion(jshortArray array, jsize start, jsize len, - const jshort *buf) { - functions->SetShortArrayRegion(this,array,start,len,buf); - } - void SetIntArrayRegion(jintArray array, jsize start, jsize len, - const jint *buf) { - functions->SetIntArrayRegion(this,array,start,len,buf); - } - void SetLongArrayRegion(jlongArray array, jsize start, jsize len, - const jlong *buf) { - functions->SetLongArrayRegion(this,array,start,len,buf); - } - void SetFloatArrayRegion(jfloatArray array, jsize start, jsize len, - const jfloat *buf) { - functions->SetFloatArrayRegion(this,array,start,len,buf); - } - void SetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, - const jdouble *buf) { - functions->SetDoubleArrayRegion(this,array,start,len,buf); - } - - jint RegisterNatives(jclass clazz, const JNINativeMethod *methods, - jint nMethods) { - return functions->RegisterNatives(this,clazz,methods,nMethods); - } - jint UnregisterNatives(jclass clazz) { - return functions->UnregisterNatives(this,clazz); - } - - jint MonitorEnter(jobject obj) { - return functions->MonitorEnter(this,obj); - } - jint MonitorExit(jobject obj) { - return functions->MonitorExit(this,obj); - } - - jint GetJavaVM(JavaVM **vm) { - return functions->GetJavaVM(this,vm); - } - - void GetStringRegion(jstring str, jsize start, jsize len, jchar *buf) { - functions->GetStringRegion(this,str,start,len,buf); - } - void GetStringUTFRegion(jstring str, jsize start, jsize len, char *buf) { - functions->GetStringUTFRegion(this,str,start,len,buf); - } - - void * GetPrimitiveArrayCritical(jarray array, jboolean *isCopy) { - return functions->GetPrimitiveArrayCritical(this,array,isCopy); - } - void ReleasePrimitiveArrayCritical(jarray array, void *carray, jint mode) { - functions->ReleasePrimitiveArrayCritical(this,array,carray,mode); - } - - const jchar * GetStringCritical(jstring string, jboolean *isCopy) { - return functions->GetStringCritical(this,string,isCopy); - } - void ReleaseStringCritical(jstring string, const jchar *cstring) { - functions->ReleaseStringCritical(this,string,cstring); - } - - jweak NewWeakGlobalRef(jobject obj) { - return functions->NewWeakGlobalRef(this,obj); - } - void DeleteWeakGlobalRef(jweak ref) { - functions->DeleteWeakGlobalRef(this,ref); - } - - jboolean ExceptionCheck() { - return functions->ExceptionCheck(this); - } - - jobject NewDirectByteBuffer(void* address, jlong capacity) { - return functions->NewDirectByteBuffer(this, address, capacity); - } - void* GetDirectBufferAddress(jobject buf) { - return functions->GetDirectBufferAddress(this, buf); - } - jlong GetDirectBufferCapacity(jobject buf) { - return functions->GetDirectBufferCapacity(this, buf); - } - jobjectRefType GetObjectRefType(jobject obj) { - return functions->GetObjectRefType(this, obj); - } - - /* Module Features */ - - jobject GetModule(jclass clazz) { - return functions->GetModule(this, clazz); - } - - /* Virtual threads */ - - jboolean IsVirtualThread(jobject obj) { - return functions->IsVirtualThread(this, obj); - } - -#endif /* __cplusplus */ -}; - -/* - * optionString may be any option accepted by the JVM, or one of the - * following: - * - * -D= Set a system property. - * -verbose[:class|gc|jni] Enable verbose output, comma-separated. E.g. - * "-verbose:class" or "-verbose:gc,class" - * Standard names include: gc, class, and jni. - * All nonstandard (VM-specific) names must begin - * with "X". - * vfprintf extraInfo is a pointer to the vfprintf hook. - * exit extraInfo is a pointer to the exit hook. - * abort extraInfo is a pointer to the abort hook. - */ -typedef struct JavaVMOption { - char *optionString; - void *extraInfo; -} JavaVMOption; - -typedef struct JavaVMInitArgs { - jint version; - - jint nOptions; - JavaVMOption *options; - jboolean ignoreUnrecognized; -} JavaVMInitArgs; - -typedef struct JavaVMAttachArgs { - jint version; - - char *name; - jobject group; -} JavaVMAttachArgs; - -/* These will be VM-specific. */ - -#define JDK1_2 -#define JDK1_4 - -/* End VM-specific. */ - -struct JNIInvokeInterface_ { - void *reserved0; - void *reserved1; - void *reserved2; - - jint (JNICALL *DestroyJavaVM)(JavaVM *vm); - - jint (JNICALL *AttachCurrentThread)(JavaVM *vm, void **penv, void *args); - - jint (JNICALL *DetachCurrentThread)(JavaVM *vm); - - jint (JNICALL *GetEnv)(JavaVM *vm, void **penv, jint version); - - jint (JNICALL *AttachCurrentThreadAsDaemon)(JavaVM *vm, void **penv, void *args); -}; - -struct JavaVM_ { - const struct JNIInvokeInterface_ *functions; -#ifdef __cplusplus - - jint DestroyJavaVM() { - return functions->DestroyJavaVM(this); - } - jint AttachCurrentThread(void **penv, void *args) { - return functions->AttachCurrentThread(this, penv, args); - } - jint DetachCurrentThread() { - return functions->DetachCurrentThread(this); - } - - jint GetEnv(void **penv, jint version) { - return functions->GetEnv(this, penv, version); - } - jint AttachCurrentThreadAsDaemon(void **penv, void *args) { - return functions->AttachCurrentThreadAsDaemon(this, penv, args); - } -#endif -}; - -#ifdef _JNI_IMPLEMENTATION_ -#define _JNI_IMPORT_OR_EXPORT_ JNIEXPORT -#else -#define _JNI_IMPORT_OR_EXPORT_ JNIIMPORT -#endif -_JNI_IMPORT_OR_EXPORT_ jint JNICALL -JNI_GetDefaultJavaVMInitArgs(void *args); - -_JNI_IMPORT_OR_EXPORT_ jint JNICALL -JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args); - -_JNI_IMPORT_OR_EXPORT_ jint JNICALL -JNI_GetCreatedJavaVMs(JavaVM **, jsize, jsize *); - -/* Defined by native libraries. */ -JNIEXPORT jint JNICALL -JNI_OnLoad(JavaVM *vm, void *reserved); - -JNIEXPORT void JNICALL -JNI_OnUnload(JavaVM *vm, void *reserved); - -#define JNI_VERSION_1_1 0x00010001 -#define JNI_VERSION_1_2 0x00010002 -#define JNI_VERSION_1_4 0x00010004 -#define JNI_VERSION_1_6 0x00010006 -#define JNI_VERSION_1_8 0x00010008 -#define JNI_VERSION_9 0x00090000 -#define JNI_VERSION_10 0x000a0000 -#define JNI_VERSION_19 0x00130000 -#define JNI_VERSION_20 0x00140000 -#define JNI_VERSION_21 0x00150000 - -#ifdef __cplusplus -} /* extern "C" */ -#endif /* __cplusplus */ - -#endif /* !_JAVASOFT_JNI_H_ */ diff --git a/netty-channel-unix-native/src/main/headers/jni_md.h b/netty-channel-unix-native/src/main/headers/jni_md.h deleted file mode 100644 index 6e583da..0000000 --- a/netty-channel-unix-native/src/main/headers/jni_md.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef _JAVASOFT_JNI_MD_H_ -#define _JAVASOFT_JNI_MD_H_ - -#ifndef __has_attribute - #define __has_attribute(x) 0 -#endif - -#ifndef JNIEXPORT - #if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility) - #ifdef ARM - #define JNIEXPORT __attribute__((externally_visible,visibility("default"))) - #else - #define JNIEXPORT __attribute__((visibility("default"))) - #endif - #else - #define JNIEXPORT - #endif -#endif - -#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility) - #ifdef ARM - #define JNIIMPORT __attribute__((externally_visible,visibility("default"))) - #else - #define JNIIMPORT __attribute__((visibility("default"))) - #endif -#else - #define JNIIMPORT -#endif - -#define JNICALL - -typedef int jint; -#ifdef _LP64 -typedef long jlong; -#else -typedef long long jlong; -#endif - -typedef signed char jbyte; - -#endif /* !_JAVASOFT_JNI_MD_H_ */ diff --git a/netty-channel/src/main/java/io/netty/channel/ChannelOutboundBuffer.java b/netty-channel/src/main/java/io/netty/channel/ChannelOutboundBuffer.java index 7008ef5..27119e8 100644 --- a/netty-channel/src/main/java/io/netty/channel/ChannelOutboundBuffer.java +++ b/netty-channel/src/main/java/io/netty/channel/ChannelOutboundBuffer.java @@ -15,6 +15,7 @@ */ package io.netty.channel; +import io.netty.buffer.AbstractReferenceCountedByteBuf; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufHolder; import io.netty.buffer.Unpooled; @@ -275,9 +276,20 @@ public final class ChannelOutboundBuffer { removeEntry(e); + // only release message, notify and decrement if it was not canceled before. if (!e.cancelled) { - // only release message, notify and decrement if it was not canceled before. - ReferenceCountUtil.safeRelease(msg); + // this save both checking against the ReferenceCounted interface + // and makes better use of virtual calls vs interface ones + if (msg instanceof AbstractReferenceCountedByteBuf) { + try { + // release now as it is flushed. + ((AbstractReferenceCountedByteBuf) msg).release(); + } catch (Throwable t) { + logger.warn("Failed to release a ByteBuf: {}", msg, t); + } + } else { + ReferenceCountUtil.safeRelease(msg); + } safeSuccess(promise); decrementPendingOutboundBytes(size, false, true); } diff --git a/netty-handler-codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2FrameWriter.java b/netty-handler-codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2FrameWriter.java index 9b60892..8540e0c 100644 --- a/netty-handler-codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2FrameWriter.java +++ b/netty-handler-codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2FrameWriter.java @@ -567,7 +567,7 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize ByteBuf fragment = headerBlock.readRetainedSlice(fragmentReadableBytes); if (headerBlock.isReadable()) { - ctx.write(buf.retain(), promiseAggregator.newPromise()); + ctx.write(buf.retainedSlice(), promiseAggregator.newPromise()); } else { // The frame header is different for the last frame, so re-allocate and release the old buffer flags = flags.endOfHeaders(true); diff --git a/netty-handler-codec-http2/src/test/java/io/netty/handler/codec/http2/DefaultHttp2FrameWriterTest.java b/netty-handler-codec-http2/src/test/java/io/netty/handler/codec/http2/DefaultHttp2FrameWriterTest.java index e134fb8..8311a20 100644 --- a/netty-handler-codec-http2/src/test/java/io/netty/handler/codec/http2/DefaultHttp2FrameWriterTest.java +++ b/netty-handler-codec-http2/src/test/java/io/netty/handler/codec/http2/DefaultHttp2FrameWriterTest.java @@ -189,7 +189,7 @@ public class DefaultHttp2FrameWriterTest { int streamId = 1; Http2Headers headers = new DefaultHttp2Headers() .method("GET").path("/").authority("foo.com").scheme("https"); - headers = dummyHeaders(headers, 20); + headers = dummyHeaders(headers, 60); http2HeadersEncoder.configuration().maxHeaderListSize(Integer.MAX_VALUE); frameWriter.headersConfiguration().maxHeaderListSize(Integer.MAX_VALUE); @@ -198,7 +198,7 @@ public class DefaultHttp2FrameWriterTest { byte[] expectedPayload = headerPayload(streamId, headers); - // First frame: HEADER(length=0x4000, flags=0x01) + // First frame: HEADER(length=0x4000, type=0x01, flags=0x01) assertEquals(Http2CodecUtil.MAX_FRAME_SIZE_LOWER_BOUND, outbound.readUnsignedMedium()); assertEquals(0x01, outbound.readByte()); @@ -207,22 +207,49 @@ public class DefaultHttp2FrameWriterTest { byte[] firstPayload = new byte[Http2CodecUtil.MAX_FRAME_SIZE_LOWER_BOUND]; outbound.readBytes(firstPayload); + int index = 0; + assertArrayEquals(Arrays.copyOfRange(expectedPayload, index, index + firstPayload.length), + firstPayload); + index += firstPayload.length; - int remainPayloadLength = expectedPayload.length - Http2CodecUtil.MAX_FRAME_SIZE_LOWER_BOUND; - // Second frame: CONTINUATION(length=remainPayloadLength, flags=0x04) + // Second frame: HEADER(length=0x4000, type=0x09, flags=0x00) + assertEquals(Http2CodecUtil.MAX_FRAME_SIZE_LOWER_BOUND, + outbound.readUnsignedMedium()); + assertEquals(0x09, outbound.readByte()); + assertEquals(0x00, outbound.readByte()); + assertEquals(streamId, outbound.readInt()); + + byte[] secondPayload = new byte[Http2CodecUtil.MAX_FRAME_SIZE_LOWER_BOUND]; + outbound.readBytes(secondPayload); + assertArrayEquals(Arrays.copyOfRange(expectedPayload, index, index + secondPayload.length), + secondPayload); + index += secondPayload.length; + + // third frame: HEADER(length=0x4000, type=0x09, flags=0x00) + assertEquals(Http2CodecUtil.MAX_FRAME_SIZE_LOWER_BOUND, + outbound.readUnsignedMedium()); + assertEquals(0x09, outbound.readByte()); + assertEquals(0x00, outbound.readByte()); + assertEquals(streamId, outbound.readInt()); + + byte[] thirdPayload = new byte[Http2CodecUtil.MAX_FRAME_SIZE_LOWER_BOUND]; + outbound.readBytes(thirdPayload); + assertArrayEquals(Arrays.copyOfRange(expectedPayload, index, index + thirdPayload.length), + thirdPayload); + index += thirdPayload.length; + + int remainPayloadLength = expectedPayload.length - index; + // Second frame: CONTINUATION(length=remainPayloadLength, type=0x09, flags=0x04) assertEquals(remainPayloadLength, outbound.readUnsignedMedium()); assertEquals(0x09, outbound.readByte()); assertEquals(0x04, outbound.readByte()); assertEquals(streamId, outbound.readInt()); - byte[] secondPayload = new byte[remainPayloadLength]; - outbound.readBytes(secondPayload); + byte[] fourthPayload = new byte[remainPayloadLength]; + outbound.readBytes(fourthPayload); - assertArrayEquals(Arrays.copyOfRange(expectedPayload, 0, firstPayload.length), - firstPayload); - assertArrayEquals(Arrays.copyOfRange(expectedPayload, firstPayload.length, - expectedPayload.length), - secondPayload); + assertArrayEquals(Arrays.copyOfRange(expectedPayload, index, index + fourthPayload.length), + fourthPayload); } @Test diff --git a/netty-handler-codec-quic-native/build.gradle b/netty-handler-codec-quic-native/build.gradle index e875605..7f74c29 100644 --- a/netty-handler-codec-quic-native/build.gradle +++ b/netty-handler-codec-quic-native/build.gradle @@ -1,4 +1,6 @@ +apply plugin: 'base' + task nettyQuicLinuxX8664(type: Jar) { archiveBaseName.set('netty-handler-codec-quic-native') archiveClassifier.set('linux-x86_64') @@ -7,7 +9,7 @@ task nettyQuicLinuxX8664(type: Jar) { include 'META-INF/native/libnetty_quiche_linux_x86_64.so' } } -//assemble.dependsOn(nettyQuicLinuxX8664) +assemble.dependsOn(nettyQuicLinuxX8664) configurations { 'linux-x86_64' { @@ -67,4 +69,4 @@ publishing { } } } -} \ No newline at end of file +} diff --git a/netty-handler-codec-quic-native/download.sh b/netty-handler-codec-quic-native/download.sh new file mode 100644 index 0000000..29d15ff --- /dev/null +++ b/netty-handler-codec-quic-native/download.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +VERSION=0.0.56.Final + +wget "https://repo1.maven.org/maven2/io/netty/incubator/netty-incubator-codec-native-quic/$VERSION/netty-incubator-codec-native-quic-$VERSION-linux-x86_64.jar" +jar xf netty-incubator-codec-native-quic-$VERSION-linux-x86_64.jar META-INF/native/libnetty_quiche_linux_x86_64.so + +wget "https://repo1.maven.org/maven2/io/netty/incubator/netty-incubator-codec-native-quic/$VERSION/netty-incubator-codec-native-quic-$VERSION-linux-aarch_64.jar" +jar xf netty-incubator-codec-native-quic-$VERSION-linux-aarch_64.jar META-INF/native/libnetty_quiche_linux_aarch_64.so + +wget "https://repo1.maven.org/maven2/io/netty/incubator/netty-incubator-codec-native-quic/$VERSION/netty-incubator-codec-native-quic-$VERSION-osx-aarch_64.jar" +jar xf netty-incubator-codec-native-quic-$VERSION-osx-aarch_64.jar META-INF/native/libnetty_quiche_osx_aarch_64.jnilib + +wget "https://repo1.maven.org/maven2/io/netty/incubator/netty-incubator-codec-native-quic/$VERSION/netty-incubator-codec-native-quic-$VERSION-osx-x86_64.jar" +jar xf netty-incubator-codec-native-quic-$VERSION-osx-x86_64.jar META-INF/native/libnetty_quiche_osx_x86_64.jnilib + +wget "https://repo1.maven.org/maven2/io/netty/incubator/netty-incubator-codec-native-quic/$VERSION/netty-incubator-codec-native-quic-$VERSION-windows-x86_64.jar" +jar xf netty-incubator-codec-native-quic-$VERSION-windows-x86_64.jar META-INF/native/netty_quiche_windows_x86_64.dll diff --git a/netty-handler-codec-quic-native/src/main/resources/META-INF/native/libnetty_quiche_linux_aarch_64.so b/netty-handler-codec-quic-native/src/main/resources/META-INF/native/libnetty_quiche_linux_aarch_64.so new file mode 100644 index 0000000..66b6693 Binary files /dev/null and b/netty-handler-codec-quic-native/src/main/resources/META-INF/native/libnetty_quiche_linux_aarch_64.so differ diff --git a/netty-handler-codec-quic-native/src/main/resources/META-INF/native/libnetty_quiche_linux_x86_64.so b/netty-handler-codec-quic-native/src/main/resources/META-INF/native/libnetty_quiche_linux_x86_64.so old mode 100755 new mode 100644 index e4040e8..dcf8086 Binary files a/netty-handler-codec-quic-native/src/main/resources/META-INF/native/libnetty_quiche_linux_x86_64.so and b/netty-handler-codec-quic-native/src/main/resources/META-INF/native/libnetty_quiche_linux_x86_64.so differ diff --git a/netty-handler-codec-quic-native/src/main/resources/META-INF/native/libnetty_quiche_osx_aarch_64.jnilib b/netty-handler-codec-quic-native/src/main/resources/META-INF/native/libnetty_quiche_osx_aarch_64.jnilib new file mode 100644 index 0000000..1d8d1fb Binary files /dev/null and b/netty-handler-codec-quic-native/src/main/resources/META-INF/native/libnetty_quiche_osx_aarch_64.jnilib differ diff --git a/netty-handler-codec-quic-native/src/main/resources/META-INF/native/libnetty_quiche_osx_x86_64.jnilib b/netty-handler-codec-quic-native/src/main/resources/META-INF/native/libnetty_quiche_osx_x86_64.jnilib new file mode 100644 index 0000000..06786fe Binary files /dev/null and b/netty-handler-codec-quic-native/src/main/resources/META-INF/native/libnetty_quiche_osx_x86_64.jnilib differ diff --git a/netty-handler-codec-quic-native/src/main/resources/META-INF/native/netty_quiche_windows_x86_64.dll b/netty-handler-codec-quic-native/src/main/resources/META-INF/native/netty_quiche_windows_x86_64.dll new file mode 100644 index 0000000..7098d06 Binary files /dev/null and b/netty-handler-codec-quic-native/src/main/resources/META-INF/native/netty_quiche_windows_x86_64.dll differ diff --git a/netty-tcnative-boringssl-static-native/build.gradle b/netty-tcnative-boringssl-static-native/build.gradle index 89218cd..f4d583a 100644 --- a/netty-tcnative-boringssl-static-native/build.gradle +++ b/netty-tcnative-boringssl-static-native/build.gradle @@ -1,4 +1,6 @@ +apply plugin: 'base' + task nettyTcNativeBoringSslStaticLinuxX8664(type: Jar) { archiveBaseName.set('netty-tcnative-boringssl-static') archiveClassifier.set('linux-x86_64') @@ -8,7 +10,7 @@ task nettyTcNativeBoringSslStaticLinuxX8664(type: Jar) { include 'META-INF/native/libnetty_tcnative_linux_x86_64.so' } } -//assemble.dependsOn(nettyTcNativeBoringSslStaticLinuxX8664) +assemble.dependsOn(nettyTcNativeBoringSslStaticLinuxX8664) task nettyTcNativeBoringSslStaticLinuxAarch64(type: Jar) { archiveBaseName.set('netty-tcnative-boringssl-static') @@ -19,7 +21,7 @@ task nettyTcNativeBoringSslStaticLinuxAarch64(type: Jar) { include 'META-INF/native/libnetty_tcnative_linux_aarch_64.so' } } -//assemble.dependsOn(nettyTcNativeBoringSslStaticLinuxAarch64) +assemble.dependsOn(nettyTcNativeBoringSslStaticLinuxAarch64) task nettyTcNativeBoringSslStaticOsxX8664(type: Jar) { archiveBaseName.set('netty-tcnative-boringssl-static') @@ -30,7 +32,7 @@ task nettyTcNativeBoringSslStaticOsxX8664(type: Jar) { include 'META-INF/native/libnetty_tcnative_osx_x86_64.jnilib' } } -//assemble.dependsOn(nettyTcNativeBoringSslStaticOsxX8664) +assemble.dependsOn(nettyTcNativeBoringSslStaticOsxX8664) task nettyTcNativeBoringSslStaticOsxAarch64(type: Jar) { archiveBaseName.set('netty-tcnative-boringssl-static') @@ -41,7 +43,7 @@ task nettyTcNativeBoringSslStaticOsxAarch64(type: Jar) { include 'META-INF/native/libnetty_tcnative_osx_aarch_64.jnilib' } } -//assemble.dependsOn(nettyTcNativeBoringSslStaticOsxAarch64) +assemble.dependsOn(nettyTcNativeBoringSslStaticOsxAarch64) task nettyTcNativeBoringSslStaticWindowsX8664(type: Jar) { archiveBaseName.set('netty-tcnative-boringssl-static') @@ -52,7 +54,7 @@ task nettyTcNativeBoringSslStaticWindowsX8664(type: Jar) { include 'META-INF/native/libnetty_tcnative_windows_x86_64.dll' } } -//assemble.dependsOn(nettyTcNativeBoringSslStaticWindowsX8664) +assemble.dependsOn(nettyTcNativeBoringSslStaticWindowsX8664) configurations { 'linux-x86_64' { diff --git a/patches/13782.patch b/patches/13782.patch new file mode 100644 index 0000000..ae43a87 --- /dev/null +++ b/patches/13782.patch @@ -0,0 +1,55 @@ +From 49952a6302c10628155d8344f57473ceb355c9be Mon Sep 17 00:00:00 2001 +From: Francesco Nigro +Date: Tue, 16 Jan 2024 13:48:59 +0100 +Subject: [PATCH] Short-circuit ByteBuf::release + +Motivation: + +ReferenceCountUtil::safeRelease can both hit interface virtual calls and requires checking for an interface type (ReferenceCounted) + +Modifications: + +Perform a class check to save both. + +Result: + +Faster buffers release +--- + .../io/netty/channel/ChannelOutboundBuffer.java | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +diff --git a/transport/src/main/java/io/netty/channel/ChannelOutboundBuffer.java b/transport/src/main/java/io/netty/channel/ChannelOutboundBuffer.java +index 7008ef558ccc..27119e8fbf47 100644 +--- a/transport/src/main/java/io/netty/channel/ChannelOutboundBuffer.java ++++ b/transport/src/main/java/io/netty/channel/ChannelOutboundBuffer.java +@@ -15,6 +15,7 @@ + */ + package io.netty.channel; + ++import io.netty.buffer.AbstractReferenceCountedByteBuf; + import io.netty.buffer.ByteBuf; + import io.netty.buffer.ByteBufHolder; + import io.netty.buffer.Unpooled; +@@ -275,9 +276,20 @@ public boolean remove() { + + removeEntry(e); + ++ // only release message, notify and decrement if it was not canceled before. + if (!e.cancelled) { +- // only release message, notify and decrement if it was not canceled before. +- ReferenceCountUtil.safeRelease(msg); ++ // this save both checking against the ReferenceCounted interface ++ // and makes better use of virtual calls vs interface ones ++ if (msg instanceof AbstractReferenceCountedByteBuf) { ++ try { ++ // release now as it is flushed. ++ ((AbstractReferenceCountedByteBuf) msg).release(); ++ } catch (Throwable t) { ++ logger.warn("Failed to release a ByteBuf: {}", msg, t); ++ } ++ } else { ++ ReferenceCountUtil.safeRelease(msg); ++ } + safeSuccess(promise); + decrementPendingOutboundBytes(size, false, true); + } diff --git a/patches/13784.patch b/patches/13784.patch new file mode 100644 index 0000000..2f0f573 --- /dev/null +++ b/patches/13784.patch @@ -0,0 +1,110 @@ +From 60441afc56decf21808b8b2767d6769c787f82a5 Mon Sep 17 00:00:00 2001 +From: Norman Maurer +Date: Wed, 17 Jan 2024 13:12:19 +0100 +Subject: [PATCH] DnsNameResolver: Fail query if id space is exhausted + +Motivation: + +When we try to execute a query we will try to select / generate an id that is used. When we are not able to find one we throw an IllegalStateException. In this case we also need to ensure we fail the original promise as otherwise the user might never be notified of the problem. + +Modifications: + +- Move throw code out of the DnsQueryContextManager to make it easier to reason about +- Fail query with IllegalStateException + +Result: + +Query will be correctly failed in the case of id space exhausting +--- + .../netty/resolver/dns/DnsQueryContext.java | 13 ++++++--- + .../resolver/dns/DnsQueryContextManager.java | 27 +++++++++++++++++-- + 2 files changed, 35 insertions(+), 5 deletions(-) + +diff --git a/resolver-dns/src/main/java/io/netty/resolver/dns/DnsQueryContext.java b/resolver-dns/src/main/java/io/netty/resolver/dns/DnsQueryContext.java +index da1091b1d160..348d15b30bd0 100644 +--- a/resolver-dns/src/main/java/io/netty/resolver/dns/DnsQueryContext.java ++++ b/resolver-dns/src/main/java/io/netty/resolver/dns/DnsQueryContext.java +@@ -81,7 +81,7 @@ abstract class DnsQueryContext { + + private volatile Future timeoutFuture; + +- private int id = -1; ++ private int id = Integer.MIN_VALUE; + + DnsQueryContext(Channel channel, + Future channelReadyFuture, +@@ -172,8 +172,15 @@ final DnsQuestion question() { + * @return the {@link ChannelFuture} that is notified once once the write completes. + */ + final ChannelFuture writeQuery(boolean flush) { +- assert id == -1 : this.getClass().getSimpleName() + ".writeQuery(...) can only be executed once."; +- id = queryContextManager.add(nameServerAddr, this); ++ assert id == Integer.MIN_VALUE : this.getClass().getSimpleName() + ++ ".writeQuery(...) can only be executed once."; ++ ++ if ((id = queryContextManager.add(nameServerAddr, this)) == -1) { ++ // We did exhaust the id space, fail the query ++ IllegalStateException e = new IllegalStateException("query ID space exhausted: " + question()); ++ finishFailure("failed to send a query via " + protocol(), e, false); ++ return channel.newFailedFuture(e); ++ } + + // Ensure we remove the id from the QueryContextManager once the query completes. + promise.addListener(new FutureListener>() { +diff --git a/resolver-dns/src/main/java/io/netty/resolver/dns/DnsQueryContextManager.java b/resolver-dns/src/main/java/io/netty/resolver/dns/DnsQueryContextManager.java +index f82648c43dd2..773eecca0aad 100644 +--- a/resolver-dns/src/main/java/io/netty/resolver/dns/DnsQueryContextManager.java ++++ b/resolver-dns/src/main/java/io/netty/resolver/dns/DnsQueryContextManager.java +@@ -38,11 +38,27 @@ final class DnsQueryContextManager { + private final Map map = + new HashMap(); + ++ /** ++ * Add {@link DnsQueryContext} to the context manager and return the ID that should be used for the query. ++ * This method will return {@code -1} if an ID could not be generated and the context was not stored. ++ * ++ * @param nameServerAddr The {@link InetSocketAddress} of the nameserver to query. ++ * @param qCtx The {@link {@link DnsQueryContext} to store. ++ * @return the ID that should be used or {@code -1} if none could be generated. ++ */ + int add(InetSocketAddress nameServerAddr, DnsQueryContext qCtx) { + final DnsQueryContextMap contexts = getOrCreateContextMap(nameServerAddr); + return contexts.add(qCtx); + } + ++ /** ++ * Return the {@link DnsQueryContext} for the given {@link InetSocketAddress} and id or {@code null} if ++ * none could be found. ++ * ++ * @param nameServerAddr The {@link InetSocketAddress} of the nameserver. ++ * @param id The id that identifies the {@link DnsQueryContext} and was used for the query. ++ * @return The context or {@code null} if none could be found. ++ */ + DnsQueryContext get(InetSocketAddress nameServerAddr, int id) { + final DnsQueryContextMap contexts = getContextMap(nameServerAddr); + if (contexts == null) { +@@ -51,6 +67,14 @@ DnsQueryContext get(InetSocketAddress nameServerAddr, int id) { + return contexts.get(id); + } + ++ /** ++ * Remove the {@link DnsQueryContext} for the given {@link InetSocketAddress} and id or {@code null} if ++ * none could be found. ++ * ++ * @param nameServerAddr The {@link InetSocketAddress} of the nameserver. ++ * @param id The id that identifies the {@link DnsQueryContext} and was used for the query. ++ * @return The context or {@code null} if none could be removed. ++ */ + DnsQueryContext remove(InetSocketAddress nameServerAddr, int id) { + final DnsQueryContextMap contexts = getContextMap(nameServerAddr); + if (contexts == null) { +@@ -150,8 +174,7 @@ synchronized int add(DnsQueryContext ctx) { + + id = id + 1 & 0xFFFF; + if (++tries >= MAX_TRIES) { +- throw new IllegalStateException( +- "query ID space exhausted after " + MAX_TRIES + ": " + ctx.question()); ++ return -1; + } + } + } diff --git a/patches/13786.patch b/patches/13786.patch new file mode 100644 index 0000000..8bb3fb8 --- /dev/null +++ b/patches/13786.patch @@ -0,0 +1,113 @@ +From 284ad8e5ce3ec87964dea6ec8a611dfb4df62a29 Mon Sep 17 00:00:00 2001 +From: songmw725 +Date: Thu, 18 Jan 2024 00:11:34 +0900 +Subject: [PATCH] Prevent sharing the index of the continuation frame header + ByteBuf. Motivation: The current implementation uses the `byteBuf` for a + continuation frame header multiple times if the header length exceeds `3 * + maxFrameLength`. However, it fails to slice the `byteBuf` during usage. + [Reference](https://github.com/netty/netty/blob/d027ba7320d430743992d613e52596b0182ca854/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2FrameWriter.java#L570) + +Modification: +- Introduce `ByteBuf.retainedSlice()` for a continuation frame header when it's used to prevent sharing the index. + +Result: +- Correctly send continuation frame headers to the remote peer, addressing the issue of reusing the index of the ByteBuf. +--- + .../codec/http2/DefaultHttp2FrameWriter.java | 2 +- + .../http2/DefaultHttp2FrameWriterTest.java | 49 ++++++++++++++----- + 2 files changed, 39 insertions(+), 12 deletions(-) + +diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2FrameWriter.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2FrameWriter.java +index 9b608921c28b..8540e0c2ed6e 100644 +--- a/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2FrameWriter.java ++++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2FrameWriter.java +@@ -567,7 +567,7 @@ private ChannelFuture writeContinuationFrames(ChannelHandlerContext ctx, int str + ByteBuf fragment = headerBlock.readRetainedSlice(fragmentReadableBytes); + + if (headerBlock.isReadable()) { +- ctx.write(buf.retain(), promiseAggregator.newPromise()); ++ ctx.write(buf.retainedSlice(), promiseAggregator.newPromise()); + } else { + // The frame header is different for the last frame, so re-allocate and release the old buffer + flags = flags.endOfHeaders(true); +diff --git a/codec-http2/src/test/java/io/netty/handler/codec/http2/DefaultHttp2FrameWriterTest.java b/codec-http2/src/test/java/io/netty/handler/codec/http2/DefaultHttp2FrameWriterTest.java +index e134fb8194df..8311a20823ef 100644 +--- a/codec-http2/src/test/java/io/netty/handler/codec/http2/DefaultHttp2FrameWriterTest.java ++++ b/codec-http2/src/test/java/io/netty/handler/codec/http2/DefaultHttp2FrameWriterTest.java +@@ -189,7 +189,7 @@ public void writeLargeHeaders() throws Exception { + int streamId = 1; + Http2Headers headers = new DefaultHttp2Headers() + .method("GET").path("/").authority("foo.com").scheme("https"); +- headers = dummyHeaders(headers, 20); ++ headers = dummyHeaders(headers, 60); + + http2HeadersEncoder.configuration().maxHeaderListSize(Integer.MAX_VALUE); + frameWriter.headersConfiguration().maxHeaderListSize(Integer.MAX_VALUE); +@@ -198,7 +198,7 @@ public void writeLargeHeaders() throws Exception { + + byte[] expectedPayload = headerPayload(streamId, headers); + +- // First frame: HEADER(length=0x4000, flags=0x01) ++ // First frame: HEADER(length=0x4000, type=0x01, flags=0x01) + assertEquals(Http2CodecUtil.MAX_FRAME_SIZE_LOWER_BOUND, + outbound.readUnsignedMedium()); + assertEquals(0x01, outbound.readByte()); +@@ -207,22 +207,49 @@ public void writeLargeHeaders() throws Exception { + + byte[] firstPayload = new byte[Http2CodecUtil.MAX_FRAME_SIZE_LOWER_BOUND]; + outbound.readBytes(firstPayload); ++ int index = 0; ++ assertArrayEquals(Arrays.copyOfRange(expectedPayload, index, index + firstPayload.length), ++ firstPayload); ++ index += firstPayload.length; + +- int remainPayloadLength = expectedPayload.length - Http2CodecUtil.MAX_FRAME_SIZE_LOWER_BOUND; +- // Second frame: CONTINUATION(length=remainPayloadLength, flags=0x04) ++ // Second frame: HEADER(length=0x4000, type=0x09, flags=0x00) ++ assertEquals(Http2CodecUtil.MAX_FRAME_SIZE_LOWER_BOUND, ++ outbound.readUnsignedMedium()); ++ assertEquals(0x09, outbound.readByte()); ++ assertEquals(0x00, outbound.readByte()); ++ assertEquals(streamId, outbound.readInt()); ++ ++ byte[] secondPayload = new byte[Http2CodecUtil.MAX_FRAME_SIZE_LOWER_BOUND]; ++ outbound.readBytes(secondPayload); ++ assertArrayEquals(Arrays.copyOfRange(expectedPayload, index, index + secondPayload.length), ++ secondPayload); ++ index += secondPayload.length; ++ ++ // third frame: HEADER(length=0x4000, type=0x09, flags=0x00) ++ assertEquals(Http2CodecUtil.MAX_FRAME_SIZE_LOWER_BOUND, ++ outbound.readUnsignedMedium()); ++ assertEquals(0x09, outbound.readByte()); ++ assertEquals(0x00, outbound.readByte()); ++ assertEquals(streamId, outbound.readInt()); ++ ++ byte[] thirdPayload = new byte[Http2CodecUtil.MAX_FRAME_SIZE_LOWER_BOUND]; ++ outbound.readBytes(thirdPayload); ++ assertArrayEquals(Arrays.copyOfRange(expectedPayload, index, index + thirdPayload.length), ++ thirdPayload); ++ index += thirdPayload.length; ++ ++ int remainPayloadLength = expectedPayload.length - index; ++ // Second frame: CONTINUATION(length=remainPayloadLength, type=0x09, flags=0x04) + assertEquals(remainPayloadLength, outbound.readUnsignedMedium()); + assertEquals(0x09, outbound.readByte()); + assertEquals(0x04, outbound.readByte()); + assertEquals(streamId, outbound.readInt()); + +- byte[] secondPayload = new byte[remainPayloadLength]; +- outbound.readBytes(secondPayload); ++ byte[] fourthPayload = new byte[remainPayloadLength]; ++ outbound.readBytes(fourthPayload); + +- assertArrayEquals(Arrays.copyOfRange(expectedPayload, 0, firstPayload.length), +- firstPayload); +- assertArrayEquals(Arrays.copyOfRange(expectedPayload, firstPayload.length, +- expectedPayload.length), +- secondPayload); ++ assertArrayEquals(Arrays.copyOfRange(expectedPayload, index, index + fourthPayload.length), ++ fourthPayload); + } + + @Test diff --git a/patches/276.patch b/patches/276.patch new file mode 100644 index 0000000..cc3c1bc --- /dev/null +++ b/patches/276.patch @@ -0,0 +1,306 @@ +From c2fdcf7d9785ae386562f37174d8378b96a58c5d Mon Sep 17 00:00:00 2001 +From: Norman Maurer +Date: Tue, 16 Jan 2024 08:59:49 +0100 +Subject: [PATCH 1/2] Ensure QuicStreamChannel.shutdownOutput() is only called + once all previous writes were processed. + +Motivation: +We need to ensure QuicStreamChannel.shutdownOutput() is only called once all previous writes were processed. This is necessary as otherwise shutdownOutput() might be called while some writes are still queued (due flowcontrol). + +Modifications: +- Always do the shutdownOutput() via a ChannelFutureListener +- Adjust tests + +Result: +Always drain write queue first before shutdown the output. +--- + .../http3/Http3FrameToHttpObjectCodec.java | 26 +++--- + .../Http3FrameToHttpObjectCodecTest.java | 85 ++++++++++++------- + 2 files changed, 68 insertions(+), 43 deletions(-) + +diff --git a/src/main/java/io/netty/incubator/codec/http3/Http3FrameToHttpObjectCodec.java b/src/main/java/io/netty/incubator/codec/http3/Http3FrameToHttpObjectCodec.java +index 5d22891..aa2deb3 100644 +--- a/src/main/java/io/netty/incubator/codec/http3/Http3FrameToHttpObjectCodec.java ++++ b/src/main/java/io/netty/incubator/codec/http3/Http3FrameToHttpObjectCodec.java +@@ -50,7 +50,7 @@ + * and back. It can be used as an adapter in conjunction with {@link + * Http3ServerConnectionHandler} or {@link Http3ClientConnectionHandler} to make http/3 connections + * backward-compatible with {@link ChannelHandler}s expecting {@link HttpObject}. +- * ++ *

+ * For simplicity, it converts to chunked encoding unless the entire stream + * is a single header. + */ +@@ -148,7 +148,7 @@ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) + return; + } else { + throw new EncoderException( +- HttpResponseStatus.CONTINUE.toString() + " must be a FullHttpResponse"); ++ HttpResponseStatus.CONTINUE + " must be a FullHttpResponse"); + } + } + } +@@ -187,18 +187,20 @@ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) + Http3Headers headers = HttpConversionUtil.toHttp3Headers(last.trailingHeaders(), validateHeaders); + promise = writeWithOptionalCombiner(ctx, + new DefaultHttp3HeadersFrame(headers), promise, combiner, true); +- } +- if (!readable) { ++ } else if (!readable) { ++ // Release the data and just use EMPTY_BUFFER. This might allow us to give back memory to the allocator ++ // faster. + last.release(); ++ if (combiner == null) { ++ // We only need to write something if there was no write before. ++ promise = writeWithOptionalCombiner(ctx, ++ new DefaultHttp3DataFrame(Unpooled.EMPTY_BUFFER), promise, combiner, true); ++ } + } +- +- if (!readable && !hasTrailers && combiner == null) { +- // we had to write nothing. happy days! +- ((QuicStreamChannel) ctx.channel()).shutdownOutput(); +- promise.trySuccess(); +- } else { +- promise.addListener(QuicStreamChannel.SHUTDOWN_OUTPUT); +- } ++ // The shutdown is always done via the listener to ensure previous written data is correctly drained ++ // before QuicStreamChannel.shutdownOutput() is called. Missing to do so might cause previous queued data ++ // to be failed with a ClosedChannelException. ++ promise.addListener(QuicStreamChannel.SHUTDOWN_OUTPUT); + } else if (msg instanceof HttpContent) { + promise = writeWithOptionalCombiner(ctx, + new DefaultHttp3DataFrame(((HttpContent) msg).content()), promise, combiner, false); +diff --git a/src/test/java/io/netty/incubator/codec/http3/Http3FrameToHttpObjectCodecTest.java b/src/test/java/io/netty/incubator/codec/http3/Http3FrameToHttpObjectCodecTest.java +index 8646bfb..d061f20 100644 +--- a/src/test/java/io/netty/incubator/codec/http3/Http3FrameToHttpObjectCodecTest.java ++++ b/src/test/java/io/netty/incubator/codec/http3/Http3FrameToHttpObjectCodecTest.java +@@ -61,6 +61,11 @@ + import io.netty.incubator.codec.quic.QuicStreamChannel; + import io.netty.util.CharsetUtil; + import org.junit.jupiter.api.Test; ++import org.junit.jupiter.api.extension.ExtensionContext; ++import org.junit.jupiter.params.ParameterizedTest; ++import org.junit.jupiter.params.provider.Arguments; ++import org.junit.jupiter.params.provider.ArgumentsProvider; ++import org.junit.jupiter.params.provider.ArgumentsSource; + + import java.nio.CharBuffer; + import java.nio.charset.StandardCharsets; +@@ -71,6 +76,7 @@ + import java.util.concurrent.ExecutionException; + import java.util.concurrent.LinkedBlockingQueue; + import java.util.concurrent.TimeUnit; ++import java.util.stream.Stream; + + import static org.hamcrest.CoreMatchers.is; + import static org.hamcrest.CoreMatchers.nullValue; +@@ -221,6 +227,13 @@ public void testUpgradeEmptyEnd() { + ch.writeOutbound(LastHttpContent.EMPTY_LAST_CONTENT); + + assertTrue(ch.isOutputShutdown()); ++ Http3DataFrame dataFrame = ch.readOutbound(); ++ try { ++ assertThat(dataFrame.content().readableBytes(), is(0)); ++ } finally { ++ dataFrame.release(); ++ } ++ + assertFalse(ch.finish()); + } + +@@ -510,6 +523,13 @@ public void testEncodeEmptyEndAsClient() { + ch.writeOutbound(LastHttpContent.EMPTY_LAST_CONTENT); + + assertTrue(ch.isOutputShutdown()); ++ Http3DataFrame dataFrame = ch.readOutbound(); ++ try { ++ assertThat(dataFrame.content().readableBytes(), is(0)); ++ } finally { ++ dataFrame.release(); ++ } ++ + assertFalse(ch.finish()); + } + +@@ -606,6 +626,13 @@ public void testEncodeEmptyLastPromiseCompletes() { + assertThat(headers.path().toString(), is("/hello/world")); + assertTrue(ch.isOutputShutdown()); + ++ Http3DataFrame dataFrame = ch.readOutbound(); ++ try { ++ assertThat(dataFrame.content().readableBytes(), is(0)); ++ } finally { ++ dataFrame.release(); ++ } ++ + assertFalse(ch.finish()); + } + +@@ -684,31 +711,30 @@ public void testEncodeVoidPromise() { + assertFalse(ch.finish()); + } + +- @Test +- public void testEncodeCombinations() { +- // this test goes through all the branches of Http3FrameToHttpObjectCodec and ensures right functionality +- +- for (boolean headers : new boolean[]{false, true}) { +- for (boolean last : new boolean[]{false, true}) { +- for (boolean nonEmptyContent : new boolean[]{false, true}) { +- for (boolean hasTrailers : new boolean[]{false, true}) { +- for (boolean voidPromise : new boolean[]{false, true}) { +- testEncodeCombination(headers, last, nonEmptyContent, hasTrailers, voidPromise); ++ private static final class EncodeCombinationsArgumentsProvider implements ArgumentsProvider { ++ @Override ++ public Stream provideArguments(ExtensionContext extensionContext) { ++ List arguments = new ArrayList<>(); ++ for (boolean headers : new boolean[]{false, true}) { ++ for (boolean last : new boolean[]{false, true}) { ++ for (boolean nonEmptyContent : new boolean[]{false, true}) { ++ for (boolean hasTrailers : new boolean[]{false, true}) { ++ for (boolean voidPromise : new boolean[]{false, true}) { ++ // this test goes through all the branches of Http3FrameToHttpObjectCodec ++ // and ensures right functionality ++ arguments.add(Arguments.of(headers, last, nonEmptyContent, hasTrailers, voidPromise)); ++ } + } + } + } + } ++ return arguments.stream(); + } + } + +- /** +- * @param headers Should this be an initial message, with headers ({@link HttpRequest})? +- * @param last Should this be a last message ({@link LastHttpContent})? +- * @param nonEmptyContent Should this message have non-empty content? +- * @param hasTrailers Should this {@code last} message have trailers? +- * @param voidPromise Should the write operation use a void promise? +- */ +- private static void testEncodeCombination( ++ @ParameterizedTest(name = "headers: {0}, last: {1}, nonEmptyContent: {2}, hasTrailers: {3}, voidPromise: {4}") ++ @ArgumentsSource(value = EncodeCombinationsArgumentsProvider.class) ++ public void testEncodeCombination( + boolean headers, + boolean last, + boolean nonEmptyContent, +@@ -772,31 +798,28 @@ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) + Http3DataFrame dataFrame = ch.readOutbound(); + assertThat(dataFrame.content().readableBytes(), is(1)); + dataFrame.release(); +- } else if (!headers && !hasTrailers && !last) { +- ch.readOutbound().release(); + } + if (hasTrailers) { + Http3HeadersFrame trailersFrame = ch.readOutbound(); + assertThat(trailersFrame.headers().get("foo"), is("bar")); ++ } else if (!nonEmptyContent && !headers) { ++ Http3DataFrame dataFrame = ch.readOutbound(); ++ assertThat(dataFrame.content().readableBytes(), is(0)); ++ dataFrame.release(); + } +- // empty LastHttpContent has no data written and will complete the promise immediately +- boolean anyData = hasTrailers || nonEmptyContent || headers || !last; ++ + if (!voidPromise) { +- if (anyData) { +- assertFalse(fullPromise.isDone()); +- } else { +- // nothing to write, immediately complete +- assertTrue(fullPromise.isDone()); +- } +- } +- if (!last || anyData) { +- assertFalse(ch.isOutputShutdown()); ++ assertFalse(fullPromise.isDone()); + } ++ ++ assertFalse(ch.isOutputShutdown()); + for (ChannelPromise framePromise : framePromises) { + framePromise.trySuccess(); + } + if (last) { + assertTrue(ch.isOutputShutdown()); ++ } else { ++ assertFalse(ch.isOutputShutdown()); + } + if (!voidPromise) { + assertTrue(fullPromise.isDone()); + +From edb7763561589ff53a20df848270cb5144b70f95 Mon Sep 17 00:00:00 2001 +From: Norman Maurer +Date: Tue, 16 Jan 2024 10:20:32 +0100 +Subject: [PATCH 2/2] Always correctly release + +--- + .../http3/Http3FrameToHttpObjectCodec.java | 50 ++++++++++--------- + 1 file changed, 26 insertions(+), 24 deletions(-) + +diff --git a/src/main/java/io/netty/incubator/codec/http3/Http3FrameToHttpObjectCodec.java b/src/main/java/io/netty/incubator/codec/http3/Http3FrameToHttpObjectCodec.java +index aa2deb3..c7b5058 100644 +--- a/src/main/java/io/netty/incubator/codec/http3/Http3FrameToHttpObjectCodec.java ++++ b/src/main/java/io/netty/incubator/codec/http3/Http3FrameToHttpObjectCodec.java +@@ -172,35 +172,37 @@ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) + + if (isLast) { + LastHttpContent last = (LastHttpContent) msg; +- boolean readable = last.content().isReadable(); +- boolean hasTrailers = !last.trailingHeaders().isEmpty(); ++ try { ++ boolean readable = last.content().isReadable(); ++ boolean hasTrailers = !last.trailingHeaders().isEmpty(); + +- if (combiner == null && readable && hasTrailers && !promise.isVoid()) { +- combiner = new PromiseCombiner(ctx.executor()); +- } ++ if (combiner == null && readable && hasTrailers && !promise.isVoid()) { ++ combiner = new PromiseCombiner(ctx.executor()); ++ } + +- if (readable) { +- promise = writeWithOptionalCombiner(ctx, +- new DefaultHttp3DataFrame(last.content()), promise, combiner, true); +- } +- if (hasTrailers) { +- Http3Headers headers = HttpConversionUtil.toHttp3Headers(last.trailingHeaders(), validateHeaders); +- promise = writeWithOptionalCombiner(ctx, +- new DefaultHttp3HeadersFrame(headers), promise, combiner, true); +- } else if (!readable) { +- // Release the data and just use EMPTY_BUFFER. This might allow us to give back memory to the allocator +- // faster. +- last.release(); +- if (combiner == null) { +- // We only need to write something if there was no write before. ++ if (readable) { ++ promise = writeWithOptionalCombiner( ++ ctx, new DefaultHttp3DataFrame(last.content().retain()), promise, combiner, true); ++ } ++ if (hasTrailers) { ++ Http3Headers headers = HttpConversionUtil.toHttp3Headers(last.trailingHeaders(), validateHeaders); + promise = writeWithOptionalCombiner(ctx, +- new DefaultHttp3DataFrame(Unpooled.EMPTY_BUFFER), promise, combiner, true); ++ new DefaultHttp3HeadersFrame(headers), promise, combiner, true); ++ } else if (!readable) { ++ if (combiner == null) { ++ // We only need to write something if there was no write before. ++ promise = writeWithOptionalCombiner( ++ ctx, new DefaultHttp3DataFrame(last.content().retain()), promise, combiner, true); ++ } + } ++ // The shutdown is always done via the listener to ensure previous written data is correctly drained ++ // before QuicStreamChannel.shutdownOutput() is called. Missing to do so might cause previous queued ++ // data to be failed with a ClosedChannelException. ++ promise = promise.unvoid().addListener(QuicStreamChannel.SHUTDOWN_OUTPUT); ++ } finally { ++ // Release LastHttpContent, we retain the content if we need it. ++ last.release(); + } +- // The shutdown is always done via the listener to ensure previous written data is correctly drained +- // before QuicStreamChannel.shutdownOutput() is called. Missing to do so might cause previous queued data +- // to be failed with a ClosedChannelException. +- promise.addListener(QuicStreamChannel.SHUTDOWN_OUTPUT); + } else if (msg instanceof HttpContent) { + promise = writeWithOptionalCombiner(ctx, + new DefaultHttp3DataFrame(((HttpContent) msg).content()), promise, combiner, false);