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 import io.netty.util.internal.PlatformDependent;
23
24 import java.io.IOException;
25 import java.net.InetSocketAddress;
26 import java.nio.ByteBuffer;
27 import java.nio.ByteOrder;
28
29 final class MsgHdrMemory {
30 public static final int MSG_HDR_SIZE =
31 Native.SIZEOF_MSGHDR + Native.SIZEOF_SOCKADDR_STORAGE + Native.SIZEOF_IOVEC + Native.CMSG_SPACE;
32 private static final byte[] EMPTY_SOCKADDR_STORAGE = new byte[Native.SIZEOF_SOCKADDR_STORAGE];
33
34
35 private static final int GLOBAL_IOV_LEN = 1;
36 private static final ByteBuffer GLOBAL_IOV_BASE = Buffer.allocateDirectWithNativeOrder(GLOBAL_IOV_LEN);
37 private static final long GLOBAL_IOV_BASE_ADDRESS = Buffer.memoryAddress(GLOBAL_IOV_BASE);
38 private final CleanableDirectBuffer msgHdrMemoryCleanable;
39 private final CleanableDirectBuffer socketAddrMemoryCleanable;
40 private final CleanableDirectBuffer iovMemoryCleanable;
41 private final CleanableDirectBuffer cmsgDataMemoryCleanable;
42 private final ByteBuffer msgHdrMemory;
43 private final ByteBuffer socketAddrMemory;
44 private final ByteBuffer iovMemory;
45 private final ByteBuffer cmsgDataMemory;
46
47 private final long msgHdrMemoryAddress;
48 private final short idx;
49 private final int cmsgDataOffset;
50
51 MsgHdrMemory(short idx, ByteBuffer msgHdrMemoryArray) {
52 this.idx = idx;
53 this.msgHdrMemoryCleanable = null;
54 this.socketAddrMemoryCleanable = null;
55 this.iovMemoryCleanable = null;
56 this.cmsgDataMemoryCleanable = null;
57 int offset = idx * MSG_HDR_SIZE;
58
59
60 this.msgHdrMemory = PlatformDependent.offsetSlice(
61 msgHdrMemoryArray, offset, Native.SIZEOF_MSGHDR
62 ).order(ByteOrder.nativeOrder());
63 offset += Native.SIZEOF_MSGHDR;
64 this.socketAddrMemory = PlatformDependent.offsetSlice(
65 msgHdrMemoryArray, offset, Native.SIZEOF_SOCKADDR_STORAGE
66 ).order(ByteOrder.nativeOrder());
67 offset += Native.SIZEOF_SOCKADDR_STORAGE;
68 this.iovMemory = PlatformDependent.offsetSlice(
69 msgHdrMemoryArray, offset, Native.SIZEOF_IOVEC
70 ).order(ByteOrder.nativeOrder());
71 offset += Native.SIZEOF_IOVEC;
72 this.cmsgDataMemory = PlatformDependent.offsetSlice(
73 msgHdrMemoryArray, offset, Native.CMSG_SPACE
74 ).order(ByteOrder.nativeOrder());
75
76 msgHdrMemoryAddress = Buffer.memoryAddress(msgHdrMemory);
77
78 long cmsgDataMemoryAddr = Buffer.memoryAddress(cmsgDataMemory);
79 long cmsgDataAddr = Native.cmsghdrData(cmsgDataMemoryAddr);
80 cmsgDataOffset = (int) (cmsgDataAddr - cmsgDataMemoryAddr);
81 }
82
83 MsgHdrMemory() {
84 this.idx = 0;
85
86 msgHdrMemoryCleanable = Buffer.allocateDirectBufferWithNativeOrder(Native.SIZEOF_MSGHDR);
87 socketAddrMemoryCleanable = null;
88 iovMemoryCleanable = Buffer.allocateDirectBufferWithNativeOrder(Native.SIZEOF_IOVEC);
89 cmsgDataMemoryCleanable = Buffer.allocateDirectBufferWithNativeOrder(Native.CMSG_SPACE_FOR_FD);
90
91 msgHdrMemory = msgHdrMemoryCleanable.buffer();
92 socketAddrMemory = null;
93 iovMemory = iovMemoryCleanable.buffer();
94 cmsgDataMemory = cmsgDataMemoryCleanable.buffer();
95
96 msgHdrMemoryAddress = Buffer.memoryAddress(msgHdrMemory);
97
98
99 Iov.set(iovMemory, GLOBAL_IOV_BASE_ADDRESS, GLOBAL_IOV_LEN);
100
101 long cmsgDataMemoryAddr = Buffer.memoryAddress(cmsgDataMemory);
102 long cmsgDataAddr = Native.cmsghdrData(cmsgDataMemoryAddr);
103 cmsgDataOffset = (int) (cmsgDataAddr - cmsgDataMemoryAddr);
104 }
105
106 void set(LinuxSocket socket, InetSocketAddress address, long bufferAddress , int length, short segmentSize) {
107 int addressLength = setSocketAddress(socket, address);
108 Iov.set(iovMemory, bufferAddress, length);
109 MsgHdr.set(msgHdrMemory, socketAddrMemory, addressLength, iovMemory, 1, cmsgDataMemory,
110 cmsgDataOffset, segmentSize);
111 }
112
113 int iovLength() {
114 return MsgHdr.iovLength(msgHdrMemory);
115 }
116
117 void set(long iovArray, int length) {
118 MsgHdr.set(msgHdrMemory, iovArray, length);
119 }
120
121 void setWithIovArrayAddress(LinuxSocket socket, InetSocketAddress address,
122 long iovArrayAddress, int iovArrayLength, short segmentSize) {
123 int addressLength = setSocketAddress(socket, address);
124 MsgHdr.set(msgHdrMemory, socketAddrMemory, addressLength, iovArrayAddress, iovArrayLength,
125 cmsgDataMemory, cmsgDataOffset, segmentSize);
126 }
127
128 private int setSocketAddress(LinuxSocket socket, InetSocketAddress address) {
129 int addressLength;
130 if (address == null) {
131 addressLength = socket.isIpv6() ? Native.SIZEOF_SOCKADDR_IN6 : Native.SIZEOF_SOCKADDR_IN;
132 socketAddrMemory.mark();
133 try {
134 socketAddrMemory.put(EMPTY_SOCKADDR_STORAGE);
135 } finally {
136 socketAddrMemory.reset();
137 }
138 } else {
139 addressLength = SockaddrIn.set(socket.isIpv6(), socketAddrMemory, address);
140 }
141 return addressLength;
142 }
143
144 void setScmRightsFd(int fd) {
145 MsgHdr.prepSendFd(msgHdrMemory, fd, cmsgDataMemory, cmsgDataOffset, iovMemory, 1);
146 }
147
148 int getScmRightsFd() throws IOException {
149 return MsgHdr.getCmsgData(msgHdrMemory, cmsgDataMemory, cmsgDataOffset);
150 }
151
152 void prepRecvReadFd() {
153 MsgHdr.prepReadFd(msgHdrMemory, cmsgDataMemory, cmsgDataOffset, iovMemory, 1);
154 }
155
156 boolean hasPort(IoUringDatagramChannel channel) {
157 if (channel.socket.isIpv6()) {
158 return SockaddrIn.hasPortIpv6(socketAddrMemory);
159 }
160 return SockaddrIn.hasPortIpv4(socketAddrMemory);
161 }
162
163 DatagramPacket get(IoUringDatagramChannel channel, IoUringIoHandler handler, ByteBuf buffer, int bytesRead) {
164 InetSocketAddress sender;
165 if (channel.socket.isIpv6()) {
166 byte[] ipv6Bytes = handler.inet6AddressArray();
167 byte[] ipv4bytes = handler.inet4AddressArray();
168
169 sender = SockaddrIn.getIPv6(socketAddrMemory, ipv6Bytes, ipv4bytes);
170 } else {
171 byte[] bytes = handler.inet4AddressArray();
172 sender = SockaddrIn.getIPv4(socketAddrMemory, bytes);
173 }
174 long bufferAddress = Iov.getBufferAddress(iovMemory);
175 int bufferLength = Iov.getBufferLength(iovMemory);
176
177
178 long memoryAddress = IoUring.memoryAddress(buffer);
179 int readerIndex = (int) (bufferAddress - memoryAddress);
180
181 ByteBuf slice = buffer.slice(readerIndex, bufferLength)
182 .writerIndex(bytesRead);
183 return new DatagramPacket(slice.retain(), channel.localAddress(), sender);
184 }
185
186 short idx() {
187 return idx;
188 }
189
190 long address() {
191 return msgHdrMemoryAddress;
192 }
193
194 void release() {
195 if (msgHdrMemoryCleanable != null) {
196 msgHdrMemoryCleanable.clean();
197 }
198 if (socketAddrMemoryCleanable != null) {
199 socketAddrMemoryCleanable.clean();
200 }
201 if (iovMemoryCleanable != null) {
202 iovMemoryCleanable.clean();
203 }
204 if (cmsgDataMemoryCleanable != null) {
205 cmsgDataMemoryCleanable.clean();
206 }
207 }
208 }