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