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:
parent
1117c6fdb8
commit
8d464d5ab4
@ -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);
|
||||||
|
}
|
@ -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
|
@ -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;
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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");
|
||||||
|
}
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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];
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user