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 void set(long iovArray, int length) {
114 MsgHdr.set(msgHdrMemory, iovArray, length);
115 }
116
117 void setWithIovArrayAddress(LinuxSocket socket, InetSocketAddress address,
118 long iovArrayAddress, int iovArrayLength, short segmentSize) {
119 int addressLength = setSocketAddress(socket, address);
120 MsgHdr.set(msgHdrMemory, socketAddrMemory, addressLength, iovArrayAddress, iovArrayLength,
121 cmsgDataMemory, cmsgDataOffset, segmentSize);
122 }
123
124 private int setSocketAddress(LinuxSocket socket, InetSocketAddress address) {
125 int addressLength;
126 if (address == null) {
127 addressLength = socket.isIpv6() ? Native.SIZEOF_SOCKADDR_IN6 : Native.SIZEOF_SOCKADDR_IN;
128 socketAddrMemory.mark();
129 try {
130 socketAddrMemory.put(EMPTY_SOCKADDR_STORAGE);
131 } finally {
132 socketAddrMemory.reset();
133 }
134 } else {
135 addressLength = SockaddrIn.set(socket.isIpv6(), socketAddrMemory, address);
136 }
137 return addressLength;
138 }
139
140 void setScmRightsFd(int fd) {
141 MsgHdr.prepSendFd(msgHdrMemory, fd, cmsgDataMemory, cmsgDataOffset, iovMemory, 1);
142 }
143
144 int getScmRightsFd() throws IOException {
145 return MsgHdr.getCmsgData(msgHdrMemory, cmsgDataMemory, cmsgDataOffset);
146 }
147
148 void prepRecvReadFd() {
149 MsgHdr.prepReadFd(msgHdrMemory, cmsgDataMemory, cmsgDataOffset, iovMemory, 1);
150 }
151
152 boolean hasPort(IoUringDatagramChannel channel) {
153 if (channel.socket.isIpv6()) {
154 return SockaddrIn.hasPortIpv6(socketAddrMemory);
155 }
156 return SockaddrIn.hasPortIpv4(socketAddrMemory);
157 }
158
159 DatagramPacket get(IoUringDatagramChannel channel, IoUringIoHandler handler, ByteBuf buffer, int bytesRead) {
160 InetSocketAddress sender;
161 if (channel.socket.isIpv6()) {
162 byte[] ipv6Bytes = handler.inet6AddressArray();
163 byte[] ipv4bytes = handler.inet4AddressArray();
164
165 sender = SockaddrIn.getIPv6(socketAddrMemory, ipv6Bytes, ipv4bytes);
166 } else {
167 byte[] bytes = handler.inet4AddressArray();
168 sender = SockaddrIn.getIPv4(socketAddrMemory, bytes);
169 }
170 long bufferAddress = Iov.getBufferAddress(iovMemory);
171 int bufferLength = Iov.getBufferLength(iovMemory);
172
173
174 long memoryAddress = IoUring.memoryAddress(buffer);
175 int readerIndex = (int) (bufferAddress - memoryAddress);
176
177 ByteBuf slice = buffer.slice(readerIndex, bufferLength)
178 .writerIndex(bytesRead);
179 return new DatagramPacket(slice.retain(), channel.localAddress(), sender);
180 }
181
182 short idx() {
183 return idx;
184 }
185
186 long address() {
187 return msgHdrMemoryAddress;
188 }
189
190 void release() {
191 if (msgHdrMemoryCleanable != null) {
192 msgHdrMemoryCleanable.clean();
193 }
194 if (socketAddrMemoryCleanable != null) {
195 socketAddrMemoryCleanable.clean();
196 }
197 if (iovMemoryCleanable != null) {
198 iovMemoryCleanable.clean();
199 }
200 if (cmsgDataMemoryCleanable != null) {
201 cmsgDataMemoryCleanable.clean();
202 }
203 }
204 }