1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty5.channel.kqueue;
17
18 import io.netty5.channel.DefaultFileRegion;
19 import io.netty5.channel.socket.SocketProtocolFamily;
20 import io.netty5.channel.unix.IovArray;
21 import io.netty5.channel.unix.PeerCredentials;
22 import io.netty5.channel.unix.Socket;
23
24 import java.io.IOException;
25 import java.net.Inet6Address;
26 import java.net.InetAddress;
27 import java.net.InetSocketAddress;
28 import java.net.ProtocolFamily;
29
30 import static io.netty5.channel.kqueue.AcceptFilter.PLATFORM_UNSUPPORTED;
31 import static io.netty5.channel.kqueue.Native.CONNECT_TCP_FASTOPEN;
32 import static io.netty5.channel.unix.Errors.ERRNO_EINPROGRESS_NEGATIVE;
33 import static io.netty5.channel.unix.Errors.ioResult;
34 import static io.netty5.channel.unix.NativeInetAddress.ipv4MappedIpv6Address;
35 import static java.util.Objects.requireNonNull;
36
37
38
39
40 final class BsdSocket extends Socket {
41
42
43
44 private static final int APPLE_SND_LOW_AT_MAX = 1 << 17;
45 private static final int FREEBSD_SND_LOW_AT_MAX = 1 << 15;
46 static final int BSD_SND_LOW_AT_MAX = Math.min(APPLE_SND_LOW_AT_MAX, FREEBSD_SND_LOW_AT_MAX);
47
48
49
50
51
52 private static final int UNSPECIFIED_SOURCE_INTERFACE = 0;
53
54 BsdSocket(int fd, SocketProtocolFamily protocolFamily) {
55 super(fd, protocolFamily);
56 }
57
58 void setAcceptFilter(AcceptFilter acceptFilter) throws IOException {
59 setAcceptFilter(intValue(), acceptFilter.filterName(), acceptFilter.filterArgs());
60 }
61
62 void setTcpNoPush(boolean tcpNoPush) throws IOException {
63 setTcpNoPush(intValue(), tcpNoPush ? 1 : 0);
64 }
65
66 void setSndLowAt(int lowAt) throws IOException {
67 setSndLowAt(intValue(), lowAt);
68 }
69
70 public void setTcpFastOpen(boolean enableTcpFastOpen) throws IOException {
71 setTcpFastOpen(intValue(), enableTcpFastOpen ? 1 : 0);
72 }
73
74 boolean isTcpNoPush() throws IOException {
75 return getTcpNoPush(intValue()) != 0;
76 }
77
78 int getSndLowAt() throws IOException {
79 return getSndLowAt(intValue());
80 }
81
82 AcceptFilter getAcceptFilter() throws IOException {
83 String[] result = getAcceptFilter(intValue());
84 return result == null ? PLATFORM_UNSUPPORTED : new AcceptFilter(result[0], result[1]);
85 }
86
87 public boolean isTcpFastOpen() throws IOException {
88 return isTcpFastOpen(intValue()) != 0;
89 }
90
91 PeerCredentials getPeerCredentials() throws IOException {
92 return getPeerCredentials(intValue());
93 }
94
95 long sendFile(DefaultFileRegion src, long baseOffset, long offset, long length) throws IOException {
96
97
98 src.open();
99
100 long res = sendFile(intValue(), src, baseOffset, offset, length);
101 if (res >= 0) {
102 return res;
103 }
104 return ioResult("sendfile", (int) res);
105 }
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122 int connectx(InetSocketAddress source, InetSocketAddress destination, IovArray data, boolean tcpFastOpen)
123 throws IOException {
124 requireNonNull(destination, "Destination InetSocketAddress cannot be null.");
125 int flags = tcpFastOpen ? CONNECT_TCP_FASTOPEN : 0;
126
127 boolean sourceIPv6;
128 byte[] sourceAddress;
129 int sourceScopeId;
130 int sourcePort;
131 if (source == null) {
132 sourceIPv6 = false;
133 sourceAddress = null;
134 sourceScopeId = 0;
135 sourcePort = 0;
136 } else {
137 InetAddress sourceInetAddress = source.getAddress();
138 sourceIPv6 = useIpv6(this, sourceInetAddress);
139 if (sourceInetAddress instanceof Inet6Address) {
140 sourceAddress = sourceInetAddress.getAddress();
141 sourceScopeId = ((Inet6Address) sourceInetAddress).getScopeId();
142 } else {
143
144 sourceScopeId = 0;
145 sourceAddress = ipv4MappedIpv6Address(sourceInetAddress.getAddress());
146 }
147 sourcePort = source.getPort();
148 }
149
150 InetAddress destinationInetAddress = destination.getAddress();
151 boolean destinationIPv6 = useIpv6(this, destinationInetAddress);
152 byte[] destinationAddress;
153 int destinationScopeId;
154 if (destinationInetAddress instanceof Inet6Address) {
155 destinationAddress = destinationInetAddress.getAddress();
156 destinationScopeId = ((Inet6Address) destinationInetAddress).getScopeId();
157 } else {
158
159 destinationScopeId = 0;
160 destinationAddress = ipv4MappedIpv6Address(destinationInetAddress.getAddress());
161 }
162 int destinationPort = destination.getPort();
163
164 long iovAddress;
165 int iovCount;
166 int iovDataLength;
167 if (data == null || data.count() == 0) {
168 iovAddress = 0;
169 iovCount = 0;
170 iovDataLength = 0;
171 } else {
172 iovAddress = data.memoryAddress(0);
173 iovCount = data.count();
174 long size = data.size();
175 if (size > Integer.MAX_VALUE) {
176 throw new IOException("IovArray.size() too big: " + size + " bytes.");
177 }
178 iovDataLength = (int) size;
179 }
180
181 int result = connectx(intValue(),
182 UNSPECIFIED_SOURCE_INTERFACE, sourceIPv6, sourceAddress, sourceScopeId, sourcePort,
183 destinationIPv6, destinationAddress, destinationScopeId, destinationPort,
184 flags, iovAddress, iovCount, iovDataLength);
185 if (result == ERRNO_EINPROGRESS_NEGATIVE) {
186
187
188
189 return -iovDataLength;
190 }
191 if (result < 0) {
192 return ioResult("connectx", result);
193 }
194 return result;
195 }
196
197 public static BsdSocket newDatagramSocket(ProtocolFamily family) {
198 if (family == null) {
199 return newSocketDgram();
200 }
201 SocketProtocolFamily protocolFamily = SocketProtocolFamily.of(family);
202 switch (protocolFamily) {
203 case UNIX:
204 return newSocketDomainDgram();
205 case INET6:
206 case INET:
207 return newSocketDgram(protocolFamily);
208 default:
209 throw new UnsupportedOperationException();
210 }
211 }
212
213 public static BsdSocket newSocket(ProtocolFamily family) {
214 if (family == null) {
215 return newSocketStream();
216 }
217 SocketProtocolFamily protocolFamily = SocketProtocolFamily.of(family);
218 switch (protocolFamily) {
219 case UNIX:
220 return newSocketDomain();
221 case INET6:
222 case INET:
223 return newSocketStream(protocolFamily);
224 default:
225 throw new UnsupportedOperationException();
226 }
227 }
228
229 public static BsdSocket newSocketStream() {
230 return new BsdSocket(newSocketStream0(), isIPv6Preferred() ?
231 SocketProtocolFamily.INET6 : SocketProtocolFamily.INET);
232 }
233
234 private static BsdSocket newSocketStream(SocketProtocolFamily protocol) {
235 return new BsdSocket(newSocketStream0(protocol), protocol);
236 }
237
238 public static BsdSocket newSocketDgram() {
239 return new BsdSocket(newSocketDgram0(), isIPv6Preferred() ?
240 SocketProtocolFamily.INET6 : SocketProtocolFamily.INET);
241 }
242
243 public static BsdSocket newSocketDgram(ProtocolFamily protocol) {
244 if (protocol == null) {
245 protocol = isIPv6Preferred() ?
246 SocketProtocolFamily.INET6 : SocketProtocolFamily.INET;
247 }
248 return new BsdSocket(newSocketDgram0(protocol), SocketProtocolFamily.of(protocol));
249 }
250
251 public static BsdSocket newSocketDomain() {
252 return new BsdSocket(newSocketDomain0(), SocketProtocolFamily.UNIX);
253 }
254
255 public static BsdSocket newSocketDomainDgram() {
256 return new BsdSocket(newSocketDomainDgram0(), SocketProtocolFamily.UNIX);
257 }
258
259 private static native long sendFile(int socketFd, DefaultFileRegion src, long baseOffset,
260 long offset, long length) throws IOException;
261
262
263
264
265 private static native int connectx(
266 int socketFd,
267
268 int sourceInterface,
269 boolean sourceIPv6, byte[] sourceAddress, int sourceScopeId, int sourcePort,
270 boolean destinationIPv6, byte[] destinationAddress, int destinationScopeId, int destinationPort,
271
272 int flags,
273 long iovAddress, int iovCount, int iovDataLength
274
275 );
276
277 private static native String[] getAcceptFilter(int fd) throws IOException;
278
279 private static native int getTcpNoPush(int fd) throws IOException;
280
281 private static native int getSndLowAt(int fd) throws IOException;
282
283 private static native int isTcpFastOpen(int fd) throws IOException;
284
285 private static native PeerCredentials getPeerCredentials(int fd) throws IOException;
286
287 private static native void setAcceptFilter(int fd, String filterName, String filterArgs) throws IOException;
288
289 private static native void setTcpNoPush(int fd, int tcpNoPush) throws IOException;
290
291 private static native void setSndLowAt(int fd, int lowAt) throws IOException;
292
293 private static native void setTcpFastOpen(int fd, int enableFastOpen) throws IOException;
294 }