diff --git a/transport-native-epoll/src/main/c/netty_epoll_native.c b/transport-native-epoll/src/main/c/netty_epoll_native.c index 7ce49aab9f..d4e0039487 100644 --- a/transport-native-epoll/src/main/c/netty_epoll_native.c +++ b/transport-native-epoll/src/main/c/netty_epoll_native.c @@ -48,6 +48,7 @@ #include "netty_unix_limits.h" #include "netty_unix_socket.h" #include "netty_unix_util.h" +#include "netty_unix.h" // Add define if NETTY_BUILD_STATIC is defined so it is picked up in netty_jni_util.c #ifdef NETTY_BUILD_STATIC @@ -107,6 +108,9 @@ static jfieldID packetPortFieldId = NULL; static jfieldID packetMemoryAddressFieldId = NULL; static jfieldID packetCountFieldId = NULL; +static const char* staticPackagePrefix = NULL; +static int register_unix_called = 0; + // util methods static int getSysctlValue(const char * property, int* returnValue) { int rc = -1; @@ -523,6 +527,12 @@ static jint netty_epoll_native_tcpMd5SigMaxKeyLen(JNIEnv* env, jclass clazz) { return TCP_MD5SIG_MAXKEYLEN; } + +static jint netty_epoll_native_registerUnix(JNIEnv* env, jclass clazz) { + register_unix_called = 1; + return netty_unix_register(env, staticPackagePrefix); +} + // JNI Registered Methods End // JNI Method Registration Table Begin @@ -556,7 +566,9 @@ static const JNINativeMethod fixed_method_table[] = { // "sendmmsg0" has a dynamic signature { "sizeofEpollEvent", "()I", (void *) netty_epoll_native_sizeofEpollEvent }, { "offsetofEpollData", "()I", (void *) netty_epoll_native_offsetofEpollData }, - { "splice0", "(IJIJJ)I", (void *) netty_epoll_native_splice0 } + { "splice0", "(IJIJJ)I", (void *) netty_epoll_native_splice0 }, + { "registerUnix", "()I", (void *) netty_epoll_native_registerUnix }, + }; static const jint fixed_method_table_size = sizeof(fixed_method_table) / sizeof(fixed_method_table[0]); @@ -601,11 +613,6 @@ static jint netty_epoll_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix int ret = JNI_ERR; int staticallyRegistered = 0; int nativeRegistered = 0; - int limitsOnLoadCalled = 0; - int errorsOnLoadCalled = 0; - int filedescriptorOnLoadCalled = 0; - int socketOnLoadCalled = 0; - int bufferOnLoadCalled = 0; int linuxsocketOnLoadCalled = 0; char* nettyClassName = NULL; jclass nativeDatagramPacketCls = NULL; @@ -636,32 +643,6 @@ static jint netty_epoll_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix } nativeRegistered = 1; - // Load all c modules that we depend upon - if (netty_unix_limits_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { - goto done; - } - limitsOnLoadCalled = 1; - - if (netty_unix_errors_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { - goto done; - } - errorsOnLoadCalled = 1; - - if (netty_unix_filedescriptor_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { - goto done; - } - filedescriptorOnLoadCalled = 1; - - if (netty_unix_socket_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { - goto done; - } - socketOnLoadCalled = 1; - - if (netty_unix_buffer_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { - goto done; - } - bufferOnLoadCalled = 1; - if (netty_epoll_linuxsocket_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { goto done; } @@ -680,6 +661,10 @@ static jint netty_epoll_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix NETTY_JNI_UTIL_GET_FIELD(env, nativeDatagramPacketCls, packetCountFieldId, "count", "I", done); ret = NETTY_JNI_UTIL_JNI_VERSION; + + if (packagePrefix != NULL) { + staticPackagePrefix = strdup(packagePrefix); + } done: netty_jni_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize()); @@ -692,21 +677,6 @@ done: if (nativeRegistered == 1) { netty_jni_util_unregister_natives(env, packagePrefix, NATIVE_CLASSNAME); } - if (limitsOnLoadCalled == 1) { - netty_unix_limits_JNI_OnUnLoad(env, packagePrefix); - } - if (errorsOnLoadCalled == 1) { - netty_unix_errors_JNI_OnUnLoad(env, packagePrefix); - } - if (filedescriptorOnLoadCalled == 1) { - netty_unix_filedescriptor_JNI_OnUnLoad(env, packagePrefix); - } - if (socketOnLoadCalled == 1) { - netty_unix_socket_JNI_OnUnLoad(env, packagePrefix); - } - if (bufferOnLoadCalled == 1) { - netty_unix_buffer_JNI_OnUnLoad(env, packagePrefix); - } if (linuxsocketOnLoadCalled == 1) { netty_epoll_linuxsocket_JNI_OnUnLoad(env, packagePrefix); } @@ -721,13 +691,17 @@ done: } static void netty_epoll_native_JNI_OnUnload(JNIEnv* env, const char* packagePrefix) { - netty_unix_limits_JNI_OnUnLoad(env, packagePrefix); - netty_unix_errors_JNI_OnUnLoad(env, packagePrefix); - netty_unix_filedescriptor_JNI_OnUnLoad(env, packagePrefix); - netty_unix_socket_JNI_OnUnLoad(env, packagePrefix); - netty_unix_buffer_JNI_OnUnLoad(env, packagePrefix); netty_epoll_linuxsocket_JNI_OnUnLoad(env, packagePrefix); + if (register_unix_called == 1) { + register_unix_called = 0; + netty_unix_unregister(env, staticPackagePrefix); + } + if (staticPackagePrefix != NULL) { + free((void *) staticPackagePrefix); + staticPackagePrefix = NULL; + } + packetAddrFieldId = NULL; packetAddrLenFieldId = NULL; packetScopeIdFieldId = NULL; diff --git a/transport-native-epoll/src/main/java/io/netty/channel/epoll/Native.java b/transport-native-epoll/src/main/java/io/netty/channel/epoll/Native.java index b694840c99..fecf9f894c 100644 --- a/transport-native-epoll/src/main/java/io/netty/channel/epoll/Native.java +++ b/transport-native-epoll/src/main/java/io/netty/channel/epoll/Native.java @@ -17,6 +17,7 @@ package io.netty.channel.epoll; import io.netty.channel.unix.FileDescriptor; import io.netty.channel.unix.Socket; +import io.netty.channel.unix.Unix; import io.netty.util.internal.NativeLibraryLoader; import io.netty.util.internal.PlatformDependent; import io.netty.util.internal.SystemPropertyUtil; @@ -76,9 +77,16 @@ public final class Native { // Just ignore } } - Socket.initialize(); + Unix.registerInternal(new Runnable() { + @Override + public void run() { + registerUnix(); + } + }); } + private static native int registerUnix(); + // EventLoop operations and constants public static final int EPOLLIN = epollin(); public static final int EPOLLOUT = epollout(); diff --git a/transport-native-kqueue/src/main/c/netty_kqueue_native.c b/transport-native-kqueue/src/main/c/netty_kqueue_native.c index 0f7376ef3a..bb17ebfb46 100644 --- a/transport-native-kqueue/src/main/c/netty_kqueue_native.c +++ b/transport-native-kqueue/src/main/c/netty_kqueue_native.c @@ -35,6 +35,7 @@ #include "netty_unix_limits.h" #include "netty_unix_socket.h" #include "netty_unix_util.h" +#include "netty_unix.h" // Add define if NETTY_BUILD_STATIC is defined so it is picked up in netty_jni_util.c #ifdef NETTY_BUILD_STATIC @@ -75,6 +76,8 @@ #endif /* __APPLE__ */ static clockid_t waitClockId = 0; // initialized by netty_unix_util_initialize_wait_clock +static const char* staticPackagePrefix = NULL; +static int register_unix_called = 0; static jint netty_kqueue_native_kqueueCreate(JNIEnv* env, jclass clazz) { jint kq = kqueue(); @@ -159,6 +162,11 @@ static jint netty_kqueue_native_keventWait(JNIEnv* env, jclass clazz, jint kqueu } } +static jint netty_kqueue_native_registerUnix(JNIEnv* env, jclass clazz) { + register_unix_called = 1; + return netty_unix_register(env, staticPackagePrefix); +} + static jint netty_kqueue_native_sizeofKEvent(JNIEnv* env, jclass clazz) { return sizeof(struct kevent); } @@ -267,7 +275,8 @@ static const JNINativeMethod fixed_method_table[] = { { "offsetofKEventFlags", "()I", (void *) netty_kqueue_native_offsetofKEventFlags }, { "offsetofKEventFFlags", "()I", (void *) netty_kqueue_native_offsetofKEventFFlags }, { "offsetofKEventFilter", "()I", (void *) netty_kqueue_native_offsetofKEventFilter }, - { "offsetofKeventData", "()I", (void *) netty_kqueue_native_offsetofKeventData } + { "offsetofKeventData", "()I", (void *) netty_kqueue_native_offsetofKeventData }, + { "registerUnix", "()I", (void *) netty_kqueue_native_registerUnix } }; static const jint fixed_method_table_size = sizeof(fixed_method_table) / sizeof(fixed_method_table[0]); // JNI Method Registration Table End @@ -275,11 +284,6 @@ static const jint fixed_method_table_size = sizeof(fixed_method_table) / sizeof( static jint netty_kqueue_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) { int staticallyRegistered = 0; int nativeRegistered = 0; - int limitsOnLoadCalled = 0; - int errorsOnLoadCalled = 0; - int filedescriptorOnLoadCalled = 0; - int socketOnLoadCalled = 0; - int bufferOnLoadCalled = 0; int bsdsocketOnLoadCalled = 0; int eventarrayOnLoadCalled = 0; @@ -298,31 +302,6 @@ static jint netty_kqueue_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefi goto error; } nativeRegistered = 1; - // Load all c modules that we depend upon - if (netty_unix_limits_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { - goto error; - } - limitsOnLoadCalled = 1; - - if (netty_unix_errors_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { - goto error; - } - errorsOnLoadCalled = 1; - - if (netty_unix_filedescriptor_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { - goto error; - } - filedescriptorOnLoadCalled = 1; - - if (netty_unix_socket_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { - goto error; - } - socketOnLoadCalled = 1; - - if (netty_unix_buffer_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { - goto error; - } - bufferOnLoadCalled = 1; if (netty_kqueue_bsdsocket_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { goto error; @@ -342,6 +321,9 @@ static jint netty_kqueue_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefi goto error; } + if (packagePrefix != NULL) { + staticPackagePrefix = strdup(packagePrefix); + } return NETTY_JNI_UTIL_JNI_VERSION; error: if (staticallyRegistered == 1) { @@ -350,21 +332,6 @@ error: if (nativeRegistered == 1) { netty_jni_util_unregister_natives(env, packagePrefix, NATIVE_CLASSNAME); } - if (limitsOnLoadCalled == 1) { - netty_unix_limits_JNI_OnUnLoad(env, packagePrefix); - } - if (errorsOnLoadCalled == 1) { - netty_unix_errors_JNI_OnUnLoad(env, packagePrefix); - } - if (filedescriptorOnLoadCalled == 1) { - netty_unix_filedescriptor_JNI_OnUnLoad(env, packagePrefix); - } - if (socketOnLoadCalled == 1) { - netty_unix_socket_JNI_OnUnLoad(env, packagePrefix); - } - if (bufferOnLoadCalled == 1) { - netty_unix_buffer_JNI_OnUnLoad(env, packagePrefix); - } if (bsdsocketOnLoadCalled == 1) { netty_kqueue_bsdsocket_JNI_OnUnLoad(env, packagePrefix); } @@ -375,14 +342,18 @@ error: } static void netty_kqueue_native_JNI_OnUnload(JNIEnv* env, const char* packagePrefix) { - netty_unix_limits_JNI_OnUnLoad(env, packagePrefix); - netty_unix_errors_JNI_OnUnLoad(env, packagePrefix); - netty_unix_filedescriptor_JNI_OnUnLoad(env, packagePrefix); - netty_unix_socket_JNI_OnUnLoad(env, packagePrefix); - netty_unix_buffer_JNI_OnUnLoad(env, packagePrefix); netty_kqueue_bsdsocket_JNI_OnUnLoad(env, packagePrefix); netty_kqueue_eventarray_JNI_OnUnLoad(env, packagePrefix); + if (register_unix_called == 1) { + register_unix_called = 0; + netty_unix_unregister(env, staticPackagePrefix); + } + if (staticPackagePrefix != NULL) { + free((void *) staticPackagePrefix); + staticPackagePrefix = NULL; + } + netty_jni_util_unregister_natives(env, packagePrefix, STATICALLY_CLASSNAME); netty_jni_util_unregister_natives(env, packagePrefix, NATIVE_CLASSNAME); } diff --git a/transport-native-kqueue/src/main/java/io/netty/channel/kqueue/Native.java b/transport-native-kqueue/src/main/java/io/netty/channel/kqueue/Native.java index cc7795097e..fd9ee54e31 100644 --- a/transport-native-kqueue/src/main/java/io/netty/channel/kqueue/Native.java +++ b/transport-native-kqueue/src/main/java/io/netty/channel/kqueue/Native.java @@ -16,7 +16,7 @@ package io.netty.channel.kqueue; import io.netty.channel.unix.FileDescriptor; -import io.netty.channel.unix.Socket; +import io.netty.channel.unix.Unix; import io.netty.util.internal.NativeLibraryLoader; import io.netty.util.internal.PlatformDependent; import io.netty.util.internal.SystemPropertyUtil; @@ -59,9 +59,16 @@ final class Native { // The library was not previously loaded, load it now. loadNativeLibrary(); } - Socket.initialize(); + Unix.registerInternal(new Runnable() { + @Override + public void run() { + registerUnix(); + } + }); } + private static native int registerUnix(); + static final short EV_ADD = evAdd(); static final short EV_ENABLE = evEnable(); static final short EV_DISABLE = evDisable(); diff --git a/transport-native-unix-common-tests/src/main/java/io/netty/channel/unix/tests/UnixTestUtils.java b/transport-native-unix-common-tests/src/main/java/io/netty/channel/unix/tests/UnixTestUtils.java index 7986e16c31..346be7b046 100644 --- a/transport-native-unix-common-tests/src/main/java/io/netty/channel/unix/tests/UnixTestUtils.java +++ b/transport-native-unix-common-tests/src/main/java/io/netty/channel/unix/tests/UnixTestUtils.java @@ -30,7 +30,7 @@ public final class UnixTestUtils { if (!file.delete()) { throw new IOException("failed to delete: " + file); } - } while (file.getAbsolutePath().length() > Socket.UDS_SUN_PATH_SIZE); + } while (file.getAbsolutePath().length() > 128); return new DomainSocketAddress(file); } catch (IOException e) { throw new IllegalStateException(e); diff --git a/transport-native-unix-common/src/main/c/netty_unix.c b/transport-native-unix-common/src/main/c/netty_unix.c new file mode 100644 index 0000000000..c618fbe155 --- /dev/null +++ b/transport-native-unix-common/src/main/c/netty_unix.c @@ -0,0 +1,85 @@ +/* + * Copyright 2020 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +#include "netty_unix_jni.h" +#include "netty_unix.h" +#include "netty_unix_buffer.h" +#include "netty_unix_errors.h" +#include "netty_unix_filedescriptor.h" +#include "netty_unix_limits.h" +#include "netty_unix_socket.h" +#include "netty_unix_util.h" + +jint netty_unix_register(JNIEnv* env, const char* packagePrefix) { + int limitsOnLoadCalled = 0; + int errorsOnLoadCalled = 0; + int filedescriptorOnLoadCalled = 0; + int socketOnLoadCalled = 0; + int bufferOnLoadCalled = 0; + + // Load all c modules that we depend upon + if (netty_unix_limits_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { + goto error; + } + limitsOnLoadCalled = 1; + + if (netty_unix_errors_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { + goto error; + } + errorsOnLoadCalled = 1; + + if (netty_unix_filedescriptor_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { + goto error; + } + filedescriptorOnLoadCalled = 1; + + if (netty_unix_socket_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { + goto error; + } + socketOnLoadCalled = 1; + + if (netty_unix_buffer_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { + goto error; + } + bufferOnLoadCalled = 1; + + return NETTY_JNI_UTIL_JNI_VERSION; +error: + if (limitsOnLoadCalled == 1) { + netty_unix_limits_JNI_OnUnLoad(env, packagePrefix); + } + if (errorsOnLoadCalled == 1) { + netty_unix_errors_JNI_OnUnLoad(env, packagePrefix); + } + if (filedescriptorOnLoadCalled == 1) { + netty_unix_filedescriptor_JNI_OnUnLoad(env, packagePrefix); + } + if (socketOnLoadCalled == 1) { + netty_unix_socket_JNI_OnUnLoad(env, packagePrefix); + } + if (bufferOnLoadCalled == 1) { + netty_unix_buffer_JNI_OnUnLoad(env, packagePrefix); + } + return JNI_ERR; +} + +void netty_unix_unregister(JNIEnv* env, const char* packagePrefix) { + netty_unix_limits_JNI_OnUnLoad(env, packagePrefix); + netty_unix_errors_JNI_OnUnLoad(env, packagePrefix); + netty_unix_filedescriptor_JNI_OnUnLoad(env, packagePrefix); + netty_unix_socket_JNI_OnUnLoad(env, packagePrefix); + netty_unix_buffer_JNI_OnUnLoad(env, packagePrefix); +} + diff --git a/transport-native-unix-common/src/main/c/netty_unix.h b/transport-native-unix-common/src/main/c/netty_unix.h new file mode 100644 index 0000000000..dff6da7b75 --- /dev/null +++ b/transport-native-unix-common/src/main/c/netty_unix.h @@ -0,0 +1,25 @@ +/* + * Copyright 2020 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +#ifndef NETTY_UNIX_H_ +#define NETTY_UNIX_H_ + +#include + +// JNI initialization hooks. +jint netty_unix_register(JNIEnv* env, const char* packagePrefix); +void netty_unix_unregister(JNIEnv* env, const char* packagePrefix); + +#endif /* NETTY_UNIX_H_ */ diff --git a/transport-native-unix-common/src/main/java/io/netty/channel/unix/Socket.java b/transport-native-unix-common/src/main/java/io/netty/channel/unix/Socket.java index f237879cff..602872891d 100644 --- a/transport-native-unix-common/src/main/java/io/netty/channel/unix/Socket.java +++ b/transport-native-unix-common/src/main/java/io/netty/channel/unix/Socket.java @@ -46,7 +46,8 @@ import static io.netty.channel.unix.NativeInetAddress.ipv4MappedIpv6Address; */ public class Socket extends FileDescriptor { - public static final int UDS_SUN_PATH_SIZE = udsSunPathSize(); + @Deprecated + public static final int UDS_SUN_PATH_SIZE = 100; protected final boolean ipv6; diff --git a/transport-native-unix-common/src/main/java/io/netty/channel/unix/Unix.java b/transport-native-unix-common/src/main/java/io/netty/channel/unix/Unix.java index f625126cb5..8c7f0f7f25 100644 --- a/transport-native-unix-common/src/main/java/io/netty/channel/unix/Unix.java +++ b/transport-native-unix-common/src/main/java/io/netty/channel/unix/Unix.java @@ -15,54 +15,37 @@ */ package io.netty.channel.unix; -import java.io.IOException; -import java.nio.channels.Selector; +import io.netty.util.internal.UnstableApi; + +import java.util.concurrent.atomic.AtomicBoolean; /** * Tells if {@code netty-transport-native-unix} is * supported. */ public final class Unix { - private static final Throwable UNAVAILABILITY_CAUSE; + private static final AtomicBoolean registered = new AtomicBoolean(); - static { - Throwable cause = null; - Selector selector = null; - try { - // We call Selector.open() as this will under the hood cause IOUtil to be loaded. - // This is a workaround for a possible classloader deadlock that could happen otherwise: - // - // See https://github.com/netty/netty/issues/10187 - selector = Selector.open(); - } catch (IOException ignore) { - // Just ignore + /** + * Internal method... Should never be called from the user. + * + * @param registerTask + */ + @UnstableApi + public static void registerInternal(Runnable registerTask) { + if (registered.compareAndSet(false, true)) { + registerTask.run(); + Socket.initialize(); } - try { - try { - // First, try calling a side-effect free JNI method to see if the library was already - // loaded by the application. - LimitsStaticallyReferencedJniMethods.udsSunPathSize(); - } finally { - try { - if (selector != null) { - selector.close(); - } - } catch (IOException ignore) { - // Just ignore - } - } - } catch (Throwable error) { - cause = error; - } - UNAVAILABILITY_CAUSE = cause; } /** * Returns {@code true} if and only if the {@code * netty_transport_native_unix} is available. */ + @Deprecated public static boolean isAvailable() { - return UNAVAILABILITY_CAUSE == null; + return false; } /** @@ -71,11 +54,9 @@ public final class Unix { * * @throws UnsatisfiedLinkError if unavailable */ + @Deprecated public static void ensureAvailability() { - if (UNAVAILABILITY_CAUSE != null) { - throw (Error) new UnsatisfiedLinkError( - "failed to load the required native library").initCause(UNAVAILABILITY_CAUSE); - } + throw new UnsupportedOperationException(); } /** @@ -84,8 +65,9 @@ public final class Unix { * * @return the cause if unavailable. {@code null} if available. */ + @Deprecated public static Throwable unavailabilityCause() { - return UNAVAILABILITY_CAUSE; + return new UnsupportedOperationException(); } private Unix() {