Compare commits

...

10 commits

481 changed files with 52890 additions and 2345 deletions

3
.gitignore vendored
View file

@ -2,7 +2,6 @@
/.classpath
/.project
/.gradle
**/data
**/work
**/logs
**/.idea
@ -12,5 +11,3 @@
.DS_Store
*.iml
*~
*.key
*.crt

View file

@ -25,6 +25,7 @@ The following changes were performed on the original source code:
- removed all macos related code (including kqueue)
- removed all aarch64 related code
- removed the direct brotli4j dependency by rewriting Brotli4jOptions to not use Encoder.Parameters
- removed deprecated channel-udt (transport-udt)
Challenges for Netty build on JDK 21
@ -41,12 +42,12 @@ Subproject organization
Original netty subproject names are not related to package names. I reorganized the names to allow better assignment
between subproject name, package name, artifact names, and java module. The following reorgnizations were performed:
netty/all -> [todo]
netty/bom -> [todo]
netty/all ->
netty/bom ->
netty/buffer -> netty-buffer
netty/codec -> netty-handler-codec, netty-handler-codec-compression, netty-handler-codec-protobuf
netty/codec-dns -> [todo]
netty/codec-haproxy -> [todo]
netty/codec-dns -> netty-handler-codec-dns
netty/codec-haproxy ->
netty/codec-http -> netty-handler-codec-http, netty-handler-codec-rtsp, netty-handler-codec-spdy
netty/codec-http2 ->
netty/codec-memcache ->
@ -61,7 +62,7 @@ netty/handler -> netty-handler
netty/handler-proxy
netty/handler-ssl-ocsp
netty/resolver -> netty-resolver
netty/resolver-dns ->
netty/resolver-dns -> netty-resolver-dns
netty/resolver-dns-classes-macos -> [dropped]
netty/resolver-dns-native-macos -> [dropped]
netty/transport -> netty-channel

View file

@ -11,8 +11,6 @@ wrapper {
distributionType = Wrapper.DistributionType.BIN
}
apply plugin: 'com.google.osdetector'
ext {
user = 'joerg'
name = 'netty'
@ -30,11 +28,15 @@ ext {
organizationUrl = 'https://xbib.org'
}
apply plugin: 'com.google.osdetector'
subprojects {
apply from: rootProject.file('gradle/repositories/maven.gradle')
apply from: rootProject.file('gradle/compile/java.gradle')
apply from: rootProject.file('gradle/test/junit5.gradle')
apply from: rootProject.file('gradle/publish/maven.gradle')
if (!it.name.endsWith('-native') && it.name != 'test-results') {
apply from: rootProject.file('gradle/repositories/maven.gradle')
apply from: rootProject.file('gradle/compile/java.gradle')
apply from: rootProject.file('gradle/test/junit5.gradle')
apply from: rootProject.file('gradle/publish/maven.gradle')
}
}
apply from: rootProject.file('gradle/publish/sonatype.gradle')
apply from: rootProject.file('gradle/publish/forgejo.gradle')

View file

@ -1,3 +1,3 @@
group = org.xbib.netty
name = netty
version = 4.1.104
version = 4.1.107.0

3
gradle/compile/c.gradle Normal file
View file

@ -0,0 +1,3 @@
apply plugin: 'base'
apply plugin: 'org.xbib.gradle.plugin.c'

View file

@ -0,0 +1 @@
apply plugin: 'org.xbib.gradle.plugin.cmake'

View file

@ -10,11 +10,8 @@ dependencies {
test {
useJUnitPlatform()
failFast = true
testLogging {
events 'STARTED', 'PASSED', 'FAILED', 'SKIPPED'
showStandardStreams = true
}
failFast = false
ignoreFailures = true
minHeapSize = "1g" // initial heap size
maxHeapSize = "2g" // maximum heap size
jvmArgs '--add-exports=java.base/jdk.internal=ALL-UNNAMED',
@ -30,11 +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'
// we have remove native images, this is no longer used
systemProperty "nativeImage.handlerMetadataGroupId", "io.netty"
// we have remove native images
// we have remove native images, this is no longer used
systemProperty "nativeimage.handlerMetadataArtifactId", "netty-transport"
testLogging {
events 'STARTED', 'PASSED', 'FAILED', 'SKIPPED'
showStandardStreams = true
}
afterSuite { desc, result ->
if (!desc.parent) {
println "\nTest result: ${result.resultType}"

Binary file not shown.

View file

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

20
gradlew.bat vendored
View file

@ -43,11 +43,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail

View file

@ -1,7 +1,7 @@
handlers=java.util.logging.ConsoleHandler
.level=ALL
.level=INFO
java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%1$tL %4$-7s [%3$s] %5$s %6$s%n
java.util.logging.ConsoleHandler.level=ALL
java.util.logging.ConsoleHandler.level=INFO
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
jdk.event.security.level=INFO
org.junit.jupiter.engine.execution.ConditionEvaluator.level=OFF

View file

@ -0,0 +1,82 @@
/* 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'))
archiveBaseName.set(project.name + '-' + project.version)
archiveExtension.set('jar')
archiveClassifier.set('linux-x86_64')
version rootProject.version
from (project.layout.projectDirectory.dir('src/main/resources')) {
include 'META-INF/native/libnetty_transport_native_epoll_x86_64.so'
}
}
assemble.dependsOn(nettyEpollLinuxX8664)
configurations {
'linux-x86_64' {
canBeConsumed = true
canBeResolved = false
/*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'))
}*/
}
}
artifacts {
'linux-x86_64'(nettyEpollLinuxX8664)
}
publishing {
publications {
publishNettyEpollLinuxX8664(MavenPublication) {
groupId rootProject.group
artifactId project.name
version rootProject.version
artifact nettyEpollLinuxX8664
pom {
artifactId = project.name
name = project.name
version = project.version
description = rootProject.ext.description
url = rootProject.ext.url
inceptionYear = rootProject.ext.inceptionYear
packaging = 'jar'
organization {
name = rootProject.ext.organizationName
url = rootProject.ext.organizationUrl
}
developers {
developer {
id = 'jprante'
name = 'Jörg Prante'
email = 'joergprante@gmail.com'
url = 'https://xbib.org/joerg'
}
}
scm {
url = rootProject.ext.scmUrl
connection = rootProject.ext.scmConnection
developerConnection = rootProject.ext.scmDeveloperConnection
}
issueManagement {
system = rootProject.ext.issueManagementSystem
url = rootProject.ext.issueManagementUrl
}
licenses {
license {
name = rootProject.ext.licenseName
url = rootProject.ext.licenseUrl
distribution = 'repo'
}
}
}
}
}
}

View file

@ -0,0 +1,909 @@
/*
* Copyright 2016 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.
*/
/*
* Since glibc 2.8, the _GNU_SOURCE feature test macro must be defined
* (before including any header files) in order to obtain the
* definition of the ucred structure. See <a href=https://linux.die.net/man/7/unix>
*/
#define _GNU_SOURCE
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/udp.h> // SOL_UDP
#include <sys/sendfile.h>
#include <linux/tcp.h> // TCP_NOTSENT_LOWAT is a linux specific define
#include "netty_epoll_linuxsocket.h"
#include "netty_epoll_vmsocket.h"
#include "netty_unix_errors.h"
#include "netty_unix_filedescriptor.h"
#include "netty_unix_jni.h"
#include "netty_unix_socket.h"
#include "netty_unix_util.h"
#define LINUXSOCKET_CLASSNAME "io/netty/channel/epoll/LinuxSocket"
// TCP_FASTOPEN is defined in linux 3.7. We define this here so older kernels can compile.
#ifndef TCP_FASTOPEN
#define TCP_FASTOPEN 23
#endif
// TCP_FASTOPEN_CONNECT is defined in linux 4.11. We define this here so older kernels can compile.
#ifndef TCP_FASTOPEN_CONNECT
#define TCP_FASTOPEN_CONNECT 30
#endif
// TCP_NOTSENT_LOWAT is defined in linux 3.12. We define this here so older kernels can compile.
#ifndef TCP_NOTSENT_LOWAT
#define TCP_NOTSENT_LOWAT 25
#endif
// SO_BUSY_POLL is defined in linux 3.11. We define this here so older kernels can compile.
#ifndef SO_BUSY_POLL
#define SO_BUSY_POLL 46
#endif
// UDP_GRO is defined in linux 5. We define this here so older kernels can compile.
#ifndef UDP_GRO
#define UDP_GRO 104
#endif
static jweak peerCredentialsClassWeak = NULL;
static jmethodID peerCredentialsMethodId = NULL;
static jfieldID fileChannelFieldId = NULL;
static jfieldID transferredFieldId = NULL;
static jfieldID fdFieldId = NULL;
static jfieldID fileDescriptorFieldId = NULL;
// JNI Registered Methods Begin
static jint netty_epoll_linuxsocket_newVSockStreamFd(JNIEnv* env, jclass clazz) {
int fd = netty_unix_socket_nonBlockingSocket(AF_VSOCK, SOCK_STREAM, 0);
if (fd == -1) {
return -errno;
}
return fd;
}
static jint netty_epoll_linuxsocket_bindVSock(JNIEnv* env, jclass clazz, jint fd, jint cid, jint port) {
struct sockaddr_vm addr;
memset(&addr, 0, sizeof(struct sockaddr_vm));
addr.svm_family = AF_VSOCK;
addr.svm_port = port;
addr.svm_cid = cid;
int res = bind(fd, (struct sockaddr*) &addr, sizeof(struct sockaddr_vm));
if (res == -1) {
return -errno;
}
return res;
}
static jint netty_epoll_linuxsocket_connectVSock(JNIEnv* env, jclass clazz, jint fd, jint cid, jint port) {
struct sockaddr_vm addr;
memset(&addr, 0, sizeof(struct sockaddr_vm));
addr.svm_family = AF_VSOCK;
addr.svm_port = port;
addr.svm_cid = cid;
int res;
int err;
do {
res = connect(fd, (struct sockaddr*) &addr, sizeof(struct sockaddr_vm));
} while (res == -1 && ((err = errno) == EINTR));
if (res == -1) {
return -errno;
}
return res;
}
static jbyteArray createVSockAddressArray(JNIEnv* env, const struct sockaddr_vm* addr) {
jbyteArray bArray = (*env)->NewByteArray(env, 8);
if (bArray == NULL) {
return NULL;
}
unsigned int cid = (addr->svm_cid);
unsigned int port = (addr->svm_port);
unsigned char a[4];
a[0] = cid >> 24;
a[1] = cid >> 16;
a[2] = cid >> 8;
a[3] = cid;
(*env)->SetByteArrayRegion(env, bArray, 0, 4, (jbyte*) &a);
a[0] = port >> 24;
a[1] = port >> 16;
a[2] = port >> 8;
a[3] = port;
(*env)->SetByteArrayRegion(env, bArray, 4, 4, (jbyte*) &a);
return bArray;
}
static jbyteArray netty_epoll_linuxsocket_remoteVSockAddress(JNIEnv* env, jclass clazz, jint fd) {
struct sockaddr_vm addr = { 0 };
socklen_t len = sizeof(addr);
if (getpeername(fd, (struct sockaddr*) &addr, &len) == -1) {
return NULL;
}
return createVSockAddressArray(env, &addr);
}
static jbyteArray netty_epoll_linuxsocket_localVSockAddress(JNIEnv* env, jclass clazz, jint fd) {
struct sockaddr_vm addr = { 0 };
socklen_t len = sizeof(addr);
if (getsockname(fd, (struct sockaddr*) &addr, &len) == -1) {
return NULL;
}
return createVSockAddressArray(env, &addr);
}
static void netty_epoll_linuxsocket_setTimeToLive(JNIEnv* env, jclass clazz, jint fd, jint optval) {
netty_unix_socket_setOption(env, fd, IPPROTO_IP, IP_TTL, &optval, sizeof(optval));
}
static void netty_epoll_linuxsocket_setIpMulticastLoop(JNIEnv* env, jclass clazz, jint fd, jboolean ipv6, jint optval) {
if (ipv6 == JNI_TRUE) {
u_int val = (u_int) optval;
netty_unix_socket_setOption(env, fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val, sizeof(val));
} else {
u_char val = (u_char) optval;
netty_unix_socket_setOption(env, fd, IPPROTO_IP, IP_MULTICAST_LOOP, &val, sizeof(val));
}
}
static void netty_epoll_linuxsocket_setInterface(JNIEnv* env, jclass clazz, jint fd, jboolean ipv6, jbyteArray interfaceAddress, jint scopeId, jint interfaceIndex) {
struct sockaddr_storage interfaceAddr;
socklen_t interfaceAddrSize;
struct sockaddr_in* interfaceIpAddr;
memset(&interfaceAddr, 0, sizeof(interfaceAddr));
if (ipv6 == JNI_TRUE) {
if (interfaceIndex == -1) {
netty_unix_errors_throwIOException(env, "Unable to find network index");
return;
}
netty_unix_socket_setOption(env, fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &interfaceIndex, sizeof(interfaceIndex));
} else {
if (netty_unix_socket_initSockaddr(env, ipv6, interfaceAddress, scopeId, 0, &interfaceAddr, &interfaceAddrSize) == -1) {
netty_unix_errors_throwIOException(env, "Could not init sockaddr");
return;
}
interfaceIpAddr = (struct sockaddr_in*) &interfaceAddr;
netty_unix_socket_setOption(env, fd, IPPROTO_IP, IP_MULTICAST_IF, &interfaceIpAddr->sin_addr, sizeof(interfaceIpAddr->sin_addr));
}
}
static void netty_epoll_linuxsocket_setTcpCork(JNIEnv* env, jclass clazz, jint fd, jint optval) {
netty_unix_socket_setOption(env, fd, IPPROTO_TCP, TCP_CORK, &optval, sizeof(optval));
}
static void netty_epoll_linuxsocket_setTcpQuickAck(JNIEnv* env, jclass clazz, jint fd, jint optval) {
netty_unix_socket_setOption(env, fd, IPPROTO_TCP, TCP_QUICKACK, &optval, sizeof(optval));
}
static void netty_epoll_linuxsocket_setTcpDeferAccept(JNIEnv* env, jclass clazz, jint fd, jint optval) {
netty_unix_socket_setOption(env, fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &optval, sizeof(optval));
}
static void netty_epoll_linuxsocket_setTcpNotSentLowAt(JNIEnv* env, jclass clazz, jint fd, jint optval) {
netty_unix_socket_setOption(env, fd, IPPROTO_TCP, TCP_NOTSENT_LOWAT, &optval, sizeof(optval));
}
static void netty_epoll_linuxsocket_setTcpFastOpen(JNIEnv* env, jclass clazz, jint fd, jint optval) {
netty_unix_socket_setOption(env, fd, IPPROTO_TCP, TCP_FASTOPEN, &optval, sizeof(optval));
}
static void netty_epoll_linuxsocket_setTcpKeepIdle(JNIEnv* env, jclass clazz, jint fd, jint optval) {
netty_unix_socket_setOption(env, fd, IPPROTO_TCP, TCP_KEEPIDLE, &optval, sizeof(optval));
}
static void netty_epoll_linuxsocket_setTcpKeepIntvl(JNIEnv* env, jclass clazz, jint fd, jint optval) {
netty_unix_socket_setOption(env, fd, IPPROTO_TCP, TCP_KEEPINTVL, &optval, sizeof(optval));
}
static void netty_epoll_linuxsocket_setTcpKeepCnt(JNIEnv* env, jclass clazz, jint fd, jint optval) {
netty_unix_socket_setOption(env, fd, IPPROTO_TCP, TCP_KEEPCNT, &optval, sizeof(optval));
}
static void netty_epoll_linuxsocket_setTcpUserTimeout(JNIEnv* env, jclass clazz, jint fd, jint optval) {
netty_unix_socket_setOption(env, fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &optval, sizeof(optval));
}
static void netty_epoll_linuxsocket_setIpFreeBind(JNIEnv* env, jclass clazz, jint fd, jint optval) {
netty_unix_socket_setOption(env, fd, IPPROTO_IP, IP_FREEBIND, &optval, sizeof(optval));
}
static void netty_epoll_linuxsocket_setIpTransparent(JNIEnv* env, jclass clazz, jint fd, jint optval) {
netty_unix_socket_setOption(env, fd, SOL_IP, IP_TRANSPARENT, &optval, sizeof(optval));
}
static void netty_epoll_linuxsocket_setIpRecvOrigDestAddr(JNIEnv* env, jclass clazz, jint fd, jint optval) {
netty_unix_socket_setOption(env, fd, IPPROTO_IP, IP_RECVORIGDSTADDR, &optval, sizeof(optval));
}
static void netty_epoll_linuxsocket_setSoBusyPoll(JNIEnv* env, jclass clazz, jint fd, jint optval) {
netty_unix_socket_setOption(env, fd, SOL_SOCKET, SO_BUSY_POLL, &optval, sizeof(optval));
}
static void netty_epoll_linuxsocket_joinGroup(JNIEnv* env, jclass clazz, jint fd, jboolean ipv6, jbyteArray groupAddress, jbyteArray interfaceAddress, jint scopeId, jint interfaceIndex) {
struct sockaddr_storage groupAddr;
socklen_t groupAddrSize;
struct sockaddr_storage interfaceAddr;
socklen_t interfaceAddrSize;
struct sockaddr_in* groupIpAddr;
struct sockaddr_in* interfaceIpAddr;
struct ip_mreq mreq;
struct sockaddr_in6* groupIp6Addr;
struct ipv6_mreq mreq6;
memset(&groupAddr, 0, sizeof(groupAddr));
memset(&interfaceAddr, 0, sizeof(interfaceAddr));
if (netty_unix_socket_initSockaddr(env, ipv6, groupAddress, scopeId, 0, &groupAddr, &groupAddrSize) == -1) {
netty_unix_errors_throwIOException(env, "Could not init sockaddr for groupAddress");
return;
}
switch (groupAddr.ss_family) {
case AF_INET:
if (netty_unix_socket_initSockaddr(env, ipv6, interfaceAddress, scopeId, 0, &interfaceAddr, &interfaceAddrSize) == -1) {
netty_unix_errors_throwIOException(env, "Could not init sockaddr for interfaceAddr");
return;
}
interfaceIpAddr = (struct sockaddr_in*) &interfaceAddr;
groupIpAddr = (struct sockaddr_in*) &groupAddr;
memcpy(&mreq.imr_multiaddr, &groupIpAddr->sin_addr, sizeof(groupIpAddr->sin_addr));
memcpy(&mreq.imr_interface, &interfaceIpAddr->sin_addr, sizeof(interfaceIpAddr->sin_addr));
netty_unix_socket_setOption(env, fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
break;
case AF_INET6:
if (interfaceIndex == -1) {
netty_unix_errors_throwIOException(env, "Unable to find network index");
return;
}
mreq6.ipv6mr_interface = interfaceIndex;
groupIp6Addr = (struct sockaddr_in6*) &groupAddr;
memcpy(&mreq6.ipv6mr_multiaddr, &groupIp6Addr->sin6_addr, sizeof(groupIp6Addr->sin6_addr));
netty_unix_socket_setOption(env, fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, sizeof(mreq6));
break;
default:
netty_unix_errors_throwIOException(env, "Address family not supported");
break;
}
}
static void netty_epoll_linuxsocket_joinSsmGroup(JNIEnv* env, jclass clazz, jint fd, jboolean ipv6, jbyteArray groupAddress, jbyteArray interfaceAddress, jint scopeId, jint interfaceIndex, jbyteArray sourceAddress) {
struct sockaddr_storage groupAddr;
socklen_t groupAddrSize;
struct sockaddr_storage interfaceAddr;
socklen_t interfaceAddrSize;
struct sockaddr_storage sourceAddr;
socklen_t sourceAddrSize;
struct sockaddr_in* groupIpAddr;
struct sockaddr_in* interfaceIpAddr;
struct sockaddr_in* sourceIpAddr;
struct ip_mreq_source mreq;
struct group_source_req mreq6;
memset(&groupAddr, 0, sizeof(groupAddr));
memset(&sourceAddr, 0, sizeof(sourceAddr));
memset(&interfaceAddr, 0, sizeof(interfaceAddr));
if (netty_unix_socket_initSockaddr(env, ipv6, groupAddress, scopeId, 0, &groupAddr, &groupAddrSize) == -1) {
netty_unix_errors_throwIOException(env, "Could not init sockaddr for groupAddress");
return;
}
if (netty_unix_socket_initSockaddr(env, ipv6, sourceAddress, scopeId, 0, &sourceAddr, &sourceAddrSize) == -1) {
netty_unix_errors_throwIOException(env, "Could not init sockaddr for sourceAddress");
return;
}
switch (groupAddr.ss_family) {
case AF_INET:
if (netty_unix_socket_initSockaddr(env, ipv6, interfaceAddress, scopeId, 0, &interfaceAddr, &interfaceAddrSize) == -1) {
netty_unix_errors_throwIOException(env, "Could not init sockaddr for interfaceAddress");
return;
}
interfaceIpAddr = (struct sockaddr_in*) &interfaceAddr;
groupIpAddr = (struct sockaddr_in*) &groupAddr;
sourceIpAddr = (struct sockaddr_in*) &sourceAddr;
memcpy(&mreq.imr_multiaddr, &groupIpAddr->sin_addr, sizeof(groupIpAddr->sin_addr));
memcpy(&mreq.imr_interface, &interfaceIpAddr->sin_addr, sizeof(interfaceIpAddr->sin_addr));
memcpy(&mreq.imr_sourceaddr, &sourceIpAddr->sin_addr, sizeof(sourceIpAddr->sin_addr));
netty_unix_socket_setOption(env, fd, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, &mreq, sizeof(mreq));
break;
case AF_INET6:
if (interfaceIndex == -1) {
netty_unix_errors_throwIOException(env, "Unable to find network index");
return;
}
mreq6.gsr_group = groupAddr;
mreq6.gsr_interface = interfaceIndex;
mreq6.gsr_source = sourceAddr;
netty_unix_socket_setOption(env, fd, IPPROTO_IPV6, MCAST_JOIN_SOURCE_GROUP, &mreq6, sizeof(mreq6));
break;
default:
netty_unix_errors_throwIOException(env, "Address family not supported");
break;
}
}
static void netty_epoll_linuxsocket_leaveGroup(JNIEnv* env, jclass clazz, jint fd, jboolean ipv6, jbyteArray groupAddress, jbyteArray interfaceAddress, jint scopeId, jint interfaceIndex) {
struct sockaddr_storage groupAddr;
socklen_t groupAddrSize;
struct sockaddr_storage interfaceAddr;
socklen_t interfaceAddrSize;
struct sockaddr_in* groupIpAddr;
struct sockaddr_in* interfaceIpAddr;
struct ip_mreq mreq;
struct sockaddr_in6* groupIp6Addr;
struct ipv6_mreq mreq6;
memset(&groupAddr, 0, sizeof(groupAddr));
memset(&interfaceAddr, 0, sizeof(interfaceAddr));
if (netty_unix_socket_initSockaddr(env, ipv6, groupAddress, scopeId, 0, &groupAddr, &groupAddrSize) == -1) {
netty_unix_errors_throwIOException(env, "Could not init sockaddr for groupAddress");
return;
}
switch (groupAddr.ss_family) {
case AF_INET:
if (netty_unix_socket_initSockaddr(env, ipv6, interfaceAddress, scopeId, 0, &interfaceAddr, &interfaceAddrSize) == -1) {
netty_unix_errors_throwIOException(env, "Could not init sockaddr for interfaceAddress");
return;
}
interfaceIpAddr = (struct sockaddr_in*) &interfaceAddr;
groupIpAddr = (struct sockaddr_in*) &groupAddr;
memcpy(&mreq.imr_multiaddr, &groupIpAddr->sin_addr, sizeof(groupIpAddr->sin_addr));
memcpy(&mreq.imr_interface, &interfaceIpAddr->sin_addr, sizeof(interfaceIpAddr->sin_addr));
netty_unix_socket_setOption(env, fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
break;
case AF_INET6:
if (interfaceIndex == -1) {
netty_unix_errors_throwIOException(env, "Unable to find network index");
return;
}
mreq6.ipv6mr_interface = interfaceIndex;
groupIp6Addr = (struct sockaddr_in6*) &groupAddr;
memcpy(&mreq6.ipv6mr_multiaddr, &groupIp6Addr->sin6_addr, sizeof(groupIp6Addr->sin6_addr));
netty_unix_socket_setOption(env, fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq6, sizeof(mreq6));
break;
default:
netty_unix_errors_throwIOException(env, "Address family not supported");
break;
}
}
static void netty_epoll_linuxsocket_leaveSsmGroup(JNIEnv* env, jclass clazz, jint fd, jboolean ipv6, jbyteArray groupAddress, jbyteArray interfaceAddress, jint scopeId, jint interfaceIndex, jbyteArray sourceAddress) {
struct sockaddr_storage groupAddr;
socklen_t groupAddrSize;
struct sockaddr_storage interfaceAddr;
socklen_t interfaceAddrSize;
struct sockaddr_storage sourceAddr;
socklen_t sourceAddrSize;
struct sockaddr_in* groupIpAddr;
struct sockaddr_in* interfaceIpAddr;
struct sockaddr_in* sourceIpAddr;
struct ip_mreq_source mreq;
struct group_source_req mreq6;
memset(&groupAddr, 0, sizeof(groupAddr));
memset(&sourceAddr, 0, sizeof(sourceAddr));
memset(&interfaceAddr, 0, sizeof(interfaceAddr));
if (netty_unix_socket_initSockaddr(env, ipv6, groupAddress, scopeId, 0, &groupAddr, &groupAddrSize) == -1) {
netty_unix_errors_throwIOException(env, "Could not init sockaddr for groupAddress");
return;
}
if (netty_unix_socket_initSockaddr(env, ipv6, sourceAddress, scopeId, 0, &sourceAddr, &sourceAddrSize) == -1) {
netty_unix_errors_throwIOException(env, "Could not init sockaddr for sourceAddress");
return;
}
switch (groupAddr.ss_family) {
case AF_INET:
if (netty_unix_socket_initSockaddr(env, ipv6, interfaceAddress, scopeId, 0, &interfaceAddr, &interfaceAddrSize) == -1) {
netty_unix_errors_throwIOException(env, "Could not init sockaddr for interfaceAddress");
return;
}
interfaceIpAddr = (struct sockaddr_in*) &interfaceAddr;
groupIpAddr = (struct sockaddr_in*) &groupAddr;
sourceIpAddr = (struct sockaddr_in*) &sourceAddr;
memcpy(&mreq.imr_multiaddr, &groupIpAddr->sin_addr, sizeof(groupIpAddr->sin_addr));
memcpy(&mreq.imr_interface, &interfaceIpAddr->sin_addr, sizeof(interfaceIpAddr->sin_addr));
memcpy(&mreq.imr_sourceaddr, &sourceIpAddr->sin_addr, sizeof(sourceIpAddr->sin_addr));
netty_unix_socket_setOption(env, fd, IPPROTO_IP, IP_DROP_SOURCE_MEMBERSHIP, &mreq, sizeof(mreq));
break;
case AF_INET6:
if (interfaceIndex == -1) {
netty_unix_errors_throwIOException(env, "Unable to find network index");
return;
}
mreq6.gsr_group = groupAddr;
mreq6.gsr_interface = interfaceIndex;
mreq6.gsr_source = sourceAddr;
netty_unix_socket_setOption(env, fd, IPPROTO_IPV6, MCAST_LEAVE_SOURCE_GROUP, &mreq6, sizeof(mreq6));
break;
default:
netty_unix_errors_throwIOException(env, "Address family not supported");
break;
}
}
static void netty_epoll_linuxsocket_setTcpMd5Sig(JNIEnv* env, jclass clazz, jint fd, jboolean ipv6, jbyteArray address, jint scopeId, jbyteArray key) {
struct sockaddr_storage addr;
socklen_t addrSize;
memset(&addr, 0, sizeof(addr));
if (netty_unix_socket_initSockaddr(env, ipv6, address, scopeId, 0, &addr, &addrSize) == -1) {
netty_unix_errors_throwIOException(env, "Could not init sockaddr");
return;
}
struct tcp_md5sig md5sig;
memset(&md5sig, 0, sizeof(md5sig));
md5sig.tcpm_addr.ss_family = addr.ss_family;
struct sockaddr_in* ipaddr;
struct sockaddr_in6* ip6addr;
switch (addr.ss_family) {
case AF_INET:
ipaddr = (struct sockaddr_in*) &addr;
memcpy(&((struct sockaddr_in *) &md5sig.tcpm_addr)->sin_addr, &ipaddr->sin_addr, sizeof(ipaddr->sin_addr));
break;
case AF_INET6:
ip6addr = (struct sockaddr_in6*) &addr;
memcpy(&((struct sockaddr_in6 *) &md5sig.tcpm_addr)->sin6_addr, &ip6addr->sin6_addr, sizeof(ip6addr->sin6_addr));
break;
}
if (key != NULL) {
md5sig.tcpm_keylen = (*env)->GetArrayLength(env, key);
(*env)->GetByteArrayRegion(env, key, 0, md5sig.tcpm_keylen, (void *) &md5sig.tcpm_key);
if ((*env)->ExceptionCheck(env) == JNI_TRUE) {
return;
}
}
if (setsockopt(fd, IPPROTO_TCP, TCP_MD5SIG, &md5sig, sizeof(md5sig)) < 0) {
netty_unix_errors_throwIOExceptionErrorNo(env, "setsockopt() failed: ", errno);
}
}
static int netty_epoll_linuxsocket_getInterface(JNIEnv* env, jclass clazz, jint fd, jboolean ipv6) {
if (ipv6 == JNI_TRUE) {
int optval;
if (netty_unix_socket_getOption(env, fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &optval, sizeof(optval)) == -1) {
return -1;
}
return optval;
} else {
struct in_addr optval;
if (netty_unix_socket_getOption(env, fd, IPPROTO_IP, IP_MULTICAST_IF, &optval, sizeof(optval)) == -1) {
return -1;
}
return ntohl(optval.s_addr);
}
}
static jint netty_epoll_linuxsocket_getTimeToLive(JNIEnv* env, jclass clazz, jint fd) {
int optval;
if (netty_unix_socket_getOption(env, fd, IPPROTO_IP, IP_TTL, &optval, sizeof(optval)) == -1) {
return -1;
}
return optval;
}
static jint netty_epoll_linuxsocket_getIpMulticastLoop(JNIEnv* env, jclass clazz, jint fd, jboolean ipv6) {
if (ipv6 == JNI_TRUE) {
u_int optval;
if (netty_unix_socket_getOption(env, fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &optval, sizeof(optval)) == -1) {
return -1;
}
return (jint) optval;
} else {
u_char optval;
if (netty_unix_socket_getOption(env, fd, IPPROTO_IP, IP_MULTICAST_LOOP, &optval, sizeof(optval)) == -1) {
return -1;
}
return (jint) optval;
}
}
static jint netty_epoll_linuxsocket_getTcpKeepIdle(JNIEnv* env, jclass clazz, jint fd) {
int optval;
if (netty_unix_socket_getOption(env, fd, IPPROTO_TCP, TCP_KEEPIDLE, &optval, sizeof(optval)) == -1) {
return -1;
}
return optval;
}
static jint netty_epoll_linuxsocket_getTcpKeepIntvl(JNIEnv* env, jclass clazz, jint fd) {
int optval;
if (netty_unix_socket_getOption(env, fd, IPPROTO_TCP, TCP_KEEPINTVL, &optval, sizeof(optval)) == -1) {
return -1;
}
return optval;
}
static jint netty_epoll_linuxsocket_getTcpKeepCnt(JNIEnv* env, jclass clazz, jint fd) {
int optval;
if (netty_unix_socket_getOption(env, fd, IPPROTO_TCP, TCP_KEEPCNT, &optval, sizeof(optval)) == -1) {
return -1;
}
return optval;
}
static jint netty_epoll_linuxsocket_getTcpUserTimeout(JNIEnv* env, jclass clazz, jint fd) {
int optval;
if (netty_unix_socket_getOption(env, fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &optval, sizeof(optval)) == -1) {
return -1;
}
return optval;
}
static jint netty_epoll_linuxsocket_isIpFreeBind(JNIEnv* env, jclass clazz, jint fd) {
int optval;
if (netty_unix_socket_getOption(env, fd, IPPROTO_IP, IP_FREEBIND, &optval, sizeof(optval)) == -1) {
return -1;
}
return optval;
}
static jint netty_epoll_linuxsocket_isIpTransparent(JNIEnv* env, jclass clazz, jint fd) {
int optval;
if (netty_unix_socket_getOption(env, fd, SOL_IP, IP_TRANSPARENT, &optval, sizeof(optval)) == -1) {
return -1;
}
return optval;
}
static jint netty_epoll_linuxsocket_isIpRecvOrigDestAddr(JNIEnv* env, jclass clazz, jint fd) {
int optval;
if (netty_unix_socket_getOption(env, fd, IPPROTO_IP, IP_RECVORIGDSTADDR, &optval, sizeof(optval)) == -1) {
return -1;
}
return optval;
}
static void netty_epoll_linuxsocket_getTcpInfo(JNIEnv* env, jclass clazz, jint fd, jlongArray array) {
struct tcp_info tcp_info;
if (netty_unix_socket_getOption(env, fd, IPPROTO_TCP, TCP_INFO, &tcp_info, sizeof(tcp_info)) == -1) {
return;
}
jlong cArray[32];
// Expand to 64 bits, then cast away unsigned-ness.
cArray[0] = (jlong) (uint64_t) tcp_info.tcpi_state;
cArray[1] = (jlong) (uint64_t) tcp_info.tcpi_ca_state;
cArray[2] = (jlong) (uint64_t) tcp_info.tcpi_retransmits;
cArray[3] = (jlong) (uint64_t) tcp_info.tcpi_probes;
cArray[4] = (jlong) (uint64_t) tcp_info.tcpi_backoff;
cArray[5] = (jlong) (uint64_t) tcp_info.tcpi_options;
cArray[6] = (jlong) (uint64_t) tcp_info.tcpi_snd_wscale;
cArray[7] = (jlong) (uint64_t) tcp_info.tcpi_rcv_wscale;
cArray[8] = (jlong) (uint64_t) tcp_info.tcpi_rto;
cArray[9] = (jlong) (uint64_t) tcp_info.tcpi_ato;
cArray[10] = (jlong) (uint64_t) tcp_info.tcpi_snd_mss;
cArray[11] = (jlong) (uint64_t) tcp_info.tcpi_rcv_mss;
cArray[12] = (jlong) (uint64_t) tcp_info.tcpi_unacked;
cArray[13] = (jlong) (uint64_t) tcp_info.tcpi_sacked;
cArray[14] = (jlong) (uint64_t) tcp_info.tcpi_lost;
cArray[15] = (jlong) (uint64_t) tcp_info.tcpi_retrans;
cArray[16] = (jlong) (uint64_t) tcp_info.tcpi_fackets;
cArray[17] = (jlong) (uint64_t) tcp_info.tcpi_last_data_sent;
cArray[18] = (jlong) (uint64_t) tcp_info.tcpi_last_ack_sent;
cArray[19] = (jlong) (uint64_t) tcp_info.tcpi_last_data_recv;
cArray[20] = (jlong) (uint64_t) tcp_info.tcpi_last_ack_recv;
cArray[21] = (jlong) (uint64_t) tcp_info.tcpi_pmtu;
cArray[22] = (jlong) (uint64_t) tcp_info.tcpi_rcv_ssthresh;
cArray[23] = (jlong) (uint64_t) tcp_info.tcpi_rtt;
cArray[24] = (jlong) (uint64_t) tcp_info.tcpi_rttvar;
cArray[25] = (jlong) (uint64_t) tcp_info.tcpi_snd_ssthresh;
cArray[26] = (jlong) (uint64_t) tcp_info.tcpi_snd_cwnd;
cArray[27] = (jlong) (uint64_t) tcp_info.tcpi_advmss;
cArray[28] = (jlong) (uint64_t) tcp_info.tcpi_reordering;
cArray[29] = (jlong) (uint64_t) tcp_info.tcpi_rcv_rtt;
cArray[30] = (jlong) (uint64_t) tcp_info.tcpi_rcv_space;
cArray[31] = (jlong) (uint64_t) tcp_info.tcpi_total_retrans;
(*env)->SetLongArrayRegion(env, array, 0, 32, cArray);
}
static jint netty_epoll_linuxsocket_isTcpCork(JNIEnv* env, jclass clazz, jint fd) {
int optval;
if (netty_unix_socket_getOption(env, fd, IPPROTO_TCP, TCP_CORK, &optval, sizeof(optval)) == -1) {
return -1;
}
return optval;
}
static jint netty_epoll_linuxsocket_getSoBusyPoll(JNIEnv* env, jclass clazz, jint fd) {
int optval;
if (netty_unix_socket_getOption(env, fd, SOL_SOCKET, SO_BUSY_POLL, &optval, sizeof(optval)) == -1) {
return -1;
}
return optval;
}
static jint netty_epoll_linuxsocket_getTcpDeferAccept(JNIEnv* env, jclass clazz, jint fd) {
int optval;
if (netty_unix_socket_getOption(env, fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &optval, sizeof(optval)) == -1) {
return -1;
}
return optval;
}
static jint netty_epoll_linuxsocket_isTcpQuickAck(JNIEnv* env, jclass clazz, jint fd) {
int optval;
if (netty_unix_socket_getOption(env, fd, IPPROTO_TCP, TCP_QUICKACK, &optval, sizeof(optval)) == -1) {
return -1;
}
return optval;
}
static jint netty_epoll_linuxsocket_getTcpNotSentLowAt(JNIEnv* env, jclass clazz, jint fd) {
int optval;
if (netty_unix_socket_getOption(env, fd, IPPROTO_TCP, TCP_NOTSENT_LOWAT, &optval, sizeof(optval)) == -1) {
return -1;
}
return optval;
}
static jobject netty_epoll_linuxsocket_getPeerCredentials(JNIEnv *env, jclass clazz, jint fd) {
struct ucred credentials;
jclass peerCredentialsClass = NULL;
if(netty_unix_socket_getOption(env,fd, SOL_SOCKET, SO_PEERCRED, &credentials, sizeof (credentials)) == -1) {
return NULL;
}
jintArray gids = (*env)->NewIntArray(env, 1);
(*env)->SetIntArrayRegion(env, gids, 0, 1, (jint*) &credentials.gid);
NETTY_JNI_UTIL_NEW_LOCAL_FROM_WEAK(env, peerCredentialsClass, peerCredentialsClassWeak, error);
jobject creds = (*env)->NewObject(env, peerCredentialsClass, peerCredentialsMethodId, credentials.pid, credentials.uid, gids);
NETTY_JNI_UTIL_DELETE_LOCAL(env, peerCredentialsClass);
return creds;
error:
return NULL;
}
static jint netty_epoll_linuxsocket_isUdpGro(JNIEnv* env, jclass clazz, jint fd) {
int optval;
if (netty_unix_socket_getOption(env, fd, SOL_UDP, UDP_GRO, &optval, sizeof(optval)) == -1) {
return -1;
}
return optval;
}
static void netty_epoll_linuxsocket_setUdpGro(JNIEnv* env, jclass clazz, jint fd, jint optval) {
netty_unix_socket_setOption(env, fd, SOL_UDP, UDP_GRO, &optval, sizeof(optval));
}
static jlong netty_epoll_linuxsocket_sendFile(JNIEnv* env, jclass clazz, jint fd, jobject fileRegion, jlong base_off, jlong off, jlong len) {
jobject fileChannel = (*env)->GetObjectField(env, fileRegion, fileChannelFieldId);
if (fileChannel == NULL) {
netty_unix_errors_throwRuntimeException(env, "failed to get DefaultFileRegion.file");
return -1;
}
jobject fileDescriptor = (*env)->GetObjectField(env, fileChannel, fileDescriptorFieldId);
if (fileDescriptor == NULL) {
netty_unix_errors_throwRuntimeException(env, "failed to get FileChannelImpl.fd");
return -1;
}
jint srcFd = (*env)->GetIntField(env, fileDescriptor, fdFieldId);
if (srcFd == -1) {
netty_unix_errors_throwRuntimeException(env, "failed to get FileDescriptor.fd");
return -1;
}
ssize_t res;
off_t offset = base_off + off;
int err;
do {
res = sendfile(fd, srcFd, &offset, (size_t) len);
} while (res == -1 && ((err = errno) == EINTR));
if (res < 0) {
return -err;
}
if (res > 0) {
// update the transferred field in DefaultFileRegion
(*env)->SetLongField(env, fileRegion, transferredFieldId, off + res);
}
return res;
}
// JNI Registered Methods End
// JNI Method Registration Table Begin
static const JNINativeMethod fixed_method_table[] = {
{ "newVSockStreamFd", "()I", (void *) netty_epoll_linuxsocket_newVSockStreamFd },
{ "bindVSock", "(III)I", (void *) netty_epoll_linuxsocket_bindVSock },
{ "connectVSock", "(III)I", (void *) netty_epoll_linuxsocket_connectVSock },
{ "remoteVSockAddress", "(I)[B", (void *) netty_epoll_linuxsocket_remoteVSockAddress },
{ "localVSockAddress", "(I)[B", (void *) netty_epoll_linuxsocket_localVSockAddress },
{ "setTimeToLive", "(II)V", (void *) netty_epoll_linuxsocket_setTimeToLive },
{ "getTimeToLive", "(I)I", (void *) netty_epoll_linuxsocket_getTimeToLive },
{ "setInterface", "(IZ[BII)V", (void *) netty_epoll_linuxsocket_setInterface },
{ "getInterface", "(IZ)I", (void *) netty_epoll_linuxsocket_getInterface },
{ "setIpMulticastLoop", "(IZI)V", (void * ) netty_epoll_linuxsocket_setIpMulticastLoop },
{ "getIpMulticastLoop", "(IZ)I", (void * ) netty_epoll_linuxsocket_getIpMulticastLoop },
{ "setTcpCork", "(II)V", (void *) netty_epoll_linuxsocket_setTcpCork },
{ "setSoBusyPoll", "(II)V", (void *) netty_epoll_linuxsocket_setSoBusyPoll },
{ "setTcpQuickAck", "(II)V", (void *) netty_epoll_linuxsocket_setTcpQuickAck },
{ "setTcpDeferAccept", "(II)V", (void *) netty_epoll_linuxsocket_setTcpDeferAccept },
{ "setTcpNotSentLowAt", "(II)V", (void *) netty_epoll_linuxsocket_setTcpNotSentLowAt },
{ "isTcpCork", "(I)I", (void *) netty_epoll_linuxsocket_isTcpCork },
{ "getSoBusyPoll", "(I)I", (void *) netty_epoll_linuxsocket_getSoBusyPoll },
{ "getTcpDeferAccept", "(I)I", (void *) netty_epoll_linuxsocket_getTcpDeferAccept },
{ "getTcpNotSentLowAt", "(I)I", (void *) netty_epoll_linuxsocket_getTcpNotSentLowAt },
{ "isTcpQuickAck", "(I)I", (void *) netty_epoll_linuxsocket_isTcpQuickAck },
{ "setTcpFastOpen", "(II)V", (void *) netty_epoll_linuxsocket_setTcpFastOpen },
{ "setTcpKeepIdle", "(II)V", (void *) netty_epoll_linuxsocket_setTcpKeepIdle },
{ "setTcpKeepIntvl", "(II)V", (void *) netty_epoll_linuxsocket_setTcpKeepIntvl },
{ "setTcpKeepCnt", "(II)V", (void *) netty_epoll_linuxsocket_setTcpKeepCnt },
{ "setTcpUserTimeout", "(II)V", (void *) netty_epoll_linuxsocket_setTcpUserTimeout },
{ "setIpFreeBind", "(II)V", (void *) netty_epoll_linuxsocket_setIpFreeBind },
{ "setIpTransparent", "(II)V", (void *) netty_epoll_linuxsocket_setIpTransparent },
{ "setIpRecvOrigDestAddr", "(II)V", (void *) netty_epoll_linuxsocket_setIpRecvOrigDestAddr },
{ "getTcpKeepIdle", "(I)I", (void *) netty_epoll_linuxsocket_getTcpKeepIdle },
{ "getTcpKeepIntvl", "(I)I", (void *) netty_epoll_linuxsocket_getTcpKeepIntvl },
{ "getTcpKeepCnt", "(I)I", (void *) netty_epoll_linuxsocket_getTcpKeepCnt },
{ "getTcpUserTimeout", "(I)I", (void *) netty_epoll_linuxsocket_getTcpUserTimeout },
{ "isIpFreeBind", "(I)I", (void *) netty_epoll_linuxsocket_isIpFreeBind },
{ "isIpTransparent", "(I)I", (void *) netty_epoll_linuxsocket_isIpTransparent },
{ "isIpRecvOrigDestAddr", "(I)I", (void *) netty_epoll_linuxsocket_isIpRecvOrigDestAddr },
{ "getTcpInfo", "(I[J)V", (void *) netty_epoll_linuxsocket_getTcpInfo },
{ "setTcpMd5Sig", "(IZ[BI[B)V", (void *) netty_epoll_linuxsocket_setTcpMd5Sig },
{ "joinGroup", "(IZ[B[BII)V", (void *) netty_epoll_linuxsocket_joinGroup },
{ "joinSsmGroup", "(IZ[B[BII[B)V", (void *) netty_epoll_linuxsocket_joinSsmGroup },
{ "leaveGroup", "(IZ[B[BII)V", (void *) netty_epoll_linuxsocket_leaveGroup },
{ "leaveSsmGroup", "(IZ[B[BII[B)V", (void *) netty_epoll_linuxsocket_leaveSsmGroup },
{ "isUdpGro", "(I)I", (void *) netty_epoll_linuxsocket_isUdpGro },
{ "setUdpGro", "(II)V", (void *) netty_epoll_linuxsocket_setUdpGro }
// "sendFile" has a dynamic signature
};
static const jint fixed_method_table_size = sizeof(fixed_method_table) / sizeof(fixed_method_table[0]);
static jint dynamicMethodsTableSize() {
return fixed_method_table_size + 2; // 2 is for the dynamic method signatures.
}
static JNINativeMethod* createDynamicMethodsTable(const char* packagePrefix) {
char* dynamicTypeName = NULL;
size_t size = sizeof(JNINativeMethod) * dynamicMethodsTableSize();
JNINativeMethod* dynamicMethods = malloc(size);
if (dynamicMethods == NULL) {
return NULL;
}
memset(dynamicMethods, 0, size);
memcpy(dynamicMethods, fixed_method_table, sizeof(fixed_method_table));
JNINativeMethod* dynamicMethod = &dynamicMethods[fixed_method_table_size];
NETTY_JNI_UTIL_PREPEND(packagePrefix, "io/netty/channel/unix/PeerCredentials;", dynamicTypeName, error);
NETTY_JNI_UTIL_PREPEND("(I)L", dynamicTypeName, dynamicMethod->signature, error);
dynamicMethod->name = "getPeerCredentials";
dynamicMethod->fnPtr = (void *) netty_epoll_linuxsocket_getPeerCredentials;
netty_jni_util_free_dynamic_name(&dynamicTypeName);
++dynamicMethod;
NETTY_JNI_UTIL_PREPEND(packagePrefix, "io/netty/channel/DefaultFileRegion;JJJ)J", dynamicTypeName, error);
NETTY_JNI_UTIL_PREPEND("(IL", dynamicTypeName, dynamicMethod->signature, error);
dynamicMethod->name = "sendFile";
dynamicMethod->fnPtr = (void *) netty_epoll_linuxsocket_sendFile;
netty_jni_util_free_dynamic_name(&dynamicTypeName);
return dynamicMethods;
error:
free(dynamicTypeName);
netty_jni_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize());
return NULL;
}
// JNI Method Registration Table End
// IMPORTANT: If you add any NETTY_JNI_UTIL_LOAD_CLASS or NETTY_JNI_UTIL_FIND_CLASS calls you also need to update
// Native to reflect that.
jint netty_epoll_linuxsocket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
int ret = JNI_ERR;
char* nettyClassName = NULL;
jclass fileRegionCls = NULL;
jclass fileChannelCls = NULL;
jclass fileDescriptorCls = NULL;
jclass peerCredentialsClass = NULL;
// Register the methods which are not referenced by static member variables
JNINativeMethod* dynamicMethods = createDynamicMethodsTable(packagePrefix);
if (dynamicMethods == NULL) {
goto done;
}
if (netty_jni_util_register_natives(env,
packagePrefix,
LINUXSOCKET_CLASSNAME,
dynamicMethods,
dynamicMethodsTableSize()) != 0) {
goto done;
}
NETTY_JNI_UTIL_PREPEND(packagePrefix, "io/netty/channel/unix/PeerCredentials", nettyClassName, done);
NETTY_JNI_UTIL_LOAD_CLASS_WEAK(env, peerCredentialsClassWeak, nettyClassName, done);
NETTY_JNI_UTIL_NEW_LOCAL_FROM_WEAK(env, peerCredentialsClass, peerCredentialsClassWeak, done);
netty_jni_util_free_dynamic_name(&nettyClassName);
NETTY_JNI_UTIL_GET_METHOD(env, peerCredentialsClass, peerCredentialsMethodId, "<init>", "(II[I)V", done);
NETTY_JNI_UTIL_PREPEND(packagePrefix, "io/netty/channel/DefaultFileRegion", nettyClassName, done);
NETTY_JNI_UTIL_FIND_CLASS(env, fileRegionCls, nettyClassName, done);
netty_jni_util_free_dynamic_name(&nettyClassName);
NETTY_JNI_UTIL_GET_FIELD(env, fileRegionCls, fileChannelFieldId, "file", "Ljava/nio/channels/FileChannel;", done);
NETTY_JNI_UTIL_GET_FIELD(env, fileRegionCls, transferredFieldId, "transferred", "J", done);
NETTY_JNI_UTIL_FIND_CLASS(env, fileChannelCls, "sun/nio/ch/FileChannelImpl", done);
NETTY_JNI_UTIL_GET_FIELD(env, fileChannelCls, fileDescriptorFieldId, "fd", "Ljava/io/FileDescriptor;", done);
NETTY_JNI_UTIL_FIND_CLASS(env, fileDescriptorCls, "java/io/FileDescriptor", done);
NETTY_JNI_UTIL_TRY_GET_FIELD(env, fileDescriptorCls, fdFieldId, "fd", "I");
if (fdFieldId == NULL) {
// Android uses a different field name, let's try it.
NETTY_JNI_UTIL_GET_FIELD(env, fileDescriptorCls, fdFieldId, "descriptor", "I", done);
}
ret = NETTY_JNI_UTIL_JNI_VERSION;
done:
netty_jni_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize());
free(nettyClassName);
NETTY_JNI_UTIL_DELETE_LOCAL(env, peerCredentialsClass);
return ret;
}
void netty_epoll_linuxsocket_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix) {
NETTY_JNI_UTIL_UNLOAD_CLASS_WEAK(env, peerCredentialsClassWeak);
netty_jni_util_unregister_natives(env, packagePrefix, LINUXSOCKET_CLASSNAME);
}

View file

@ -0,0 +1,26 @@
/*
* Copyright 2016 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_EPOLL_LINUXSOCKET_H_
#define NETTY_EPOLL_LINUXSOCKET_H_
#include <jni.h>
// JNI initialization hooks. Users of this file are responsible for calling these in the JNI_OnLoad and JNI_OnUnload methods.
jint netty_epoll_linuxsocket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix);
void netty_epoll_linuxsocket_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix);
#endif

View file

@ -0,0 +1,919 @@
/*
* Copyright 2013 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.
*/
#define _GNU_SOURCE
#include <jni.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/timerfd.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/utsname.h>
#include <stddef.h>
#include <limits.h>
#include <inttypes.h>
#include <link.h>
#include <time.h>
// Needed to be able to use syscalls directly and so not depend on newer GLIBC versions
#include <linux/net.h>
#include <sys/syscall.h>
// Needed for UDP_SEGMENT
#include <netinet/udp.h>
#include "netty_epoll_linuxsocket.h"
#include "netty_unix_buffer.h"
#include "netty_unix_errors.h"
#include "netty_unix_filedescriptor.h"
#include "netty_unix_jni.h"
#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
#define NETTY_JNI_UTIL_BUILD_STATIC
#endif
#define STATICALLY_CLASSNAME "io/netty/channel/epoll/NativeStaticallyReferencedJniMethods"
#define NATIVE_CLASSNAME "io/netty/channel/epoll/Native"
// TCP_FASTOPEN is defined in linux 3.7. We define this here so older kernels can compile.
#ifndef TCP_FASTOPEN
#define TCP_FASTOPEN 23
#endif
// Allow to compile on systems with older kernels.
#ifndef UDP_SEGMENT
#define UDP_SEGMENT 103
#endif
// UDP_GRO is defined in linux 5. We define this here so older kernels can compile.
#ifndef UDP_GRO
#define UDP_GRO 104
#endif
#ifdef IP_RECVORIGDSTADDR
#if !defined(SOL_IP) && defined(IPPROTO_IP)
#define SOL_IP IPPROTO_IP
#endif /* !SOL_IP && IPPROTO_IP */
#endif // IP_RECVORIGDSTADDR
// optional
extern int epoll_create1(int flags) __attribute__((weak));
extern int epoll_pwait2(int epfd, struct epoll_event *events, int maxevents, const struct timespec *timeout, const sigset_t *sigmask) __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
// Only support SYS_recvmmsg for __x86_64__ / __i386__ for now
#if defined(__x86_64__)
// See https://github.com/torvalds/linux/blob/v5.4/arch/x86/entry/syscalls/syscall_64.tbl
#define SYS_recvmmsg 299
#elif defined(__i386__)
// See https://github.com/torvalds/linux/blob/v5.4/arch/x86/entry/syscalls/syscall_32.tbl
#define SYS_recvmmsg 337
#elif defined(__loongarch64)
// See https://github.com/torvalds/linux/blob/v6.1/include/uapi/asm-generic/unistd.h
#define SYS_recvmmsg 243
#else
#define SYS_recvmmsg -1
#endif
#endif // SYS_recvmmsg
#ifndef SYS_sendmmsg
// Only support SYS_sendmmsg for __x86_64__ / __i386__ for now
#if defined(__x86_64__)
// See https://github.com/torvalds/linux/blob/v5.4/arch/x86/entry/syscalls/syscall_64.tbl
#define SYS_sendmmsg 307
#elif defined(__i386__)
// See https://github.com/torvalds/linux/blob/v5.4/arch/x86/entry/syscalls/syscall_32.tbl
#define SYS_sendmmsg 345
#elif defined(__loongarch64)
// See https://github.com/torvalds/linux/blob/v6.1/include/uapi/asm-generic/unistd.h
#define SYS_sendmmsg 269
#else
#define SYS_sendmmsg -1
#endif
#endif // SYS_sendmmsg
// Those are initialized in the init(...) method and cached for performance reasons
static jfieldID packetSenderAddrFieldId = NULL;
static jfieldID packetSenderAddrLenFieldId = NULL;
static jfieldID packetSenderScopeIdFieldId = NULL;
static jfieldID packetSenderPortFieldId = NULL;
static jfieldID packetRecipientAddrFieldId = NULL;
static jfieldID packetRecipientAddrLenFieldId = NULL;
static jfieldID packetRecipientScopeIdFieldId = NULL;
static jfieldID packetRecipientPortFieldId = NULL;
static jfieldID packetSegmentSizeFieldId = NULL;
static jfieldID packetMemoryAddressFieldId = NULL;
static jfieldID packetCountFieldId = NULL;
static const char* staticPackagePrefix = NULL;
static int register_unix_called = 0;
static int epoll_pwait2_supported = 0;
// util methods
static int getSysctlValue(const char * property, int* returnValue) {
int rc = -1;
FILE *fd=fopen(property, "r");
if (fd != NULL) {
char buf[32] = {0x0};
if (fgets(buf, 32, fd) != NULL) {
*returnValue = atoi(buf);
rc = 0;
}
fclose(fd);
}
return rc;
}
static inline jint epollCtl(JNIEnv* env, jint efd, int op, jint fd, jint flags) {
uint32_t events = flags;
struct epoll_event ev = {
.data.fd = fd,
.events = events
};
return epoll_ctl(efd, op, fd, &ev);
}
// JNI Registered Methods Begin
static jint netty_epoll_native_eventFd(JNIEnv* env, jclass clazz) {
jint eventFD = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
if (eventFD < 0) {
netty_unix_errors_throwChannelExceptionErrorNo(env, "eventfd() failed: ", errno);
}
return eventFD;
}
static jint netty_epoll_native_timerFd(JNIEnv* env, jclass clazz) {
jint timerFD = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
if (timerFD < 0) {
netty_unix_errors_throwChannelExceptionErrorNo(env, "timerfd_create() failed: ", errno);
}
return timerFD;
}
static void netty_epoll_native_eventFdWrite(JNIEnv* env, jclass clazz, jint fd, jlong value) {
uint64_t val;
for (;;) {
jint ret = eventfd_write(fd, (eventfd_t) value);
if (ret < 0) {
// We need to read before we can write again, let's try to read and then write again and if this
// fails we will bail out.
//
// See https://man7.org/linux/man-pages/man2/eventfd.2.html.
if (errno == EAGAIN) {
if (eventfd_read(fd, &val) == 0 || errno == EAGAIN) {
// Try again
continue;
}
netty_unix_errors_throwChannelExceptionErrorNo(env, "eventfd_read(...) failed: ", errno);
} else {
netty_unix_errors_throwChannelExceptionErrorNo(env, "eventfd_write(...) failed: ", errno);
}
}
break;
}
}
static void netty_epoll_native_eventFdRead(JNIEnv* env, jclass clazz, jint fd) {
uint64_t eventfd_t;
if (eventfd_read(fd, &eventfd_t) != 0) {
// something is serious wrong
netty_unix_errors_throwRuntimeException(env, "eventfd_read() failed");
}
}
static jint netty_epoll_native_epollCreate(JNIEnv* env, jclass clazz) {
jint efd;
if (epoll_create1) {
efd = epoll_create1(EPOLL_CLOEXEC);
} else {
// size will be ignored anyway but must be positive
efd = epoll_create(126);
}
if (efd < 0) {
int err = errno;
if (epoll_create1) {
netty_unix_errors_throwChannelExceptionErrorNo(env, "epoll_create1() failed: ", err);
} else {
netty_unix_errors_throwChannelExceptionErrorNo(env, "epoll_create() failed: ", err);
}
return efd;
}
if (!epoll_create1) {
if (fcntl(efd, F_SETFD, FD_CLOEXEC) < 0) {
int err = errno;
close(efd);
netty_unix_errors_throwChannelExceptionErrorNo(env, "fcntl() failed: ", err);
return err;
}
}
return efd;
}
static jint netty_epoll_native_epollWait(JNIEnv* env, jclass clazz, jint efd, jlong address, jint len, jint timeout) {
struct epoll_event *ev = (struct epoll_event*) (intptr_t) address;
int result, err;
do {
result = epoll_wait(efd, ev, len, timeout);
if (result >= 0) {
return result;
}
} while((err = errno) == EINTR);
return -err;
}
// This needs to be consistent with Native.java
#define EPOLL_WAIT_RESULT(V, ARM_TIMER) ((jlong) ((uint64_t) ((uint32_t) V) << 32 | ARM_TIMER))
static jlong netty_epoll_native_epollWait0(JNIEnv* env, jclass clazz, jint efd, jlong address, jint len, jint timerFd, jint tvSec, jint tvNsec, jlong millisThreshold) {
// only reschedule the timer if there is a newer event.
// -1 is a special value used by EpollEventLoop.
uint32_t armTimer = millisThreshold <= 0 ? 1 : 0;
if (tvSec != ((jint) -1) && tvNsec != ((jint) -1)) {
if (millisThreshold > 0 && (tvSec != 0 || tvNsec != 0)) {
// Let's try to reduce the syscalls as much as possible as timerfd_settime(...) can be expensive:
// See https://github.com/netty/netty/issues/11695
if (epoll_pwait2_supported == 1) {
// We have epoll_pwait2(...) and it is supported, this means we can just pass in the itimerspec directly and not need an
// extra syscall even for very small timeouts.
struct timespec ts = { tvSec, tvNsec };
struct epoll_event *ev = (struct epoll_event*) (intptr_t) address;
int result, err;
do {
result = epoll_pwait2(efd, ev, len, &ts, NULL);
if (result >= 0) {
return EPOLL_WAIT_RESULT(result, armTimer);
}
} while((err = errno) == EINTR);
return EPOLL_WAIT_RESULT(-err, armTimer);
}
int millis = tvNsec / 1000000;
// Check if we can reduce the syscall overhead by just use epoll_wait. This is done in cases when we can
// tolerate some "drift".
if (tvNsec == 0 ||
// Let's use the threshold to accept that we may be not 100 % accurate and ignore anything that
// is smaller then 1 ms.
millis >= millisThreshold ||
tvSec > 0) {
millis += tvSec * 1000;
int result = netty_epoll_native_epollWait(env, clazz, efd, address, len, millis);
return EPOLL_WAIT_RESULT(result, armTimer);
}
}
struct itimerspec ts;
memset(&ts.it_interval, 0, sizeof(struct timespec));
ts.it_value.tv_sec = tvSec;
ts.it_value.tv_nsec = tvNsec;
if (timerfd_settime(timerFd, 0, &ts, NULL) < 0) {
netty_unix_errors_throwChannelExceptionErrorNo(env, "timerfd_settime() failed: ", errno);
return -1;
}
armTimer = 1;
}
int result = netty_epoll_native_epollWait(env, clazz, efd, address, len, -1);
return EPOLL_WAIT_RESULT(result, armTimer);
}
static inline void cpu_relax() {
#if defined(__x86_64__)
asm volatile("pause\n": : :"memory");
#elif defined(__aarch64__)
asm volatile("isb\n": : :"memory");
#elif defined(__riscv) && defined(__riscv_zihintpause)
asm volatile("pause\n": : :"memory");
#endif
}
static jint netty_epoll_native_epollBusyWait0(JNIEnv* env, jclass clazz, jint efd, jlong address, jint len) {
struct epoll_event *ev = (struct epoll_event*) (intptr_t) address;
int result, err;
// Zeros = poll (aka return immediately).
do {
result = epoll_wait(efd, ev, len, 0);
if (result == 0) {
// Since we're always polling epoll_wait with no timeout,
// signal CPU that we're in a busy loop
cpu_relax();
}
if (result >= 0) {
return result;
}
} while((err = errno) == EINTR);
return -err;
}
static jint netty_epoll_native_epollCtlAdd0(JNIEnv* env, jclass clazz, jint efd, jint fd, jint flags) {
int res = epollCtl(env, efd, EPOLL_CTL_ADD, fd, flags);
if (res < 0) {
return -errno;
}
return res;
}
static jint netty_epoll_native_epollCtlMod0(JNIEnv* env, jclass clazz, jint efd, jint fd, jint flags) {
int res = epollCtl(env, efd, EPOLL_CTL_MOD, fd, flags);
if (res < 0) {
return -errno;
}
return res;
}
static jint netty_epoll_native_epollCtlDel0(JNIEnv* env, jclass clazz, jint efd, jint fd) {
// Create an empty event to workaround a bug in older kernels which can not handle NULL.
struct epoll_event event = { 0 };
int res = epoll_ctl(efd, EPOLL_CTL_DEL, fd, &event);
if (res < 0) {
return -errno;
}
return res;
}
static jint netty_epoll_native_sendmmsg0(JNIEnv* env, jclass clazz, jint fd, jboolean ipv6, jobjectArray packets, jint offset, jint len) {
struct mmsghdr msg[len];
struct sockaddr_storage addr[len];
char controls[len][CMSG_SPACE(sizeof(uint16_t))];
socklen_t addrSize;
int i;
memset(msg, 0, sizeof(msg));
for (i = 0; i < len; i++) {
jobject packet = (*env)->GetObjectArrayElement(env, packets, i + offset);
jbyteArray address = (jbyteArray) (*env)->GetObjectField(env, packet, packetRecipientAddrFieldId);
jint addrLen = (*env)->GetIntField(env, packet, packetRecipientAddrLenFieldId);
jint packetSegmentSize = (*env)->GetIntField(env, packet, packetSegmentSizeFieldId);
if (packetSegmentSize > 0) {
msg[i].msg_hdr.msg_control = controls[i];
msg[i].msg_hdr.msg_controllen = sizeof(controls[i]);
struct cmsghdr *cm = CMSG_FIRSTHDR(&msg[i].msg_hdr);
cm->cmsg_level = SOL_UDP;
cm->cmsg_type = UDP_SEGMENT;
cm->cmsg_len = CMSG_LEN(sizeof(uint16_t));
*((uint16_t *) CMSG_DATA(cm)) = packetSegmentSize;
}
if (addrLen != 0) {
jint scopeId = (*env)->GetIntField(env, packet, packetRecipientScopeIdFieldId);
jint port = (*env)->GetIntField(env, packet, packetRecipientPortFieldId);
if (netty_unix_socket_initSockaddr(env, ipv6, address, scopeId, port, &addr[i], &addrSize) == -1) {
return -1;
}
msg[i].msg_hdr.msg_name = &addr[i];
msg[i].msg_hdr.msg_namelen = addrSize;
}
msg[i].msg_hdr.msg_iov = (struct iovec*) (intptr_t) (*env)->GetLongField(env, packet, packetMemoryAddressFieldId);
msg[i].msg_hdr.msg_iovlen = (*env)->GetIntField(env, packet, packetCountFieldId);
}
ssize_t res;
int err;
do {
// 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));
if (res < 0) {
return -err;
}
return (jint) res;
}
static void init_packet_address(JNIEnv* env, jobject packet, struct sockaddr_storage* addr, jfieldID addrFieldId,
jfieldID addrLenFieldId, jfieldID scopeIdFieldId, jfieldID portFieldId) {
jbyteArray address = (jbyteArray) (*env)->GetObjectField(env, packet, addrFieldId);
if (addr->ss_family == AF_INET) {
struct sockaddr_in* ipaddr = (struct sockaddr_in*) addr;
(*env)->SetByteArrayRegion(env, address, 0, 4, (jbyte*) &ipaddr->sin_addr.s_addr);
(*env)->SetIntField(env, packet, addrLenFieldId, 4);
(*env)->SetIntField(env, packet, scopeIdFieldId, 0);
(*env)->SetIntField(env, packet, portFieldId, ntohs(ipaddr->sin_port));
} else {
int addrLen = netty_unix_socket_ipAddressLength(addr);
struct sockaddr_in6* ip6addr = (struct sockaddr_in6*) addr;
if (addrLen == 4) {
// IPV4 mapped IPV6 address
jbyte* addr = (jbyte*) &ip6addr->sin6_addr.s6_addr;
(*env)->SetByteArrayRegion(env, address, 0, 4, addr + 12);
} else {
(*env)->SetByteArrayRegion(env, address, 0, 16, (jbyte*) &ip6addr->sin6_addr.s6_addr);
}
(*env)->SetIntField(env, packet, addrLenFieldId, addrLen);
(*env)->SetIntField(env, packet, scopeIdFieldId, ip6addr->sin6_scope_id);
(*env)->SetIntField(env, packet, portFieldId, ntohs(ip6addr->sin6_port));
}
}
static void init_packet(JNIEnv* env, jobject packet, struct msghdr* msg, int len) {
(*env)->SetIntField(env, packet, packetCountFieldId, len);
init_packet_address(env, packet, (struct sockaddr_storage*) msg->msg_name, packetSenderAddrFieldId, packetSenderAddrLenFieldId, packetSenderScopeIdFieldId, packetSenderPortFieldId);
struct cmsghdr *cmsg = NULL;
uint16_t gso_size = 0;
uint16_t *gsosizeptr = NULL;
for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) {
if (cmsg->cmsg_level == SOL_UDP && cmsg->cmsg_type == UDP_GRO) {
gsosizeptr = (uint16_t *) CMSG_DATA(cmsg);
gso_size = *gsosizeptr;
}
#ifdef IP_RECVORIGDSTADDR
else if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVORIGDSTADDR) {
init_packet_address(env, packet, (struct sockaddr_storage*) CMSG_DATA(cmsg), packetRecipientAddrFieldId, packetRecipientAddrLenFieldId, packetRecipientScopeIdFieldId, packetRecipientPortFieldId);
}
#endif // IP_RECVORIGDSTADDR
}
(*env)->SetIntField(env, packet, packetSegmentSizeFieldId, gso_size);
}
static jint netty_epoll_native_recvmsg0(JNIEnv* env, jclass clazz, jint fd, jboolean ipv6, jobject packet) {
struct msghdr msg = { 0 };
struct sockaddr_storage sock_address;
int addrSize = sizeof(sock_address);
// Enough space for GRO and IP_RECVORIGDSTADDR
char control[CMSG_SPACE(sizeof(uint16_t)) + sizeof(struct sockaddr_storage)] = { 0 };
msg.msg_name = &sock_address;
msg.msg_namelen = (socklen_t) addrSize;
msg.msg_iov = (struct iovec*) (intptr_t) (*env)->GetLongField(env, packet, packetMemoryAddressFieldId);
msg.msg_iovlen = (*env)->GetIntField(env, packet, packetCountFieldId);
msg.msg_control = control;
msg.msg_controllen = sizeof(control);
ssize_t res;
int err;
do {
res = recvmsg(fd, &msg, 0);
// keep on reading if it was interrupted
} while (res == -1 && ((err = errno) == EINTR));
if (res < 0) {
return -err;
}
init_packet(env, packet, &msg, res);
return (jint) res;
}
static jint netty_epoll_native_recvmmsg0(JNIEnv* env, jclass clazz, jint fd, jboolean ipv6, jobjectArray packets, jint offset, jint len) {
struct mmsghdr msg[len];
memset(msg, 0, sizeof(msg));
struct sockaddr_storage addr[len];
int addrSize = sizeof(addr);
memset(addr, 0, addrSize);
int storageSize = sizeof(struct sockaddr_storage);
char* cntrlbuf = NULL;
#ifdef IP_RECVORIGDSTADDR
int readLocalAddr = 0;
if (netty_unix_socket_getOption(env, fd, IPPROTO_IP, IP_RECVORIGDSTADDR,
&readLocalAddr, sizeof(readLocalAddr)) < 0) {
cntrlbuf = malloc(sizeof(char) * storageSize * len);
}
#endif // IP_RECVORIGDSTADDR
int i;
for (i = 0; i < len; i++) {
jobject packet = (*env)->GetObjectArrayElement(env, packets, i + offset);
msg[i].msg_hdr.msg_iov = (struct iovec*) (intptr_t) (*env)->GetLongField(env, packet, packetMemoryAddressFieldId);
msg[i].msg_hdr.msg_iovlen = (*env)->GetIntField(env, packet, packetCountFieldId);
msg[i].msg_hdr.msg_name = addr + i;
msg[i].msg_hdr.msg_namelen = (socklen_t) addrSize;
if (cntrlbuf != NULL) {
msg[i].msg_hdr.msg_control = cntrlbuf + i * storageSize;
msg[i].msg_hdr.msg_controllen = storageSize;
}
}
ssize_t res;
int err;
do {
// 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) {
for (i = 0; i < res; i++) {
jobject packet = (*env)->GetObjectArrayElement(env, packets, i + offset);
init_packet(env, packet, &msg[i].msg_hdr, msg[i].msg_len);
}
}
// Free the control message buffer if needed.
free(cntrlbuf);
if (res < 0) {
return -err;
}
return (jint) res;
}
static jstring netty_epoll_native_kernelVersion(JNIEnv* env, jclass clazz) {
struct utsname name;
int res = uname(&name);
if (res == 0) {
return (*env)->NewStringUTF(env, name.release);
}
netty_unix_errors_throwRuntimeExceptionErrorNo(env, "uname() failed: ", errno);
return NULL;
}
static jboolean netty_epoll_native_isSupportingSendmmsg(JNIEnv* env, jclass clazz) {
if (SYS_sendmmsg == -1) {
return JNI_FALSE;
}
if (syscall(SYS_sendmmsg, -1, NULL, 0, 0) == -1) {
if (errno == ENOSYS) {
return JNI_FALSE;
}
}
return JNI_TRUE;
}
static jboolean netty_epoll_native_isSupportingUdpSegment(JNIEnv* env, jclass clazz) {
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd == -1) {
return JNI_FALSE;
}
int gso_size = 512;
int ret = setsockopt(fd, SOL_UDP, UDP_SEGMENT, &gso_size, sizeof(gso_size));
close(fd);
return ret == -1 ? JNI_FALSE : JNI_TRUE;
}
static jboolean netty_epoll_native_isSupportingRecvmmsg(JNIEnv* env, jclass clazz) {
if (SYS_recvmmsg == -1) {
return JNI_FALSE;
}
if (syscall(SYS_recvmmsg, -1, NULL, 0, 0, NULL) == -1) {
if (errno == ENOSYS) {
return JNI_FALSE;
}
}
return JNI_TRUE;
}
static jint netty_epoll_native_tcpFastopenMode(JNIEnv* env, jclass clazz) {
int fastopen = 0;
getSysctlValue("/proc/sys/net/ipv4/tcp_fastopen", &fastopen);
return fastopen;
}
static jint netty_epoll_native_epollet(JNIEnv* env, jclass clazz) {
return EPOLLET;
}
static jint netty_epoll_native_epollin(JNIEnv* env, jclass clazz) {
return EPOLLIN;
}
static jint netty_epoll_native_epollout(JNIEnv* env, jclass clazz) {
return EPOLLOUT;
}
static jint netty_epoll_native_epollrdhup(JNIEnv* env, jclass clazz) {
return EPOLLRDHUP;
}
static jint netty_epoll_native_epollerr(JNIEnv* env, jclass clazz) {
return EPOLLERR;
}
static jint netty_epoll_native_sizeofEpollEvent(JNIEnv* env, jclass clazz) {
return sizeof(struct epoll_event);
}
static jint netty_epoll_native_offsetofEpollData(JNIEnv* env, jclass clazz) {
return offsetof(struct epoll_event, data);
}
static jint netty_epoll_native_splice0(JNIEnv* env, jclass clazz, jint fd, jlong offIn, jint fdOut, jlong offOut, jlong len) {
ssize_t res;
int err;
loff_t off_in = (loff_t) offIn;
loff_t off_out = (loff_t) offOut;
loff_t* p_off_in = off_in >= 0 ? &off_in : NULL;
loff_t* p_off_out = off_out >= 0 ? &off_out : NULL;
do {
res = splice(fd, p_off_in, fdOut, p_off_out, (size_t) len, SPLICE_F_NONBLOCK | SPLICE_F_MOVE);
// keep on splicing if it was interrupted
} while (res == -1 && ((err = errno) == EINTR));
if (res < 0) {
return -err;
}
return (jint) res;
}
static jint netty_epoll_native_tcpMd5SigMaxKeyLen(JNIEnv* env, jclass clazz) {
struct tcp_md5sig md5sig;
// Defensive size check
if (sizeof(md5sig.tcpm_key) < TCP_MD5SIG_MAXKEYLEN) {
return sizeof(md5sig.tcpm_key);
}
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
static const JNINativeMethod statically_referenced_fixed_method_table[] = {
{ "epollet", "()I", (void *) netty_epoll_native_epollet },
{ "epollin", "()I", (void *) netty_epoll_native_epollin },
{ "epollout", "()I", (void *) netty_epoll_native_epollout },
{ "epollrdhup", "()I", (void *) netty_epoll_native_epollrdhup },
{ "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 },
{ "tcpFastopenMode", "()I", (void *) netty_epoll_native_tcpFastopenMode },
{ "kernelVersion", "()Ljava/lang/String;", (void *) netty_epoll_native_kernelVersion }
};
static const jint statically_referenced_fixed_method_table_size = sizeof(statically_referenced_fixed_method_table) / sizeof(statically_referenced_fixed_method_table[0]);
static const JNINativeMethod fixed_method_table[] = {
{ "eventFd", "()I", (void *) netty_epoll_native_eventFd },
{ "timerFd", "()I", (void *) netty_epoll_native_timerFd },
{ "eventFdWrite", "(IJ)V", (void *) netty_epoll_native_eventFdWrite },
{ "eventFdRead", "(I)V", (void *) netty_epoll_native_eventFdRead },
{ "epollCreate", "()I", (void *) netty_epoll_native_epollCreate },
{ "epollWait0", "(IJIIIIJ)J", (void *) netty_epoll_native_epollWait0 },
{ "epollWait", "(IJII)I", (void *) netty_epoll_native_epollWait },
{ "epollBusyWait0", "(IJI)I", (void *) netty_epoll_native_epollBusyWait0 },
{ "epollCtlAdd0", "(III)I", (void *) netty_epoll_native_epollCtlAdd0 },
{ "epollCtlMod0", "(III)I", (void *) netty_epoll_native_epollCtlMod0 },
{ "epollCtlDel0", "(II)I", (void *) netty_epoll_native_epollCtlDel0 },
// "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 },
{ "isSupportingUdpSegment", "()Z", (void *) netty_epoll_native_isSupportingUdpSegment },
{ "registerUnix", "()I", (void *) netty_epoll_native_registerUnix },
};
static const jint fixed_method_table_size = sizeof(fixed_method_table) / sizeof(fixed_method_table[0]);
static jint dynamicMethodsTableSize() {
return fixed_method_table_size + 3; // 3 is for the dynamic method signatures.
}
static JNINativeMethod* createDynamicMethodsTable(const char* packagePrefix) {
char* dynamicTypeName = NULL;
size_t size = sizeof(JNINativeMethod) * dynamicMethodsTableSize();
JNINativeMethod* dynamicMethods = malloc(size);
if (dynamicMethods == NULL) {
return NULL;
}
memset(dynamicMethods, 0, size);
memcpy(dynamicMethods, fixed_method_table, sizeof(fixed_method_table));
JNINativeMethod* dynamicMethod = &dynamicMethods[fixed_method_table_size];
NETTY_JNI_UTIL_PREPEND(packagePrefix, "io/netty/channel/epoll/NativeDatagramPacketArray$NativeDatagramPacket;II)I", dynamicTypeName, error);
NETTY_JNI_UTIL_PREPEND("(IZ[L", dynamicTypeName, dynamicMethod->signature, error);
dynamicMethod->name = "sendmmsg0";
dynamicMethod->fnPtr = (void *) netty_epoll_native_sendmmsg0;
netty_jni_util_free_dynamic_name(&dynamicTypeName);
++dynamicMethod;
NETTY_JNI_UTIL_PREPEND(packagePrefix, "io/netty/channel/epoll/NativeDatagramPacketArray$NativeDatagramPacket;II)I", dynamicTypeName, error);
NETTY_JNI_UTIL_PREPEND("(IZ[L", dynamicTypeName, dynamicMethod->signature, error);
dynamicMethod->name = "recvmmsg0";
dynamicMethod->fnPtr = (void *) netty_epoll_native_recvmmsg0;
netty_jni_util_free_dynamic_name(&dynamicTypeName);
++dynamicMethod;
NETTY_JNI_UTIL_PREPEND(packagePrefix, "io/netty/channel/epoll/NativeDatagramPacketArray$NativeDatagramPacket;)I", dynamicTypeName, error);
NETTY_JNI_UTIL_PREPEND("(IZL", dynamicTypeName, dynamicMethod->signature, error);
dynamicMethod->name = "recvmsg0";
dynamicMethod->fnPtr = (void *) netty_epoll_native_recvmsg0;
netty_jni_util_free_dynamic_name(&dynamicTypeName);
return dynamicMethods;
error:
free(dynamicTypeName);
netty_jni_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize());
return NULL;
}
// JNI Method Registration Table End
// IMPORTANT: If you add any NETTY_JNI_UTIL_LOAD_CLASS or NETTY_JNI_UTIL_FIND_CLASS calls you also need to update
// Native to reflect that.
static jint netty_epoll_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
int ret = JNI_ERR;
int staticallyRegistered = 0;
int nativeRegistered = 0;
int linuxsocketOnLoadCalled = 0;
char* nettyClassName = NULL;
jclass nativeDatagramPacketCls = NULL;
JNINativeMethod* dynamicMethods = NULL;
// We must register the statically referenced methods first!
if (netty_jni_util_register_natives(env,
packagePrefix,
STATICALLY_CLASSNAME,
statically_referenced_fixed_method_table,
statically_referenced_fixed_method_table_size) != 0) {
goto done;
}
staticallyRegistered = 1;
// Register the methods which are not referenced by static member variables
dynamicMethods = createDynamicMethodsTable(packagePrefix);
if (dynamicMethods == NULL) {
goto done;
}
if (netty_jni_util_register_natives(env,
packagePrefix,
NATIVE_CLASSNAME,
dynamicMethods,
dynamicMethodsTableSize()) != 0) {
goto done;
}
nativeRegistered = 1;
if (netty_epoll_linuxsocket_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
goto done;
}
linuxsocketOnLoadCalled = 1;
// Initialize this module
NETTY_JNI_UTIL_PREPEND(packagePrefix, "io/netty/channel/epoll/NativeDatagramPacketArray$NativeDatagramPacket", nettyClassName, done);
NETTY_JNI_UTIL_FIND_CLASS(env, nativeDatagramPacketCls, nettyClassName, done);
netty_jni_util_free_dynamic_name(&nettyClassName);
NETTY_JNI_UTIL_GET_FIELD(env, nativeDatagramPacketCls, packetSenderAddrFieldId, "senderAddr", "[B", done);
NETTY_JNI_UTIL_GET_FIELD(env, nativeDatagramPacketCls, packetSenderAddrLenFieldId, "senderAddrLen", "I", done);
NETTY_JNI_UTIL_GET_FIELD(env, nativeDatagramPacketCls, packetSenderScopeIdFieldId, "senderScopeId", "I", done);
NETTY_JNI_UTIL_GET_FIELD(env, nativeDatagramPacketCls, packetSenderPortFieldId, "senderPort", "I", done);
NETTY_JNI_UTIL_GET_FIELD(env, nativeDatagramPacketCls, packetRecipientAddrFieldId, "recipientAddr", "[B", done);
NETTY_JNI_UTIL_GET_FIELD(env, nativeDatagramPacketCls, packetRecipientAddrLenFieldId, "recipientAddrLen", "I", done);
NETTY_JNI_UTIL_GET_FIELD(env, nativeDatagramPacketCls, packetRecipientScopeIdFieldId, "recipientScopeId", "I", done);
NETTY_JNI_UTIL_GET_FIELD(env, nativeDatagramPacketCls, packetRecipientPortFieldId, "recipientPort", "I", done);
NETTY_JNI_UTIL_GET_FIELD(env, nativeDatagramPacketCls, packetSegmentSizeFieldId, "segmentSize", "I", done);
NETTY_JNI_UTIL_GET_FIELD(env, nativeDatagramPacketCls, packetMemoryAddressFieldId, "memoryAddress", "J", done);
NETTY_JNI_UTIL_GET_FIELD(env, nativeDatagramPacketCls, packetCountFieldId, "count", "I", done);
ret = NETTY_JNI_UTIL_JNI_VERSION;
staticPackagePrefix = packagePrefix;
// Check if there is an epoll_pwait2 system call and also if it works. One some systems it might be there
// but actually is not implemented and so fail with ENOSYS.
// See https://github.com/netty/netty/issues/12343
if (epoll_pwait2) {
int efd = epoll_create(1);
if (efd != -1) {
struct timespec ts = { 0, 0 };
struct epoll_event ev;
do {
if (epoll_pwait2(efd, &ev, 1, &ts, NULL) != -1) {
epoll_pwait2_supported = 1;
break;
}
} while(errno == EINTR);
close(efd);
}
}
done:
netty_jni_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize());
free(nettyClassName);
if (ret == JNI_ERR) {
if (staticallyRegistered == 1) {
netty_jni_util_unregister_natives(env, packagePrefix, STATICALLY_CLASSNAME);
}
if (nativeRegistered == 1) {
netty_jni_util_unregister_natives(env, packagePrefix, NATIVE_CLASSNAME);
}
if (linuxsocketOnLoadCalled == 1) {
netty_epoll_linuxsocket_JNI_OnUnLoad(env, packagePrefix);
}
packetSenderAddrFieldId = NULL;
packetSenderAddrLenFieldId = NULL;
packetSenderScopeIdFieldId = NULL;
packetSenderPortFieldId = NULL;
packetRecipientAddrFieldId = NULL;
packetRecipientAddrLenFieldId = NULL;
packetRecipientScopeIdFieldId = NULL;
packetRecipientPortFieldId = NULL;
packetSegmentSizeFieldId = NULL;
packetMemoryAddressFieldId = NULL;
packetCountFieldId = NULL;
}
return ret;
}
static void netty_epoll_native_JNI_OnUnload(JNIEnv* env) {
netty_epoll_linuxsocket_JNI_OnUnLoad(env, staticPackagePrefix);
if (register_unix_called == 1) {
register_unix_called = 0;
netty_unix_unregister(env, staticPackagePrefix);
}
netty_jni_util_unregister_natives(env, staticPackagePrefix, STATICALLY_CLASSNAME);
netty_jni_util_unregister_natives(env, staticPackagePrefix, NATIVE_CLASSNAME);
if (staticPackagePrefix != NULL) {
free((void *) staticPackagePrefix);
staticPackagePrefix = NULL;
}
packetSenderAddrFieldId = NULL;
packetSenderAddrLenFieldId = NULL;
packetSenderScopeIdFieldId = NULL;
packetSenderPortFieldId = NULL;
packetRecipientAddrFieldId = NULL;
packetRecipientAddrLenFieldId = NULL;
packetRecipientScopeIdFieldId = NULL;
packetRecipientPortFieldId = NULL;
packetSegmentSizeFieldId = NULL;
packetMemoryAddressFieldId = NULL;
packetCountFieldId = NULL;
}
// Invoked by the JVM when statically linked
// We build with -fvisibility=hidden so ensure we mark everything that needs to be visible with JNIEXPORT
// https://mail.openjdk.java.net/pipermail/core-libs-dev/2013-February/014549.html
// Invoked by the JVM when statically linked
JNIEXPORT jint JNI_OnLoad_netty_transport_native_epoll(JavaVM* vm, void* reserved) {
return netty_jni_util_JNI_OnLoad(vm, reserved, "netty_transport_native_epoll", netty_epoll_native_JNI_OnLoad);
}
// Invoked by the JVM when statically linked
JNIEXPORT void JNI_OnUnload_netty_transport_native_epoll(JavaVM* vm, void* reserved) {
netty_jni_util_JNI_OnUnload(vm, reserved, netty_epoll_native_JNI_OnUnload);
}
#ifndef NETTY_BUILD_STATIC
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
return netty_jni_util_JNI_OnLoad(vm, reserved, "netty_transport_native_epoll", netty_epoll_native_JNI_OnLoad);
}
JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved) {
netty_jni_util_JNI_OnUnload(vm, reserved, netty_epoll_native_JNI_OnUnload);
}
#endif /* NETTY_BUILD_STATIC */

View file

@ -0,0 +1,38 @@
/*
* Copyright 2023 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_EPOLL_VMSOCKET_H_
#define NETTY_EPOLL_VMSOCKET_H_
#include <sys/socket.h>
#ifndef AF_VSOCK
#define AF_VSOCK 40
#endif
struct sockaddr_vm {
sa_family_t svm_family;
unsigned short svm_reserved1;
unsigned int svm_port;
unsigned int svm_cid;
unsigned char svm_zero[sizeof(struct sockaddr) -
sizeof(sa_family_t) -
sizeof(unsigned short) -
sizeof(unsigned int) -
sizeof(unsigned int)];
};
#endif /* NETTY_EPOLL_VMSOCKET_H_ */

View file

@ -1,4 +1,12 @@
apply plugin: 'com.google.osdetector'
dependencies {
api project(':netty-channel')
api project(':netty-channel-unix')
testImplementation project(':netty-testsuite')
testImplementation project(':netty-handler')
testImplementation testLibs.assertj
testImplementation testLibs.rerunner.jupiter
testRuntimeOnly project(path: ':netty-channel-epoll-native', configuration: osdetector.classifier)
testRuntimeOnly project(path: ':netty-tcnative-boringssl-static-native', configuration: osdetector.classifier)
}

View file

@ -0,0 +1,212 @@
/*
* Copyright 2017 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.FixedRecvByteBufAllocator;
import io.netty.channel.ServerChannel;
import io.netty.channel.SimpleChannelInboundHandler;
import java.net.InetSocketAddress;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import static org.junit.jupiter.api.Assertions.assertEquals;
public abstract class DetectPeerCloseWithoutReadTest {
protected abstract EventLoopGroup newGroup();
protected abstract Class<? extends ServerChannel> serverChannel();
protected abstract Class<? extends Channel> clientChannel();
@Test
@Timeout(value = 10000, unit = TimeUnit.MILLISECONDS)
public void clientCloseWithoutServerReadIsDetectedNoExtraReadRequested() throws InterruptedException {
clientCloseWithoutServerReadIsDetected0(false);
}
@Test
@Timeout(value = 10000, unit = TimeUnit.MILLISECONDS)
public void clientCloseWithoutServerReadIsDetectedExtraReadRequested() throws InterruptedException {
clientCloseWithoutServerReadIsDetected0(true);
}
private void clientCloseWithoutServerReadIsDetected0(final boolean extraReadRequested)
throws InterruptedException {
EventLoopGroup serverGroup = null;
EventLoopGroup clientGroup = null;
Channel serverChannel = null;
try {
final CountDownLatch latch = new CountDownLatch(1);
final AtomicInteger bytesRead = new AtomicInteger();
final int expectedBytes = 100;
serverGroup = newGroup();
clientGroup = newGroup();
ServerBootstrap sb = new ServerBootstrap();
sb.group(serverGroup);
sb.channel(serverChannel());
// Ensure we read only one message per read() call and that we need multiple read()
// calls to consume everything.
sb.childOption(ChannelOption.AUTO_READ, false);
sb.childOption(ChannelOption.MAX_MESSAGES_PER_READ, 1);
sb.childOption(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(expectedBytes / 10));
sb.childHandler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) {
ch.pipeline().addLast(new TestHandler(bytesRead, extraReadRequested, latch));
}
});
serverChannel = sb.bind(new InetSocketAddress(0)).syncUninterruptibly().channel();
Bootstrap cb = new Bootstrap();
cb.group(serverGroup);
cb.channel(clientChannel());
cb.handler(new ChannelInboundHandlerAdapter());
Channel clientChannel = cb.connect(serverChannel.localAddress()).syncUninterruptibly().channel();
ByteBuf buf = clientChannel.alloc().buffer(expectedBytes);
buf.writerIndex(buf.writerIndex() + expectedBytes);
clientChannel.writeAndFlush(buf).addListener(ChannelFutureListener.CLOSE);
latch.await();
assertEquals(expectedBytes, bytesRead.get());
} finally {
if (serverChannel != null) {
serverChannel.close().syncUninterruptibly();
}
if (serverGroup != null) {
serverGroup.shutdownGracefully();
}
if (clientGroup != null) {
clientGroup.shutdownGracefully();
}
}
}
@Test
@Timeout(value = 10000, unit = TimeUnit.MILLISECONDS)
public void serverCloseWithoutClientReadIsDetectedNoExtraReadRequested() throws InterruptedException {
serverCloseWithoutClientReadIsDetected0(false);
}
@Test
@Timeout(value = 10000, unit = TimeUnit.MILLISECONDS)
public void serverCloseWithoutClientReadIsDetectedExtraReadRequested() throws InterruptedException {
serverCloseWithoutClientReadIsDetected0(true);
}
private void serverCloseWithoutClientReadIsDetected0(final boolean extraReadRequested) throws InterruptedException {
EventLoopGroup serverGroup = null;
EventLoopGroup clientGroup = null;
Channel serverChannel = null;
Channel clientChannel = null;
try {
final CountDownLatch latch = new CountDownLatch(1);
final AtomicInteger bytesRead = new AtomicInteger();
final int expectedBytes = 100;
serverGroup = newGroup();
clientGroup = newGroup();
ServerBootstrap sb = new ServerBootstrap();
sb.group(serverGroup);
sb.channel(serverChannel());
sb.childHandler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) {
ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
@Override
public void channelActive(ChannelHandlerContext ctx) {
ByteBuf buf = ctx.alloc().buffer(expectedBytes);
buf.writerIndex(buf.writerIndex() + expectedBytes);
ctx.writeAndFlush(buf).addListener(ChannelFutureListener.CLOSE);
ctx.fireChannelActive();
}
});
}
});
serverChannel = sb.bind(new InetSocketAddress(0)).syncUninterruptibly().channel();
Bootstrap cb = new Bootstrap();
cb.group(serverGroup);
cb.channel(clientChannel());
// Ensure we read only one message per read() call and that we need multiple read()
// calls to consume everything.
cb.option(ChannelOption.AUTO_READ, false);
cb.option(ChannelOption.MAX_MESSAGES_PER_READ, 1);
cb.option(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(expectedBytes / 10));
cb.handler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(new TestHandler(bytesRead, extraReadRequested, latch));
}
});
clientChannel = cb.connect(serverChannel.localAddress()).syncUninterruptibly().channel();
latch.await();
assertEquals(expectedBytes, bytesRead.get());
} finally {
if (serverChannel != null) {
serverChannel.close().syncUninterruptibly();
}
if (clientChannel != null) {
clientChannel.close().syncUninterruptibly();
}
if (serverGroup != null) {
serverGroup.shutdownGracefully();
}
if (clientGroup != null) {
clientGroup.shutdownGracefully();
}
}
}
private static final class TestHandler extends SimpleChannelInboundHandler<ByteBuf> {
private final AtomicInteger bytesRead;
private final boolean extraReadRequested;
private final CountDownLatch latch;
TestHandler(AtomicInteger bytesRead, boolean extraReadRequested, CountDownLatch latch) {
this.bytesRead = bytesRead;
this.extraReadRequested = extraReadRequested;
this.latch = latch;
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) {
bytesRead.addAndGet(msg.readableBytes());
if (extraReadRequested) {
// Because autoread is off, we call read to consume all data until we detect the close.
ctx.read();
}
}
@Override
public void channelInactive(ChannelHandlerContext ctx) {
latch.countDown();
ctx.fireChannelInactive();
}
}
}

View file

@ -0,0 +1,28 @@
/*
* Copyright 2015 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.channel.unix.DomainSocketAddress;
import java.net.SocketAddress;
import java.util.UUID;
public class EpollAbstractDomainSocketEchoTest extends EpollDomainSocketEchoTest {
@Override
protected SocketAddress newSocketAddress() {
// these don't actually show up in the file system so creating a temp file isn't reliable
return new DomainSocketAddress("\0" + System.getProperty("java.io.tmpdir") + UUID.randomUUID());
}
}

View file

@ -0,0 +1,93 @@
/*
* Copyright 2015 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.channel.ChannelException;
import io.netty.channel.unix.Buffer;
import io.netty.channel.unix.IntegerUnixChannelOption;
import io.netty.channel.unix.RawUnixChannelOption;
import org.junit.jupiter.api.Test;
import java.nio.ByteBuffer;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.fail;
public class EpollChannelConfigTest {
@Test
public void testOptionGetThrowsChannelException() throws Exception {
Epoll.ensureAvailability();
EpollSocketChannel channel = new EpollSocketChannel();
channel.config().getSoLinger();
channel.fd().close();
try {
channel.config().getSoLinger();
fail();
} catch (ChannelException e) {
// expected
}
}
@Test
public void testOptionSetThrowsChannelException() throws Exception {
Epoll.ensureAvailability();
EpollSocketChannel channel = new EpollSocketChannel();
channel.config().setKeepAlive(true);
channel.fd().close();
try {
channel.config().setKeepAlive(true);
fail();
} catch (ChannelException e) {
// expected
}
}
@Test
public void testIntegerOption() throws Exception {
Epoll.ensureAvailability();
EpollSocketChannel channel = new EpollSocketChannel();
IntegerUnixChannelOption opt = new IntegerUnixChannelOption("INT_OPT", 1, 2);
Integer zero = 0;
assertEquals(zero, channel.config().getOption(opt));
channel.config().setOption(opt, 1);
assertNotEquals(zero, channel.config().getOption(opt));
channel.fd().close();
}
@Test
public void testRawOption() throws Exception {
Epoll.ensureAvailability();
EpollSocketChannel channel = new EpollSocketChannel();
// Value for SOL_SOCKET and SO_REUSEADDR
// See https://github.com/torvalds/linux/blob/v5.17/include/uapi/asm-generic/socket.h
RawUnixChannelOption opt = new RawUnixChannelOption("RAW_OPT", 1, 2, 4);
ByteBuffer disabled = Buffer.allocateDirectWithNativeOrder(4);
disabled.putInt(0).flip();
assertEquals(disabled, channel.config().getOption(opt));
ByteBuffer enabled = Buffer.allocateDirectWithNativeOrder(4);
enabled.putInt(1).flip();
channel.config().setOption(opt, enabled);
assertNotEquals(disabled, channel.config().getOption(opt));
channel.fd().close();
}
}

View file

@ -0,0 +1,39 @@
/*
* Copyright 2017 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelConfig;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.CompositeBufferGatheringWriteTest;
import java.util.List;
public class EpollCompositeBufferGatheringWriteTest extends CompositeBufferGatheringWriteTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithoutFastOpen();
}
@Override
protected void compositeBufferPartialWriteDoesNotCorruptDataInitServerConfig(ChannelConfig config,
int soSndBuf) {
if (config instanceof EpollChannelConfig) {
((EpollChannelConfig) config).setMaxBytesPerGatheringWrite(soSndBuf);
}
}
}

View file

@ -0,0 +1,33 @@
/*
* Copyright 2019 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class EpollDatagramChannelConfigTest {
@Test
public void testIpFreeBind() throws Exception {
Epoll.ensureAvailability();
EpollDatagramChannel channel = new EpollDatagramChannel();
assertTrue(channel.config().setOption(EpollChannelOption.IP_FREEBIND, true));
assertTrue(channel.config().getOption(EpollChannelOption.IP_FREEBIND));
channel.fd().close();
}
}

View file

@ -0,0 +1,115 @@
/*
* Copyright 2019 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.socket.InternetProtocolFamily;
import io.netty.channel.unix.Socket;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import static io.netty.util.NetUtil.LOCALHOST;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class EpollDatagramChannelTest {
@BeforeEach
public void setUp() {
Epoll.ensureAvailability();
}
@Test
public void testDefaultMaxMessagePerRead() {
EpollDatagramChannel channel = new EpollDatagramChannel();
assertEquals(16, channel.config().getMaxMessagesPerRead());
channel.unsafe().closeForcibly();
}
@Test
public void testNotActiveNoLocalRemoteAddress() throws IOException {
checkNotActiveNoLocalRemoteAddress(new EpollDatagramChannel());
checkNotActiveNoLocalRemoteAddress(new EpollDatagramChannel(InternetProtocolFamily.IPv4));
checkNotActiveNoLocalRemoteAddress(new EpollDatagramChannel(InternetProtocolFamily.IPv6));
}
@Test
public void testActiveHasLocalAddress() throws IOException {
Socket socket = Socket.newSocketDgram();
EpollDatagramChannel channel = new EpollDatagramChannel(socket.intValue());
InetSocketAddress localAddress = channel.localAddress();
assertTrue(channel.active);
assertNotNull(localAddress);
assertEquals(socket.localAddress(), localAddress);
channel.fd().close();
}
@Test
public void testLocalAddressBeforeAndAfterBind() {
EventLoopGroup group = new EpollEventLoopGroup(1);
try {
TestHandler handler = new TestHandler();
InetSocketAddress localAddressBeforeBind = new InetSocketAddress(LOCALHOST, 0);
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(EpollDatagramChannel.class)
.localAddress(localAddressBeforeBind)
.handler(handler);
ChannelFuture future = bootstrap.bind().syncUninterruptibly();
assertNull(handler.localAddress);
SocketAddress localAddressAfterBind = future.channel().localAddress();
assertNotNull(localAddressAfterBind);
assertTrue(localAddressAfterBind instanceof InetSocketAddress);
assertTrue(((InetSocketAddress) localAddressAfterBind).getPort() != 0);
future.channel().close().syncUninterruptibly();
} finally {
group.shutdownGracefully();
}
}
private static void checkNotActiveNoLocalRemoteAddress(EpollDatagramChannel channel) throws IOException {
assertFalse(channel.active);
assertNull(channel.localAddress());
assertNull(channel.remoteAddress());
channel.fd().close();
}
private static final class TestHandler extends ChannelInboundHandlerAdapter {
private volatile SocketAddress localAddress;
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
this.localAddress = ctx.channel().localAddress();
super.channelRegistered(ctx);
}
}
}

View file

@ -0,0 +1,30 @@
/*
* Copyright 2017 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.DatagramConnectNotExistsTest;
import java.util.List;
public class EpollDatagramConnectNotExistsTest extends DatagramConnectNotExistsTest {
@Override
protected List<TestsuitePermutation.BootstrapFactory<Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.datagramSocket();
}
}

View file

@ -0,0 +1,30 @@
/*
* Copyright 2019 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.DatagramMulticastIPv6Test;
import java.util.List;
public class EpollDatagramMulticastIPv6Test extends DatagramMulticastIPv6Test {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<Bootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.datagram(internetProtocolFamily());
}
}

View file

@ -0,0 +1,32 @@
/*
* Copyright 2021 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.channel.socket.InternetProtocolFamily;
import io.netty.testsuite.transport.socket.DatagramMulticastTest;
public class EpollDatagramMulticastIpv6WithIpv4AddrTest extends DatagramMulticastTest {
@Override
protected InternetProtocolFamily groupInternetProtocalFamily() {
return InternetProtocolFamily.IPv4;
}
@Override
protected InternetProtocolFamily socketInternetProtocalFamily() {
return InternetProtocolFamily.IPv6;
}
}

View file

@ -0,0 +1,29 @@
/*
* Copyright 2019 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.DatagramMulticastTest;
import java.util.List;
public class EpollDatagramMulticastTest extends DatagramMulticastTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<Bootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.datagram(internetProtocolFamily());
}
}

View file

@ -0,0 +1,307 @@
/*
* Copyright 2019 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.AdaptiveRecvByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOption;
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 io.netty.util.internal.PlatformDependent;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
public class EpollDatagramScatteringReadTest extends AbstractDatagramTest {
@BeforeAll
public static void assumeRecvmmsgSupported() {
assumeTrue(Native.IS_SUPPORTING_RECVMMSG);
}
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<Bootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.epollOnlyDatagram(internetProtocolFamily());
}
@Test
public void testScatteringReadPartial(TestInfo testInfo) throws Throwable {
run(testInfo, new Runner<Bootstrap, Bootstrap>() {
@Override
public void run(Bootstrap bootstrap, Bootstrap bootstrap2) throws Throwable {
testScatteringReadPartial(bootstrap, bootstrap2);
}
});
}
public void testScatteringReadPartial(Bootstrap sb, Bootstrap cb) throws Throwable {
testScatteringRead(sb, cb, false, true);
}
@Test
public void testScatteringRead(TestInfo testInfo) throws Throwable {
run(testInfo, new Runner<Bootstrap, Bootstrap>() {
@Override
public void run(Bootstrap bootstrap, Bootstrap bootstrap2) throws Throwable {
testScatteringRead(bootstrap, bootstrap2);
}
});
}
public void testScatteringRead(Bootstrap sb, Bootstrap cb) throws Throwable {
testScatteringRead(sb, cb, false, false);
}
@Test
public void testScatteringReadConnectedPartial(TestInfo testInfo) throws Throwable {
run(testInfo, new Runner<Bootstrap, Bootstrap>() {
@Override
public void run(Bootstrap bootstrap, Bootstrap bootstrap2) throws Throwable {
testScatteringReadConnectedPartial(bootstrap, bootstrap2);
}
});
}
public void testScatteringReadConnectedPartial(Bootstrap sb, Bootstrap cb) throws Throwable {
testScatteringRead(sb, cb, true, true);
}
@Test
public void testScatteringConnectedRead(TestInfo testInfo) throws Throwable {
run(testInfo, new Runner<Bootstrap, Bootstrap>() {
@Override
public void run(Bootstrap bootstrap, Bootstrap bootstrap2) throws Throwable {
testScatteringConnectedRead(bootstrap, bootstrap2);
}
});
}
public void testScatteringConnectedRead(Bootstrap sb, Bootstrap cb) throws Throwable {
testScatteringRead(sb, cb, true, false);
}
private void testScatteringRead(Bootstrap sb, Bootstrap cb, boolean connected, boolean partial) throws Throwable {
int packetSize = 8;
int numPackets = 4;
sb.option(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(
packetSize, packetSize * (partial ? numPackets / 2 : numPackets), 64 * 1024));
// Set the MAX_DATAGRAM_PAYLOAD_SIZE to something bigger then the actual packet size.
// This will allow us to check if we correctly thread the received len.
sb.option(EpollChannelOption.MAX_DATAGRAM_PAYLOAD_SIZE, packetSize * 2);
Channel sc = null;
Channel cc = null;
try {
cb.handler(new SimpleChannelInboundHandler<Object>() {
@Override
public void channelRead0(ChannelHandlerContext ctx, Object msgs) throws Exception {
// Nothing will be sent.
}
});
cc = cb.bind(newSocketAddress()).sync().channel();
final SocketAddress ccAddress = cc.localAddress();
final AtomicReference<Throwable> errorRef = new AtomicReference<Throwable>();
final CountDownLatch latch = new CountDownLatch(numPackets);
sb.handler(new SimpleChannelInboundHandler<DatagramPacket>() {
private long numRead;
private int counter;
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
assertTrue(counter > 1);
counter = 0;
ctx.read();
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) {
assertEquals(ccAddress, msg.sender());
// Each packet contains a long which represent the write iteration.
assertEquals(8, msg.content().readableBytes());
assertEquals(numRead, msg.content().readLong());
numRead++;
counter++;
latch.countDown();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
errorRef.compareAndSet(null, cause);
}
});
sb.option(ChannelOption.AUTO_READ, false);
sc = sb.bind(newSocketAddress()).sync().channel();
if (connected) {
sc.connect(cc.localAddress()).syncUninterruptibly();
}
InetSocketAddress addr = (InetSocketAddress) sc.localAddress();
List<ChannelFuture> futures = new ArrayList<ChannelFuture>(numPackets);
for (int i = 0; i < numPackets; i++) {
futures.add(cc.write(new DatagramPacket(cc.alloc().directBuffer().writeLong(i), addr)));
}
cc.flush();
for (ChannelFuture f: futures) {
f.sync();
}
// Enable autoread now which also triggers a read, this should cause scattering reads (recvmmsg) to happen.
sc.config().setAutoRead(true);
if (!latch.await(10, TimeUnit.SECONDS)) {
Throwable error = errorRef.get();
if (error != null) {
throw error;
}
fail("Timeout while waiting for packets");
}
} finally {
if (cc != null) {
cc.close().syncUninterruptibly();
}
if (sc != null) {
sc.close().syncUninterruptibly();
}
}
}
@Test
public void testScatteringReadWithSmallBuffer(TestInfo testInfo) throws Throwable {
run(testInfo, new Runner<Bootstrap, Bootstrap>() {
@Override
public void run(Bootstrap bootstrap, Bootstrap bootstrap2) throws Throwable {
testScatteringReadWithSmallBuffer(bootstrap, bootstrap2);
}
});
}
public void testScatteringReadWithSmallBuffer(Bootstrap sb, Bootstrap cb) throws Throwable {
testScatteringReadWithSmallBuffer0(sb, cb, false);
}
@Test
public void testScatteringConnectedReadWithSmallBuffer(TestInfo testInfo) throws Throwable {
run(testInfo, new Runner<Bootstrap, Bootstrap>() {
@Override
public void run(Bootstrap bootstrap, Bootstrap bootstrap2) throws Throwable {
testScatteringConnectedReadWithSmallBuffer(bootstrap, bootstrap2);
}
});
}
public void testScatteringConnectedReadWithSmallBuffer(Bootstrap sb, Bootstrap cb) throws Throwable {
testScatteringReadWithSmallBuffer0(sb, cb, true);
}
private void testScatteringReadWithSmallBuffer0(Bootstrap sb, Bootstrap cb, boolean connected) throws Throwable {
int packetSize = 16;
sb.option(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(1400, 1400, 64 * 1024));
sb.option(EpollChannelOption.MAX_DATAGRAM_PAYLOAD_SIZE, 1400);
Channel sc = null;
Channel cc = null;
try {
cb.handler(new SimpleChannelInboundHandler<Object>() {
@Override
public void channelRead0(ChannelHandlerContext ctx, Object msgs) {
// Nothing will be sent.
}
});
cc = cb.bind(newSocketAddress()).sync().channel();
final SocketAddress ccAddress = cc.localAddress();
final AtomicReference<Throwable> errorRef = new AtomicReference<Throwable>();
final byte[] bytes = new byte[packetSize];
PlatformDependent.threadLocalRandom().nextBytes(bytes);
final CountDownLatch latch = new CountDownLatch(1);
sb.handler(new SimpleChannelInboundHandler<DatagramPacket>() {
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) {
assertEquals(ccAddress, msg.sender());
assertEquals(bytes.length, msg.content().readableBytes());
byte[] receivedBytes = new byte[bytes.length];
msg.content().readBytes(receivedBytes);
assertArrayEquals(bytes, receivedBytes);
latch.countDown();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
errorRef.compareAndSet(null, cause);
}
});
sc = sb.bind(newSocketAddress()).sync().channel();
if (connected) {
sc.connect(cc.localAddress()).syncUninterruptibly();
}
InetSocketAddress addr = (InetSocketAddress) sc.localAddress();
cc.writeAndFlush(new DatagramPacket(cc.alloc().directBuffer().writeBytes(bytes), addr)).sync();
if (!latch.await(10, TimeUnit.SECONDS)) {
Throwable error = errorRef.get();
if (error != null) {
throw error;
}
fail("Timeout while waiting for packets");
}
} finally {
if (cc != null) {
cc.close().syncUninterruptibly();
}
if (sc != null) {
sc.close().syncUninterruptibly();
}
}
}
}

View file

@ -0,0 +1,29 @@
/*
* Copyright 2019 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.testsuite.transport.TestsuitePermutation.BootstrapComboFactory;
import io.netty.testsuite.transport.socket.DatagramUnicastIPv6MappedTest;
import java.util.List;
public class EpollDatagramUnicastIPv6MappedTest extends DatagramUnicastIPv6MappedTest {
@Override
protected List<BootstrapComboFactory<Bootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.datagram(internetProtocolFamily());
}
}

View file

@ -0,0 +1,29 @@
/*
* Copyright 2019 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.DatagramUnicastIPv6Test;
import java.util.List;
public class EpollDatagramUnicastIPv6Test extends DatagramUnicastIPv6Test {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<Bootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.datagram(internetProtocolFamily());
}
}

View file

@ -0,0 +1,190 @@
/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.CompositeByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOption;
import io.netty.channel.FixedRecvByteBufAllocator;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.InternetProtocolFamily;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.DatagramUnicastInetTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import java.net.InetSocketAddress;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
public class EpollDatagramUnicastTest extends DatagramUnicastInetTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<Bootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.datagram(InternetProtocolFamily.IPv4);
}
public void testSimpleSendWithConnect(Bootstrap sb, Bootstrap cb) throws Throwable {
// Run this test with IP_RECVORIGDSTADDR option enabled
sb.option(EpollChannelOption.IP_RECVORIGDSTADDR, true);
super.testSimpleSendWithConnect(sb, cb);
sb.option(EpollChannelOption.IP_RECVORIGDSTADDR, false);
}
@Test
public void testSendSegmentedDatagramPacket(TestInfo testInfo) throws Throwable {
run(testInfo, new Runner<Bootstrap, Bootstrap>() {
@Override
public void run(Bootstrap bootstrap, Bootstrap bootstrap2) throws Throwable {
testSendSegmentedDatagramPacket(bootstrap, bootstrap2);
}
});
}
public void testSendSegmentedDatagramPacket(Bootstrap sb, Bootstrap cb) throws Throwable {
testSegmentedDatagramPacket(sb, cb, false, false);
}
@Test
public void testSendSegmentedDatagramPacketComposite(TestInfo testInfo) throws Throwable {
run(testInfo, new Runner<Bootstrap, Bootstrap>() {
@Override
public void run(Bootstrap bootstrap, Bootstrap bootstrap2) throws Throwable {
testSendSegmentedDatagramPacketComposite(bootstrap, bootstrap2);
}
});
}
public void testSendSegmentedDatagramPacketComposite(Bootstrap sb, Bootstrap cb) throws Throwable {
testSegmentedDatagramPacket(sb, cb, true, false);
}
@Test
public void testSendAndReceiveSegmentedDatagramPacket(TestInfo testInfo) throws Throwable {
run(testInfo, new Runner<Bootstrap, Bootstrap>() {
@Override
public void run(Bootstrap bootstrap, Bootstrap bootstrap2) throws Throwable {
testSendAndReceiveSegmentedDatagramPacket(bootstrap, bootstrap2);
}
});
}
public void testSendAndReceiveSegmentedDatagramPacket(Bootstrap sb, Bootstrap cb) throws Throwable {
testSegmentedDatagramPacket(sb, cb, false, true);
}
@Test
public void testSendAndReceiveSegmentedDatagramPacketComposite(TestInfo testInfo) throws Throwable {
run(testInfo, new Runner<Bootstrap, Bootstrap>() {
@Override
public void run(Bootstrap bootstrap, Bootstrap bootstrap2) throws Throwable {
testSendAndReceiveSegmentedDatagramPacketComposite(bootstrap, bootstrap2);
}
});
}
public void testSendAndReceiveSegmentedDatagramPacketComposite(Bootstrap sb, Bootstrap cb) throws Throwable {
testSegmentedDatagramPacket(sb, cb, true, true);
}
private void testSegmentedDatagramPacket(Bootstrap sb, Bootstrap cb, boolean composite, boolean gro)
throws Throwable {
if (!(cb.group() instanceof EpollEventLoopGroup)) {
// Only supported for the native epoll transport.
return;
}
if (gro && !(sb.group() instanceof EpollEventLoopGroup)) {
// Only supported for the native epoll transport.
return;
}
assumeTrue(EpollDatagramChannel.isSegmentedDatagramPacketSupported());
Channel sc = null;
Channel cc = null;
try {
cb.handler(new SimpleChannelInboundHandler<Object>() {
@Override
public void channelRead0(ChannelHandlerContext ctx, Object msgs) {
// Nothing will be sent.
}
});
cc = cb.bind(newSocketAddress()).sync().channel();
final int numBuffers = 16;
final int segmentSize = 512;
int bufferCapacity = numBuffers * segmentSize;
final CountDownLatch latch = new CountDownLatch(numBuffers);
AtomicReference<Throwable> errorRef = new AtomicReference<Throwable>();
if (gro) {
// Enable GRO and also ensure we can read everything with one read as otherwise
// we will drop things on the floor.
sb.option(EpollChannelOption.UDP_GRO, true);
sb.option(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(bufferCapacity));
}
sc = sb.handler(new SimpleChannelInboundHandler<DatagramPacket>() {
@Override
public void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) {
if (packet.content().readableBytes() == segmentSize) {
latch.countDown();
}
}
}).bind(newSocketAddress()).sync().channel();
if (sc instanceof EpollDatagramChannel) {
assertEquals(gro, sc.config().getOption(EpollChannelOption.UDP_GRO));
}
InetSocketAddress addr = sendToAddress((InetSocketAddress) sc.localAddress());
final ByteBuf buffer;
if (composite) {
CompositeByteBuf compositeBuffer = Unpooled.compositeBuffer();
for (int i = 0; i < numBuffers; i++) {
compositeBuffer.addComponent(true,
Unpooled.directBuffer(segmentSize).writeZero(segmentSize));
}
buffer = compositeBuffer;
} else {
buffer = Unpooled.directBuffer(bufferCapacity).writeZero(bufferCapacity);
}
cc.writeAndFlush(new io.netty.channel.unix.SegmentedDatagramPacket(buffer, segmentSize, addr)).sync();
if (!latch.await(10, TimeUnit.SECONDS)) {
Throwable error = errorRef.get();
if (error != null) {
throw error;
}
fail();
}
} finally {
if (cc != null) {
cc.close().sync();
}
if (sc != null) {
sc.close().sync();
}
}
}
}

View file

@ -0,0 +1,37 @@
/*
* Copyright 2017 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.ServerChannel;
public class EpollDetectPeerCloseWithoutReadTest extends DetectPeerCloseWithoutReadTest {
@Override
protected EventLoopGroup newGroup() {
return new EpollEventLoopGroup(2);
}
@Override
protected Class<? extends ServerChannel> serverChannel() {
return EpollServerSocketChannel.class;
}
@Override
protected Class<? extends Channel> clientChannel() {
return EpollSocketChannel.class;
}
}

View file

@ -0,0 +1,36 @@
/*
* Copyright 2023 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class EpollDomainDatagramChannelTest {
@BeforeEach
public void setUp() {
Epoll.ensureAvailability();
}
@Test
public void testDefaultMaxMessagePerRead() {
EpollDomainDatagramChannel channel = new EpollDomainDatagramChannel();
assertEquals(16, channel.config().getMaxMessagesPerRead());
channel.unsafe().closeForcibly();
}
}

View file

@ -0,0 +1,76 @@
/*
* Copyright 2021 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.unix.DomainDatagramPacket;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.AbstractClientSocketTest;
import io.netty.util.CharsetUtil;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import java.io.FileNotFoundException;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
class EpollDomainDatagramPathTest extends AbstractClientSocketTest {
@Test
void testConnectPathDoesNotExist(TestInfo testInfo) throws Throwable {
run(testInfo, new Runner<Bootstrap>() {
@Override
public void run(Bootstrap bootstrap) {
try {
bootstrap.handler(new ChannelInboundHandlerAdapter())
.connect(EpollSocketTestPermutation.newDomainSocketAddress()).sync().channel();
fail("Expected FileNotFoundException");
} catch (Exception e) {
assertTrue(e instanceof FileNotFoundException);
}
}
});
}
@Test
void testWriteReceiverPathDoesNotExist(TestInfo testInfo) throws Throwable {
run(testInfo, new Runner<Bootstrap>() {
@Override
public void run(Bootstrap bootstrap) {
try {
Channel ch = bootstrap.handler(new ChannelInboundHandlerAdapter())
.bind(EpollSocketTestPermutation.newDomainSocketAddress()).sync().channel();
ch.writeAndFlush(new DomainDatagramPacket(
Unpooled.copiedBuffer("test", CharsetUtil.US_ASCII),
EpollSocketTestPermutation.newDomainSocketAddress())).sync();
fail("Expected FileNotFoundException");
} catch (Exception e) {
assertTrue(e instanceof FileNotFoundException);
}
}
});
}
@Override
protected List<TestsuitePermutation.BootstrapFactory<Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.domainDatagramSocket();
}
}

View file

@ -0,0 +1,168 @@
/*
* Copyright 2021 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.unix.DomainDatagramChannel;
import io.netty.channel.unix.DomainDatagramPacket;
import io.netty.channel.unix.DomainSocketAddress;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.DatagramUnicastTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import java.net.SocketAddress;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
class EpollDomainDatagramUnicastTest extends DatagramUnicastTest {
@Test
void testBind(TestInfo testInfo) throws Throwable {
run(testInfo, new Runner<Bootstrap, Bootstrap>() {
@Override
public void run(Bootstrap bootstrap, Bootstrap bootstrap2) throws Throwable {
testBind(bootstrap2);
}
});
}
private void testBind(Bootstrap cb) throws Throwable {
Channel channel = null;
try {
channel = cb.handler(new ChannelInboundHandlerAdapter())
.bind(newSocketAddress()).sync().channel();
assertThat(channel.localAddress()).isNotNull()
.isInstanceOf(DomainSocketAddress.class);
} finally {
closeChannel(channel);
}
}
@Override
protected boolean supportDisconnect() {
return false;
}
@Override
protected boolean isConnected(Channel channel) {
return ((DomainDatagramChannel) channel).isConnected();
}
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<Bootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.domainDatagram();
}
@Override
protected SocketAddress newSocketAddress() {
return EpollSocketTestPermutation.newDomainSocketAddress();
}
@Override
protected Channel setupClientChannel(Bootstrap cb, final byte[] bytes, final CountDownLatch latch,
final AtomicReference<Throwable> errorRef) throws Throwable {
cb.handler(new SimpleChannelInboundHandler<DomainDatagramPacket>() {
@Override
public void channelRead0(ChannelHandlerContext ctx, DomainDatagramPacket msg) {
try {
ByteBuf buf = msg.content();
assertEquals(bytes.length, buf.readableBytes());
for (int i = 0; i < bytes.length; i++) {
assertEquals(bytes[i], buf.getByte(buf.readerIndex() + i));
}
assertEquals(ctx.channel().localAddress(), msg.recipient());
} finally {
latch.countDown();
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
errorRef.compareAndSet(null, cause);
}
});
return cb.bind(newSocketAddress()).sync().channel();
}
@Override
protected Channel setupServerChannel(Bootstrap sb, final byte[] bytes, final SocketAddress sender,
final CountDownLatch latch, final AtomicReference<Throwable> errorRef,
final boolean echo) throws Throwable {
sb.handler(new SimpleChannelInboundHandler<DomainDatagramPacket>() {
@Override
public void channelRead0(ChannelHandlerContext ctx, DomainDatagramPacket msg) {
try {
if (sender == null) {
assertNotNull(msg.sender());
} else {
assertEquals(sender, msg.sender());
}
ByteBuf buf = msg.content();
assertEquals(bytes.length, buf.readableBytes());
for (int i = 0; i < bytes.length; i++) {
assertEquals(bytes[i], buf.getByte(buf.readerIndex() + i));
}
assertEquals(ctx.channel().localAddress(), msg.recipient());
if (echo) {
ctx.writeAndFlush(new DomainDatagramPacket(buf.retainedDuplicate(), msg.sender()));
}
} finally {
latch.countDown();
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
errorRef.compareAndSet(null, cause);
}
});
return sb.bind(newSocketAddress()).sync().channel();
}
@Override
protected ChannelFuture write(Channel cc, ByteBuf buf, SocketAddress remote, WrapType wrapType) {
switch (wrapType) {
case DUP:
return cc.write(new DomainDatagramPacket(buf.retainedDuplicate(), (DomainSocketAddress) remote));
case SLICE:
return cc.write(new DomainDatagramPacket(buf.retainedSlice(), (DomainSocketAddress) remote));
case READ_ONLY:
return cc.write(new DomainDatagramPacket(buf.retain().asReadOnly(), (DomainSocketAddress) remote));
case NONE:
return cc.write(new DomainDatagramPacket(buf.retain(), (DomainSocketAddress) remote));
default:
throw new Error("unknown wrap type: " + wrapType);
}
}
}

View file

@ -0,0 +1,45 @@
/*
* Copyright 2023 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.unix.DomainSocketAddress;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketAddressesTest;
import java.net.SocketAddress;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertNotNull;
class EpollDomainSocketAddressesTest extends SocketAddressesTest {
@Override
protected SocketAddress newSocketAddress() {
return EpollSocketTestPermutation.newDomainSocketAddress();
}
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.domainSocket();
}
@Override
protected void assertAddress(SocketAddress address) {
assertNotNull(((DomainSocketAddress) address).path());
}
}

View file

@ -0,0 +1,36 @@
/*
* Copyright 2018 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketDataReadInitialStateTest;
import java.net.SocketAddress;
import java.util.List;
public class EpollDomainSocketDataReadInitialStateTest extends SocketDataReadInitialStateTest {
@Override
protected SocketAddress newSocketAddress() {
return EpollSocketTestPermutation.newDomainSocketAddress();
}
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.domainSocket();
}
}

View file

@ -0,0 +1,35 @@
/*
* Copyright 2015 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import java.net.SocketAddress;
import java.util.List;
public class EpollDomainSocketEchoTest extends EpollSocketEchoTest {
@Override
protected SocketAddress newSocketAddress() {
return EpollSocketTestPermutation.newDomainSocketAddress();
}
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.domainSocket();
}
}

View file

@ -0,0 +1,116 @@
/*
* Copyright 2015 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.unix.DomainSocketReadMode;
import io.netty.channel.unix.FileDescriptor;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.AbstractSocketTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.Timeout;
import java.net.SocketAddress;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class EpollDomainSocketFdTest extends AbstractSocketTest {
@Override
protected SocketAddress newSocketAddress() {
return EpollSocketTestPermutation.newDomainSocketAddress();
}
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.domainSocket();
}
@Test
@Timeout(value = 30000, unit = TimeUnit.MILLISECONDS)
public void testSendRecvFd(TestInfo testInfo) throws Throwable {
run(testInfo, new Runner<ServerBootstrap, Bootstrap>() {
@Override
public void run(ServerBootstrap serverBootstrap, Bootstrap bootstrap) throws Throwable {
testSendRecvFd(serverBootstrap, bootstrap);
}
});
}
public void testSendRecvFd(ServerBootstrap sb, Bootstrap cb) throws Throwable {
final BlockingQueue<Object> queue = new LinkedBlockingQueue<Object>(1);
sb.childHandler(new ChannelInboundHandlerAdapter() {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// Create new channel and obtain a file descriptor from it.
final EpollDomainSocketChannel ch = new EpollDomainSocketChannel();
ctx.writeAndFlush(ch.fd()).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
Throwable cause = future.cause();
queue.offer(cause);
}
}
});
}
});
cb.handler(new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
FileDescriptor fd = (FileDescriptor) msg;
queue.offer(fd);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
queue.add(cause);
ctx.close();
}
});
cb.option(EpollChannelOption.DOMAIN_SOCKET_READ_MODE,
DomainSocketReadMode.FILE_DESCRIPTORS);
Channel sc = sb.bind().sync().channel();
Channel cc = cb.connect(sc.localAddress()).sync().channel();
Object received = queue.take();
cc.close().sync();
sc.close().sync();
if (received instanceof FileDescriptor) {
FileDescriptor fd = (FileDescriptor) received;
assertTrue(fd.isOpen());
fd.close();
assertFalse(fd.isOpen());
assertNull(queue.poll());
} else {
throw (Throwable) received;
}
}
}

View file

@ -0,0 +1,35 @@
/*
* Copyright 2015 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import java.net.SocketAddress;
import java.util.List;
public class EpollDomainSocketFileRegionTest extends EpollSocketFileRegionTest {
@Override
protected SocketAddress newSocketAddress() {
return EpollSocketTestPermutation.newDomainSocketAddress();
}
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.domainSocket();
}
}

View file

@ -0,0 +1,37 @@
/*
* Copyright 2015 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketFixedLengthEchoTest;
import java.net.SocketAddress;
import java.util.List;
public class EpollDomainSocketFixedLengthEchoTest extends SocketFixedLengthEchoTest {
@Override
protected SocketAddress newSocketAddress() {
return EpollSocketTestPermutation.newDomainSocketAddress();
}
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.domainSocket();
}
}

View file

@ -0,0 +1,37 @@
/*
* Copyright 2015 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketGatheringWriteTest;
import java.net.SocketAddress;
import java.util.List;
public class EpollDomainSocketGatheringWriteTest extends SocketGatheringWriteTest {
@Override
protected SocketAddress newSocketAddress() {
return EpollSocketTestPermutation.newDomainSocketAddress();
}
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.domainSocket();
}
}

View file

@ -0,0 +1,36 @@
/*
* Copyright 2015 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketObjectEchoTest;
import java.net.SocketAddress;
import java.util.List;
public class EpollDomainSocketObjectEchoTest extends SocketObjectEchoTest {
@Override
protected SocketAddress newSocketAddress() {
return EpollSocketTestPermutation.newDomainSocketAddress();
}
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.domainSocket();
}
}

View file

@ -0,0 +1,36 @@
/*
* Copyright 2019 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.AbstractSocketReuseFdTest;
import java.net.SocketAddress;
import java.util.List;
public class EpollDomainSocketReuseFdTest extends AbstractSocketReuseFdTest {
@Override
protected SocketAddress newSocketAddress() {
return EpollSocketTestPermutation.newDomainSocketAddress();
}
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.domainSocket();
}
}

View file

@ -0,0 +1,69 @@
/*
* Copyright 2019 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.unix.Buffer;
import io.netty.testsuite.transport.TestsuitePermutation.BootstrapFactory;
import io.netty.testsuite.transport.socket.AbstractSocketShutdownOutputByPeerTest;
import java.io.IOException;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.util.List;
public class EpollDomainSocketShutdownOutputByPeerTest extends AbstractSocketShutdownOutputByPeerTest<LinuxSocket> {
@Override
protected List<BootstrapFactory<ServerBootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.serverDomainSocket();
}
@Override
protected SocketAddress newSocketAddress() {
return EpollSocketTestPermutation.newDomainSocketAddress();
}
@Override
protected void shutdownOutput(LinuxSocket s) throws IOException {
s.shutdown(false, true);
}
@Override
protected void connect(LinuxSocket s, SocketAddress address) throws IOException {
s.connect(address);
}
@Override
protected void close(LinuxSocket s) throws IOException {
s.close();
}
@Override
protected void write(LinuxSocket s, int data) throws IOException {
final ByteBuffer buf = Buffer.allocateDirectWithNativeOrder(4);
buf.putInt(data);
buf.flip();
s.send(buf, buf.position(), buf.limit());
Buffer.free(buf);
}
@Override
protected LinuxSocket newSocket() {
return LinuxSocket.newSocketDomain();
}
}

View file

@ -0,0 +1,36 @@
/*
* Copyright 2019 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketSslClientRenegotiateTest;
import java.net.SocketAddress;
import java.util.List;
public class EpollDomainSocketSslClientRenegotiateTest extends SocketSslClientRenegotiateTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.domainSocket();
}
@Override
protected SocketAddress newSocketAddress() {
return EpollSocketTestPermutation.newDomainSocketAddress();
}
}

View file

@ -0,0 +1,36 @@
/*
* Copyright 2015 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketSslEchoTest;
import java.net.SocketAddress;
import java.util.List;
public class EpollDomainSocketSslEchoTest extends SocketSslEchoTest {
@Override
protected SocketAddress newSocketAddress() {
return EpollSocketTestPermutation.newDomainSocketAddress();
}
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.domainSocket();
}
}

View file

@ -0,0 +1,36 @@
/*
* Copyright 2015 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketSslGreetingTest;
import java.net.SocketAddress;
import java.util.List;
public class EpollDomainSocketSslGreetingTest extends SocketSslGreetingTest {
@Override
protected SocketAddress newSocketAddress() {
return EpollSocketTestPermutation.newDomainSocketAddress();
}
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.domainSocket();
}
}

View file

@ -0,0 +1,36 @@
/*
* Copyright 2015 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketStartTlsTest;
import java.net.SocketAddress;
import java.util.List;
public class EpollDomainSocketStartTlsTest extends SocketStartTlsTest {
@Override
protected SocketAddress newSocketAddress() {
return EpollSocketTestPermutation.newDomainSocketAddress();
}
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.domainSocket();
}
}

View file

@ -0,0 +1,36 @@
/*
* Copyright 2015 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketStringEchoTest;
import java.net.SocketAddress;
import java.util.List;
public class EpollDomainSocketStringEchoTest extends SocketStringEchoTest {
@Override
protected SocketAddress newSocketAddress() {
return EpollSocketTestPermutation.newDomainSocketAddress();
}
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.domainSocket();
}
}

View file

@ -0,0 +1,39 @@
/*
* Copyright 2016 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBufAllocator;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketAutoReadTest;
import java.util.List;
public class EpollETSocketAutoReadTest extends SocketAutoReadTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithFastOpen();
}
@Override
protected void configure(ServerBootstrap bootstrap, Bootstrap bootstrap2, ByteBufAllocator allocator) {
super.configure(bootstrap, bootstrap2, allocator);
bootstrap.option(EpollChannelOption.EPOLL_MODE, EpollMode.EDGE_TRIGGERED)
.childOption(EpollChannelOption.EPOLL_MODE, EpollMode.EDGE_TRIGGERED);
bootstrap2.option(EpollChannelOption.EPOLL_MODE, EpollMode.EDGE_TRIGGERED);
}
}

View file

@ -0,0 +1,39 @@
/*
* Copyright 2018 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBufAllocator;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketConditionalWritabilityTest;
import java.util.List;
public class EpollETSocketConditionalWritabilityTest extends SocketConditionalWritabilityTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithFastOpen();
}
@Override
protected void configure(ServerBootstrap bootstrap, Bootstrap bootstrap2, ByteBufAllocator allocator) {
super.configure(bootstrap, bootstrap2, allocator);
bootstrap.option(EpollChannelOption.EPOLL_MODE, EpollMode.EDGE_TRIGGERED)
.childOption(EpollChannelOption.EPOLL_MODE, EpollMode.EDGE_TRIGGERED);
bootstrap2.option(EpollChannelOption.EPOLL_MODE, EpollMode.EDGE_TRIGGERED);
}
}

View file

@ -0,0 +1,39 @@
/*
* Copyright 2018 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBufAllocator;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketDataReadInitialStateTest;
import java.util.List;
public class EpollETSocketDataReadInitialStateTest extends SocketDataReadInitialStateTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithFastOpen();
}
@Override
protected void configure(ServerBootstrap bootstrap, Bootstrap bootstrap2, ByteBufAllocator allocator) {
super.configure(bootstrap, bootstrap2, allocator);
bootstrap.option(EpollChannelOption.EPOLL_MODE, EpollMode.EDGE_TRIGGERED)
.childOption(EpollChannelOption.EPOLL_MODE, EpollMode.EDGE_TRIGGERED);
bootstrap2.option(EpollChannelOption.EPOLL_MODE, EpollMode.EDGE_TRIGGERED);
}
}

View file

@ -0,0 +1,39 @@
/*
* Copyright 2016 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBufAllocator;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketExceptionHandlingTest;
import java.util.List;
public class EpollETSocketExceptionHandlingTest extends SocketExceptionHandlingTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithFastOpen();
}
@Override
protected void configure(ServerBootstrap bootstrap, Bootstrap bootstrap2, ByteBufAllocator allocator) {
super.configure(bootstrap, bootstrap2, allocator);
bootstrap.option(EpollChannelOption.EPOLL_MODE, EpollMode.EDGE_TRIGGERED)
.childOption(EpollChannelOption.EPOLL_MODE, EpollMode.EDGE_TRIGGERED);
bootstrap2.option(EpollChannelOption.EPOLL_MODE, EpollMode.EDGE_TRIGGERED);
}
}

View file

@ -0,0 +1,39 @@
/*
* Copyright 2017 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBufAllocator;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketHalfClosedTest;
import java.util.List;
public class EpollETSocketHalfClosedTest extends SocketHalfClosedTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithoutFastOpen();
}
@Override
protected void configure(ServerBootstrap bootstrap, Bootstrap bootstrap2, ByteBufAllocator allocator) {
super.configure(bootstrap, bootstrap2, allocator);
bootstrap.option(EpollChannelOption.EPOLL_MODE, EpollMode.EDGE_TRIGGERED)
.childOption(EpollChannelOption.EPOLL_MODE, EpollMode.EDGE_TRIGGERED);
bootstrap2.option(EpollChannelOption.EPOLL_MODE, EpollMode.EDGE_TRIGGERED);
}
}

View file

@ -0,0 +1,39 @@
/*
* Copyright 2016 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBufAllocator;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketReadPendingTest;
import java.util.List;
public class EpollETSocketReadPendingTest extends SocketReadPendingTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithFastOpen();
}
@Override
protected void configure(ServerBootstrap bootstrap, Bootstrap bootstrap2, ByteBufAllocator allocator) {
super.configure(bootstrap, bootstrap2, allocator);
bootstrap.option(EpollChannelOption.EPOLL_MODE, EpollMode.EDGE_TRIGGERED)
.childOption(EpollChannelOption.EPOLL_MODE, EpollMode.EDGE_TRIGGERED);
bootstrap2.option(EpollChannelOption.EPOLL_MODE, EpollMode.EDGE_TRIGGERED);
}
}

View file

@ -0,0 +1,31 @@
/*
* Copyright 2018 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBufAllocator;
public class EpollETSocketStringEchoBusyWaitTest extends EpollSocketStringEchoBusyWaitTest {
@Override
protected void configure(ServerBootstrap bootstrap, Bootstrap bootstrap2, ByteBufAllocator allocator) {
super.configure(bootstrap, bootstrap2, allocator);
bootstrap.option(EpollChannelOption.EPOLL_MODE, EpollMode.EDGE_TRIGGERED)
.childOption(EpollChannelOption.EPOLL_MODE, EpollMode.EDGE_TRIGGERED);
bootstrap2.option(EpollChannelOption.EPOLL_MODE, EpollMode.EDGE_TRIGGERED);
}
}

View file

@ -0,0 +1,189 @@
/*
* Copyright 2017 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.testsuite.transport.AbstractSingleThreadEventLoopTest;
import io.netty.channel.DefaultSelectStrategyFactory;
import io.netty.channel.EventLoop;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.ServerChannel;
import io.netty.channel.socket.ServerSocketChannel;
import io.netty.channel.unix.FileDescriptor;
import io.netty.util.concurrent.DefaultThreadFactory;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.RejectedExecutionHandlers;
import io.netty.util.concurrent.ThreadPerTaskExecutor;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class EpollEventLoopTest extends AbstractSingleThreadEventLoopTest {
@Override
protected boolean supportsChannelIteration() {
return true;
}
@Override
protected EventLoopGroup newEventLoopGroup() {
return new EpollEventLoopGroup();
}
@Override
protected ServerSocketChannel newChannel() {
return new EpollServerSocketChannel();
}
@Override
protected Class<? extends ServerChannel> serverChannelClass() {
return EpollServerSocketChannel.class;
}
@Test
public void testScheduleBigDelayNotOverflow() {
final AtomicReference<Throwable> capture = new AtomicReference<Throwable>();
final EventLoopGroup group = new EpollEventLoop(null,
new ThreadPerTaskExecutor(new DefaultThreadFactory(getClass())), 0,
DefaultSelectStrategyFactory.INSTANCE.newSelectStrategy(), RejectedExecutionHandlers.reject(),
null, null) {
@Override
void handleLoopException(Throwable t) {
capture.set(t);
super.handleLoopException(t);
}
};
try {
final EventLoop eventLoop = group.next();
Future<?> future = eventLoop.schedule(new Runnable() {
@Override
public void run() {
// NOOP
}
}, Long.MAX_VALUE, TimeUnit.MILLISECONDS);
assertFalse(future.awaitUninterruptibly(1000));
assertTrue(future.cancel(true));
assertNull(capture.get());
} finally {
group.shutdownGracefully();
}
}
@Test
public void testEventFDETSemantics() throws Throwable {
final FileDescriptor epoll = Native.newEpollCreate();
final FileDescriptor eventFd = Native.newEventFd();
final FileDescriptor timerFd = Native.newTimerFd();
final EpollEventArray array = new EpollEventArray(1024);
try {
Native.epollCtlAdd(epoll.intValue(), eventFd.intValue(), Native.EPOLLIN | Native.EPOLLET);
final AtomicReference<Throwable> causeRef = new AtomicReference<Throwable>();
final AtomicInteger integer = new AtomicInteger();
final Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
for (int i = 0; i < 2; i++) {
int ready = Native.epollWait(epoll, array, timerFd, -1, -1);
assertEquals(1, ready);
assertEquals(eventFd.intValue(), array.fd(0));
integer.incrementAndGet();
}
} catch (IOException e) {
causeRef.set(e);
}
}
});
t.start();
Native.eventFdWrite(eventFd.intValue(), 1);
// Spin until we was the wakeup.
while (integer.get() != 1) {
Thread.sleep(10);
}
// Sleep for a short moment to ensure there is not other wakeup.
Thread.sleep(1000);
assertEquals(1, integer.get());
Native.eventFdWrite(eventFd.intValue(), 1);
t.join();
Throwable cause = causeRef.get();
if (cause != null) {
throw cause;
}
assertEquals(2, integer.get());
} finally {
array.free();
epoll.close();
eventFd.close();
timerFd.close();
}
}
@Test
public void testResultNoTimeoutCorrectlyEncoded() throws Throwable {
final FileDescriptor epoll = Native.newEpollCreate();
final FileDescriptor eventFd = Native.newEventFd();
final FileDescriptor timerFd = Native.newTimerFd();
final EpollEventArray array = new EpollEventArray(1024);
try {
Native.epollCtlAdd(epoll.intValue(), eventFd.intValue(), Native.EPOLLIN | Native.EPOLLET);
final AtomicReference<Throwable> causeRef = new AtomicReference<Throwable>();
final Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
for (;;) {
long ready = Native.epollWait(epoll, array, timerFd, 0, 0, 10);
if (ready > 0) {
assertEquals(1, Native.epollReady(ready));
assertEquals(eventFd.intValue(), array.fd(0));
return;
}
Thread.sleep(100);
}
} catch (IOException e) {
causeRef.set(e);
} catch (InterruptedException ignore) {
// ignore
}
}
});
t.start();
Native.eventFdWrite(eventFd.intValue(), 1);
t.join();
Throwable cause = causeRef.get();
if (cause != null) {
throw cause;
}
} finally {
array.free();
epoll.close();
eventFd.close();
timerFd.close();
}
}
}

View file

@ -0,0 +1,25 @@
/*
* Copyright 2021 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import java.net.SocketAddress;
public class EpollJdkLoopbackSocketSslEchoTest extends EpollSocketSslEchoTest {
@Override
protected SocketAddress newSocketAddress() {
return UnixTestUtils.newInetLoopbackSocketAddress();
}
}

View file

@ -0,0 +1,26 @@
/*
* Copyright 2020 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import org.junit.jupiter.api.BeforeAll;
public class EpollKQueueIovArrayTest extends IovArrayTest {
@BeforeAll
public static void loadNative() {
Epoll.ensureAvailability();
}
}

View file

@ -0,0 +1,39 @@
/*
* Copyright 2016 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBufAllocator;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketAutoReadTest;
import java.util.List;
public class EpollLTSocketAutoReadTest extends SocketAutoReadTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithFastOpen();
}
@Override
protected void configure(ServerBootstrap bootstrap, Bootstrap bootstrap2, ByteBufAllocator allocator) {
super.configure(bootstrap, bootstrap2, allocator);
bootstrap.option(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED)
.childOption(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED);
bootstrap2.option(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED);
}
}

View file

@ -0,0 +1,39 @@
/*
* Copyright 2018 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBufAllocator;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketConditionalWritabilityTest;
import java.util.List;
public class EpollLTSocketConditionalWritabilityTest extends SocketConditionalWritabilityTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithFastOpen();
}
@Override
protected void configure(ServerBootstrap bootstrap, Bootstrap bootstrap2, ByteBufAllocator allocator) {
super.configure(bootstrap, bootstrap2, allocator);
bootstrap.option(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED)
.childOption(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED);
bootstrap2.option(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED);
}
}

View file

@ -0,0 +1,39 @@
/*
* Copyright 2018 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBufAllocator;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketDataReadInitialStateTest;
import java.util.List;
public class EpollLTSocketDataReadInitialStateTest extends SocketDataReadInitialStateTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithFastOpen();
}
@Override
protected void configure(ServerBootstrap bootstrap, Bootstrap bootstrap2, ByteBufAllocator allocator) {
super.configure(bootstrap, bootstrap2, allocator);
bootstrap.option(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED)
.childOption(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED);
bootstrap2.option(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED);
}
}

View file

@ -0,0 +1,39 @@
/*
* Copyright 2016 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBufAllocator;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketExceptionHandlingTest;
import java.util.List;
public class EpollLTSocketExceptionHandlingTest extends SocketExceptionHandlingTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithFastOpen();
}
@Override
protected void configure(ServerBootstrap bootstrap, Bootstrap bootstrap2, ByteBufAllocator allocator) {
super.configure(bootstrap, bootstrap2, allocator);
bootstrap.option(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED)
.childOption(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED);
bootstrap2.option(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED);
}
}

View file

@ -0,0 +1,39 @@
/*
* Copyright 2017 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBufAllocator;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketHalfClosedTest;
import java.util.List;
public class EpollLTSocketHalfClosedTest extends SocketHalfClosedTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithoutFastOpen();
}
@Override
protected void configure(ServerBootstrap bootstrap, Bootstrap bootstrap2, ByteBufAllocator allocator) {
super.configure(bootstrap, bootstrap2, allocator);
bootstrap.option(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED)
.childOption(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED);
bootstrap2.option(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED);
}
}

View file

@ -0,0 +1,39 @@
/*
* Copyright 2016 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBufAllocator;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketReadPendingTest;
import java.util.List;
public class EpollLTSocketReadPendingTest extends SocketReadPendingTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithFastOpen();
}
@Override
protected void configure(ServerBootstrap bootstrap, Bootstrap bootstrap2, ByteBufAllocator allocator) {
super.configure(bootstrap, bootstrap2, allocator);
bootstrap.option(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED)
.childOption(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED);
bootstrap2.option(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED);
}
}

View file

@ -0,0 +1,31 @@
/*
* Copyright 2018 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBufAllocator;
public class EpollLTSocketStringEchoBusyWaitTest extends EpollSocketStringEchoBusyWaitTest {
@Override
protected void configure(ServerBootstrap bootstrap, Bootstrap bootstrap2, ByteBufAllocator allocator) {
super.configure(bootstrap, bootstrap2, allocator);
bootstrap.option(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED)
.childOption(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED);
bootstrap2.option(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED);
}
}

View file

@ -0,0 +1,263 @@
/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.AbstractBootstrap;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.util.NetUtil;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.ResourceLeakDetector;
import io.netty.util.internal.logging.InternalLogLevel;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
public class EpollReuseAddrTest {
private static final InternalLogger LOGGER = InternalLoggerFactory.getInstance(EpollReuseAddrTest.class);
private static final int MAJOR;
private static final int MINOR;
private static final int BUGFIX;
static {
String kernelVersion = Native.KERNEL_VERSION;
int index = kernelVersion.indexOf('-');
if (index > -1) {
kernelVersion = kernelVersion.substring(0, index);
}
String[] versionParts = kernelVersion.split("\\.");
if (versionParts.length <= 3) {
MAJOR = Integer.parseInt(versionParts[0]);
MINOR = Integer.parseInt(versionParts[1]);
if (versionParts.length == 3) {
int bugFix;
try {
bugFix = Integer.parseInt(versionParts[2]);
} catch (NumberFormatException ignore) {
// the last part of the version may include all kind of different things. Especially when
// someone compiles his / her own kernel.
// Just ignore a parse error here and use 0.
bugFix = 0;
}
BUGFIX = bugFix;
} else {
BUGFIX = 0;
}
} else {
LOGGER.log(InternalLogLevel.INFO, "Unable to parse kernel version: " + kernelVersion);
MAJOR = 0;
MINOR = 0;
BUGFIX = 0;
}
}
@Test
public void testMultipleBindSocketChannelWithoutReusePortFails() {
assumeTrue(versionEqOrGt(3, 9, 0));
testMultipleBindDatagramChannelWithoutReusePortFails0(createServerBootstrap());
}
@Test
public void testMultipleBindDatagramChannelWithoutReusePortFails() {
assumeTrue(versionEqOrGt(3, 9, 0));
testMultipleBindDatagramChannelWithoutReusePortFails0(createBootstrap());
}
private static void testMultipleBindDatagramChannelWithoutReusePortFails0(AbstractBootstrap<?, ?> bootstrap) {
bootstrap.handler(new LoggingHandler(LogLevel.ERROR));
ChannelFuture future = bootstrap.bind().syncUninterruptibly();
try {
bootstrap.bind(future.channel().localAddress()).syncUninterruptibly();
fail();
} catch (Exception e) {
assertTrue(e instanceof IOException);
}
future.channel().close().syncUninterruptibly();
}
@Test
@Timeout(value = 10000, unit = TimeUnit.MILLISECONDS)
public void testMultipleBindSocketChannel() throws Exception {
assumeTrue(versionEqOrGt(3, 9, 0));
ServerBootstrap bootstrap = createServerBootstrap();
bootstrap.option(EpollChannelOption.SO_REUSEPORT, true);
final AtomicBoolean accepted1 = new AtomicBoolean();
bootstrap.childHandler(new ServerSocketTestHandler(accepted1));
ChannelFuture future = bootstrap.bind().syncUninterruptibly();
InetSocketAddress address1 = (InetSocketAddress) future.channel().localAddress();
final AtomicBoolean accepted2 = new AtomicBoolean();
bootstrap.childHandler(new ServerSocketTestHandler(accepted2));
ChannelFuture future2 = bootstrap.bind(address1).syncUninterruptibly();
InetSocketAddress address2 = (InetSocketAddress) future2.channel().localAddress();
assertEquals(address1, address2);
while (!accepted1.get() || !accepted2.get()) {
Socket socket = new Socket(address1.getAddress(), address1.getPort());
socket.setReuseAddress(true);
socket.close();
}
future.channel().close().syncUninterruptibly();
future2.channel().close().syncUninterruptibly();
}
@Test
@Timeout(value = 10000, unit = TimeUnit.MILLISECONDS)
@Disabled // TODO: Unignore after making it pass on centos6-1 and debian7-1
public void testMultipleBindDatagramChannel() throws Exception {
ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.ADVANCED);
assumeTrue(versionEqOrGt(3, 9, 0));
Bootstrap bootstrap = createBootstrap();
bootstrap.option(EpollChannelOption.SO_REUSEPORT, true);
final AtomicBoolean received1 = new AtomicBoolean();
bootstrap.handler(new DatagramSocketTestHandler(received1));
ChannelFuture future = bootstrap.bind().syncUninterruptibly();
final InetSocketAddress address1 = (InetSocketAddress) future.channel().localAddress();
final AtomicBoolean received2 = new AtomicBoolean();
bootstrap.handler(new DatagramSocketTestHandler(received2));
ChannelFuture future2 = bootstrap.bind(address1).syncUninterruptibly();
final InetSocketAddress address2 = (InetSocketAddress) future2.channel().localAddress();
assertEquals(address1, address2);
final byte[] bytes = "data".getBytes();
// fire up 16 Threads and send DatagramPackets to make sure we stress it enough to see DatagramPackets received
// on both sockets.
int count = 16;
final CountDownLatch latch = new CountDownLatch(count);
Runnable r = new Runnable() {
@Override
public void run() {
try {
DatagramSocket socket = new DatagramSocket();
while (!received1.get() || !received2.get()) {
socket.send(new DatagramPacket(
bytes, 0, bytes.length, address1.getAddress(), address1.getPort()));
}
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
latch.countDown();
}
};
ExecutorService executor = Executors.newFixedThreadPool(count);
for (int i = 0 ; i < count; i++) {
executor.execute(r);
}
latch.await();
executor.shutdown();
future.channel().close().syncUninterruptibly();
future2.channel().close().syncUninterruptibly();
assertTrue(received1.get());
assertTrue(received2.get());
}
private static ServerBootstrap createServerBootstrap() {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(EpollSocketTestPermutation.EPOLL_BOSS_GROUP, EpollSocketTestPermutation.EPOLL_WORKER_GROUP);
bootstrap.channel(EpollServerSocketChannel.class);
bootstrap.childHandler(new DummyHandler());
InetSocketAddress address = new InetSocketAddress(NetUtil.LOCALHOST, 0);
bootstrap.localAddress(address);
return bootstrap;
}
private static Bootstrap createBootstrap() {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(EpollSocketTestPermutation.EPOLL_WORKER_GROUP);
bootstrap.channel(EpollDatagramChannel.class);
InetSocketAddress address = new InetSocketAddress(NetUtil.LOCALHOST, 0);
bootstrap.localAddress(address);
return bootstrap;
}
private static boolean versionEqOrGt(int major, int minor, int bugfix) {
if (MAJOR > major) {
return true;
}
if (MAJOR == major) {
if (MINOR > minor) {
return true;
} else if (MINOR == minor) {
if (BUGFIX >= bugfix) {
return true;
}
}
}
return false;
}
@ChannelHandler.Sharable
private static class ServerSocketTestHandler extends ChannelInboundHandlerAdapter {
private final AtomicBoolean accepted;
ServerSocketTestHandler(AtomicBoolean accepted) {
this.accepted = accepted;
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
accepted.set(true);
ctx.close();
}
}
@ChannelHandler.Sharable
private static class DatagramSocketTestHandler extends ChannelInboundHandlerAdapter {
private final AtomicBoolean received;
DatagramSocketTestHandler(AtomicBoolean received) {
this.received = received;
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ReferenceCountUtil.release(msg);
received.set(true);
}
}
@ChannelHandler.Sharable
private static final class DummyHandler extends ChannelHandlerAdapter { }
}

View file

@ -0,0 +1,103 @@
/*
* Copyright 2016 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.Executable;
import java.net.InetSocketAddress;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class EpollServerSocketChannelConfigTest {
private static EventLoopGroup group;
private static EpollServerSocketChannel ch;
@BeforeAll
public static void before() {
group = new EpollEventLoopGroup(1);
ServerBootstrap bootstrap = new ServerBootstrap();
ch = (EpollServerSocketChannel) bootstrap.group(group)
.channel(EpollServerSocketChannel.class)
.childHandler(new ChannelInboundHandlerAdapter())
.bind(new InetSocketAddress(0)).syncUninterruptibly().channel();
}
@AfterAll
public static void after() {
try {
ch.close().syncUninterruptibly();
} finally {
group.shutdownGracefully();
}
}
@Test
public void testTcpDeferAccept() {
ch.config().setTcpDeferAccept(0);
assertEquals(0, ch.config().getTcpDeferAccept());
ch.config().setTcpDeferAccept(10);
// The returned value may be bigger then what we set.
// See https://www.spinics.net/lists/netdev/msg117330.html
assertTrue(10 <= ch.config().getTcpDeferAccept());
}
@Test
public void testReusePort() {
ch.config().setReusePort(false);
assertFalse(ch.config().isReusePort());
ch.config().setReusePort(true);
assertTrue(ch.config().isReusePort());
}
@Test
public void testFreeBind() {
ch.config().setFreeBind(false);
assertFalse(ch.config().isFreeBind());
ch.config().setFreeBind(true);
assertTrue(ch.config().isFreeBind());
}
@Test
public void getGetOptions() {
Map<ChannelOption<?>, Object> map = ch.config().getOptions();
assertFalse(map.isEmpty());
}
@Test
public void testFastOpen() {
assertThrows(IllegalArgumentException.class, new Executable() {
@Override
public void execute() {
ch.config().setTcpFastopen(-1);
}
});
ch.config().setTcpFastopen(10);
assertEquals(10, ch.config().getTcpFastopen());
}
}

View file

@ -0,0 +1,42 @@
/*
* Copyright 2023 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketAddressesTest;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
class EpollSocketAddressesTest extends SocketAddressesTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithFastOpen();
}
@Override
protected void assertAddress(SocketAddress address) {
assertTrue(((InetSocketAddress) address).getPort() > 0);
assertFalse(((InetSocketAddress) address).getAddress().isAnyLocalAddress());
}
}

View file

@ -0,0 +1,178 @@
/*
* Copyright 2015 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.github.artsok.RepeatedIfExceptionsTest;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelException;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.Executable;
import org.opentest4j.TestAbortedException;
import java.net.InetSocketAddress;
import java.nio.channels.ClosedChannelException;
import java.util.Map;
import java.util.Random;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
public class EpollSocketChannelConfigTest {
private static EventLoopGroup group;
private static EpollSocketChannel ch;
private static Random rand;
@BeforeAll
public static void beforeClass() {
rand = new Random();
group = new EpollEventLoopGroup(1);
}
@AfterAll
public static void afterClass() {
group.shutdownGracefully();
}
@BeforeEach
public void setup() {
Bootstrap bootstrap = new Bootstrap();
ch = (EpollSocketChannel) bootstrap.group(group)
.channel(EpollSocketChannel.class)
.handler(new ChannelInboundHandlerAdapter())
.bind(new InetSocketAddress(0)).syncUninterruptibly().channel();
}
@AfterEach
public void teardown() {
ch.close().syncUninterruptibly();
}
private static long randLong(long min, long max) {
return min + nextLong(max - min + 1);
}
private static long nextLong(long n) {
long bits, val;
do {
bits = (rand.nextLong() << 1) >>> 1;
val = bits % n;
} while (bits - val + (n - 1) < 0L);
return val;
}
@Test
public void testRandomTcpNotSentLowAt() {
final long expected = randLong(0, 0xFFFFFFFFL);
final long actual;
try {
ch.config().setTcpNotSentLowAt(expected);
actual = ch.config().getTcpNotSentLowAt();
} catch (RuntimeException e) {
throw new TestAbortedException("assumeNoException", e);
}
assertEquals(expected, actual);
}
@Test
public void testInvalidHighTcpNotSentLowAt() {
try {
final long value = 0xFFFFFFFFL + 1;
ch.config().setTcpNotSentLowAt(value);
} catch (IllegalArgumentException e) {
return;
} catch (RuntimeException e) {
throw new TestAbortedException("assumeNoException", e);
}
fail();
}
@Test
public void testInvalidLowTcpNotSentLowAt() {
try {
final long value = -1;
ch.config().setTcpNotSentLowAt(value);
} catch (IllegalArgumentException e) {
return;
} catch (RuntimeException e) {
throw new TestAbortedException("assumeNoException", e);
}
fail();
}
@Test
public void testTcpCork() {
ch.config().setTcpCork(false);
assertFalse(ch.config().isTcpCork());
ch.config().setTcpCork(true);
assertTrue(ch.config().isTcpCork());
}
@Test
public void testTcpQickAck() {
ch.config().setTcpQuickAck(false);
assertFalse(ch.config().isTcpQuickAck());
ch.config().setTcpQuickAck(true);
assertTrue(ch.config().isTcpQuickAck());
}
// For this test to pass, we are relying on the sockets file descriptor not being reused after the socket is closed.
// This is inherently racy, so we allow getSoLinger to throw ChannelException a few of times, but eventually we do
// want to see a ClosedChannelException for the test to pass.
@RepeatedIfExceptionsTest(repeats = 4)
public void testSetOptionWhenClosed() {
ch.close().syncUninterruptibly();
ChannelException e = assertThrows(ChannelException.class, new Executable() {
@Override
public void execute() throws Throwable {
ch.config().setSoLinger(0);
}
});
assertThat(e).hasCauseInstanceOf(ClosedChannelException.class);
}
// For this test to pass, we are relying on the sockets file descriptor not being reused after the socket is closed.
// This is inherently racy, so we allow getSoLinger to throw ChannelException a few of times, but eventually we do
// want to see a ClosedChannelException for the test to pass.
@RepeatedIfExceptionsTest(repeats = 4)
public void testGetOptionWhenClosed() {
ch.close().syncUninterruptibly();
ChannelException e = assertThrows(ChannelException.class, new Executable() {
@Override
public void execute() throws Throwable {
ch.config().getSoLinger();
}
});
assertThat(e).hasCauseInstanceOf(ClosedChannelException.class);
}
@Test
public void getGetOptions() {
Map<ChannelOption<?>, Object> map = ch.config().getOptions();
assertFalse(map.isEmpty());
}
}

View file

@ -0,0 +1,29 @@
/*
* Copyright 2016 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketChannelNotYetConnectedTest;
import java.util.List;
public class EpollSocketChannelNotYetConnectedTest extends SocketChannelNotYetConnectedTest {
@Override
protected List<TestsuitePermutation.BootstrapFactory<Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.clientSocketWithFastOpen();
}
}

View file

@ -0,0 +1,123 @@
/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import org.junit.jupiter.api.Test;
import java.net.InetSocketAddress;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class EpollSocketChannelTest {
@Test
public void testTcpInfo() throws Exception {
EventLoopGroup group = new EpollEventLoopGroup(1);
try {
Bootstrap bootstrap = new Bootstrap();
EpollSocketChannel ch = (EpollSocketChannel) bootstrap.group(group)
.channel(EpollSocketChannel.class)
.handler(new ChannelInboundHandlerAdapter())
.bind(new InetSocketAddress(0)).syncUninterruptibly().channel();
EpollTcpInfo info = ch.tcpInfo();
assertTcpInfo0(info);
ch.close().syncUninterruptibly();
} finally {
group.shutdownGracefully();
}
}
@Test
public void testTcpInfoReuse() throws Exception {
EventLoopGroup group = new EpollEventLoopGroup(1);
try {
Bootstrap bootstrap = new Bootstrap();
EpollSocketChannel ch = (EpollSocketChannel) bootstrap.group(group)
.channel(EpollSocketChannel.class)
.handler(new ChannelInboundHandlerAdapter())
.bind(new InetSocketAddress(0)).syncUninterruptibly().channel();
EpollTcpInfo info = new EpollTcpInfo();
ch.tcpInfo(info);
assertTcpInfo0(info);
ch.close().syncUninterruptibly();
} finally {
group.shutdownGracefully();
}
}
private static void assertTcpInfo0(EpollTcpInfo info) throws Exception {
assertNotNull(info);
assertTrue(info.state() >= 0);
assertTrue(info.caState() >= 0);
assertTrue(info.retransmits() >= 0);
assertTrue(info.probes() >= 0);
assertTrue(info.backoff() >= 0);
assertTrue(info.options() >= 0);
assertTrue(info.sndWscale() >= 0);
assertTrue(info.rcvWscale() >= 0);
assertTrue(info.rto() >= 0);
assertTrue(info.ato() >= 0);
assertTrue(info.sndMss() >= 0);
assertTrue(info.rcvMss() >= 0);
assertTrue(info.unacked() >= 0);
assertTrue(info.sacked() >= 0);
assertTrue(info.lost() >= 0);
assertTrue(info.retrans() >= 0);
assertTrue(info.fackets() >= 0);
assertTrue(info.lastDataSent() >= 0);
assertTrue(info.lastAckSent() >= 0);
assertTrue(info.lastDataRecv() >= 0);
assertTrue(info.lastAckRecv() >= 0);
assertTrue(info.pmtu() >= 0);
assertTrue(info.rcvSsthresh() >= 0);
assertTrue(info.rtt() >= 0);
assertTrue(info.rttvar() >= 0);
assertTrue(info.sndSsthresh() >= 0);
assertTrue(info.sndCwnd() >= 0);
assertTrue(info.advmss() >= 0);
assertTrue(info.reordering() >= 0);
assertTrue(info.rcvRtt() >= 0);
assertTrue(info.rcvSpace() >= 0);
assertTrue(info.totalRetrans() >= 0);
}
// See https://github.com/netty/netty/issues/7159
@Test
public void testSoLingerNoAssertError() throws Exception {
EventLoopGroup group = new EpollEventLoopGroup(1);
try {
Bootstrap bootstrap = new Bootstrap();
EpollSocketChannel ch = (EpollSocketChannel) bootstrap.group(group)
.channel(EpollSocketChannel.class)
.option(ChannelOption.SO_LINGER, 10)
.handler(new ChannelInboundHandlerAdapter())
.bind(new InetSocketAddress(0)).syncUninterruptibly().channel();
ch.close().syncUninterruptibly();
} finally {
group.shutdownGracefully();
}
}
}

View file

@ -0,0 +1,30 @@
/*
* Copyright 2017 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketCloseForciblyTest;
import java.util.List;
public class EpollSocketCloseForciblyTest extends SocketCloseForciblyTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithoutFastOpen();
}
}

View file

@ -0,0 +1,31 @@
/*
* Copyright 2016 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketConnectTest;
import java.util.List;
public class EpollSocketConnectTest extends SocketConnectTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithoutFastOpen();
}
}

View file

@ -0,0 +1,29 @@
/*
* Copyright 2015 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketConnectionAttemptTest;
import java.util.List;
public class EpollSocketConnectionAttemptTest extends SocketConnectionAttemptTest {
@Override
protected List<TestsuitePermutation.BootstrapFactory<Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.clientSocket();
}
}

View file

@ -0,0 +1,31 @@
/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketEchoTest;
import java.util.List;
public class EpollSocketEchoTest extends SocketEchoTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithFastOpen();
}
}

View file

@ -0,0 +1,31 @@
/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketFileRegionTest;
import java.util.List;
public class EpollSocketFileRegionTest extends SocketFileRegionTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithFastOpen();
}
}

View file

@ -0,0 +1,31 @@
/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketFixedLengthEchoTest;
import java.util.List;
public class EpollSocketFixedLengthEchoTest extends SocketFixedLengthEchoTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithFastOpen();
}
}

View file

@ -0,0 +1,31 @@
/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketGatheringWriteTest;
import java.util.List;
public class EpollSocketGatheringWriteTest extends SocketGatheringWriteTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithoutFastOpen();
}
}

View file

@ -0,0 +1,43 @@
/*
* Copyright 2016 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketMultipleConnectTest;
import java.util.ArrayList;
import java.util.List;
public class EpollSocketMultipleConnectTest extends SocketMultipleConnectTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> factories
= new ArrayList<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>>();
for (TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap> comboFactory
: EpollSocketTestPermutation.INSTANCE.socketWithFastOpen()) {
EventLoopGroup group = comboFactory.newClientInstance().config().group();
if (group instanceof NioEventLoopGroup || group instanceof EpollEventLoopGroup) {
factories.add(comboFactory);
}
}
return factories;
}
}

View file

@ -0,0 +1,31 @@
/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketObjectEchoTest;
import java.util.List;
public class EpollSocketObjectEchoTest extends SocketObjectEchoTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithFastOpen();
}
}

View file

@ -0,0 +1,49 @@
/*
* Copyright 2016 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.unix.Errors;
import io.netty.channel.unix.Errors.NativeIoException;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketRstTest;
import java.io.IOException;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class EpollSocketRstTest extends SocketRstTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithoutFastOpen();
}
@Override
protected void assertRstOnCloseException(IOException cause, Channel clientChannel) {
if (!AbstractEpollChannel.class.isInstance(clientChannel)) {
super.assertRstOnCloseException(cause, clientChannel);
return;
}
assertTrue(cause instanceof NativeIoException,
"actual [type, message]: [" + cause.getClass() + ", " + cause.getMessage() + "]");
assertEquals(Errors.ERRNO_ECONNRESET_NEGATIVE, ((NativeIoException) cause).expectedErr());
}
}

View file

@ -0,0 +1,29 @@
/*
* Copyright 2016 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketShutdownOutputByPeerTest;
import java.util.List;
public class EpollSocketShutdownOutputByPeerTest extends SocketShutdownOutputByPeerTest {
@Override
protected List<TestsuitePermutation.BootstrapFactory<ServerBootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.serverSocket();
}
}

View file

@ -0,0 +1,29 @@
/*
* Copyright 2016 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketShutdownOutputBySelfTest;
import java.util.List;
public class EpollSocketShutdownOutputBySelfTest extends SocketShutdownOutputBySelfTest {
@Override
protected List<TestsuitePermutation.BootstrapFactory<Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.clientSocket();
}
}

View file

@ -0,0 +1,30 @@
/*
* Copyright 2019 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketSslClientRenegotiateTest;
import java.util.List;
public class EpollSocketSslClientRenegotiateTest extends SocketSslClientRenegotiateTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithFastOpen();
}
}

View file

@ -0,0 +1,30 @@
/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketSslEchoTest;
import java.util.List;
public class EpollSocketSslEchoTest extends SocketSslEchoTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithFastOpen();
}
}

View file

@ -0,0 +1,30 @@
/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketSslGreetingTest;
import java.util.List;
public class EpollSocketSslGreetingTest extends SocketSslGreetingTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithFastOpen();
}
}

View file

@ -0,0 +1,30 @@
/*
* Copyright 2019 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketSslSessionReuseTest;
import java.util.List;
public class EpollSocketSslSessionReuseTest extends SocketSslSessionReuseTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithFastOpen();
}
}

View file

@ -0,0 +1,30 @@
/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketStartTlsTest;
import java.util.List;
public class EpollSocketStartTlsTest extends SocketStartTlsTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithFastOpen();
}
}

View file

@ -0,0 +1,100 @@
/*
* Copyright 2018 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SelectStrategy;
import io.netty.channel.SelectStrategyFactory;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.TestsuitePermutation.BootstrapComboFactory;
import io.netty.testsuite.transport.TestsuitePermutation.BootstrapFactory;
import io.netty.testsuite.transport.socket.SocketStringEchoTest;
import io.netty.util.IntSupplier;
import io.netty.util.concurrent.DefaultThreadFactory;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import java.util.ArrayList;
import java.util.List;
public class EpollSocketStringEchoBusyWaitTest extends SocketStringEchoTest {
private static EventLoopGroup EPOLL_LOOP;
@BeforeAll
public static void setup() throws Exception {
EPOLL_LOOP = new EpollEventLoopGroup(2, new DefaultThreadFactory("testsuite-epoll-busy-wait", true),
new SelectStrategyFactory() {
@Override
public SelectStrategy newSelectStrategy() {
return new SelectStrategy() {
@Override
public int calculateStrategy(IntSupplier selectSupplier, boolean hasTasks) {
return SelectStrategy.BUSY_WAIT;
}
};
}
});
}
@AfterAll
public static void teardown() throws Exception {
if (EPOLL_LOOP != null) {
EPOLL_LOOP.shutdownGracefully();
}
}
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
List<BootstrapComboFactory<ServerBootstrap, Bootstrap>> list =
new ArrayList<BootstrapComboFactory<ServerBootstrap, Bootstrap>>();
final BootstrapFactory<ServerBootstrap> sbf = serverSocket();
final BootstrapFactory<Bootstrap> cbf = clientSocket();
list.add(new BootstrapComboFactory<ServerBootstrap, Bootstrap>() {
@Override
public ServerBootstrap newServerInstance() {
return sbf.newInstance();
}
@Override
public Bootstrap newClientInstance() {
return cbf.newInstance();
}
});
return list;
}
private static BootstrapFactory<ServerBootstrap> serverSocket() {
return new BootstrapFactory<ServerBootstrap>() {
@Override
public ServerBootstrap newInstance() {
return new ServerBootstrap().group(EPOLL_LOOP, EPOLL_LOOP).channel(EpollServerSocketChannel.class);
}
};
}
private static BootstrapFactory<Bootstrap> clientSocket() {
return new BootstrapFactory<Bootstrap>() {
@Override
public Bootstrap newInstance() {
return new Bootstrap().group(EPOLL_LOOP).channel(EpollSocketChannel.class);
}
};
}
}

View file

@ -0,0 +1,31 @@
/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.SocketStringEchoTest;
import java.util.List;
public class EpollSocketStringEchoTest extends SocketStringEchoTest {
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.socketWithFastOpen();
}
}

View file

@ -0,0 +1,123 @@
/*
* Copyright 2015 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelOption;
import io.netty.channel.ConnectTimeoutException;
import io.netty.channel.EventLoopGroup;
import io.netty.util.CharsetUtil;
import io.netty.util.NetUtil;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.Executable;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.Collections;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class EpollSocketTcpMd5Test {
private static final byte[] SERVER_KEY = "abc".getBytes(CharsetUtil.US_ASCII);
private static final byte[] BAD_KEY = "def".getBytes(CharsetUtil.US_ASCII);
private static EventLoopGroup GROUP;
private EpollServerSocketChannel server;
@BeforeAll
public static void beforeClass() {
GROUP = new EpollEventLoopGroup(1);
}
@AfterAll
public static void afterClass() {
GROUP.shutdownGracefully();
}
@BeforeEach
public void setup() {
Bootstrap bootstrap = new Bootstrap();
server = (EpollServerSocketChannel) bootstrap.group(GROUP)
.channel(EpollServerSocketChannel.class)
.handler(new ChannelInboundHandlerAdapter())
.bind(new InetSocketAddress(NetUtil.LOCALHOST4, 0)).syncUninterruptibly().channel();
}
@AfterEach
public void teardown() {
server.close().syncUninterruptibly();
}
@Test
public void testServerSocketChannelOption() throws Exception {
server.config().setOption(EpollChannelOption.TCP_MD5SIG,
Collections.<InetAddress, byte[]>singletonMap(NetUtil.LOCALHOST4, SERVER_KEY));
server.config().setOption(EpollChannelOption.TCP_MD5SIG, Collections.<InetAddress, byte[]>emptyMap());
}
@Test
public void testServerOption() throws Exception {
Bootstrap bootstrap = new Bootstrap();
EpollServerSocketChannel ch = (EpollServerSocketChannel) bootstrap.group(GROUP)
.channel(EpollServerSocketChannel.class)
.handler(new ChannelInboundHandlerAdapter())
.bind(new InetSocketAddress(0)).syncUninterruptibly().channel();
ch.config().setOption(EpollChannelOption.TCP_MD5SIG,
Collections.<InetAddress, byte[]>singletonMap(NetUtil.LOCALHOST4, SERVER_KEY));
ch.config().setOption(EpollChannelOption.TCP_MD5SIG, Collections.<InetAddress, byte[]>emptyMap());
ch.close().syncUninterruptibly();
}
@Test
public void testKeyMismatch() throws Exception {
server.config().setOption(EpollChannelOption.TCP_MD5SIG,
Collections.<InetAddress, byte[]>singletonMap(NetUtil.LOCALHOST4, SERVER_KEY));
assertThrows(ConnectTimeoutException.class, new Executable() {
@Override
public void execute() throws Throwable {
EpollSocketChannel client = (EpollSocketChannel) new Bootstrap().group(GROUP)
.channel(EpollSocketChannel.class)
.handler(new ChannelInboundHandlerAdapter())
.option(EpollChannelOption.TCP_MD5SIG,
Collections.<InetAddress, byte[]>singletonMap(NetUtil.LOCALHOST4, BAD_KEY))
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000)
.connect(server.localAddress()).syncUninterruptibly().channel();
client.close().syncUninterruptibly();
}
});
}
@Test
public void testKeyMatch() throws Exception {
server.config().setOption(EpollChannelOption.TCP_MD5SIG,
Collections.<InetAddress, byte[]>singletonMap(NetUtil.LOCALHOST4, SERVER_KEY));
EpollSocketChannel client = (EpollSocketChannel) new Bootstrap().group(GROUP)
.channel(EpollSocketChannel.class)
.handler(new ChannelInboundHandlerAdapter())
.option(EpollChannelOption.TCP_MD5SIG,
Collections.<InetAddress, byte[]>singletonMap(NetUtil.LOCALHOST4, SERVER_KEY))
.connect(server.localAddress()).syncUninterruptibly().channel();
client.close().syncUninterruptibly();
}
}

View file

@ -0,0 +1,81 @@
/*
* Copyright 2016 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.channel.unix.DomainSocketAddress;
import io.netty.channel.unix.PeerCredentials;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class EpollSocketTest extends SocketTest<LinuxSocket> {
@BeforeAll
public static void loadJNI() {
Epoll.ensureAvailability();
}
@Test
public void testTcpCork() throws Exception {
assertFalse(socket.isTcpCork());
socket.setTcpCork(true);
assertTrue(socket.isTcpCork());
}
@Test
public void testPeerCreds() throws IOException {
LinuxSocket s1 = LinuxSocket.newSocketDomain();
LinuxSocket s2 = LinuxSocket.newSocketDomain();
try {
DomainSocketAddress dsa = UnixTestUtils.newDomainSocketAddress();
s1.bind(dsa);
s1.listen(1);
assertTrue(s2.connect(dsa));
byte [] addr = new byte[64];
s1.accept(addr);
PeerCredentials pc = s1.getPeerCredentials();
assertNotEquals(pc.uid(), -1);
} finally {
s1.close();
s2.close();
}
}
@Override
protected LinuxSocket newSocket() {
return LinuxSocket.newSocketStream();
}
@Override
protected int level() {
// Value for SOL_SOCKET
// See https://github.com/torvalds/linux/blob/v5.17/include/uapi/asm-generic/socket.h
return 1;
}
@Override
protected int optname() {
// Value for SO_REUSEADDR
// See https://github.com/torvalds/linux/blob/v5.17/include/uapi/asm-generic/socket.h
return 2;
}
}

View file

@ -0,0 +1,264 @@
/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFactory;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.socket.InternetProtocolFamily;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.channel.unix.DomainSocketAddress;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.TestsuitePermutation.BootstrapFactory;
import io.netty.testsuite.transport.socket.SocketTestPermutation;
import io.netty.util.concurrent.DefaultThreadFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static io.netty.channel.epoll.Native.IS_SUPPORTING_TCP_FASTOPEN_CLIENT;
import static io.netty.channel.epoll.Native.IS_SUPPORTING_TCP_FASTOPEN_SERVER;
class EpollSocketTestPermutation extends SocketTestPermutation {
static final EpollSocketTestPermutation INSTANCE = new EpollSocketTestPermutation();
static final EventLoopGroup EPOLL_BOSS_GROUP =
new EpollEventLoopGroup(BOSSES, new DefaultThreadFactory("testsuite-epoll-boss", true));
static final EventLoopGroup EPOLL_WORKER_GROUP =
new EpollEventLoopGroup(WORKERS, new DefaultThreadFactory("testsuite-epoll-worker", true));
@Override
public List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> socket() {
List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> list =
combo(serverSocket(), clientSocketWithFastOpen());
list.remove(list.size() - 1); // Exclude NIO x NIO test
return list;
}
public List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> socketWithoutFastOpen() {
List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> list =
combo(serverSocket(), clientSocket());
list.remove(list.size() - 1); // Exclude NIO x NIO test
return list;
}
@Override
public List<BootstrapFactory<ServerBootstrap>> serverSocket() {
List<BootstrapFactory<ServerBootstrap>> toReturn = new ArrayList<BootstrapFactory<ServerBootstrap>>();
toReturn.add(new BootstrapFactory<ServerBootstrap>() {
@Override
public ServerBootstrap newInstance() {
return new ServerBootstrap().group(EPOLL_BOSS_GROUP, EPOLL_WORKER_GROUP)
.channel(EpollServerSocketChannel.class);
}
});
if (IS_SUPPORTING_TCP_FASTOPEN_SERVER) {
toReturn.add(new BootstrapFactory<ServerBootstrap>() {
@Override
public ServerBootstrap newInstance() {
ServerBootstrap serverBootstrap = new ServerBootstrap().group(EPOLL_BOSS_GROUP, EPOLL_WORKER_GROUP)
.channel(EpollServerSocketChannel.class);
serverBootstrap.option(ChannelOption.TCP_FASTOPEN, 5);
return serverBootstrap;
}
});
}
toReturn.add(new BootstrapFactory<ServerBootstrap>() {
@Override
public ServerBootstrap newInstance() {
return new ServerBootstrap().group(nioBossGroup, nioWorkerGroup)
.channel(NioServerSocketChannel.class);
}
});
return toReturn;
}
@Override
public List<BootstrapFactory<Bootstrap>> clientSocket() {
List<BootstrapFactory<Bootstrap>> toReturn = new ArrayList<BootstrapFactory<Bootstrap>>();
toReturn.add(new BootstrapFactory<Bootstrap>() {
@Override
public Bootstrap newInstance() {
return new Bootstrap().group(EPOLL_WORKER_GROUP).channel(EpollSocketChannel.class);
}
});
toReturn.add(new BootstrapFactory<Bootstrap>() {
@Override
public Bootstrap newInstance() {
return new Bootstrap().group(nioWorkerGroup).channel(NioSocketChannel.class);
}
});
return toReturn;
}
@Override
public List<BootstrapFactory<Bootstrap>> clientSocketWithFastOpen() {
List<BootstrapFactory<Bootstrap>> factories = clientSocket();
if (IS_SUPPORTING_TCP_FASTOPEN_CLIENT) {
int insertIndex = factories.size() - 1; // Keep NIO fixture last.
factories.add(insertIndex, new BootstrapFactory<Bootstrap>() {
@Override
public Bootstrap newInstance() {
return new Bootstrap().group(EPOLL_WORKER_GROUP).channel(EpollSocketChannel.class)
.option(ChannelOption.TCP_FASTOPEN_CONNECT, true);
}
});
}
return factories;
}
@Override
public List<TestsuitePermutation.BootstrapComboFactory<Bootstrap, Bootstrap>> datagram(
final InternetProtocolFamily family) {
// Make the list of Bootstrap factories.
List<BootstrapFactory<Bootstrap>> bfs = Arrays.asList(
new BootstrapFactory<Bootstrap>() {
@Override
public Bootstrap newInstance() {
return new Bootstrap().group(nioWorkerGroup).channelFactory(new ChannelFactory<Channel>() {
@Override
public Channel newChannel() {
return new NioDatagramChannel(family);
}
@Override
public String toString() {
return NioDatagramChannel.class.getSimpleName() + ".class";
}
});
}
},
new BootstrapFactory<Bootstrap>() {
@Override
public Bootstrap newInstance() {
return new Bootstrap().group(EPOLL_WORKER_GROUP).channelFactory(new ChannelFactory<Channel>() {
@Override
public Channel newChannel() {
return new EpollDatagramChannel(family);
}
@Override
public String toString() {
return InternetProtocolFamily.class.getSimpleName() + ".class";
}
});
}
}
);
return combo(bfs, bfs);
}
List<TestsuitePermutation.BootstrapComboFactory<Bootstrap, Bootstrap>> epollOnlyDatagram(
final InternetProtocolFamily family) {
return combo(Collections.singletonList(datagramBootstrapFactory(family)),
Collections.singletonList(datagramBootstrapFactory(family)));
}
private static BootstrapFactory<Bootstrap> datagramBootstrapFactory(final InternetProtocolFamily family) {
return new BootstrapFactory<Bootstrap>() {
@Override
public Bootstrap newInstance() {
return new Bootstrap().group(EPOLL_WORKER_GROUP).channelFactory(new ChannelFactory<Channel>() {
@Override
public Channel newChannel() {
return new EpollDatagramChannel(family);
}
@Override
public String toString() {
return InternetProtocolFamily.class.getSimpleName() + ".class";
}
});
}
};
}
public List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> domainSocket() {
return combo(serverDomainSocket(), clientDomainSocket());
}
public List<BootstrapFactory<ServerBootstrap>> serverDomainSocket() {
return Collections.<BootstrapFactory<ServerBootstrap>>singletonList(
new BootstrapFactory<ServerBootstrap>() {
@Override
public ServerBootstrap newInstance() {
return new ServerBootstrap().group(EPOLL_BOSS_GROUP, EPOLL_WORKER_GROUP)
.channel(EpollServerDomainSocketChannel.class);
}
}
);
}
public List<BootstrapFactory<Bootstrap>> clientDomainSocket() {
return Collections.<BootstrapFactory<Bootstrap>>singletonList(
new BootstrapFactory<Bootstrap>() {
@Override
public Bootstrap newInstance() {
return new Bootstrap().group(EPOLL_WORKER_GROUP).channel(EpollDomainSocketChannel.class);
}
}
);
}
@Override
public List<BootstrapFactory<Bootstrap>> datagramSocket() {
return Collections.<BootstrapFactory<Bootstrap>>singletonList(
new BootstrapFactory<Bootstrap>() {
@Override
public Bootstrap newInstance() {
return new Bootstrap().group(EPOLL_WORKER_GROUP).channel(EpollDatagramChannel.class);
}
}
);
}
public List<TestsuitePermutation.BootstrapComboFactory<Bootstrap, Bootstrap>> domainDatagram() {
return combo(domainDatagramSocket(), domainDatagramSocket());
}
public List<BootstrapFactory<Bootstrap>> domainDatagramSocket() {
return Collections.<BootstrapFactory<Bootstrap>>singletonList(
new BootstrapFactory<Bootstrap>() {
@Override
public Bootstrap newInstance() {
return new Bootstrap().group(EPOLL_WORKER_GROUP).channel(EpollDomainDatagramChannel.class);
}
}
);
}
public static DomainSocketAddress newDomainSocketAddress() {
return UnixTestUtils.newDomainSocketAddress();
}
}

View file

@ -0,0 +1,313 @@
/*
* Copyright 2015 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.unix.FileDescriptor;
import io.netty.util.NetUtil;
import io.netty.util.internal.PlatformDependent;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class EpollSpliceTest {
private static final int SPLICE_LEN = 32 * 1024;
private static final Random random = new Random();
private static final byte[] data = new byte[1048576];
static {
random.nextBytes(data);
}
@Test
public void spliceToSocket() throws Throwable {
final EchoHandler sh = new EchoHandler();
final EchoHandler ch = new EchoHandler();
EventLoopGroup group = new EpollEventLoopGroup(1);
ServerBootstrap bs = new ServerBootstrap();
bs.channel(EpollServerSocketChannel.class);
bs.group(group).childHandler(sh);
final Channel sc = bs.bind(NetUtil.LOCALHOST, 0).syncUninterruptibly().channel();
ServerBootstrap bs2 = new ServerBootstrap();
bs2.channel(EpollServerSocketChannel.class);
bs2.childOption(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED);
bs2.group(group).childHandler(new ChannelInboundHandlerAdapter() {
@Override
public void channelActive(final ChannelHandlerContext ctx) throws Exception {
ctx.channel().config().setAutoRead(false);
Bootstrap bs = new Bootstrap();
bs.option(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED);
bs.channel(EpollSocketChannel.class);
bs.group(ctx.channel().eventLoop()).handler(new ChannelInboundHandlerAdapter() {
@Override
public void channelActive(ChannelHandlerContext context) throws Exception {
final EpollSocketChannel ch = (EpollSocketChannel) ctx.channel();
final EpollSocketChannel ch2 = (EpollSocketChannel) context.channel();
// We are splicing two channels together, at this point we have a tcp proxy which handles all
// the data transfer only in kernel space!
// Integer.MAX_VALUE will splice infinitely.
ch.spliceTo(ch2, Integer.MAX_VALUE).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
future.channel().close();
}
}
});
// Trigger multiple splices to see if partial splicing works as well.
ch2.spliceTo(ch, SPLICE_LEN).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
future.channel().close();
} else {
ch2.spliceTo(ch, SPLICE_LEN).addListener(this);
}
}
});
ctx.channel().config().setAutoRead(true);
}
@Override
public void channelInactive(ChannelHandlerContext context) throws Exception {
context.close();
}
});
bs.connect(sc.localAddress()).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
ctx.close();
} else {
future.channel().closeFuture().addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
ctx.close();
}
});
}
}
});
}
});
Channel pc = bs2.bind(NetUtil.LOCALHOST, 0).syncUninterruptibly().channel();
Bootstrap cb = new Bootstrap();
cb.group(group);
cb.channel(EpollSocketChannel.class);
cb.handler(ch);
Channel cc = cb.connect(pc.localAddress()).syncUninterruptibly().channel();
for (int i = 0; i < data.length;) {
int length = Math.min(random.nextInt(1024 * 64), data.length - i);
ByteBuf buf = Unpooled.wrappedBuffer(data, i, length);
cc.writeAndFlush(buf);
i += length;
}
while (ch.counter < data.length) {
if (sh.exception.get() != null) {
break;
}
if (ch.exception.get() != null) {
break;
}
Thread.sleep(50);
}
while (sh.counter < data.length) {
if (sh.exception.get() != null) {
break;
}
if (ch.exception.get() != null) {
break;
}
Thread.sleep(50);
}
sh.channel.close().sync();
ch.channel.close().sync();
sc.close().sync();
pc.close().sync();
group.shutdownGracefully();
if (sh.exception.get() != null && !(sh.exception.get() instanceof IOException)) {
throw sh.exception.get();
}
if (ch.exception.get() != null && !(ch.exception.get() instanceof IOException)) {
throw ch.exception.get();
}
if (sh.exception.get() != null) {
throw sh.exception.get();
}
if (ch.exception.get() != null) {
throw ch.exception.get();
}
}
@Test
@Timeout(value = 10000, unit = TimeUnit.MILLISECONDS)
public void spliceToFile() throws Throwable {
EventLoopGroup group = new EpollEventLoopGroup(1);
File file = PlatformDependent.createTempFile("netty-splice", null, null);
file.deleteOnExit();
SpliceHandler sh = new SpliceHandler(file);
ServerBootstrap bs = new ServerBootstrap();
bs.channel(EpollServerSocketChannel.class);
bs.group(group).childHandler(sh);
bs.childOption(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED);
Channel sc = bs.bind(NetUtil.LOCALHOST, 0).syncUninterruptibly().channel();
Bootstrap cb = new Bootstrap();
cb.group(group);
cb.channel(EpollSocketChannel.class);
cb.handler(new ChannelInboundHandlerAdapter());
Channel cc = cb.connect(sc.localAddress()).syncUninterruptibly().channel();
for (int i = 0; i < data.length;) {
int length = Math.min(random.nextInt(1024 * 64), data.length - i);
ByteBuf buf = Unpooled.wrappedBuffer(data, i, length);
cc.writeAndFlush(buf);
i += length;
}
while (sh.future2 == null || !sh.future2.isDone() || !sh.future.isDone()) {
if (sh.exception.get() != null) {
break;
}
Thread.sleep(50);
}
sc.close().sync();
cc.close().sync();
if (sh.exception.get() != null && !(sh.exception.get() instanceof IOException)) {
throw sh.exception.get();
}
byte[] written = new byte[data.length];
FileInputStream in = new FileInputStream(file);
try {
assertEquals(written.length, in.read(written));
assertArrayEquals(data, written);
} finally {
in.close();
group.shutdownGracefully();
}
}
private static class EchoHandler extends SimpleChannelInboundHandler<ByteBuf> {
volatile Channel channel;
final AtomicReference<Throwable> exception = new AtomicReference<Throwable>();
volatile int counter;
@Override
public void channelActive(ChannelHandlerContext ctx)
throws Exception {
channel = ctx.channel();
}
@Override
public void channelRead0(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
byte[] actual = new byte[in.readableBytes()];
in.readBytes(actual);
int lastIdx = counter;
for (int i = 0; i < actual.length; i ++) {
assertEquals(data[i + lastIdx], actual[i]);
}
if (channel.parent() != null) {
channel.write(Unpooled.wrappedBuffer(actual));
}
counter += actual.length;
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx,
Throwable cause) throws Exception {
if (exception.compareAndSet(null, cause)) {
cause.printStackTrace();
ctx.close();
}
}
}
private static class SpliceHandler extends ChannelInboundHandlerAdapter {
private final File file;
volatile ChannelFuture future;
volatile ChannelFuture future2;
final AtomicReference<Throwable> exception = new AtomicReference<Throwable>();
SpliceHandler(File file) {
this.file = file;
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
final EpollSocketChannel ch = (EpollSocketChannel) ctx.channel();
final FileDescriptor fd = FileDescriptor.from(file);
// splice two halves separately to test starting offset
future = ch.spliceTo(fd, 0, data.length / 2);
future2 = ch.spliceTo(fd, data.length / 2, data.length / 2);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx,
Throwable cause) throws Exception {
if (exception.compareAndSet(null, cause)) {
cause.printStackTrace();
ctx.close();
}
}
}
}

View file

@ -0,0 +1,75 @@
/*
* Copyright 2019 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.channel.unix.FileDescriptor;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class EpollTest {
@Test
public void testIsAvailable() {
assertTrue(Epoll.isAvailable());
}
// Testcase for https://github.com/netty/netty/issues/8444
@Test
@Timeout(value = 5000, unit = TimeUnit.MILLISECONDS)
public void testEpollWaitWithTimeOutMinusOne() throws Exception {
final EpollEventArray eventArray = new EpollEventArray(8);
try {
final FileDescriptor epoll = Native.newEpollCreate();
final FileDescriptor timerFd = Native.newTimerFd();
final FileDescriptor eventfd = Native.newEventFd();
Native.epollCtlAdd(epoll.intValue(), timerFd.intValue(), Native.EPOLLIN);
Native.epollCtlAdd(epoll.intValue(), eventfd.intValue(), Native.EPOLLIN);
final AtomicReference<Throwable> ref = new AtomicReference<Throwable>();
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
assertEquals(1, Native.epollWait(epoll, eventArray, false));
// This should have been woken up because of eventfd_write.
assertEquals(eventfd.intValue(), eventArray.fd(0));
} catch (Throwable cause) {
ref.set(cause);
}
}
});
t.start();
t.join(1000);
assertTrue(t.isAlive());
Native.eventFdWrite(eventfd.intValue(), 1);
t.join();
assertNull(ref.get());
epoll.close();
timerFd.close();
eventfd.close();
} finally {
eventArray.free();
}
}
}

View file

@ -0,0 +1,30 @@
/*
* Copyright 2019 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.bootstrap.Bootstrap;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.WriteBeforeRegisteredTest;
import java.util.List;
public class EpollWriteBeforeRegisteredTest extends WriteBeforeRegisteredTest {
@Override
protected List<TestsuitePermutation.BootstrapFactory<Bootstrap>> newFactories() {
return EpollSocketTestPermutation.INSTANCE.clientSocketWithFastOpen();
}
}

View file

@ -0,0 +1,64 @@
/*
* Copyright 2020 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.buffer.UnpooledDirectByteBuf;
import io.netty.channel.unix.IovArray;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public abstract class IovArrayTest {
@Test
public void testNotFailsWihtoutMemoryAddress() {
ByteBuf buffer = new NoMemoryAddressByteBuf(128);
IovArray array = new IovArray(buffer);
ByteBuf buf = Unpooled.directBuffer().writeZero(8);
ByteBuf buf2 = new NoMemoryAddressByteBuf(8).writeZero(8);
assertTrue(array.add(buf, 0, buf.readableBytes()));
assertTrue(array.add(buf, 0, buf2.readableBytes()));
assertEquals(2, array.count());
assertEquals(16, array.size());
assertTrue(buf.release());
assertTrue(buf2.release());
assertNotEquals(-1, array.memoryAddress(0));
array.release();
assertEquals(0, buffer.refCnt());
}
private static final class NoMemoryAddressByteBuf extends UnpooledDirectByteBuf {
NoMemoryAddressByteBuf(int capacity) {
super(UnpooledByteBufAllocator.DEFAULT, capacity, Integer.MAX_VALUE);
}
@Override
public boolean hasMemoryAddress() {
return false;
}
@Override
public long memoryAddress() {
throw new UnsupportedOperationException();
}
}
}

Some files were not shown because too many files have changed in this diff Show more