View Javadoc
1   /*
2    * Copyright 2024 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
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  
22  import java.net.InetSocketAddress;
23  import java.nio.ByteBuffer;
24  
25  final class MsgHdrMemory {
26      private static final byte[] EMPTY_SOCKADDR_STORAGE = new byte[Native.SIZEOF_SOCKADDR_STORAGE];
27      private final ByteBuffer msgHdrMemory;
28      private final ByteBuffer socketAddrMemory;
29      private final ByteBuffer iovMemory;
30      private final ByteBuffer cmsgDataMemory;
31  
32      private final long msgHdrMemoryAddress;
33      private final short idx;
34      private final int cmsgDataOffset;
35  
36      MsgHdrMemory(short idx) {
37          this.idx = idx;
38          msgHdrMemory = Buffer.allocateDirectWithNativeOrder(Native.SIZEOF_MSGHDR);
39          msgHdrMemoryAddress = Buffer.memoryAddress(msgHdrMemory);
40          socketAddrMemory = Buffer.allocateDirectWithNativeOrder(Native.SIZEOF_SOCKADDR_STORAGE);
41          iovMemory = Buffer.allocateDirectWithNativeOrder(Native.SIZEOF_IOVEC);
42          cmsgDataMemory = Buffer.allocateDirectWithNativeOrder(Native.CMSG_SPACE);
43  
44          long cmsgDataMemoryAddr = Buffer.memoryAddress(cmsgDataMemory);
45          long cmsgDataAddr = Native.cmsghdrData(cmsgDataMemoryAddr);
46          cmsgDataOffset = (int) (cmsgDataAddr + cmsgDataMemoryAddr);
47      }
48  
49      void set(LinuxSocket socket, InetSocketAddress address, long bufferAddress , int length, short segmentSize) {
50          int addressLength;
51          if (address == null) {
52              addressLength = socket.isIpv6() ? Native.SIZEOF_SOCKADDR_IN6 : Native.SIZEOF_SOCKADDR_IN;
53              socketAddrMemory.mark();
54              try {
55                  socketAddrMemory.put(EMPTY_SOCKADDR_STORAGE);
56              } finally {
57                  socketAddrMemory.reset();
58              }
59          } else {
60              addressLength = SockaddrIn.set(socket.isIpv6(), socketAddrMemory, address);
61          }
62          Iov.set(iovMemory, bufferAddress, length);
63          MsgHdr.set(msgHdrMemory, socketAddrMemory, addressLength, iovMemory, 1, cmsgDataMemory,
64                  cmsgDataOffset, segmentSize);
65      }
66  
67      boolean hasPort(IoUringDatagramChannel channel) {
68          if (channel.socket.isIpv6()) {
69              return SockaddrIn.hasPortIpv6(socketAddrMemory);
70          }
71          return SockaddrIn.hasPortIpv4(socketAddrMemory);
72      }
73  
74      DatagramPacket get(IoUringDatagramChannel channel, IoUringIoHandler handler, ByteBuf buffer, int bytesRead) {
75          InetSocketAddress sender;
76          if (channel.socket.isIpv6()) {
77              byte[] ipv6Bytes = handler.inet6AddressArray();
78              byte[] ipv4bytes = handler.inet4AddressArray();
79  
80              sender = SockaddrIn.getIPv6(socketAddrMemory, ipv6Bytes, ipv4bytes);
81          } else {
82              byte[] bytes = handler.inet4AddressArray();
83              sender = SockaddrIn.getIPv4(socketAddrMemory, bytes);
84          }
85          long bufferAddress = Iov.getBufferAddress(iovMemory);
86          int bufferLength = Iov.getBufferLength(iovMemory);
87          // reconstruct the reader index based on the memoryAddress of the buffer and the bufferAddress that was used
88          // in the iovec.
89          int readerIndex = (int) (bufferAddress - buffer.memoryAddress());
90  
91          ByteBuf slice = buffer.slice(readerIndex, bufferLength)
92                  .writerIndex(bytesRead);
93          return new DatagramPacket(slice.retain(), channel.localAddress(), sender);
94      }
95  
96      short idx() {
97          return idx;
98      }
99  
100     long address() {
101         return msgHdrMemoryAddress;
102     }
103 
104     void release() {
105         Buffer.free(msgHdrMemory);
106         Buffer.free(socketAddrMemory);
107         Buffer.free(iovMemory);
108         Buffer.free(cmsgDataMemory);
109     }
110 }