1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.channel.uring;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.channel.socket.DatagramPacket;
20 import io.netty.channel.unix.Buffer;
21 import io.netty.util.internal.CleanableDirectBuffer;
22
23 import java.net.InetSocketAddress;
24 import java.nio.ByteBuffer;
25
26 final class MsgHdrMemory {
27 private static final byte[] EMPTY_SOCKADDR_STORAGE = new byte[Native.SIZEOF_SOCKADDR_STORAGE];
28
29
30 private static final int GLOBAL_IOV_LEN = 1;
31 private static final ByteBuffer GLOBAL_IOV_BASE = Buffer.allocateDirectWithNativeOrder(GLOBAL_IOV_LEN);
32 private static final long GLOBAL_IOV_BASE_ADDRESS = Buffer.memoryAddress(GLOBAL_IOV_BASE);
33 private final CleanableDirectBuffer msgHdrMemoryCleanable;
34 private final CleanableDirectBuffer socketAddrMemoryCleanable;
35 private final CleanableDirectBuffer iovMemoryCleanable;
36 private final CleanableDirectBuffer cmsgDataMemoryCleanable;
37 private final ByteBuffer msgHdrMemory;
38 private final ByteBuffer socketAddrMemory;
39 private final ByteBuffer iovMemory;
40 private final ByteBuffer cmsgDataMemory;
41
42 private final long msgHdrMemoryAddress;
43 private final short idx;
44 private final int cmsgDataOffset;
45
46 MsgHdrMemory(short idx) {
47 this.idx = idx;
48 msgHdrMemoryCleanable = Buffer.allocateDirectBufferWithNativeOrder(Native.SIZEOF_MSGHDR);
49 socketAddrMemoryCleanable = Buffer.allocateDirectBufferWithNativeOrder(Native.SIZEOF_SOCKADDR_STORAGE);
50 iovMemoryCleanable = Buffer.allocateDirectBufferWithNativeOrder(Native.SIZEOF_IOVEC);
51 cmsgDataMemoryCleanable = Buffer.allocateDirectBufferWithNativeOrder(Native.CMSG_SPACE);
52
53 msgHdrMemory = msgHdrMemoryCleanable.buffer();
54 socketAddrMemory = socketAddrMemoryCleanable.buffer();
55 iovMemory = iovMemoryCleanable.buffer();
56 cmsgDataMemory = cmsgDataMemoryCleanable.buffer();
57
58 msgHdrMemoryAddress = Buffer.memoryAddress(msgHdrMemory);
59
60 long cmsgDataMemoryAddr = Buffer.memoryAddress(cmsgDataMemory);
61 long cmsgDataAddr = Native.cmsghdrData(cmsgDataMemoryAddr);
62 cmsgDataOffset = (int) (cmsgDataAddr - cmsgDataMemoryAddr);
63 }
64
65 MsgHdrMemory() {
66 this.idx = 0;
67
68 msgHdrMemoryCleanable = Buffer.allocateDirectBufferWithNativeOrder(Native.SIZEOF_MSGHDR);
69 socketAddrMemoryCleanable = null;
70 iovMemoryCleanable = Buffer.allocateDirectBufferWithNativeOrder(Native.SIZEOF_IOVEC);
71 cmsgDataMemoryCleanable = Buffer.allocateDirectBufferWithNativeOrder(Native.CMSG_SPACE_FOR_FD);
72
73 msgHdrMemory = msgHdrMemoryCleanable.buffer();
74 socketAddrMemory = null;
75 iovMemory = iovMemoryCleanable.buffer();
76 cmsgDataMemory = cmsgDataMemoryCleanable.buffer();
77
78 msgHdrMemoryAddress = Buffer.memoryAddress(msgHdrMemory);
79
80
81 Iov.set(iovMemory, GLOBAL_IOV_BASE_ADDRESS, GLOBAL_IOV_LEN);
82
83 long cmsgDataMemoryAddr = Buffer.memoryAddress(cmsgDataMemory);
84 long cmsgDataAddr = Native.cmsghdrData(cmsgDataMemoryAddr);
85 cmsgDataOffset = (int) (cmsgDataAddr - cmsgDataMemoryAddr);
86 }
87
88 void set(LinuxSocket socket, InetSocketAddress address, long bufferAddress , int length, short segmentSize) {
89 int addressLength;
90 if (address == null) {
91 addressLength = socket.isIpv6() ? Native.SIZEOF_SOCKADDR_IN6 : Native.SIZEOF_SOCKADDR_IN;
92 socketAddrMemory.mark();
93 try {
94 socketAddrMemory.put(EMPTY_SOCKADDR_STORAGE);
95 } finally {
96 socketAddrMemory.reset();
97 }
98 } else {
99 addressLength = SockaddrIn.set(socket.isIpv6(), socketAddrMemory, address);
100 }
101 Iov.set(iovMemory, bufferAddress, length);
102 MsgHdr.set(msgHdrMemory, socketAddrMemory, addressLength, iovMemory, 1, cmsgDataMemory,
103 cmsgDataOffset, segmentSize);
104 }
105
106 void setScmRightsFd(int fd) {
107 MsgHdr.prepSendFd(msgHdrMemory, fd, cmsgDataMemory, cmsgDataOffset, iovMemory, 1);
108 }
109
110 int getScmRightsFd() {
111 return MsgHdr.getCmsgData(msgHdrMemory, cmsgDataMemory, cmsgDataOffset);
112 }
113
114 void prepRecvReadFd() {
115 MsgHdr.prepReadFd(msgHdrMemory, cmsgDataMemory, cmsgDataOffset, iovMemory, 1);
116 }
117
118 boolean hasPort(IoUringDatagramChannel channel) {
119 if (channel.socket.isIpv6()) {
120 return SockaddrIn.hasPortIpv6(socketAddrMemory);
121 }
122 return SockaddrIn.hasPortIpv4(socketAddrMemory);
123 }
124
125 DatagramPacket get(IoUringDatagramChannel channel, IoUringIoHandler handler, ByteBuf buffer, int bytesRead) {
126 InetSocketAddress sender;
127 if (channel.socket.isIpv6()) {
128 byte[] ipv6Bytes = handler.inet6AddressArray();
129 byte[] ipv4bytes = handler.inet4AddressArray();
130
131 sender = SockaddrIn.getIPv6(socketAddrMemory, ipv6Bytes, ipv4bytes);
132 } else {
133 byte[] bytes = handler.inet4AddressArray();
134 sender = SockaddrIn.getIPv4(socketAddrMemory, bytes);
135 }
136 long bufferAddress = Iov.getBufferAddress(iovMemory);
137 int bufferLength = Iov.getBufferLength(iovMemory);
138
139
140 long memoryAddress = IoUring.memoryAddress(buffer);
141 int readerIndex = (int) (bufferAddress - memoryAddress);
142
143 ByteBuf slice = buffer.slice(readerIndex, bufferLength)
144 .writerIndex(bytesRead);
145 return new DatagramPacket(slice.retain(), channel.localAddress(), sender);
146 }
147
148 short idx() {
149 return idx;
150 }
151
152 long address() {
153 return msgHdrMemoryAddress;
154 }
155
156 void release() {
157 msgHdrMemoryCleanable.clean();
158 if (socketAddrMemoryCleanable != null) {
159 socketAddrMemoryCleanable.clean();
160 }
161 iovMemoryCleanable.clean();
162 cmsgDataMemoryCleanable.clean();
163 }
164 }