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