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.util.internal.PlatformDependent;
19  
20  import java.net.Inet4Address;
21  import java.net.Inet6Address;
22  import java.net.InetAddress;
23  import java.net.InetSocketAddress;
24  import java.net.UnknownHostException;
25  
26  import static io.netty.util.internal.PlatformDependent.BIG_ENDIAN_NATIVE_ORDER;
27  
28  final class SockaddrIn {
29      static final byte[] IPV4_MAPPED_IPV6_PREFIX = {
30              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xff, (byte) 0xff };
31      static final int IPV4_ADDRESS_LENGTH = 4;
32      static final int IPV6_ADDRESS_LENGTH = 16;
33  
34      private SockaddrIn() { }
35  
36      static int write(boolean ipv6, long memory, InetSocketAddress address) {
37          if (ipv6) {
38              return writeIPv6(memory, address.getAddress(), address.getPort());
39          } else {
40              return writeIPv4(memory, address.getAddress(), address.getPort());
41          }
42      }
43  
44      /**
45       * <pre>{@code
46       * struct sockaddr_in {
47       *      sa_family_t    sin_family; // address family: AF_INET
48       *      in_port_t      sin_port;   // port in network byte order
49       *      struct in_addr sin_addr;   // internet address
50       * };
51       *
52       * // Internet address.
53       * struct in_addr {
54       *     uint32_t       s_addr;     // address in network byte order
55       * };
56       * }</pre>
57       */
58      static int writeIPv4(long memory, InetAddress address, int port) {
59          PlatformDependent.setMemory(memory, Native.SIZEOF_SOCKADDR_IN, (byte) 0);
60  
61          PlatformDependent.putShort(memory + Native.SOCKADDR_IN_OFFSETOF_SIN_FAMILY, Native.AF_INET);
62          PlatformDependent.putShort(memory + Native.SOCKADDR_IN_OFFSETOF_SIN_PORT, handleNetworkOrder((short) port));
63          byte[] bytes = address.getAddress();
64          int offset = 0;
65          if (bytes.length == IPV6_ADDRESS_LENGTH) {
66              // IPV6 mapped IPV4 address, we only need the last 4 bytes.
67              offset = IPV4_MAPPED_IPV6_PREFIX.length;
68          }
69          assert bytes.length == offset + 4;
70          PlatformDependent.copyMemory(bytes, offset,
71                  memory + Native.SOCKADDR_IN_OFFSETOF_SIN_ADDR + Native.IN_ADDRESS_OFFSETOF_S_ADDR, 4);
72          return Native.SIZEOF_SOCKADDR_IN;
73      }
74  
75      /**
76       * <pre>{@code
77       * struct sockaddr_in6 {
78       *     sa_family_t     sin6_family;   // AF_INET6
79       *     in_port_t       sin6_port;     // port number
80       *     uint32_t        sin6_flowinfo; // IPv6 flow information
81       *     struct in6_addr sin6_addr;     // IPv6 address
82       *     uint32_t        sin6_scope_id; /* Scope ID (new in 2.4)
83       * };
84       *
85       * struct in6_addr {
86       *     unsigned char s6_addr[16];   // IPv6 address
87       * };
88       * }</pre>
89       */
90      static int writeIPv6(long memory, InetAddress address, int port) {
91          PlatformDependent.setMemory(memory, Native.SIZEOF_SOCKADDR_IN6, (byte) 0);
92          PlatformDependent.putShort(memory + Native.SOCKADDR_IN6_OFFSETOF_SIN6_FAMILY, Native.AF_INET6);
93          PlatformDependent.putShort(memory + Native.SOCKADDR_IN6_OFFSETOF_SIN6_PORT, handleNetworkOrder((short) port));
94          // Skip sin6_flowinfo as we did memset before
95          byte[] bytes = address.getAddress();
96          if  (bytes.length == IPV4_ADDRESS_LENGTH) {
97              int offset = Native.SOCKADDR_IN6_OFFSETOF_SIN6_ADDR + Native.IN6_ADDRESS_OFFSETOF_S6_ADDR;
98              PlatformDependent.copyMemory(IPV4_MAPPED_IPV6_PREFIX, 0, memory + offset, IPV4_MAPPED_IPV6_PREFIX.length);
99              PlatformDependent.copyMemory(bytes, 0,
100                     memory + offset + IPV4_MAPPED_IPV6_PREFIX.length, IPV4_ADDRESS_LENGTH);
101             // Skip sin6_scope_id as we did memset before
102         } else {
103             PlatformDependent.copyMemory(
104                     bytes, 0, memory + Native.SOCKADDR_IN6_OFFSETOF_SIN6_ADDR + Native.IN6_ADDRESS_OFFSETOF_S6_ADDR,
105                     IPV6_ADDRESS_LENGTH);
106             PlatformDependent.putInt(
107                     memory + Native.SOCKADDR_IN6_OFFSETOF_SIN6_SCOPE_ID, ((Inet6Address) address).getScopeId());
108         }
109         return Native.SIZEOF_SOCKADDR_IN6;
110     }
111 
112     static InetSocketAddress readIPv4(long memory, byte[] tmpArray) {
113         assert tmpArray.length == IPV4_ADDRESS_LENGTH;
114         int port = handleNetworkOrder(PlatformDependent.getShort(
115                 memory + Native.SOCKADDR_IN_OFFSETOF_SIN_PORT)) & 0xFFFF;
116         PlatformDependent.copyMemory(memory + Native.SOCKADDR_IN_OFFSETOF_SIN_ADDR + Native.IN_ADDRESS_OFFSETOF_S_ADDR,
117                 tmpArray, 0, IPV4_ADDRESS_LENGTH);
118         try {
119             return new InetSocketAddress(InetAddress.getByAddress(tmpArray), port);
120         } catch (UnknownHostException ignore) {
121             return null;
122         }
123     }
124 
125     static InetSocketAddress readIPv6(long memory, byte[] ipv6Array, byte[] ipv4Array) {
126         assert ipv6Array.length == IPV6_ADDRESS_LENGTH;
127         assert ipv4Array.length == IPV4_ADDRESS_LENGTH;
128 
129         int port = handleNetworkOrder(PlatformDependent.getShort(
130                 memory + Native.SOCKADDR_IN6_OFFSETOF_SIN6_PORT)) & 0xFFFF;
131         PlatformDependent.copyMemory(
132                 memory + Native.SOCKADDR_IN6_OFFSETOF_SIN6_ADDR + Native.IN6_ADDRESS_OFFSETOF_S6_ADDR,
133                 ipv6Array, 0, IPV6_ADDRESS_LENGTH);
134         if (PlatformDependent.equals(
135                 ipv6Array, 0, IPV4_MAPPED_IPV6_PREFIX, 0, IPV4_MAPPED_IPV6_PREFIX.length)) {
136             System.arraycopy(ipv6Array, IPV4_MAPPED_IPV6_PREFIX.length, ipv4Array, 0, IPV4_ADDRESS_LENGTH);
137             try {
138                 return new InetSocketAddress(Inet4Address.getByAddress(ipv4Array), port);
139             } catch (UnknownHostException ignore) {
140                 return null;
141             }
142         } else {
143             int scopeId = PlatformDependent.getInt(memory + Native.SOCKADDR_IN6_OFFSETOF_SIN6_SCOPE_ID);
144             try {
145                 return new InetSocketAddress(Inet6Address.getByAddress(null, ipv6Array, scopeId), port);
146             } catch (UnknownHostException ignore) {
147                 return null;
148             }
149         }
150     }
151 
152     static boolean hasPortIpv4(long memory) {
153         int port = handleNetworkOrder(PlatformDependent.getShort(
154                 memory + Native.SOCKADDR_IN_OFFSETOF_SIN_PORT)) & 0xFFFF;
155         return port > 0;
156     }
157 
158     static boolean hasPortIpv6(long memory) {
159         int port = handleNetworkOrder(PlatformDependent.getShort(
160                 memory + Native.SOCKADDR_IN6_OFFSETOF_SIN6_PORT)) & 0xFFFF;
161         return port > 0;
162     }
163 
164     private static short handleNetworkOrder(short v) {
165         return BIG_ENDIAN_NATIVE_ORDER ? v : Short.reverseBytes(v);
166     }
167 }