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