1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.quic;
17
18 import io.netty.util.internal.PlatformDependent;
19 import org.jetbrains.annotations.Nullable;
20
21 import java.net.Inet4Address;
22 import java.net.Inet6Address;
23 import java.net.InetAddress;
24 import java.net.InetSocketAddress;
25 import java.net.UnknownHostException;
26 import java.nio.ByteBuffer;
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[Quiche.SIZEOF_SOCKADDR_IN6];
34 static final byte[] SOCKADDR_IN_EMPTY_ARRAY = new byte[Quiche.SIZEOF_SOCKADDR_IN];
35
36 private SockaddrIn() { }
37
38 static int cmp(long memory, long memory2) {
39 return Quiche.sockaddr_cmp(memory, memory2);
40 }
41
42 static int setAddress(ByteBuffer memory, InetSocketAddress address) {
43 InetAddress addr = address.getAddress();
44 return setAddress(addr instanceof Inet6Address, memory, address);
45 }
46
47 static int setAddress(boolean ipv6, ByteBuffer memory, InetSocketAddress address) {
48 if (ipv6) {
49 return SockaddrIn.setIPv6(memory, address.getAddress(), address.getPort());
50 } else {
51 return SockaddrIn.setIPv4(memory, address.getAddress(), address.getPort());
52 }
53 }
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69 static int setIPv4(ByteBuffer memory, InetAddress address, int port) {
70 int position = memory.position();
71 try {
72
73 memory.put(SOCKADDR_IN_EMPTY_ARRAY);
74
75 memory.putShort(position + Quiche.SOCKADDR_IN_OFFSETOF_SIN_FAMILY, Quiche.AF_INET);
76 memory.putShort(position + Quiche.SOCKADDR_IN_OFFSETOF_SIN_PORT, (short) port);
77
78 byte[] bytes = address.getAddress();
79 int offset = 0;
80 if (bytes.length == IPV6_ADDRESS_LENGTH) {
81
82 offset = IPV4_MAPPED_IPV6_PREFIX.length;
83 }
84 assert bytes.length == offset + IPV4_ADDRESS_LENGTH;
85 memory.position(position + Quiche.SOCKADDR_IN_OFFSETOF_SIN_ADDR + Quiche.IN_ADDRESS_OFFSETOF_S_ADDR);
86 memory.put(bytes, offset, IPV4_ADDRESS_LENGTH);
87 return Quiche.SIZEOF_SOCKADDR_IN;
88 } finally {
89 memory.position(position);
90 }
91 }
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106 static int setIPv6(ByteBuffer memory, InetAddress address, int port) {
107 int position = memory.position();
108 try {
109
110 memory.put(SOCKADDR_IN6_EMPTY_ARRAY);
111
112 memory.putShort(position + Quiche.SOCKADDR_IN6_OFFSETOF_SIN6_FAMILY, Quiche.AF_INET6);
113 memory.putShort(position + Quiche.SOCKADDR_IN6_OFFSETOF_SIN6_PORT, (short) port);
114
115
116 byte[] bytes = address.getAddress();
117 int offset = Quiche.SOCKADDR_IN6_OFFSETOF_SIN6_ADDR + Quiche.IN6_ADDRESS_OFFSETOF_S6_ADDR;
118
119 if (bytes.length == IPV4_ADDRESS_LENGTH) {
120 memory.position(position + offset);
121 memory.put(IPV4_MAPPED_IPV6_PREFIX);
122
123 memory.position(position + offset + IPV4_MAPPED_IPV6_PREFIX.length);
124 memory.put(bytes, 0, IPV4_ADDRESS_LENGTH);
125
126
127 } else {
128 memory.position(position + offset);
129 memory.put(bytes, 0, IPV6_ADDRESS_LENGTH);
130
131 memory.putInt(position + Quiche.SOCKADDR_IN6_OFFSETOF_SIN6_SCOPE_ID,
132 ((Inet6Address) address).getScopeId());
133 }
134 return Quiche.SIZEOF_SOCKADDR_IN6;
135 } finally {
136 memory.position(position);
137 }
138 }
139
140 @Nullable
141 static InetSocketAddress getIPv4(ByteBuffer memory, byte[] tmpArray) {
142 assert tmpArray.length == IPV4_ADDRESS_LENGTH;
143 int position = memory.position();
144
145 try {
146 int port = memory.getShort(position + Quiche.SOCKADDR_IN_OFFSETOF_SIN_PORT) & 0xFFFF;
147 memory.position(position + Quiche.SOCKADDR_IN_OFFSETOF_SIN_ADDR + Quiche.IN_ADDRESS_OFFSETOF_S_ADDR);
148 memory.get(tmpArray);
149 try {
150 return new InetSocketAddress(InetAddress.getByAddress(tmpArray), port);
151 } catch (UnknownHostException ignore) {
152 return null;
153 }
154 } finally {
155 memory.position(position);
156 }
157 }
158
159 @Nullable
160 static InetSocketAddress getIPv6(ByteBuffer memory, byte[] ipv6Array, byte[] ipv4Array) {
161 assert ipv6Array.length == IPV6_ADDRESS_LENGTH;
162 assert ipv4Array.length == IPV4_ADDRESS_LENGTH;
163 int position = memory.position();
164
165 try {
166 int port = memory.getShort(
167 position + Quiche.SOCKADDR_IN6_OFFSETOF_SIN6_PORT) & 0xFFFF;
168 memory.position(position + Quiche.SOCKADDR_IN6_OFFSETOF_SIN6_ADDR + Quiche.IN6_ADDRESS_OFFSETOF_S6_ADDR);
169 memory.get(ipv6Array);
170 if (PlatformDependent.equals(
171 ipv6Array, 0, IPV4_MAPPED_IPV6_PREFIX, 0, IPV4_MAPPED_IPV6_PREFIX.length)) {
172 System.arraycopy(ipv6Array, IPV4_MAPPED_IPV6_PREFIX.length, ipv4Array, 0, IPV4_ADDRESS_LENGTH);
173 try {
174 return new InetSocketAddress(Inet4Address.getByAddress(ipv4Array), port);
175 } catch (UnknownHostException ignore) {
176 return null;
177 }
178 } else {
179 int scopeId = memory.getInt(position + Quiche.SOCKADDR_IN6_OFFSETOF_SIN6_SCOPE_ID);
180 try {
181 return new InetSocketAddress(Inet6Address.getByAddress(null, ipv6Array, scopeId), port);
182 } catch (UnknownHostException ignore) {
183 return null;
184 }
185 }
186 } finally {
187 memory.position(position);
188 }
189 }
190 }