Compare commits
10 commits
49b6c772a5
...
52d3d16cb0
Author | SHA1 | Date | |
---|---|---|---|
52d3d16cb0 | |||
09ba068497 | |||
1b906bf706 | |||
938371e9eb | |||
e293f2e603 | |||
fc565512cc | |||
ada04aef58 | |||
dde0ad8a11 | |||
07c6dd718a | |||
3d532a821f |
481 changed files with 52890 additions and 2345 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -2,7 +2,6 @@
|
||||||
/.classpath
|
/.classpath
|
||||||
/.project
|
/.project
|
||||||
/.gradle
|
/.gradle
|
||||||
**/data
|
|
||||||
**/work
|
**/work
|
||||||
**/logs
|
**/logs
|
||||||
**/.idea
|
**/.idea
|
||||||
|
@ -12,5 +11,3 @@
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*.iml
|
*.iml
|
||||||
*~
|
*~
|
||||||
*.key
|
|
||||||
*.crt
|
|
||||||
|
|
11
NOTICE.txt
11
NOTICE.txt
|
@ -25,6 +25,7 @@ The following changes were performed on the original source code:
|
||||||
- removed all macos related code (including kqueue)
|
- removed all macos related code (including kqueue)
|
||||||
- removed all aarch64 related code
|
- removed all aarch64 related code
|
||||||
- removed the direct brotli4j dependency by rewriting Brotli4jOptions to not use Encoder.Parameters
|
- 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
|
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
|
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:
|
between subproject name, package name, artifact names, and java module. The following reorgnizations were performed:
|
||||||
|
|
||||||
netty/all -> [todo]
|
netty/all ->
|
||||||
netty/bom -> [todo]
|
netty/bom ->
|
||||||
netty/buffer -> netty-buffer
|
netty/buffer -> netty-buffer
|
||||||
netty/codec -> netty-handler-codec, netty-handler-codec-compression, netty-handler-codec-protobuf
|
netty/codec -> netty-handler-codec, netty-handler-codec-compression, netty-handler-codec-protobuf
|
||||||
netty/codec-dns -> [todo]
|
netty/codec-dns -> netty-handler-codec-dns
|
||||||
netty/codec-haproxy -> [todo]
|
netty/codec-haproxy ->
|
||||||
netty/codec-http -> netty-handler-codec-http, netty-handler-codec-rtsp, netty-handler-codec-spdy
|
netty/codec-http -> netty-handler-codec-http, netty-handler-codec-rtsp, netty-handler-codec-spdy
|
||||||
netty/codec-http2 ->
|
netty/codec-http2 ->
|
||||||
netty/codec-memcache ->
|
netty/codec-memcache ->
|
||||||
|
@ -61,7 +62,7 @@ netty/handler -> netty-handler
|
||||||
netty/handler-proxy
|
netty/handler-proxy
|
||||||
netty/handler-ssl-ocsp
|
netty/handler-ssl-ocsp
|
||||||
netty/resolver -> netty-resolver
|
netty/resolver -> netty-resolver
|
||||||
netty/resolver-dns ->
|
netty/resolver-dns -> netty-resolver-dns
|
||||||
netty/resolver-dns-classes-macos -> [dropped]
|
netty/resolver-dns-classes-macos -> [dropped]
|
||||||
netty/resolver-dns-native-macos -> [dropped]
|
netty/resolver-dns-native-macos -> [dropped]
|
||||||
netty/transport -> netty-channel
|
netty/transport -> netty-channel
|
||||||
|
|
|
@ -11,8 +11,6 @@ wrapper {
|
||||||
distributionType = Wrapper.DistributionType.BIN
|
distributionType = Wrapper.DistributionType.BIN
|
||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'com.google.osdetector'
|
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
user = 'joerg'
|
user = 'joerg'
|
||||||
name = 'netty'
|
name = 'netty'
|
||||||
|
@ -30,11 +28,15 @@ ext {
|
||||||
organizationUrl = 'https://xbib.org'
|
organizationUrl = 'https://xbib.org'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apply plugin: 'com.google.osdetector'
|
||||||
|
|
||||||
subprojects {
|
subprojects {
|
||||||
|
if (!it.name.endsWith('-native') && it.name != 'test-results') {
|
||||||
apply from: rootProject.file('gradle/repositories/maven.gradle')
|
apply from: rootProject.file('gradle/repositories/maven.gradle')
|
||||||
apply from: rootProject.file('gradle/compile/java.gradle')
|
apply from: rootProject.file('gradle/compile/java.gradle')
|
||||||
apply from: rootProject.file('gradle/test/junit5.gradle')
|
apply from: rootProject.file('gradle/test/junit5.gradle')
|
||||||
apply from: rootProject.file('gradle/publish/maven.gradle')
|
apply from: rootProject.file('gradle/publish/maven.gradle')
|
||||||
}
|
}
|
||||||
|
}
|
||||||
apply from: rootProject.file('gradle/publish/sonatype.gradle')
|
apply from: rootProject.file('gradle/publish/sonatype.gradle')
|
||||||
apply from: rootProject.file('gradle/publish/forgejo.gradle')
|
apply from: rootProject.file('gradle/publish/forgejo.gradle')
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
group = org.xbib.netty
|
group = org.xbib.netty
|
||||||
name = netty
|
name = netty
|
||||||
version = 4.1.104
|
version = 4.1.107.0
|
||||||
|
|
3
gradle/compile/c.gradle
Normal file
3
gradle/compile/c.gradle
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
apply plugin: 'base'
|
||||||
|
apply plugin: 'org.xbib.gradle.plugin.c'
|
1
gradle/compile/cmake.gradle
Normal file
1
gradle/compile/cmake.gradle
Normal file
|
@ -0,0 +1 @@
|
||||||
|
apply plugin: 'org.xbib.gradle.plugin.cmake'
|
|
@ -10,11 +10,8 @@ dependencies {
|
||||||
|
|
||||||
test {
|
test {
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
failFast = true
|
failFast = false
|
||||||
testLogging {
|
ignoreFailures = true
|
||||||
events 'STARTED', 'PASSED', 'FAILED', 'SKIPPED'
|
|
||||||
showStandardStreams = true
|
|
||||||
}
|
|
||||||
minHeapSize = "1g" // initial heap size
|
minHeapSize = "1g" // initial heap size
|
||||||
maxHeapSize = "2g" // maximum heap size
|
maxHeapSize = "2g" // maximum heap size
|
||||||
jvmArgs '--add-exports=java.base/jdk.internal=ALL-UNNAMED',
|
jvmArgs '--add-exports=java.base/jdk.internal=ALL-UNNAMED',
|
||||||
|
@ -30,11 +27,10 @@ test {
|
||||||
'--add-opens=jdk.unsupported/sun.misc=ALL-UNNAMED',
|
'--add-opens=jdk.unsupported/sun.misc=ALL-UNNAMED',
|
||||||
'-Dio.netty.bootstrap.extensions=serviceload'
|
'-Dio.netty.bootstrap.extensions=serviceload'
|
||||||
systemProperty 'java.util.logging.config.file', 'src/test/resources/logging.properties'
|
systemProperty 'java.util.logging.config.file', 'src/test/resources/logging.properties'
|
||||||
// we have remove native images, this is no longer used
|
testLogging {
|
||||||
systemProperty "nativeImage.handlerMetadataGroupId", "io.netty"
|
events 'STARTED', 'PASSED', 'FAILED', 'SKIPPED'
|
||||||
// we have remove native images
|
showStandardStreams = true
|
||||||
// we have remove native images, this is no longer used
|
}
|
||||||
systemProperty "nativeimage.handlerMetadataArtifactId", "netty-transport"
|
|
||||||
afterSuite { desc, result ->
|
afterSuite { desc, result ->
|
||||||
if (!desc.parent) {
|
if (!desc.parent) {
|
||||||
println "\nTest result: ${result.resultType}"
|
println "\nTest result: ${result.resultType}"
|
||||||
|
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +1,6 @@
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
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
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|
20
gradlew.bat
vendored
20
gradlew.bat
vendored
|
@ -43,11 +43,11 @@ set JAVA_EXE=java.exe
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if %ERRORLEVEL% equ 0 goto execute
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation.
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
|
@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
if exist "%JAVA_EXE%" goto execute
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation.
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
handlers=java.util.logging.ConsoleHandler
|
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.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
|
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
|
||||||
jdk.event.security.level=INFO
|
jdk.event.security.level=INFO
|
||||||
org.junit.jupiter.engine.execution.ConditionEvaluator.level=OFF
|
org.junit.jupiter.engine.execution.ConditionEvaluator.level=OFF
|
||||||
|
|
82
netty-channel-epoll-native/build.gradle
Normal file
82
netty-channel-epoll-native/build.gradle
Normal 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'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
909
netty-channel-epoll-native/src/main/c/netty_epoll_linuxsocket.c
Normal file
909
netty-channel-epoll-native/src/main/c/netty_epoll_linuxsocket.c
Normal 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);
|
||||||
|
}
|
|
@ -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
|
919
netty-channel-epoll-native/src/main/c/netty_epoll_native.c
Normal file
919
netty-channel-epoll-native/src/main/c/netty_epoll_native.c
Normal 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 */
|
38
netty-channel-epoll-native/src/main/c/netty_epoll_vmsocket.h
Normal file
38
netty-channel-epoll-native/src/main/c/netty_epoll_vmsocket.h
Normal 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_ */
|
Binary file not shown.
|
@ -1,4 +1,12 @@
|
||||||
|
apply plugin: 'com.google.osdetector'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api project(':netty-channel')
|
api project(':netty-channel')
|
||||||
api project(':netty-channel-unix')
|
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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 { }
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
Loading…
Reference in a new issue