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.channel.ChannelException;
19  import io.netty.channel.socket.SocketProtocolFamily;
20  import io.netty.channel.unix.Errors;
21  import io.netty.channel.unix.NativeInetAddress;
22  import io.netty.channel.unix.PeerCredentials;
23  import io.netty.channel.unix.Socket;
24  import io.netty.util.internal.SocketUtils;
25  
26  import java.io.IOException;
27  import java.net.Inet6Address;
28  import java.net.InetAddress;
29  import java.net.NetworkInterface;
30  import java.net.UnknownHostException;
31  import java.util.Enumeration;
32  
33  /**
34   * A socket which provides access Linux native methods.
35   */
36  final class LinuxSocket extends Socket {
37      static final InetAddress INET6_ANY = unsafeInetAddrByName("::");
38      private static final InetAddress INET_ANY = unsafeInetAddrByName("0.0.0.0");
39      private static final long MAX_UINT32_T = 0xFFFFFFFFL;
40      private boolean blocking;
41  
42      LinuxSocket(int fd) {
43          super(fd);
44      }
45  
46      static LinuxSocket makeBlocking(LinuxSocket socket) {
47          try {
48              socket.makeBlocking();
49              return socket;
50          } catch (IOException e) {
51              throw new ChannelException(e);
52          }
53      }
54  
55      SocketProtocolFamily family() {
56          return ipv6 ? SocketProtocolFamily.INET6 : SocketProtocolFamily.INET;
57      }
58  
59      @Override
60      public boolean markClosed() {
61          return super.markClosed();
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, family() == SocketProtocolFamily.INET6);
75          if (address.equals(family() == SocketProtocolFamily.INET ? INET_ANY : INET6_ANY)) {
76              throw new IOException("NetworkInterface does not support " + family());
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             final NativeInetAddress s = NativeInetAddress.newInstance(source);
123             joinSsmGroup(intValue(), ipv6, g.address(), i.address(),
124                     g.scopeId(), interfaceIndex(netInterface), s.address());
125         } else {
126             joinGroup(intValue(), ipv6, g.address(), i.address(), g.scopeId(), interfaceIndex(netInterface));
127         }
128     }
129 
130     void leaveGroup(InetAddress group, NetworkInterface netInterface, InetAddress source) throws IOException {
131         final NativeInetAddress g = NativeInetAddress.newInstance(group);
132         final boolean isIpv6 = group instanceof Inet6Address;
133         final NativeInetAddress i = NativeInetAddress.newInstance(deriveInetAddress(netInterface, isIpv6));
134         if (source != null) {
135             final NativeInetAddress s = NativeInetAddress.newInstance(source);
136             leaveSsmGroup(intValue(), ipv6, g.address(), i.address(),
137                     g.scopeId(), interfaceIndex(netInterface), s.address());
138         } else {
139             leaveGroup(intValue(), ipv6, g.address(), i.address(), g.scopeId(), interfaceIndex(netInterface));
140         }
141     }
142 
143     private static int interfaceIndex(NetworkInterface networkInterface) {
144         return networkInterface.getIndex();
145     }
146 
147     private static int interfaceIndex(InetAddress address) throws IOException {
148         NetworkInterface iface = NetworkInterface.getByInetAddress(address);
149         if (iface != null) {
150             return iface.getIndex();
151         }
152         return -1;
153     }
154 
155     void setTcpDeferAccept(int deferAccept) throws IOException {
156         setTcpDeferAccept(intValue(), deferAccept);
157     }
158 
159     void setTcpQuickAck(boolean quickAck) throws IOException {
160         setTcpQuickAck(intValue(), quickAck ? 1 : 0);
161     }
162 
163     void setTcpCork(boolean tcpCork) throws IOException {
164         setTcpCork(intValue(), tcpCork ? 1 : 0);
165     }
166 
167     void setSoBusyPoll(int loopMicros) throws IOException {
168         setSoBusyPoll(intValue(), loopMicros);
169     }
170 
171     void setTcpNotSentLowAt(long tcpNotSentLowAt) throws IOException {
172         if (tcpNotSentLowAt < 0 || tcpNotSentLowAt > MAX_UINT32_T) {
173             throw new IllegalArgumentException("tcpNotSentLowAt must be a uint32_t");
174         }
175         setTcpNotSentLowAt(intValue(), (int) tcpNotSentLowAt);
176     }
177 
178     void setTcpFastOpen(int tcpFastopenBacklog) throws IOException {
179         setTcpFastOpen(intValue(), tcpFastopenBacklog);
180     }
181 
182     void setTcpFastOpenConnect(boolean tcpFastOpenConnect) throws IOException {
183         setTcpFastOpenConnect(intValue(), tcpFastOpenConnect ? 1 : 0);
184     }
185 
186     boolean isTcpFastOpenConnect() throws IOException {
187         return isTcpFastOpenConnect(intValue()) != 0;
188     }
189 
190     void setTcpKeepIdle(int seconds) throws IOException {
191         setTcpKeepIdle(intValue(), seconds);
192     }
193 
194     void setTcpKeepIntvl(int seconds) throws IOException {
195         setTcpKeepIntvl(intValue(), seconds);
196     }
197 
198     void setTcpKeepCnt(int probes) throws IOException {
199         setTcpKeepCnt(intValue(), probes);
200     }
201 
202     void setTcpUserTimeout(int milliseconds) throws IOException {
203         setTcpUserTimeout(intValue(), milliseconds);
204     }
205 
206     void setIpFreeBind(boolean enabled) throws IOException {
207         setIpFreeBind(intValue(), enabled ? 1 : 0);
208     }
209 
210     void setIpTransparent(boolean enabled) throws IOException {
211         setIpTransparent(intValue(), enabled ? 1 : 0);
212     }
213 
214     void setIpRecvOrigDestAddr(boolean enabled) throws IOException {
215         setIpRecvOrigDestAddr(intValue(), enabled ? 1 : 0);
216     }
217 
218     int getTimeToLive() throws IOException {
219         return getTimeToLive(intValue());
220     }
221 
222     void getTcpInfo(IoUringTcpInfo info) throws IOException {
223         getTcpInfo(intValue(), info.info);
224     }
225 
226     void setTcpMd5Sig(InetAddress address, byte[] key) throws IOException {
227         final NativeInetAddress a = NativeInetAddress.newInstance(address);
228         setTcpMd5Sig(intValue(), ipv6, a.address(), a.scopeId(), key);
229     }
230 
231     boolean isTcpCork() throws IOException  {
232         return isTcpCork(intValue()) != 0;
233     }
234 
235     int getSoBusyPoll() throws IOException  {
236         return getSoBusyPoll(intValue());
237     }
238 
239     int getTcpDeferAccept() throws IOException {
240         return getTcpDeferAccept(intValue());
241     }
242 
243     boolean isTcpQuickAck() throws IOException {
244         return isTcpQuickAck(intValue()) != 0;
245     }
246 
247     long getTcpNotSentLowAt() throws IOException {
248         return getTcpNotSentLowAt(intValue()) & MAX_UINT32_T;
249     }
250 
251     int getTcpKeepIdle() throws IOException {
252         return getTcpKeepIdle(intValue());
253     }
254 
255     int getTcpKeepIntvl() throws IOException {
256         return getTcpKeepIntvl(intValue());
257     }
258 
259     int getTcpKeepCnt() throws IOException {
260         return getTcpKeepCnt(intValue());
261     }
262 
263     int getTcpUserTimeout() throws IOException {
264         return getTcpUserTimeout(intValue());
265     }
266 
267     boolean isIpFreeBind() throws IOException {
268         return isIpFreeBind(intValue()) != 0;
269     }
270 
271     boolean isIpTransparent() throws IOException {
272         return isIpTransparent(intValue()) != 0;
273     }
274 
275     boolean isIpRecvOrigDestAddr() throws IOException {
276         return isIpRecvOrigDestAddr(intValue()) != 0;
277     }
278 
279     PeerCredentials getPeerCredentials() throws IOException {
280         return getPeerCredentials(intValue());
281     }
282 
283     boolean isLoopbackModeDisabled() throws IOException {
284         return getIpMulticastLoop(intValue(), ipv6) == 0;
285     }
286 
287     void setLoopbackModeDisabled(boolean loopbackModeDisabled) throws IOException {
288         setIpMulticastLoop(intValue(), ipv6, loopbackModeDisabled ? 0 : 1);
289     }
290 
291     void setUdpGro(boolean gro) throws IOException {
292         setUdpGro(intValue(), gro ? 1 : 0);
293     }
294 
295     void makeBlocking() throws IOException {
296         int result = makeBlocking(intValue());
297         if (result != 0) {
298             throw Errors.newIOException("makeBlocking", result);
299         }
300         blocking = true;
301     }
302 
303     boolean isBlocking() {
304         return blocking;
305     }
306 
307     private static InetAddress deriveInetAddress(NetworkInterface netInterface, boolean ipv6) {
308         final InetAddress ipAny = ipv6 ? INET6_ANY : INET_ANY;
309         if (netInterface != null) {
310             final Enumeration<InetAddress> ias = netInterface.getInetAddresses();
311             while (ias.hasMoreElements()) {
312                 final InetAddress ia = ias.nextElement();
313                 final boolean isV6 = ia instanceof Inet6Address;
314                 if (isV6 == ipv6) {
315                     return ia;
316                 }
317             }
318         }
319         return ipAny;
320     }
321 
322     boolean isIpv6() {
323         return ipv6;
324     }
325 
326     public static LinuxSocket newSocketStream(boolean ipv6) {
327         return new LinuxSocket(newSocketStream0(ipv6));
328     }
329 
330     public static LinuxSocket newSocketStream() {
331         return newSocketStream(isIPv6Preferred());
332     }
333 
334     public static LinuxSocket newSocketDgram(boolean ipv6) {
335         return new LinuxSocket(newSocketDgram0(ipv6));
336     }
337 
338     public static LinuxSocket newSocketDgram() {
339         return newSocketDgram(isIPv6Preferred());
340     }
341 
342     public static LinuxSocket newSocketDomain() {
343         return new LinuxSocket(newSocketDomain0());
344     }
345 
346     private static InetAddress unsafeInetAddrByName(String inetName) {
347         try {
348             return InetAddress.getByName(inetName);
349         } catch (UnknownHostException uhe) {
350             throw new ChannelException(uhe);
351         }
352     }
353 
354     private static native void joinGroup(int fd, boolean ipv6, byte[] group, byte[] interfaceAddress,
355                                          int scopeId, int interfaceIndex) throws IOException;
356     private static native void joinSsmGroup(int fd, boolean ipv6, byte[] group, byte[] interfaceAddress,
357                                             int scopeId, int interfaceIndex, byte[] source) throws IOException;
358     private static native void leaveGroup(int fd, boolean ipv6, byte[] group, byte[] interfaceAddress,
359                                           int scopeId, int interfaceIndex) throws IOException;
360     private static native void leaveSsmGroup(int fd, boolean ipv6, byte[] group, byte[] interfaceAddress,
361                                              int scopeId, int interfaceIndex, byte[] source) throws IOException;
362 
363     private static native int getTcpDeferAccept(int fd) throws IOException;
364     private static native int isTcpQuickAck(int fd) throws IOException;
365     private static native int isTcpCork(int fd) throws IOException;
366     private static native int getSoBusyPoll(int fd) throws IOException;
367     private static native int getTcpNotSentLowAt(int fd) throws IOException;
368     private static native int getTcpKeepIdle(int fd) throws IOException;
369     private static native int getTcpKeepIntvl(int fd) throws IOException;
370     private static native int getTcpKeepCnt(int fd) throws IOException;
371     private static native int getTcpUserTimeout(int fd) throws IOException;
372     private static native int getTimeToLive(int fd) throws IOException;
373     private static native int isIpFreeBind(int fd) throws IOException;
374     private static native int isIpTransparent(int fd) throws IOException;
375     private static native int isIpRecvOrigDestAddr(int fd) throws IOException;
376     private static native void getTcpInfo(int fd, long[] array) throws IOException;
377     private static native PeerCredentials getPeerCredentials(int fd) throws IOException;
378     private static native int isTcpFastOpenConnect(int fd) throws IOException;
379 
380     private static native void setTcpDeferAccept(int fd, int deferAccept) throws IOException;
381     private static native void setTcpQuickAck(int fd, int quickAck) throws IOException;
382     private static native void setTcpCork(int fd, int tcpCork) throws IOException;
383     private static native void setSoBusyPoll(int fd, int loopMicros) throws IOException;
384     private static native void setTcpNotSentLowAt(int fd, int tcpNotSentLowAt) throws IOException;
385     private static native void setTcpFastOpen(int fd, int tcpFastopenBacklog) throws IOException;
386     private static native void setTcpFastOpenConnect(int fd, int tcpFastOpenConnect) throws IOException;
387     private static native void setTcpKeepIdle(int fd, int seconds) throws IOException;
388     private static native void setTcpKeepIntvl(int fd, int seconds) throws IOException;
389     private static native void setTcpKeepCnt(int fd, int probes) throws IOException;
390     private static native void setTcpUserTimeout(int fd, int milliseconds)throws IOException;
391     private static native void setIpFreeBind(int fd, int freeBind) throws IOException;
392     private static native void setIpTransparent(int fd, int transparent) throws IOException;
393     private static native void setIpRecvOrigDestAddr(int fd, int transparent) throws IOException;
394     private static native void setTcpMd5Sig(
395             int fd, boolean ipv6, byte[] address, int scopeId, byte[] key) throws IOException;
396     private static native void setInterface(
397             int fd, boolean ipv6, byte[] interfaceAddress, int scopeId, int networkInterfaceIndex) throws IOException;
398     private static native int getInterface(int fd, boolean ipv6);
399     private static native int getIpMulticastLoop(int fd, boolean ipv6) throws IOException;
400     private static native void setIpMulticastLoop(int fd, boolean ipv6, int enabled) throws IOException;
401     private static native void setTimeToLive(int fd, int ttl) throws IOException;
402     private static native int makeBlocking(int fd) throws IOException;
403     private static native void setUdpGro(int fd, int gro) throws IOException;
404 }