netty5/transport-native-io_uring/src/main/java/io/netty/channel/uring/SockaddrIn.java
Norman Maurer 70b7621963
Implement batching of reading and writing when using datagram with io_uring. (#10606)
Motivation:

io_uring does not support recvmmsg / sendmmsg directly and so we need to
"emulate" it by submitting multiple IORING_IO_RECVMSG /
IORING_IO_SENDMSG calls.

Modifications:

- Allow to issue multiple write / read calls at once no matter what
  concrete AbstractIOUringChannel subclass it is
- Add support for batching recvmsg / sendmsg when using
IOUringDatagramChannel

Result:

Better performance
2020-09-29 16:58:46 +02:00

136 lines
5.7 KiB
Java

/*
* 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.util.internal.PlatformDependent;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import static io.netty.util.internal.PlatformDependent.BIG_ENDIAN_NATIVE_ORDER;
final class SockaddrIn {
static final byte[] IPV4_MAPPED_IPV6_PREFIX = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xff, (byte) 0xff };
private SockaddrIn() { }
static int write(boolean ipv6, long memory, InetSocketAddress address) {
if (ipv6) {
return SockaddrIn.writeIPv6(memory, address.getAddress(), address.getPort());
} else {
return SockaddrIn.writeIPv4(memory, address.getAddress(), address.getPort());
}
}
/**
*
* struct sockaddr_in {
* sa_family_t sin_family; // address family: AF_INET
* in_port_t sin_port; // port in network byte order
* struct in_addr sin_addr; // internet address
* };
*
* // Internet address.
* struct in_addr {
* uint32_t s_addr; // address in network byte order
* };
*
*/
static int writeIPv4(long memory, InetAddress address, int port) {
PlatformDependent.setMemory(memory, Native.SIZEOF_SOCKADDR_IN, (byte) 0);
PlatformDependent.putShort(memory + Native.SOCKADDR_IN_OFFSETOF_SIN_FAMILY, Native.AF_INET);
PlatformDependent.putShort(memory + Native.SOCKADDR_IN_OFFSETOF_SIN_PORT, handleNetworkOrder((short) port));
byte[] bytes = address.getAddress();
int offset = 0;
if (bytes.length == 16) {
// IPV6 mapped IPV4 address, we only need the last 4 bytes.
offset = 12;
}
assert bytes.length == offset + 4;
PlatformDependent.copyMemory(bytes, offset,
memory + Native.SOCKADDR_IN_OFFSETOF_SIN_ADDR + Native.IN_ADDRESS_OFFSETOF_S_ADDR, 4);
return Native.SIZEOF_SOCKADDR_IN;
}
/**
* struct sockaddr_in6 {
* sa_family_t sin6_family; // AF_INET6
* in_port_t sin6_port; // port number
* uint32_t sin6_flowinfo; // IPv6 flow information
* struct in6_addr sin6_addr; // IPv6 address
* uint32_t sin6_scope_id; /* Scope ID (new in 2.4)
* };
*
* struct in6_addr {
* unsigned char s6_addr[16]; // IPv6 address
* };
*/
static int writeIPv6(long memory, InetAddress address, int port) {
PlatformDependent.setMemory(memory, Native.SIZEOF_SOCKADDR_IN6, (byte) 0);
PlatformDependent.putShort(memory + Native.SOCKADDR_IN6_OFFSETOF_SIN6_FAMILY, Native.AF_INET6);
PlatformDependent.putShort(memory + Native.SOCKADDR_IN6_OFFSETOF_SIN6_PORT, handleNetworkOrder((short) port));
// Skip sin6_flowinfo as we did memset before
byte[] bytes = address.getAddress();
if (bytes.length == 4) {
int offset = Native.SOCKADDR_IN6_OFFSETOF_SIN6_ADDR + Native.IN6_ADDRESS_OFFSETOF_S6_ADDR;
PlatformDependent.copyMemory(IPV4_MAPPED_IPV6_PREFIX, 0, memory + offset, IPV4_MAPPED_IPV6_PREFIX.length);
PlatformDependent.copyMemory(bytes, 0, memory + offset + IPV4_MAPPED_IPV6_PREFIX.length, 4);
// Skip sin6_scope_id as we did memset before
} else {
PlatformDependent.copyMemory(bytes, 0,
memory + Native.SOCKADDR_IN6_OFFSETOF_SIN6_ADDR + Native.IN6_ADDRESS_OFFSETOF_S6_ADDR, 16);
PlatformDependent.putInt(
memory + Native.SOCKADDR_IN6_OFFSETOF_SIN6_SCOPE_ID, ((Inet6Address) address).getScopeId());
}
return Native.SIZEOF_SOCKADDR_IN6;
}
static InetSocketAddress readIPv4(long memory, byte[] tmpArray) {
assert tmpArray.length == 4;
int port = handleNetworkOrder(PlatformDependent.getShort(
memory + Native.SOCKADDR_IN_OFFSETOF_SIN_PORT)) & 0xFFFF;
PlatformDependent.copyMemory(memory + Native.SOCKADDR_IN_OFFSETOF_SIN_ADDR + Native.IN_ADDRESS_OFFSETOF_S_ADDR,
tmpArray, 0, 4);
try {
return new InetSocketAddress(InetAddress.getByAddress(tmpArray), port);
} catch (UnknownHostException ignore) {
return null;
}
}
static InetSocketAddress readIPv6(long memory, byte[] tmpArray) {
assert tmpArray.length == 16;
int port = handleNetworkOrder(PlatformDependent.getShort(
memory + Native.SOCKADDR_IN6_OFFSETOF_SIN6_PORT)) & 0xFFFF;
PlatformDependent.copyMemory(
memory + Native.SOCKADDR_IN6_OFFSETOF_SIN6_ADDR + Native.IN6_ADDRESS_OFFSETOF_S6_ADDR,
tmpArray, 0, 16);
int scopeId = PlatformDependent.getInt(memory + Native.SOCKADDR_IN6_OFFSETOF_SIN6_SCOPE_ID);
try {
return new InetSocketAddress(Inet6Address.getByAddress(null, tmpArray, scopeId), port);
} catch (UnknownHostException ignore) {
return null;
}
}
private static short handleNetworkOrder(short v) {
return BIG_ENDIAN_NATIVE_ORDER ? v : Short.reverseBytes(v);
}
}