Include LinuxSocket TCP options

Motivation:

some tcp options (like TcpFastopen or TcpFastopenConnect etc.) are required for testsuite tests

Modification:

-copied the class LinuxSocket from epoll and  JNI to load this module in io_uring jni
-some configurations have been adjusted

Result:

more tcp options are available
This commit is contained in:
Josef Grieb 2020-08-24 08:55:55 +02:00 committed by josef
parent 1117c6fdb8
commit 8d464d5ab4
12 changed files with 2142 additions and 31 deletions

View File

@ -0,0 +1,793 @@
/*
* 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:
*
* http://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 <sys/sendfile.h>
#include <linux/tcp.h> // TCP_NOTSENT_LOWAT is a linux specific define
#include "netty_io_uring_linuxsocket.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"
// 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
static jclass peerCredentialsClass = 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 void netty_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_linuxsocket_setTcpFastOpenConnect(JNIEnv* env, jclass clazz, jint fd, jint optval) {
netty_unix_socket_setOption(env, fd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, &optval, sizeof(optval));
}
static void netty_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_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_io_uring_linuxsocket_isTcpFastOpenConnect(JNIEnv* env, jclass clazz, jint fd) {
int optval;
// We call netty_unix_socket_getOption0 directly so we can handle ENOPROTOOPT by ourself.
if (netty_unix_socket_getOption0(fd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, &optval, sizeof(optval)) == -1) {
if (errno == ENOPROTOOPT) {
// Not supported by the system, so just return 0.
return 0;
}
netty_unix_socket_getOptionHandleError(env, errno);
return -1;
}
return optval;
}
static jint netty_io_uring_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_io_uring_linuxsocket_getPeerCredentials(JNIEnv *env, jclass clazz, jint fd) {
struct ucred credentials;
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);
return (*env)->NewObject(env, peerCredentialsClass, peerCredentialsMethodId, credentials.pid, credentials.uid, gids);
}
static jlong netty_io_uring_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[] = {
{ "setTimeToLive", "(II)V", (void *) netty_io_uring_linuxsocket_setTimeToLive },
{ "getTimeToLive", "(I)I", (void *) netty_io_uring_linuxsocket_getTimeToLive },
{ "setInterface", "(IZ[BII)V", (void *) netty_io_uring_linuxsocket_setInterface },
{ "getInterface", "(IZ)I", (void *) netty_io_uring_linuxsocket_getInterface },
{ "setIpMulticastLoop", "(IZI)V", (void * ) netty_io_uring_linuxsocket_setIpMulticastLoop },
{ "getIpMulticastLoop", "(IZ)I", (void * ) netty_io_uring_linuxsocket_getIpMulticastLoop },
{ "setTcpCork", "(II)V", (void *) netty_io_uring_linuxsocket_setTcpCork },
{ "setSoBusyPoll", "(II)V", (void *) netty_io_uring_linuxsocket_setSoBusyPoll },
{ "setTcpQuickAck", "(II)V", (void *) netty_io_uring_linuxsocket_setTcpQuickAck },
{ "setTcpDeferAccept", "(II)V", (void *) netty_io_uring_linuxsocket_setTcpDeferAccept },
{ "setTcpNotSentLowAt", "(II)V", (void *) netty_io_uring_linuxsocket_setTcpNotSentLowAt },
{ "isTcpCork", "(I)I", (void *) netty_io_uring_linuxsocket_isTcpCork },
{ "getSoBusyPoll", "(I)I", (void *) netty_io_uring_linuxsocket_getSoBusyPoll },
{ "getTcpDeferAccept", "(I)I", (void *) netty_io_uring_linuxsocket_getTcpDeferAccept },
{ "getTcpNotSentLowAt", "(I)I", (void *) netty_io_uring_linuxsocket_getTcpNotSentLowAt },
{ "isTcpQuickAck", "(I)I", (void *) netty_io_uring_linuxsocket_isTcpQuickAck },
{ "setTcpFastOpen", "(II)V", (void *) netty_io_uring_linuxsocket_setTcpFastOpen },
{ "setTcpFastOpenConnect", "(II)V", (void *) netty_io_uring_linuxsocket_setTcpFastOpenConnect },
{ "isTcpFastOpenConnect", "(I)I", (void *) netty_io_uring_linuxsocket_isTcpFastOpenConnect },
{ "setTcpKeepIdle", "(II)V", (void *) netty_io_uring_linuxsocket_setTcpKeepIdle },
{ "setTcpKeepIntvl", "(II)V", (void *) netty_io_uring_linuxsocket_setTcpKeepIntvl },
{ "setTcpKeepCnt", "(II)V", (void *) netty_io_uring_linuxsocket_setTcpKeepCnt },
{ "setTcpUserTimeout", "(II)V", (void *) netty_io_uring_linuxsocket_setTcpUserTimeout },
{ "setIpFreeBind", "(II)V", (void *) netty_io_uring_linuxsocket_setIpFreeBind },
{ "setIpTransparent", "(II)V", (void *) netty_io_uring_linuxsocket_setIpTransparent },
{ "setIpRecvOrigDestAddr", "(II)V", (void *) netty_io_uring_linuxsocket_setIpRecvOrigDestAddr },
{ "getTcpKeepIdle", "(I)I", (void *) netty_io_uring_linuxsocket_getTcpKeepIdle },
{ "getTcpKeepIntvl", "(I)I", (void *) netty_io_uring_linuxsocket_getTcpKeepIntvl },
{ "getTcpKeepCnt", "(I)I", (void *) netty_io_uring_linuxsocket_getTcpKeepCnt },
{ "getTcpUserTimeout", "(I)I", (void *) netty_io_uring_linuxsocket_getTcpUserTimeout },
{ "isIpFreeBind", "(I)I", (void *) netty_io_uring_linuxsocket_isIpFreeBind },
{ "isIpTransparent", "(I)I", (void *) netty_io_uring_linuxsocket_isIpTransparent },
{ "isIpRecvOrigDestAddr", "(I)I", (void *) netty_io_uring_linuxsocket_isIpRecvOrigDestAddr },
{ "getTcpInfo", "(I[J)V", (void *) netty_io_uring_linuxsocket_getTcpInfo },
{ "setTcpMd5Sig", "(IZ[BI[B)V", (void *) netty_io_uring_linuxsocket_setTcpMd5Sig },
{ "joinGroup", "(IZ[B[BII)V", (void *) netty_io_uring_linuxsocket_joinGroup },
{ "joinSsmGroup", "(IZ[B[BII[B)V", (void *) netty_io_uring_linuxsocket_joinSsmGroup },
{ "leaveGroup", "(IZ[B[BII)V", (void *) netty_io_uring_linuxsocket_leaveGroup },
{ "leaveSsmGroup", "(IZ[B[BII[B)V", (void *) netty_io_uring_linuxsocket_leaveSsmGroup }
// "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_PREPEND(packagePrefix, "io/netty/channel/unix/PeerCredentials;", dynamicTypeName, error);
NETTY_PREPEND("(I)L", dynamicTypeName, dynamicMethod->signature, error);
dynamicMethod->name = "getPeerCredentials";
dynamicMethod->fnPtr = (void *) netty_io_uring_linuxsocket_getPeerCredentials;
netty_unix_util_free_dynamic_name(&dynamicTypeName);
++dynamicMethod;
NETTY_PREPEND(packagePrefix, "io/netty/channel/DefaultFileRegion;JJJ)J", dynamicTypeName, error);
NETTY_PREPEND("(IL", dynamicTypeName, dynamicMethod->signature, error);
dynamicMethod->name = "sendFile";
dynamicMethod->fnPtr = (void *) netty_io_uring_linuxsocket_sendFile;
netty_unix_util_free_dynamic_name(&dynamicTypeName);
return dynamicMethods;
error:
free(dynamicTypeName);
netty_unix_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize());
return NULL;
}
// JNI Method Registration Table End
jint netty_io_uring_linuxsocket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
int ret = JNI_ERR;
char* nettyClassName = NULL;
jclass fileRegionCls = NULL;
jclass fileChannelCls = NULL;
jclass fileDescriptorCls = NULL;
// Register the methods which are not referenced by static member variables
JNINativeMethod* dynamicMethods = createDynamicMethodsTable(packagePrefix);
if (dynamicMethods == NULL) {
goto done;
}
if (netty_unix_util_register_natives(env,
packagePrefix,
"io/netty/channel/uring/LinuxSocket",
dynamicMethods,
dynamicMethodsTableSize()) != 0) {
goto done;
}
NETTY_PREPEND(packagePrefix, "io/netty/channel/unix/PeerCredentials", nettyClassName, done);
NETTY_LOAD_CLASS(env, peerCredentialsClass, nettyClassName, done);
netty_unix_util_free_dynamic_name(&nettyClassName);
NETTY_GET_METHOD(env, peerCredentialsClass, peerCredentialsMethodId, "<init>", "(II[I)V", done);
NETTY_PREPEND(packagePrefix, "io/netty/channel/DefaultFileRegion", nettyClassName, done);
NETTY_FIND_CLASS(env, fileRegionCls, nettyClassName, done);
netty_unix_util_free_dynamic_name(&nettyClassName);
NETTY_GET_FIELD(env, fileRegionCls, fileChannelFieldId, "file", "Ljava/nio/channels/FileChannel;", done);
NETTY_GET_FIELD(env, fileRegionCls, transferredFieldId, "transferred", "J", done);
NETTY_FIND_CLASS(env, fileChannelCls, "sun/nio/ch/FileChannelImpl", done);
NETTY_GET_FIELD(env, fileChannelCls, fileDescriptorFieldId, "fd", "Ljava/io/FileDescriptor;", done);
NETTY_FIND_CLASS(env, fileDescriptorCls, "java/io/FileDescriptor", done);
NETTY_GET_FIELD(env, fileDescriptorCls, fdFieldId, "fd", "I", done);
ret = NETTY_JNI_VERSION;
done:
netty_unix_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize());
free(nettyClassName);
return ret;
}
void netty_io_uring_linuxsocket_JNI_OnUnLoad(JNIEnv* env) {
NETTY_UNLOAD_CLASS(env, peerCredentialsClass);
}

View File

@ -0,0 +1,26 @@
/*
* Copyright 2016 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://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_IO_URING_LINUXSOCKET_H_
#define NETTY_IO_URING_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_io_uring_linuxsocket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix);
void netty_io_uring_linuxsocket_JNI_OnUnLoad(JNIEnv* env);
#endif

View File

@ -32,6 +32,7 @@
#include <unistd.h> #include <unistd.h>
#include "syscall.h" #include "syscall.h"
#include "netty_io_uring_linuxsocket.h"
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdbool.h> #include <stdbool.h>
@ -228,20 +229,23 @@ static void netty_epoll_native_eventFdWrite(JNIEnv* env, jclass clazz, jint fd,
static void netty_io_uring_ring_buffer_exit(JNIEnv *env, jclass class, jobject ringBuffer) { static void netty_io_uring_ring_buffer_exit(JNIEnv *env, jclass class, jobject ringBuffer) {
// Find the id of the Java method to be called // Find the id of the Java method to be called
jclass ringBufferClass = (*env)->GetObjectClass(env, ringBuffer);
jmethodID submissionQueueMethodId = (*env)->GetMethodID(env, ringBufferClass, "getIoUringSubmissionQueue", "()Lio/netty/channel/uring/IOUringSubmissionQueue;"); jmethodID submissionQueueMethodId = (*env)->GetMethodID(env, ringBufferClass, "getIoUringSubmissionQueue", "()Lio/netty/channel/uring/IOUringSubmissionQueue;");
jmethodID completionQueueMethodId = (*env)->GetMethodID(env, ringBufferClass, "getIoUringCompletionQueue", "()Lio/netty/channel/uring/IOUringCompletionQueue;"); jmethodID completionQueueMethodId = (*env)->GetMethodID(env, ringBufferClass, "getIoUringCompletionQueue", "()Lio/netty/channel/uring/IOUringCompletionQueue;");
jobject submissionQueue = (*env)->CallObjectMethod(env, ringBuffer, submissionQueueMethodId); jobject submissionQueue = (*env)->CallObjectMethod(env, ringBuffer, submissionQueueMethodId);
jobject completionQueue = (*env)->CallObjectMethod(env, ringBuffer, completionQueueMethodId); jobject completionQueue = (*env)->CallObjectMethod(env, ringBuffer, completionQueueMethodId);
jclass submissionQueueClass = (*env)->GetObjectClass(env, submissionQueue);
jclass completionQueueClass = (*env)->GetObjectClass(env, completionQueue);
jmethodID submissionQueueArrayAddressMethodId = (*env)->GetMethodID(env, ioUringSubmissionQueueClass, "getSubmissionQueueArrayAddress", "()J"); jmethodID submissionQueueArrayAddressMethodId = (*env)->GetMethodID(env, submissionQueueClass, "getSubmissionQueueArrayAddress", "()J");
jmethodID submissionQueueKringEntriesAddressMethodId = (*env)->GetMethodID(env, ioUringSubmissionQueueClass, "getKRingEntriesAddress", "()J"); jmethodID submissionQueueKringEntriesAddressMethodId = (*env)->GetMethodID(env, submissionQueueClass, "getKRingEntriesAddress", "()J");
jmethodID submissionQueueRingFdMethodId = (*env)->GetMethodID(env, ioUringSubmissionQueueClass, "getRingFd", "()I"); jmethodID submissionQueueRingFdMethodId = (*env)->GetMethodID(env, submissionQueueClass, "getRingFd", "()I");
jmethodID submissionQueueRingAddressMethodId = (*env)->GetMethodID(env, ioUringSubmissionQueueClass, "getRingAddress", "()J"); jmethodID submissionQueueRingAddressMethodId = (*env)->GetMethodID(env, submissionQueueClass, "getRingAddress", "()J");
jmethodID submissionQueueRingSizeMethodId = (*env)->GetMethodID(env, ioUringSubmissionQueueClass, "getRingSize", "()I"); jmethodID submissionQueueRingSizeMethodId = (*env)->GetMethodID(env, submissionQueueClass, "getRingSize", "()I");
jmethodID completionQueueRingAddressMethodId = (*env)->GetMethodID(env, ioUringCompletionQueueClass, "getRingAddress", "()J"); jmethodID completionQueueRingAddressMethodId = (*env)->GetMethodID(env, completionQueueClass, "getRingAddress", "()J");
jmethodID completionQueueRingSizeMethodId = (*env)->GetMethodID(env, ioUringCompletionQueueClass, "getRingSize", "()I"); jmethodID completionQueueRingSizeMethodId = (*env)->GetMethodID(env, completionQueueClass, "getRingSize", "()I");
jlong submissionQueueArrayAddress = (*env)->CallLongMethod(env, submissionQueue, submissionQueueArrayAddressMethodId); jlong submissionQueueArrayAddress = (*env)->CallLongMethod(env, submissionQueue, submissionQueueArrayAddressMethodId);
jlong submissionQueueKringEntriesAddress = (*env)->CallLongMethod(env, submissionQueue, submissionQueueKringEntriesAddressMethodId); jlong submissionQueueKringEntriesAddress = (*env)->CallLongMethod(env, submissionQueue, submissionQueueKringEntriesAddressMethodId);
@ -273,7 +277,8 @@ static jobject netty_io_uring_setup(JNIEnv *env, jclass class1, jint entries) {
int ring_fd = sys_io_uring_setup((int)entries, &p); int ring_fd = sys_io_uring_setup((int)entries, &p);
//Todo //Todo
if (ring_fd < -1) { if (ring_fd < 0) {
printf("RingFd error: %d\n", ring_fd);
//throw Exception //throw Exception
return NULL; return NULL;
} }
@ -335,6 +340,7 @@ JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
int filedescriptorOnLoadCalled = 0; int filedescriptorOnLoadCalled = 0;
int socketOnLoadCalled = 0; int socketOnLoadCalled = 0;
int bufferOnLoadCalled = 0; int bufferOnLoadCalled = 0;
int linuxsocketOnLoadCalled = 0;
JNIEnv *env; JNIEnv *env;
char *nettyClassName = NULL; char *nettyClassName = NULL;
@ -393,6 +399,11 @@ JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
} }
bufferOnLoadCalled = 1; bufferOnLoadCalled = 1;
if (netty_io_uring_linuxsocket_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
goto done;
}
linuxsocketOnLoadCalled = 1;
NETTY_PREPEND(packagePrefix, "io/netty/channel/uring/RingBuffer", NETTY_PREPEND(packagePrefix, "io/netty/channel/uring/RingBuffer",
nettyClassName, done); nettyClassName, done);
NETTY_LOAD_CLASS(env, ringBufferClass, nettyClassName, done); NETTY_LOAD_CLASS(env, ringBufferClass, nettyClassName, done);
@ -435,6 +446,9 @@ done:
if (bufferOnLoadCalled == 1) { if (bufferOnLoadCalled == 1) {
netty_unix_buffer_JNI_OnUnLoad(env); netty_unix_buffer_JNI_OnUnLoad(env);
} }
if (linuxsocketOnLoadCalled == 1) {
netty_io_uring_linuxsocket_JNI_OnUnLoad(env);
}
ringBufferMethodId = NULL; ringBufferMethodId = NULL;
ioUringSubmissionQueueMethodId = NULL; ioUringSubmissionQueueMethodId = NULL;

View File

@ -41,14 +41,14 @@ import static io.netty.util.internal.ObjectUtil.*;
abstract class AbstractIOUringChannel extends AbstractChannel implements UnixChannel { abstract class AbstractIOUringChannel extends AbstractChannel implements UnixChannel {
private static final ChannelMetadata METADATA = new ChannelMetadata(false); private static final ChannelMetadata METADATA = new ChannelMetadata(false);
final Socket socket; final LinuxSocket socket;
protected volatile boolean active; protected volatile boolean active;
boolean uringInReadyPending; boolean uringInReadyPending;
private volatile SocketAddress local; private volatile SocketAddress local;
private volatile SocketAddress remote; private volatile SocketAddress remote;
AbstractIOUringChannel(final Channel parent, Socket socket) { AbstractIOUringChannel(final Channel parent, LinuxSocket socket) {
super(parent); super(parent);
this.socket = checkNotNull(socket, "fd"); this.socket = checkNotNull(socket, "fd");
this.active = true; this.active = true;
@ -61,6 +61,17 @@ abstract class AbstractIOUringChannel extends AbstractChannel implements UnixCha
} }
} }
protected AbstractIOUringChannel(final Channel parent, LinuxSocket socket, boolean active) {
super(parent);
this.socket = checkNotNull(socket, "fd");
this.active = active;
if (active) {
this.local = socket.localAddress();
this.remote = socket.remoteAddress();
}
}
public boolean isOpen() { public boolean isOpen() {
return socket.isOpen(); return socket.isOpen();
} }

View File

@ -26,10 +26,10 @@ import java.net.SocketAddress;
abstract class AbstractIOUringServerChannel extends AbstractIOUringChannel implements ServerChannel { abstract class AbstractIOUringServerChannel extends AbstractIOUringChannel implements ServerChannel {
AbstractIOUringServerChannel(int fd) { AbstractIOUringServerChannel(int fd) {
super(null, new Socket(fd)); super(null, new LinuxSocket(fd));
} }
AbstractIOUringServerChannel(Socket fd) { AbstractIOUringServerChannel(LinuxSocket fd) {
super(null, fd); super(null, fd);
} }

View File

@ -0,0 +1,44 @@
/*
* 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:
*
* http://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.uring;
import io.netty.channel.ChannelOption;
import io.netty.channel.unix.UnixChannelOption;
import java.net.InetAddress;
import java.util.Map;
public class IOUringChannelOption<T> extends UnixChannelOption<T> {
public static final ChannelOption<Boolean> TCP_CORK = valueOf(IOUringChannelOption.class, "TCP_CORK");
public static final ChannelOption<Long> TCP_NOTSENT_LOWAT =
valueOf(IOUringChannelOption.class, "TCP_NOTSENT_LOWAT");
public static final ChannelOption<Integer> TCP_KEEPIDLE = valueOf(IOUringChannelOption.class, "TCP_KEEPIDLE");
public static final ChannelOption<Integer> TCP_KEEPINTVL = valueOf(IOUringChannelOption.class, "TCP_KEEPINTVL");
public static final ChannelOption<Integer> TCP_KEEPCNT = valueOf(IOUringChannelOption.class, "TCP_KEEPCNT");
public static final ChannelOption<Integer> TCP_USER_TIMEOUT =
valueOf(IOUringChannelOption.class, "TCP_USER_TIMEOUT");
public static final ChannelOption<Boolean> IP_FREEBIND = valueOf("IP_FREEBIND");
public static final ChannelOption<Boolean> IP_TRANSPARENT = valueOf("IP_TRANSPARENT");
public static final ChannelOption<Boolean> IP_RECVORIGDSTADDR = valueOf("IP_RECVORIGDSTADDR");
public static final ChannelOption<Integer> TCP_FASTOPEN = valueOf(IOUringChannelOption.class, "TCP_FASTOPEN");
public static final ChannelOption<Boolean> TCP_FASTOPEN_CONNECT =
valueOf(IOUringChannelOption.class, "TCP_FASTOPEN_CONNECT");
public static final ChannelOption<Integer> TCP_DEFER_ACCEPT =
ChannelOption.valueOf(IOUringChannelOption.class, "TCP_DEFER_ACCEPT");
public static final ChannelOption<Boolean> TCP_QUICKACK = valueOf(IOUringChannelOption.class, "TCP_QUICKACK");
public static final ChannelOption<Map<InetAddress, byte[]>> TCP_MD5SIG = valueOf("TCP_MD5SIG");
}

View File

@ -20,8 +20,13 @@ import io.netty.channel.socket.ServerSocketChannel;
import io.netty.channel.unix.FileDescriptor; import io.netty.channel.unix.FileDescriptor;
import io.netty.channel.unix.Socket; import io.netty.channel.unix.Socket;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
public final class IOUringServerSocketChannel extends AbstractIOUringServerChannel implements ServerSocketChannel { public final class IOUringServerSocketChannel extends AbstractIOUringServerChannel implements ServerSocketChannel {
private final IOUringServerSocketChannelConfig config; private final IOUringServerSocketChannelConfig config;
@ -38,12 +43,7 @@ public final class IOUringServerSocketChannel extends AbstractIOUringServerChann
@Override @Override
Channel newChildChannel(int fd) throws Exception { Channel newChildChannel(int fd) throws Exception {
return new IOUringSocketChannel(this, new Socket(fd)); return new IOUringSocketChannel(this, new LinuxSocket(fd));
}
@Override
public ServerSocketChannel parent() {
return (ServerSocketChannel) super.parent();
} }
@Override @Override
@ -59,8 +59,7 @@ public final class IOUringServerSocketChannel extends AbstractIOUringServerChann
@Override @Override
public void doBind(SocketAddress localAddress) throws Exception { public void doBind(SocketAddress localAddress) throws Exception {
super.doBind(localAddress); super.doBind(localAddress);
//Todo set config option socket.listen(config.getBacklog());
socket.listen(500);
active = true; active = true;
} }

View File

@ -15,8 +15,18 @@
*/ */
package io.netty.channel.uring; package io.netty.channel.uring;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.ChannelException;
import io.netty.channel.ChannelOption;
import io.netty.channel.MessageSizeEstimator;
import io.netty.channel.RecvByteBufAllocator;
import io.netty.channel.WriteBufferWaterMark;
import io.netty.channel.socket.ServerSocketChannelConfig; import io.netty.channel.socket.ServerSocketChannelConfig;
import java.io.IOException;
import java.net.InetAddress;
import java.util.Map;
public class IOUringServerSocketChannelConfig extends IOUringServerChannelConfig implements ServerSocketChannelConfig { public class IOUringServerSocketChannelConfig extends IOUringServerChannelConfig implements ServerSocketChannelConfig {
IOUringServerSocketChannelConfig(AbstractIOUringServerChannel channel) { IOUringServerSocketChannelConfig(AbstractIOUringServerChannel channel) {
@ -29,4 +39,241 @@ public class IOUringServerSocketChannelConfig extends IOUringServerChannelConfig
super.setReuseAddress(reuseAddress); super.setReuseAddress(reuseAddress);
return this; return this;
} }
@Override
public Map<ChannelOption<?>, Object> getOptions() {
return getOptions(super.getOptions(), IOUringChannelOption.SO_REUSEPORT, IOUringChannelOption.IP_FREEBIND,
IOUringChannelOption.IP_TRANSPARENT, IOUringChannelOption.TCP_DEFER_ACCEPT);
}
@SuppressWarnings("unchecked")
@Override
public <T> T getOption(ChannelOption<T> option) {
if (option == IOUringChannelOption.SO_REUSEPORT) {
return (T) Boolean.valueOf(isReusePort());
}
if (option == IOUringChannelOption.IP_FREEBIND) {
return (T) Boolean.valueOf(isFreeBind());
}
if (option == IOUringChannelOption.IP_TRANSPARENT) {
return (T) Boolean.valueOf(isIpTransparent());
}
if (option == IOUringChannelOption.TCP_DEFER_ACCEPT) {
return (T) Integer.valueOf(getTcpDeferAccept());
}
return super.getOption(option);
}
@Override
public <T> boolean setOption(ChannelOption<T> option, T value) {
validate(option, value);
if (option == IOUringChannelOption.SO_REUSEPORT) {
setReusePort((Boolean) value);
} else if (option == IOUringChannelOption.IP_FREEBIND) {
setFreeBind((Boolean) value);
} else if (option == IOUringChannelOption.IP_TRANSPARENT) {
setIpTransparent((Boolean) value);
} else if (option == IOUringChannelOption.TCP_DEFER_ACCEPT) {
setTcpDeferAccept((Integer) value);
} else {
return super.setOption(option, value);
}
return true;
}
@Override
public IOUringServerSocketChannelConfig setReceiveBufferSize(int receiveBufferSize) {
super.setReceiveBufferSize(receiveBufferSize);
return this;
}
@Override
public IOUringServerSocketChannelConfig setPerformancePreferences(int connectionTime, int latency, int bandwidth) {
return this;
}
@Override
public IOUringServerSocketChannelConfig setBacklog(int backlog) {
super.setBacklog(backlog);
return this;
}
@Override
public IOUringServerSocketChannelConfig setConnectTimeoutMillis(int connectTimeoutMillis) {
super.setConnectTimeoutMillis(connectTimeoutMillis);
return this;
}
@Override
@Deprecated
public IOUringServerSocketChannelConfig setMaxMessagesPerRead(int maxMessagesPerRead) {
super.setMaxMessagesPerRead(maxMessagesPerRead);
return this;
}
@Override
public IOUringServerSocketChannelConfig setWriteSpinCount(int writeSpinCount) {
super.setWriteSpinCount(writeSpinCount);
return this;
}
@Override
public IOUringServerSocketChannelConfig setAllocator(ByteBufAllocator allocator) {
super.setAllocator(allocator);
return this;
}
@Override
public IOUringServerSocketChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) {
super.setRecvByteBufAllocator(allocator);
return this;
}
@Override
public IOUringServerSocketChannelConfig setAutoRead(boolean autoRead) {
super.setAutoRead(autoRead);
return this;
}
@Override
@Deprecated
public IOUringServerSocketChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark) {
super.setWriteBufferHighWaterMark(writeBufferHighWaterMark);
return this;
}
@Override
@Deprecated
public IOUringServerSocketChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark) {
super.setWriteBufferLowWaterMark(writeBufferLowWaterMark);
return this;
}
@Override
public IOUringServerSocketChannelConfig setWriteBufferWaterMark(WriteBufferWaterMark writeBufferWaterMark) {
super.setWriteBufferWaterMark(writeBufferWaterMark);
return this;
}
@Override
public IOUringServerSocketChannelConfig setMessageSizeEstimator(MessageSizeEstimator estimator) {
super.setMessageSizeEstimator(estimator);
return this;
}
// /**
// * Set the {@code TCP_MD5SIG} option on the socket. See {@code linux/tcp.h} for more details.
// * Keys can only be set on, not read to prevent a potential leak, as they are confidential.
// * Allowing them being read would mean anyone with access to the channel could get them.
// */
// public IOUringServerSocketChannelConfig setTcpMd5Sig(Map<InetAddress, byte[]> keys) {
// try {
// ((IOUringServerSocketChannel) channel).setTcpMd5Sig(keys);
// return this;
// } catch (IOException e) {
// throw new ChannelException(e);
// }
// }
/**
* Returns {@code true} if the SO_REUSEPORT option is set.
*/
public boolean isReusePort() {
try {
return ((IOUringServerSocketChannel) channel).socket.isReusePort();
} catch (IOException e) {
throw new ChannelException(e);
}
}
// /**
// * Set the SO_REUSEPORT option on the underlying Channel. This will allow to bind multiple
// * {@link EpollSocketChannel}s to the same port and so accept connections with multiple threads.
// *
// * Be aware this method needs be called before {@link EpollSocketChannel#bind(java.net.SocketAddress)} to have
// * any affect.
// */
public IOUringServerSocketChannelConfig setReusePort(boolean reusePort) {
try {
((IOUringServerSocketChannel) channel).socket.setReusePort(reusePort);
return this;
} catch (IOException e) {
throw new ChannelException(e);
}
}
/**
* Returns {@code true} if <a href="http://man7.org/linux/man-pages/man7/ip.7.html">IP_FREEBIND</a> is enabled,
* {@code false} otherwise.
*/
public boolean isFreeBind() {
try {
return ((IOUringServerSocketChannel) channel).socket.isIpFreeBind();
} catch (IOException e) {
throw new ChannelException(e);
}
}
/**
* If {@code true} is used <a href="http://man7.org/linux/man-pages/man7/ip.7.html">IP_FREEBIND</a> is enabled,
* {@code false} for disable it. Default is disabled.
*/
public IOUringServerSocketChannelConfig setFreeBind(boolean freeBind) {
try {
((IOUringServerSocketChannel) channel).socket.setIpFreeBind(freeBind);
return this;
} catch (IOException e) {
throw new ChannelException(e);
}
}
/**
* Returns {@code true} if <a href="http://man7.org/linux/man-pages/man7/ip.7.html">IP_TRANSPARENT</a> is enabled,
* {@code false} otherwise.
*/
public boolean isIpTransparent() {
try {
return ((IOUringServerSocketChannel) channel).socket.isIpTransparent();
} catch (IOException e) {
throw new ChannelException(e);
}
}
/**
* If {@code true} is used <a href="http://man7.org/linux/man-pages/man7/ip.7.html">IP_TRANSPARENT</a> is enabled,
* {@code false} for disable it. Default is disabled.
*/
public IOUringServerSocketChannelConfig setIpTransparent(boolean transparent) {
try {
((IOUringServerSocketChannel) channel).socket.setIpTransparent(transparent);
return this;
} catch (IOException e) {
throw new ChannelException(e);
}
}
/**
* Set the {@code TCP_DEFER_ACCEPT} option on the socket. See {@code man 7 tcp} for more details.
*/
public IOUringServerSocketChannelConfig setTcpDeferAccept(int deferAccept) {
try {
((IOUringServerSocketChannel) channel).socket.setTcpDeferAccept(deferAccept);
return this;
} catch (IOException e) {
throw new ChannelException(e);
}
}
/**
* Returns a positive value if <a href="http://linux.die.net/man/7/tcp">TCP_DEFER_ACCEPT</a> is enabled.
*/
public int getTcpDeferAccept() {
try {
return ((IOUringServerSocketChannel) channel).socket.getTcpDeferAccept();
} catch (IOException e) {
throw new ChannelException(e);
}
}
} }

View File

@ -36,7 +36,12 @@ import java.net.SocketAddress;
public final class IOUringSocketChannel extends AbstractIOUringChannel implements SocketChannel { public final class IOUringSocketChannel extends AbstractIOUringChannel implements SocketChannel {
private final IOUringSocketChannelConfig config; private final IOUringSocketChannelConfig config;
IOUringSocketChannel(final Channel parent, final Socket fd) { public IOUringSocketChannel() {
super(null, LinuxSocket.newSocketStream(), false);
this.config = new IOUringSocketChannelConfig(this);
}
IOUringSocketChannel(final Channel parent, final LinuxSocket fd) {
super(parent, fd); super(parent, fd);
this.config = new IOUringSocketChannelConfig(this); this.config = new IOUringSocketChannelConfig(this);
} }

View File

@ -16,7 +16,9 @@
package io.netty.channel.uring; package io.netty.channel.uring;
import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelException; import io.netty.channel.ChannelException;
import io.netty.channel.ChannelOption;
import io.netty.channel.DefaultChannelConfig; import io.netty.channel.DefaultChannelConfig;
import io.netty.channel.MessageSizeEstimator; import io.netty.channel.MessageSizeEstimator;
import io.netty.channel.RecvByteBufAllocator; import io.netty.channel.RecvByteBufAllocator;
@ -24,25 +26,132 @@ import io.netty.channel.WriteBufferWaterMark;
import io.netty.channel.socket.SocketChannelConfig; import io.netty.channel.socket.SocketChannelConfig;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress;
import java.util.Map;
import static io.netty.channel.ChannelOption.*;
import static io.netty.channel.unix.Limits.*;
public class IOUringSocketChannelConfig extends DefaultChannelConfig implements SocketChannelConfig { public class IOUringSocketChannelConfig extends DefaultChannelConfig implements SocketChannelConfig {
private volatile boolean allowHalfClosure; private volatile boolean allowHalfClosure;
private volatile long maxBytesPerGatheringWrite = SSIZE_MAX;
/** public IOUringSocketChannelConfig(Channel channel) {
* Creates a new instance.
*/
IOUringSocketChannelConfig(IOUringSocketChannel channel) {
super(channel); super(channel);
} }
@Override @Override
public int getReceiveBufferSize() { public Map<ChannelOption<?>, Object> getOptions() {
try { return getOptions(
return ((IOUringSocketChannel) channel).socket.getReceiveBufferSize(); super.getOptions(),
} catch (IOException e) { SO_RCVBUF, SO_SNDBUF, TCP_NODELAY, SO_KEEPALIVE, SO_REUSEADDR, SO_LINGER, IP_TOS,
throw new ChannelException(e); ALLOW_HALF_CLOSURE, IOUringChannelOption.TCP_CORK, IOUringChannelOption.TCP_NOTSENT_LOWAT,
IOUringChannelOption.TCP_KEEPCNT, IOUringChannelOption.TCP_KEEPIDLE, IOUringChannelOption.TCP_KEEPINTVL,
IOUringChannelOption.TCP_QUICKACK, IOUringChannelOption.IP_TRANSPARENT,
IOUringChannelOption.TCP_FASTOPEN_CONNECT);
}
@SuppressWarnings("unchecked")
@Override
public <T> T getOption(ChannelOption<T> option) {
if (option == SO_RCVBUF) {
return (T) Integer.valueOf(getReceiveBufferSize());
} }
if (option == SO_SNDBUF) {
return (T) Integer.valueOf(getSendBufferSize());
}
if (option == TCP_NODELAY) {
return (T) Boolean.valueOf(isTcpNoDelay());
}
if (option == SO_KEEPALIVE) {
return (T) Boolean.valueOf(isKeepAlive());
}
if (option == SO_REUSEADDR) {
return (T) Boolean.valueOf(isReuseAddress());
}
if (option == SO_LINGER) {
return (T) Integer.valueOf(getSoLinger());
}
if (option == IP_TOS) {
return (T) Integer.valueOf(getTrafficClass());
}
if (option == ALLOW_HALF_CLOSURE) {
return (T) Boolean.valueOf(isAllowHalfClosure());
}
if (option == IOUringChannelOption.TCP_CORK) {
return (T) Boolean.valueOf(isTcpCork());
}
if (option == IOUringChannelOption.TCP_NOTSENT_LOWAT) {
return (T) Long.valueOf(getTcpNotSentLowAt());
}
if (option == IOUringChannelOption.TCP_KEEPIDLE) {
return (T) Integer.valueOf(getTcpKeepIdle());
}
if (option == IOUringChannelOption.TCP_KEEPINTVL) {
return (T) Integer.valueOf(getTcpKeepIntvl());
}
if (option == IOUringChannelOption.TCP_KEEPCNT) {
return (T) Integer.valueOf(getTcpKeepCnt());
}
if (option == IOUringChannelOption.TCP_USER_TIMEOUT) {
return (T) Integer.valueOf(getTcpUserTimeout());
}
if (option == IOUringChannelOption.TCP_QUICKACK) {
return (T) Boolean.valueOf(isTcpQuickAck());
}
if (option == IOUringChannelOption.IP_TRANSPARENT) {
return (T) Boolean.valueOf(isIpTransparent());
}
if (option == IOUringChannelOption.TCP_FASTOPEN_CONNECT) {
return (T) Boolean.valueOf(isTcpFastOpenConnect());
}
return super.getOption(option);
}
@Override
public <T> boolean setOption(ChannelOption<T> option, T value) {
validate(option, value);
if (option == SO_RCVBUF) {
setReceiveBufferSize((Integer) value);
} else if (option == SO_SNDBUF) {
setSendBufferSize((Integer) value);
} else if (option == TCP_NODELAY) {
setTcpNoDelay((Boolean) value);
} else if (option == SO_KEEPALIVE) {
setKeepAlive((Boolean) value);
} else if (option == SO_REUSEADDR) {
setReuseAddress((Boolean) value);
} else if (option == SO_LINGER) {
setSoLinger((Integer) value);
} else if (option == IP_TOS) {
setTrafficClass((Integer) value);
} else if (option == ALLOW_HALF_CLOSURE) {
setAllowHalfClosure((Boolean) value);
} else if (option == IOUringChannelOption.TCP_CORK) {
setTcpCork((Boolean) value);
} else if (option == IOUringChannelOption.TCP_NOTSENT_LOWAT) {
setTcpNotSentLowAt((Long) value);
} else if (option == IOUringChannelOption.TCP_KEEPIDLE) {
setTcpKeepIdle((Integer) value);
} else if (option == IOUringChannelOption.TCP_KEEPCNT) {
setTcpKeepCnt((Integer) value);
} else if (option == IOUringChannelOption.TCP_KEEPINTVL) {
setTcpKeepIntvl((Integer) value);
} else if (option == IOUringChannelOption.TCP_USER_TIMEOUT) {
setTcpUserTimeout((Integer) value);
} else if (option == IOUringChannelOption.IP_TRANSPARENT) {
setIpTransparent((Boolean) value);
} else if (option == IOUringChannelOption.TCP_QUICKACK) {
setTcpQuickAck((Boolean) value);
} else if (option == IOUringChannelOption.TCP_FASTOPEN_CONNECT) {
setTcpFastOpenConnect((Boolean) value);
} else {
return super.setOption(option, value);
}
return true;
} }
@Override @Override
@ -99,6 +208,85 @@ public class IOUringSocketChannelConfig extends DefaultChannelConfig implements
} }
} }
/**
* Get the {@code TCP_CORK} option on the socket. See {@code man 7 tcp} for more details.
*/
public boolean isTcpCork() {
try {
return ((IOUringSocketChannel) channel).socket.isTcpCork();
} catch (IOException e) {
throw new ChannelException(e);
}
}
/**
* Get the {@code SO_BUSY_POLL} option on the socket. See {@code man 7 tcp} for more details.
*/
public int getSoBusyPoll() {
try {
return ((IOUringSocketChannel) channel).socket.getSoBusyPoll();
} catch (IOException e) {
throw new ChannelException(e);
}
}
/**
* Get the {@code TCP_NOTSENT_LOWAT} option on the socket. See {@code man 7 tcp} for more details.
*
* @return value is a uint32_t
*/
public long getTcpNotSentLowAt() {
try {
return ((IOUringSocketChannel) channel).socket.getTcpNotSentLowAt();
} catch (IOException e) {
throw new ChannelException(e);
}
}
/**
* Get the {@code TCP_KEEPIDLE} option on the socket. See {@code man 7 tcp} for more details.
*/
public int getTcpKeepIdle() {
try {
return ((IOUringSocketChannel) channel).socket.getTcpKeepIdle();
} catch (IOException e) {
throw new ChannelException(e);
}
}
/**
* Get the {@code TCP_KEEPINTVL} option on the socket. See {@code man 7 tcp} for more details.
*/
public int getTcpKeepIntvl() {
try {
return ((IOUringSocketChannel) channel).socket.getTcpKeepIntvl();
} catch (IOException e) {
throw new ChannelException(e);
}
}
/**
* Get the {@code TCP_KEEPCNT} option on the socket. See {@code man 7 tcp} for more details.
*/
public int getTcpKeepCnt() {
try {
return ((IOUringSocketChannel) channel).socket.getTcpKeepCnt();
} catch (IOException e) {
throw new ChannelException(e);
}
}
/**
* Get the {@code TCP_USER_TIMEOUT} option on the socket. See {@code man 7 tcp} for more details.
*/
public int getTcpUserTimeout() {
try {
return ((IOUringSocketChannel) channel).socket.getTcpUserTimeout();
} catch (IOException e) {
throw new ChannelException(e);
}
}
@Override @Override
public IOUringSocketChannelConfig setKeepAlive(boolean keepAlive) { public IOUringSocketChannelConfig setKeepAlive(boolean keepAlive) {
try { try {
@ -139,12 +327,22 @@ public class IOUringSocketChannelConfig extends DefaultChannelConfig implements
public IOUringSocketChannelConfig setSendBufferSize(int sendBufferSize) { public IOUringSocketChannelConfig setSendBufferSize(int sendBufferSize) {
try { try {
((IOUringSocketChannel) channel).socket.setSendBufferSize(sendBufferSize); ((IOUringSocketChannel) channel).socket.setSendBufferSize(sendBufferSize);
calculateMaxBytesPerGatheringWrite();
return this; return this;
} catch (IOException e) { } catch (IOException e) {
throw new ChannelException(e); throw new ChannelException(e);
} }
} }
@Override
public int getReceiveBufferSize() {
try {
return ((IOUringSocketChannel) channel).socket.getReceiveBufferSize();
} catch (IOException e) {
throw new ChannelException(e);
}
}
@Override @Override
public IOUringSocketChannelConfig setSoLinger(int soLinger) { public IOUringSocketChannelConfig setSoLinger(int soLinger) {
try { try {
@ -165,6 +363,44 @@ public class IOUringSocketChannelConfig extends DefaultChannelConfig implements
} }
} }
/**
* Set the {@code TCP_CORK} option on the socket. See {@code man 7 tcp} for more details.
*/
public IOUringSocketChannelConfig setTcpCork(boolean tcpCork) {
try {
((IOUringSocketChannel) channel).socket.setTcpCork(tcpCork);
return this;
} catch (IOException e) {
throw new ChannelException(e);
}
}
/**
* Set the {@code SO_BUSY_POLL} option on the socket. See {@code man 7 tcp} for more details.
*/
public IOUringSocketChannelConfig setSoBusyPoll(int loopMicros) {
try {
((IOUringSocketChannel) channel).socket.setSoBusyPoll(loopMicros);
return this;
} catch (IOException e) {
throw new ChannelException(e);
}
}
/**
* Set the {@code TCP_NOTSENT_LOWAT} option on the socket. See {@code man 7 tcp} for more details.
*
* @param tcpNotSentLowAt is a uint32_t
*/
public IOUringSocketChannelConfig setTcpNotSentLowAt(long tcpNotSentLowAt) {
try {
((IOUringSocketChannel) channel).socket.setTcpNotSentLowAt(tcpNotSentLowAt);
return this;
} catch (IOException e) {
throw new ChannelException(e);
}
}
@Override @Override
public IOUringSocketChannelConfig setTrafficClass(int trafficClass) { public IOUringSocketChannelConfig setTrafficClass(int trafficClass) {
try { try {
@ -175,6 +411,151 @@ public class IOUringSocketChannelConfig extends DefaultChannelConfig implements
} }
} }
/**
* Set the {@code TCP_KEEPIDLE} option on the socket. See {@code man 7 tcp} for more details.
*/
public IOUringSocketChannelConfig setTcpKeepIdle(int seconds) {
try {
((IOUringSocketChannel) channel).socket.setTcpKeepIdle(seconds);
return this;
} catch (IOException e) {
throw new ChannelException(e);
}
}
/**
* Set the {@code TCP_KEEPINTVL} option on the socket. See {@code man 7 tcp} for more details.
*/
public IOUringSocketChannelConfig setTcpKeepIntvl(int seconds) {
try {
((IOUringSocketChannel) channel).socket.setTcpKeepIntvl(seconds);
return this;
} catch (IOException e) {
throw new ChannelException(e);
}
}
/**
* @deprecated use {@link #setTcpKeepCnt(int)}
*/
@Deprecated
public IOUringSocketChannelConfig setTcpKeepCntl(int probes) {
return setTcpKeepCnt(probes);
}
/**
* Set the {@code TCP_KEEPCNT} option on the socket. See {@code man 7 tcp} for more details.
*/
public IOUringSocketChannelConfig setTcpKeepCnt(int probes) {
try {
((IOUringSocketChannel) channel).socket.setTcpKeepCnt(probes);
return this;
} catch (IOException e) {
throw new ChannelException(e);
}
}
/**
* Set the {@code TCP_USER_TIMEOUT} option on the socket. See {@code man 7 tcp} for more details.
*/
public IOUringSocketChannelConfig setTcpUserTimeout(int milliseconds) {
try {
((IOUringSocketChannel) channel).socket.setTcpUserTimeout(milliseconds);
return this;
} catch (IOException e) {
throw new ChannelException(e);
}
}
/**
* Returns {@code true} if <a href="http://man7.org/linux/man-pages/man7/ip.7.html">IP_TRANSPARENT</a> is enabled,
* {@code false} otherwise.
*/
public boolean isIpTransparent() {
try {
return ((IOUringSocketChannel) channel).socket.isIpTransparent();
} catch (IOException e) {
throw new ChannelException(e);
}
}
/**
* If {@code true} is used <a href="http://man7.org/linux/man-pages/man7/ip.7.html">IP_TRANSPARENT</a> is enabled,
* {@code false} for disable it. Default is disabled.
*/
public IOUringSocketChannelConfig setIpTransparent(boolean transparent) {
try {
((IOUringSocketChannel) channel).socket.setIpTransparent(transparent);
return this;
} catch (IOException e) {
throw new ChannelException(e);
}
}
// /**
// * Set the {@code TCP_MD5SIG} option on the socket. See {@code linux/tcp.h} for more details. Keys can only be set
// * on, not read to prevent a potential leak, as they are confidential. Allowing them being read would mean anyone
// * with access to the channel could get them.
// */
// public IOUringSocketChannelConfig setTcpMd5Sig(Map<InetAddress, byte[]> keys) {
// try {
// ((IOUringSocketChannel) channel).setTcpMd5Sig(keys);
// return this;
// } catch (IOException e) {
// throw new ChannelException(e);
// }
// }
/**
* Set the {@code TCP_QUICKACK} option on the socket. See <a href="http://linux.die.net/man/7/tcp">TCP_QUICKACK</a>
* for more details.
*/
public IOUringSocketChannelConfig setTcpQuickAck(boolean quickAck) {
try {
((IOUringSocketChannel) channel).socket.setTcpQuickAck(quickAck);
return this;
} catch (IOException e) {
throw new ChannelException(e);
}
}
/**
* Returns {@code true} if <a href="http://linux.die.net/man/7/tcp">TCP_QUICKACK</a> is enabled, {@code false}
* otherwise.
*/
public boolean isTcpQuickAck() {
try {
return ((IOUringSocketChannel) channel).socket.isTcpQuickAck();
} catch (IOException e) {
throw new ChannelException(e);
}
}
/**
* Set the {@code TCP_FASTOPEN_CONNECT} option on the socket. Requires Linux kernel 4.11 or later. See
* <a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=19f6d3f3">this commit</a>
* for more details.
*/
public IOUringSocketChannelConfig setTcpFastOpenConnect(boolean fastOpenConnect) {
try {
((IOUringSocketChannel) channel).socket.setTcpFastOpenConnect(fastOpenConnect);
return this;
} catch (IOException e) {
throw new ChannelException(e);
}
}
/**
* Returns {@code true} if {@code TCP_FASTOPEN_CONNECT} is enabled, {@code false} otherwise.
*/
public boolean isTcpFastOpenConnect() {
try {
return ((IOUringSocketChannel) channel).socket.isTcpFastOpenConnect();
} catch (IOException e) {
throw new ChannelException(e);
}
}
@Override @Override
public boolean isAllowHalfClosure() { public boolean isAllowHalfClosure() {
return allowHalfClosure; return allowHalfClosure;
@ -254,4 +635,16 @@ public class IOUringSocketChannelConfig extends DefaultChannelConfig implements
super.setMessageSizeEstimator(estimator); super.setMessageSizeEstimator(estimator);
return this; return this;
} }
final void setMaxBytesPerGatheringWrite(long maxBytesPerGatheringWrite) {
this.maxBytesPerGatheringWrite = maxBytesPerGatheringWrite;
}
private void calculateMaxBytesPerGatheringWrite() {
// Multiply by 2 to give some extra space in case the OS can process write data faster than we can provide.
int newSendBufferSize = getSendBufferSize() << 1;
if (newSendBufferSize > 0) {
setMaxBytesPerGatheringWrite(getSendBufferSize() << 1);
}
}
} }

View File

@ -0,0 +1,193 @@
/*
* 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:
*
* http://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.uring;
/**
* <p>
* struct tcp_info
* {
* __u8 tcpi_state;
* __u8 tcpi_ca_state;
* __u8 tcpi_retransmits;
* __u8 tcpi_probes;
* __u8 tcpi_backoff;
* __u8 tcpi_options;
* __u8 tcpi_snd_wscale : 4, tcpi_rcv_wscale : 4;
*
* __u32 tcpi_rto;
* __u32 tcpi_ato;
* __u32 tcpi_snd_mss;
* __u32 tcpi_rcv_mss;
*
* __u32 tcpi_unacked;
* __u32 tcpi_sacked;
* __u32 tcpi_lost;
* __u32 tcpi_retrans;
* __u32 tcpi_fackets;
*
* __u32 tcpi_last_data_sent;
* __u32 tcpi_last_ack_sent;
* __u32 tcpi_last_data_recv;
* __u32 tcpi_last_ack_recv;
*
* __u32 tcpi_pmtu;
* __u32 tcpi_rcv_ssthresh;
* __u32 tcpi_rtt;
* __u32 tcpi_rttvar;
* __u32 tcpi_snd_ssthresh;
* __u32 tcpi_snd_cwnd;
* __u32 tcpi_advmss;
* __u32 tcpi_reordering;
*
* __u32 tcpi_rcv_rtt;
* __u32 tcpi_rcv_space;
*
* __u32 tcpi_total_retrans;
* };
* </p>
*/
public final class IOUringTcpInfo {
final long[] info = new long[32];
public int state() {
return (int) info[0];
}
public int caState() {
return (int) info[1];
}
public int retransmits() {
return (int) info[2];
}
public int probes() {
return (int) info[3];
}
public int backoff() {
return (int) info[4];
}
public int options() {
return (int) info[5];
}
public int sndWscale() {
return (int) info[6];
}
public int rcvWscale() {
return (int) info[7];
}
public long rto() {
return info[8];
}
public long ato() {
return info[9];
}
public long sndMss() {
return info[10];
}
public long rcvMss() {
return info[11];
}
public long unacked() {
return info[12];
}
public long sacked() {
return info[13];
}
public long lost() {
return info[14];
}
public long retrans() {
return info[15];
}
public long fackets() {
return info[16];
}
public long lastDataSent() {
return info[17];
}
public long lastAckSent() {
return info[18];
}
public long lastDataRecv() {
return info[19];
}
public long lastAckRecv() {
return info[20];
}
public long pmtu() {
return info[21];
}
public long rcvSsthresh() {
return info[22];
}
public long rtt() {
return info[23];
}
public long rttvar() {
return info[24];
}
public long sndSsthresh() {
return info[25];
}
public long sndCwnd() {
return info[26];
}
public long advmss() {
return info[27];
}
public long reordering() {
return info[28];
}
public long rcvRtt() {
return info[29];
}
public long rcvSpace() {
return info[30];
}
public long totalRetrans() {
return info[31];
}
}

View File

@ -0,0 +1,386 @@
/*
* 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:
*
* http://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.uring;
import io.netty.channel.ChannelException;
import io.netty.channel.DefaultFileRegion;
import io.netty.channel.socket.InternetProtocolFamily;
import io.netty.channel.unix.NativeInetAddress;
import io.netty.channel.unix.PeerCredentials;
import io.netty.channel.unix.Socket;
import io.netty.util.internal.PlatformDependent;
import io.netty.util.internal.SocketUtils;
import java.io.IOException;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.util.Enumeration;
import static io.netty.channel.unix.Errors.*;
/**
* A socket which provides access Linux native methods.
*/
final class LinuxSocket extends Socket {
static final InetAddress INET6_ANY = unsafeInetAddrByName("::");
private static final InetAddress INET_ANY = unsafeInetAddrByName("0.0.0.0");
private static final long MAX_UINT32_T = 0xFFFFFFFFL;
LinuxSocket(int fd) {
super(fd);
}
private InternetProtocolFamily family() {
return ipv6 ? InternetProtocolFamily.IPv6 : InternetProtocolFamily.IPv4;
}
void setTimeToLive(int ttl) throws IOException {
setTimeToLive(intValue(), ttl);
}
void setInterface(InetAddress address) throws IOException {
final NativeInetAddress a = NativeInetAddress.newInstance(address);
setInterface(intValue(), ipv6, a.address(), a.scopeId(), interfaceIndex(address));
}
void setNetworkInterface(NetworkInterface netInterface) throws IOException {
InetAddress address = deriveInetAddress(netInterface, family() == InternetProtocolFamily.IPv6);
if (address.equals(family() == InternetProtocolFamily.IPv4 ? INET_ANY : INET6_ANY)) {
throw new IOException("NetworkInterface does not support " + family());
}
final NativeInetAddress nativeAddress = NativeInetAddress.newInstance(address);
setInterface(intValue(), ipv6, nativeAddress.address(), nativeAddress.scopeId(), interfaceIndex(netInterface));
}
InetAddress getInterface() throws IOException {
NetworkInterface inf = getNetworkInterface();
if (inf != null) {
Enumeration<InetAddress> addresses = SocketUtils.addressesFromNetworkInterface(inf);
if (addresses.hasMoreElements()) {
return addresses.nextElement();
}
}
return null;
}
NetworkInterface getNetworkInterface() throws IOException {
int ret = getInterface(intValue(), ipv6);
if (ipv6) {
return PlatformDependent.javaVersion() >= 7 ? NetworkInterface.getByIndex(ret) : null;
}
InetAddress address = inetAddress(ret);
return address != null ? NetworkInterface.getByInetAddress(address) : null;
}
private static InetAddress inetAddress(int value) {
byte[] var1 = {
(byte) (value >>> 24 & 255),
(byte) (value >>> 16 & 255),
(byte) (value >>> 8 & 255),
(byte) (value & 255)
};
try {
return InetAddress.getByAddress(var1);
} catch (UnknownHostException ignore) {
return null;
}
}
void joinGroup(InetAddress group, NetworkInterface netInterface, InetAddress source) throws IOException {
final NativeInetAddress g = NativeInetAddress.newInstance(group);
final boolean isIpv6 = group instanceof Inet6Address;
final NativeInetAddress i = NativeInetAddress.newInstance(deriveInetAddress(netInterface, isIpv6));
if (source != null) {
final NativeInetAddress s = NativeInetAddress.newInstance(source);
joinSsmGroup(intValue(), ipv6, g.address(), i.address(),
g.scopeId(), interfaceIndex(netInterface), s.address());
} else {
joinGroup(intValue(), ipv6, g.address(), i.address(), g.scopeId(), interfaceIndex(netInterface));
}
}
void leaveGroup(InetAddress group, NetworkInterface netInterface, InetAddress source) throws IOException {
final NativeInetAddress g = NativeInetAddress.newInstance(group);
final boolean isIpv6 = group instanceof Inet6Address;
final NativeInetAddress i = NativeInetAddress.newInstance(deriveInetAddress(netInterface, isIpv6));
if (source != null) {
final NativeInetAddress s = NativeInetAddress.newInstance(source);
leaveSsmGroup(intValue(), ipv6, g.address(), i.address(),
g.scopeId(), interfaceIndex(netInterface), s.address());
} else {
leaveGroup(intValue(), ipv6, g.address(), i.address(), g.scopeId(), interfaceIndex(netInterface));
}
}
private static int interfaceIndex(NetworkInterface networkInterface) {
return PlatformDependent.javaVersion() >= 7 ? networkInterface.getIndex() : -1;
}
private static int interfaceIndex(InetAddress address) throws IOException {
if (PlatformDependent.javaVersion() >= 7) {
NetworkInterface iface = NetworkInterface.getByInetAddress(address);
if (iface != null) {
return iface.getIndex();
}
}
return -1;
}
void setTcpDeferAccept(int deferAccept) throws IOException {
setTcpDeferAccept(intValue(), deferAccept);
}
void setTcpQuickAck(boolean quickAck) throws IOException {
setTcpQuickAck(intValue(), quickAck ? 1 : 0);
}
void setTcpCork(boolean tcpCork) throws IOException {
setTcpCork(intValue(), tcpCork ? 1 : 0);
}
void setSoBusyPoll(int loopMicros) throws IOException {
setSoBusyPoll(intValue(), loopMicros);
}
void setTcpNotSentLowAt(long tcpNotSentLowAt) throws IOException {
if (tcpNotSentLowAt < 0 || tcpNotSentLowAt > MAX_UINT32_T) {
throw new IllegalArgumentException("tcpNotSentLowAt must be a uint32_t");
}
setTcpNotSentLowAt(intValue(), (int) tcpNotSentLowAt);
}
void setTcpFastOpen(int tcpFastopenBacklog) throws IOException {
setTcpFastOpen(intValue(), tcpFastopenBacklog);
}
void setTcpFastOpenConnect(boolean tcpFastOpenConnect) throws IOException {
setTcpFastOpenConnect(intValue(), tcpFastOpenConnect ? 1 : 0);
}
boolean isTcpFastOpenConnect() throws IOException {
return isTcpFastOpenConnect(intValue()) != 0;
}
void setTcpKeepIdle(int seconds) throws IOException {
setTcpKeepIdle(intValue(), seconds);
}
void setTcpKeepIntvl(int seconds) throws IOException {
setTcpKeepIntvl(intValue(), seconds);
}
void setTcpKeepCnt(int probes) throws IOException {
setTcpKeepCnt(intValue(), probes);
}
void setTcpUserTimeout(int milliseconds) throws IOException {
setTcpUserTimeout(intValue(), milliseconds);
}
void setIpFreeBind(boolean enabled) throws IOException {
setIpFreeBind(intValue(), enabled ? 1 : 0);
}
void setIpTransparent(boolean enabled) throws IOException {
setIpTransparent(intValue(), enabled ? 1 : 0);
}
void setIpRecvOrigDestAddr(boolean enabled) throws IOException {
setIpRecvOrigDestAddr(intValue(), enabled ? 1 : 0);
}
int getTimeToLive() throws IOException {
return getTimeToLive(intValue());
}
void getTcpInfo(IOUringTcpInfo info) throws IOException {
getTcpInfo(intValue(), info.info);
}
void setTcpMd5Sig(InetAddress address, byte[] key) throws IOException {
final NativeInetAddress a = NativeInetAddress.newInstance(address);
setTcpMd5Sig(intValue(), ipv6, a.address(), a.scopeId(), key);
}
boolean isTcpCork() throws IOException {
return isTcpCork(intValue()) != 0;
}
int getSoBusyPoll() throws IOException {
return getSoBusyPoll(intValue());
}
int getTcpDeferAccept() throws IOException {
return getTcpDeferAccept(intValue());
}
boolean isTcpQuickAck() throws IOException {
return isTcpQuickAck(intValue()) != 0;
}
long getTcpNotSentLowAt() throws IOException {
return getTcpNotSentLowAt(intValue()) & MAX_UINT32_T;
}
int getTcpKeepIdle() throws IOException {
return getTcpKeepIdle(intValue());
}
int getTcpKeepIntvl() throws IOException {
return getTcpKeepIntvl(intValue());
}
int getTcpKeepCnt() throws IOException {
return getTcpKeepCnt(intValue());
}
int getTcpUserTimeout() throws IOException {
return getTcpUserTimeout(intValue());
}
boolean isIpFreeBind() throws IOException {
return isIpFreeBind(intValue()) != 0;
}
boolean isIpTransparent() throws IOException {
return isIpTransparent(intValue()) != 0;
}
boolean isIpRecvOrigDestAddr() throws IOException {
return isIpRecvOrigDestAddr(intValue()) != 0;
}
PeerCredentials getPeerCredentials() throws IOException {
return getPeerCredentials(intValue());
}
boolean isLoopbackModeDisabled() throws IOException {
return getIpMulticastLoop(intValue(), ipv6) == 0;
}
void setLoopbackModeDisabled(boolean loopbackModeDisabled) throws IOException {
setIpMulticastLoop(intValue(), ipv6, loopbackModeDisabled ? 0 : 1);
}
long sendFile(DefaultFileRegion src, long baseOffset, long offset, long length) throws IOException {
// Open the file-region as it may be created via the lazy constructor. This is needed as we directly access
// the FileChannel field via JNI.
src.open();
long res = sendFile(intValue(), src, baseOffset, offset, length);
if (res >= 0) {
return res;
}
return ioResult("sendfile", (int) res);
}
private static InetAddress deriveInetAddress(NetworkInterface netInterface, boolean ipv6) {
final InetAddress ipAny = ipv6 ? INET6_ANY : INET_ANY;
if (netInterface != null) {
final Enumeration<InetAddress> ias = netInterface.getInetAddresses();
while (ias.hasMoreElements()) {
final InetAddress ia = ias.nextElement();
final boolean isV6 = ia instanceof Inet6Address;
if (isV6 == ipv6) {
return ia;
}
}
}
return ipAny;
}
public static LinuxSocket newSocketStream(boolean ipv6) {
return new LinuxSocket(newSocketStream0(ipv6));
}
public static LinuxSocket newSocketStream() {
return newSocketStream(isIPv6Preferred());
}
public static LinuxSocket newSocketDgram(boolean ipv6) {
return new LinuxSocket(newSocketDgram0(ipv6));
}
public static LinuxSocket newSocketDgram() {
return newSocketDgram(isIPv6Preferred());
}
public static LinuxSocket newSocketDomain() {
return new LinuxSocket(newSocketDomain0());
}
private static InetAddress unsafeInetAddrByName(String inetName) {
try {
return InetAddress.getByName(inetName);
} catch (UnknownHostException uhe) {
throw new ChannelException(uhe);
}
}
private static native void joinGroup(int fd, boolean ipv6, byte[] group, byte[] interfaceAddress,
int scopeId, int interfaceIndex) throws IOException;
private static native void joinSsmGroup(int fd, boolean ipv6, byte[] group, byte[] interfaceAddress,
int scopeId, int interfaceIndex, byte[] source) throws IOException;
private static native void leaveGroup(int fd, boolean ipv6, byte[] group, byte[] interfaceAddress,
int scopeId, int interfaceIndex) throws IOException;
private static native void leaveSsmGroup(int fd, boolean ipv6, byte[] group, byte[] interfaceAddress,
int scopeId, int interfaceIndex, byte[] source) throws IOException;
private static native long sendFile(int socketFd, DefaultFileRegion src, long baseOffset,
long offset, long length) throws IOException;
private static native int getTcpDeferAccept(int fd) throws IOException;
private static native int isTcpQuickAck(int fd) throws IOException;
private static native int isTcpCork(int fd) throws IOException;
private static native int getSoBusyPoll(int fd) throws IOException;
private static native int getTcpNotSentLowAt(int fd) throws IOException;
private static native int getTcpKeepIdle(int fd) throws IOException;
private static native int getTcpKeepIntvl(int fd) throws IOException;
private static native int getTcpKeepCnt(int fd) throws IOException;
private static native int getTcpUserTimeout(int fd) throws IOException;
private static native int getTimeToLive(int fd) throws IOException;
private static native int isIpFreeBind(int fd) throws IOException;
private static native int isIpTransparent(int fd) throws IOException;
private static native int isIpRecvOrigDestAddr(int fd) throws IOException;
private static native void getTcpInfo(int fd, long[] array) throws IOException;
private static native PeerCredentials getPeerCredentials(int fd) throws IOException;
private static native int isTcpFastOpenConnect(int fd) throws IOException;
private static native void setTcpDeferAccept(int fd, int deferAccept) throws IOException;
private static native void setTcpQuickAck(int fd, int quickAck) throws IOException;
private static native void setTcpCork(int fd, int tcpCork) throws IOException;
private static native void setSoBusyPoll(int fd, int loopMicros) throws IOException;
private static native void setTcpNotSentLowAt(int fd, int tcpNotSentLowAt) throws IOException;
private static native void setTcpFastOpen(int fd, int tcpFastopenBacklog) throws IOException;
private static native void setTcpFastOpenConnect(int fd, int tcpFastOpenConnect) throws IOException;
private static native void setTcpKeepIdle(int fd, int seconds) throws IOException;
private static native void setTcpKeepIntvl(int fd, int seconds) throws IOException;
private static native void setTcpKeepCnt(int fd, int probes) throws IOException;
private static native void setTcpUserTimeout(int fd, int milliseconds)throws IOException;
private static native void setIpFreeBind(int fd, int freeBind) throws IOException;
private static native void setIpTransparent(int fd, int transparent) throws IOException;
private static native void setIpRecvOrigDestAddr(int fd, int transparent) throws IOException;
private static native void setTcpMd5Sig(
int fd, boolean ipv6, byte[] address, int scopeId, byte[] key) throws IOException;
private static native void setInterface(
int fd, boolean ipv6, byte[] interfaceAddress, int scopeId, int networkInterfaceIndex) throws IOException;
private static native int getInterface(int fd, boolean ipv6);
private static native int getIpMulticastLoop(int fd, boolean ipv6) throws IOException;
private static native void setIpMulticastLoop(int fd, boolean ipv6, int enabled) throws IOException;
private static native void setTimeToLive(int fd, int ttl) throws IOException;
}