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.util.internal.PlatformDependent;
21  
22  import java.net.InetSocketAddress;
23  
24  final class MsgHdrMemory {
25      private final long memory;
26      private final short idx;
27      private final long cmsgDataAddr;
28  
29      MsgHdrMemory(short idx) {
30          this.idx = idx;
31          int size = Native.SIZEOF_MSGHDR + Native.SIZEOF_SOCKADDR_STORAGE + Native.SIZEOF_IOVEC + Native.CMSG_SPACE;
32          memory = PlatformDependent.allocateMemory(size);
33          PlatformDependent.setMemory(memory, size, (byte) 0);
34  
35          // We retrieve the address of the data once so we can just be JNI free after construction.
36          cmsgDataAddr = Native.cmsghdrData(memory + Native.SIZEOF_MSGHDR +
37                  Native.SIZEOF_SOCKADDR_STORAGE + Native.SIZEOF_IOVEC);
38      }
39  
40      void write(LinuxSocket socket, InetSocketAddress address, long bufferAddress , int length, short segmentSize) {
41          long sockAddress = memory + Native.SIZEOF_MSGHDR;
42          long iovAddress = sockAddress + Native.SIZEOF_SOCKADDR_STORAGE;
43          long cmsgAddr = iovAddress + Native.SIZEOF_IOVEC;
44          int addressLength;
45          if (address == null) {
46              addressLength = socket.isIpv6() ? Native.SIZEOF_SOCKADDR_IN6 : Native.SIZEOF_SOCKADDR_IN;
47              PlatformDependent.setMemory(sockAddress, Native.SIZEOF_SOCKADDR_STORAGE, (byte) 0);
48          } else {
49              addressLength = SockaddrIn.write(socket.isIpv6(), sockAddress, address);
50          }
51          Iov.write(iovAddress, bufferAddress, length);
52          MsgHdr.write(memory, sockAddress, addressLength, iovAddress, 1, cmsgAddr, cmsgDataAddr, segmentSize);
53      }
54  
55      boolean hasPort(IoUringDatagramChannel channel) {
56          long sockAddress = memory + Native.SIZEOF_MSGHDR;
57          if (channel.socket.isIpv6()) {
58              return SockaddrIn.hasPortIpv6(sockAddress);
59          }
60          return SockaddrIn.hasPortIpv4(sockAddress);
61      }
62  
63      DatagramPacket read(IoUringDatagramChannel channel, IoUringIoHandler handler, ByteBuf buffer, int bytesRead) {
64          long sockAddress = memory + Native.SIZEOF_MSGHDR;
65          InetSocketAddress sender;
66          if (channel.socket.isIpv6()) {
67              byte[] ipv6Bytes = handler.inet6AddressArray();
68              byte[] ipv4bytes = handler.inet4AddressArray();
69  
70              sender = SockaddrIn.readIPv6(sockAddress, ipv6Bytes, ipv4bytes);
71          } else {
72              byte[] bytes = handler.inet4AddressArray();
73              sender = SockaddrIn.readIPv4(sockAddress, bytes);
74          }
75          long iovAddress = memory + Native.SIZEOF_MSGHDR + Native.SIZEOF_SOCKADDR_STORAGE;
76          long bufferAddress = Iov.readBufferAddress(iovAddress);
77          int bufferLength = Iov.readBufferLength(iovAddress);
78          // reconstruct the reader index based on the memoryAddress of the buffer and the bufferAddress that was used
79          // in the iovec.
80          int readerIndex = (int) (bufferAddress - buffer.memoryAddress());
81  
82          ByteBuf slice = buffer.slice(readerIndex, bufferLength)
83                  .writerIndex(bytesRead);
84          return new DatagramPacket(slice.retain(), channel.localAddress(), sender);
85      }
86  
87      short idx() {
88          return idx;
89      }
90  
91      long address() {
92          return memory;
93      }
94  
95      void release() {
96          PlatformDependent.freeMemory(memory);
97      }
98  }