diff --git a/transport-native-epoll/pom.xml b/transport-native-epoll/pom.xml index 80f7291f71..fdab2d5571 100644 --- a/transport-native-epoll/pom.xml +++ b/transport-native-epoll/pom.xml @@ -34,6 +34,7 @@ ${project.build.directory}/unix-common-lib ${unix.common.lib.dir}/META-INF/native/lib ${unix.common.lib.dir}/META-INF/native/include + CFLAGS=-O3 -Werror -fno-omit-frame-pointer -Wunused-variable -fvisibility=hidden -I${unix.common.include.unpacked.dir} LDFLAGS=-L${unix.common.lib.unpacked.dir} -Wl,--no-as-needed -lrt -Wl,--whole-archive -l${unix.common.lib.name} -Wl,--no-whole-archive ${project.basedir}/src/main/c true @@ -192,102 +193,6 @@ - - - maven-antrun-plugin - - - - validate - - run - - ant-get-systeminfo - - true - - - - - - - - - - - - - - - org.codehaus.mojo - build-helper-maven-plugin - - - - initialize - regex-glibc-sendmmsg - - regex-property - - - glibc.sendmmsg.support - ${ldd_version} - - ^((?!^[^)]+\)\s+(0*2\.1[4-9]|0*2\.[2-9][0-9]+|0*[3-9][0-9]*|0*[1-9]+[0-9]+).*).)*$ - IO_NETTY_SENDMSSG_NOT_FOUND - false - - - - - initialize - regex-linux-sendmmsg - - regex-property - - - linux.sendmmsg.support - ${uname_os_version} - - ^((?!^[0-9]*[3-9]\.?.*).)*$ - IO_NETTY_SENDMSSG_NOT_FOUND - false - - - - - generate-sources - regex-combined-sendmmsg - - regex-property - - - jni.compiler.args.cflags - ${linux.sendmmsg.support}${glibc.sendmmsg.support} - - .*IO_NETTY_SENDMSSG_NOT_FOUND.* - CFLAGS=-O3 -DIO_NETTY_SENDMMSG_NOT_FOUND -Werror -fno-omit-frame-pointer -Wunused-variable -fvisibility=hidden -I${unix.common.include.unpacked.dir} - false - - - - - generate-sources - regex-unset-if-needed-sendmmsg - - regex-property - - - jni.compiler.args.cflags - ${jni.compiler.args.cflags} - - ^((?!CFLAGS=).)*$ - CFLAGS=-O3 -Werror -fno-omit-frame-pointer -Wunused-variable -fvisibility=hidden -I${unix.common.include.unpacked.dir} - false - - - - 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 cac6472a16..22635489b6 100644 --- a/transport-native-epoll/src/main/c/netty_epoll_native.c +++ b/transport-native-epoll/src/main/c/netty_epoll_native.c @@ -36,6 +36,9 @@ #include #include #include +// Needed to be able to use syscalls directly and so not depend on newer GLIBC versions +#include +#include #include "netty_epoll_linuxsocket.h" #include "netty_unix_buffer.h" @@ -54,15 +57,20 @@ // optional extern int epoll_create1(int flags) __attribute__((weak)); -#ifdef IO_NETTY_SENDMMSG_NOT_FOUND -extern int sendmmsg(int sockfd, struct mmsghdr* msgvec, unsigned int vlen, unsigned int flags) __attribute__((weak)); - #ifndef __USE_GNU struct mmsghdr { struct msghdr msg_hdr; /* Message header */ unsigned int msg_len; /* Number of bytes transmitted */ }; #endif + +// All linux syscall numbers are stable so this is safe. +#ifndef SYS_recvmmsg +#define SYS_recvmmsg 299 +#endif + +#ifndef SYS_sendmmsg +#define SYS_sendmmsg 307 #endif // Those are initialized in the init(...) method and cached for performance reasons @@ -305,7 +313,8 @@ static jint netty_epoll_native_sendmmsg0(JNIEnv* env, jclass clazz, jint fd, jbo ssize_t res; int err; do { - res = sendmmsg(fd, msg, len, 0); + // We directly use the syscall to prevent depending on GLIBC 2.14. + res = syscall(SYS_sendmmsg, fd, msg, len, 0); // keep on writing if it was interrupted } while (res == -1 && ((err = errno) == EINTR)); @@ -336,8 +345,10 @@ static jint netty_epoll_native_recvmmsg0(JNIEnv* env, jclass clazz, jint fd, jbo ssize_t res; int err; do { - res = recvmmsg(fd, msg, len, 0, NULL); - // keep on reading if it was interrupted + // We directly use the syscall to prevent depending on GLIBC 2.12. + res = syscall(SYS_recvmmsg, fd, &msg, len, 0, NULL); + + // keep on reading if it was interrupted } while (res == -1 && ((err = errno) == EINTR)); if (res < 0) { @@ -388,14 +399,22 @@ static jstring netty_epoll_native_kernelVersion(JNIEnv* env, jclass clazz) { netty_unix_errors_throwRuntimeExceptionErrorNo(env, "uname() failed: ", errno); return NULL; } - static jboolean netty_epoll_native_isSupportingSendmmsg(JNIEnv* env, jclass clazz) { - // Use & to avoid warnings with -Wtautological-pointer-compare when sendmmsg is - // not weakly defined. - if (&sendmmsg != NULL) { - return JNI_TRUE; + if (syscall(SYS_sendmmsg, -1, NULL, 0, 0) == -1) { + if (errno == ENOSYS) { + return JNI_FALSE; + } } - return JNI_FALSE; + return JNI_TRUE; +} + +static jboolean netty_epoll_native_isSupportingRecvmmsg(JNIEnv* env, jclass clazz) { + if (syscall(SYS_recvmmsg, -1, NULL, 0, 0, NULL) == -1) { + if (errno == ENOSYS) { + return JNI_FALSE; + } + } + return JNI_TRUE; } static jboolean netty_epoll_native_isSupportingTcpFastopen(JNIEnv* env, jclass clazz) { @@ -476,6 +495,7 @@ static const JNINativeMethod statically_referenced_fixed_method_table[] = { { "epollerr", "()I", (void *) netty_epoll_native_epollerr }, { "tcpMd5SigMaxKeyLen", "()I", (void *) netty_epoll_native_tcpMd5SigMaxKeyLen }, { "isSupportingSendmmsg", "()Z", (void *) netty_epoll_native_isSupportingSendmmsg }, + { "isSupportingRecvmmsg", "()Z", (void *) netty_epoll_native_isSupportingRecvmmsg }, { "isSupportingTcpFastopen", "()Z", (void *) netty_epoll_native_isSupportingTcpFastopen }, { "kernelVersion", "()Ljava/lang/String;", (void *) netty_epoll_native_kernelVersion } }; diff --git a/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollDatagramChannel.java b/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollDatagramChannel.java index 26090d0809..c1f95dd6a3 100644 --- a/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollDatagramChannel.java +++ b/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollDatagramChannel.java @@ -483,7 +483,11 @@ public final class EpollDatagramChannel extends AbstractEpollChannel implements ByteBuf byteBuf = allocHandle.allocate(allocator); final boolean read; int datagramSize = config().getMaxDatagramPayloadSize(); - int numDatagram = datagramSize == 0 ? 1 : byteBuf.writableBytes() / datagramSize; + + // Only try to use recvmmsg if its really supported by the running system. + int numDatagram = Native.IS_SUPPORTING_RECVMMSG ? + datagramSize == 0 ? 1 : byteBuf.writableBytes() / datagramSize : + 0; try { if (numDatagram <= 1) { 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 9fb92aaf1c..32c9ba7f5b 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 @@ -32,6 +32,7 @@ import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.epolle import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.epollin; import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.epollout; import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.epollrdhup; +import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.isSupportingRecvmmsg; import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.isSupportingSendmmsg; import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.isSupportingTcpFastopen; import static io.netty.channel.epoll.NativeStaticallyReferencedJniMethods.kernelVersion; @@ -67,6 +68,8 @@ public final class Native { public static final int EPOLLERR = epollerr(); public static final boolean IS_SUPPORTING_SENDMMSG = isSupportingSendmmsg(); + static final boolean IS_SUPPORTING_RECVMMSG = isSupportingRecvmmsg(); + public static final boolean IS_SUPPORTING_TCP_FASTOPEN = isSupportingTcpFastopen(); public static final int TCP_MD5SIG_MAXKEYLEN = tcpMd5SigMaxKeyLen(); public static final String KERNEL_VERSION = kernelVersion(); diff --git a/transport-native-epoll/src/main/java/io/netty/channel/epoll/NativeStaticallyReferencedJniMethods.java b/transport-native-epoll/src/main/java/io/netty/channel/epoll/NativeStaticallyReferencedJniMethods.java index 4f6f99c528..9b20d686f0 100644 --- a/transport-native-epoll/src/main/java/io/netty/channel/epoll/NativeStaticallyReferencedJniMethods.java +++ b/transport-native-epoll/src/main/java/io/netty/channel/epoll/NativeStaticallyReferencedJniMethods.java @@ -40,6 +40,7 @@ final class NativeStaticallyReferencedJniMethods { static native int iovMax(); static native int uioMaxIov(); static native boolean isSupportingSendmmsg(); + static native boolean isSupportingRecvmmsg(); static native boolean isSupportingTcpFastopen(); static native String kernelVersion(); } diff --git a/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollDatagramScatteringReadTest.java b/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollDatagramScatteringReadTest.java index d7f5d480c6..85f62f301f 100644 --- a/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollDatagramScatteringReadTest.java +++ b/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollDatagramScatteringReadTest.java @@ -25,6 +25,8 @@ import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.socket.DatagramPacket; import io.netty.testsuite.transport.TestsuitePermutation; import io.netty.testsuite.transport.socket.AbstractDatagramTest; +import org.junit.Assume; +import org.junit.BeforeClass; import org.junit.Test; import java.net.InetSocketAddress; @@ -43,6 +45,11 @@ import static org.junit.Assert.fail; public class EpollDatagramScatteringReadTest extends AbstractDatagramTest { + @BeforeClass + public static void assumeRecvmmsgSupported() { + Assume.assumeTrue(Native.IS_SUPPORTING_RECVMMSG); + } + @Override protected List> newFactories() { return EpollSocketTestPermutation.INSTANCE.epollOnlyDatagram(internetProtocolFamily());