1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty5.channel.epoll;
17
18 import io.netty5.channel.ChannelException;
19 import io.netty5.channel.DefaultFileRegion;
20 import io.netty5.channel.socket.SocketProtocolFamily;
21 import io.netty5.channel.unix.NativeInetAddress;
22 import io.netty5.channel.unix.PeerCredentials;
23 import io.netty5.channel.unix.Socket;
24 import io.netty5.util.internal.SocketUtils;
25 import io.netty5.util.internal.UnstableApi;
26
27 import java.io.IOException;
28 import java.net.Inet6Address;
29 import java.net.InetAddress;
30 import java.net.NetworkInterface;
31 import java.net.ProtocolFamily;
32 import java.net.UnknownHostException;
33 import java.util.Enumeration;
34
35 import static io.netty5.channel.unix.Errors.ioResult;
36
37
38
39
40 @UnstableApi
41 public final class LinuxSocket extends Socket {
42 static final InetAddress INET6_ANY = unsafeInetAddrByName("::");
43 private static final InetAddress INET_ANY = unsafeInetAddrByName("0.0.0.0");
44 private static final long MAX_UINT32_T = 0xFFFFFFFFL;
45
46 LinuxSocket(int fd, SocketProtocolFamily family) {
47 super(fd, family);
48 }
49
50 int sendmmsg(NativeDatagramPacketArray.NativeDatagramPacket[] msgs,
51 int offset, int len) throws IOException {
52 return Native.sendmmsg(intValue(), ipv6, msgs, offset, len);
53 }
54
55 int recvmmsg(NativeDatagramPacketArray.NativeDatagramPacket[] msgs,
56 int offset, int len) throws IOException {
57 return Native.recvmmsg(intValue(), ipv6, msgs, offset, len);
58 }
59
60 int recvmsg(NativeDatagramPacketArray.NativeDatagramPacket msg) throws IOException {
61 return Native.recvmsg(intValue(), ipv6, msg);
62 }
63
64 void setTimeToLive(int ttl) throws IOException {
65 setTimeToLive(intValue(), ttl);
66 }
67
68 void setInterface(InetAddress address) throws IOException {
69 final NativeInetAddress a = NativeInetAddress.newInstance(address);
70 setInterface(intValue(), ipv6, a.address(), a.scopeId(), interfaceIndex(address));
71 }
72
73 void setNetworkInterface(NetworkInterface netInterface) throws IOException {
74 InetAddress address = deriveInetAddress(netInterface, protocolFamily() == SocketProtocolFamily.INET6);
75 if (address.equals(protocolFamily() == SocketProtocolFamily.INET ? INET_ANY : INET6_ANY)) {
76 throw new IOException("NetworkInterface does not support " + protocolFamily());
77 }
78 final NativeInetAddress nativeAddress = NativeInetAddress.newInstance(address);
79 setInterface(intValue(), ipv6, nativeAddress.address(), nativeAddress.scopeId(), interfaceIndex(netInterface));
80 }
81
82 InetAddress getInterface() throws IOException {
83 NetworkInterface inf = getNetworkInterface();
84 if (inf != null) {
85 Enumeration<InetAddress> addresses = SocketUtils.addressesFromNetworkInterface(inf);
86 if (addresses.hasMoreElements()) {
87 return addresses.nextElement();
88 }
89 }
90 return null;
91 }
92
93 NetworkInterface getNetworkInterface() throws IOException {
94 int ret = getInterface(intValue(), ipv6);
95 if (ipv6) {
96 return NetworkInterface.getByIndex(ret);
97 }
98 InetAddress address = inetAddress(ret);
99 return address != null ? NetworkInterface.getByInetAddress(address) : null;
100 }
101
102 private static InetAddress inetAddress(int value) {
103 byte[] var1 = {
104 (byte) (value >>> 24 & 255),
105 (byte) (value >>> 16 & 255),
106 (byte) (value >>> 8 & 255),
107 (byte) (value & 255)
108 };
109
110 try {
111 return InetAddress.getByAddress(var1);
112 } catch (UnknownHostException ignore) {
113 return null;
114 }
115 }
116
117 void joinGroup(InetAddress group, NetworkInterface netInterface, InetAddress source) throws IOException {
118 final NativeInetAddress g = NativeInetAddress.newInstance(group);
119 final boolean isIpv6 = group instanceof Inet6Address;
120 final NativeInetAddress i = NativeInetAddress.newInstance(deriveInetAddress(netInterface, isIpv6));
121 if (source != null) {
122 if (source.getClass() != group.getClass()) {
123 throw new IllegalArgumentException("Source address is different type to group");
124 }
125 final NativeInetAddress s = NativeInetAddress.newInstance(source);
126 joinSsmGroup(intValue(), ipv6 && isIpv6, g.address(), i.address(),
127 g.scopeId(), interfaceIndex(netInterface), s.address());
128 } else {
129 joinGroup(intValue(), ipv6 && isIpv6, g.address(), i.address(), g.scopeId(), interfaceIndex(netInterface));
130 }
131 }
132
133 void leaveGroup(InetAddress group, NetworkInterface netInterface, InetAddress source) throws IOException {
134 final NativeInetAddress g = NativeInetAddress.newInstance(group);
135 final boolean isIpv6 = group instanceof Inet6Address;
136 final NativeInetAddress i = NativeInetAddress.newInstance(deriveInetAddress(netInterface, isIpv6));
137 if (source != null) {
138 if (source.getClass() != group.getClass()) {
139 throw new IllegalArgumentException("Source address is different type to group");
140 }
141 final NativeInetAddress s = NativeInetAddress.newInstance(source);
142 leaveSsmGroup(intValue(), ipv6 && isIpv6, g.address(), i.address(),
143 g.scopeId(), interfaceIndex(netInterface), s.address());
144 } else {
145 leaveGroup(intValue(), ipv6 && isIpv6, g.address(), i.address(), g.scopeId(), interfaceIndex(netInterface));
146 }
147 }
148
149 private static int interfaceIndex(NetworkInterface networkInterface) {
150 return networkInterface.getIndex();
151 }
152
153 private static int interfaceIndex(InetAddress address) throws IOException {
154 NetworkInterface iface = NetworkInterface.getByInetAddress(address);
155 if (iface != null) {
156 return iface.getIndex();
157 }
158 return -1;
159 }
160
161 void setTcpDeferAccept(int deferAccept) throws IOException {
162 setTcpDeferAccept(intValue(), deferAccept);
163 }
164
165 void setTcpQuickAck(boolean quickAck) throws IOException {
166 setTcpQuickAck(intValue(), quickAck ? 1 : 0);
167 }
168
169 void setTcpCork(boolean tcpCork) throws IOException {
170 setTcpCork(intValue(), tcpCork ? 1 : 0);
171 }
172
173 void setSoBusyPoll(int loopMicros) throws IOException {
174 setSoBusyPoll(intValue(), loopMicros);
175 }
176
177 void setTcpNotSentLowAt(long tcpNotSentLowAt) throws IOException {
178 if (tcpNotSentLowAt < 0 || tcpNotSentLowAt > MAX_UINT32_T) {
179 throw new IllegalArgumentException("tcpNotSentLowAt must be a uint32_t");
180 }
181 setTcpNotSentLowAt(intValue(), (int) tcpNotSentLowAt);
182 }
183
184 void setTcpFastOpen(int tcpFastopenBacklog) throws IOException {
185 setTcpFastOpen(intValue(), tcpFastopenBacklog);
186 }
187
188 void setTcpKeepIdle(int seconds) throws IOException {
189 setTcpKeepIdle(intValue(), seconds);
190 }
191
192 void setTcpKeepIntvl(int seconds) throws IOException {
193 setTcpKeepIntvl(intValue(), seconds);
194 }
195
196 void setTcpKeepCnt(int probes) throws IOException {
197 setTcpKeepCnt(intValue(), probes);
198 }
199
200 void setTcpUserTimeout(int milliseconds) throws IOException {
201 setTcpUserTimeout(intValue(), milliseconds);
202 }
203
204 void setIpFreeBind(boolean enabled) throws IOException {
205 setIpFreeBind(intValue(), enabled ? 1 : 0);
206 }
207
208 void setIpTransparent(boolean enabled) throws IOException {
209 setIpTransparent(intValue(), enabled ? 1 : 0);
210 }
211
212 void setIpRecvOrigDestAddr(boolean enabled) throws IOException {
213 setIpRecvOrigDestAddr(intValue(), enabled ? 1 : 0);
214 }
215
216 int getTimeToLive() throws IOException {
217 return getTimeToLive(intValue());
218 }
219
220 void getTcpInfo(EpollTcpInfo info) throws IOException {
221 getTcpInfo(intValue(), info.info);
222 }
223
224 void setTcpMd5Sig(InetAddress address, byte[] key) throws IOException {
225 final NativeInetAddress a = NativeInetAddress.newInstance(address);
226 setTcpMd5Sig(intValue(), ipv6, a.address(), a.scopeId(), key);
227 }
228
229 boolean isTcpCork() throws IOException {
230 return isTcpCork(intValue()) != 0;
231 }
232
233 int getSoBusyPoll() throws IOException {
234 return getSoBusyPoll(intValue());
235 }
236
237 int getTcpDeferAccept() throws IOException {
238 return getTcpDeferAccept(intValue());
239 }
240
241 boolean isTcpQuickAck() throws IOException {
242 return isTcpQuickAck(intValue()) != 0;
243 }
244
245 long getTcpNotSentLowAt() throws IOException {
246 return getTcpNotSentLowAt(intValue()) & MAX_UINT32_T;
247 }
248
249 int getTcpKeepIdle() throws IOException {
250 return getTcpKeepIdle(intValue());
251 }
252
253 int getTcpKeepIntvl() throws IOException {
254 return getTcpKeepIntvl(intValue());
255 }
256
257 int getTcpKeepCnt() throws IOException {
258 return getTcpKeepCnt(intValue());
259 }
260
261 int getTcpUserTimeout() throws IOException {
262 return getTcpUserTimeout(intValue());
263 }
264
265 boolean isIpFreeBind() throws IOException {
266 return isIpFreeBind(intValue()) != 0;
267 }
268
269 boolean isIpTransparent() throws IOException {
270 return isIpTransparent(intValue()) != 0;
271 }
272
273 boolean isIpRecvOrigDestAddr() throws IOException {
274 return isIpRecvOrigDestAddr(intValue()) != 0;
275 }
276
277 PeerCredentials getPeerCredentials() throws IOException {
278 return getPeerCredentials(intValue());
279 }
280
281 boolean isLoopbackModeDisabled() throws IOException {
282 return getIpMulticastLoop(intValue(), ipv6) == 0;
283 }
284
285 void setLoopbackModeDisabled(boolean loopbackModeDisabled) throws IOException {
286 setIpMulticastLoop(intValue(), ipv6, loopbackModeDisabled ? 0 : 1);
287 }
288
289 boolean isUdpGro() throws IOException {
290 return isUdpGro(intValue()) != 0;
291 }
292
293 void setUdpGro(boolean gro) throws IOException {
294 setUdpGro(intValue(), gro ? 1 : 0);
295 }
296
297 long sendFile(DefaultFileRegion src, long baseOffset, long offset, long length) throws IOException {
298
299
300 src.open();
301
302 long res = sendFile(intValue(), src, baseOffset, offset, length);
303 if (res >= 0) {
304 return res;
305 }
306 return ioResult("sendfile", (int) res);
307 }
308
309 private static InetAddress deriveInetAddress(NetworkInterface netInterface, boolean ipv6) {
310 final InetAddress ipAny = ipv6 ? INET6_ANY : INET_ANY;
311 if (netInterface != null) {
312 final Enumeration<InetAddress> ias = netInterface.getInetAddresses();
313 while (ias.hasMoreElements()) {
314 final InetAddress ia = ias.nextElement();
315 final boolean isV6 = ia instanceof Inet6Address;
316 if (isV6 == ipv6) {
317 return ia;
318 }
319 }
320 }
321 return ipAny;
322 }
323
324 public static LinuxSocket newDatagramSocket(ProtocolFamily family) {
325 if (family == null) {
326 return newSocketDgram();
327 }
328 SocketProtocolFamily protocolFamily = SocketProtocolFamily.of(family);
329 switch (protocolFamily) {
330 case UNIX:
331 return newSocketDomainDgram();
332 case INET6:
333 case INET:
334 return newSocketDgram(protocolFamily);
335 default:
336 throw new UnsupportedOperationException();
337 }
338 }
339
340 public static LinuxSocket newSocket(ProtocolFamily family) {
341 if (family == null) {
342 return newSocketStream();
343 }
344 SocketProtocolFamily protocolFamily = SocketProtocolFamily.of(family);
345
346 switch (protocolFamily) {
347 case UNIX:
348 return newSocketDomain();
349 case INET6:
350 case INET:
351 return newSocketStream(protocolFamily);
352 default:
353 throw new UnsupportedOperationException();
354 }
355 }
356
357 public static LinuxSocket newSocketStream(boolean ipv6) {
358 return new LinuxSocket(newSocketStream0(ipv6), ipv6 ? SocketProtocolFamily.INET6 : SocketProtocolFamily.INET);
359 }
360
361 public static LinuxSocket newSocketStream(ProtocolFamily protocol) {
362 return new LinuxSocket(newSocketStream0(protocol), SocketProtocolFamily.of(protocol));
363 }
364
365 public static LinuxSocket newSocketStream() {
366 return newSocketStream(isIPv6Preferred());
367 }
368
369 public static LinuxSocket newSocketDgram(boolean ipv6) {
370 return new LinuxSocket(newSocketDgram0(ipv6), ipv6 ? SocketProtocolFamily.INET6 : SocketProtocolFamily.INET);
371 }
372
373 public static LinuxSocket newSocketDgram(ProtocolFamily family) {
374 return new LinuxSocket(newSocketDgram0(family), SocketProtocolFamily.of(family));
375 }
376
377 public static LinuxSocket newSocketDgram() {
378 return newSocketDgram(isIPv6Preferred());
379 }
380
381 public static LinuxSocket newSocketDomain() {
382 return new LinuxSocket(newSocketDomain0(), SocketProtocolFamily.UNIX);
383 }
384
385 public static LinuxSocket newSocketDomainDgram() {
386 return new LinuxSocket(newSocketDomainDgram0(), SocketProtocolFamily.UNIX);
387 }
388
389 private static InetAddress unsafeInetAddrByName(String inetName) {
390 try {
391 return InetAddress.getByName(inetName);
392 } catch (UnknownHostException uhe) {
393 throw new ChannelException(uhe);
394 }
395 }
396
397 private static native void joinGroup(int fd, boolean ipv6, byte[] group, byte[] interfaceAddress,
398 int scopeId, int interfaceIndex) throws IOException;
399 private static native void joinSsmGroup(int fd, boolean ipv6, byte[] group, byte[] interfaceAddress,
400 int scopeId, int interfaceIndex, byte[] source) throws IOException;
401 private static native void leaveGroup(int fd, boolean ipv6, byte[] group, byte[] interfaceAddress,
402 int scopeId, int interfaceIndex) throws IOException;
403 private static native void leaveSsmGroup(int fd, boolean ipv6, byte[] group, byte[] interfaceAddress,
404 int scopeId, int interfaceIndex, byte[] source) throws IOException;
405 private static native long sendFile(int socketFd, DefaultFileRegion src, long baseOffset,
406 long offset, long length) throws IOException;
407
408 private static native int getTcpDeferAccept(int fd) throws IOException;
409 private static native int isTcpQuickAck(int fd) throws IOException;
410 private static native int isTcpCork(int fd) throws IOException;
411 private static native int getSoBusyPoll(int fd) throws IOException;
412 private static native int getTcpNotSentLowAt(int fd) throws IOException;
413 private static native int getTcpKeepIdle(int fd) throws IOException;
414 private static native int getTcpKeepIntvl(int fd) throws IOException;
415 private static native int getTcpKeepCnt(int fd) throws IOException;
416 private static native int getTcpUserTimeout(int fd) throws IOException;
417 private static native int getTimeToLive(int fd) throws IOException;
418 private static native int isIpFreeBind(int fd) throws IOException;
419 private static native int isIpTransparent(int fd) throws IOException;
420 private static native int isIpRecvOrigDestAddr(int fd) throws IOException;
421 private static native void getTcpInfo(int fd, long[] array) throws IOException;
422 private static native PeerCredentials getPeerCredentials(int fd) throws IOException;
423
424 private static native void setTcpDeferAccept(int fd, int deferAccept) throws IOException;
425 private static native void setTcpQuickAck(int fd, int quickAck) throws IOException;
426 private static native void setTcpCork(int fd, int tcpCork) throws IOException;
427 private static native void setSoBusyPoll(int fd, int loopMicros) throws IOException;
428 private static native void setTcpNotSentLowAt(int fd, int tcpNotSentLowAt) throws IOException;
429 private static native void setTcpFastOpen(int fd, int tcpFastopenBacklog) throws IOException;
430 private static native void setTcpKeepIdle(int fd, int seconds) throws IOException;
431 private static native void setTcpKeepIntvl(int fd, int seconds) throws IOException;
432 private static native void setTcpKeepCnt(int fd, int probes) throws IOException;
433 private static native void setTcpUserTimeout(int fd, int milliseconds)throws IOException;
434 private static native void setIpFreeBind(int fd, int freeBind) throws IOException;
435 private static native void setIpTransparent(int fd, int transparent) throws IOException;
436 private static native void setIpRecvOrigDestAddr(int fd, int transparent) throws IOException;
437 private static native void setTcpMd5Sig(
438 int fd, boolean ipv6, byte[] address, int scopeId, byte[] key) throws IOException;
439 private static native void setInterface(
440 int fd, boolean ipv6, byte[] interfaceAddress, int scopeId, int networkInterfaceIndex) throws IOException;
441 private static native int getInterface(int fd, boolean ipv6);
442 private static native int getIpMulticastLoop(int fd, boolean ipv6) throws IOException;
443 private static native void setIpMulticastLoop(int fd, boolean ipv6, int enabled) throws IOException;
444 private static native void setTimeToLive(int fd, int ttl) throws IOException;
445 private static native int isUdpGro(int fd) throws IOException;
446 private static native void setUdpGro(int fd, int gro) throws IOException;
447 }