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  import java.nio.ByteBuffer;
26  import java.nio.ByteOrder;
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      static final byte[] SOCKADDR_IN6_EMPTY_ARRAY = new byte[Native.SIZEOF_SOCKADDR_IN6];
34      static final byte[] SOCKADDR_IN_EMPTY_ARRAY = new byte[Native.SIZEOF_SOCKADDR_IN];
35  
36      private SockaddrIn() { }
37  
38      static int set(boolean ipv6, ByteBuffer memory, InetSocketAddress address) {
39          if (ipv6) {
40              return setIPv6(memory, address.getAddress(), address.getPort());
41          }
42          return setIPv4(memory, address.getAddress(), address.getPort());
43      }
44  
45      /**
46       * <pre>{@code
47       * struct sockaddr_in {
48       *      sa_family_t    sin_family; // address family: AF_INET
49       *      in_port_t      sin_port;   // port in network byte order
50       *      struct in_addr sin_addr;   // internet address
51       * };
52       *
53       * // Internet address.
54       * struct in_addr {
55       *     uint32_t       s_addr;     // address in network byte order
56       * };
57       * }</pre>
58       */
59      static int setIPv4(ByteBuffer memory, InetAddress address, int port) {
60          int position = memory.position();
61          memory.mark();
62          try {
63              // memset
64              memory.put(SOCKADDR_IN_EMPTY_ARRAY);
65  
66              memory.putShort(position + Native.SOCKADDR_IN_OFFSETOF_SIN_FAMILY, Native.AF_INET);
67              memory.putShort(position + Native.SOCKADDR_IN_OFFSETOF_SIN_PORT, handleNetworkOrder(memory.order(),
68                      (short) port));
69  
70              byte[] bytes = address.getAddress();
71              int offset = 0;
72              if (bytes.length == IPV6_ADDRESS_LENGTH) {
73                  // IPV6 mapped IPV4 address, we only need the last 4 bytes.
74                  offset = IPV4_MAPPED_IPV6_PREFIX.length;
75              }
76              assert bytes.length == offset + IPV4_ADDRESS_LENGTH;
77              memory.position(position + Native.SOCKADDR_IN_OFFSETOF_SIN_ADDR + Native.IN_ADDRESS_OFFSETOF_S_ADDR);
78              memory.put(bytes, offset, IPV4_ADDRESS_LENGTH);
79              return Native.SIZEOF_SOCKADDR_IN;
80          } finally {
81              // Restore position as we did change it via memory.put(byte[]...).
82              memory.reset();
83          }
84      }
85  
86      /**
87       * <pre>{@code
88       * struct sockaddr_in6 {
89       *     sa_family_t     sin6_family;   // AF_INET6
90       *     in_port_t       sin6_port;     // port number
91       *     uint32_t        sin6_flowinfo; // IPv6 flow information
92       *     struct in6_addr sin6_addr;     // IPv6 address
93       *     uint32_t        sin6_scope_id; /* Scope ID (new in 2.4)
94       * };
95       *
96       * struct in6_addr {
97       *     unsigned char s6_addr[16];   // IPv6 address
98       * };
99       * }</pre>
100      */
101     static int setIPv6(ByteBuffer memory, InetAddress address, int port) {
102         int position = memory.position();
103         memory.mark();
104         try {
105             // memset
106             memory.put(SOCKADDR_IN6_EMPTY_ARRAY);
107             memory.putShort(position + Native.SOCKADDR_IN6_OFFSETOF_SIN6_FAMILY, Native.AF_INET6);
108             memory.putShort(position + Native.SOCKADDR_IN6_OFFSETOF_SIN6_PORT,
109                     handleNetworkOrder(memory.order(), (short) port));
110             // Skip sin6_flowinfo as we did memset before
111             byte[] bytes = address.getAddress();
112             int offset = Native.SOCKADDR_IN6_OFFSETOF_SIN6_ADDR + Native.IN6_ADDRESS_OFFSETOF_S6_ADDR;
113             if (bytes.length == IPV4_ADDRESS_LENGTH) {
114                 memory.position(position + offset);
115                 memory.put(IPV4_MAPPED_IPV6_PREFIX);
116                 memory.put(bytes, 0, IPV4_ADDRESS_LENGTH);
117 
118                 // Skip sin6_scope_id as we did memset before
119             } else {
120                 memory.position(position + offset);
121                 memory.put(bytes, 0, IPV6_ADDRESS_LENGTH);
122 
123                 memory.putInt(position + Native.SOCKADDR_IN6_OFFSETOF_SIN6_SCOPE_ID,
124                         ((Inet6Address) address).getScopeId());
125             }
126             return Native.SIZEOF_SOCKADDR_IN6;
127         } finally {
128             memory.reset();
129         }
130     }
131 
132     static InetSocketAddress getIPv4(ByteBuffer memory, byte[] tmpArray) {
133         assert tmpArray.length == IPV4_ADDRESS_LENGTH;
134         int position = memory.position();
135         memory.mark();
136         try {
137             int port = handleNetworkOrder(memory.order(),
138                     memory.getShort(position + Native.SOCKADDR_IN_OFFSETOF_SIN_PORT)) & 0xFFFF;
139             memory.position(position + Native.SOCKADDR_IN_OFFSETOF_SIN_ADDR + Native.IN_ADDRESS_OFFSETOF_S_ADDR);
140             memory.get(tmpArray);
141             try {
142                 return new InetSocketAddress(InetAddress.getByAddress(tmpArray), port);
143             } catch (UnknownHostException ignore) {
144                 return null;
145             }
146         } finally {
147             memory.reset();
148         }
149     }
150 
151     static InetSocketAddress getIPv6(ByteBuffer memory, byte[] ipv6Array, byte[] ipv4Array) {
152         assert ipv6Array.length == IPV6_ADDRESS_LENGTH;
153         assert ipv4Array.length == IPV4_ADDRESS_LENGTH;
154         int position = memory.position();
155         memory.mark();
156         try {
157             int port = handleNetworkOrder(memory.order(), memory.getShort(
158                     position + Native.SOCKADDR_IN6_OFFSETOF_SIN6_PORT)) & 0xFFFF;
159             memory.position(position + Native.SOCKADDR_IN6_OFFSETOF_SIN6_ADDR + Native.IN6_ADDRESS_OFFSETOF_S6_ADDR);
160             memory.get(ipv6Array);
161             if (PlatformDependent.equals(
162                     ipv6Array, 0, IPV4_MAPPED_IPV6_PREFIX, 0, IPV4_MAPPED_IPV6_PREFIX.length)) {
163                 System.arraycopy(ipv6Array, IPV4_MAPPED_IPV6_PREFIX.length, ipv4Array, 0, IPV4_ADDRESS_LENGTH);
164                 try {
165                     return new InetSocketAddress(Inet4Address.getByAddress(ipv4Array), port);
166                 } catch (UnknownHostException ignore) {
167                     return null;
168                 }
169             } else {
170                 int scopeId = memory.getInt(position + Native.SOCKADDR_IN6_OFFSETOF_SIN6_SCOPE_ID);
171                 try {
172                     return new InetSocketAddress(Inet6Address.getByAddress(null, ipv6Array, scopeId), port);
173                 } catch (UnknownHostException ignore) {
174                     return null;
175                 }
176             }
177         } finally {
178             memory.reset();
179         }
180     }
181 
182     static boolean hasPortIpv4(ByteBuffer memory) {
183         int port = memory.getShort(memory.position() + Native.SOCKADDR_IN_OFFSETOF_SIN_PORT) & 0xFFFF;
184         return port > 0;
185     }
186 
187     static boolean hasPortIpv6(ByteBuffer memory) {
188         int port = memory.getShort(memory.position() + Native.SOCKADDR_IN6_OFFSETOF_SIN6_PORT) & 0xFFFF;
189         return port > 0;
190     }
191 
192     private static short handleNetworkOrder(ByteOrder order, short v) {
193         return order != ByteOrder.nativeOrder() ? v : Short.reverseBytes(v);
194     }
195 }